diff --git a/Cargo.lock b/Cargo.lock index 0381b429dd0..03cb8b4e56a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1532,34 +1532,6 @@ dependencies = [ "unicode-segmentation", ] -[[package]] -name = "cookie" -version = "0.16.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb" -dependencies = [ - "percent-encoding", - "time", - "version_check", -] - -[[package]] -name = "cookie_store" -version = "0.16.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d606d0fba62e13cf04db20536c05cb7f13673c161cb47a47a82b9b9e7d3f1daa" -dependencies = [ - "cookie", - "idna 0.2.3", - "log", - "publicsuffix", - "serde", - "serde_derive", - "serde_json", - "time", - "url", -] - [[package]] name = "core-foundation" version = "0.9.3" @@ -3306,16 +3278,6 @@ dependencies = [ "unicode-normalization", ] -[[package]] -name = "idna" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - [[package]] name = "idna" version = "0.4.0" @@ -5624,12 +5586,6 @@ version = "2.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94" -[[package]] -name = "psl-types" -version = "2.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac" - [[package]] name = "ptr_meta" version = "0.1.4" @@ -5650,16 +5606,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "publicsuffix" -version = "2.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96a8c1bda5ae1af7f99a2962e49df150414a43d62404644d98dd5c3a93d07457" -dependencies = [ - "idna 0.3.0", - "psl-types", -] - [[package]] name = "pulldown-cmark" version = "0.9.3" @@ -6096,8 +6042,6 @@ checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" dependencies = [ "base64 0.21.5", "bytes", - "cookie", - "cookie_store", "encoding_rs", "futures-core", "futures-util", diff --git a/core/Cargo.toml b/core/Cargo.toml index ec73bb49395..276aa7f2f17 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -75,7 +75,6 @@ native-tls-vendored = ["reqwest/native-tls-vendored"] # Enable path cache. # This is an internal feature, and should not be used by users. internal-path-cache = ["dep:moka"] -internal-http-cookies = ["reqwest/cookies"] # Enable all layers. layers-all = [ @@ -155,7 +154,7 @@ services-http = [] services-huggingface = [] services-ipfs = ["dep:prost"] services-ipmfs = [] -services-icloud = ["internal-path-cache", "internal-http-cookies"] +services-icloud = ["internal-path-cache"] services-koofr = [] services-libsql = ["dep:hrana-client-proto"] services-memcached = ["dep:bb8"] diff --git a/core/src/raw/http_util/client.rs b/core/src/raw/http_util/client.rs index e4d47d88e86..2c5e4bc5c78 100644 --- a/core/src/raw/http_util/client.rs +++ b/core/src/raw/http_util/client.rs @@ -69,8 +69,6 @@ impl HttpClient { #[cfg(feature = "trust-dns")] let builder = builder.trust_dns(true); - #[cfg(feature = "internal-http-cookies")] - let builder = builder.cookie_store(true); Ok(Self { client: builder.build().map_err(|err| { diff --git a/core/src/services/icloud/core.rs b/core/src/services/icloud/core.rs index dcf6525f73b..0430e954fb3 100644 --- a/core/src/services/icloud/core.rs +++ b/core/src/services/icloud/core.rs @@ -17,6 +17,7 @@ use async_trait::async_trait; use bytes::{Buf, Bytes}; +use std::collections::BTreeMap; use std::fmt::{Debug, Formatter}; use std::sync::Arc; @@ -68,7 +69,7 @@ pub struct SessionData { scnt: Option, account_country: Option, - + cookies: BTreeMap, drivews_url: String, docws_url: String, } @@ -81,6 +82,8 @@ impl SessionData { session_token: None, scnt: None, account_country: None, + + cookies: BTreeMap::default(), drivews_url: String::new(), docws_url: String::new(), } @@ -110,9 +113,18 @@ impl Debug for IcloudSigner { } impl IcloudSigner { - /// Get the session data from signer. - pub fn session_data(&self) -> &SessionData { - &self.data + /// Get the drivews_url from signer session data. + /// Async await init finish. + pub async fn drivews_url(&mut self) -> Result<&str> { + self.init().await?; + Ok(&self.data.drivews_url) + } + + /// Get the docws_url from signer session data. + /// Async await init finish. + pub async fn docws_url(&mut self) -> Result<&str> { + self.init().await?; + Ok(&self.data.docws_url) } /// iCloud will use our oauth state as client id. @@ -121,6 +133,10 @@ impl IcloudSigner { } async fn init(&mut self) -> Result<()> { + if self.initiated { + return Ok(()); + } + // Sign the auth endpoint first. let uri = format!("{}/signin?isRememberMeEnable=true", AUTH_ENDPOINT); let body = serde_json::to_vec(&json!({ @@ -141,6 +157,7 @@ impl IcloudSigner { if resp.status() != StatusCode::OK { return Err(parse_error(resp).await?); } + if let Some(rscd) = resp.headers().get(APPLE_RESPONSE_HEADER) { let status_code = StatusCode::from_bytes(rscd.as_bytes()).unwrap(); if status_code != StatusCode::CONFLICT { @@ -154,8 +171,7 @@ impl IcloudSigner { "accountCountryCode": self.data.account_country.clone().unwrap_or_default(), "dsWebAuthToken":self.ds_web_auth_token.clone().unwrap_or_default(), "extended_login": true, - "trustToken": self.trust_token.clone().unwrap_or_default(), - })) + "trustToken": self.trust_token.clone().unwrap_or_default(),})) .map_err(new_json_serialize_error)?; let mut req = Request::post(uri) @@ -169,6 +185,9 @@ impl IcloudSigner { return Err(parse_error(resp).await?); } + // Updata SessionData cookies.We need obtain `X-APPLE-WEBAUTH-USER` cookie to get file. + self.update(&resp)?; + let bs = resp.into_body().bytes().await?; let auth_info: IcloudWebservicesResponse = serde_json::from_slice(&bs).map_err(new_json_deserialize_error)?; @@ -185,6 +204,7 @@ impl IcloudSigner { self.data.docws_url = v.to_string(); } + self.initiated = true; Ok(()) } @@ -224,6 +244,19 @@ impl IcloudSigner { ); } + if !self.data.cookies.is_empty() { + let cookies: Vec = self + .data + .cookies + .iter() + .map(|(k, v)| format!("{}={}", k, v)) + .collect(); + headers.insert( + header::COOKIE, + build_header_value(&cookies.as_slice().join("; "))?, + ); + } + for (key, value) in AUTH_HEADERS { headers.insert(key, build_header_value(value)?); } @@ -237,7 +270,6 @@ impl IcloudSigner { { self.data.account_country = Some(account_country.to_string()); } - if let Some(session_id) = parse_header_to_str(resp.headers(), SESSION_ID_HEADER)? { self.data.session_id = Some(session_id.to_string()); } @@ -249,6 +281,19 @@ impl IcloudSigner { self.data.scnt = Some(scnt.to_string()); } + let cookies: Vec = resp + .headers() + .get_all(header::SET_COOKIE) + .iter() + .map(|v| v.to_str().unwrap().to_string()) + .collect(); + + for cookie in cookies { + if let Some((key, value)) = cookie.split_once('=') { + self.data.cookies.insert(key.into(), value.into()); + } + } + Ok(()) } @@ -261,15 +306,8 @@ impl IcloudSigner { &mut self, mut req: Request, ) -> Result> { - // Init the signer first. - if self.initiated { - self.init().await?; - self.initiated = true; - } - self.sign(&mut req)?; let resp = self.client.send(req).await?; - self.update(&resp)?; Ok(resp) } @@ -297,7 +335,7 @@ impl IcloudCore { let uri = format!( "{}/retrieveItemDetailsInFolders", - signer.session_data().drivews_url + signer.drivews_url().await? ); let body = serde_json::to_vec(&json!([ @@ -333,7 +371,7 @@ impl IcloudCore { let uri = format!( "{}/ws/{}/download/by_id?document_id={}", - signer.session_data().drivews_url, + signer.docws_url().await?, zone, id ); @@ -454,7 +492,7 @@ impl PathQuery for IcloudPathQuery { let uri = format!( "{}/retrieveItemDetailsInFolders", - signer.session_data().drivews_url + signer.drivews_url().await? ); let body = serde_json::to_vec(&json!([ @@ -489,9 +527,10 @@ impl PathQuery for IcloudPathQuery { async fn create_dir(&self, parent_id: &str, name: &str) -> Result { let mut signer = self.signer.lock().await; - let client_id = signer.client_id(); - let uri = format!("{}/createFolders", signer.session_data().drivews_url); + let client_id = signer.client_id().to_string(); + + let uri = format!("{}/createFolders", signer.drivews_url().await?); let body = serde_json::to_vec(&json!( { "destinationDrivewsId": parent_id,