From 1555eff02d658d80027b17dbc3b43a4b572504a7 Mon Sep 17 00:00:00 2001 From: Anton Hurlenko Date: Fri, 20 Oct 2023 19:10:41 +0300 Subject: [PATCH] Use app API for password authorization --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/client.rs | 42 +++++++++++++++++++++++++++++++++++------- src/error.rs | 2 ++ src/models.rs | 5 +++++ 5 files changed, 44 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c4c9a98..45fa2ed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1564,7 +1564,7 @@ dependencies = [ [[package]] name = "orly" -version = "0.1.4" +version = "0.1.5" dependencies = [ "anyhow", "askama", diff --git a/Cargo.toml b/Cargo.toml index 457d119..8f17af3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "orly" -version = "0.1.4" +version = "0.1.5" edition = "2021" authors = ["hurlenko"] description = "Download O'Reilly books as EPUB" diff --git a/src/client.rs b/src/client.rs index 0eb8009..a3b8d8a 100644 --- a/src/client.rs +++ b/src/client.rs @@ -5,7 +5,7 @@ use chrono::{DateTime, Local, NaiveDate}; use futures::stream::{self, StreamExt}; use anyhow::Context; -use log::{error, info, trace}; +use log::{debug, error, info, trace}; use reqwest::{ header::{ HeaderMap, HeaderValue, ACCEPT, ACCEPT_ENCODING, COOKIE, UPGRADE_INSECURE_REQUESTS, @@ -16,7 +16,10 @@ use reqwest::{ use crate::{ error::{OrlyError, Result}, - models::{BillingInfo, Book, Chapter, ChapterMeta, ChaptersResponse, Credentials, TocElement}, + models::{ + BillingInfo, Book, Chapter, ChapterMeta, ChaptersResponse, Credentials, LoginLookup, + TocElement, + }, }; pub struct Authenticated; @@ -71,10 +74,10 @@ impl OreillyClient { fn default_client() -> ClientBuilder { let mut headers = HeaderMap::new(); - headers.insert(ACCEPT, HeaderValue::from_static("application/json,text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8")); + headers.insert(ACCEPT, HeaderValue::from_static("*/*")); headers.insert(ACCEPT_ENCODING, HeaderValue::from_static("gzip, deflate")); headers.insert(UPGRADE_INSECURE_REQUESTS, HeaderValue::from_static("1")); - headers.insert(USER_AGENT, HeaderValue::from_static("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36")); + headers.insert(USER_AGENT, HeaderValue::from_static("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36")); reqwest::Client::builder() .default_headers(headers) .cookie_store(true) @@ -116,19 +119,44 @@ impl OreillyClient { email: &str, password: &str, ) -> Result> { - info!("Logging into Safari Books Online..."); - let mut map = HashMap::new(); map.insert("email", email); + + info!("Checking if password login is possible"); + let response = self + .client + .post("https://api.oreilly.com/api/m/v2/auth/lookup/") + .json(&map) + .send() + .await?; + + debug!("Email lookup response: {:#?}", response); + + let login_lookup = response.json::().await?; + + if !login_lookup.password_login_allowed { + return Err(crate::error::OrlyError::PasswordLoginUnsupported( + email.to_string(), + )); + } + + info!("Logging into Safari Books Online..."); + map.insert("password", password); let response = self .client - .post("https://www.oreilly.com/member/auth/login/") + .post("https://api.oreilly.com/api/v1/auth/login/") .json(&map) + .basic_auth( + "052079", + Some("00a63c08e9d240b6f4f14b93a135da227e8b9da99103db38c4b4eb4c"), + ) .send() .await?; + debug!("Auth response: {:#?}", response); + if let Err(err) = response.error_for_status_ref() { return Err(OrlyError::AuthenticationFailed(format!( "Login request failed, make sure your email and password are correct: {}", diff --git a/src/error.rs b/src/error.rs index 82030f2..a16d9a7 100644 --- a/src/error.rs +++ b/src/error.rs @@ -14,6 +14,8 @@ pub enum OrlyError { AuthenticationFailed(String), #[error("Subscription expired")] SubscriptionExpired, + #[error("Password login is not supported for account {0}")] + PasswordLoginUnsupported(String), #[error(transparent)] Other(#[from] anyhow::Error), } diff --git a/src/models.rs b/src/models.rs index e95c906..34616d3 100644 --- a/src/models.rs +++ b/src/models.rs @@ -50,6 +50,11 @@ pub(crate) struct Credentials { pub logged_in: bool, } +#[derive(Deserialize, Debug)] +pub(crate) struct LoginLookup { + pub password_login_allowed: bool, +} + #[derive(Deserialize, Debug)] pub struct Author { pub name: String,