From 9f41af6eee44d346e97c42a471d505d9f3df1453 Mon Sep 17 00:00:00 2001 From: Matthew Esposito Date: Thu, 28 Dec 2023 15:37:02 -0500 Subject: [PATCH] Improve spoofing - match headers more closely, pull in real versions/builds --- scripts/update_oauth_resources.sh | 99 +++++++++++++ src/client.rs | 2 +- src/main.rs | 1 + src/oauth.rs | 113 ++++++++------- src/oauth_resources.rs | 231 ++++++++++++++++++++++++++++++ src/subreddit.rs | 2 +- src/user.rs | 2 +- 7 files changed, 397 insertions(+), 53 deletions(-) create mode 100755 scripts/update_oauth_resources.sh create mode 100644 src/oauth_resources.rs diff --git a/scripts/update_oauth_resources.sh b/scripts/update_oauth_resources.sh new file mode 100755 index 0000000..5a3ed6d --- /dev/null +++ b/scripts/update_oauth_resources.sh @@ -0,0 +1,99 @@ +#!/bin/bash + +# Fetch iOS app versions +ios_version_list=$(curl -s "https://ipaarchive.com/app/usa/1064216828" | rg "(20\d{2}\.\d+.\d+) / (\d+)" --only-matching -r "Version \$1/Build \$2" | sort | uniq) + +# Count the number of lines in the version list +ios_app_count=$(echo "$ios_version_list" | wc -l) + +echo -e "Fetching \e[34m$ios_app_count iOS app versions...\e[0m" + + +# Specify the filename as a variable +filename="src/oauth_resources.rs" + +# Add comment that it is user generated +echo "// This file was generated by scripts/update_oauth_resources.sh" >> "$filename" +echo "// Rerun scripts/update_oauth_resources.sh to update this file" >> "$filename" +echo "// Please do not edit manually" >> "$filename" +echo "// Filled in with real app versions" >> "$filename" + +# Open the array in the source file +echo "pub static IOS_APP_VERSION_LIST: &[&str; $ios_app_count] = &[" >> "$filename" + + +# Append the version list to the source file +echo "$ios_version_list" | while IFS= read -r line; do + echo " \"$line\"," >> "$filename" + echo -e "Fetched \e[34m$line\e[0m." +done + +# Close the array in the source file +echo "];" >> "$filename" + +# Fetch Android app versions +page_1=$(curl -s "https://apkcombo.com/reddit/com.reddit.frontpage/old-versions/" | rg "" -r "https://apkcombo.com\$1" | sort | uniq) +# Append with pages +page_2=$(curl -s "https://apkcombo.com/reddit/com.reddit.frontpage/old-versions?page=2" | rg "" -r "https://apkcombo.com\$1" | sort | uniq) +page_3=$(curl -s "https://apkcombo.com/reddit/com.reddit.frontpage/old-versions?page=3" | rg "" -r "https://apkcombo.com\$1" | sort | uniq) +page_4=$(curl -s "https://apkcombo.com/reddit/com.reddit.frontpage/old-versions?page=4" | rg "" -r "https://apkcombo.com\$1" | sort | uniq) +page_5=$(curl -s "https://apkcombo.com/reddit/com.reddit.frontpage/old-versions?page=5" | rg "" -r "https://apkcombo.com\$1" | sort | uniq) + +# Concatenate all pages +versions="${page_1}" +versions+=$'\n' +versions+="${page_2}" +versions+=$'\n' +versions+="${page_3}" +versions+=$'\n' +versions+="${page_4}" +versions+=$'\n' +versions+="${page_5}" + +# Count the number of lines in the version list +android_count=$(echo "$versions" | wc -l) + +echo -e "Fetching \e[32m$android_count Android app versions...\e[0m" + +# Append to the source file +echo "pub static ANDROID_APP_VERSION_LIST: &[&str; $android_count] = &[" >> "$filename" + +# For each in versions, curl the page and extract the build number +echo "$versions" | while IFS= read -r line; do + fetch_page=$(curl -s "$line") + build=$(echo "$fetch_page" | rg "\((\d+)\)" --only-matching -r "\$1" | head -n1) + version=$(echo "$fetch_page" | rg "Reddit (20\d{2}\.\d+\.\d+)" --only-matching -r "\$1" | head -n1) + echo " \"Version $version/Build $build\"," >> "$filename" + echo -e "Fetched \e[32mVersion $version/Build $build\e[0m" +done + +# Close the array in the source file +echo "];" >> "$filename" + +# Retrieve iOS versions +table=$(curl -s "https://en.wikipedia.org/w/api.php?action=parse&page=IOS_17&prop=wikitext§ion=31&format=json" | jq ".parse.wikitext.\"*\"" | rg "(17\.[\d\.]*)\\\n\|(\w*)\\\n\|" --only-matching -r "Version \$1 (Build \$2)") + +# Count the number of lines in the version list +ios_count=$(echo "$table" | wc -l) + +echo -e "Fetching \e[34m$ios_count iOS versions...\e[0m" + +# Append to the source file +echo "pub static IOS_OS_VERSION_LIST: &[&str; $ios_count] = &[" >> "$filename" + +# For each in versions, curl the page and extract the build number +echo "$table" | while IFS= read -r line; do + echo " \"$line\"," >> "$filename" + echo -e "Fetched $line\e[0m" +done + +# Close the array in the source file +echo "];" >> "$filename" + +echo -e "\e[34mRetrieved $ios_app_count iOS app versions.\e[0m" +echo -e "\e[32mRetrieved $android_count Android app versions.\e[0m" +echo -e "\e[34mRetrieved $ios_count iOS versions.\e[0m" + +echo -e "\e[34mTotal: $((ios_app_count + android_count + ios_count))\e[0m" + +echo -e "\e[32mSuccess!\e[0m" diff --git a/src/client.rs b/src/client.rs index e60135f..757a8e9 100644 --- a/src/client.rs +++ b/src/client.rs @@ -332,7 +332,7 @@ pub async fn json(path: String, quarantine: bool) -> Result { } } -#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[tokio::test(flavor = "multi_thread", worker_threads = 8)] async fn test_localization_popular() { let val = json("/r/popular/hot.json?&raw_json=1&geo_filter=GLOBAL".to_string(), false).await.unwrap(); assert_eq!("GLOBAL", val["data"]["geo_filter"].as_str().unwrap()); diff --git a/src/main.rs b/src/main.rs index fc4069b..ff6c9ec 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,6 +7,7 @@ mod config; mod duplicates; mod instance_info; mod oauth; +mod oauth_resources; mod post; mod search; mod settings; diff --git a/src/oauth.rs b/src/oauth.rs index 23a27e7..2513ff5 100644 --- a/src/oauth.rs +++ b/src/oauth.rs @@ -1,6 +1,9 @@ use std::{collections::HashMap, time::Duration}; -use crate::client::{CLIENT, OAUTH_CLIENT}; +use crate::{ + client::{CLIENT, OAUTH_CLIENT}, + oauth_resources::{ANDROID_APP_VERSION_LIST, IOS_APP_VERSION_LIST, IOS_OS_VERSION_LIST}, +}; use base64::{engine::general_purpose, Engine as _}; use hyper::{client, Body, Method, Request}; use log::info; @@ -12,26 +15,10 @@ static REDDIT_IOS_OAUTH_CLIENT_ID: &str = "LNDo9k1o8UAEUw"; static AUTH_ENDPOINT: &str = "https://accounts.reddit.com"; -// Various Android user agents - build numbers from valid APK variants -pub static ANDROID_USER_AGENT: [&str; 3] = [ - "Reddit/Version 2023.21.0/Build 956283/Android 13", - "Reddit/Version 2023.21.0/Build 968223/Android 10", - "Reddit/Version 2023.21.0/Build 946732/Android 12", -]; - -// Various iOS user agents - iOS versions. -pub static IOS_USER_AGENT: [&str; 3] = [ - "Reddit/Version 2023.22.0/Build 613580/iOS Version 17.0 (Build 21A5248V)", - "Reddit/Version 2023.22.0/Build 613580/iOS Version 16.0 (Build 20A5328h)", - "Reddit/Version 2023.22.0/Build 613580/iOS Version 16.5", -]; -// Various iOS device codes. iPhone 11 displays as `iPhone12,1` -// I just changed the number a few times for some plausible values -pub static IOS_DEVICES: [&str; 5] = ["iPhone8,1", "iPhone11,1", "iPhone12,1", "iPhone13,1", "iPhone14,1"]; - +// Spoofed client for Android and iOS devices #[derive(Debug, Clone, Default)] pub struct Oauth { - // Currently unused, may be necessary if we decide to support GQL in the future + pub(crate) initial_headers: HashMap, pub(crate) headers_map: HashMap, pub(crate) token: String, expires_in: u64, @@ -47,10 +34,12 @@ impl Oauth { pub(crate) fn default() -> Self { // Generate a random device to spoof let device = Device::random(); - let headers = device.headers.clone(); + let headers_map = device.headers.clone(); + let initial_headers = device.initial_headers.clone(); // For now, just insert headers - no token request Self { - headers_map: headers, + headers_map, + initial_headers, token: String::new(), expires_in: 0, device, @@ -62,16 +51,8 @@ impl Oauth { let mut builder = Request::builder().method(Method::POST).uri(&url); // Add headers from spoofed client - for (key, value) in self.headers_map.iter() { - // Skip Authorization header - won't be present in `Device` struct - // and will only be there in subsequent token refreshes. - // Sending a bearer auth token when requesting one is a bad idea - // Normally, you'd want to send it along to authenticate a refreshed token, - // but neither Android nor iOS does this - it just requests a new token. - // We try to match behavior as closely as possible. - if key != "Authorization" { - builder = builder.header(key, value); - } + for (key, value) in self.initial_headers.iter() { + builder = builder.header(key, value); } // Set up HTTP Basic Auth - basically just the const OAuth ID's with no password, // Base64-encoded. https://en.wikipedia.org/wiki/Basic_access_authentication @@ -82,7 +63,7 @@ impl Oauth { // Set JSON body. I couldn't tell you what this means. But that's what the client sends let json = json!({ - "scopes": ["*","email","pii"] + "scopes": ["*","email"] }); let body = Body::from(json.to_string()); @@ -100,6 +81,11 @@ impl Oauth { self.headers_map.insert("x-reddit-loid".to_owned(), header.to_str().ok()?.to_string()); } + // Same with x-reddit-session + if let Some(header) = resp.headers().get("x-reddit-session") { + self.headers_map.insert("x-reddit-session".to_owned(), header.to_str().ok()?.to_string()); + } + // Serialize response let body_bytes = hyper::body::to_bytes(resp.into_body()).await.ok()?; let json: serde_json::Value = serde_json::from_slice(&body_bytes).ok()?; @@ -109,7 +95,7 @@ impl Oauth { self.expires_in = json.get("expires_in")?.as_u64()?; self.headers_map.insert("Authorization".to_owned(), format!("Bearer {}", self.token)); - info!("✅ Success - Retrieved token \"{}...\", expires in {}", &self.token[..32], self.expires_in); + info!("[✅] Success - Retrieved token \"{}...\", expires in {}", &self.token[..32], self.expires_in); Some(()) } @@ -132,11 +118,11 @@ pub async fn token_daemon() { // sleep for the expiry time minus 2 minutes let duration = Duration::from_secs(expires_in - 120); - info!("Waiting for {duration:?} seconds before refreshing OAuth token..."); + info!("[⏳] Waiting for {duration:?} seconds before refreshing OAuth token..."); tokio::time::sleep(duration).await; - info!("[{duration:?} ELAPSED] Refreshing OAuth token..."); + info!("[⌛] {duration:?} Elapsed! Refreshing OAuth token..."); // Refresh token - in its own scope { @@ -147,6 +133,7 @@ pub async fn token_daemon() { #[derive(Debug, Clone, Default)] struct Device { oauth_id: String, + initial_headers: HashMap, headers: HashMap, } @@ -155,8 +142,11 @@ impl Device { // Generate uuid let uuid = uuid::Uuid::new_v4().to_string(); - // Select random user agent from ANDROID_USER_AGENT - let android_user_agent = choose(&ANDROID_USER_AGENT).to_string(); + // Generate random user-agent + let android_app_version = choose(ANDROID_APP_VERSION_LIST).to_string(); + let android_version = fastrand::u8(9..=14); + + let android_user_agent = format!("Reddit/{android_app_version}/Android {android_version}"); // Android device headers let headers = HashMap::from([ @@ -165,36 +155,47 @@ impl Device { ("User-Agent".into(), android_user_agent), ]); - info!("Spoofing Android client with headers: {headers:?}, uuid: \"{uuid}\", and OAuth ID \"{REDDIT_ANDROID_OAUTH_CLIENT_ID}\""); + info!("[🔄] Spoofing Android client with headers: {headers:?}, uuid: \"{uuid}\", and OAuth ID \"{REDDIT_ANDROID_OAUTH_CLIENT_ID}\""); Self { oauth_id: REDDIT_ANDROID_OAUTH_CLIENT_ID.to_string(), - headers, + headers: headers.clone(), + initial_headers: headers, } } fn ios() -> Self { // Generate uuid let uuid = uuid::Uuid::new_v4().to_string(); - // Select random user agent from IOS_USER_AGENT - let ios_user_agent = choose(&IOS_USER_AGENT).to_string(); + // Generate random user-agent + let ios_app_version = choose(IOS_APP_VERSION_LIST).to_string(); + let ios_os_version = choose(IOS_OS_VERSION_LIST).to_string(); + let ios_user_agent = format!("Reddit/{ios_app_version}/iOS {ios_os_version}"); - // Select random iOS device from IOS_DEVICES - let ios_device = choose(&IOS_DEVICES).to_string(); + // Generate random device + let ios_device_num = fastrand::u8(8..=15).to_string(); + let ios_device = format!("iPhone{ios_device_num},1").to_string(); - // iOS device headers + let initial_headers = HashMap::from([ + ("X-Reddit-DPR".into(), "2".into()), + ("User-Agent".into(), ios_user_agent.clone()), + ("Device-Name".into(), ios_device.clone()), + ]); let headers = HashMap::from([ ("X-Reddit-DPR".into(), "2".into()), ("Device-Name".into(), ios_device.clone()), - ("X-Reddit-Device-Id".into(), uuid.clone()), ("User-Agent".into(), ios_user_agent), ("Client-Vendor-Id".into(), uuid.clone()), + ("x-dev-ad-id".into(), "00000000-0000-0000-0000-000000000000".into()), + ("Reddit-User_Id".into(), "anonymous_browsing_mode".into()), + ("x-reddit-device-id".into(), uuid.clone()), ]); - info!("Spoofing iOS client {ios_device} with headers: {headers:?}, uuid: \"{uuid}\", and OAuth ID \"{REDDIT_IOS_OAUTH_CLIENT_ID}\""); + info!("[🔄] Spoofing iOS client {ios_device} with headers: {headers:?}, uuid: \"{uuid}\", and OAuth ID \"{REDDIT_IOS_OAUTH_CLIENT_ID}\""); Self { oauth_id: REDDIT_IOS_OAUTH_CLIENT_ID.to_string(), + initial_headers, headers, } } @@ -208,18 +209,30 @@ impl Device { } } -// Waiting on fastrand 2.0.0 for the `choose` function -// https://github.com/smol-rs/fastrand/pull/59/ fn choose(list: &[T]) -> T { *fastrand::choose_multiple(list.iter(), 1)[0] } -#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[tokio::test(flavor = "multi_thread", worker_threads = 8)] async fn test_oauth_client() { assert!(!OAUTH_CLIENT.read().await.token.is_empty()); } -#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[tokio::test(flavor = "multi_thread", worker_threads = 8)] async fn test_oauth_client_refresh() { OAUTH_CLIENT.write().await.refresh().await.unwrap(); } +#[tokio::test(flavor = "multi_thread", worker_threads = 8)] +async fn test_oauth_token_exists() { + assert!(!OAUTH_CLIENT.read().await.token.is_empty()); +} + +#[tokio::test(flavor = "multi_thread", worker_threads = 8)] +async fn test_oauth_headers_len() { + assert!(OAUTH_CLIENT.read().await.headers_map.len() >= 3); +} + +#[test] +fn test_creating_device() { + Device::random(); +} diff --git a/src/oauth_resources.rs b/src/oauth_resources.rs new file mode 100644 index 0000000..9b9f7d8 --- /dev/null +++ b/src/oauth_resources.rs @@ -0,0 +1,231 @@ +pub static IOS_APP_VERSION_LIST: &[&str; 67] = &[ + "Version 2020.0.0/Build 306960", + "Version 2020.10.0/Build 307041", + "Version 2020.10.1/Build 307047", + "Version 2020.1.0/Build 306966", + "Version 2020.11.0/Build 307049", + "Version 2020.11.1/Build 307063", + "Version 2020.12.0/Build 307070", + "Version 2020.13.0/Build 307072", + "Version 2020.13.1/Build 307075", + "Version 2020.14.0/Build 307077", + "Version 2020.14.1/Build 307080", + "Version 2020.15.0/Build 307084", + "Version 2020.16.0/Build 307090", + "Version 2020.17.0/Build 307093", + "Version 2020.19.0/Build 307137", + "Version 2020.20.0/Build 307156", + "Version 2020.20.1/Build 307159", + "Version 2020.2.0/Build 306969", + "Version 2020.21.0/Build 307162", + "Version 2020.21.1/Build 307165", + "Version 2020.22.0/Build 307177", + "Version 2020.22.1/Build 307181", + "Version 2020.23.0/Build 307183", + "Version 2020.24.0/Build 307189", + "Version 2020.25.0/Build 307198", + "Version 2020.26.0/Build 307205", + "Version 2020.26.1/Build 307213", + "Version 2020.27.0/Build 307229", + "Version 2020.28.0/Build 307233", + "Version 2020.29.0/Build 307235", + "Version 2020.30.0/Build 307238", + "Version 2020.3.0/Build 306971", + "Version 2020.31.0/Build 307240", + "Version 2020.31.1/Build 307246", + "Version 2020.32.0/Build 307250", + "Version 2020.33.0/Build 307252", + "Version 2020.34.0/Build 307260", + "Version 2020.35.0/Build 307262", + "Version 2020.36.0/Build 307265", + "Version 2020.37.0/Build 307272", + "Version 2020.38.0/Build 307286", + "Version 2020.39.0/Build 307306", + "Version 2020.4.0/Build 306978", + "Version 2020.5.0/Build 306993", + "Version 2020.5.1/Build 307005", + "Version 2020.6.0/Build 307007", + "Version 2020.7.0/Build 307012", + "Version 2020.8.0/Build 307014", + "Version 2020.8.1/Build 307017", + "Version 2020.9.0/Build 307035", + "Version 2020.9.1/Build 307039", + "Version 2023.18.0/Build 310494", + "Version 2023.19.0/Build 310507", + "Version 2023.20.0/Build 310535", + "Version 2023.21.0/Build 310560", + "Version 2023.22.0/Build 613580", + "Version 2023.23.0/Build 310613", + "Version 2023.23.1/Build 613639", + "Version 2023.24.0/Build 613663", + "Version 2023.25.0/Build 613739", + "Version 2023.26.0/Build 613749", + "Version 2023.27.0/Build 613771", + "Version 2023.28.0/Build 613803", + "Version 2023.28.1/Build 613809", + "Version 2023.29.0/Build 613825", + "Version 2023.30.0/Build 613849", + "Version 2023.31.0/Build 613864", +]; +pub static ANDROID_APP_VERSION_LIST: &[&str; 150] = &[ + "Version 2023.25.1/Build 1018737", + "Version 2023.26.0/Build 1019073", + "Version 2023.27.0/Build 1031923", + "Version 2023.28.0/Build 1046887", + "Version 2023.29.0/Build 1059855", + "Version 2023.30.0/Build 1078734", + "Version 2023.31.0/Build 1091027", + "Version 2023.32.0/Build 1109919", + "Version 2023.32.1/Build 1114141", + "Version 2023.33.1/Build 1129741", + "Version 2023.34.0/Build 1144243", + "Version 2023.35.0/Build 1157967", + "Version 2023.36.0/Build 1168982", + "Version 2023.37.0/Build 1182743", + "Version 2023.38.0/Build 1198522", + "Version 2023.39.0/Build 1211607", + "Version 2023.39.1/Build 1221505", + "Version 2023.40.0/Build 1221521", + "Version 2023.41.0/Build 1233125", + "Version 2023.41.1/Build 1239615", + "Version 2023.42.0/Build 1245088", + "Version 2023.43.0/Build 1257426", + "Version 2023.44.0/Build 1268622", + "Version 2023.45.0/Build 1281371", + "Version 2023.47.0/Build 1303604", + "Version 2023.48.0/Build 1319123", + "Version 2023.49.0/Build 1321715", + "Version 2023.49.1/Build 1322281", + "Version 2023.50.0/Build 1332338", + "Version 2023.50.1/Build 1345844", + "Version 2023.02.0/Build 717912", + "Version 2023.03.0/Build 729220", + "Version 2023.04.0/Build 744681", + "Version 2023.05.0/Build 755453", + "Version 2023.06.0/Build 775017", + "Version 2023.07.0/Build 788827", + "Version 2023.07.1/Build 790267", + "Version 2023.08.0/Build 798718", + "Version 2023.09.0/Build 812015", + "Version 2023.09.1/Build 816833", + "Version 2023.10.0/Build 821148", + "Version 2023.11.0/Build 830610", + "Version 2023.12.0/Build 841150", + "Version 2023.13.0/Build 852246", + "Version 2023.14.0/Build 861593", + "Version 2023.14.1/Build 864826", + "Version 2023.15.0/Build 870628", + "Version 2023.16.0/Build 883294", + "Version 2023.16.1/Build 886269", + "Version 2023.17.0/Build 896030", + "Version 2023.17.1/Build 900542", + "Version 2023.18.0/Build 911877", + "Version 2023.19.0/Build 927681", + "Version 2023.20.0/Build 943980", + "Version 2023.20.1/Build 946732", + "Version 2023.21.0/Build 956283", + "Version 2023.22.0/Build 968223", + "Version 2023.23.0/Build 983896", + "Version 2023.24.0/Build 998541", + "Version 2023.25.0/Build 1014750", + "Version 2022.24.0/Build 510950", + "Version 2022.24.1/Build 513462", + "Version 2022.25.0/Build 515072", + "Version 2022.25.1/Build 516394", + "Version 2022.25.2/Build 519915", + "Version 2022.26.0/Build 521193", + "Version 2022.27.0/Build 527406", + "Version 2022.27.1/Build 529687", + "Version 2022.28.0/Build 533235", + "Version 2022.30.0/Build 548620", + "Version 2022.31.0/Build 556666", + "Version 2022.31.1/Build 562612", + "Version 2022.32.0/Build 567875", + "Version 2022.33.0/Build 572600", + "Version 2022.34.0/Build 579352", + "Version 2022.35.0/Build 588016", + "Version 2022.35.1/Build 589034", + "Version 2022.36.0/Build 593102", + "Version 2022.37.0/Build 601691", + "Version 2022.38.0/Build 607460", + "Version 2022.39.0/Build 615385", + "Version 2022.39.1/Build 619019", + "Version 2022.40.0/Build 624782", + "Version 2022.41.0/Build 630468", + "Version 2022.41.1/Build 634168", + "Version 2022.42.0/Build 638508", + "Version 2022.43.0/Build 648277", + "Version 2022.44.0/Build 664348", + "Version 2022.45.0/Build 677985", + "Version 2023.01.0/Build 709875", + "Version 2021.45.0/Build 387663", + "Version 2021.46.0/Build 392043", + "Version 2021.47.0/Build 394342", + "Version 2022.10.0/Build 429896", + "Version 2022.1.0/Build 402829", + "Version 2022.11.0/Build 433004", + "Version 2022.12.0/Build 436848", + "Version 2022.13.0/Build 442084", + "Version 2022.13.1/Build 444621", + "Version 2022.14.1/Build 452742", + "Version 2022.15.0/Build 455453", + "Version 2022.16.0/Build 462377", + "Version 2022.17.0/Build 468480", + "Version 2022.18.0/Build 473740", + "Version 2022.19.1/Build 482464", + "Version 2022.20.0/Build 487703", + "Version 2022.2.0/Build 405543", + "Version 2022.21.0/Build 492436", + "Version 2022.22.0/Build 498700", + "Version 2022.23.0/Build 502374", + "Version 2022.23.1/Build 506606", + "Version 2022.3.0/Build 408637", + "Version 2022.4.0/Build 411368", + "Version 2022.5.0/Build 414731", + "Version 2022.6.0/Build 418391", + "Version 2022.6.1/Build 419585", + "Version 2022.6.2/Build 420562", + "Version 2022.7.0/Build 420849", + "Version 2022.8.0/Build 423906", + "Version 2022.9.0/Build 426592", + "Version 2021.17.0/Build 323213", + "Version 2021.18.0/Build 324849", + "Version 2021.19.0/Build 325762", + "Version 2021.20.0/Build 326964", + "Version 2021.21.0/Build 327703", + "Version 2021.21.1/Build 328461", + "Version 2021.22.0/Build 329696", + "Version 2021.23.0/Build 331631", + "Version 2021.24.0/Build 333951", + "Version 2021.25.0/Build 335451", + "Version 2021.26.0/Build 336739", + "Version 2021.27.0/Build 338857", + "Version 2021.28.0/Build 340747", + "Version 2021.29.0/Build 342342", + "Version 2021.30.0/Build 343820", + "Version 2021.31.0/Build 346485", + "Version 2021.32.0/Build 349507", + "Version 2021.33.0/Build 351843", + "Version 2021.34.0/Build 353911", + "Version 2021.35.0/Build 355878", + "Version 2021.36.0/Build 359254", + "Version 2021.36.1/Build 360572", + "Version 2021.37.0/Build 361905", + "Version 2021.38.0/Build 365032", + "Version 2021.39.0/Build 369068", + "Version 2021.39.1/Build 372418", + "Version 2021.41.0/Build 376052", + "Version 2021.42.0/Build 378193", + "Version 2021.43.0/Build 382019", + "Version 2021.44.0/Build 385129", +]; +pub static IOS_OS_VERSION_LIST: &[&str; 8] = &[ + "Version 17.0.1 (Build 21A340)", + "Version 17.0.2 (Build 21A350)", + "Version 17.0.3 (Build 21A360)", + "Version 17.1 (Build 21B74)", + "Version 17.1.1 (Build 21B91)", + "Version 17.1.2 (Build 21B101)", + "Version 17.2 (Build 21C62)", + "Version 17.2.1 (Build 21C66)", +]; diff --git a/src/subreddit.rs b/src/subreddit.rs index 560b487..30499f0 100644 --- a/src/subreddit.rs +++ b/src/subreddit.rs @@ -443,7 +443,7 @@ async fn subreddit(sub: &str, quarantined: bool) -> Result { }) } -#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[tokio::test(flavor = "multi_thread", worker_threads = 8)] async fn test_fetching_subreddit() { let subreddit = subreddit("rust", false).await; assert!(subreddit.is_ok()); diff --git a/src/user.rs b/src/user.rs index 8ffc366..7b7610a 100644 --- a/src/user.rs +++ b/src/user.rs @@ -130,7 +130,7 @@ async fn user(name: &str) -> Result { }) } -#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[tokio::test(flavor = "multi_thread", worker_threads = 8)] async fn test_fetching_user() { let user = user("spez").await; assert!(user.is_ok());