├── .github
├── FUNDING.yml
└── workflows
│ └── main.yml
├── flow.png
├── .idea
├── misc.xml
├── vcs.xml
├── modules.xml
├── tarkov.iml
└── runConfigurations
│ ├── Format.xml
│ └── Check.xml
├── examples
├── auth_basic.rs
├── auth_2fa.rs
├── auth_captcha.rs
├── search_traders.rs
├── trader_sell_item.rs
├── ragfair_sell_item.rs
├── search_trader_items.rs
├── trader_barter_deal.rs
├── trader_cash_deal.rs
└── ragfair_buy_item.rs
├── src
├── hwid.rs
├── friend.rs
├── bad_json.rs
├── market_filter.rs
├── inventory.rs
├── auth.rs
├── lib.rs
├── ragfair.rs
├── trading.rs
├── profile.rs
└── constant.rs
├── Cargo.toml
├── LICENSE
├── README.md
├── .gitignore
├── tests
└── test_api.rs
└── Cargo.lock
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | custom: buymeacoff.ee/ddd
2 |
--------------------------------------------------------------------------------
/flow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dank/tarkov/HEAD/flow.png
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/tarkov.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/examples/auth_basic.rs:
--------------------------------------------------------------------------------
1 | use tarkov::hwid::generate_hwid;
2 | use tarkov::{Error, Tarkov};
3 |
4 | #[tokio::main]
5 | async fn main() -> Result<(), Error> {
6 | std::env::set_var("RUST_LOG", "tarkov=info");
7 | env_logger::init();
8 |
9 | let t = Tarkov::login("me@example.com", "password", generate_hwid().as_str()).await?;
10 | println!("{}", t.session);
11 |
12 | let t = Tarkov::from_access_token(
13 | "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
14 | generate_hwid().as_str(),
15 | )
16 | .await?;
17 | println!("{}", t.session);
18 |
19 | let t = Tarkov::from_session("e1bc65a216325f0ad0db8518fa299db1");
20 | println!("{}", t.session);
21 |
22 | Ok(())
23 | }
24 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: CI (Linux)
2 | on: ["push", "pull_request"]
3 |
4 | jobs:
5 | build:
6 | runs-on: ubuntu-18.04
7 | steps:
8 | - name: Checkout
9 | uses: actions/checkout@v2
10 | - name: Install toolchain
11 | uses: actions-rs/toolchain@v1
12 | with:
13 | toolchain: stable
14 | target: x86_64-unknown-linux-gnu
15 | override: true
16 | - name: Run cargo fmt
17 | uses: actions-rs/cargo@v1
18 | with:
19 | command: fmt
20 | args: --all -- --check
21 | - name: Run cargo check
22 | uses: actions-rs/cargo@v1
23 | with:
24 | command: check
25 | args: --all --examples --tests
--------------------------------------------------------------------------------
/.idea/runConfigurations/Format.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/Check.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/hwid.rs:
--------------------------------------------------------------------------------
1 | use rand::Rng;
2 |
3 | fn random_md5(rng: &mut R) -> String {
4 | format!("{:x}", md5::compute(&rng.gen::().to_le_bytes()))
5 | }
6 |
7 | /// Generate a random EFT compatible HWID.
8 | pub fn generate_hwid() -> String {
9 | let mut rng = rand::thread_rng();
10 |
11 | let short_md5 = {
12 | let mut hash = random_md5(&mut rng);
13 | hash.truncate(hash.len() - 8);
14 |
15 | hash
16 | };
17 |
18 | format!(
19 | "#1-{}:{}:{}-{}-{}-{}-{}-{}",
20 | random_md5(&mut rng),
21 | random_md5(&mut rng),
22 | random_md5(&mut rng),
23 | random_md5(&mut rng),
24 | random_md5(&mut rng),
25 | random_md5(&mut rng),
26 | random_md5(&mut rng),
27 | short_md5
28 | )
29 | }
30 |
31 | #[test]
32 | fn test_generate_hwid() {
33 | assert_eq!(generate_hwid().len(), 258)
34 | }
35 |
--------------------------------------------------------------------------------
/examples/auth_2fa.rs:
--------------------------------------------------------------------------------
1 | use tarkov::auth::LoginError;
2 | use tarkov::hwid::generate_hwid;
3 | use tarkov::{Error, Tarkov};
4 |
5 | #[tokio::main]
6 | async fn main() -> Result<(), Error> {
7 | std::env::set_var("RUST_LOG", "tarkov=info");
8 | env_logger::init();
9 |
10 | let email = "me@example.com";
11 | let password = "password";
12 | let hwid = generate_hwid();
13 |
14 | let t = match Tarkov::login(email, password, &hwid).await {
15 | Ok(t) => Ok(t),
16 | Err(Error::LoginError(e)) => match e {
17 | // 2FA required!
18 | LoginError::TwoFactorRequired => {
19 | // Get 2FA from email (or generate TOTP) then continue...
20 | let code = "XYZ";
21 | Tarkov::login_with_2fa(email, password, code, &hwid).await
22 | }
23 | _ => Err(e)?,
24 | },
25 | Err(e) => Err(e),
26 | }?;
27 |
28 | println!("{}", t.session);
29 |
30 | Ok(())
31 | }
32 |
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "tarkov"
3 | description = "A client library for the Escape from Tarkov API"
4 | version = "0.1.6"
5 | authors = ["Dan Kyung "]
6 | edition = "2018"
7 | readme = "README.md"
8 | license = "MIT"
9 | keywords = ["escapefromtarkov", "eft", "tarkov", "sdk", "api"]
10 | include = ["src/**/*", "Cargo.toml", "LICENSE"]
11 | repository = "https://github.com/dank/tarkov"
12 | documentation = "https://docs.rs/tarkov"
13 |
14 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
15 |
16 | [dependencies]
17 | md5 = "0.7"
18 | err-derive = "0.2"
19 | serde = { version = "1.0", features = ["derive"] }
20 | serde_json = "1.0"
21 | flate2 = { version = "1.0", features = ["zlib"], default-features = false }
22 | rand = "0.7"
23 | log = "0.4"
24 | serde_repr = "0.1"
25 | hyper = "0.13"
26 | hyper-tls = "0.4"
27 | http = "0.2"
28 |
29 | [dev-dependencies]
30 | env_logger = "0.7"
31 | tokio = { version = "0.2", features = ["macros"] }
32 |
--------------------------------------------------------------------------------
/examples/auth_captcha.rs:
--------------------------------------------------------------------------------
1 | use tarkov::auth::LoginError;
2 | use tarkov::hwid::generate_hwid;
3 | use tarkov::{Error, Tarkov};
4 |
5 | #[tokio::main]
6 | async fn main() -> Result<(), Error> {
7 | std::env::set_var("RUST_LOG", "tarkov=info");
8 | env_logger::init();
9 |
10 | let email = "me@example.com";
11 | let password = "password";
12 | let hwid = generate_hwid();
13 |
14 | let t = match Tarkov::login(email, password, &hwid).await {
15 | Ok(t) => Ok(t),
16 | Err(Error::LoginError(e)) => match e {
17 | // Captcha required!
18 | LoginError::CaptchaRequired => {
19 | // Solve captcha here and try again
20 | let captcha = "03AOLTBLQ952pO-qQYPeLr53N5nK9Co14iXyCp...";
21 | Tarkov::login_with_captcha(email, password, captcha, &hwid).await
22 | }
23 | _ => Err(e)?,
24 | },
25 | Err(e) => Err(e),
26 | }?;
27 |
28 | println!("{}", t.session);
29 |
30 | Ok(())
31 | }
32 |
--------------------------------------------------------------------------------
/examples/search_traders.rs:
--------------------------------------------------------------------------------
1 | use tarkov::profile::Side;
2 | use tarkov::{Error, Tarkov};
3 |
4 | #[tokio::main]
5 | async fn main() -> Result<(), Error> {
6 | std::env::set_var("RUST_LOG", "tarkov=info");
7 | env_logger::init();
8 |
9 | let t = Tarkov::from_session("e1bc65a216325f0ad0db8518fa299db2");
10 |
11 | // Find and select PMC profile to complete login.
12 | let profiles = t.get_profiles().await?;
13 | let profile = profiles
14 | .into_iter()
15 | .find(|p| p.info.side != Side::Savage)
16 | .unwrap();
17 | t.select_profile(&profile.id).await?;
18 |
19 | // Fetch the translation table because trader names are in Russian.
20 | let locale = t.get_i18n("en").await?;
21 |
22 | // Find trader by name.
23 | let traders = t.get_traders().await?;
24 | let trader = traders
25 | .into_iter()
26 | .find(|t| locale.traders.get(&t.id).unwrap().nickname == "Mechanic")
27 | .unwrap();
28 |
29 | println!("{:#?}", trader);
30 |
31 | Ok(())
32 | }
33 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Dan Kyung
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/examples/trader_sell_item.rs:
--------------------------------------------------------------------------------
1 | use tarkov::profile::Side;
2 | use tarkov::{Error, Tarkov};
3 |
4 | #[tokio::main]
5 | async fn main() -> Result<(), Error> {
6 | std::env::set_var("RUST_LOG", "tarkov=info");
7 | env_logger::init();
8 |
9 | let t = Tarkov::from_session("da3902b29e442da4972f8ce499834ee7");
10 |
11 | // Find and select PMC profile to complete login.
12 | let profiles = t.get_profiles().await?;
13 | let profile = profiles
14 | .into_iter()
15 | .find(|p| p.info.side != Side::Savage)
16 | .unwrap();
17 | t.select_profile(&profile.id).await?;
18 |
19 | // Get Therapist
20 | let traders = t.get_traders().await?;
21 | let trader = traders
22 | .into_iter()
23 | .find(|t| t.nickname == "Терапевт")
24 | .unwrap();
25 |
26 | // Get painkiller item ID from my inventory
27 | let painkiller = &profile
28 | .inventory
29 | .items
30 | .into_iter()
31 | .find(|i| i.schema_id == "544fb37f4bdc2dee738b4567")
32 | .unwrap();
33 |
34 | // Sell item
35 | println!("{:#?}", t.sell_item(&trader.id, &painkiller.id, 1).await);
36 |
37 | Ok(())
38 | }
39 |
--------------------------------------------------------------------------------
/examples/ragfair_sell_item.rs:
--------------------------------------------------------------------------------
1 | use tarkov::profile::Side;
2 | use tarkov::ragfair::Requirement;
3 | use tarkov::{Error, Tarkov};
4 |
5 | #[tokio::main]
6 | async fn main() -> Result<(), Error> {
7 | std::env::set_var("RUST_LOG", "tarkov=info");
8 | env_logger::init();
9 |
10 | let t = Tarkov::from_session("e1bc65a216325f0ad0db8518fa299db2");
11 |
12 | // Find and select PMC profile to complete login.
13 | let profiles = t.get_profiles().await?;
14 | let profile = profiles
15 | .into_iter()
16 | .find(|p| p.info.side != Side::Savage)
17 | .unwrap();
18 | t.select_profile(&profile.id).await?;
19 |
20 | // Get the painkiller item ID from my inventory
21 | let painkiller = &profile
22 | .inventory
23 | .items
24 | .into_iter()
25 | .find(|i| i.schema_id == "544fb37f4bdc2dee738b4567")
26 | .unwrap();
27 |
28 | // Get market price of painkiller
29 | let price = t.get_item_price(&painkiller.schema_id).await?;
30 |
31 | // Put the painkiller on market for average price
32 | println!(
33 | "{:#?}",
34 | t.offer_item(
35 | &[&painkiller.id],
36 | &[Requirement {
37 | schema_id: "5449016a4bdc2d6f028b456f".to_string(),
38 | count: price.avg.round(),
39 | }],
40 | false,
41 | )
42 | .await?
43 | );
44 |
45 | Ok(())
46 | }
47 |
--------------------------------------------------------------------------------
/examples/search_trader_items.rs:
--------------------------------------------------------------------------------
1 | use tarkov::profile::Side;
2 | use tarkov::{Error, Tarkov};
3 |
4 | #[tokio::main]
5 | async fn main() -> Result<(), Error> {
6 | std::env::set_var("RUST_LOG", "tarkov=info");
7 | env_logger::init();
8 |
9 | let t = Tarkov::from_session("e1bc65a216325f0ad0db8518fa299db2");
10 |
11 | // Find and select PMC profile to complete login.
12 | let profiles = t.get_profiles().await?;
13 | let profile = profiles
14 | .into_iter()
15 | .find(|p| p.info.side != Side::Savage)
16 | .unwrap();
17 | t.select_profile(&profile.id).await?;
18 |
19 | // Fetch the translation table because trader names are in Russian.
20 | let locale = t.get_i18n("en").await?;
21 |
22 | // Find trader by name.
23 | let traders = t.get_traders().await?;
24 | let trader = traders
25 | .into_iter()
26 | .find(|t| locale.traders.get(&t.id).unwrap().nickname == "Therapist")
27 | .unwrap();
28 |
29 | // Fetch all items to map item ID to item name/descriptor.
30 | let items = t.get_items().await?;
31 |
32 | // Find trader's item by name
33 | let trader_items = t.get_trader_items(&trader.id).await?;
34 | let painkiller = trader_items
35 | .into_iter()
36 | .find(|i| {
37 | // Therapist sells painkillers for Roubles or 2 matches. Finding the barter deal.
38 | let item = items.get(&i.schema_id).unwrap();
39 | item.name == "painkiller" && i.price.get(0).unwrap().count == 2.0
40 | })
41 | .unwrap();
42 |
43 | println!("{:#?}", painkiller);
44 |
45 | Ok(())
46 | }
47 |
--------------------------------------------------------------------------------
/src/friend.rs:
--------------------------------------------------------------------------------
1 | use crate::{handle_error, ErrorResponse, Result, Tarkov, PROD_ENDPOINT};
2 |
3 | use crate::profile::Side;
4 | use serde::{Deserialize, Serialize};
5 |
6 | #[derive(Debug, Deserialize)]
7 | struct FriendResponse {
8 | #[serde(flatten)]
9 | error: ErrorResponse,
10 | data: Option,
11 | }
12 |
13 | /// Friend list
14 | #[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
15 | #[serde(rename_all = "PascalCase")]
16 | pub struct Friends {
17 | /// Friends
18 | pub friends: Vec,
19 | /// Muted friend IDs
20 | pub ignore: Vec,
21 | /// ?
22 | pub in_ignore_list: Vec,
23 | }
24 |
25 | /// Friend
26 | #[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
27 | #[serde(rename_all = "PascalCase")]
28 | pub struct Friend {
29 | /// Friend ID
30 | #[serde(rename = "_id")]
31 | pub id: String,
32 | /// Friend info
33 | pub info: Info,
34 | }
35 |
36 | /// Friend info
37 | #[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
38 | #[serde(rename_all = "PascalCase")]
39 | pub struct Info {
40 | /// Friend nickname
41 | pub nickname: String,
42 | /// Friend side
43 | pub side: Side,
44 | /// Friend level
45 | pub level: u64,
46 | /// ?
47 | pub member_category: String,
48 | }
49 |
50 | impl Tarkov {
51 | /// Get a list of account's friends.
52 | pub async fn get_friends(&self) -> Result {
53 | let url = format!("{}/client/friend/list", PROD_ENDPOINT);
54 | let res: FriendResponse = self.post_json(&url, &{}).await?;
55 |
56 | handle_error(res.error, res.data)
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/examples/trader_barter_deal.rs:
--------------------------------------------------------------------------------
1 | use tarkov::inventory::BarterItem;
2 | use tarkov::profile::Side;
3 | use tarkov::{Error, Tarkov};
4 |
5 | #[tokio::main]
6 | async fn main() -> Result<(), Error> {
7 | std::env::set_var("RUST_LOG", "tarkov=info");
8 | env_logger::init();
9 |
10 | let t = Tarkov::from_session("e1bc65a216325f0ad0db8518fa299db2");
11 |
12 | // Find and select PMC profile to complete login.
13 | let profiles = t.get_profiles().await?;
14 | let profile = profiles
15 | .into_iter()
16 | .find(|p| p.info.side != Side::Savage)
17 | .unwrap();
18 | t.select_profile(&profile.id).await?;
19 |
20 | // Get Therapist
21 | let traders = t.get_traders().await?;
22 | let trader = traders
23 | .into_iter()
24 | .find(|t| t.nickname == "Терапевт")
25 | .unwrap();
26 |
27 | // Therapist wants 2 matches for 1 painkiller.
28 | let painkiller = t
29 | .get_trader_items(&trader.id)
30 | .await?
31 | .into_iter()
32 | .find(|i| i.id == "5e064f5deb009468d90baf01")
33 | .unwrap();
34 |
35 | // Get the IDs of 2 painkillers from my inventory
36 | let barter_items = &profile
37 | .inventory
38 | .items
39 | .into_iter()
40 | .filter(|i| i.schema_id == painkiller.price.get(0).unwrap().schema_id)
41 | .map(|i| BarterItem {
42 | id: i.id,
43 | count: 1.0,
44 | })
45 | .collect::>()[..2];
46 |
47 | // Trade item
48 | println!(
49 | "{:#?}",
50 | t.trade_item(&trader.id, &painkiller.id, 1, barter_items)
51 | .await?
52 | );
53 |
54 | Ok(())
55 | }
56 |
--------------------------------------------------------------------------------
/examples/trader_cash_deal.rs:
--------------------------------------------------------------------------------
1 | use tarkov::inventory::BarterItem;
2 | use tarkov::profile::Side;
3 | use tarkov::{Error, Tarkov};
4 |
5 | #[tokio::main]
6 | async fn main() -> Result<(), Error> {
7 | std::env::set_var("RUST_LOG", "tarkov=info");
8 | env_logger::init();
9 |
10 | let t = Tarkov::from_session("3e463058dd4884ab0c4a6035dc56066b");
11 |
12 | // Find and select PMC profile to complete login.
13 | let profiles = t.get_profiles().await?;
14 | let profile = profiles
15 | .into_iter()
16 | .find(|p| p.info.side != Side::Savage)
17 | .unwrap();
18 | t.select_profile(&profile.id).await?;
19 |
20 | // Get Therapist
21 | let traders = t.get_traders().await?;
22 | let trader = traders
23 | .into_iter()
24 | .find(|t| t.nickname == "Терапевт")
25 | .unwrap();
26 |
27 | // Therapist wants 3990₽ for 1 painkiller.
28 | let painkiller = t
29 | .get_trader_items(&trader.id)
30 | .await?
31 | .into_iter()
32 | .find(|i| i.id == "5e064f5deb009468d90baef7")
33 | .unwrap();
34 |
35 | // Get Rouble item ID from my inventory
36 | let rouble = &profile
37 | .inventory
38 | .items
39 | .into_iter()
40 | .find(|i| i.schema_id == "5449016a4bdc2d6f028b456f")
41 | .unwrap();
42 |
43 | // Trade item
44 | println!(
45 | "{:#?}",
46 | t.trade_item(
47 | &trader.id,
48 | "5e064f5deb009468d90baef7",
49 | 1,
50 | &[BarterItem {
51 | id: rouble.id.to_owned(),
52 | count: painkiller.price.get(0).unwrap().count, // Assume price is 3990₽.
53 | }],
54 | )
55 | .await
56 | );
57 |
58 | Ok(())
59 | }
60 |
--------------------------------------------------------------------------------
/examples/ragfair_buy_item.rs:
--------------------------------------------------------------------------------
1 | use std::time::{SystemTime, UNIX_EPOCH};
2 | use tarkov::inventory::BarterItem;
3 | use tarkov::market_filter::{Currency, MarketFilter, Owner};
4 | use tarkov::profile::Side;
5 | use tarkov::{Error, Tarkov};
6 |
7 | #[tokio::main]
8 | async fn main() -> Result<(), Error> {
9 | std::env::set_var("RUST_LOG", "tarkov=info");
10 | env_logger::init();
11 |
12 | let t = Tarkov::from_session("e1bc65a216325f0ad0db8518fa299db2");
13 |
14 | // Find and select PMC profile to complete login.
15 | let profiles = t.get_profiles().await?;
16 | let profile = profiles
17 | .into_iter()
18 | .find(|p| p.info.side != Side::Savage)
19 | .unwrap();
20 | t.select_profile(&profile.id).await?;
21 |
22 | // Fetch the translation table for market categories.
23 | let locale = t.get_i18n("en").await?;
24 |
25 | // Get the "Barter items" category ID.
26 | let barter_item_category_id: Option = {
27 | let mut id = None;
28 | for (k, v) in locale.handbook {
29 | if v == "Barter items" {
30 | id = Some(k);
31 | break;
32 | }
33 | }
34 |
35 | id
36 | };
37 |
38 | // Search flea market.
39 | let offers = t
40 | .search_market(
41 | 0,
42 | 15,
43 | MarketFilter {
44 | max_price: Some(2000),
45 | handbook_id: barter_item_category_id.as_deref(),
46 | owner_type: Owner::Player,
47 | hide_bartering_offers: true,
48 | currency: Currency::Rouble,
49 | ..MarketFilter::default()
50 | },
51 | )
52 | .await?;
53 |
54 | // Find the first item available for purchase immediately.
55 | let current_time = SystemTime::now();
56 | let epoch_time = current_time.duration_since(UNIX_EPOCH).unwrap().as_secs();
57 | let offer = offers
58 | .offers
59 | .into_iter()
60 | .find(|o| o.start_time + 60 <= epoch_time && o.end_time >= epoch_time)
61 | .unwrap();
62 |
63 | // Get Rouble item ID from my inventory
64 | let rouble = &profile
65 | .inventory
66 | .items
67 | .into_iter()
68 | .find(|i| i.schema_id == "5449016a4bdc2d6f028b456f")
69 | .unwrap();
70 |
71 | // Buy the item.
72 | println!(
73 | "{:#?}",
74 | t.buy_item(
75 | &offer.id,
76 | 1,
77 | &[BarterItem {
78 | id: rouble.id.to_owned(),
79 | count: offer.requirements_cost as f64,
80 | }],
81 | )
82 | .await?
83 | );
84 |
85 | Ok(())
86 | }
87 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Tarkov
2 | [](https://crates.io/crates/tarkov)
3 | [](https://docs.rs/tarkov)
4 | [](LICENSE)
5 |
6 | An unofficial client library for the [Escape from Tarkov](https://escapefromtarkov.com) (EFT) API.
7 |
8 | Note: The game updates faster than I can update this crate. Make sure the `GAME_VERSION` and `LAUNCHER_VERSION` consts are up to date.
9 |
10 | ## Features
11 | - [x] Authentication
12 | - [x] Flea market
13 | - [x] Traders
14 | - [ ] Hideout
15 | - [ ] Inventory management (equip, move, delete, etc)
16 | - [ ] Messenger
17 | - [ ] Quests
18 |
19 | ## Getting Started
20 |
21 | Comprehensive examples can be found in the [`examples`](examples) directory.
22 |
23 | ### Usage
24 | Add this to your `Cargo.toml`:
25 | ```
26 | [dependencies]
27 | tarkov = "0.1"
28 | ```
29 |
30 | ### Authentication
31 | 
32 | There are three ways to authenticate your EFT account for `tarkov`:
33 | 1. Email & password is the easiest way to authenticate your account. However, a captcha and 2FA code may be required. Read the [HWID section](#hardware-id) for more details.
34 | 2. Access token or Bearer token can be found by sniffing EFT launcher traffic. HWID from the launcher is required.
35 | 3. Session is a cookie called `PHPSESSID`, it can be found by sniffing EFT launcher traffic. HWID is not required for this method.
36 |
37 | **Your _PMC_ character profile must be selected with `select_profile` to complete the authentication.**
38 |
39 | ### Hardware ID
40 | Hardware ID (HWID) may be required on authentication, it can either be sniffed from the EFT launcher or generated. It's recommended to save the HWID in a _persistent store_ and reuse it after the first successful authentication.
41 |
42 | Using a fresh HWID means both captcha and 2FA code will be required on your first login attempt. This can be avoid by using the HWID generated by the EFT launcher or authenticating with your session cookie.
43 |
44 | ### Captcha
45 | This library does not attempt to solve captchas for you, the `g-recaptcha-response` token from reCAPTCHA may be required on authentication.
46 |
47 | reCAPTCHA can be solved externally using tools like [captcha-harvester](https://github.com/dzt/captcha-harvester).
48 |
49 | ### Rust Version
50 | `tarkov` has a minimum version requirement of `1.40`.
51 |
52 | ## "Unofficial"
53 |
54 | I should emphasize that this library is _unofficial_. EFT does not have a public API, everything in this repo was reversed from the game.
55 |
56 | The API is clearly designed for internal use. It contains numerous spelling mistakes, inconsistent conventions, and tons of bad practice JSON. The developers may push breaking changes without prior warning.
57 |
58 | ## License
59 | [MIT](LICENSE)
60 |
--------------------------------------------------------------------------------
/src/bad_json.rs:
--------------------------------------------------------------------------------
1 | //! EFT API returns a lot of inconsistent and bad JSON. Serde deserializers to fix those broken JSON.
2 |
3 | use crate::inventory::Location;
4 | use serde::de::{Error, Visitor};
5 | use serde::{Deserialize, Deserializer, Serialize};
6 | use serde_json::Value;
7 | use std::fmt;
8 |
9 | pub(crate) fn deserialize_integer_to_string<'de, D>(de: D) -> Result
10 | where
11 | D: Deserializer<'de>,
12 | {
13 | let json: serde_json::Value = Deserialize::deserialize(de)?;
14 | match json {
15 | Value::Number(i) => Ok(i.to_string()),
16 | Value::String(s) => Ok(s),
17 | _ => Err(Error::custom("Unexpected value")),
18 | }
19 | }
20 |
21 | pub(crate) fn deserialize_integer_to_option_string<'de, D>(
22 | de: D,
23 | ) -> Result