Better document check-in (postData) and log-in
Dadoum

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