Dadoum commited on 2026-09-28 03:11:40
Showing 3 changed files, with 55 additions and 11 deletions.
| ... | ... |
@@ -239,28 +239,31 @@ impl TryFrom<u64> for StatusCode {
|
| 239 | 239 |
#[serde(transparent)] |
| 240 | 240 |
pub struct ContinuationToken(String); |
| 241 | 241 |
|
| 242 |
+/// Authenticate with an Apple Account username or AltDSID and a password. |
|
| 243 |
+/// Pass `alt_dsid.as_ref()` to use a typed `AltDsid`. |
|
| 242 | 244 |
pub async fn login( |
| 243 | 245 |
http_session: &AnisetteHTTPSession<'_, '_>, |
| 244 |
- apple_id: &str, |
|
| 246 |
+ user: &str, |
|
| 245 | 247 |
password: &str, |
| 246 | 248 |
) -> AuthResult {
|
| 247 |
- login_with_credential(http_session, apple_id, LoginCredential::Password(password)).await |
|
| 249 |
+ login_with_credential(http_session, user, LoginCredential::Password(password)).await |
|
| 248 | 250 |
} |
| 249 | 251 |
|
| 250 | 252 |
/// Authenticate using a previously issued continuation token instead of a password. |
| 251 | 253 |
/// |
| 252 |
-/// Use the Apple ID and device identity associated with the token. The server can |
|
| 254 |
+/// `user` may be an Apple Account username or AltDSID (`alt_dsid.as_ref()`). |
|
| 255 |
+/// Use the account and device identity associated with the token. The server can |
|
| 253 | 256 |
/// still require a secondary action or reject a revoked token; callers decide |
| 254 | 257 |
/// whether to fall back to password authentication. Extract the token from the |
| 255 | 258 |
/// returned server-provided data again after success to pick up a replacement. |
| 256 | 259 |
pub async fn login_with_continuation_token( |
| 257 | 260 |
http_session: &AnisetteHTTPSession<'_, '_>, |
| 258 |
- apple_id: &str, |
|
| 261 |
+ user: &str, |
|
| 259 | 262 |
continuation_token: &ContinuationToken, |
| 260 | 263 |
) -> AuthResult {
|
| 261 | 264 |
login_with_credential( |
| 262 | 265 |
http_session, |
| 263 |
- apple_id, |
|
| 266 |
+ user, |
|
| 264 | 267 |
LoginCredential::ContinuationToken(continuation_token), |
| 265 | 268 |
) |
| 266 | 269 |
.await |
| ... | ... |
@@ -274,7 +277,7 @@ enum LoginCredential<'a> {
|
| 274 | 277 |
|
| 275 | 278 |
async fn login_with_credential( |
| 276 | 279 |
http_session: &AnisetteHTTPSession<'_, '_>, |
| 277 |
- apple_id: &str, |
|
| 280 |
+ user: &str, |
|
| 278 | 281 |
credential: LoginCredential<'_>, |
| 279 | 282 |
) -> AuthResult {
|
| 280 | 283 |
let gs_service_url = http_session |
| ... | ... |
@@ -317,7 +320,7 @@ async fn login_with_credential( |
| 317 | 320 |
"s2k", |
| 318 | 321 |
"s2k_fo" // most Apple servers seem to not even implement that protocol anymore. |
| 319 | 322 |
], |
| 320 |
- "u": apple_id |
|
| 323 |
+ "u": user |
|
| 321 | 324 |
} |
| 322 | 325 |
}; |
| 323 | 326 |
|
| ... | ... |
@@ -397,7 +400,7 @@ async fn login_with_credential( |
| 397 | 400 |
}; |
| 398 | 401 |
|
| 399 | 402 |
let verifier = |
| 400 |
- srp_client.process_reply(&a, apple_id.as_bytes(), &processed_password, salt, b)?; |
|
| 403 |
+ srp_client.process_reply(&a, user.as_bytes(), &processed_password, salt, b)?; |
|
| 401 | 404 |
|
| 402 | 405 |
let request_plist = dict! {
|
| 403 | 406 |
"Header": dict!{
|
| ... | ... |
@@ -408,7 +411,7 @@ async fn login_with_credential( |
| 408 | 411 |
"c": cookie, |
| 409 | 412 |
"cpd": cpd, |
| 410 | 413 |
"o": "complete", |
| 411 |
- "u": apple_id |
|
| 414 |
+ "u": user |
|
| 412 | 415 |
} |
| 413 | 416 |
}; |
| 414 | 417 |
|
| ... | ... |
@@ -21,6 +21,12 @@ use thiserror::Error; |
| 21 | 21 |
#[serde(transparent)] |
| 22 | 22 |
pub struct AltDsid(pub(super) String); |
| 23 | 23 |
|
| 24 |
+impl AsRef<str> for AltDsid {
|
|
| 25 |
+ fn as_ref(&self) -> &str {
|
|
| 26 |
+ &self.0 |
|
| 27 |
+ } |
|
| 28 |
+} |
|
| 29 |
+ |
|
| 24 | 30 |
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] |
| 25 | 31 |
#[serde(transparent)] |
| 26 | 32 |
pub struct IdmsToken(String); |
| ... | ... |
@@ -61,6 +61,42 @@ pub enum PostDataError {
|
| 61 | 61 |
InvalidURLBag, |
| 62 | 62 |
} |
| 63 | 63 |
|
| 64 |
+#[derive(Debug, Clone, Copy, PartialEq, Eq)] |
|
| 65 |
+pub enum Service {
|
|
| 66 |
+ ICloud, |
|
| 67 |
+ ITunesStore, |
|
| 68 |
+ IMessage, |
|
| 69 |
+ FaceTime, |
|
| 70 |
+ GameCenter, |
|
| 71 |
+ Piggybacking, |
|
| 72 |
+} |
|
| 73 |
+ |
|
| 74 |
+#[derive(Debug, Clone, Copy, PartialEq, Eq)] |
|
| 75 |
+pub enum CheckInEvent {
|
|
| 76 |
+ Liveness, |
|
| 77 |
+ UpdateDeviceState, |
|
| 78 |
+ SignOutAll, |
|
| 79 |
+ SignOutService(Service), |
|
| 80 |
+} |
|
| 81 |
+ |
|
| 82 |
+impl Serialize for CheckInEvent {
|
|
| 83 |
+ fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
|
| 84 |
+ serializer.serialize_str(match self {
|
|
| 85 |
+ Self::Liveness => "liveness", |
|
| 86 |
+ Self::UpdateDeviceState => "update-device-state", |
|
| 87 |
+ Self::SignOutAll => "signout-all", |
|
| 88 |
+ Self::SignOutService(service) => match service {
|
|
| 89 |
+ Service::ICloud => "signout-icloud", |
|
| 90 |
+ Service::ITunesStore => "signout-itunesstore", |
|
| 91 |
+ Service::IMessage => "signout-imessage", |
|
| 92 |
+ Service::FaceTime => "signout-facetime", |
|
| 93 |
+ Service::GameCenter => "signout-gamecenter", |
|
| 94 |
+ Service::Piggybacking => "signout-piggybacking", |
|
| 95 |
+ }, |
|
| 96 |
+ }) |
|
| 97 |
+ } |
|
| 98 |
+} |
|
| 99 |
+ |
|
| 64 | 100 |
#[derive(Debug, Default, Serialize)] |
| 65 | 101 |
pub struct DeviceData {
|
| 66 | 102 |
#[serde(rename = "circleStatus")] |
| ... | ... |
@@ -69,8 +105,7 @@ pub struct DeviceData {
|
| 69 | 105 |
pub device_color: Option<String>, |
| 70 | 106 |
#[serde(rename = "dn")] |
| 71 | 107 |
pub device_name: Option<String>, |
| 72 |
- #[serde(rename = "event")] |
|
| 73 |
- pub event: Option<String>, // liveness |
|
| 108 |
+ pub event: Option<CheckInEvent>, |
|
| 74 | 109 |
#[serde(rename = "imei")] |
| 75 | 110 |
pub imei: Option<String>, |
| 76 | 111 |
#[serde(rename = "loc")] |
| 77 | 112 |