From 2d9314aa3145ec7948341f38164e13c2a2d945ad Mon Sep 17 00:00:00 2001 From: A Farzat Date: Wed, 11 Feb 2026 11:13:36 +0300 Subject: Add a login check Try to access the profile page to see if the cookies work or not. --- Cargo.lock | 13 +++++++++++++ Cargo.toml | 1 + src/main.rs | 18 ++++++++++++++++-- src/orly.rs | 22 ++++++++++++++++++++++ 4 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 src/orly.rs diff --git a/Cargo.lock b/Cargo.lock index 6d02809..ef277f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1006,6 +1006,7 @@ dependencies = [ "reqwest", "serde", "serde_json", + "tokio", "tracing", "tracing-subscriber", ] @@ -1265,9 +1266,21 @@ dependencies = [ "mio", "pin-project-lite", "socket2", + "tokio-macros", "windows-sys 0.61.2", ] +[[package]] +name = "tokio-macros" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tokio-rustls" version = "0.26.4" diff --git a/Cargo.toml b/Cargo.toml index dc2f515..42e52da 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,5 +10,6 @@ colored = "3.1" reqwest = { version = "0.13", default-features = false, features = ["rustls"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" +tokio = { version = "1.49", features = ["rt-multi-thread", "macros"] } tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt"] } diff --git a/src/main.rs b/src/main.rs index 6981b8e..f79f191 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,14 +3,18 @@ mod config; mod cookies; mod display; mod http_client; +mod orly; use clap::Parser; use cli::Args; use cookies::CookieStore; use display::Display; use http_client::HttpClient; +use orly::check_login; +use reqwest::Client; -fn main() { +#[tokio::main] +async fn main() { let args = Args::parse(); let mut ui = Display::new(&args.bookid); @@ -40,12 +44,22 @@ fn main() { )); // Build the HTTP client with our cookies (no network calls yet). - let _client = match HttpClient::from_store(&store) { + let client = match HttpClient::from_store(&store) { Ok(c) => c, Err(e) => ui.error_and_exit(&format!("Failed to build HTTP client: {e}")), }; ui.info("HTTP client initialized with cookies (no requests performed)."); + // Check whether the cookies work (are we logged in?). + match check_login(&client).await { + Ok(true) => ui.info("Login confirmed..."), + Ok(false) => ui.error_and_exit( + "Logged out. Cookies could be stale or invalid.\n\ + Try refreshing your cookies.json and trying again.", + ), + Err(e) => ui.error_and_exit(&format!("Login check failed: {e}")), + }; + let output_dir = config::books_root().join(format!("(pending) ({})", args.bookid)); ui.set_output_dir(output_dir); diff --git a/src/orly.rs b/src/orly.rs new file mode 100644 index 0000000..cd8b645 --- /dev/null +++ b/src/orly.rs @@ -0,0 +1,22 @@ +use crate::http_client::HttpClient; +use anyhow::{bail, Result}; + +pub const PROFILE_URL: &str = "https://learning.oreilly.com/profile/"; + +/// Check whether cookies keep us logged in by fetching the profile page. +/// Returns: +/// - Ok(true) => HTTP 200 (assume logged in) +/// - Ok(false) => Redirect or 401/403 (assume not logged in) +/// - Err(..) => Network/other error +pub async fn check_login(client: &HttpClient) -> Result { + let res = client.client().get(PROFILE_URL).send().await?; + let status = res.status(); + + if status.is_redirection() { + Ok(false) + } else if status == 200 { + Ok(true) + } else { + bail!("Profile request returned unexpected status {}", status) + } +} -- cgit v1.2.3-70-g09d2