-
Notifications
You must be signed in to change notification settings - Fork 753
fix(service/icloud):Missing 'X-APPLE-WEBAUTH-USER cookie' and URL initialized failed #4029
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
d27b8d4
aabad85
9c2fc1f
f631dcf
7ea07cd
fd3ac15
82c817b
126b552
58059cc
c930f6f
e3694d1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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<String>, | ||
| account_country: Option<String>, | ||
|
|
||
| cookies: BTreeMap<String, String>, | ||
| 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<String> = self | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We don't need this because reqwest automatically loads and sets
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Apple server will check 'X-APPLE-WEBAUTH-USER cookie' in cookies.If we don't update in
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
We don't need to. |
||
| .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<String> = 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<AsyncBody>, | ||
| ) -> Result<Response<IncomingAsyncBody>> { | ||
| // 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<String> { | ||
| 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, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please check
self.initiatedfirst. Or we can move the check intoinit()directly.