From a685f3709f3c886607aacb9e1138578aab6b852e Mon Sep 17 00:00:00 2001 From: Aravinth Manivannan Date: Fri, 27 Oct 2023 03:40:55 +0530 Subject: [PATCH] feat: parse webpage and compute PoW for widget --- Cargo.lock | 457 +++++++++++++++++++++++++++++++++++++++++++++++++++- Cargo.toml | 1 + README.md | 26 ++- src/main.rs | 196 +++++++++++++--------- 4 files changed, 591 insertions(+), 89 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0f26bf1..8f9fc1c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,19 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "ahash" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "anstream" version = "0.6.4" @@ -141,6 +154,12 @@ version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "bytes" version = "1.5.0" @@ -252,6 +271,29 @@ dependencies = [ "typenum", ] +[[package]] +name = "cssparser" +version = "0.31.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b3df4f93e5fbbe73ec01ec8d3f68bba73107993a5b1e7519273c32db9b0d5be" +dependencies = [ + "cssparser-macros", + "dtoa-short", + "itoa", + "phf 0.11.2", + "smallvec", +] + +[[package]] +name = "cssparser-macros" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" +dependencies = [ + "quote", + "syn 2.0.38", +] + [[package]] name = "darling" version = "0.14.4" @@ -318,6 +360,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "digest" version = "0.10.7" @@ -328,6 +381,27 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "dtoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" + +[[package]] +name = "dtoa-short" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbaceec3c6e4211c79e7b1800fb9680527106beb2f9c51904a3210c03a448c74" +dependencies = [ + "dtoa", +] + +[[package]] +name = "ego-tree" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a68a4904193147e0a8dec3314640e6db742afd5f6e634f428a6af230d9b3591" + [[package]] name = "encoding_rs" version = "0.8.33" @@ -393,6 +467,16 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "futf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" +dependencies = [ + "mac", + "new_debug_unreachable", +] + [[package]] name = "futures-channel" version = "0.3.28" @@ -432,6 +516,15 @@ dependencies = [ "pin-utils", ] +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -442,6 +535,26 @@ dependencies = [ "version_check", ] +[[package]] +name = "getopts" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "gimli" version = "0.28.0" @@ -485,6 +598,20 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" +[[package]] +name = "html5ever" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7" +dependencies = [ + "log", + "mac", + "markup5ever", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "http" version = "0.2.9" @@ -621,12 +748,42 @@ version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + [[package]] name = "log" version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +[[package]] +name = "mac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" + +[[package]] +name = "markup5ever" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016" +dependencies = [ + "log", + "phf 0.10.1", + "phf_codegen", + "string_cache", + "string_cache_codegen", + "tendril", +] + [[package]] name = "mcaptcha-cli" version = "0.2.0" @@ -634,6 +791,7 @@ dependencies = [ "clap", "mcaptcha_pow_sha256", "reqwest", + "scraper", "serde", "serde_json", "tokio", @@ -703,6 +861,12 @@ dependencies = [ "tempfile", ] +[[package]] +name = "new_debug_unreachable" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" + [[package]] name = "num" version = "0.4.1" @@ -860,12 +1024,115 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.4.1", + "smallvec", + "windows-targets", +] + [[package]] name = "percent-encoding" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +[[package]] +name = "phf" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" +dependencies = [ + "phf_shared 0.10.0", +] + +[[package]] +name = "phf" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_macros", + "phf_shared 0.11.2", +] + +[[package]] +name = "phf_codegen" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" +dependencies = [ + "phf_generator 0.10.0", + "phf_shared 0.10.0", +] + +[[package]] +name = "phf_generator" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" +dependencies = [ + "phf_shared 0.10.0", + "rand", +] + +[[package]] +name = "phf_generator" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +dependencies = [ + "phf_shared 0.11.2", + "rand", +] + +[[package]] +name = "phf_macros" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" +dependencies = [ + "phf_generator 0.11.2", + "phf_shared 0.11.2", + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher", +] + +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", +] + [[package]] name = "pin-project-lite" version = "0.2.13" @@ -884,6 +1151,18 @@ version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + [[package]] name = "proc-macro2" version = "1.0.69" @@ -902,6 +1181,36 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + [[package]] name = "redox_syscall" version = "0.3.5" @@ -911,6 +1220,15 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "reqwest" version = "0.11.22" @@ -985,6 +1303,28 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "scraper" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3693f9a0203d49a7ba8f38aa915316b3d535c1862d03dae7009cb71a3408b36a" +dependencies = [ + "ahash", + "cssparser", + "ego-tree", + "getopts", + "html5ever", + "once_cell", + "selectors", + "tendril", +] + [[package]] name = "security-framework" version = "2.9.2" @@ -1008,6 +1348,25 @@ dependencies = [ "libc", ] +[[package]] +name = "selectors" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eb30575f3638fc8f6815f448d50cb1a2e255b0897985c8c59f4d37b72a07b06" +dependencies = [ + "bitflags 2.4.1", + "cssparser", + "derive_more", + "fxhash", + "log", + "new_debug_unreachable", + "phf 0.10.1", + "phf_codegen", + "precomputed-hash", + "servo_arc", + "smallvec", +] + [[package]] name = "serde" version = "1.0.189" @@ -1051,6 +1410,15 @@ dependencies = [ "serde", ] +[[package]] +name = "servo_arc" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d036d71a959e00c77a63538b90a6c2390969f9772b096ea837205c6bd0491a44" +dependencies = [ + "stable_deref_trait", +] + [[package]] name = "sha2" version = "0.10.8" @@ -1062,6 +1430,12 @@ dependencies = [ "digest", ] +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + [[package]] name = "slab" version = "0.4.9" @@ -1071,6 +1445,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "smallvec" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" + [[package]] name = "socket2" version = "0.4.10" @@ -1091,6 +1471,38 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "string_cache" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" +dependencies = [ + "new_debug_unreachable", + "once_cell", + "parking_lot", + "phf_shared 0.10.0", + "precomputed-hash", + "serde", +] + +[[package]] +name = "string_cache_codegen" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988" +dependencies = [ + "phf_generator 0.10.0", + "phf_shared 0.10.0", + "proc-macro2", + "quote", +] + [[package]] name = "strsim" version = "0.10.0" @@ -1148,11 +1560,22 @@ checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" dependencies = [ "cfg-if", "fastrand", - "redox_syscall", + "redox_syscall 0.3.5", "rustix", "windows-sys", ] +[[package]] +name = "tendril" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" +dependencies = [ + "futf", + "mac", + "utf-8", +] + [[package]] name = "tinyvec" version = "1.6.0" @@ -1278,6 +1701,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-width" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" + [[package]] name = "url" version = "2.4.1" @@ -1290,6 +1719,12 @@ dependencies = [ "serde", ] +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + [[package]] name = "utf8parse" version = "0.2.1" @@ -1496,3 +1931,23 @@ dependencies = [ "cfg-if", "windows-sys", ] + +[[package]] +name = "zerocopy" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81ba595b9f2772fbee2312de30eeb80ec773b4cb2f1e8098db024afadda6c06f" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "772666c41fb6dceaf520b564b962d738a8e1a83b41bd48945f50837aed78bb1d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] diff --git a/Cargo.toml b/Cargo.toml index 7a322d5..3233bb6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,3 +17,4 @@ reqwest = { version = "0.11.18", features = ["json", "gzip", "native-tls-vendore serde = { version = "1.0.189", features = ["derive"] } serde_json = "1.0.107" url = { version = "2.4.1", features = ["serde"] } +scraper = "0.18.0" diff --git a/README.md b/README.md index c6c9f66..a48887d 100644 --- a/README.md +++ b/README.md @@ -17,22 +17,23 @@ ### Modes: 1. Offline: Computes PoW over given CAPTCHA parameters -2. Online: CLI alternative for people using browsers without JavaScript - support +2. Protected Page: Compute mCaptcha challenge for the CAPTCHA at a + protected page +3. Widget URL: Compute PoW for captcha at widget URL ```bash -CLI tool to solve mCaptcha - Usage: mcaptcha-cli Commands: - offline Compute PoW with offline parameters - online Compute PoW by fetching parameters from CAPTCHA URL - help Print this message or the help of the given subcommand(s) + offline Compute PoW with offline parameters + protected-page Compute PoW by fetching parameters from protected page URL + widget-url Compute PoW by fetching parameters from CAPTCHA URL + help Print this message or the help of the given subcommand(s) Options: -h, --help Print help -V, --version Print version + ``` #### Offline @@ -65,7 +66,16 @@ result: 340276562956196291522979356090220150471 [this](https://github.com/realaravinth/dotfiles/blob/6fc6c87cc912e17488a35c0d3327ecf393221270/scripts/rand#L20) script) -#### Online +#### Protected Page + +Used to generate authorization tokens for CAPTCHA at a protected page + +```bash +03:39 atm@lab cli ±|feat-parse-webpage ✗|→ mcaptcha-cli protected-page https://showcase.mcaptcha.org/ +Authorization token: eRAZJiMrW58uDYA1s64Tmwq1u30HutuF +``` + +#### Widget URL Fetches CAPTCHA parameters from CAPTCHA URL, computes PoW, validates against given mCaptcha server and returns authorization token diff --git a/src/main.rs b/src/main.rs index 6339d24..fc80f12 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,6 +10,7 @@ use clap::*; use mcaptcha_pow_sha256::ConfigBuilder; use mcaptcha_pow_sha256::PoW; use reqwest::Client; +use scraper::{Html, Selector}; use serde::{Deserialize, Serialize}; use url::Url; @@ -30,14 +31,114 @@ struct Offline { } #[derive(Deserialize, Parser, Serialize, Clone, Debug)] -/// Compute PoW by fetching parameters from CAPTCHA URL -struct Online { - /// URL of the CAPTCHA. Example: https://example.org/widget?sitekey=foo - #[arg(short, long)] +/// Compute PoW by fetching parameters from protected page URL +struct ProtectedPage { + /// URL of the protected page. Example: https://example.org/protected.html url: Url, } -impl Online { +impl ProtectedPage { + async fn extract_url(self) -> Option { + let c = Client::default(); + let text = c.get(self.url).send().await.unwrap().text().await.unwrap(); + let fragement = Html::parse_fragment(&text); + let selector = Selector::parse("label#mcaptcha__token-label").unwrap(); + if let Some(label) = fragement.select(&selector).next() { + if let Some(val) = label.value().attr("data-mcaptcha_url") { + if let Ok(url) = Url::parse(val) { + return Some(WidgetUrl { url }); + } + } + } + + None + } +} + +#[derive(Deserialize, Parser, Serialize, Clone, Debug)] +/// Compute PoW by fetching parameters from CAPTCHA URL +struct WidgetUrl { + url: Url, +} + +impl WidgetUrl { + async fn run(&self) { + let c = Client::default(); + let sitekey = self.extract_sitekey(); + + if sitekey.is_none() { + println!("ERROR: Sitekey not found in URL. Please enter correct URL"); + return; + } + let sitekey = sitekey.unwrap(); + + let url = self.get_config_url(); + + #[derive(Clone, Debug, Serialize, Deserialize)] + struct ConfigRequest { + key: String, + } + + #[derive(Clone, Debug, Serialize, Deserialize)] + struct ConfigResp { + string: String, + difficulty_factor: u32, + salt: String, + } + let req = ConfigRequest { + key: sitekey.to_string(), + }; + + let resp: ConfigResp = c + .post(url) + .json(&req) + .send() + .await + .unwrap() + .json() + .await + .unwrap(); + let start = Instant::now(); + let work = prove_work(resp.string.clone(), resp.salt, resp.difficulty_factor); + let finish = Instant::now(); + let time_elapsed = finish.duration_since(start); + let time = time_elapsed.as_millis() as usize; + + #[derive(Clone, Debug, Serialize, Deserialize)] + struct VerifyRequest { + key: String, + nonce: u64, + result: String, + string: String, + time: usize, + worker_type: String, + } + + #[derive(Clone, Debug, Serialize, Deserialize)] + struct VerifyResp { + token: String, + } + + let req = VerifyRequest { + key: sitekey.clone(), + nonce: work.nonce, + result: work.result, + string: resp.string, + time, + worker_type: String::from("mCaptcha CLI"), + }; + let url = self.get_verify_url(); + let resp: VerifyResp = c + .post(url) + .json(&req) + .send() + .await + .unwrap() + .json() + .await + .unwrap(); + println!("Authorization token: {}", resp.token); + } fn extract_sitekey(&self) -> Option { let mut sitekey = None; for (k, v) in self.url.query_pairs() { @@ -67,7 +168,8 @@ impl Online { #[command(author, version, about, long_about = None)] enum Args { Offline(Offline), - Online(Online), + ProtectedPage(ProtectedPage), + WidgetUrl(WidgetUrl), } fn prove_work(phrase: String, salt: String, difficulty_factor: u32) -> PoW { @@ -92,82 +194,16 @@ async fn main() { println!("original phrase: {}", &phrase); println!("result: {}", &work.result); } - Args::Online(matches) => { - let sitekey = matches.extract_sitekey(); + Args::WidgetUrl(matches) => { + matches.run().await; + } - if sitekey.is_none() { - println!("ERROR: Sitekey not found in URL. Please enter correct URL"); - return; - } - let sitekey = sitekey.unwrap(); - - let c = Client::default(); - let url = matches.get_config_url(); - - #[derive(Clone, Debug, Serialize, Deserialize)] - struct ConfigRequest { - key: String, - } - - #[derive(Clone, Debug, Serialize, Deserialize)] - struct ConfigResp { - string: String, - difficulty_factor: u32, - salt: String, - } - let req = ConfigRequest { - key: sitekey.to_string(), - }; - - let resp: ConfigResp = c - .post(url) - .json(&req) - .send() + Args::ProtectedPage(matches) => { + let widget = matches + .extract_url() .await - .unwrap() - .json() - .await - .unwrap(); - let start = Instant::now(); - let work = prove_work(resp.string.clone(), resp.salt, resp.difficulty_factor); - let finish = Instant::now(); - let time_elapsed = finish.duration_since(start); - let time = time_elapsed.as_millis() as usize; - - #[derive(Clone, Debug, Serialize, Deserialize)] - struct VerifyRequest { - key: String, - nonce: u64, - result: String, - string: String, - time: usize, - worker_type: String, - } - - #[derive(Clone, Debug, Serialize, Deserialize)] - struct VerifyResp { - token: String, - } - - let req = VerifyRequest { - key: sitekey.clone(), - nonce: work.nonce, - result: work.result, - string: resp.string, - time, - worker_type: String::from("mCaptcha CLI"), - }; - let url = matches.get_verify_url(); - let resp: VerifyResp = c - .post(url) - .json(&req) - .send() - .await - .unwrap() - .json() - .await - .unwrap(); - println!("Authorization token: {}", resp.token); + .unwrap_or_else(|| panic!("No mCaptcha widget found in the web page")); + widget.run().await; } } }