Extract AuthToken code in separate module
Dadoum

Dadoum commited on 2026-01-02 02:55:15
Showing 6 changed files, with 307 additions and 226 deletions.

... ...
@@ -1,4 +1,4 @@
1
-pub struct BundleInformation<'lt> {
1
+pub struct BundleInformation<'lt> { // Maybe simplify to 'static?
2 2
     pub bundle_name: &'lt str,
3 3
     pub bundle_identifier: &'lt str,
4 4
     pub bundle_version: &'lt str,
... ...
@@ -2,7 +2,9 @@ mod anisette;
2 2
 mod post_data;
3 3
 mod secondary_actions;
4 4
 mod url_switch;
5
+mod authenticated_session;
5 6
 
7
+pub use authenticated_session::*;
6 8
 use crate::bundle_information::BundleInformation;
7 9
 use crate::device::Device;
8 10
 use crate::grandslam::AuthOutcome::AnisetteResyncRequired;
... ...
@@ -24,7 +26,7 @@ use bytes::Bytes;
24 26
 use cbc::cipher::{BlockModeDecrypt, KeyIvInit};
25 27
 use chrono::{Local, SecondsFormat};
26 28
 use hmac::{Hmac, KeyInit, Mac};
27
-use log::trace;
29
+use log::{trace, warn};
28 30
 use plist::{Dictionary, Value};
29 31
 use plist_macros::{array, dict};
30 32
 pub use post_data::*;
