diff --git a/Cargo.lock b/Cargo.lock index bc3f389..c92fc87 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "autocfg" version = "0.1.7" @@ -12,6 +14,12 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" +[[package]] +name = "base-x" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b" + [[package]] name = "base64" version = "0.12.3" @@ -121,6 +129,39 @@ dependencies = [ "bitflags", ] +[[package]] +name = "const_fn" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f92cfa0fd5690b3cf8c1ef2cabbd9b7ef22fa53cf5e1f92b05103f6d5d1cf6e7" + +[[package]] +name = "cookie" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03a5d7b21829bc7b4bf4754a978a241ae54ea55a40f92bb20216e54096f4b951" +dependencies = [ + "percent-encoding", + "time 0.2.25", + "version_check", +] + +[[package]] +name = "cookie_store" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3818dfca4b0cb5211a659bbcbb94225b7127407b2b135e650d717bfb78ab10d3" +dependencies = [ + "cookie", + "idna", + "log", + "publicsuffix", + "serde", + "serde_json", + "time 0.2.25", + "url", +] + [[package]] name = "core-foundation" version = "0.9.1" @@ -199,6 +240,12 @@ dependencies = [ "generic-array 0.14.4", ] +[[package]] +name = "discard" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" + [[package]] name = "dtoa" version = "0.4.6" @@ -229,6 +276,15 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "error-chain" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" +dependencies = [ + "version_check", +] + [[package]] name = "fake-simd" version = "0.1.2" @@ -441,7 +497,7 @@ dependencies = [ "http", "mime", "sha-1 0.8.2", - "time", + "time 0.1.44", ] [[package]] @@ -721,7 +777,7 @@ dependencies = [ [[package]] name = "modem_status" -version = "0.1.0" +version = "0.2.0" dependencies = [ "base64 0.13.0", "lazy_static", @@ -998,6 +1054,19 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "publicsuffix" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bbaa49075179162b49acac1c6aa45fb4dafb5f13cf6794276d77bc7fd95757b" +dependencies = [ + "error-chain", + "idna", + "lazy_static", + "regex", + "url", +] + [[package]] name = "quick-error" version = "1.2.3" @@ -1185,6 +1254,21 @@ version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" +[[package]] +name = "regex" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +dependencies = [ + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + [[package]] name = "remove_dir_all" version = "0.5.3" @@ -1202,6 +1286,8 @@ checksum = "e9eaa17ac5d7b838b7503d118fa16ad88f440498bf9ffe5424e621f93190d61e" dependencies = [ "base64 0.12.3", "bytes", + "cookie", + "cookie_store", "encoding_rs", "futures-core", "futures-util", @@ -1220,6 +1306,7 @@ dependencies = [ "pin-project-lite", "serde", "serde_urlencoded", + "time 0.2.25", "tokio", "tokio-tls", "url", @@ -1229,6 +1316,15 @@ dependencies = [ "winreg", ] +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver", +] + [[package]] name = "ryu" version = "1.0.5" @@ -1315,6 +1411,21 @@ dependencies = [ "thin-slice", ] +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + [[package]] name = "serde" version = "1.0.117" @@ -1393,6 +1504,12 @@ dependencies = [ "opaque-debug 0.3.0", ] +[[package]] +name = "sha1" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" + [[package]] name = "siphasher" version = "0.3.3" @@ -1429,6 +1546,64 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "standback" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff" +dependencies = [ + "version_check", +] + +[[package]] +name = "stdweb" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" +dependencies = [ + "discard", + "rustc_version", + "stdweb-derive", + "stdweb-internal-macros", + "stdweb-internal-runtime", + "wasm-bindgen", +] + +[[package]] +name = "stdweb-derive" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "serde_derive", + "syn", +] + +[[package]] +name = "stdweb-internal-macros" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" +dependencies = [ + "base-x", + "proc-macro2", + "quote", + "serde", + "serde_derive", + "serde_json", + "sha1", + "syn", +] + +[[package]] +name = "stdweb-internal-runtime" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" + [[package]] name = "string_cache" version = "0.8.0" @@ -1507,6 +1682,44 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "time" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1195b046942c221454c2539395f85413b33383a067449d78aab2b7b052a142f7" +dependencies = [ + "const_fn", + "libc", + "standback", + "stdweb", + "time-macros", + "version_check", + "winapi 0.3.9", +] + +[[package]] +name = "time-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1" +dependencies = [ + "proc-macro-hack", + "time-macros-impl", +] + +[[package]] +name = "time-macros-impl" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f" +dependencies = [ + "proc-macro-hack", + "proc-macro2", + "quote", + "standback", + "syn", +] + [[package]] name = "tinyvec" version = "1.0.1" diff --git a/Cargo.toml b/Cargo.toml index 29ca021..63feb2f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "modem_status" -version = "0.1.0" +version = "0.2.0" authors = ["Matthew Donoughe "] edition = "2018" @@ -12,7 +12,7 @@ name = "modem_status" [dependencies] base64 = "0.13" lazy_static = "1" -reqwest = "0.10" +reqwest = { version = "0.10", features = ["cookies"] } serde = { version = "1", features = ["derive"] } tokio = { version = "0.2", features = ["macros", "rt-threaded"] } unhtml = { version = "0.8", features = ["derive"] } diff --git a/README.md b/README.md index fd36487..ba75f52 100644 --- a/README.md +++ b/README.md @@ -5,10 +5,10 @@ This is a small tool to workaround a firmware upgrade Comcast pushed out to my A The modem firmware is pretty terrible, so the process is: 1. Send HTTP Basic authorization *and* the same "user:password" token as a query string (not a query string parameter) to the status page. On success, the status page will be replaced by a token. On failure, the status page will be replaced by the login page. -2. Request the status page again, sending the token as an HTTP cookie. +2. Request the status page again, sending the token as a query string (again, not a query parameter). 3. Request logout.html to clean up resources. If you do not do this, a resource will be exhausted and you will no longer be able to log in until logout.html is requested. -The modem interface is loaded over TLS 1.2, but using an expired, insecure, self-signed certificate that is not valid for the modem IP or even server identification. I assume all users have the same private key embedded in their firmware. The security is so bad that actually Windows software may refuse to connect, probably because of the md5RSA signature algorithm. +The modem interface is loaded over TLS 1.2, but using a self-signed certificate that is not valid for the modem IP or even server identification. I assume all users have the same private key embedded in their firmware. ## Usage @@ -16,7 +16,7 @@ Configure the environment variables: - `MODEM_IP`: The IP address of the modem. The default of 192.168.100.1 is probably correct. - `MODEM_USER`: The username for authenticating to the modem. The default of admin is probably correct. -- `MODEM_PASSWORD`: The password for authenticating to the modem. If you haven't changed it, it is the last eight characters of the serial number printed on the bottom of the modem, in uppercase. +- `MODEM_PASSWORD`: The password for authenticating to the modem. If you haven't changed it already, it is the last eight characters of the serial number printed on the bottom of the modem, in uppercase. You must log in to the modem and change the password at least once before using this program. Run modem_status. diff --git a/src/main.rs b/src/main.rs index e0a24ce..91f1067 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,7 +13,7 @@ lazy_static! { static ref MODEM_PASSWORD: Option = env::var("MODEM_PASSWORD").ok(); static ref AUTH_URL: Option> = MODEM_PASSWORD.as_ref().map(|password| Url::parse(&format!( - "https://{}/cmconnectionstatus.html?{}", + "https://{}/cmconnectionstatus.html?login_{}", MODEM_IP.as_ref(), base64::encode(format!("{}:{}", MODEM_USER.as_ref(), password)) ))); @@ -88,11 +88,10 @@ async fn test( Ok(token) => token, Err(error) => return Err(error), }; + let mut status_url = STATUS_URL.as_ref().unwrap().clone(); + status_url.set_query(Some(&format!("ct_{}", token))); let request = client - .get(STATUS_URL.as_ref().unwrap().clone()) - // the modem has a bug where the host header must come before the cookies - .header(reqwest::header::HOST, MODEM_IP.clone().into_owned()) - .header(reqwest::header::COOKIE, format!("credential={}", token)) + .get(status_url) .build() .unwrap(); match client.execute(request).await { @@ -129,9 +128,13 @@ async fn test( } } -async fn test_handler( - client: reqwest::Client, -) -> Result { +async fn test_handler() -> Result { + let client = reqwest::Client::builder() + .cookie_store(true) + .danger_accept_invalid_certs(true) + .build() + .unwrap(); + test(client) .await .map_or_else(|e| Ok(e.into_response()), |r| Ok(r.into_response())) @@ -139,12 +142,7 @@ async fn test_handler( #[tokio::main] async fn main() { - let client = reqwest::Client::builder() - .danger_accept_invalid_certs(true) - .build() - .unwrap(); - - let health = warp::path!("health").and_then(move || test_handler(client.clone())); + let health = warp::path!("health").and_then(test_handler); warp::serve(health).run(([0, 0, 0, 0], 3030)).await; }