diff --git a/.gitignore b/.gitignore index d01bd1a..88ab7a5 100644 --- a/.gitignore +++ b/.gitignore @@ -18,4 +18,5 @@ Cargo.lock # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ \ No newline at end of file +#.idea/ +secret.txt \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index cd031eb..a14e91a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,18 +1,19 @@ [package] name = "aw" -version = "0.0.3" +version = "0.0.4" edition = "2021" [dependencies] clap = { version = "4.5.15", features = ["derive"] } -tokio = { version = "1.39.2", default-features = false, features = ["rt", "sync"] } +tokio = { version = "1.39.2", default-features = false, features = ["rt-multi-thread", "rt"] } reqwest = { version = "0.12.5", default-features = false, features = ["http2", "json", "rustls-tls"] } serde_json = { version = "1.0.120", default-features = false, features = ["alloc"] } serde = { version = "1.0.204", features = ["derive"] } ring = { version = "0.17.8", default-features = false} -tokio-stream = "0.1.15" +indicatif = "0.17.8" chrono = "0.4.38" base64 = "0.22.1" +rand = "0.8.5" [[bin]] name = "aw" diff --git a/src/cli.rs b/src/cli.rs index 3c195f6..97a7896 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -10,4 +10,4 @@ fn main() -> Result<(), Box> { let _ = ld_::interface(cli.n); println!("Processing time: {:?}", start_time.elapsed()); Ok(()) -} \ No newline at end of file +} diff --git a/src/client/cipher.rs b/src/client/cipher.rs index 67eeb72..fd1ec3b 100644 --- a/src/client/cipher.rs +++ b/src/client/cipher.rs @@ -10,3 +10,12 @@ pub fn get_key() -> String { res } +pub fn encode(raw: &str) -> String { + let secret = BASE64.encode(raw.as_bytes()); + secret +} + +pub fn decode(secret: &str) -> String { + let raw = BASE64.decode(secret).unwrap(); + String::from_utf8(raw).unwrap() +} \ No newline at end of file diff --git a/src/client/geo.rs b/src/client/geo.rs new file mode 100644 index 0000000..feb0a69 --- /dev/null +++ b/src/client/geo.rs @@ -0,0 +1,53 @@ +use rand::Rng as _; +use std::net::Ipv4Addr; + +pub fn generate_geo_ip() -> String { + let mut rng = rand::thread_rng(); + Ipv4Addr::new( + rng.gen_range(1..=253), + rng.gen(), + rng.gen(), + rng.gen_range(1..=254) + ).to_string() +} + +pub fn generate_us_ip() -> String { + let mut rng = rand::thread_rng(); + let _blocks = [ + (3, 0, 0, 0, 4), // 3.0.0.0/8 + (4, 0, 0, 0, 6), // 4.0.0.0/6 + (8, 0, 0, 0, 7), // 8.0.0.0/7 + (11, 0, 0, 0, 8), // 11.0.0.0/8 + (12, 0, 0, 0, 6), // 12.0.0.0/6 + (16, 0, 0, 0, 6), // 16.0.0.0/6 + (20, 0, 0, 0, 7), // 20.0.0.0/7 + (24, 0, 0, 0, 8), // 24.0.0.0/8 + (26, 0, 0, 0, 7), // 26.0.0.0/7 + (28, 0, 0, 0, 6), // 28.0.0.0/6 + (32, 0, 0, 0, 3), // 32.0.0.0/3 + (64, 0, 0, 0, 2), // 64.0.0.0/2 + (128, 0, 0, 0, 3), // 128.0.0.0/3 + (160, 0, 0, 0, 5), // 160.0.0.0/5 + (168, 0, 0, 0, 6), // 168.0.0.0/6 + (172, 0, 0, 0, 8), // 172.0.0.0/8 + (173, 0, 0, 0, 8), // 173.0.0.0/8 + (174, 0, 0, 0, 7), // 174.0.0.0/7 + (184, 0, 0, 0, 6), // 184.0.0.0/6 + (192, 0, 0, 0, 8), // 192.0.0.0/8 + (198, 0, 0, 0, 7), // 198.0.0.0/7 + (200, 0, 0, 0, 5), // 200.0.0.0/5 + (208, 0, 0, 0, 4), // 208.0.0.0/4 + ]; + let (base_a, _, _, _, mask) = _blocks[rng.gen_range(0.._blocks.len())]; + let ip = match mask { + 8 => Ipv4Addr::new(base_a, rng.gen(), rng.gen(), rng.gen()), + 7 => Ipv4Addr::new(base_a, rng.gen(), rng.gen(), rng.gen()), + 6 => Ipv4Addr::new(base_a + rng.gen_range(0..4), rng.gen(), rng.gen(), rng.gen()), + 5 => Ipv4Addr::new(base_a + rng.gen_range(0..8), rng.gen(), rng.gen(), rng.gen()), + 4 => Ipv4Addr::new(base_a + rng.gen_range(0..16), rng.gen(), rng.gen(), rng.gen()), + 3 => Ipv4Addr::new(base_a + rng.gen_range(0..32), rng.gen(), rng.gen(), rng.gen()), + 2 => Ipv4Addr::new(base_a + rng.gen_range(0..64), rng.gen(), rng.gen(), rng.gen()), + _ => Ipv4Addr::new(base_a, rng.gen(), rng.gen(), rng.gen()), + }; + ip.to_string() +} \ No newline at end of file diff --git a/src/client/mod.rs b/src/client/mod.rs index cdb0325..51a3a76 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -2,4 +2,6 @@ pub mod warp; pub use warp::WARP; pub mod date; -pub mod cipher; \ No newline at end of file +pub mod cipher; +pub mod geo; +pub mod process; \ No newline at end of file diff --git a/src/client/process.rs b/src/client/process.rs new file mode 100644 index 0000000..d5a230f --- /dev/null +++ b/src/client/process.rs @@ -0,0 +1,261 @@ +use tokio::time::Duration; +use indicatif::{MultiProgress, ProgressBar, ProgressStyle}; + +const RETRY_DELAY: Duration = Duration::from_secs(120); +const CAPACITY: usize = 1000; +const MAX_SEED: usize = 2; +const _EPOOL: &str = "SVQ4azYxMm4tSDhDNDJFajYtODAyN0pFVHAgbzY3OXZjMEYtM1ZMVzFrNzQtY0YwOWE0N1AgMHkyYjNVejUtUGNrSDk3NTQtM202NEExcnUgN1AwM0VXMk0tTWdsMzEyYjYtNXU2QzJ5NHMgMnZ0RDlJNzQtN3R3MTBhVDQtRVk1NzB1NlEgc0MyNTRPVjEtNkIwTTgxenMtOFltN0paMTMgOUw1R0VzODAtOHVTM3g5ZTEtOW12WTU2N2EgN2wyM1RXNWYtdjZUNTI5S3ctMWRvMlJBMzQgZTdNWEUyMDktaXg1MElyMTItOHEzY2IxN3ogM1BGSDg1OXktYzUxNEo5cHItMkU5NE0xUlggN0thYjEwTzQtOU9sdlc4NDMtNTBucWg3MmkgM0o0bmZ2OTIteDUzTTRBOFctWGQxdjkyN2IgYWhHMFM4MzEtME1tNTEzQkotSzduNlQxNVcgSzk0N0ZPRzUtNjRsMHZESDIteTc4MzFwVmkgcjE0dDlKeTUtOTZRM2gxVnYtN040YWkwcDggTTRGM2Q2N0EtYlo5azBxNzIteVVSZTg5MjQgSUJTTDgyNDYtSTM1OWlMNnEtNXdYMmZsNDcgUDZFMzE4Yk4tN2JJMlIwUTgtNzJKOWZ1NFYgVDVEWjgzRzAtUm1BMTQ5N3ctODFYeVJZMzcgOGw1MER4YzEtWms4ajdhOTAtMndOOTMxb0U="; + +use super::warp::WARP; +use super::cipher; +use super::geo; + +pub async fn batch_create(num: usize) -> Vec { + let mp = MultiProgress::new(); + let create_style = ProgressStyle::with_template("[{elapsed_precise}] [{eta_precise}] {wide_bar:.cyan/green} {pos:>7}/{len:7}") + .unwrap() + .tick_chars("⠁⠂⠄⡀⢀⠠⠐⠈ "); + + let mut tasks = Vec::new(); + let mut warps = Vec::new(); + + for _ in 0..num { + let task = tokio::spawn(async { + let ip = geo::generate_us_ip(); + WARP::build(ip).await + }); + + tasks.push(task); + + if tasks.len() == CAPACITY { + let mut _tasks = vec![]; + _tasks.append(&mut tasks); + + let pb = mp.add(ProgressBar::new(_tasks.len() as u64)); + pb.set_style(create_style.clone()); + + for task in _tasks { + if let Ok(Ok(warp)) = task.await { + warps.push(warp); + } + pb.inc(1); + } + tasks.clear(); + pb.finish(); + tokio::time::sleep(RETRY_DELAY).await; + } + } + + let _pb = mp.add(ProgressBar::new(tasks.len() as u64)); + _pb.set_style(create_style.clone()); + for task in tasks { + if let Ok(Ok(warp)) = task.await { + warps.push(warp); + } + _pb.inc(1); + } + _pb.finish(); + warps +} + +pub async fn batch_seed(warp: Vec) -> Vec { + let mp = MultiProgress::new(); + let seed_style = ProgressStyle::with_template("[{elapsed_precise}] [{eta_precise}] {wide_bar:.cyan/yellow} {pos:>7}/{len:7}") + .unwrap() + .tick_chars("⠁⠂⠄⡀⢀⠠⠐⠈ "); + + let mut _warps = warp.clone(); + let pool = cipher::decode(_EPOOL); + let seeds : Vec<_> = pool.split(" ").into_iter().collect(); + let mut tasks = Vec::new(); + let mut warps = Vec::new(); + + for _ in 0..MAX_SEED { + for seed in &seeds { + if let Some(warp) = _warps.pop() { + let seed = seed.to_string(); + let task = tokio::spawn(async move { + warp.update_license(seed).await + }); + tasks.push(task); + } else { + break; + } + + if tasks.len() == CAPACITY { + tokio::time::sleep(RETRY_DELAY).await; + let mut _tasks = vec![]; + _tasks.append(&mut tasks); + + let pb = mp.add(ProgressBar::new(_tasks.len() as u64)); + pb.set_style(seed_style.clone()); + + for task in _tasks { + if let Ok(Ok(warp)) = task.await { + warps.push(warp); + } + pb.inc(1); + } + tasks.clear(); + pb.finish(); + } + } + } + + let _pb = mp.add(ProgressBar::new(tasks.len() as u64)); + _pb.set_style(seed_style.clone()); + for task in tasks { + if let Ok(Ok(warp)) = task.await { + warps.push(warp); + } + _pb.inc(1); + } + _pb.finish(); + warps +} + +pub async fn batch_update(warp: Vec) -> Vec { + let mp = MultiProgress::new(); + let update_style = ProgressStyle::with_template("[{elapsed_precise}] [{eta_precise}] {wide_bar:.cyan/blue} {pos:>7}/{len:7}") + .unwrap() + .tick_chars("⠁⠂⠄⡀⢀⠠⠐⠈ "); + + let mut tasks = Vec::new(); + let mut warps = Vec::new(); + + for sw in warp{ + let ss = sw.license(); + let task = tokio::spawn(async move { + sw.update_license(ss).await + }); + tasks.push(task); + + if tasks.len() == CAPACITY { + tokio::time::sleep(RETRY_DELAY).await; + let mut _tasks = vec![]; + _tasks.append(&mut tasks); + + let pb = mp.add(ProgressBar::new(_tasks.len() as u64)); + pb.set_style(update_style.clone()); + + for task in _tasks { + if let Ok(Ok(warp)) = task.await { + warps.push(warp); + } + pb.inc(1); + } + tasks.clear(); + pb.finish(); + } + } + + let _pb = mp.add(ProgressBar::new(tasks.len() as u64)); + _pb.set_style(update_style.clone()); + for task in tasks { + if let Ok(Ok(warp)) = task.await { + warps.push(warp); + } + _pb.inc(1); + } + _pb.finish(); + + warps +} + +pub async fn batch_delete(warp: Vec) -> Vec { + let mp = MultiProgress::new(); + let delete_style = ProgressStyle::with_template("[{elapsed_precise}] [{eta_precise}] {wide_bar:.cyan/red} {pos:>7}/{len:7}") + .unwrap() + .tick_chars("⠁⠂⠄⡀⢀⠠⠐⠈ "); + + let mut tasks = Vec::new(); + let mut warps = Vec::new(); + + for dw in warp{ + let task = tokio::spawn(async move { + dw.delete().await + }); + tasks.push(task); + + if tasks.len() == CAPACITY { + tokio::time::sleep(RETRY_DELAY).await; + let mut _tasks = vec![]; + _tasks.append(&mut tasks); + + let pb = mp.add(ProgressBar::new(_tasks.len() as u64)); + pb.set_style(delete_style.clone()); + + for task in _tasks { + if let Ok(Ok(warp)) = task.await { + warps.push(warp); + } + pb.inc(1); + } + tasks.clear(); + pb.finish(); + } + } + + let _pb = mp.add(ProgressBar::new(tasks.len() as u64)); + _pb.set_style(delete_style.clone()); + for task in tasks { + if let Ok(Ok(warp)) = task.await { + warps.push(warp); + } + _pb.inc(1); + } + _pb.finish(); + + warps +} + +pub async fn batch_info(warp: Vec){ + let mut tasks = Vec::new(); + + for _warp in warp{ + let task = tokio::spawn(async move { + _warp.get_quota().await + }); + tasks.push(task); + } + + for task in tasks { + if let Ok(Ok(info)) = task.await { + println!("{:#?}", info); + } + } +} + + + + // let _pb = mp.add(ProgressBar::new(seed_tasks.len() as u64)); + // _pb.set_style(update_style.clone()); + // for task in seed_tasks { + // if let Ok(Ok(warp)) = task.await { + // seed_warps.push(warp); + // } + // _pb.inc(1); + // } + // _pb.finish(); + + // tokio::time::sleep(RETRY_DELAY).await; + // let mut warps = Vec::new(); + // let mut tasks = Vec::new(); + + // for sw in seed_warps{ + // let ss = sw.license(); + // let task = tokio::spawn(async move { + // sw.update_license(ss).await + // }); + // tasks.push(task); + // } + + // let _pb = mp.add(ProgressBar::new(tasks.len() as u64)); + // _pb.set_style(update_style.clone()); + // for task in tasks { + // if let Ok(Ok(warp)) = task.await { + // warps.push(warp); + // } + // _pb.inc(1); + // } + // _pb.finish(); \ No newline at end of file diff --git a/src/client/warp.rs b/src/client/warp.rs index 6bd7ac3..56ced83 100644 --- a/src/client/warp.rs +++ b/src/client/warp.rs @@ -1,79 +1,103 @@ use serde_json::json; use serde::{Deserialize, Serialize}; -use tokio::time::{sleep, Duration}; use super::cipher; use super::date; const END_POINT: &str = "https://api.cloudflareclient.com/v0a2077/reg"; -const RETRY_DELAY: Duration = Duration::from_secs(60); #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ACCOUNT { - pub id: String, - pub license: String + id: String, + license: String } #[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Internal { + id: String, + key: String, + token: String, + account: ACCOUNT +} + +#[derive(Debug, Clone)] pub struct WARP { - pub id: String, - pub key: String, - pub token: String, - pub account: ACCOUNT + pub client: reqwest::Client, + pub intern: Internal, } impl WARP { - pub async fn new() -> Result>{ + pub fn new(client: reqwest::Client, intern: Internal) -> Self { + Self { client, intern } + } + + pub async fn build(geoip: String) -> Result> { + let mut headers = reqwest::header::HeaderMap::new(); + headers.insert("X-Forwarded-For", geoip.parse().unwrap()); + + let client = reqwest::Client::builder() + .http2_keep_alive_timeout(tokio::time::Duration::from_secs(45)) + .default_headers(headers) + .build() + .unwrap(); + let payload = json!({ "tos": date::get_tos(), "key": cipher::get_key() }); - let client = reqwest::Client::builder() - .http2_keep_alive_timeout(std::time::Duration::from_secs(15)) - .build()?; - let response = client.post(END_POINT) .json(&payload) .send() .await?; + let intern = response.json::().await?; + Ok(Self::new(client, intern)) + } + + pub async fn update_license(self, license: String) -> Result> { + let end_point = format!("{}/{}/account", END_POINT, self.intern.id); + + let payload = json!({ + "license": license, + }); + + let response = self.client.put(end_point.clone()) + .bearer_auth(self.intern.token.clone()) + .json(&payload) + .send() + .await?; + if !response.status().is_success() { - return Err(format!("HTTP error: {}", response.text().await?).into()); + return Err(format!("PUT HTTP error: {}", response.text().await?).into()); } - let warp = response - .json::() - .await?; - Ok(warp) + Ok(self.clone()) } - pub async fn build() -> Result>{ - let warp = loop { - match Self::new().await { - Ok(warp) => break warp, - Err(_) => { - eprintln!("Retrying in {} seconds...", RETRY_DELAY.as_secs()); - sleep(RETRY_DELAY).await; - }, - } - }; - - Ok(warp) - } + pub async fn get_license(self, seed: String) -> Result> { + let end_point = format!("{}/{}/account", END_POINT, self.intern.id); - pub async fn update(&mut self, license: String) -> Result>{ - let end_point = format!("{}/{}/account", END_POINT, self.id); let payload = json!({ - "license": license, + "license": seed, }); - let client = reqwest::Client::builder() - .http2_keep_alive_timeout(std::time::Duration::from_secs(15)) - .build()?; + let response = self.client.put(end_point.clone()) + .bearer_auth(self.intern.token.clone()) + .json(&payload) + .send() + .await?; + + if !response.status().is_success() { + return Err(format!("PUT HTTP error: {}", response.text().await?).into()); + } + + let payload = json!({ + "license": self.intern.account.license, + }); - let response = client.put(end_point.clone()) - .bearer_auth(&self.token) + let response = self.client.put(end_point.clone()) + .bearer_auth(self.intern.token.clone()) .json(&payload) .send() .await?; @@ -82,44 +106,52 @@ impl WARP { return Err(format!("PUT HTTP error: {}", response.text().await?).into()); } - let response = client.get(end_point) - .bearer_auth(&self.token) + let response = self.client.delete(end_point) + .bearer_auth(self.intern.token.clone()) .send() .await?; if !response.status().is_success() { - return Err(format!("GET HTTP error: {}", response.text().await?).into()); + return Err(format!("DELETE HTTP error: {}", response.text().await?).into()); } - let last_license = self.account.license.clone(); - self.account = response.json::().await?; - Ok(last_license) + Ok(self.clone()) } - pub async fn delete(&self) -> Result<(), Box>{ - let end_point = format!("{}/{}", END_POINT, self.id); + pub async fn get_quota(&self) -> Result> { + let end_point = format!("{}/{}/account", END_POINT, self.intern.id); + let response = self.client.get(end_point) + .bearer_auth(&self.intern.token) + .send() + .await?; - let client = reqwest::Client::builder() - .http2_keep_alive_timeout(std::time::Duration::from_secs(45)) - .build()?; + if !response.status().is_success() { + return Err(format!("GET HTTP error: {}", response.text().await?).into()); + } + + // let json = response.json().await?; + let json: serde_json::Value = response.json().await?; + let info = json["quota"].to_string(); + // let caption = json["candidates"][0]["content"]["parts"][0]["text"] + // .as_str() + // .ok_or_else(|| format!("Failed to parse response: {}", response_text))?; + Ok(info) + } - let response = client.delete(end_point) - .bearer_auth(&self.token) + pub async fn delete(self) -> Result> { + let end_point = format!("{}/{}/account", END_POINT, self.intern.id); + let response = self.client.delete(end_point) + .bearer_auth(self.intern.token.clone()) .send() .await?; if !response.status().is_success() { return Err(format!("DELETE HTTP error: {}", response.text().await?).into()); } - Ok(()) + Ok(self.clone()) } - pub async fn get_license(&mut self, seed: String) -> Result>{ - let license = self.update(seed).await.unwrap(); - let _ = self.update(license.clone()).await.unwrap(); - let _ = self.delete().await.unwrap(); - - Ok(license) + pub fn license(&self) -> String{ + self.intern.account.license.clone() } - } \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index bbddeb3..c9e76fa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,44 +1,26 @@ -use tokio_stream::{StreamExt, iter}; pub mod client; +use client::process; -const CAPACITY: usize = 5; -const SEED: &str ="0U7h98No-L6987BhV-uDd80i36"; +pub fn interface(num: usize) -> Result<(), Box> { + let rt = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build()?; -pub async fn run_tokio(num: usize) -> Result<(), Box> { - let semaphore = std::sync::Arc::new(tokio::sync::Semaphore::new(CAPACITY)); - let seed = std::env::var("SEED").unwrap_or_else(|_| SEED.to_string()); + let new_warps = rt.block_on(process::batch_create(num)); + println!("{:#?}", new_warps.len()); + let seed_warps = rt.block_on(process::batch_seed(new_warps)); + println!("{:#?}", seed_warps.len()); + let update_warps = rt.block_on(process::batch_update(seed_warps)); + println!("{:#?}", update_warps.len()); - let tasks: Vec<_> = iter(0..num) - .map(|_| { - let semaphore = semaphore.clone(); - let seed = seed.clone(); - async move { - let permit = semaphore.acquire_owned().await.unwrap(); - let license = match client::WARP::build().await { - Ok(mut a) => a.get_license(seed).await.unwrap(), - Err(_) => format!("error"), - }; + rt.block_on(process::batch_info(update_warps.clone())); - println!("{}", license); - drop(permit); - } - }) - .collect().await; + let delete_warps = rt.block_on(process::batch_update(update_warps)); + println!("{:#?}", delete_warps.len()); - for task in tasks { - task.await; + for warp in &delete_warps{ + println!("{}", warp.license()); } Ok(()) } - -pub fn interface(num: usize) -> Result<(), Box> { - let rt = tokio::runtime::Builder::new_current_thread() - .enable_all() - .build() - .unwrap(); - - println!("Processing num: {:?}", num); - let _ = rt.block_on(run_tokio(num)); - Ok(()) -}