... ...
@@ -320,7 +322,7 @@ pub fn build_client_provided_data(
320 322
 
321 323
 #[repr(u64)]
322 324
 enum StatusCode {
323
-    Success = 0,
325
+    Success = 200,
324 326
     SecondaryActionRequired = 409,
325 327
     AnisetteReprovisionRequired = 433,
326 328
     AnisetteResyncRequired = 434,
... ...
@@ -344,24 +346,6 @@ impl TryFrom<u64> for StatusCode {
344 346
     }
345 347
 }
346 348
 
347
-#[derive(Debug, Deserialize)]
348
-pub struct GSToken {
349
-    pub duration: u64,
350
-    // #[serde(rename = "cts")]
351
-    // pub start_epoch_millis: u64,
352
-    #[serde(rename = "expiry")]
353
-    pub expiry_epoch_millis: u64,
354
-    pub token: String,
355
-}
356
-
357
-#[derive(Debug)]
358
-pub struct AuthToken {
359
-    pub alt_dsid: String,
360
-    pub idms_token: String,
361
-    pub session_key: Vec<u8>,
362
-    pub cookie: Vec<u8>,
363
-}
364
-
365 349
 pub async fn login(
366 350
     http_session: &AnisetteHTTPSession<'_, '_>,
367 351
     apple_id: &str,
... ...
@@ -501,6 +485,8 @@ pub async fn login(
501 485
     let response_plist: Dictionary =
502 486
         plist::from_bytes(&response).map_err(|err| AuthError::Parsing(2, err))?;
503 487
 
488
+    trace!("Received: {:#?}", response_plist);
489
+
504 490
     let response_dict = response_plist
505 491
         .get("Response")
506 492
         .and_then(|response| response.as_dictionary())
... ...
@@ -616,201 +602,3 @@ pub async fn login(
616 602
         }
617 603
     }
618 604
 }
619 605
\ No newline at end of file
620
-
621
-pub fn parse_tokens_from_server_provided_data(
622
-    server_provided_data: &Dictionary,
623
-) -> Option<(AuthToken, Vec<(String, GSToken)>)> {
624
-    let alt_dsid = server_provided_data
625
-        .get("adsid")
626
-        .and_then(|alt_dsid| alt_dsid.as_string())
627
-        .map(|alt_dsid| alt_dsid.to_string());
628
-
629
-    let idms_token = server_provided_data
630
-        .get("GsIdmsToken")
631
-        .and_then(|idms_token| idms_token.as_string())
632
-        .map(|idms_token| idms_token.to_string());
633
-
634
-    let session_key = server_provided_data
635
-        .get("sk")
636
-        .and_then(|session_key| session_key.as_data())
637
-        .map(|session_key| session_key.to_vec());
638
-
639
-    let cookie = server_provided_data
640
-        .get("c")
641
-        .and_then(|cookie| cookie.as_data())
642
-        .map(|cookie| cookie.to_vec());
643
-
644
-    let tokens = server_provided_data
645
-        .get("t")
646
-        .and_then(|tokens| tokens.as_dictionary())
647
-        .map(|tokens| {
648
-            tokens
649
-                .iter()
650
-                .filter_map(|(key, token)| {
651
-                    plist::from_value(token)
652
-                        .ok()
653
-                        .map(|token| (key.clone(), token))
654
-                })
655
-                .collect()
656
-        });
657
-
658
-    match (alt_dsid, idms_token, session_key, cookie) {
659
-        (Some(alt_dsid), Some(idms_token), Some(session_key), Some(cookie)) => Some((
660
-            AuthToken {
661
-                alt_dsid,
662
-                idms_token,
663
-                session_key,
664
-                cookie,
665
-            },
666
-            tokens.unwrap_or_default(),
667
-        )),
668
-        _ => None,
669
-    }
670
-}
671
-
672
-#[derive(Debug)]
673
-pub enum AppTokenRequestError {
674
-    InvalidURLBag,
675
-    Anisette(ADIError),
676
-    InvalidAuthToken,
677
-    Network(reqwest::Error),
678
-    Parsing(plist::Error),
679
-    Structure(Dictionary),
680
-    Apple(AppleError),
681
-    InvalidResponse,
682
-}
683
-
684
-impl std::fmt::Display for AppTokenRequestError {
685
-    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
686
-        match self {
687
-            AppTokenRequestError::InvalidURLBag => write!(f, "Invalid URL bag"),
688
-            AppTokenRequestError::Anisette(err) => {
689
-                write!(f, "Cannot generate device authentication data: {err}")
690
-            }
691
-            AppTokenRequestError::InvalidAuthToken => {
692
-                write!(f, "The provided authentication token is not valid")
693
-            }
694
-            AppTokenRequestError::Network(err) => write!(f, "Network error: {err}"),
695
-            AppTokenRequestError::Parsing(err) => {
696
-                write!(f, "Failed to parse the app token request response: {err}")
697
-            }
698
-            AppTokenRequestError::Structure(_) => {
699
-                write!(f, "Failed to parse the app token request response")
700
-            }
701
-            AppTokenRequestError::Apple(err) => write!(f, "Cannot proceed: {err}"),
702
-            AppTokenRequestError::InvalidResponse => {
703
-                write!(f, "Invalid token returned by the server")
704
-            }
705
-        }
706
-    }
707
-}
708
-
709
-impl std::error::Error for AppTokenRequestError {}
710
-
711
-pub async fn get_app_token(
712
-    http_session: &AnisetteHTTPSession<'_, '_>,
713
-    auth_token: &AuthToken,
714
-    app_token_identifier: &str,
715
-) -> Result<GSToken, AppTokenRequestError> {
716
-    let gs_service_url = http_session
717
-        .url_bag()
718
-        .get("gsService")
719
-        .and_then(Value::as_string)
720
-        .ok_or(AppTokenRequestError::InvalidURLBag)?;
721
-
722
-    let cpd = build_client_provided_data(http_session).map_err(AppTokenRequestError::Anisette)?;
723
-
724
-    let checksum = Hmac::<Sha256>::new_from_slice(&auth_token.session_key)
725
-        .map_err(|_| AppTokenRequestError::InvalidAuthToken)?
726
-        .chain_update("apptokens")
727
-        .chain_update(&auth_token.alt_dsid)
728
-        .chain_update(app_token_identifier)
729
-        .finalize()
730
-        .into_bytes()
731
-        .to_vec();
732
-
733
-    let request_plist = dict! {
734
-        "Header": dict!{
735
-            "Version": "1.0.1"
736
-        },
737
-        "Request": dict!{
738
-            "u": auth_token.alt_dsid.clone(),
739
-            "app": array![
740
-                app_token_identifier
741
-            ],
742
-            "c": Value::Data(auth_token.cookie.clone()),
743
-            "t": auth_token.idms_token.clone(),
744
-            "checksum": Value::Data(checksum),
745
-            "cpd": cpd,
746
-            "o": "apptokens",
747
-        }
748
-    };
749
-
750
-    let mut request_body = Vec::new();
751
-    plist::to_writer_xml(&mut request_body, &request_plist).unwrap();
752
-
753
-    let response = http_session
754
-        .anisette_request_builder(GRANDSLAM_DSID, Method::POST, gs_service_url)
755
-        .map_err(AppTokenRequestError::Anisette)?
756
-        .body(request_body)
757
-        .send()
758
-        .await
759
-        .map_err(AppTokenRequestError::Network)?
760
-        .bytes()
761
-        .await
762
-        .map_err(AppTokenRequestError::Network)?;
763
-
764
-    let response_plist: Dictionary =
765
-        plist::from_bytes(&response).map_err(AppTokenRequestError::Parsing)?;
766
-
767
-    let response_dict = response_plist
768
-        .get("Response")
769
-        .and_then(|response| response.as_dictionary())
770
-        .ok_or(AppTokenRequestError::Structure(response_plist.clone()))?;
771
-
772
-    // println!("Response: {response_dict:?}");
773
-
774
-    let status = response_dict
775
-        .get("Status")
776
-        .and_then(|status| status.as_dictionary())
777
-        .ok_or(AppTokenRequestError::Structure(response_plist.clone()))?;
778
-
779
-    parse_status(status).map_err(AppTokenRequestError::Apple)?;
780
-
781
-    let encrypted_tokens = response_dict
782
-        .get("et")
783
-        .and_then(|et| et.as_data())
784
-        .ok_or(AppTokenRequestError::Structure(response_plist.clone()))?;
785
-
786
-    let associated_data = &encrypted_tokens[0..3];
787
-    if associated_data != b"XYZ" {
788
-        return Err(AppTokenRequestError::InvalidResponse);
789
-    }
790
-
791
-    let iv = &encrypted_tokens[3..19];
792
-    let encrypted_token = &encrypted_tokens[19..];
793
-
794
-    let tokens_data = AesGcm::<Aes256, U16>::new_from_slice(&auth_token.session_key)
795
-        .map_err(|_| AppTokenRequestError::InvalidAuthToken)?
796
-        .decrypt(
797
-            // iv is of fixed size. It shall not fail.
798
-            iv.try_into().expect("Invalid IV size??"),
799
-            Payload {
800
-                msg: encrypted_token,
801
-                aad: associated_data,
802
-            },
803
-        )
804
-        .map_err(|_| AppTokenRequestError::InvalidResponse)?;
805
-
806
-    let tokens: Dictionary =
807
-        plist::from_bytes(&tokens_data).map_err(AppTokenRequestError::Parsing)?;
808
-
809
-    trace!("Decrypted token response: {:#?}", tokens);
810
-
811
-    tokens
812
-        .get("t")
813
-        .and_then(|token| token.as_dictionary())
814
-        .and_then(|token| token.get(app_token_identifier))
815
-        .and_then(|token| plist::from_value(token).ok())
816
-        .ok_or(AppTokenRequestError::InvalidResponse)
817
-}
... ...
@@ -0,0 +1,288 @@
1
+use aes::Aes256;
2
+use aes::cipher::consts::U16;
3
+use aes_gcm::aead::{Aead, Payload};
4
+use aes_gcm::{AesGcm, KeyInit};
5
+use base64::Engine;
6
+use base64::prelude::BASE64_STANDARD;
7
+use hmac::{Hmac, Mac};
8
+use log::{trace, warn};
9
+use plist::{Dictionary, Value};
10
+use reqwest::{Method, RequestBuilder};
11
+use serde::Deserialize;
12
+use sha2::Sha256;
13
+use adi::proxy::{ADIError, ADIResult};
14
+use plist_macros::{array, dict};
15
+use crate::grandslam::{build_client_provided_data, GRANDSLAM_DSID};
16
+use crate::http_session::{parse_status, AnisetteHTTPSession, AppleError, URLBag};
17
+
18
+#[derive(Debug, Deserialize)]
19
+pub struct GSToken {
20
+    pub duration: u64,
21
+    // #[serde(rename = "cts")]
22
+    // pub start_epoch_millis: u64,
23
+    #[serde(rename = "expiry")]
24
+    pub expiry_epoch_millis: u64,
25
+    pub token: String,
26
+}
27
+
28
+#[derive(Debug)]
29
+pub struct AuthToken {
30
+    pub alt_dsid: String,
31
+    pub idms_token: String,
32
+    pub session_key: Vec<u8>,
33
+    pub cookie: Vec<u8>,
34
+    pub identity_token: String,
35
+}
36
+
37
+impl AuthToken {
38
+    fn new(alt_dsid: String, idms_token: String, session_key: Vec<u8>, cookie: Vec<u8>) -> Self {
39
+        let identity_token = BASE64_STANDARD.encode(format!("{alt_dsid}:{idms_token}"));
40
+        AuthToken {
41
+            alt_dsid,
42
+            idms_token,
43
+            session_key,
44
+            cookie,
45
+            identity_token,
46
+        }
47
+    }
48
+}
49
+
50
+pub fn parse_tokens_from_server_provided_data(
51
+    server_provided_data: &Dictionary,
52
+) -> Option<(AuthToken, Vec<(String, GSToken)>)> {
53
+    let alt_dsid = server_provided_data
54
+        .get("adsid")
55
+        .and_then(|alt_dsid| alt_dsid.as_string())
56
+        .map(|alt_dsid| alt_dsid.to_string());
57
+
58
+    let idms_token = server_provided_data
59
+        .get("GsIdmsToken")
60
+        .and_then(|idms_token| idms_token.as_string())
61
+        .map(|idms_token| idms_token.to_string());
62
+
63
+    let session_key = server_provided_data
64
+        .get("sk")
65
+        .and_then(|session_key| session_key.as_data())
66
+        .map(|session_key| session_key.to_vec());
67
+
68
+    let cookie = server_provided_data
69
+        .get("c")
70
+        .and_then(|cookie| cookie.as_data())
71
+        .map(|cookie| cookie.to_vec());
72
+
73
+    let tokens = server_provided_data
74
+        .get("t")
75
+        .and_then(|tokens| tokens.as_dictionary())
76
+        .map(|tokens| {
77
+            tokens
78
+                .iter()
79
+                .filter_map(|(key, token)| {
80
+                    plist::from_value(token)
81
+                        .ok()
82
+                        .map(|token| (key.clone(), token))
83
+                })
84
+                .collect()
85
+        });
86
+
87
+    match (alt_dsid, idms_token, session_key, cookie) {
88
+        (Some(alt_dsid), Some(idms_token), Some(session_key), Some(cookie)) => Some((
89
+            AuthToken::new(
90
+                alt_dsid,
91
+                idms_token,
92
+                session_key,
93
+                cookie,
94
+            ),
95
+            tokens.unwrap_or_default(),
96
+        )),
97
+        _ => None,
98
+    }
99
+}
100
+
101
+#[derive(Debug)]
102
+pub enum AppTokenRequestError {
103
+    InvalidURLBag,
104
+    Anisette(ADIError),
105
+    InvalidAuthToken,
106
+    Network(reqwest::Error),
107
+    Parsing(plist::Error),
108
+    Structure(Dictionary),
109
+    Apple(AppleError),
110
+    InvalidResponse,
111
+}
112
+
113
+impl std::fmt::Display for AppTokenRequestError {
114
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
115
+        match self {
116
+            AppTokenRequestError::InvalidURLBag => write!(f, "Invalid URL bag"),
117
+            AppTokenRequestError::Anisette(err) => {
118
+                write!(f, "Cannot generate device authentication data: {err}")
119
+            }
120
+            AppTokenRequestError::InvalidAuthToken => {
121
+                write!(f, "The provided authentication token is not valid")
122
+            }
123
+            AppTokenRequestError::Network(err) => write!(f, "Network error: {err}"),
124
+            AppTokenRequestError::Parsing(err) => {
125
+                write!(f, "Failed to parse the app token request response: {err}")
126
+            }
127
+            AppTokenRequestError::Structure(_) => {
128
+                write!(f, "Failed to parse the app token request response")
129
+            }
130
+            AppTokenRequestError::Apple(err) => write!(f, "Cannot proceed: {err}"),
131
+            AppTokenRequestError::InvalidResponse => {
132
+                write!(f, "Invalid token returned by the server")
133
+            }
134
+        }
135
+    }
136
+}
137
+
138
+impl std::error::Error for AppTokenRequestError {}
139
+
140
+pub struct AuthenticatedHTTPSession<'lt, 'adi> {
141
+    pub http_session: AnisetteHTTPSession<'lt, 'adi>,
142
+    pub auth_token: AuthToken,
143
+}
144
+
145
+impl<'a, 'b> AuthenticatedHTTPSession<'a, 'b> {
146
+    pub fn new(http_session: AnisetteHTTPSession<'a, 'b>, auth_token: AuthToken) -> Self {
147
+        Self {
148
+            http_session,
149
+            auth_token,
150
+        }
151
+    }
152
+
153
+    pub fn url_bag(&self) -> &URLBag { self.http_session.url_bag() }
154
+    pub fn simple_request_builder(&self, method: Method, url: &str) -> RequestBuilder { self.http_session.simple_request_builder(method, url) }
155
+    pub fn anisette_request_builder(&self, method: Method, url: &str) -> ADIResult<RequestBuilder> { self.http_session.anisette_request_builder(GRANDSLAM_DSID, method, url) }
156
+    pub fn authenticated_request_builder(&self, method: Method, url: &str) -> ADIResult<RequestBuilder> {
157
+        Ok(
158
+            self.anisette_request_builder(method, url)?
159
+                .header("X-Apple-Identity-Token", self.auth_token.identity_token.as_str())
160
+        )
161
+    }
162
+
163
+    pub async fn get_app_token(
164
+        &self,
165
+        app_token_identifier: &str, // TODO: maybe create some type for app tokens identifier?
166
+    ) -> Result<GSToken, AppTokenRequestError> {
167
+        let AuthenticatedHTTPSession { http_session, auth_token } = self;
168
+
169
+        let gs_service_url = http_session
170
+            .url_bag()
171
+            .get("gsService")
172
+            .and_then(Value::as_string)
173
+            .ok_or(AppTokenRequestError::InvalidURLBag)?;
174
+
175
+        let cpd = build_client_provided_data(&http_session).map_err(AppTokenRequestError::Anisette)?;
176
+
177
+        let checksum = Hmac::<Sha256>::new_from_slice(&auth_token.session_key)
178
+            .map_err(|_| AppTokenRequestError::InvalidAuthToken)?
179
+            .chain_update("apptokens")
180
+            .chain_update(&auth_token.alt_dsid)
181
+            .chain_update(app_token_identifier)
182
+            .finalize()
183
+            .into_bytes()
184
+            .to_vec();
185
+
186
+        let request_plist = dict! {
187
+        "Header": dict!{
188
+            "Version": "1.0.1"
189
+        },
190
+        "Request": dict!{
191
+            "u": auth_token.alt_dsid.clone(),
192
+            "app": array![
193
+                app_token_identifier
194
+            ],
195
+            "c": Value::Data(auth_token.cookie.clone()),
196
+            "t": auth_token.idms_token.clone(),
197
+            "checksum": Value::Data(checksum),
198
+            "cpd": cpd,
199
+            "o": "apptokens",
200
+        }
201
+    };
202
+
203
+        let mut request_body = Vec::new();
204
+        plist::to_writer_xml(&mut request_body, &request_plist).unwrap();
205
+
206
+        let response = http_session
207
+            .anisette_request_builder(GRANDSLAM_DSID, Method::POST, gs_service_url)
208
+            .map_err(AppTokenRequestError::Anisette)?
209
+            .body(request_body)
210
+            .send()
211
+            .await
212
+            .map_err(AppTokenRequestError::Network)?
213
+            .bytes()
214
+            .await
215
+            .map_err(AppTokenRequestError::Network)?;
216
+
217
+        let response_plist: Dictionary =
218
+            plist::from_bytes(&response).map_err(AppTokenRequestError::Parsing)?;
219
+
220
+        let response_dict = response_plist
221
+            .get("Response")
222
+            .and_then(|response| response.as_dictionary())
223
+            .ok_or(AppTokenRequestError::Structure(response_plist.clone()))?;
224
+
225
+        // println!("Response: {response_dict:?}");
226
+
227
+        let status = response_dict
228
+            .get("Status")
229
+            .and_then(|status| status.as_dictionary())
230
+            .ok_or(AppTokenRequestError::Structure(response_plist.clone()))?;
231
+
232
+        parse_status(status).map_err(AppTokenRequestError::Apple)?;
233
+
234
+        let encrypted_tokens = response_dict
235
+            .get("et")
236
+            .and_then(|et| et.as_data())
237
+            .ok_or(AppTokenRequestError::Structure(response_plist.clone()))?;
238
+
239
+        let associated_data = &encrypted_tokens[0..3];
240
+        if associated_data != b"XYZ" {
241
+            warn!("Surprised by the associated data provided by Apple: {associated_data:02X?}");
242
+            // return Err(AppTokenRequestError::InvalidResponse);
243
+        }
244
+
245
+        let iv = &encrypted_tokens[3..19];
246
+        let encrypted_token = &encrypted_tokens[19..];
247
+
248
+        let tokens_data = AesGcm::<Aes256, U16>::new_from_slice(&auth_token.session_key)
249
+            .map_err(|_| AppTokenRequestError::InvalidAuthToken)?
250
+            .decrypt(
251
+                // iv is of fixed size. It shall not fail.
252
+                iv.try_into().expect("Invalid IV size??"),
253
+                Payload {
254
+                    msg: encrypted_token,
255
+                    aad: associated_data,
256
+                },
257
+            )
258
+            .map_err(|_| AppTokenRequestError::InvalidResponse)?;
259
+
260
+        let tokens: Dictionary =
261
+            plist::from_bytes(&tokens_data).map_err(AppTokenRequestError::Parsing)?;
262
+
263
+        trace!("Decrypted token response: {:#?}", tokens);
264
+
265
+        tokens
266
+            .get("t")
267
+            .and_then(|token| token.as_dictionary())
268
+            .and_then(|token| token.get(app_token_identifier))
269
+            .and_then(|token| plist::from_value(token).ok())
270
+            .ok_or(AppTokenRequestError::InvalidResponse)
271
+    }
272
+
273
+    pub async fn validate_code(&self, validation_code: &str) -> Result<(), AppTokenRequestError> { // TODO: change that error type.
274
+        let validate_code_url = self
275
+            .url_bag()
276
+            .get("validateCode")
277
+            .and_then(Value::as_string)
278
+            .ok_or(AppTokenRequestError::InvalidURLBag)?;
279
+
280
+        let _ =
281
+            self.authenticated_request_builder(Method::POST, validate_code_url)
282
+                .map_err(AppTokenRequestError::Anisette)?
283
+                .header("security-code", validation_code);
284
+
285
+        todo!()
286
+    }
287
+
288
+}
... ...
@@ -168,8 +168,7 @@ impl<'data> Library<'data> {
168 168
             }
