Skip to content

Commit

Permalink
fix(service/icloud):Missing 'X-APPLE-WEBAUTH-USER cookie' and URL ini…
Browse files Browse the repository at this point in the history
…tialized failed (#4029)

* fix(service/icloud):Missing 'X-APPLE-WEBAUTH-USER cookie' and URL not securely initialized

Signed-off-by: bokket <[email protected]>

* remove

Signed-off-by: bokket <[email protected]>

* change init logic

Signed-off-by: bokket <[email protected]>

* add cookies

Signed-off-by: bokket <[email protected]>

* refactor:use get_all headers instead loop

Signed-off-by: bokket <[email protected]>

* remove

Signed-off-by: bokket <[email protected]>

* fmt

Signed-off-by: bokket <[email protected]>

* delete

Signed-off-by: bokket <[email protected]>

---------

Signed-off-by: bokket <[email protected]>
  • Loading branch information
bokket authored Jan 22, 2024
1 parent 0fad910 commit 6dfd402
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 79 deletions.
56 changes: 0 additions & 56 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
Expand Down Expand Up @@ -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"]
Expand Down
2 changes: 0 additions & 2 deletions core/src/raw/http_util/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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| {
Expand Down
77 changes: 58 additions & 19 deletions core/src/services/icloud/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -68,7 +69,7 @@ pub struct SessionData {

scnt: Option<String>,
account_country: Option<String>,

cookies: BTreeMap<String, String>,
drivews_url: String,
docws_url: String,
}
Expand All @@ -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(),
}
Expand Down Expand Up @@ -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.
Expand All @@ -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!({
Expand All @@ -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 {
Expand All @@ -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)
Expand All @@ -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)?;
Expand All @@ -185,6 +204,7 @@ impl IcloudSigner {
self.data.docws_url = v.to_string();
}

self.initiated = true;
Ok(())
}

Expand Down Expand Up @@ -224,6 +244,19 @@ impl IcloudSigner {
);
}

if !self.data.cookies.is_empty() {
let cookies: Vec<String> = 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)?);
}
Expand All @@ -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());
}
Expand All @@ -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(())
}

Expand All @@ -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)
}
Expand Down Expand Up @@ -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!([
Expand Down Expand Up @@ -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
);
Expand Down Expand Up @@ -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!([
Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit 6dfd402

Please sign in to comment.