169 169
         };
170 170
 
171
-        relocate(&elf.dynrelas);
172
-        relocate(&elf.dynrels);
171
+        elf.shdr_relocs.iter().for_each(|(_, reloc_section)| relocate(reloc_section));
173 172
 
174 173
         let gnu_hash_section = elf
175 174
             .section_headers
... ...
@@ -5,7 +5,6 @@ edition = "2021"
5 5
 
6 6
 [dependencies]
7 7
 adi.workspace = true
8
-adid-proxy.workspace = true
9 8
 android-coreadi.workspace = true
10 9
 apple-account.workspace = true
11 10
 elf-loader.workspace = true
... ...
@@ -13,3 +12,6 @@ elf-loader.workspace = true
13 12
 tokio.workspace = true
14 13
 libc = "0.2.176"
15 14
 env_logger = "0.11.8"
15
+
16
+[target.'cfg(target_os = "macos")'.dependencies]
17
+adid-proxy.workspace = true
... ...
@@ -2,7 +2,7 @@ use adi::proxy::ADIProxy;
2 2
 use android_coreadi::AndroidCoreADIProxy;
3 3
 use apple_account::bundle_information::{APPLE_TV_BUNDLE_INFORMATION, XCODE_BUNDLE_INFORMATION};
4 4
 use apple_account::device::Device;
5
-use apple_account::grandslam::AuthOutcome;
5
+use apple_account::grandslam::{AuthOutcome, AuthenticatedHTTPSession};
6 6
 use apple_account::http_session::AnisetteHTTPSession;
7 7
 use apple_account::{grandslam, itunes};
8 8
 use std::{env, fs};
... ...
@@ -38,9 +38,13 @@ async fn grandslam_test(
38 38
         AuthOutcome::Success(server_provided_data)
39 39
         | AuthOutcome::SecondaryActionRequired(server_provided_data, _) => {
40 40
             match grandslam::parse_tokens_from_server_provided_data(server_provided_data) {
41
-                Some((token, _)) => {
41
+                Some((auth_token, _)) => {
42
+                    let http_session = AuthenticatedHTTPSession::new(
43
+                        http_session,
44
+                        auth_token
45
+                    );
42 46
                     let xcode_token =
43
-                        grandslam::get_app_token(&http_session, &token, "com.apple.gs.xcode.auth")
47
+                        http_session.get_app_token("com.apple.gs.xcode.auth")
44 48
                             .await?;
45 49
                     println!("token: {:?}", xcode_token);
46 50
                 }
... ...
@@ -93,7 +97,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
93 97
         println!("{}", code);
94 98
     }
95 99
     let proxy = {
96
-        let core_adi_data = fs::read("nodistrib/lib/arm64-v8a/libCoreADI.so")?;
100
+        let core_adi_data = fs::read("nodistrib/lib/x86_64/libCoreADI.so")?;
97 101
         let proxy = AndroidCoreADIProxy::load_library(core_adi_data)?;
98 102
 
99 103
         proxy.set_android_id("0123456789012345")?;
100 104