Initial commit: mostly implement grandslam and omnisette replacement
Dadoum

Dadoum commited on 2025-12-29 06:24:09
Showing 52 changed files, with 8721 additions and 0 deletions.

... ...
@@ -0,0 +1,3 @@
1
+# These are supported funding model platforms
2
+
3
+github: ["Dadoum"]
... ...
@@ -0,0 +1 @@
1
+/target
... ...
@@ -0,0 +1,3781 @@
1
+# This file is automatically @generated by Cargo.
2
+# It is not intended for manual editing.
3
+version = 4
4
+
5
+[[package]]
6
+name = "addr2line"
7
+version = "0.25.1"
8
+source = "registry+https://github.com/rust-lang/crates.io-index"
9
+checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b"
10
+dependencies = [
11
+ "gimli",
12
+]
13
+
14
+[[package]]
15
+name = "adi"
16
+version = "0.1.0"
17
+dependencies = [
18
+ "bincode",
19
+ "log",
20
+ "serde",
21
+]
22
+
23
+[[package]]
24
+name = "adid-proxy"
25
+version = "0.1.0"
26
+dependencies = [
27
+ "adi",
28
+ "block",
29
+ "xpc-connection-sys",
30
+]
31
+
32
+[[package]]
33
+name = "adler2"
34
+version = "2.0.1"
35
+source = "registry+https://github.com/rust-lang/crates.io-index"
36
+checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
37
+
38
+[[package]]
39
+name = "aead"
40
+version = "0.6.0-rc.5"
41
+source = "registry+https://github.com/rust-lang/crates.io-index"
42
+checksum = "67a578e7d4edaef88aeb9cdd81556f4a62266ce26601317c006a79e8bc58b5af"
43
+dependencies = [
44
+ "crypto-common",
45
+ "inout",
46
+]
47
+
48
+[[package]]
49
+name = "aes"
50
+version = "0.9.0-rc.2"
51
+source = "registry+https://github.com/rust-lang/crates.io-index"
52
+checksum = "fd9e1c818b25efb32214df89b0ec22f01aa397aaeb718d1022bf0635a3bfd1a8"
53
+dependencies = [
54
+ "cfg-if 1.0.4",
55
+ "cipher",
56
+ "cpufeatures",
57
+]
58
+
59
+[[package]]
60
+name = "aes-gcm"
61
+version = "0.11.0-rc.2"
62
+source = "registry+https://github.com/rust-lang/crates.io-index"
63
+checksum = "7f5c07f414d7dc0755870f84c7900425360288d24e0eae4836f9dee19a30fa5f"
64
+dependencies = [
65
+ "aead",
66
+ "aes",
67
+ "cipher",
68
+ "ctr",
69
+ "ghash",
70
+ "subtle",
71
+]
72
+
73
+[[package]]
74
+name = "aho-corasick"
75
+version = "1.1.3"
76
+source = "registry+https://github.com/rust-lang/crates.io-index"
77
+checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
78
+dependencies = [
79
+ "memchr",
80
+]
81
+
82
+[[package]]
83
+name = "aliasable"
84
+version = "0.1.3"
85
+source = "registry+https://github.com/rust-lang/crates.io-index"
86
+checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd"
87
+
88
+[[package]]
89
+name = "android-coreadi"
90
+version = "0.1.0"
91
+dependencies = [
92
+ "adi",
93
+ "elf-loader",
94
+ "libc",
95
+ "ouroboros",
96
+ "rand",
97
+]
98
+
99
+[[package]]
100
+name = "android_system_properties"
101
+version = "0.1.5"
102
+source = "registry+https://github.com/rust-lang/crates.io-index"
103
+checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
104
+dependencies = [
105
+ "libc",
106
+]
107
+
108
+[[package]]
109
+name = "ansi_term"
110
+version = "0.12.1"
111
+source = "registry+https://github.com/rust-lang/crates.io-index"
112
+checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
113
+dependencies = [
114
+ "winapi",
115
+]
116
+
117
+[[package]]
118
+name = "anstream"
119
+version = "0.6.21"
120
+source = "registry+https://github.com/rust-lang/crates.io-index"
121
+checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a"
122
+dependencies = [
123
+ "anstyle",
124
+ "anstyle-parse",
125
+ "anstyle-query",
126
+ "anstyle-wincon",
127
+ "colorchoice",
128
+ "is_terminal_polyfill",
129
+ "utf8parse",
130
+]
131
+
132
+[[package]]
133
+name = "anstyle"
134
+version = "1.0.13"
135
+source = "registry+https://github.com/rust-lang/crates.io-index"
136
+checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
137
+
138
+[[package]]
139
+name = "anstyle-parse"
140
+version = "0.2.7"
141
+source = "registry+https://github.com/rust-lang/crates.io-index"
142
+checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
143
+dependencies = [
144
+ "utf8parse",
145
+]
146
+
147
+[[package]]
148
+name = "anstyle-query"
149
+version = "1.1.4"
150
+source = "registry+https://github.com/rust-lang/crates.io-index"
151
+checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2"
152
+dependencies = [
153
+ "windows-sys 0.60.2",
154
+]
155
+
156
+[[package]]
157
+name = "anstyle-wincon"
158
+version = "3.0.10"
159
+source = "registry+https://github.com/rust-lang/crates.io-index"
160
+checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a"
161
+dependencies = [
162
+ "anstyle",
163
+ "once_cell_polyfill",
164
+ "windows-sys 0.60.2",
165
+]
166
+
167
+[[package]]
168
+name = "apple-account"
169
+version = "0.1.0"
170
+dependencies = [
171
+ "adi",
172
+ "aes",
173
+ "aes-gcm",
174
+ "base64 0.22.1",
175
+ "bytes",
176
+ "cbc",
177
+ "chrono",
178
+ "hex",
179
+ "hmac",
180
+ "iana-time-zone",
181
+ "log",
182
+ "pbkdf2",
183
+ "plist",
184
+ "plist-macros",
185
+ "rand",
186
+ "reqwest 0.12.27",
187
+ "serde",
188
+ "sha2",
189
+ "srp",
190
+ "sys-locale",
191
+]
192
+
193
+[[package]]
194
+name = "apple-codesign"
195
+version = "0.1.0"
196
+dependencies = [
197
+ "futures",
198
+ "lief",
199
+ "log",
200
+ "plist",
201
+ "sha1",
202
+ "sha2",
203
+ "tokio",
204
+]
205
+
206
+[[package]]
207
+name = "aquamarine"
208
+version = "0.1.12"
209
+source = "registry+https://github.com/rust-lang/crates.io-index"
210
+checksum = "a941c39708478e8eea39243b5983f1c42d2717b3620ee91f4a52115fd02ac43f"
211
+dependencies = [
212
+ "itertools 0.9.0",
213
+ "proc-macro-error",
214
+ "proc-macro2",
215
+ "quote",
216
+ "syn 1.0.109",
217
+]
218
+
219
+[[package]]
220
+name = "atomic-waker"
221
+version = "1.1.2"
222
+source = "registry+https://github.com/rust-lang/crates.io-index"
223
+checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
224
+
225
+[[package]]
226
+name = "atty"
227
+version = "0.2.14"
228
+source = "registry+https://github.com/rust-lang/crates.io-index"
229
+checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
230
+dependencies = [
231
+ "hermit-abi 0.1.19",
232
+ "libc",
233
+ "winapi",
234
+]
235
+
236
+[[package]]
237
+name = "autocfg"
238
+version = "1.5.0"
239
+source = "registry+https://github.com/rust-lang/crates.io-index"
240
+checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
241
+
242
+[[package]]
243
+name = "autocxx"
244
+version = "0.26.0"
245
+source = "registry+https://github.com/rust-lang/crates.io-index"
246
+checksum = "1ba64dd33efd8f09724143d45ab91b48aebcee52f4fb11add3464c998fab47dc"
247
+dependencies = [
248
+ "aquamarine",
249
+ "autocxx-macro",
250
+ "cxx",
251
+ "moveit",
252
+]
253
+
254
+[[package]]
255
+name = "autocxx-macro"
256
+version = "0.26.0"
257
+source = "registry+https://github.com/rust-lang/crates.io-index"
258
+checksum = "8e594e68d030b6eb1ce7e2b40958f4f4ae7150c588c76d76b9f8178d41c47d80"
259
+dependencies = [
260
+ "autocxx-parser",
261
+ "proc-macro-error",
262
+ "proc-macro2",
263
+ "quote",
264
+ "syn 2.0.107",
265
+]
266
+
267
+[[package]]
268
+name = "autocxx-parser"
269
+version = "0.26.0"
270
+source = "registry+https://github.com/rust-lang/crates.io-index"
271
+checksum = "2ef00b2fc378804c31c4fbd693a7fea93f8a90467dce331dae1e4ce41e542953"
272
+dependencies = [
273
+ "indexmap 1.9.3",
274
+ "itertools 0.10.5",
275
+ "log",
276
+ "once_cell",
277
+ "proc-macro2",
278
+ "quote",
279
+ "serde",
280
+ "serde_json",
281
+ "syn 2.0.107",
282
+ "thiserror 1.0.69",
283
+]
284
+
285
+[[package]]
286
+name = "backtrace"
287
+version = "0.3.76"
288
+source = "registry+https://github.com/rust-lang/crates.io-index"
289
+checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6"
290
+dependencies = [
291
+ "addr2line",
292
+ "cfg-if 1.0.4",
293
+ "libc",
294
+ "miniz_oxide",
295
+ "object",
296
+ "rustc-demangle",
297
+ "windows-link 0.2.1",
298
+]
299
+
300
+[[package]]
301
+name = "backtrace-ext"
302
+version = "0.2.1"
303
+source = "registry+https://github.com/rust-lang/crates.io-index"
304
+checksum = "537beee3be4a18fb023b570f80e3ae28003db9167a751266b259926e25539d50"
305
+dependencies = [
306
+ "backtrace",
307
+]
308
+
309
+[[package]]
310
+name = "base64"
311
+version = "0.21.7"
312
+source = "registry+https://github.com/rust-lang/crates.io-index"
313
+checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
314
+
315
+[[package]]
316
+name = "base64"
317
+version = "0.22.1"
318
+source = "registry+https://github.com/rust-lang/crates.io-index"
319
+checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
320
+
321
+[[package]]
322
+name = "bincode"
323
+version = "2.0.1"
324
+source = "registry+https://github.com/rust-lang/crates.io-index"
325
+checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740"
326
+dependencies = [
327
+ "serde",
328
+ "unty",
329
+]
330
+
331
+[[package]]
332
+name = "bindgen"
333
+version = "0.53.3"
334
+source = "registry+https://github.com/rust-lang/crates.io-index"
335
+checksum = "c72a978d268b1d70b0e963217e60fdabd9523a941457a6c42a7315d15c7e89e5"
336
+dependencies = [
337
+ "bitflags 1.3.2",
338
+ "cexpr",
339
+ "cfg-if 0.1.10",
340
+ "clang-sys",
341
+ "clap",
342
+ "env_logger 0.7.1",
343
+ "lazy_static",
344
+ "lazycell",
345
+ "log",
346
+ "peeking_take_while",
347
+ "proc-macro2",
348
+ "quote",
349
+ "regex",
350
+ "rustc-hash 1.1.0",
351
+ "shlex 0.1.1",
352
+ "which",
353
+]
354
+
355
+[[package]]
356
+name = "bitflags"
357
+version = "1.3.2"
358
+source = "registry+https://github.com/rust-lang/crates.io-index"
359
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
360
+
361
+[[package]]
362
+name = "bitflags"
363
+version = "2.10.0"
364
+source = "registry+https://github.com/rust-lang/crates.io-index"
365
+checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
366
+
367
+[[package]]
368
+name = "block"
369
+version = "0.1.6"
370
+source = "registry+https://github.com/rust-lang/crates.io-index"
371
+checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
372
+
373
+[[package]]
374
+name = "block-buffer"
375
+version = "0.11.0"
376
+source = "registry+https://github.com/rust-lang/crates.io-index"
377
+checksum = "96eb4cdd6cf1b31d671e9efe75c5d1ec614776856cefbe109ca373554a6d514f"
378
+dependencies = [
379
+ "hybrid-array",
380
+]
381
+
382
+[[package]]
383
+name = "block-padding"
384
+version = "0.4.2"
385
+source = "registry+https://github.com/rust-lang/crates.io-index"
386
+checksum = "710f1dd022ef4e93f8a438b4ba958de7f64308434fa6a87104481645cc30068b"
387
+dependencies = [
388
+ "hybrid-array",
389
+]
390
+
391
+[[package]]
392
+name = "bumpalo"
393
+version = "3.19.0"
394
+source = "registry+https://github.com/rust-lang/crates.io-index"
395
+checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
396
+
397
+[[package]]
398
+name = "byteorder"
399
+version = "1.5.0"
400
+source = "registry+https://github.com/rust-lang/crates.io-index"
401
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
402
+
403
+[[package]]
404
+name = "bytes"
405
+version = "1.10.1"
406
+source = "registry+https://github.com/rust-lang/crates.io-index"
407
+checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
408
+
409
+[[package]]
410
+name = "cbc"
411
+version = "0.2.0-rc.2"
412
+source = "registry+https://github.com/rust-lang/crates.io-index"
413
+checksum = "3c34a745c272d1f6124df3006881364190a8f033ff3857ce196a17aa4a753096"
414
+dependencies = [
415
+ "cipher",
416
+]
417
+
418
+[[package]]
419
+name = "cc"
420
+version = "1.2.41"
421
+source = "registry+https://github.com/rust-lang/crates.io-index"
422
+checksum = "ac9fe6cdbb24b6ade63616c0a0688e45bb56732262c158df3c0c4bea4ca47cb7"
423
+dependencies = [
424
+ "find-msvc-tools",
425
+ "shlex 1.3.0",
426
+]
427
+
428
+[[package]]
429
+name = "cexpr"
430
+version = "0.4.0"
431
+source = "registry+https://github.com/rust-lang/crates.io-index"
432
+checksum = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27"
433
+dependencies = [
434
+ "nom",
435
+]
436
+
437
+[[package]]
438
+name = "cfg-if"
439
+version = "0.1.10"
440
+source = "registry+https://github.com/rust-lang/crates.io-index"
441
+checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
442
+
443
+[[package]]
444
+name = "cfg-if"
445
+version = "1.0.4"
446
+source = "registry+https://github.com/rust-lang/crates.io-index"
447
+checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
448
+
449
+[[package]]
450
+name = "cfg_aliases"
451
+version = "0.2.1"
452
+source = "registry+https://github.com/rust-lang/crates.io-index"
453
+checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
454
+
455
+[[package]]
456
+name = "chrono"
457
+version = "0.4.42"
458
+source = "registry+https://github.com/rust-lang/crates.io-index"
459
+checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2"
460
+dependencies = [
461
+ "iana-time-zone",
462
+ "js-sys",
463
+ "num-traits",
464
+ "wasm-bindgen",
465
+ "windows-link 0.2.1",
466
+]
467
+
468
+[[package]]
469
+name = "cipher"
470
+version = "0.5.0-rc.2"
471
+source = "registry+https://github.com/rust-lang/crates.io-index"
472
+checksum = "155e4a260750fa4f7754649f049748aacc31db238a358d85fd721002f230f92f"
473
+dependencies = [
474
+ "block-buffer",
475
+ "crypto-common",
476
+ "inout",
477
+]
478
+
479
+[[package]]
480
+name = "clang-sys"
481
+version = "0.29.3"
482
+source = "registry+https://github.com/rust-lang/crates.io-index"
483
+checksum = "fe6837df1d5cba2397b835c8530f51723267e16abbf83892e9e5af4f0e5dd10a"
484
+dependencies = [
485
+ "glob",
486
+ "libc",
487
+ "libloading",
488
+]
489
+
490
+[[package]]
491
+name = "clap"
492
+version = "2.34.0"
493
+source = "registry+https://github.com/rust-lang/crates.io-index"
494
+checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
495
+dependencies = [
496
+ "ansi_term",
497
+ "atty",
498
+ "bitflags 1.3.2",
499
+ "strsim",
500
+ "textwrap 0.11.0",
501
+ "unicode-width",
502
+ "vec_map",
503
+]
504
+
505
+[[package]]
506
+name = "colorchoice"
507
+version = "1.0.4"
508
+source = "registry+https://github.com/rust-lang/crates.io-index"
509
+checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
510
+
511
+[[package]]
512
+name = "const-oid"
513
+version = "0.10.1"
514
+source = "registry+https://github.com/rust-lang/crates.io-index"
515
+checksum = "0dabb6555f92fb9ee4140454eb5dcd14c7960e1225c6d1a6cc361f032947713e"
516
+
517
+[[package]]
518
+name = "core-foundation"
519
+version = "0.9.4"
520
+source = "registry+https://github.com/rust-lang/crates.io-index"
521
+checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
522
+dependencies = [
523
+ "core-foundation-sys",
524
+ "libc",
525
+]
526
+
527
+[[package]]
528
+name = "core-foundation-sys"
529
+version = "0.8.7"
530
+source = "registry+https://github.com/rust-lang/crates.io-index"
531
+checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
532
+
533
+[[package]]
534
+name = "cpufeatures"
535
+version = "0.2.17"
536
+source = "registry+https://github.com/rust-lang/crates.io-index"
537
+checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
538
+dependencies = [
539
+ "libc",
540
+]
541
+
542
+[[package]]
543
+name = "crc32fast"
544
+version = "1.5.0"
545
+source = "registry+https://github.com/rust-lang/crates.io-index"
546
+checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
547
+dependencies = [
548
+ "cfg-if 1.0.4",
549
+]
550
+
551
+[[package]]
552
+name = "crossbeam-utils"
553
+version = "0.8.21"
554
+source = "registry+https://github.com/rust-lang/crates.io-index"
555
+checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
556
+
557
+[[package]]
558
+name = "crypto-common"
559
+version = "0.2.0-rc.8"
560
+source = "registry+https://github.com/rust-lang/crates.io-index"
561
+checksum = "e6165b8029cdc3e765b74d3548f85999ee799d5124877ce45c2c85ca78e4d4aa"
562
+dependencies = [
563
+ "getrandom 0.4.0-rc.0",
564
+ "hybrid-array",
565
+ "rand_core 0.10.0-rc-3",
566
+]
567
+
568
+[[package]]
569
+name = "ctr"
570
+version = "0.10.0-rc.2"
571
+source = "registry+https://github.com/rust-lang/crates.io-index"
572
+checksum = "3d0ec605a95e78815a4c4b8040217d56d5a1ab37043851ee9e7e65b89afa00e3"
573
+dependencies = [
574
+ "cipher",
575
+]
576
+
577
+[[package]]
578
+name = "cxx"
579
+version = "1.0.117"
580
+source = "registry+https://github.com/rust-lang/crates.io-index"
581
+checksum = "0c15f3b597018782655a05d417f28bac009f6eb60f4b6703eb818998c1aaa16a"
582
+dependencies = [
583
+ "cc",
584
+ "cxxbridge-flags",
585
+ "cxxbridge-macro",
586
+ "link-cplusplus",
587
+]
588
+
589
+[[package]]
590
+name = "cxxbridge-flags"
591
+version = "1.0.117"
592
+source = "registry+https://github.com/rust-lang/crates.io-index"
593
+checksum = "7a7eb4c4fd18505f5a935f9c2ee77780350dcdb56da7cd037634e806141c5c43"
594
+
595
+[[package]]
596
+name = "cxxbridge-macro"
597
+version = "1.0.117"
598
+source = "registry+https://github.com/rust-lang/crates.io-index"
599
+checksum = "5d914fcc6452d133236ee067a9538be25ba6a644a450e1a6c617da84bf029854"
600
+dependencies = [
601
+ "proc-macro2",
602
+ "quote",
603
+ "syn 2.0.107",
604
+]
605
+
606
+[[package]]
607
+name = "deranged"
608
+version = "0.5.5"
609
+source = "registry+https://github.com/rust-lang/crates.io-index"
610
+checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587"
611
+dependencies = [
612
+ "powerfmt",
613
+]
614
+
615
+[[package]]
616
+name = "digest"
617
+version = "0.11.0-rc.4"
618
+source = "registry+https://github.com/rust-lang/crates.io-index"
619
+checksum = "ea390c940e465846d64775e55e3115d5dc934acb953de6f6e6360bc232fe2bf7"
620
+dependencies = [
621
+ "block-buffer",
622
+ "const-oid",
623
+ "crypto-common",
624
+ "subtle",
625
+]
626
+
627
+[[package]]
628
+name = "displaydoc"
629
+version = "0.2.5"
630
+source = "registry+https://github.com/rust-lang/crates.io-index"
631
+checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
632
+dependencies = [
633
+ "proc-macro2",
634
+ "quote",
635
+ "syn 2.0.107",
636
+]
637
+
638
+[[package]]
639
+name = "either"
640
+version = "1.15.0"
641
+source = "registry+https://github.com/rust-lang/crates.io-index"
642
+checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
643
+
644
+[[package]]
645
+name = "elf-loader"
646
+version = "2.0.0"
647
+dependencies = [
648
+ "goblin",
649
+ "log",
650
+ "memmap2",
651
+ "region",
652
+ "sysv64",
653
+]
654
+
655
+[[package]]
656
+name = "encoding_rs"
657
+version = "0.8.35"
658
+source = "registry+https://github.com/rust-lang/crates.io-index"
659
+checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
660
+dependencies = [
661
+ "cfg-if 1.0.4",
662
+]
663
+
664
+[[package]]
665
+name = "env_filter"
666
+version = "0.1.4"
667
+source = "registry+https://github.com/rust-lang/crates.io-index"
668
+checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2"
669
+dependencies = [
670
+ "log",
671
+ "regex",
672
+]
673
+
674
+[[package]]
675
+name = "env_logger"
676
+version = "0.7.1"
677
+source = "registry+https://github.com/rust-lang/crates.io-index"
678
+checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
679
+dependencies = [
680
+ "atty",
681
+ "humantime",
682
+ "log",
683
+ "regex",
684
+ "termcolor",
685
+]
686
+
687
+[[package]]
688
+name = "env_logger"
689
+version = "0.11.8"
690
+source = "registry+https://github.com/rust-lang/crates.io-index"
691
+checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f"
692
+dependencies = [
693
+ "anstream",
694
+ "anstyle",
695
+ "env_filter",
696
+ "jiff",
697
+ "log",
698
+]
699
+
700
+[[package]]
701
+name = "equivalent"
702
+version = "1.0.2"
703
+source = "registry+https://github.com/rust-lang/crates.io-index"
704
+checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
705
+
706
+[[package]]
707
+name = "errno"
708
+version = "0.3.14"
709
+source = "registry+https://github.com/rust-lang/crates.io-index"
710
+checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
711
+dependencies = [
712
+ "libc",
713
+ "windows-sys 0.61.2",
714
+]
715
+
716
+[[package]]
717
+name = "fastrand"
718
+version = "2.3.0"
719
+source = "registry+https://github.com/rust-lang/crates.io-index"
720
+checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
721
+
722
+[[package]]
723
+name = "find-msvc-tools"
724
+version = "0.1.4"
725
+source = "registry+https://github.com/rust-lang/crates.io-index"
726
+checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127"
727
+
728
+[[package]]
729
+name = "flate2"
730
+version = "1.1.4"
731
+source = "registry+https://github.com/rust-lang/crates.io-index"
732
+checksum = "dc5a4e564e38c699f2880d3fda590bedc2e69f3f84cd48b457bd892ce61d0aa9"
733
+dependencies = [
734
+ "crc32fast",
735
+ "miniz_oxide",
736
+]
737
+
738
+[[package]]
739
+name = "fnv"
740
+version = "1.0.7"
741
+source = "registry+https://github.com/rust-lang/crates.io-index"
742
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
743
+
744
+[[package]]
745
+name = "foreign-types"
746
+version = "0.3.2"
747
+source = "registry+https://github.com/rust-lang/crates.io-index"
748
+checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
749
+dependencies = [
750
+ "foreign-types-shared",
751
+]
752
+
753
+[[package]]
754
+name = "foreign-types-shared"
755
+version = "0.1.1"
756
+source = "registry+https://github.com/rust-lang/crates.io-index"
757
+checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
758
+
759
+[[package]]
760
+name = "form_urlencoded"
761
+version = "1.2.2"
762
+source = "registry+https://github.com/rust-lang/crates.io-index"
763
+checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf"
764
+dependencies = [
765
+ "percent-encoding",
766
+]
767
+
768
+[[package]]
769
+name = "futures"
770
+version = "0.3.31"
771
+source = "registry+https://github.com/rust-lang/crates.io-index"
772
+checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
773
+dependencies = [
774
+ "futures-channel",
775
+ "futures-core",
776
+ "futures-executor",
777
+ "futures-io",
778
+ "futures-sink",
779
+ "futures-task",
780
+ "futures-util",
781
+]
782
+
783
+[[package]]
784
+name = "futures-channel"
785
+version = "0.3.31"
786
+source = "registry+https://github.com/rust-lang/crates.io-index"
787
+checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
788
+dependencies = [
789
+ "futures-core",
790
+ "futures-sink",
791
+]
792
+
793
+[[package]]
794
+name = "futures-core"
795
+version = "0.3.31"
796
+source = "registry+https://github.com/rust-lang/crates.io-index"
797
+checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
798
+
799
+[[package]]
800
+name = "futures-executor"
801
+version = "0.3.31"
802
+source = "registry+https://github.com/rust-lang/crates.io-index"
803
+checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f"
804
+dependencies = [
805
+ "futures-core",
806
+ "futures-task",
807
+ "futures-util",
808
+]
809
+
810
+[[package]]
811
+name = "futures-io"
812
+version = "0.3.31"
813
+source = "registry+https://github.com/rust-lang/crates.io-index"
814
+checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
815
+
816
+[[package]]
817
+name = "futures-macro"
818
+version = "0.3.31"
819
+source = "registry+https://github.com/rust-lang/crates.io-index"
820
+checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
821
+dependencies = [
822
+ "proc-macro2",
823
+ "quote",
824
+ "syn 2.0.107",
825
+]
826
+
827
+[[package]]
828
+name = "futures-sink"
829
+version = "0.3.31"
830
+source = "registry+https://github.com/rust-lang/crates.io-index"
831
+checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
832
+
833
+[[package]]
834
+name = "futures-task"
835
+version = "0.3.31"
836
+source = "registry+https://github.com/rust-lang/crates.io-index"
837
+checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
838
+
839
+[[package]]
840
+name = "futures-util"
841
+version = "0.3.31"
842
+source = "registry+https://github.com/rust-lang/crates.io-index"
843
+checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
844
+dependencies = [
845
+ "futures-channel",
846
+ "futures-core",
847
+ "futures-io",
848
+ "futures-macro",
849
+ "futures-sink",
850
+ "futures-task",
851
+ "memchr",
852
+ "pin-project-lite",
853
+ "pin-utils",
854
+ "slab",
855
+]
856
+
857
+[[package]]
858
+name = "getrandom"
859
+version = "0.2.16"
860
+source = "registry+https://github.com/rust-lang/crates.io-index"
861
+checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
862
+dependencies = [
863
+ "cfg-if 1.0.4",
864
+ "js-sys",
865
+ "libc",
866
+ "wasi",
867
+ "wasm-bindgen",
868
+]
869
+
870
+[[package]]
871
+name = "getrandom"
872
+version = "0.3.4"
873
+source = "registry+https://github.com/rust-lang/crates.io-index"
874
+checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
875
+dependencies = [
876
+ "cfg-if 1.0.4",
877
+ "js-sys",
878
+ "libc",
879
+ "r-efi",
880
+ "wasip2",
881
+ "wasm-bindgen",
882
+]
883
+
884
+[[package]]
885
+name = "getrandom"
886
+version = "0.4.0-rc.0"
887
+source = "registry+https://github.com/rust-lang/crates.io-index"
888
+checksum = "3b99f0d993a2b9b97b9a201193aa8ad21305cde06a3be9a7e1f8f4201e5cc27e"
889
+dependencies = [
890
+ "cfg-if 1.0.4",
891
+ "libc",
892
+ "r-efi",
893
+ "rand_core 0.10.0-rc-3",
894
+ "wasip2",
895
+]
896
+
897
+[[package]]
898
+name = "ghash"
899
+version = "0.6.0-rc.3"
900
+source = "registry+https://github.com/rust-lang/crates.io-index"
901
+checksum = "333de57ed9494a40df4bbb866752b100819dde0d18f2264c48f5a08a85fe673d"
902
+dependencies = [
903
+ "polyval",
904
+]
905
+
906
+[[package]]
907
+name = "gimli"
908
+version = "0.32.3"
909
+source = "registry+https://github.com/rust-lang/crates.io-index"
910
+checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7"
911
+
912
+[[package]]
913
+name = "git-version"
914
+version = "0.3.9"
915
+source = "registry+https://github.com/rust-lang/crates.io-index"
916
+checksum = "1ad568aa3db0fcbc81f2f116137f263d7304f512a1209b35b85150d3ef88ad19"
917
+dependencies = [
918
+ "git-version-macro",
919
+]
920
+
921
+[[package]]
922
+name = "git-version-macro"
923
+version = "0.3.9"
924
+source = "registry+https://github.com/rust-lang/crates.io-index"
925
+checksum = "53010ccb100b96a67bc32c0175f0ed1426b31b655d562898e57325f81c023ac0"
926
+dependencies = [
927
+ "proc-macro2",
928
+ "quote",
929
+ "syn 2.0.107",
930
+]
931
+
932
+[[package]]
933
+name = "glob"
934
+version = "0.3.3"
935
+source = "registry+https://github.com/rust-lang/crates.io-index"
936
+checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
937
+
938
+[[package]]
939
+name = "goblin"
940
+version = "0.10.2"
941
+source = "registry+https://github.com/rust-lang/crates.io-index"
942
+checksum = "7be320f077239a0361c20d608b4768c62a1b77aa4946dd76395aa4cd502cba7d"
943
+dependencies = [
944
+ "log",
945
+ "plain",
946
+ "scroll",
947
+]
948
+
949
+[[package]]
950
+name = "h2"
951
+version = "0.3.27"
952
+source = "registry+https://github.com/rust-lang/crates.io-index"
953
+checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d"
954
+dependencies = [
955
+ "bytes",
956
+ "fnv",
957
+ "futures-core",
958
+ "futures-sink",
959
+ "futures-util",
960
+ "http 0.2.12",
961
+ "indexmap 2.12.0",
962
+ "slab",
963
+ "tokio",
964
+ "tokio-util",
965
+ "tracing",
966
+]
967
+
968
+[[package]]
969
+name = "h2"
970
+version = "0.4.12"
971
+source = "registry+https://github.com/rust-lang/crates.io-index"
972
+checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386"
973
+dependencies = [
974
+ "atomic-waker",
975
+ "bytes",
976
+ "fnv",
977
+ "futures-core",
978
+ "futures-sink",
979
+ "http 1.3.1",
980
+ "indexmap 2.12.0",
981
+ "slab",
982
+ "tokio",
983
+ "tokio-util",
984
+ "tracing",
985
+]
986
+
987
+[[package]]
988
+name = "hashbrown"
989
+version = "0.12.3"
990
+source = "registry+https://github.com/rust-lang/crates.io-index"
991
+checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
992
+
993
+[[package]]
994
+name = "hashbrown"
995
+version = "0.16.0"
996
+source = "registry+https://github.com/rust-lang/crates.io-index"
997
+checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d"
998
+
999
+[[package]]
1000
+name = "heck"
1001
+version = "0.4.1"
1002
+source = "registry+https://github.com/rust-lang/crates.io-index"
1003
+checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
1004
+
1005
+[[package]]
1006
+name = "hermit-abi"
1007
+version = "0.1.19"
1008
+source = "registry+https://github.com/rust-lang/crates.io-index"
1009
+checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
1010
+dependencies = [
1011
+ "libc",
1012
+]
1013
+
1014
+[[package]]
1015
+name = "hermit-abi"
1016
+version = "0.5.2"
1017
+source = "registry+https://github.com/rust-lang/crates.io-index"
1018
+checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
1019
+
1020
+[[package]]
1021
+name = "hex"
1022
+version = "0.4.3"
1023
+source = "registry+https://github.com/rust-lang/crates.io-index"
1024
+checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
1025
+
1026
+[[package]]
1027
+name = "hmac"
1028
+version = "0.13.0-rc.3"
1029
+source = "registry+https://github.com/rust-lang/crates.io-index"
1030
+checksum = "f1c597ac7d6cc8143e30e83ef70915e7f883b18d8bec2e2b2bce47f5bbb06d57"
1031
+dependencies = [
1032
+ "digest",
1033
+]
1034
+
1035
+[[package]]
1036
+name = "http"
1037
+version = "0.2.12"
1038
+source = "registry+https://github.com/rust-lang/crates.io-index"
1039
+checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1"
1040
+dependencies = [
1041
+ "bytes",
1042
+ "fnv",
1043
+ "itoa",
1044
+]
1045
+
1046
+[[package]]
1047
+name = "http"
1048
+version = "1.3.1"
1049
+source = "registry+https://github.com/rust-lang/crates.io-index"
1050
+checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565"
1051
+dependencies = [
1052
+ "bytes",
1053
+ "fnv",
1054
+ "itoa",
1055
+]
1056
+
1057
+[[package]]
1058
+name = "http-body"
1059
+version = "0.4.6"
1060
+source = "registry+https://github.com/rust-lang/crates.io-index"
1061
+checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2"
1062
+dependencies = [
1063
+ "bytes",
1064
+ "http 0.2.12",
1065
+ "pin-project-lite",
1066
+]
1067
+
1068
+[[package]]
1069
+name = "http-body"
1070
+version = "1.0.1"
1071
+source = "registry+https://github.com/rust-lang/crates.io-index"
1072
+checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
1073
+dependencies = [
1074
+ "bytes",
1075
+ "http 1.3.1",
1076
+]
1077
+
1078
+[[package]]
1079
+name = "http-body-util"
1080
+version = "0.1.3"
1081
+source = "registry+https://github.com/rust-lang/crates.io-index"
1082
+checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a"
1083
+dependencies = [
1084
+ "bytes",
1085
+ "futures-core",
1086
+ "http 1.3.1",
1087
+ "http-body 1.0.1",
1088
+ "pin-project-lite",
1089
+]
1090
+
1091
+[[package]]
1092
+name = "httparse"
1093
+version = "1.10.1"
1094
+source = "registry+https://github.com/rust-lang/crates.io-index"
1095
+checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
1096
+
1097
+[[package]]
1098
+name = "httpdate"
1099
+version = "1.0.3"
1100
+source = "registry+https://github.com/rust-lang/crates.io-index"
1101
+checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
1102
+
1103
+[[package]]
1104
+name = "humantime"
1105
+version = "1.3.0"
1106
+source = "registry+https://github.com/rust-lang/crates.io-index"
1107
+checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
1108
+dependencies = [
1109
+ "quick-error",
1110
+]
1111
+
1112
+[[package]]
1113
+name = "hybrid-array"
1114
+version = "0.4.5"
1115
+source = "registry+https://github.com/rust-lang/crates.io-index"
1116
+checksum = "f471e0a81b2f90ffc0cb2f951ae04da57de8baa46fa99112b062a5173a5088d0"
1117
+dependencies = [
1118
+ "typenum",
1119
+]
1120
+
1121
+[[package]]
1122
+name = "hyper"
1123
+version = "0.14.32"
1124
+source = "registry+https://github.com/rust-lang/crates.io-index"
1125
+checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7"
1126
+dependencies = [
1127
+ "bytes",
1128
+ "futures-channel",
1129
+ "futures-core",
1130
+ "futures-util",
1131
+ "h2 0.3.27",
1132
+ "http 0.2.12",
1133
+ "http-body 0.4.6",
1134
+ "httparse",
1135
+ "httpdate",
1136
+ "itoa",
1137
+ "pin-project-lite",
1138
+ "socket2 0.5.10",
1139
+ "tokio",
1140
+ "tower-service",
1141
+ "tracing",
1142
+ "want",
1143
+]
1144
+
1145
+[[package]]
1146
+name = "hyper"
1147
+version = "1.7.0"
1148
+source = "registry+https://github.com/rust-lang/crates.io-index"
1149
+checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e"
1150
+dependencies = [
1151
+ "atomic-waker",
1152
+ "bytes",
1153
+ "futures-channel",
1154
+ "futures-core",
1155
+ "h2 0.4.12",
1156
+ "http 1.3.1",
1157
+ "http-body 1.0.1",
1158
+ "httparse",
1159
+ "itoa",
1160
+ "pin-project-lite",
1161
+ "pin-utils",
1162
+ "smallvec",
1163
+ "tokio",
1164
+ "want",
1165
+]
1166
+
1167
+[[package]]
1168
+name = "hyper-rustls"
1169
+version = "0.24.2"
1170
+source = "registry+https://github.com/rust-lang/crates.io-index"
1171
+checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590"
1172
+dependencies = [
1173
+ "futures-util",
1174
+ "http 0.2.12",
1175
+ "hyper 0.14.32",
1176
+ "rustls 0.21.12",
1177
+ "tokio",
1178
+ "tokio-rustls 0.24.1",
1179
+]
1180
+
1181
+[[package]]
1182
+name = "hyper-rustls"
1183
+version = "0.27.7"
1184
+source = "registry+https://github.com/rust-lang/crates.io-index"
1185
+checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58"
1186
+dependencies = [
1187
+ "http 1.3.1",
1188
+ "hyper 1.7.0",
1189
+ "hyper-util",
1190
+ "rustls 0.23.33",
1191
+ "rustls-pki-types",
1192
+ "tokio",
1193
+ "tokio-rustls 0.26.4",
1194
+ "tower-service",
1195
+ "webpki-roots 1.0.4",
1196
+]
1197
+
1198
+[[package]]
1199
+name = "hyper-tls"
1200
+version = "0.6.0"
1201
+source = "registry+https://github.com/rust-lang/crates.io-index"
1202
+checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
1203
+dependencies = [
1204
+ "bytes",
1205
+ "http-body-util",
1206
+ "hyper 1.7.0",
1207
+ "hyper-util",
1208
+ "native-tls",
1209
+ "tokio",
1210
+ "tokio-native-tls",
1211
+ "tower-service",
1212
+]
1213
+
1214
+[[package]]
1215
+name = "hyper-util"
1216
+version = "0.1.17"
1217
+source = "registry+https://github.com/rust-lang/crates.io-index"
1218
+checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8"
1219
+dependencies = [
1220
+ "base64 0.22.1",
1221
+ "bytes",
1222
+ "futures-channel",
1223
+ "futures-core",
1224
+ "futures-util",
1225
+ "http 1.3.1",
1226
+ "http-body 1.0.1",
1227
+ "hyper 1.7.0",
1228
+ "ipnet",
1229
+ "libc",
1230
+ "percent-encoding",
1231
+ "pin-project-lite",
1232
+ "socket2 0.6.1",
1233
+ "system-configuration 0.6.1",
1234
+ "tokio",
1235
+ "tower-service",
1236
+ "tracing",
1237
+ "windows-registry",
1238
+]
1239
+
1240
+[[package]]
1241
+name = "iana-time-zone"
1242
+version = "0.1.64"
1243
+source = "registry+https://github.com/rust-lang/crates.io-index"
1244
+checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb"
1245
+dependencies = [
1246
+ "android_system_properties",
1247
+ "core-foundation-sys",
1248
+ "iana-time-zone-haiku",
1249
+ "js-sys",
1250
+ "log",
1251
+ "wasm-bindgen",
1252
+ "windows-core",
1253
+]
1254
+
1255
+[[package]]
1256
+name = "iana-time-zone-haiku"
1257
+version = "0.1.2"
1258
+source = "registry+https://github.com/rust-lang/crates.io-index"
1259
+checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
1260
+dependencies = [
1261
+ "cc",
1262
+]
1263
+
1264
+[[package]]
1265
+name = "icu_collections"
1266
+version = "2.0.0"
1267
+source = "registry+https://github.com/rust-lang/crates.io-index"
1268
+checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47"
1269
+dependencies = [
1270
+ "displaydoc",
1271
+ "potential_utf",
1272
+ "yoke",
1273
+ "zerofrom",
1274
+ "zerovec",
1275
+]
1276
+
1277
+[[package]]
1278
+name = "icu_locale_core"
1279
+version = "2.0.0"
1280
+source = "registry+https://github.com/rust-lang/crates.io-index"
1281
+checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a"
1282
+dependencies = [
1283
+ "displaydoc",
1284
+ "litemap",
1285
+ "tinystr",
1286
+ "writeable",
1287
+ "zerovec",
1288
+]
1289
+
1290
+[[package]]
1291
+name = "icu_normalizer"
1292
+version = "2.0.0"
1293
+source = "registry+https://github.com/rust-lang/crates.io-index"
1294
+checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979"
1295
+dependencies = [
1296
+ "displaydoc",
1297
+ "icu_collections",
1298
+ "icu_normalizer_data",
1299
+ "icu_properties",
1300
+ "icu_provider",
1301
+ "smallvec",
1302
+ "zerovec",
1303
+]
1304
+
1305
+[[package]]
1306
+name = "icu_normalizer_data"
1307
+version = "2.0.0"
1308
+source = "registry+https://github.com/rust-lang/crates.io-index"
1309
+checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3"
1310
+
1311
+[[package]]
1312
+name = "icu_properties"
1313
+version = "2.0.1"
1314
+source = "registry+https://github.com/rust-lang/crates.io-index"
1315
+checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b"
1316
+dependencies = [
1317
+ "displaydoc",
1318
+ "icu_collections",
1319
+ "icu_locale_core",
1320
+ "icu_properties_data",
1321
+ "icu_provider",
1322
+ "potential_utf",
1323
+ "zerotrie",
1324
+ "zerovec",
1325
+]
1326
+
1327
+[[package]]
1328
+name = "icu_properties_data"
1329
+version = "2.0.1"
1330
+source = "registry+https://github.com/rust-lang/crates.io-index"
1331
+checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632"
1332
+
1333
+[[package]]
1334
+name = "icu_provider"
1335
+version = "2.0.0"
1336
+source = "registry+https://github.com/rust-lang/crates.io-index"
1337
+checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af"
1338
+dependencies = [
1339
+ "displaydoc",
1340
+ "icu_locale_core",
1341
+ "stable_deref_trait",
1342
+ "tinystr",
1343
+ "writeable",
1344
+ "yoke",
1345
+ "zerofrom",
1346
+ "zerotrie",
1347
+ "zerovec",
1348
+]
1349
+
1350
+[[package]]
1351
+name = "idna"
1352
+version = "1.1.0"
1353
+source = "registry+https://github.com/rust-lang/crates.io-index"
1354
+checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de"
1355
+dependencies = [
1356
+ "idna_adapter",
1357
+ "smallvec",
1358
+ "utf8_iter",
1359
+]
1360
+
1361
+[[package]]
1362
+name = "idna_adapter"
1363
+version = "1.2.1"
1364
+source = "registry+https://github.com/rust-lang/crates.io-index"
1365
+checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344"
1366
+dependencies = [
1367
+ "icu_normalizer",
1368
+ "icu_properties",
1369
+]
1370
+
1371
+[[package]]
1372
+name = "indexmap"
1373
+version = "1.9.3"
1374
+source = "registry+https://github.com/rust-lang/crates.io-index"
1375
+checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
1376
+dependencies = [
1377
+ "autocfg",
1378
+ "hashbrown 0.12.3",
1379
+ "serde",
1380
+]
1381
+
1382
+[[package]]
1383
+name = "indexmap"
1384
+version = "2.12.0"
1385
+source = "registry+https://github.com/rust-lang/crates.io-index"
1386
+checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f"
1387
+dependencies = [
1388
+ "equivalent",
1389
+ "hashbrown 0.16.0",
1390
+]
1391
+
1392
+[[package]]
1393
+name = "inout"
1394
+version = "0.2.1"
1395
+source = "registry+https://github.com/rust-lang/crates.io-index"
1396
+checksum = "c7357b6e7aa75618c7864ebd0634b115a7218b0615f4cb1df33ac3eca23943d4"
1397
+dependencies = [
1398
+ "block-padding",
1399
+ "hybrid-array",
1400
+]
1401
+
1402
+[[package]]
1403
+name = "ipnet"
1404
+version = "2.11.0"
1405
+source = "registry+https://github.com/rust-lang/crates.io-index"
1406
+checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130"
1407
+
1408
+[[package]]
1409
+name = "iri-string"
1410
+version = "0.7.9"
1411
+source = "registry+https://github.com/rust-lang/crates.io-index"
1412
+checksum = "4f867b9d1d896b67beb18518eda36fdb77a32ea590de864f1325b294a6d14397"
1413
+dependencies = [
1414
+ "memchr",
1415
+ "serde",
1416
+]
1417
+
1418
+[[package]]
1419
+name = "is-terminal"
1420
+version = "0.4.17"
1421
+source = "registry+https://github.com/rust-lang/crates.io-index"
1422
+checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46"
1423
+dependencies = [
1424
+ "hermit-abi 0.5.2",
1425
+ "libc",
1426
+ "windows-sys 0.61.2",
1427
+]
1428
+
1429
+[[package]]
1430
+name = "is_ci"
1431
+version = "1.2.0"
1432
+source = "registry+https://github.com/rust-lang/crates.io-index"
1433
+checksum = "7655c9839580ee829dfacba1d1278c2b7883e50a277ff7541299489d6bdfdc45"
1434
+
1435
+[[package]]
1436
+name = "is_terminal_polyfill"
1437
+version = "1.70.1"
1438
+source = "registry+https://github.com/rust-lang/crates.io-index"
1439
+checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
1440
+
1441
+[[package]]
1442
+name = "itertools"
1443
+version = "0.9.0"
1444
+source = "registry+https://github.com/rust-lang/crates.io-index"
1445
+checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
1446
+dependencies = [
1447
+ "either",
1448
+]
1449
+
1450
+[[package]]
1451
+name = "itertools"
1452
+version = "0.10.5"
1453
+source = "registry+https://github.com/rust-lang/crates.io-index"
1454
+checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
1455
+dependencies = [
1456
+ "either",
1457
+]
1458
+
1459
+[[package]]
1460
+name = "itoa"
1461
+version = "1.0.15"
1462
+source = "registry+https://github.com/rust-lang/crates.io-index"
1463
+checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
1464
+
1465
+[[package]]
1466
+name = "jiff"
1467
+version = "0.2.15"
1468
+source = "registry+https://github.com/rust-lang/crates.io-index"
1469
+checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49"
1470
+dependencies = [
1471
+ "jiff-static",
1472
+ "log",
1473
+ "portable-atomic",
1474
+ "portable-atomic-util",
1475
+ "serde",
1476
+]
1477
+
1478
+[[package]]
1479
+name = "jiff-static"
1480
+version = "0.2.15"
1481
+source = "registry+https://github.com/rust-lang/crates.io-index"
1482
+checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4"
1483
+dependencies = [
1484
+ "proc-macro2",
1485
+ "quote",
1486
+ "syn 2.0.107",
1487
+]
1488
+
1489
+[[package]]
1490
+name = "js-sys"
1491
+version = "0.3.81"
1492
+source = "registry+https://github.com/rust-lang/crates.io-index"
1493
+checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305"
1494
+dependencies = [
1495
+ "once_cell",
1496
+ "wasm-bindgen",
1497
+]
1498
+
1499
+[[package]]
1500
+name = "lazy_static"
1501
+version = "1.5.0"
1502
+source = "registry+https://github.com/rust-lang/crates.io-index"
1503
+checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
1504
+
1505
+[[package]]
1506
+name = "lazycell"
1507
+version = "1.3.0"
1508
+source = "registry+https://github.com/rust-lang/crates.io-index"
1509
+checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
1510
+
1511
+[[package]]
1512
+name = "libc"
1513
+version = "0.2.176"
1514
+source = "registry+https://github.com/rust-lang/crates.io-index"
1515
+checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174"
1516
+
1517
+[[package]]
1518
+name = "libloading"
1519
+version = "0.5.2"
1520
+source = "registry+https://github.com/rust-lang/crates.io-index"
1521
+checksum = "f2b111a074963af1d37a139918ac6d49ad1d0d5e47f72fd55388619691a7d753"
1522
+dependencies = [
1523
+ "cc",
1524
+ "winapi",
1525
+]
1526
+
1527
+[[package]]
1528
+name = "lief"
1529
+version = "0.17.1"
1530
+source = "registry+https://github.com/rust-lang/crates.io-index"
1531
+checksum = "18773f648622afc222330700726227739936a1fa0040b91f007c80605525c4ff"
1532
+dependencies = [
1533
+ "bitflags 2.10.0",
1534
+ "cxx",
1535
+ "lief-ffi",
1536
+ "num-bigint",
1537
+ "num-derive",
1538
+ "num-traits",
1539
+ "tempfile",
1540
+]
1541
+
1542
+[[package]]
1543
+name = "lief-build"
1544
+version = "0.17.1"
1545
+source = "registry+https://github.com/rust-lang/crates.io-index"
1546
+checksum = "3abce5340e56c7f9191d699302b9496445b0438033b48a9937b41c506f677731"
1547
+dependencies = [
1548
+ "git-version",
1549
+ "miette",
1550
+ "reqwest 0.11.24",
1551
+ "semver",
1552
+ "zip",
1553
+]
1554
+
1555
+[[package]]
1556
+name = "lief-ffi"
1557
+version = "0.17.1"
1558
+source = "registry+https://github.com/rust-lang/crates.io-index"
1559
+checksum = "fba2ccbe972b26212f69f7b938fc198214f4eaa7f548a8d724f1a04968137f96"
1560
+dependencies = [
1561
+ "autocxx",
1562
+ "cxx",
1563
+ "lief-build",
1564
+ "miette",
1565
+]
1566
+
1567
+[[package]]
1568
+name = "link-cplusplus"
1569
+version = "1.0.12"
1570
+source = "registry+https://github.com/rust-lang/crates.io-index"
1571
+checksum = "7f78c730aaa7d0b9336a299029ea49f9ee53b0ed06e9202e8cb7db9bae7b8c82"
1572
+dependencies = [
1573
+ "cc",
1574
+]
1575
+
1576
+[[package]]
1577
+name = "linux-raw-sys"
1578
+version = "0.11.0"
1579
+source = "registry+https://github.com/rust-lang/crates.io-index"
1580
+checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039"
1581
+
1582
+[[package]]
1583
+name = "litemap"
1584
+version = "0.8.0"
1585
+source = "registry+https://github.com/rust-lang/crates.io-index"
1586
+checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956"
1587
+
1588
+[[package]]
1589
+name = "log"
1590
+version = "0.4.29"
1591
+source = "registry+https://github.com/rust-lang/crates.io-index"
1592
+checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
1593
+
1594
+[[package]]
1595
+name = "lru-slab"
1596
+version = "0.1.2"
1597
+source = "registry+https://github.com/rust-lang/crates.io-index"
1598
+checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154"
1599
+
1600
+[[package]]
1601
+name = "mach2"
1602
+version = "0.4.3"
1603
+source = "registry+https://github.com/rust-lang/crates.io-index"
1604
+checksum = "d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44"
1605
+dependencies = [
1606
+ "libc",
1607
+]
1608
+
1609
+[[package]]
1610
+name = "memchr"
1611
+version = "2.7.6"
1612
+source = "registry+https://github.com/rust-lang/crates.io-index"
1613
+checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
1614
+
1615
+[[package]]
1616
+name = "memmap2"
1617
+version = "0.9.8"
1618
+source = "registry+https://github.com/rust-lang/crates.io-index"
1619
+checksum = "843a98750cd611cc2965a8213b53b43e715f13c37a9e096c6408e69990961db7"
1620
+dependencies = [
1621
+ "libc",
1622
+]
1623
+
1624
+[[package]]
1625
+name = "miette"
1626
+version = "5.10.0"
1627
+source = "registry+https://github.com/rust-lang/crates.io-index"
1628
+checksum = "59bb584eaeeab6bd0226ccf3509a69d7936d148cf3d036ad350abe35e8c6856e"
1629
+dependencies = [
1630
+ "backtrace",
1631
+ "backtrace-ext",
1632
+ "is-terminal",
1633
+ "miette-derive",
1634
+ "once_cell",
1635
+ "owo-colors",
1636
+ "supports-color",
1637
+ "supports-hyperlinks",
1638
+ "supports-unicode",
1639
+ "terminal_size",
1640
+ "textwrap 0.15.2",
1641
+ "thiserror 1.0.69",
1642
+ "unicode-width",
1643
+]
1644
+
1645
+[[package]]
1646
+name = "miette-derive"
1647
+version = "5.10.0"
1648
+source = "registry+https://github.com/rust-lang/crates.io-index"
1649
+checksum = "49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c"
1650
+dependencies = [
1651
+ "proc-macro2",
1652
+ "quote",
1653
+ "syn 2.0.107",
1654
+]
1655
+
1656
+[[package]]
1657
+name = "mime"
1658
+version = "0.3.17"
1659
+source = "registry+https://github.com/rust-lang/crates.io-index"
1660
+checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
1661
+
1662
+[[package]]
1663
+name = "miniz_oxide"
1664
+version = "0.8.9"
1665
+source = "registry+https://github.com/rust-lang/crates.io-index"
1666
+checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
1667
+dependencies = [
1668
+ "adler2",
1669
+ "simd-adler32",
1670
+]
1671
+
1672
+[[package]]
1673
+name = "mio"
1674
+version = "1.1.0"
1675
+source = "registry+https://github.com/rust-lang/crates.io-index"
1676
+checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873"
1677
+dependencies = [
1678
+ "libc",
1679
+ "wasi",
1680
+ "windows-sys 0.61.2",
1681
+]
1682
+
1683
+[[package]]
1684
+name = "moveit"
1685
+version = "0.6.0"
1686
+source = "registry+https://github.com/rust-lang/crates.io-index"
1687
+checksum = "87d7335204cb6ef7bd647fa6db0be3e4d7aa25b5823a7aa030027ddf512cefba"
1688
+dependencies = [
1689
+ "cxx",
1690
+]
1691
+
1692
+[[package]]
1693
+name = "native-tls"
1694
+version = "0.2.14"
1695
+source = "registry+https://github.com/rust-lang/crates.io-index"
1696
+checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e"
1697
+dependencies = [
1698
+ "libc",
1699
+ "log",
1700
+ "openssl",
1701
+ "openssl-probe",
1702
+ "openssl-sys",
1703
+ "schannel",
1704
+ "security-framework",
1705
+ "security-framework-sys",
1706
+ "tempfile",
1707
+]
1708
+
1709
+[[package]]
1710
+name = "nom"
1711
+version = "5.1.3"
1712
+source = "registry+https://github.com/rust-lang/crates.io-index"
1713
+checksum = "08959a387a676302eebf4ddbcbc611da04285579f76f88ee0506c63b1a61dd4b"
1714
+dependencies = [
1715
+ "memchr",
1716
+ "version_check",
1717
+]
1718
+
1719
+[[package]]
1720
+name = "num-bigint"
1721
+version = "0.4.6"
1722
+source = "registry+https://github.com/rust-lang/crates.io-index"
1723
+checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
1724
+dependencies = [
1725
+ "num-integer",
1726
+ "num-traits",
1727
+]
1728
+
1729
+[[package]]
1730
+name = "num-conv"
1731
+version = "0.1.0"
1732
+source = "registry+https://github.com/rust-lang/crates.io-index"
1733
+checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
1734
+
1735
+[[package]]
1736
+name = "num-derive"
1737
+version = "0.4.2"
1738
+source = "registry+https://github.com/rust-lang/crates.io-index"
1739
+checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
1740
+dependencies = [
1741
+ "proc-macro2",
1742
+ "quote",
1743
+ "syn 2.0.107",
1744
+]
1745
+
1746
+[[package]]
1747
+name = "num-integer"
1748
+version = "0.1.46"
1749
+source = "registry+https://github.com/rust-lang/crates.io-index"
1750
+checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
1751
+dependencies = [
1752
+ "num-traits",
1753
+]
1754
+
1755
+[[package]]
1756
+name = "num-traits"
1757
+version = "0.2.19"
1758
+source = "registry+https://github.com/rust-lang/crates.io-index"
1759
+checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
1760
+dependencies = [
1761
+ "autocfg",
1762
+]
1763
+
1764
+[[package]]
1765
+name = "object"
1766
+version = "0.37.3"
1767
+source = "registry+https://github.com/rust-lang/crates.io-index"
1768
+checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe"
1769
+dependencies = [
1770
+ "memchr",
1771
+]
1772
+
1773
+[[package]]
1774
+name = "once_cell"
1775
+version = "1.21.3"
1776
+source = "registry+https://github.com/rust-lang/crates.io-index"
1777
+checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
1778
+
1779
+[[package]]
1780
+name = "once_cell_polyfill"
1781
+version = "1.70.1"
1782
+source = "registry+https://github.com/rust-lang/crates.io-index"
1783
+checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
1784
+
1785
+[[package]]
1786
+name = "openssl"
1787
+version = "0.10.75"
1788
+source = "registry+https://github.com/rust-lang/crates.io-index"
1789
+checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328"
1790
+dependencies = [
1791
+ "bitflags 2.10.0",
1792
+ "cfg-if 1.0.4",
1793
+ "foreign-types",
1794
+ "libc",
1795
+ "once_cell",
1796
+ "openssl-macros",
1797
+ "openssl-sys",
1798
+]
1799
+
1800
+[[package]]
1801
+name = "openssl-macros"
1802
+version = "0.1.1"
1803
+source = "registry+https://github.com/rust-lang/crates.io-index"
1804
+checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
1805
+dependencies = [
1806
+ "proc-macro2",
1807
+ "quote",
1808
+ "syn 2.0.107",
1809
+]
1810
+
1811
+[[package]]
1812
+name = "openssl-probe"
1813
+version = "0.1.6"
1814
+source = "registry+https://github.com/rust-lang/crates.io-index"
1815
+checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
1816
+
1817
+[[package]]
1818
+name = "openssl-sys"
1819
+version = "0.9.111"
1820
+source = "registry+https://github.com/rust-lang/crates.io-index"
1821
+checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321"
1822
+dependencies = [
1823
+ "cc",
1824
+ "libc",
1825
+ "pkg-config",
1826
+ "vcpkg",
1827
+]
1828
+
1829
+[[package]]
1830
+name = "ouroboros"
1831
+version = "0.18.5"
1832
+source = "registry+https://github.com/rust-lang/crates.io-index"
1833
+checksum = "1e0f050db9c44b97a94723127e6be766ac5c340c48f2c4bb3ffa11713744be59"
1834
+dependencies = [
1835
+ "aliasable",
1836
+ "ouroboros_macro",
1837
+ "static_assertions",
1838
+]
1839
+
1840
+[[package]]
1841
+name = "ouroboros_macro"
1842
+version = "0.18.5"
1843
+source = "registry+https://github.com/rust-lang/crates.io-index"
1844
+checksum = "3c7028bdd3d43083f6d8d4d5187680d0d3560d54df4cc9d752005268b41e64d0"
1845
+dependencies = [
1846
+ "heck",
1847
+ "proc-macro2",
1848
+ "proc-macro2-diagnostics",
1849
+ "quote",
1850
+ "syn 2.0.107",
1851
+]
1852
+
1853
+[[package]]
1854
+name = "owo-colors"
1855
+version = "3.5.0"
1856
+source = "registry+https://github.com/rust-lang/crates.io-index"
1857
+checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f"
1858
+
1859
+[[package]]
1860
+name = "pbkdf2"
1861
+version = "0.13.0-rc.5"
1862
+source = "registry+https://github.com/rust-lang/crates.io-index"
1863
+checksum = "c015873c38594dfb7724f90b2ed912a606697393bda2d39fd83c2394301f808a"
1864
+dependencies = [
1865
+ "digest",
1866
+ "hmac",
1867
+]
1868
+
1869
+[[package]]
1870
+name = "peeking_take_while"
1871
+version = "0.1.2"
1872
+source = "registry+https://github.com/rust-lang/crates.io-index"
1873
+checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
1874
+
1875
+[[package]]
1876
+name = "percent-encoding"
1877
+version = "2.3.2"
1878
+source = "registry+https://github.com/rust-lang/crates.io-index"
1879
+checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
1880
+
1881
+[[package]]
1882
+name = "pin-project-lite"
1883
+version = "0.2.16"
1884
+source = "registry+https://github.com/rust-lang/crates.io-index"
1885
+checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
1886
+
1887
+[[package]]
1888
+name = "pin-utils"
1889
+version = "0.1.0"
1890
+source = "registry+https://github.com/rust-lang/crates.io-index"
1891
+checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
1892
+
1893
+[[package]]
1894
+name = "pkg-config"
1895
+version = "0.3.32"
1896
+source = "registry+https://github.com/rust-lang/crates.io-index"
1897
+checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
1898
+
1899
+[[package]]
1900
+name = "plain"
1901
+version = "0.2.3"
1902
+source = "registry+https://github.com/rust-lang/crates.io-index"
1903
+checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
1904
+
1905
+[[package]]
1906
+name = "plist"
1907
+version = "1.8.0"
1908
+source = "registry+https://github.com/rust-lang/crates.io-index"
1909
+checksum = "740ebea15c5d1428f910cd1a5f52cebf8d25006245ed8ade92702f4943d91e07"
1910
+dependencies = [
1911
+ "base64 0.22.1",
1912
+ "indexmap 2.12.0",
1913
+ "quick-xml",
1914
+ "serde",
1915
+ "time",
1916
+]
1917
+
1918
+[[package]]
1919
+name = "plist-macros"
1920
+version = "0.1.0"
1921
+dependencies = [
1922
+ "plist",
1923
+]
1924
+
1925
+[[package]]
1926
+name = "polyval"
1927
+version = "0.7.0-rc.3"
1928
+source = "registry+https://github.com/rust-lang/crates.io-index"
1929
+checksum = "1ad60831c19edda4b20878a676595c357e93a9b4e6dca2ba98d75b01066b317b"
1930
+dependencies = [
1931
+ "cfg-if 1.0.4",
1932
+ "cpufeatures",
1933
+ "universal-hash",
1934
+]
1935
+
1936
+[[package]]
1937
+name = "portable-atomic"
1938
+version = "1.11.1"
1939
+source = "registry+https://github.com/rust-lang/crates.io-index"
1940
+checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
1941
+
1942
+[[package]]
1943
+name = "portable-atomic-util"
1944
+version = "0.2.4"
1945
+source = "registry+https://github.com/rust-lang/crates.io-index"
1946
+checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507"
1947
+dependencies = [
1948
+ "portable-atomic",
1949
+]
1950
+
1951
+[[package]]
1952
+name = "potential_utf"
1953
+version = "0.1.3"
1954
+source = "registry+https://github.com/rust-lang/crates.io-index"
1955
+checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a"
1956
+dependencies = [
1957
+ "zerovec",
1958
+]
1959
+
1960
+[[package]]
1961
+name = "powerfmt"
1962
+version = "0.2.0"
1963
+source = "registry+https://github.com/rust-lang/crates.io-index"
1964
+checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
1965
+
1966
+[[package]]
1967
+name = "ppv-lite86"
1968
+version = "0.2.21"
1969
+source = "registry+https://github.com/rust-lang/crates.io-index"
1970
+checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
1971
+dependencies = [
1972
+ "zerocopy",
1973
+]
1974
+
1975
+[[package]]
1976
+name = "proc-macro-error"
1977
+version = "1.0.4"
1978
+source = "registry+https://github.com/rust-lang/crates.io-index"
1979
+checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
1980
+dependencies = [
1981
+ "proc-macro-error-attr",
1982
+ "proc-macro2",
1983
+ "quote",
1984
+ "syn 1.0.109",
1985
+ "version_check",
1986
+]
1987
+
1988
+[[package]]
1989
+name = "proc-macro-error-attr"
1990
+version = "1.0.4"
1991
+source = "registry+https://github.com/rust-lang/crates.io-index"
1992
+checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
1993
+dependencies = [
1994
+ "proc-macro2",
1995
+ "quote",
1996
+ "version_check",
1997
+]
1998
+
1999
+[[package]]
2000
+name = "proc-macro2"
2001
+version = "1.0.101"
2002
+source = "registry+https://github.com/rust-lang/crates.io-index"
2003
+checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
2004
+dependencies = [
2005
+ "unicode-ident",
2006
+]
2007
+
2008
+[[package]]
2009
+name = "proc-macro2-diagnostics"
2010
+version = "0.10.1"
2011
+source = "registry+https://github.com/rust-lang/crates.io-index"
2012
+checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8"
2013
+dependencies = [
2014
+ "proc-macro2",
2015
+ "quote",
2016
+ "syn 2.0.107",
2017
+ "version_check",
2018
+ "yansi",
2019
+]
2020
+
2021
+[[package]]
2022
+name = "purple-builder"
2023
+version = "0.1.0"
2024
+dependencies = [
2025
+ "adi",
2026
+ "elf-loader",
2027
+ "env_logger 0.11.8",
2028
+]
2029
+
2030
+[[package]]
2031
+name = "quick-error"
2032
+version = "1.2.3"
2033
+source = "registry+https://github.com/rust-lang/crates.io-index"
2034
+checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
2035
+
2036
+[[package]]
2037
+name = "quick-xml"
2038
+version = "0.38.4"
2039
+source = "registry+https://github.com/rust-lang/crates.io-index"
2040
+checksum = "b66c2058c55a409d601666cffe35f04333cf1013010882cec174a7467cd4e21c"
2041
+dependencies = [
2042
+ "memchr",
2043
+]
2044
+
2045
+[[package]]
2046
+name = "quinn"
2047
+version = "0.11.9"
2048
+source = "registry+https://github.com/rust-lang/crates.io-index"
2049
+checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20"
2050
+dependencies = [
2051
+ "bytes",
2052
+ "cfg_aliases",
2053
+ "pin-project-lite",
2054
+ "quinn-proto",
2055
+ "quinn-udp",
2056
+ "rustc-hash 2.1.1",
2057
+ "rustls 0.23.33",
2058
+ "socket2 0.6.1",
2059
+ "thiserror 2.0.17",
2060
+ "tokio",
2061
+ "tracing",
2062
+ "web-time",
2063
+]
2064
+
2065
+[[package]]
2066
+name = "quinn-proto"
2067
+version = "0.11.13"
2068
+source = "registry+https://github.com/rust-lang/crates.io-index"
2069
+checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31"
2070
+dependencies = [
2071
+ "bytes",
2072
+ "getrandom 0.3.4",
2073
+ "lru-slab",
2074
+ "rand",
2075
+ "ring",
2076
+ "rustc-hash 2.1.1",
2077
+ "rustls 0.23.33",
2078
+ "rustls-pki-types",
2079
+ "slab",
2080
+ "thiserror 2.0.17",
2081
+ "tinyvec",
2082
+ "tracing",
2083
+ "web-time",
2084
+]
2085
+
2086
+[[package]]
2087
+name = "quinn-udp"
2088
+version = "0.5.14"
2089
+source = "registry+https://github.com/rust-lang/crates.io-index"
2090
+checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd"
2091
+dependencies = [
2092
+ "cfg_aliases",
2093
+ "libc",
2094
+ "once_cell",
2095
+ "socket2 0.6.1",
2096
+ "tracing",
2097
+ "windows-sys 0.60.2",
2098
+]
2099
+
2100
+[[package]]
2101
+name = "quote"
2102
+version = "1.0.41"
2103
+source = "registry+https://github.com/rust-lang/crates.io-index"
2104
+checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1"
2105
+dependencies = [
2106
+ "proc-macro2",
2107
+]
2108
+
2109
+[[package]]
2110
+name = "r-efi"
2111
+version = "5.3.0"
2112
+source = "registry+https://github.com/rust-lang/crates.io-index"
2113
+checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
2114
+
2115
+[[package]]
2116
+name = "rand"
2117
+version = "0.9.2"
2118
+source = "registry+https://github.com/rust-lang/crates.io-index"
2119
+checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
2120
+dependencies = [
2121
+ "rand_chacha",
2122
+ "rand_core 0.9.3",
2123
+]
2124
+
2125
+[[package]]
2126
+name = "rand_chacha"
2127
+version = "0.9.0"
2128
+source = "registry+https://github.com/rust-lang/crates.io-index"
2129
+checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
2130
+dependencies = [
2131
+ "ppv-lite86",
2132
+ "rand_core 0.9.3",
2133
+]
2134
+
2135
+[[package]]
2136
+name = "rand_core"
2137
+version = "0.9.3"
2138
+source = "registry+https://github.com/rust-lang/crates.io-index"
2139
+checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
2140
+dependencies = [
2141
+ "getrandom 0.3.4",
2142
+]
2143
+
2144
+[[package]]
2145
+name = "rand_core"
2146
+version = "0.10.0-rc-3"
2147
+source = "registry+https://github.com/rust-lang/crates.io-index"
2148
+checksum = "f66ee92bc15280519ef199a274fe0cafff4245d31bc39aaa31c011ad56cb1f05"
2149
+
2150
+[[package]]
2151
+name = "regex"
2152
+version = "1.12.2"
2153
+source = "registry+https://github.com/rust-lang/crates.io-index"
2154
+checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4"
2155
+dependencies = [
2156
+ "aho-corasick",
2157
+ "memchr",
2158
+ "regex-automata",
2159
+ "regex-syntax",
2160
+]
2161
+
2162
+[[package]]
2163
+name = "regex-automata"
2164
+version = "0.4.13"
2165
+source = "registry+https://github.com/rust-lang/crates.io-index"
2166
+checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c"
2167
+dependencies = [
2168
+ "aho-corasick",
2169
+ "memchr",
2170
+ "regex-syntax",
2171
+]
2172
+
2173
+[[package]]
2174
+name = "regex-syntax"
2175
+version = "0.8.8"
2176
+source = "registry+https://github.com/rust-lang/crates.io-index"
2177
+checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
2178
+
2179
+[[package]]
2180
+name = "region"
2181
+version = "3.0.2"
2182
+source = "registry+https://github.com/rust-lang/crates.io-index"
2183
+checksum = "e6b6ebd13bc009aef9cd476c1310d49ac354d36e240cf1bd753290f3dc7199a7"
2184
+dependencies = [
2185
+ "bitflags 1.3.2",
2186
+ "libc",
2187
+ "mach2",
2188
+ "windows-sys 0.52.0",
2189
+]
2190
+
2191
+[[package]]
2192
+name = "reqwest"
2193
+version = "0.11.24"
2194
+source = "registry+https://github.com/rust-lang/crates.io-index"
2195
+checksum = "c6920094eb85afde5e4a138be3f2de8bbdf28000f0029e72c45025a56b042251"
2196
+dependencies = [
2197
+ "base64 0.21.7",
2198
+ "bytes",
2199
+ "encoding_rs",
2200
+ "futures-core",
2201
+ "futures-util",
2202
+ "h2 0.3.27",
2203
+ "http 0.2.12",
2204
+ "http-body 0.4.6",
2205
+ "hyper 0.14.32",
2206
+ "hyper-rustls 0.24.2",
2207
+ "ipnet",
2208
+ "js-sys",
2209
+ "log",
2210
+ "mime",
2211
+ "once_cell",
2212
+ "percent-encoding",
2213
+ "pin-project-lite",
2214
+ "rustls 0.21.12",
2215
+ "rustls-pemfile",
2216
+ "serde",
2217
+ "serde_json",
2218
+ "serde_urlencoded",
2219
+ "sync_wrapper 0.1.2",
2220
+ "system-configuration 0.5.1",
2221
+ "tokio",
2222
+ "tokio-rustls 0.24.1",
2223
+ "tower-service",
2224
+ "url",
2225
+ "wasm-bindgen",
2226
+ "wasm-bindgen-futures",
2227
+ "web-sys",
2228
+ "webpki-roots 0.25.4",
2229
+ "winreg",
2230
+]
2231
+
2232
+[[package]]
2233
+name = "reqwest"
2234
+version = "0.12.27"
2235
+source = "registry+https://github.com/rust-lang/crates.io-index"
2236
+checksum = "8e893f6bece5953520ddbb3f8f46f3ef36dd1fef4ee9b087c4b4a725fd5d10e4"
2237
+dependencies = [
2238
+ "base64 0.22.1",
2239
+ "bytes",
2240
+ "encoding_rs",
2241
+ "futures-core",
2242
+ "h2 0.4.12",
2243
+ "http 1.3.1",
2244
+ "http-body 1.0.1",
2245
+ "http-body-util",
2246
+ "hyper 1.7.0",
2247
+ "hyper-rustls 0.27.7",
2248
+ "hyper-tls",
2249
+ "hyper-util",
2250
+ "js-sys",
2251
+ "log",
2252
+ "mime",
2253
+ "native-tls",
2254
+ "percent-encoding",
2255
+ "pin-project-lite",
2256
+ "quinn",
2257
+ "rustls 0.23.33",
2258
+ "rustls-pki-types",
2259
+ "serde",
2260
+ "serde_json",
2261
+ "serde_urlencoded",
2262
+ "sync_wrapper 1.0.2",
2263
+ "tokio",
2264
+ "tokio-native-tls",
2265
+ "tokio-rustls 0.26.4",
2266
+ "tower",
2267
+ "tower-http",
2268
+ "tower-service",
2269
+ "url",
2270
+ "wasm-bindgen",
2271
+ "wasm-bindgen-futures",
2272
+ "web-sys",
2273
+ "webpki-roots 1.0.4",
2274
+]
2275
+
2276
+[[package]]
2277
+name = "ring"
2278
+version = "0.17.14"
2279
+source = "registry+https://github.com/rust-lang/crates.io-index"
2280
+checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
2281
+dependencies = [
2282
+ "cc",
2283
+ "cfg-if 1.0.4",
2284
+ "getrandom 0.2.16",
2285
+ "libc",
2286
+ "untrusted",
2287
+ "windows-sys 0.52.0",
2288
+]
2289
+
2290
+[[package]]
2291
+name = "rustc-demangle"
2292
+version = "0.1.26"
2293
+source = "registry+https://github.com/rust-lang/crates.io-index"
2294
+checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace"
2295
+
2296
+[[package]]
2297
+name = "rustc-hash"
2298
+version = "1.1.0"
2299
+source = "registry+https://github.com/rust-lang/crates.io-index"
2300
+checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
2301
+
2302
+[[package]]
2303
+name = "rustc-hash"
2304
+version = "2.1.1"
2305
+source = "registry+https://github.com/rust-lang/crates.io-index"
2306
+checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
2307
+
2308
+[[package]]
2309
+name = "rustix"
2310
+version = "1.1.2"
2311
+source = "registry+https://github.com/rust-lang/crates.io-index"
2312
+checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e"
2313
+dependencies = [
2314
+ "bitflags 2.10.0",
2315
+ "errno",
2316
+ "libc",
2317
+ "linux-raw-sys",
2318
+ "windows-sys 0.61.2",
2319
+]
2320
+
2321
+[[package]]
2322
+name = "rustls"
2323
+version = "0.21.12"
2324
+source = "registry+https://github.com/rust-lang/crates.io-index"
2325
+checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e"
2326
+dependencies = [
2327
+ "log",
2328
+ "ring",
2329
+ "rustls-webpki 0.101.7",
2330
+ "sct",
2331
+]
2332
+
2333
+[[package]]
2334
+name = "rustls"
2335
+version = "0.23.33"
2336
+source = "registry+https://github.com/rust-lang/crates.io-index"
2337
+checksum = "751e04a496ca00bb97a5e043158d23d66b5aabf2e1d5aa2a0aaebb1aafe6f82c"
2338
+dependencies = [
2339
+ "once_cell",
2340
+ "ring",
2341
+ "rustls-pki-types",
2342
+ "rustls-webpki 0.103.7",
2343
+ "subtle",
2344
+ "zeroize",
2345
+]
2346
+
2347
+[[package]]
2348
+name = "rustls-pemfile"
2349
+version = "1.0.4"
2350
+source = "registry+https://github.com/rust-lang/crates.io-index"
2351
+checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c"
2352
+dependencies = [
2353
+ "base64 0.21.7",
2354
+]
2355
+
2356
+[[package]]
2357
+name = "rustls-pki-types"
2358
+version = "1.12.0"
2359
+source = "registry+https://github.com/rust-lang/crates.io-index"
2360
+checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79"
2361
+dependencies = [
2362
+ "web-time",
2363
+ "zeroize",
2364
+]
2365
+
2366
+[[package]]
2367
+name = "rustls-webpki"
2368
+version = "0.101.7"
2369
+source = "registry+https://github.com/rust-lang/crates.io-index"
2370
+checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765"
2371
+dependencies = [
2372
+ "ring",
2373
+ "untrusted",
2374
+]
2375
+
2376
+[[package]]
2377
+name = "rustls-webpki"
2378
+version = "0.103.7"
2379
+source = "registry+https://github.com/rust-lang/crates.io-index"
2380
+checksum = "e10b3f4191e8a80e6b43eebabfac91e5dcecebb27a71f04e820c47ec41d314bf"
2381
+dependencies = [
2382
+ "ring",
2383
+ "rustls-pki-types",
2384
+ "untrusted",
2385
+]
2386
+
2387
+[[package]]
2388
+name = "rustversion"
2389
+version = "1.0.22"
2390
+source = "registry+https://github.com/rust-lang/crates.io-index"
2391
+checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
2392
+
2393
+[[package]]
2394
+name = "ryu"
2395
+version = "1.0.20"
2396
+source = "registry+https://github.com/rust-lang/crates.io-index"
2397
+checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
2398
+
2399
+[[package]]
2400
+name = "schannel"
2401
+version = "0.1.28"
2402
+source = "registry+https://github.com/rust-lang/crates.io-index"
2403
+checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1"
2404
+dependencies = [
2405
+ "windows-sys 0.61.2",
2406
+]
2407
+
2408
+[[package]]
2409
+name = "scroll"
2410
+version = "0.13.0"
2411
+source = "registry+https://github.com/rust-lang/crates.io-index"
2412
+checksum = "c1257cd4248b4132760d6524d6dda4e053bc648c9070b960929bf50cfb1e7add"
2413
+dependencies = [
2414
+ "scroll_derive",
2415
+]
2416
+
2417
+[[package]]
2418
+name = "scroll_derive"
2419
+version = "0.13.1"
2420
+source = "registry+https://github.com/rust-lang/crates.io-index"
2421
+checksum = "ed76efe62313ab6610570951494bdaa81568026e0318eaa55f167de70eeea67d"
2422
+dependencies = [
2423
+ "proc-macro2",
2424
+ "quote",
2425
+ "syn 2.0.107",
2426
+]
2427
+
2428
+[[package]]
2429
+name = "sct"
2430
+version = "0.7.1"
2431
+source = "registry+https://github.com/rust-lang/crates.io-index"
2432
+checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414"
2433
+dependencies = [
2434
+ "ring",
2435
+ "untrusted",
2436
+]
2437
+
2438
+[[package]]
2439
+name = "security-framework"
2440
+version = "2.11.1"
2441
+source = "registry+https://github.com/rust-lang/crates.io-index"
2442
+checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
2443
+dependencies = [
2444
+ "bitflags 2.10.0",
2445
+ "core-foundation",
2446
+ "core-foundation-sys",
2447
+ "libc",
2448
+ "security-framework-sys",
2449
+]
2450
+
2451
+[[package]]
2452
+name = "security-framework-sys"
2453
+version = "2.15.0"
2454
+source = "registry+https://github.com/rust-lang/crates.io-index"
2455
+checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0"
2456
+dependencies = [
2457
+ "core-foundation-sys",
2458
+ "libc",
2459
+]
2460
+
2461
+[[package]]
2462
+name = "semver"
2463
+version = "1.0.22"
2464
+source = "registry+https://github.com/rust-lang/crates.io-index"
2465
+checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca"
2466
+
2467
+[[package]]
2468
+name = "serde"
2469
+version = "1.0.228"
2470
+source = "registry+https://github.com/rust-lang/crates.io-index"
2471
+checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
2472
+dependencies = [
2473
+ "serde_core",
2474
+ "serde_derive",
2475
+]
2476
+
2477
+[[package]]
2478
+name = "serde_core"
2479
+version = "1.0.228"
2480
+source = "registry+https://github.com/rust-lang/crates.io-index"
2481
+checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
2482
+dependencies = [
2483
+ "serde_derive",
2484
+]
2485
+
2486
+[[package]]
2487
+name = "serde_derive"
2488
+version = "1.0.228"
2489
+source = "registry+https://github.com/rust-lang/crates.io-index"
2490
+checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
2491
+dependencies = [
2492
+ "proc-macro2",
2493
+ "quote",
2494
+ "syn 2.0.107",
2495
+]
2496
+
2497
+[[package]]
2498
+name = "serde_json"
2499
+version = "1.0.145"
2500
+source = "registry+https://github.com/rust-lang/crates.io-index"
2501
+checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c"
2502
+dependencies = [
2503
+ "itoa",
2504
+ "memchr",
2505
+ "ryu",
2506
+ "serde",
2507
+ "serde_core",
2508
+]
2509
+
2510
+[[package]]
2511
+name = "serde_urlencoded"
2512
+version = "0.7.1"
2513
+source = "registry+https://github.com/rust-lang/crates.io-index"
2514
+checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
2515
+dependencies = [
2516
+ "form_urlencoded",
2517
+ "itoa",
2518
+ "ryu",
2519
+ "serde",
2520
+]
2521
+
2522
+[[package]]
2523
+name = "sha1"
2524
+version = "0.11.0-rc.3"
2525
+source = "registry+https://github.com/rust-lang/crates.io-index"
2526
+checksum = "aa1ae819b9870cadc959a052363de870944a1646932d274a4e270f64bf79e5ef"
2527
+dependencies = [
2528
+ "cfg-if 1.0.4",
2529
+ "cpufeatures",
2530
+ "digest",
2531
+]
2532
+
2533
+[[package]]
2534
+name = "sha2"
2535
+version = "0.11.0-rc.3"
2536
+source = "registry+https://github.com/rust-lang/crates.io-index"
2537
+checksum = "19d43dc0354d88b791216bb5c1bfbb60c0814460cc653ae0ebd71f286d0bd927"
2538
+dependencies = [
2539
+ "cfg-if 1.0.4",
2540
+ "cpufeatures",
2541
+ "digest",
2542
+]
2543
+
2544
+[[package]]
2545
+name = "shlex"
2546
+version = "0.1.1"
2547
+source = "registry+https://github.com/rust-lang/crates.io-index"
2548
+checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
2549
+
2550
+[[package]]
2551
+name = "shlex"
2552
+version = "1.3.0"
2553
+source = "registry+https://github.com/rust-lang/crates.io-index"
2554
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
2555
+
2556
+[[package]]
2557
+name = "simd-adler32"
2558
+version = "0.3.7"
2559
+source = "registry+https://github.com/rust-lang/crates.io-index"
2560
+checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
2561
+
2562
+[[package]]
2563
+name = "slab"
2564
+version = "0.4.11"
2565
+source = "registry+https://github.com/rust-lang/crates.io-index"
2566
+checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589"
2567
+
2568
+[[package]]
2569
+name = "smallvec"
2570
+version = "1.15.1"
2571
+source = "registry+https://github.com/rust-lang/crates.io-index"
2572
+checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
2573
+
2574
+[[package]]
2575
+name = "smawk"
2576
+version = "0.3.2"
2577
+source = "registry+https://github.com/rust-lang/crates.io-index"
2578
+checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c"
2579
+
2580
+[[package]]
2581
+name = "socket2"
2582
+version = "0.5.10"
2583
+source = "registry+https://github.com/rust-lang/crates.io-index"
2584
+checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678"
2585
+dependencies = [
2586
+ "libc",
2587
+ "windows-sys 0.52.0",
2588
+]
2589
+
2590
+[[package]]
2591
+name = "socket2"
2592
+version = "0.6.1"
2593
+source = "registry+https://github.com/rust-lang/crates.io-index"
2594
+checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881"
2595
+dependencies = [
2596
+ "libc",
2597
+ "windows-sys 0.60.2",
2598
+]
2599
+
2600
+[[package]]
2601
+name = "srp"
2602
+version = "0.7.0-pre.0"
2603
+source = "git+https://github.com/RustCrypto/PAKEs#5e629b72caf484a3cb4c2292594a0fde8aa32df7"
2604
+dependencies = [
2605
+ "digest",
2606
+ "lazy_static",
2607
+ "num-bigint",
2608
+ "subtle",
2609
+]
2610
+
2611
+[[package]]
2612
+name = "stable_deref_trait"
2613
+version = "1.2.1"
2614
+source = "registry+https://github.com/rust-lang/crates.io-index"
2615
+checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
2616
+
2617
+[[package]]
2618
+name = "static_assertions"
2619
+version = "1.1.0"
2620
+source = "registry+https://github.com/rust-lang/crates.io-index"
2621
+checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
2622
+
2623
+[[package]]
2624
+name = "strsim"
2625
+version = "0.8.0"
2626
+source = "registry+https://github.com/rust-lang/crates.io-index"
2627
+checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
2628
+
2629
+[[package]]
2630
+name = "subtle"
2631
+version = "2.6.1"
2632
+source = "registry+https://github.com/rust-lang/crates.io-index"
2633
+checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
2634
+
2635
+[[package]]
2636
+name = "super-sideloader"
2637
+version = "0.1.0"
2638
+dependencies = [
2639
+ "adi",
2640
+ "adid-proxy",
2641
+ "android-coreadi",
2642
+ "apple-account",
2643
+ "elf-loader",
2644
+ "env_logger 0.11.8",
2645
+ "libc",
2646
+ "tokio",
2647
+]
2648
+
2649
+[[package]]
2650
+name = "supports-color"
2651
+version = "2.1.0"
2652
+source = "registry+https://github.com/rust-lang/crates.io-index"
2653
+checksum = "d6398cde53adc3c4557306a96ce67b302968513830a77a95b2b17305d9719a89"
2654
+dependencies = [
2655
+ "is-terminal",
2656
+ "is_ci",
2657
+]
2658
+
2659
+[[package]]
2660
+name = "supports-hyperlinks"
2661
+version = "2.1.0"
2662
+source = "registry+https://github.com/rust-lang/crates.io-index"
2663
+checksum = "f84231692eb0d4d41e4cdd0cabfdd2e6cd9e255e65f80c9aa7c98dd502b4233d"
2664
+dependencies = [
2665
+ "is-terminal",
2666
+]
2667
+
2668
+[[package]]
2669
+name = "supports-unicode"
2670
+version = "2.1.0"
2671
+source = "registry+https://github.com/rust-lang/crates.io-index"
2672
+checksum = "f850c19edd184a205e883199a261ed44471c81e39bd95b1357f5febbef00e77a"
2673
+dependencies = [
2674
+ "is-terminal",
2675
+]
2676
+
2677
+[[package]]
2678
+name = "syn"
2679
+version = "1.0.109"
2680
+source = "registry+https://github.com/rust-lang/crates.io-index"
2681
+checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
2682
+dependencies = [
2683
+ "proc-macro2",
2684
+ "quote",
2685
+ "unicode-ident",
2686
+]
2687
+
2688
+[[package]]
2689
+name = "syn"
2690
+version = "2.0.107"
2691
+source = "registry+https://github.com/rust-lang/crates.io-index"
2692
+checksum = "2a26dbd934e5451d21ef060c018dae56fc073894c5a7896f882928a76e6d081b"
2693
+dependencies = [
2694
+ "proc-macro2",
2695
+ "quote",
2696
+ "unicode-ident",
2697
+]
2698
+
2699
+[[package]]
2700
+name = "sync_wrapper"
2701
+version = "0.1.2"
2702
+source = "registry+https://github.com/rust-lang/crates.io-index"
2703
+checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
2704
+
2705
+[[package]]
2706
+name = "sync_wrapper"
2707
+version = "1.0.2"
2708
+source = "registry+https://github.com/rust-lang/crates.io-index"
2709
+checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
2710
+dependencies = [
2711
+ "futures-core",
2712
+]
2713
+
2714
+[[package]]
2715
+name = "synstructure"
2716
+version = "0.13.2"
2717
+source = "registry+https://github.com/rust-lang/crates.io-index"
2718
+checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
2719
+dependencies = [
2720
+ "proc-macro2",
2721
+ "quote",
2722
+ "syn 2.0.107",
2723
+]
2724
+
2725
+[[package]]
2726
+name = "sys-locale"
2727
+version = "0.3.2"
2728
+source = "registry+https://github.com/rust-lang/crates.io-index"
2729
+checksum = "8eab9a99a024a169fe8a903cf9d4a3b3601109bcc13bd9e3c6fff259138626c4"
2730
+dependencies = [
2731
+ "libc",
2732
+]
2733
+
2734
+[[package]]
2735
+name = "system-configuration"
2736
+version = "0.5.1"
2737
+source = "registry+https://github.com/rust-lang/crates.io-index"
2738
+checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7"
2739
+dependencies = [
2740
+ "bitflags 1.3.2",
2741
+ "core-foundation",
2742
+ "system-configuration-sys 0.5.0",
2743
+]
2744
+
2745
+[[package]]
2746
+name = "system-configuration"
2747
+version = "0.6.1"
2748
+source = "registry+https://github.com/rust-lang/crates.io-index"
2749
+checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b"
2750
+dependencies = [
2751
+ "bitflags 2.10.0",
2752
+ "core-foundation",
2753
+ "system-configuration-sys 0.6.0",
2754
+]
2755
+
2756
+[[package]]
2757
+name = "system-configuration-sys"
2758
+version = "0.5.0"
2759
+source = "registry+https://github.com/rust-lang/crates.io-index"
2760
+checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9"
2761
+dependencies = [
2762
+ "core-foundation-sys",
2763
+ "libc",
2764
+]
2765
+
2766
+[[package]]
2767
+name = "system-configuration-sys"
2768
+version = "0.6.0"
2769
+source = "registry+https://github.com/rust-lang/crates.io-index"
2770
+checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4"
2771
+dependencies = [
2772
+ "core-foundation-sys",
2773
+ "libc",
2774
+]
2775
+
2776
+[[package]]
2777
+name = "sysv64"
2778
+version = "0.1.0"
2779
+dependencies = [
2780
+ "proc-macro2",
2781
+ "quote",
2782
+ "syn 2.0.107",
2783
+]
2784
+
2785
+[[package]]
2786
+name = "tempfile"
2787
+version = "3.23.0"
2788
+source = "registry+https://github.com/rust-lang/crates.io-index"
2789
+checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16"
2790
+dependencies = [
2791
+ "fastrand",
2792
+ "getrandom 0.3.4",
2793
+ "once_cell",
2794
+ "rustix",
2795
+ "windows-sys 0.61.2",
2796
+]
2797
+
2798
+[[package]]
2799
+name = "termcolor"
2800
+version = "1.4.1"
2801
+source = "registry+https://github.com/rust-lang/crates.io-index"
2802
+checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
2803
+dependencies = [
2804
+ "winapi-util",
2805
+]
2806
+
2807
+[[package]]
2808
+name = "terminal_size"
2809
+version = "0.1.17"
2810
+source = "registry+https://github.com/rust-lang/crates.io-index"
2811
+checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df"
2812
+dependencies = [
2813
+ "libc",
2814
+ "winapi",
2815
+]
2816
+
2817
+[[package]]
2818
+name = "textwrap"
2819
+version = "0.11.0"
2820
+source = "registry+https://github.com/rust-lang/crates.io-index"
2821
+checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
2822
+dependencies = [
2823
+ "unicode-width",
2824
+]
2825
+
2826
+[[package]]
2827
+name = "textwrap"
2828
+version = "0.15.2"
2829
+source = "registry+https://github.com/rust-lang/crates.io-index"
2830
+checksum = "b7b3e525a49ec206798b40326a44121291b530c963cfb01018f63e135bac543d"
2831
+dependencies = [
2832
+ "smawk",
2833
+ "unicode-linebreak",
2834
+ "unicode-width",
2835
+]
2836
+
2837
+[[package]]
2838
+name = "thiserror"
2839
+version = "1.0.69"
2840
+source = "registry+https://github.com/rust-lang/crates.io-index"
2841
+checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
2842
+dependencies = [
2843
+ "thiserror-impl 1.0.69",
2844
+]
2845
+
2846
+[[package]]
2847
+name = "thiserror"
2848
+version = "2.0.17"
2849
+source = "registry+https://github.com/rust-lang/crates.io-index"
2850
+checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8"
2851
+dependencies = [
2852
+ "thiserror-impl 2.0.17",
2853
+]
2854
+
2855
+[[package]]
2856
+name = "thiserror-impl"
2857
+version = "1.0.69"
2858
+source = "registry+https://github.com/rust-lang/crates.io-index"
2859
+checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
2860
+dependencies = [
2861
+ "proc-macro2",
2862
+ "quote",
2863
+ "syn 2.0.107",
2864
+]
2865
+
2866
+[[package]]
2867
+name = "thiserror-impl"
2868
+version = "2.0.17"
2869
+source = "registry+https://github.com/rust-lang/crates.io-index"
2870
+checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913"
2871
+dependencies = [
2872
+ "proc-macro2",
2873
+ "quote",
2874
+ "syn 2.0.107",
2875
+]
2876
+
2877
+[[package]]
2878
+name = "time"
2879
+version = "0.3.44"
2880
+source = "registry+https://github.com/rust-lang/crates.io-index"
2881
+checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d"
2882
+dependencies = [
2883
+ "deranged",
2884
+ "itoa",
2885
+ "num-conv",
2886
+ "powerfmt",
2887
+ "serde",
2888
+ "time-core",
2889
+ "time-macros",
2890
+]
2891
+
2892
+[[package]]
2893
+name = "time-core"
2894
+version = "0.1.6"
2895
+source = "registry+https://github.com/rust-lang/crates.io-index"
2896
+checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b"
2897
+
2898
+[[package]]
2899
+name = "time-macros"
2900
+version = "0.2.24"
2901
+source = "registry+https://github.com/rust-lang/crates.io-index"
2902
+checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3"
2903
+dependencies = [
2904
+ "num-conv",
2905
+ "time-core",
2906
+]
2907
+
2908
+[[package]]
2909
+name = "tinystr"
2910
+version = "0.8.1"
2911
+source = "registry+https://github.com/rust-lang/crates.io-index"
2912
+checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b"
2913
+dependencies = [
2914
+ "displaydoc",
2915
+ "zerovec",
2916
+]
2917
+
2918
+[[package]]
2919
+name = "tinyvec"
2920
+version = "1.10.0"
2921
+source = "registry+https://github.com/rust-lang/crates.io-index"
2922
+checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa"
2923
+dependencies = [
2924
+ "tinyvec_macros",
2925
+]
2926
+
2927
+[[package]]
2928
+name = "tinyvec_macros"
2929
+version = "0.1.1"
2930
+source = "registry+https://github.com/rust-lang/crates.io-index"
2931
+checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
2932
+
2933
+[[package]]
2934
+name = "tokio"
2935
+version = "1.48.0"
2936
+source = "registry+https://github.com/rust-lang/crates.io-index"
2937
+checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408"
2938
+dependencies = [
2939
+ "bytes",
2940
+ "libc",
2941
+ "mio",
2942
+ "pin-project-lite",
2943
+ "socket2 0.6.1",
2944
+ "tokio-macros",
2945
+ "windows-sys 0.61.2",
2946
+]
2947
+
2948
+[[package]]
2949
+name = "tokio-macros"
2950
+version = "2.6.0"
2951
+source = "registry+https://github.com/rust-lang/crates.io-index"
2952
+checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5"
2953
+dependencies = [
2954
+ "proc-macro2",
2955
+ "quote",
2956
+ "syn 2.0.107",
2957
+]
2958
+
2959
+[[package]]
2960
+name = "tokio-native-tls"
2961
+version = "0.3.1"
2962
+source = "registry+https://github.com/rust-lang/crates.io-index"
2963
+checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
2964
+dependencies = [
2965
+ "native-tls",
2966
+ "tokio",
2967
+]
2968
+
2969
+[[package]]
2970
+name = "tokio-rustls"
2971
+version = "0.24.1"
2972
+source = "registry+https://github.com/rust-lang/crates.io-index"
2973
+checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081"
2974
+dependencies = [
2975
+ "rustls 0.21.12",
2976
+ "tokio",
2977
+]
2978
+
2979
+[[package]]
2980
+name = "tokio-rustls"
2981
+version = "0.26.4"
2982
+source = "registry+https://github.com/rust-lang/crates.io-index"
2983
+checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61"
2984
+dependencies = [
2985
+ "rustls 0.23.33",
2986
+ "tokio",
2987
+]
2988
+
2989
+[[package]]
2990
+name = "tokio-util"
2991
+version = "0.7.16"
2992
+source = "registry+https://github.com/rust-lang/crates.io-index"
2993
+checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5"
2994
+dependencies = [
2995
+ "bytes",
2996
+ "futures-core",
2997
+ "futures-sink",
2998
+ "pin-project-lite",
2999
+ "tokio",
3000
+]
3001
+
3002
+[[package]]
3003
+name = "tower"
3004
+version = "0.5.2"
3005
+source = "registry+https://github.com/rust-lang/crates.io-index"
3006
+checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9"
3007
+dependencies = [
3008
+ "futures-core",
3009
+ "futures-util",
3010
+ "pin-project-lite",
3011
+ "sync_wrapper 1.0.2",
3012
+ "tokio",
3013
+ "tower-layer",
3014
+ "tower-service",
3015
+]
3016
+
3017
+[[package]]
3018
+name = "tower-http"
3019
+version = "0.6.8"
3020
+source = "registry+https://github.com/rust-lang/crates.io-index"
3021
+checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8"
3022
+dependencies = [
3023
+ "bitflags 2.10.0",
3024
+ "bytes",
3025
+ "futures-util",
3026
+ "http 1.3.1",
3027
+ "http-body 1.0.1",
3028
+ "iri-string",
3029
+ "pin-project-lite",
3030
+ "tower",
3031
+ "tower-layer",
3032
+ "tower-service",
3033
+]
3034
+
3035
+[[package]]
3036
+name = "tower-layer"
3037
+version = "0.3.3"
3038
+source = "registry+https://github.com/rust-lang/crates.io-index"
3039
+checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e"
3040
+
3041
+[[package]]
3042
+name = "tower-service"
3043
+version = "0.3.3"
3044
+source = "registry+https://github.com/rust-lang/crates.io-index"
3045
+checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
3046
+
3047
+[[package]]
3048
+name = "tracing"
3049
+version = "0.1.41"
3050
+source = "registry+https://github.com/rust-lang/crates.io-index"
3051
+checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
3052
+dependencies = [
3053
+ "pin-project-lite",
3054
+ "tracing-core",
3055
+]
3056
+
3057
+[[package]]
3058
+name = "tracing-core"
3059
+version = "0.1.34"
3060
+source = "registry+https://github.com/rust-lang/crates.io-index"
3061
+checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678"
3062
+dependencies = [
3063
+ "once_cell",
3064
+]
3065
+
3066
+[[package]]
3067
+name = "try-lock"
3068
+version = "0.2.5"
3069
+source = "registry+https://github.com/rust-lang/crates.io-index"
3070
+checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
3071
+
3072
+[[package]]
3073
+name = "typenum"
3074
+version = "1.19.0"
3075
+source = "registry+https://github.com/rust-lang/crates.io-index"
3076
+checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
3077
+
3078
+[[package]]
3079
+name = "unicode-ident"
3080
+version = "1.0.19"
3081
+source = "registry+https://github.com/rust-lang/crates.io-index"
3082
+checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d"
3083
+
3084
+[[package]]
3085
+name = "unicode-linebreak"
3086
+version = "0.1.5"
3087
+source = "registry+https://github.com/rust-lang/crates.io-index"
3088
+checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f"
3089
+
3090
+[[package]]
3091
+name = "unicode-width"
3092
+version = "0.1.14"
3093
+source = "registry+https://github.com/rust-lang/crates.io-index"
3094
+checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
3095
+
3096
+[[package]]
3097
+name = "universal-hash"
3098
+version = "0.6.0-rc.4"
3099
+source = "registry+https://github.com/rust-lang/crates.io-index"
3100
+checksum = "0386f227888b17b65d3e38219a7d41185035471300855c285667811907bb1677"
3101
+dependencies = [
3102
+ "crypto-common",
3103
+ "subtle",
3104
+]
3105
+
3106
+[[package]]
3107
+name = "untrusted"
3108
+version = "0.9.0"
3109
+source = "registry+https://github.com/rust-lang/crates.io-index"
3110
+checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
3111
+
3112
+[[package]]
3113
+name = "unty"
3114
+version = "0.0.4"
3115
+source = "registry+https://github.com/rust-lang/crates.io-index"
3116
+checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae"
3117
+
3118
+[[package]]
3119
+name = "url"
3120
+version = "2.5.7"
3121
+source = "registry+https://github.com/rust-lang/crates.io-index"
3122
+checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b"
3123
+dependencies = [
3124
+ "form_urlencoded",
3125
+ "idna",
3126
+ "percent-encoding",
3127
+ "serde",
3128
+]
3129
+
3130
+[[package]]
3131
+name = "utf8_iter"
3132
+version = "1.0.4"
3133
+source = "registry+https://github.com/rust-lang/crates.io-index"
3134
+checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
3135
+
3136
+[[package]]
3137
+name = "utf8parse"
3138
+version = "0.2.2"
3139
+source = "registry+https://github.com/rust-lang/crates.io-index"
3140
+checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
3141
+
3142
+[[package]]
3143
+name = "vcpkg"
3144
+version = "0.2.15"
3145
+source = "registry+https://github.com/rust-lang/crates.io-index"
3146
+checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
3147
+
3148
+[[package]]
3149
+name = "vec_map"
3150
+version = "0.8.2"
3151
+source = "registry+https://github.com/rust-lang/crates.io-index"
3152
+checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
3153
+
3154
+[[package]]
3155
+name = "version_check"
3156
+version = "0.9.5"
3157
+source = "registry+https://github.com/rust-lang/crates.io-index"
3158
+checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
3159
+
3160
+[[package]]
3161
+name = "want"
3162
+version = "0.3.1"
3163
+source = "registry+https://github.com/rust-lang/crates.io-index"
3164
+checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
3165
+dependencies = [
3166
+ "try-lock",
3167
+]
3168
+
3169
+[[package]]
3170
+name = "wasi"
3171
+version = "0.11.1+wasi-snapshot-preview1"
3172
+source = "registry+https://github.com/rust-lang/crates.io-index"
3173
+checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
3174
+
3175
+[[package]]
3176
+name = "wasip2"
3177
+version = "1.0.1+wasi-0.2.4"
3178
+source = "registry+https://github.com/rust-lang/crates.io-index"
3179
+checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7"
3180
+dependencies = [
3181
+ "wit-bindgen",
3182
+]
3183
+
3184
+[[package]]
3185
+name = "wasm-bindgen"
3186
+version = "0.2.104"
3187
+source = "registry+https://github.com/rust-lang/crates.io-index"
3188
+checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d"
3189
+dependencies = [
3190
+ "cfg-if 1.0.4",
3191
+ "once_cell",
3192
+ "rustversion",
3193
+ "wasm-bindgen-macro",
3194
+ "wasm-bindgen-shared",
3195
+]
3196
+
3197
+[[package]]
3198
+name = "wasm-bindgen-backend"
3199
+version = "0.2.104"
3200
+source = "registry+https://github.com/rust-lang/crates.io-index"
3201
+checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19"
3202
+dependencies = [
3203
+ "bumpalo",
3204
+ "log",
3205
+ "proc-macro2",
3206
+ "quote",
3207
+ "syn 2.0.107",
3208
+ "wasm-bindgen-shared",
3209
+]
3210
+
3211
+[[package]]
3212
+name = "wasm-bindgen-futures"
3213
+version = "0.4.54"
3214
+source = "registry+https://github.com/rust-lang/crates.io-index"
3215
+checksum = "7e038d41e478cc73bae0ff9b36c60cff1c98b8f38f8d7e8061e79ee63608ac5c"
3216
+dependencies = [
3217
+ "cfg-if 1.0.4",
3218
+ "js-sys",
3219
+ "once_cell",
3220
+ "wasm-bindgen",
3221
+ "web-sys",
3222
+]
3223
+
3224
+[[package]]
3225
+name = "wasm-bindgen-macro"
3226
+version = "0.2.104"
3227
+source = "registry+https://github.com/rust-lang/crates.io-index"
3228
+checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119"
3229
+dependencies = [
3230
+ "quote",
3231
+ "wasm-bindgen-macro-support",
3232
+]
3233
+
3234
+[[package]]
3235
+name = "wasm-bindgen-macro-support"
3236
+version = "0.2.104"
3237
+source = "registry+https://github.com/rust-lang/crates.io-index"
3238
+checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7"
3239
+dependencies = [
3240
+ "proc-macro2",
3241
+ "quote",
3242
+ "syn 2.0.107",
3243
+ "wasm-bindgen-backend",
3244
+ "wasm-bindgen-shared",
3245
+]
3246
+
3247
+[[package]]
3248
+name = "wasm-bindgen-shared"
3249
+version = "0.2.104"
3250
+source = "registry+https://github.com/rust-lang/crates.io-index"
3251
+checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1"
3252
+dependencies = [
3253
+ "unicode-ident",
3254
+]
3255
+
3256
+[[package]]
3257
+name = "web-sys"
3258
+version = "0.3.81"
3259
+source = "registry+https://github.com/rust-lang/crates.io-index"
3260
+checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120"
3261
+dependencies = [
3262
+ "js-sys",
3263
+ "wasm-bindgen",
3264
+]
3265
+
3266
+[[package]]
3267
+name = "web-time"
3268
+version = "1.1.0"
3269
+source = "registry+https://github.com/rust-lang/crates.io-index"
3270
+checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"
3271
+dependencies = [
3272
+ "js-sys",
3273
+ "wasm-bindgen",
3274
+]
3275
+
3276
+[[package]]
3277
+name = "webpki-roots"
3278
+version = "0.25.4"
3279
+source = "registry+https://github.com/rust-lang/crates.io-index"
3280
+checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1"
3281
+
3282
+[[package]]
3283
+name = "webpki-roots"
3284
+version = "1.0.4"
3285
+source = "registry+https://github.com/rust-lang/crates.io-index"
3286
+checksum = "b2878ef029c47c6e8cf779119f20fcf52bde7ad42a731b2a304bc221df17571e"
3287
+dependencies = [
3288
+ "rustls-pki-types",
3289
+]
3290
+
3291
+[[package]]
3292
+name = "which"
3293
+version = "3.1.1"
3294
+source = "registry+https://github.com/rust-lang/crates.io-index"
3295
+checksum = "d011071ae14a2f6671d0b74080ae0cd8ebf3a6f8c9589a2cd45f23126fe29724"
3296
+dependencies = [
3297
+ "libc",
3298
+]
3299
+
3300
+[[package]]
3301
+name = "winapi"
3302
+version = "0.3.9"
3303
+source = "registry+https://github.com/rust-lang/crates.io-index"
3304
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
3305
+dependencies = [
3306
+ "winapi-i686-pc-windows-gnu",
3307
+ "winapi-x86_64-pc-windows-gnu",
3308
+]
3309
+
3310
+[[package]]
3311
+name = "winapi-i686-pc-windows-gnu"
3312
+version = "0.4.0"
3313
+source = "registry+https://github.com/rust-lang/crates.io-index"
3314
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
3315
+
3316
+[[package]]
3317
+name = "winapi-util"
3318
+version = "0.1.11"
3319
+source = "registry+https://github.com/rust-lang/crates.io-index"
3320
+checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
3321
+dependencies = [
3322
+ "windows-sys 0.61.2",
3323
+]
3324
+
3325
+[[package]]
3326
+name = "winapi-x86_64-pc-windows-gnu"
3327
+version = "0.4.0"
3328
+source = "registry+https://github.com/rust-lang/crates.io-index"
3329
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
3330
+
3331
+[[package]]
3332
+name = "windows-core"
3333
+version = "0.61.2"
3334
+source = "registry+https://github.com/rust-lang/crates.io-index"
3335
+checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3"
3336
+dependencies = [
3337
+ "windows-implement",
3338
+ "windows-interface",
3339
+ "windows-link 0.1.3",
3340
+ "windows-result",
3341
+ "windows-strings",
3342
+]
3343
+
3344
+[[package]]
3345
+name = "windows-implement"
3346
+version = "0.60.2"
3347
+source = "registry+https://github.com/rust-lang/crates.io-index"
3348
+checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
3349
+dependencies = [
3350
+ "proc-macro2",
3351
+ "quote",
3352
+ "syn 2.0.107",
3353
+]
3354
+
3355
+[[package]]
3356
+name = "windows-interface"
3357
+version = "0.59.3"
3358
+source = "registry+https://github.com/rust-lang/crates.io-index"
3359
+checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
3360
+dependencies = [
3361
+ "proc-macro2",
3362
+ "quote",
3363
+ "syn 2.0.107",
3364
+]
3365
+
3366
+[[package]]
3367
+name = "windows-link"
3368
+version = "0.1.3"
3369
+source = "registry+https://github.com/rust-lang/crates.io-index"
3370
+checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
3371
+
3372
+[[package]]
3373
+name = "windows-link"
3374
+version = "0.2.1"
3375
+source = "registry+https://github.com/rust-lang/crates.io-index"
3376
+checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
3377
+
3378
+[[package]]
3379
+name = "windows-registry"
3380
+version = "0.5.3"
3381
+source = "registry+https://github.com/rust-lang/crates.io-index"
3382
+checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e"
3383
+dependencies = [
3384
+ "windows-link 0.1.3",
3385
+ "windows-result",
3386
+ "windows-strings",
3387
+]
3388
+
3389
+[[package]]
3390
+name = "windows-result"
3391
+version = "0.3.4"
3392
+source = "registry+https://github.com/rust-lang/crates.io-index"
3393
+checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
3394
+dependencies = [
3395
+ "windows-link 0.1.3",
3396
+]
3397
+
3398
+[[package]]
3399
+name = "windows-strings"
3400
+version = "0.4.2"
3401
+source = "registry+https://github.com/rust-lang/crates.io-index"
3402
+checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57"
3403
+dependencies = [
3404
+ "windows-link 0.1.3",
3405
+]
3406
+
3407
+[[package]]
3408
+name = "windows-sys"
3409
+version = "0.48.0"
3410
+source = "registry+https://github.com/rust-lang/crates.io-index"
3411
+checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
3412
+dependencies = [
3413
+ "windows-targets 0.48.5",
3414
+]
3415
+
3416
+[[package]]
3417
+name = "windows-sys"
3418
+version = "0.52.0"
3419
+source = "registry+https://github.com/rust-lang/crates.io-index"
3420
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
3421
+dependencies = [
3422
+ "windows-targets 0.52.6",
3423
+]
3424
+
3425
+[[package]]
3426
+name = "windows-sys"
3427
+version = "0.60.2"
3428
+source = "registry+https://github.com/rust-lang/crates.io-index"
3429
+checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
3430
+dependencies = [
3431
+ "windows-targets 0.53.5",
3432
+]
3433
+
3434
+[[package]]
3435
+name = "windows-sys"
3436
+version = "0.61.2"
3437
+source = "registry+https://github.com/rust-lang/crates.io-index"
3438
+checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
3439
+dependencies = [
3440
+ "windows-link 0.2.1",
3441
+]
3442
+
3443
+[[package]]
3444
+name = "windows-targets"
3445
+version = "0.48.5"
3446
+source = "registry+https://github.com/rust-lang/crates.io-index"
3447
+checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
3448
+dependencies = [
3449
+ "windows_aarch64_gnullvm 0.48.5",
3450
+ "windows_aarch64_msvc 0.48.5",
3451
+ "windows_i686_gnu 0.48.5",
3452
+ "windows_i686_msvc 0.48.5",
3453
+ "windows_x86_64_gnu 0.48.5",
3454
+ "windows_x86_64_gnullvm 0.48.5",
3455
+ "windows_x86_64_msvc 0.48.5",
3456
+]
3457
+
3458
+[[package]]
3459
+name = "windows-targets"
3460
+version = "0.52.6"
3461
+source = "registry+https://github.com/rust-lang/crates.io-index"
3462
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
3463
+dependencies = [
3464
+ "windows_aarch64_gnullvm 0.52.6",
3465
+ "windows_aarch64_msvc 0.52.6",
3466
+ "windows_i686_gnu 0.52.6",
3467
+ "windows_i686_gnullvm 0.52.6",
3468
+ "windows_i686_msvc 0.52.6",
3469
+ "windows_x86_64_gnu 0.52.6",
3470
+ "windows_x86_64_gnullvm 0.52.6",
3471
+ "windows_x86_64_msvc 0.52.6",
3472
+]
3473
+
3474
+[[package]]
3475
+name = "windows-targets"
3476
+version = "0.53.5"
3477
+source = "registry+https://github.com/rust-lang/crates.io-index"
3478
+checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
3479
+dependencies = [
3480
+ "windows-link 0.2.1",
3481
+ "windows_aarch64_gnullvm 0.53.1",
3482
+ "windows_aarch64_msvc 0.53.1",
3483
+ "windows_i686_gnu 0.53.1",
3484
+ "windows_i686_gnullvm 0.53.1",
3485
+ "windows_i686_msvc 0.53.1",
3486
+ "windows_x86_64_gnu 0.53.1",
3487
+ "windows_x86_64_gnullvm 0.53.1",
3488
+ "windows_x86_64_msvc 0.53.1",
3489
+]
3490
+
3491
+[[package]]
3492
+name = "windows_aarch64_gnullvm"
3493
+version = "0.48.5"
3494
+source = "registry+https://github.com/rust-lang/crates.io-index"
3495
+checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
3496
+
3497
+[[package]]
3498
+name = "windows_aarch64_gnullvm"
3499
+version = "0.52.6"
3500
+source = "registry+https://github.com/rust-lang/crates.io-index"
3501
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
3502
+
3503
+[[package]]
3504
+name = "windows_aarch64_gnullvm"
3505
+version = "0.53.1"
3506
+source = "registry+https://github.com/rust-lang/crates.io-index"
3507
+checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
3508
+
3509
+[[package]]
3510
+name = "windows_aarch64_msvc"
3511
+version = "0.48.5"
3512
+source = "registry+https://github.com/rust-lang/crates.io-index"
3513
+checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
3514
+
3515
+[[package]]
3516
+name = "windows_aarch64_msvc"
3517
+version = "0.52.6"
3518
+source = "registry+https://github.com/rust-lang/crates.io-index"
3519
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
3520
+
3521
+[[package]]
3522
+name = "windows_aarch64_msvc"
3523
+version = "0.53.1"
3524
+source = "registry+https://github.com/rust-lang/crates.io-index"
3525
+checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
3526
+
3527
+[[package]]
3528
+name = "windows_i686_gnu"
3529
+version = "0.48.5"
3530
+source = "registry+https://github.com/rust-lang/crates.io-index"
3531
+checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
3532
+
3533
+[[package]]
3534
+name = "windows_i686_gnu"
3535
+version = "0.52.6"
3536
+source = "registry+https://github.com/rust-lang/crates.io-index"
3537
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
3538
+
3539
+[[package]]
3540
+name = "windows_i686_gnu"
3541
+version = "0.53.1"
3542
+source = "registry+https://github.com/rust-lang/crates.io-index"
3543
+checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
3544
+
3545
+[[package]]
3546
+name = "windows_i686_gnullvm"
3547
+version = "0.52.6"
3548
+source = "registry+https://github.com/rust-lang/crates.io-index"
3549
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
3550
+
3551
+[[package]]
3552
+name = "windows_i686_gnullvm"
3553
+version = "0.53.1"
3554
+source = "registry+https://github.com/rust-lang/crates.io-index"
3555
+checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
3556
+
3557
+[[package]]
3558
+name = "windows_i686_msvc"
3559
+version = "0.48.5"
3560
+source = "registry+https://github.com/rust-lang/crates.io-index"
3561
+checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
3562
+
3563
+[[package]]
3564
+name = "windows_i686_msvc"
3565
+version = "0.52.6"
3566
+source = "registry+https://github.com/rust-lang/crates.io-index"
3567
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
3568
+
3569
+[[package]]
3570
+name = "windows_i686_msvc"
3571
+version = "0.53.1"
3572
+source = "registry+https://github.com/rust-lang/crates.io-index"
3573
+checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
3574
+
3575
+[[package]]
3576
+name = "windows_x86_64_gnu"
3577
+version = "0.48.5"
3578
+source = "registry+https://github.com/rust-lang/crates.io-index"
3579
+checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
3580
+
3581
+[[package]]
3582
+name = "windows_x86_64_gnu"
3583
+version = "0.52.6"
3584
+source = "registry+https://github.com/rust-lang/crates.io-index"
3585
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
3586
+
3587
+[[package]]
3588
+name = "windows_x86_64_gnu"
3589
+version = "0.53.1"
3590
+source = "registry+https://github.com/rust-lang/crates.io-index"
3591
+checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
3592
+
3593
+[[package]]
3594
+name = "windows_x86_64_gnullvm"
3595
+version = "0.48.5"
3596
+source = "registry+https://github.com/rust-lang/crates.io-index"
3597
+checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
3598
+
3599
+[[package]]
3600
+name = "windows_x86_64_gnullvm"
3601
+version = "0.52.6"
3602
+source = "registry+https://github.com/rust-lang/crates.io-index"
3603
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
3604
+
3605
+[[package]]
3606
+name = "windows_x86_64_gnullvm"
3607
+version = "0.53.1"
3608
+source = "registry+https://github.com/rust-lang/crates.io-index"
3609
+checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
3610
+
3611
+[[package]]
3612
+name = "windows_x86_64_msvc"
3613
+version = "0.48.5"
3614
+source = "registry+https://github.com/rust-lang/crates.io-index"
3615
+checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
3616
+
3617
+[[package]]
3618
+name = "windows_x86_64_msvc"
3619
+version = "0.52.6"
3620
+source = "registry+https://github.com/rust-lang/crates.io-index"
3621
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
3622
+
3623
+[[package]]
3624
+name = "windows_x86_64_msvc"
3625
+version = "0.53.1"
3626
+source = "registry+https://github.com/rust-lang/crates.io-index"
3627
+checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
3628
+
3629
+[[package]]
3630
+name = "winreg"
3631
+version = "0.50.0"
3632
+source = "registry+https://github.com/rust-lang/crates.io-index"
3633
+checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
3634
+dependencies = [
3635
+ "cfg-if 1.0.4",
3636
+ "windows-sys 0.48.0",
3637
+]
3638
+
3639
+[[package]]
3640
+name = "wit-bindgen"
3641
+version = "0.46.0"
3642
+source = "registry+https://github.com/rust-lang/crates.io-index"
3643
+checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59"
3644
+
3645
+[[package]]
3646
+name = "writeable"
3647
+version = "0.6.1"
3648
+source = "registry+https://github.com/rust-lang/crates.io-index"
3649
+checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb"
3650
+
3651
+[[package]]
3652
+name = "xpc-connection-sys"
3653
+version = "0.1.1"
3654
+source = "registry+https://github.com/rust-lang/crates.io-index"
3655
+checksum = "e9e73f03a600d0244f3dce6a5c65af535e9cc9f3d19aae00359a1c44d4e14b6c"
3656
+dependencies = [
3657
+ "bindgen",
3658
+]
3659
+
3660
+[[package]]
3661
+name = "yansi"
3662
+version = "1.0.1"
3663
+source = "registry+https://github.com/rust-lang/crates.io-index"
3664
+checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
3665
+
3666
+[[package]]
3667
+name = "yoke"
3668
+version = "0.8.0"
3669
+source = "registry+https://github.com/rust-lang/crates.io-index"
3670
+checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc"
3671
+dependencies = [
3672
+ "serde",
3673
+ "stable_deref_trait",
3674
+ "yoke-derive",
3675
+ "zerofrom",
3676
+]
3677
+
3678
+[[package]]
3679
+name = "yoke-derive"
3680
+version = "0.8.0"
3681
+source = "registry+https://github.com/rust-lang/crates.io-index"
3682
+checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6"
3683
+dependencies = [
3684
+ "proc-macro2",
3685
+ "quote",
3686
+ "syn 2.0.107",
3687
+ "synstructure",
3688
+]
3689
+
3690
+[[package]]
3691
+name = "zerocopy"
3692
+version = "0.8.27"
3693
+source = "registry+https://github.com/rust-lang/crates.io-index"
3694
+checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c"
3695
+dependencies = [
3696
+ "zerocopy-derive",
3697
+]
3698
+
3699
+[[package]]
3700
+name = "zerocopy-derive"
3701
+version = "0.8.27"
3702
+source = "registry+https://github.com/rust-lang/crates.io-index"
3703
+checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831"
3704
+dependencies = [
3705
+ "proc-macro2",
3706
+ "quote",
3707
+ "syn 2.0.107",
3708
+]
3709
+
3710
+[[package]]
3711
+name = "zerofrom"
3712
+version = "0.1.6"
3713
+source = "registry+https://github.com/rust-lang/crates.io-index"
3714
+checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5"
3715
+dependencies = [
3716
+ "zerofrom-derive",
3717
+]
3718
+
3719
+[[package]]
3720
+name = "zerofrom-derive"
3721
+version = "0.1.6"
3722
+source = "registry+https://github.com/rust-lang/crates.io-index"
3723
+checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
3724
+dependencies = [
3725
+ "proc-macro2",
3726
+ "quote",
3727
+ "syn 2.0.107",
3728
+ "synstructure",
3729
+]
3730
+
3731
+[[package]]
3732
+name = "zeroize"
3733
+version = "1.8.2"
3734
+source = "registry+https://github.com/rust-lang/crates.io-index"
3735
+checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"
3736
+
3737
+[[package]]
3738
+name = "zerotrie"
3739
+version = "0.2.2"
3740
+source = "registry+https://github.com/rust-lang/crates.io-index"
3741
+checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595"
3742
+dependencies = [
3743
+ "displaydoc",
3744
+ "yoke",
3745
+ "zerofrom",
3746
+]
3747
+
3748
+[[package]]
3749
+name = "zerovec"
3750
+version = "0.11.4"
3751
+source = "registry+https://github.com/rust-lang/crates.io-index"
3752
+checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b"
3753
+dependencies = [
3754
+ "yoke",
3755
+ "zerofrom",
3756
+ "zerovec-derive",
3757
+]
3758
+
3759
+[[package]]
3760
+name = "zerovec-derive"
3761
+version = "0.11.1"
3762
+source = "registry+https://github.com/rust-lang/crates.io-index"
3763
+checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f"
3764
+dependencies = [
3765
+ "proc-macro2",
3766
+ "quote",
3767
+ "syn 2.0.107",
3768
+]
3769
+
3770
+[[package]]
3771
+name = "zip"
3772
+version = "0.6.6"
3773
+source = "registry+https://github.com/rust-lang/crates.io-index"
3774
+checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261"
3775
+dependencies = [
3776
+ "byteorder",
3777
+ "crc32fast",
3778
+ "crossbeam-utils",
3779
+ "flate2",
3780
+ "time",
3781
+]
... ...
@@ -0,0 +1,23 @@
1
+[workspace]
2
+resolver = "2"
3
+members = ["adi", "adid-proxy", "android-coreadi", "apple-account", "apple-codesign-quick", "elf-loader", "plist-macros", "purple-builder", "super-sideloader"]
4
+
5
+[workspace.dependencies]
6
+adi = { path = "adi" }
7
+adid-proxy = { path = "adid-proxy" }
8
+android-coreadi = { path = "android-coreadi" }
9
+apple-account = { path = "apple-account" }
10
+elf-loader = { path = "elf-loader" }
11
+plist-macros = { path = "plist-macros" }
12
+
13
+plist = "1"
14
+reqwest = { version = "0.12", features = ["rustls-tls"] }
15
+tokio = { version = "1", features = ["rt", "rt-multi-thread", "macros"] }
16
+
17
+aes = "0.9.0-rc.2"
18
+aes-gcm = "0.11.0-rc.2"
19
+cbc = { version = "0.2.0-rc.2", features = ["alloc"] }
20
+hmac = "0.13.0-rc.3"
21
+pbkdf2 = "0.13.0-rc.5"
22
+sha1 = "0.11.0-rc.3"
23
+sha2 = "0.11.0-rc.3"
... ...
@@ -0,0 +1,79 @@
1
+# apple crate collection
2
+
3
+At some point I started a sideloader rewrite in Rust in
4
+parallel of my D rewrite, but now that there are a few 
5
+alternatives, I am not sure of whether I will finish it.
6
+
7
+Anyway, for that I wrote a few shiny crates that could help
8
+rewrite iTunes or anything apple related.
9
+
10
+Here is a breakdown of every crate here:
11
+
12
+### adi
13
+
14
+Abstracts an ADI connection, allows direct communication with ADI code.
15
+
16
+### adid-proxy
17
+
18
+Create an `adi::ADIProxy` on a Darwin system that can connect to the `adid` daemon.
19
+
20
+### android-coreadi
21
+
22
+Create an `adi::ADIProxy` on any Unix system (TODO: add Windows support) from
23
+any `libCoreADI.so` distribution supporting your architecture.
24
+
25
+### apple-account (unfinished yet)
26
+
27
+A fully-featured, type-safe, well-designed Apple server API wrapper.
28
+
29
+You can log into an Apple account via GSA APIs with any ADIProxy, fetch the tokens,
30
+while handling every error correctly, including Apple's server errors.
31
+
32
+(currently, the Grandslam part lacks the code to do 2FA without a browser,
33
+and the iTunes connection part is not yet implemented
34
+
35
+### apple-codesign(-quick) (unfinished yet)
36
+
37
+A port of Sideloader's barebone very fast signer in Rust.
38
+
39
+Sideloader's signer is less hacky than zsign and is way faster than apple-codesign-rs 
40
+(probably partly because it takes a few shortcuts too in addition of being multithreaded
41
+and designed with performance in mind).
42
+
43
+### elf-loader
44
+
45
+A better minimal cross-platform elf-loader crate.
46
+
47
+I will add feature as needed for the other packages
48
+
49
+### fairplay (unfinished yet)
50
+
51
+Abstracting CoreFP for use on any system, a bit like `adi`, will be used in 
52
+`apple-account` iTunes part.
53
+
54
+### plist-macros
55
+
56
+Allows declarative declaration of plist.
57
+
58
+### purple-builder (unfinished yet)
59
+
60
+A reimplementation of Xcode maybe some day? (but Rust GUI situation is not great, so I postponed that D:)
61
+
62
+### super-sideloader
63
+
64
+That Sideloader rewrite in Rust I postponed. Currently, it's full of apple-account's testing code.
65
+
66
+### there should be a separate xcode api crate
67
+
68
+but I did not start to work on it :p
69
+
70
+## Okay but why have you rewrote everything?
71
+
72
+I wasn't satisfied with what was already available :p.
73
+
74
+## Addendum
75
+
76
+Don't hesitate to reach me out if you have any questions, in the discussion tab here or on Discord!
77
+I do my best to be reactive and useful.
78
+
79
+Also, if you enjoy my work, please consider giving me a small tip <3
... ...
@@ -0,0 +1,11 @@
1
+[package]
2
+name = "adi"
3
+version = "0.1.0"
4
+edition = "2024"
5
+
6
+[dependencies]
7
+bincode = { version = "2.0", default-features = false, features = ["std", "serde"] }
8
+serde = { version = "1.0", features = ["derive"] }
9
+
10
+[dev-dependencies]
11
+log = "0.4.29"
... ...
@@ -0,0 +1,296 @@
1
+use serde::de::DeserializeOwned;
2
+use serde::{Serialize, Serializer};
3
+use std::slice;
4
+
5
+pub trait ADIMessage: Serialize {
6
+    const MAGIC: u32;
7
+
8
+    type ReturnType: DeserializeOwned; // = u32;
9
+}
10
+
11
+fn serialize_ptr<S: Serializer, T>(ptr: &*const T, serializer: S) -> Result<S::Ok, S::Error> {
12
+    (*ptr as usize).serialize(serializer)
13
+}
14
+
15
+fn serialize_ptr_mut<S: Serializer, T>(ptr: &*mut T, serializer: S) -> Result<S::Ok, S::Error> {
16
+    (*ptr as usize).serialize(serializer)
17
+}
18
+
19
+#[derive(Serialize, PartialEq)]
20
+#[repr(C)]
21
+pub struct CoreADIAccount {
22
+    pub ds_id: i64,
23
+    pub mid_len: u32,
24
+    pub otp_len: u32,
25
+    #[serde(serialize_with = "serialize_ptr")]
26
+    pub mid_ptr: *const u8,
27
+    #[serde(serialize_with = "serialize_ptr")]
28
+    pub otp_ptr: *const u8,
29
+}
30
+
31
+impl std::fmt::Debug for CoreADIAccount {
32
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33
+        f.debug_struct("ADIAccount")
34
+            .field("ds_id", &self.ds_id)
35
+            .field("mid", &self.mid())
36
+            .field("otp", &self.otp())
37
+            .finish()
38
+    }
39
+}
40
+
41
+impl CoreADIAccount {
42
+    fn mid(&self) -> &[u8] {
43
+        unsafe { slice::from_raw_parts(self.mid_ptr, self.mid_len as usize) }
44
+    }
45
+
46
+    fn otp(&self) -> &[u8] {
47
+        unsafe { slice::from_raw_parts(self.otp_ptr, self.otp_len as usize) }
48
+    }
49
+}
50
+
51
+#[derive(Serialize, PartialEq, Debug)]
52
+#[repr(C)]
53
+pub struct InitializeMessage {}
54
+
55
+#[derive(Serialize, PartialEq, Debug)]
56
+#[repr(C)]
57
+pub struct IsMachineProvisionedMessage {
58
+    pub ds_id: i64,
59
+}
60
+
61
+#[derive(Serialize, PartialEq, Debug)]
62
+#[repr(C)]
63
+pub struct GetAllProvisionedAccountsMessage {
64
+    #[serde(serialize_with = "serialize_ptr_mut")]
65
+    pub account_list_ptr: *mut *const CoreADIAccount,
66
+    #[serde(serialize_with = "serialize_ptr_mut")]
67
+    pub account_list_len: *mut u32,
68
+}
69
+
70
+#[derive(Serialize, PartialEq, Debug)]
71
+#[repr(C)]
72
+pub struct ProvisioningStartMessage {
73
+    pub ds_id: i64,
74
+    #[serde(serialize_with = "serialize_ptr")]
75
+    pub spim_ptr: *const u8,
76
+    pub spim_len: u32,
77
+    #[serde(serialize_with = "serialize_ptr_mut")]
78
+    pub cpim_ptr: *mut *const u8,
79
+    #[serde(serialize_with = "serialize_ptr_mut")]
80
+    pub cpim_len: *mut u32,
81
+    #[serde(serialize_with = "serialize_ptr_mut")]
82
+    pub session: *mut u32,
83
+}
84
+
85
+#[derive(Serialize, PartialEq, Debug)]
86
+#[repr(C)]
87
+pub struct ProvisioningEndMessage {
88
+    pub session: u32,
89
+    #[serde(serialize_with = "serialize_ptr")]
90
+    pub ptm_ptr: *const u8,
91
+    pub ptm_length: u32,
92
+    #[serde(serialize_with = "serialize_ptr")]
93
+    pub tk_ptr: *const u8,
94
+    pub tk_length: u32,
95
+}
96
+
97
+#[derive(Serialize, PartialEq, Debug)]
98
+#[repr(C)]
99
+pub struct ProvisioningSessionDestroyMessage {
100
+    pub session: u32,
101
+}
102
+
103
+#[derive(Serialize, PartialEq, Debug)]
104
+#[repr(C)]
105
+pub struct SetIDMSRoutingMessage {
106
+    pub ds_id: i64,
107
+    pub idms_routing: u64,
108
+}
109
+
110
+#[derive(Serialize, PartialEq, Debug)]
111
+#[repr(C)]
112
+pub struct GetIDMSRoutingMessage {
113
+    pub ds_id: i64,
114
+    #[serde(serialize_with = "serialize_ptr_mut")]
115
+    pub idms_routing: *mut u64,
116
+}
117
+
118
+#[derive(Serialize, PartialEq, Debug)]
119
+#[repr(C)]
120
+pub struct SynchronizeMessage {
121
+    pub ds_id: i64,
122
+    #[serde(serialize_with = "serialize_ptr")]
123
+    pub sim_ptr: *const u8,
124
+    pub sim_len: u32,
125
+    #[serde(serialize_with = "serialize_ptr_mut")]
126
+    pub mid_ptr: *mut *const u8,
127
+    #[serde(serialize_with = "serialize_ptr_mut")]
128
+    pub mid_len: *mut u32,
129
+    #[serde(serialize_with = "serialize_ptr_mut")]
130
+    pub srm_ptr: *mut *const u8,
131
+    #[serde(serialize_with = "serialize_ptr_mut")]
132
+    pub srm_len: *mut u32,
133
+}
134
+
135
+#[derive(Serialize, PartialEq, Debug)]
136
+#[repr(C)]
137
+pub struct ProvisioningEraseMessage {
138
+    pub ds_id: i64,
139
+}
140
+
141
+#[derive(Serialize, PartialEq, Debug)]
142
+#[repr(C)]
143
+pub struct RequestOTPMessage {
144
+    pub ds_id: i64,
145
+    #[serde(serialize_with = "serialize_ptr_mut")]
146
+    pub mid_ptr: *mut *const u8,
147
+    #[serde(serialize_with = "serialize_ptr_mut")]
148
+    pub mid_len: *mut u32,
149
+    #[serde(serialize_with = "serialize_ptr_mut")]
150
+    pub otp_ptr: *mut *const u8,
151
+    #[serde(serialize_with = "serialize_ptr_mut")]
152
+    pub otp_len: *mut u32,
153
+}
154
+
155
+#[derive(Serialize, PartialEq, Debug)]
156
+#[repr(C)]
157
+pub struct StorageDisposeMessage {
158
+    #[serde(serialize_with = "serialize_ptr")]
159
+    pub ptr: *const u8,
160
+}
161
+
162
+#[derive(Serialize, PartialEq, Debug)]
163
+#[repr(C)]
164
+pub struct AllProvisionedAcctStorageDisposeMessage {
165
+    #[serde(serialize_with = "serialize_ptr")]
166
+    pub ptr: *const CoreADIAccount,
167
+    pub len: u32,
168
+}
169
+
170
+#[derive(Serialize, PartialEq, Debug)]
171
+#[repr(C)]
172
+pub struct TearDownLibraryMessage {}
173
+
174
+impl ADIMessage for InitializeMessage {
175
+    const MAGIC: u32 = 0x12db31c5;
176
+    type ReturnType = i32;
177
+}
178
+
179
+impl ADIMessage for IsMachineProvisionedMessage {
180
+    const MAGIC: u32 = 0xb0eda7af;
181
+    type ReturnType = i32;
182
+}
183
+
184
+impl ADIMessage for GetAllProvisionedAccountsMessage {
185
+    const MAGIC: u32 = 0x72096fe6;
186
+    type ReturnType = i32;
187
+}
188
+
189
+impl ADIMessage for ProvisioningStartMessage {
190
+    const MAGIC: u32 = 0x716bd86c;
191
+    type ReturnType = i32;
192
+}
193
+
194
+impl ADIMessage for ProvisioningEndMessage {
195
+    const MAGIC: u32 = 0x0b2b3196;
196
+    type ReturnType = i32;
197
+}
198
+
199
+impl ADIMessage for ProvisioningSessionDestroyMessage {
200
+    const MAGIC: u32 = 0x55a637c0;
201
+    type ReturnType = i32;
202
+}
203
+
204
+impl ADIMessage for SetIDMSRoutingMessage {
205
+    const MAGIC: u32 = 0x632b8d6e;
206
+    type ReturnType = i32;
207
+}
208
+
209
+impl ADIMessage for GetIDMSRoutingMessage {
210
+    const MAGIC: u32 = 0x85fe63b0;
211
+    type ReturnType = i32;
212
+}
213
+
214
+impl ADIMessage for SynchronizeMessage {
215
+    const MAGIC: u32 = 0xa54951ec;
216
+    type ReturnType = i32;
217
+}
218
+
219
+impl ADIMessage for ProvisioningEraseMessage {
220
+    const MAGIC: u32 = 0x7715488c;
221
+    type ReturnType = i32;
222
+}
223
+
224
+impl ADIMessage for RequestOTPMessage {
225
+    const MAGIC: u32 = 0xcfe0b46a;
226
+    type ReturnType = i32;
227
+}
228
+
229
+impl ADIMessage for StorageDisposeMessage {
230
+    const MAGIC: u32 = 0x3e58e7f9;
231
+    type ReturnType = i32;
232
+}
233
+
234
+impl ADIMessage for AllProvisionedAcctStorageDisposeMessage {
235
+    const MAGIC: u32 = 0x9679d4b5;
236
+    type ReturnType = i32;
237
+}
238
+
239
+impl ADIMessage for TearDownLibraryMessage {
240
+    const MAGIC: u32 = 0x08c0fe9e;
241
+    type ReturnType = i32;
242
+}
243
+
244
+/// Contains messages only implemented on Apple platforms
245
+pub mod apple {
246
+    use crate::calls::ADIMessage;
247
+    use crate::calls::serialize_ptr_mut;
248
+    use serde::Serialize;
249
+
250
+    #[derive(Serialize, PartialEq, Debug)]
251
+    #[repr(C)]
252
+    pub struct Gen2FACodeMessage {
253
+        pub ds_id: i64,
254
+        #[serde(serialize_with = "serialize_ptr_mut")]
255
+        pub code: *mut u32,
256
+    }
257
+
258
+    impl ADIMessage for Gen2FACodeMessage {
259
+        const MAGIC: u32 = 0x385b2ce8;
260
+        type ReturnType = i32;
261
+    }
262
+}
263
+
264
+/// Contains messages only implemented on Android platforms
265
+pub mod android {
266
+    use crate::calls::ADIMessage;
267
+    use crate::calls::serialize_ptr;
268
+    use serde::Serialize;
269
+
270
+    // Only on Android implementations
271
+    #[derive(Serialize, PartialEq, Debug)]
272
+    #[repr(C)]
273
+    pub struct SetAndroidIDMessage {
274
+        #[serde(serialize_with = "serialize_ptr")]
275
+        pub android_id_ptr: *const u8,
276
+        pub android_id_len: u32,
277
+    }
278
+
279
+    // Only on Android implementations
280
+    #[derive(Serialize, PartialEq, Debug)]
281
+    #[repr(C)]
282
+    pub struct SetProvisioningPathMessage {
283
+        #[serde(serialize_with = "serialize_ptr")]
284
+        pub provisioning_path: *const std::ffi::c_char,
285
+    }
286
+    // */
287
+    impl ADIMessage for SetAndroidIDMessage {
288
+        const MAGIC: u32 = 0xc774d292;
289
+        type ReturnType = i32;
290
+    }
291
+
292
+    impl ADIMessage for SetProvisioningPathMessage {
293
+        const MAGIC: u32 = 0xb23c691e;
294
+        type ReturnType = i32;
295
+    }
296
+}
... ...
@@ -0,0 +1,495 @@
1
+use crate::calls::{
2
+    ADIMessage, AllProvisionedAcctStorageDisposeMessage, CoreADIAccount,
3
+    GetAllProvisionedAccountsMessage, GetIDMSRoutingMessage, InitializeMessage,
4
+    IsMachineProvisionedMessage, ProvisioningEndMessage, ProvisioningEraseMessage,
5
+    ProvisioningSessionDestroyMessage, ProvisioningStartMessage, RequestOTPMessage,
6
+    SetIDMSRoutingMessage, StorageDisposeMessage, SynchronizeMessage, TearDownLibraryMessage,
7
+    android, apple,
8
+};
9
+use crate::proxy::{
10
+    ADIAccount, ADIBuffer, ADIPayload, ADIProvisioningSession, ADIProxy, ADIResult, EncryptionType,
11
+};
12
+use bincode::config;
13
+use bincode::serde::{decode_from_slice, encode_to_vec};
14
+use std::ffi::CStr;
15
+use std::marker::PhantomData;
16
+use std::mem::MaybeUninit;
17
+use std::slice;
18
+
19
+#[repr(C)]
20
+#[derive(Debug)]
21
+pub struct CoreADIParameters {
22
+    pub payload: *mut u8,
23
+    pub input_size: u32,
24
+    pub output_size: u32,
25
+    pub flags: u32,
26
+}
27
+
28
+pub trait CoreADIProxy {
29
+    unsafe fn dispatch(&self, function_code: u32, parameters: *const CoreADIParameters) -> i32;
30
+}
31
+
32
+pub trait CoreADIProxyHelper: CoreADIProxy {
33
+    fn dispatch_message<Message: ADIMessage>(
34
+        &self,
35
+        message: Message,
36
+    ) -> ADIResult<Message::ReturnType>;
37
+}
38
+
39
+impl<T: CoreADIProxy + ?Sized> CoreADIProxyHelper for T {
40
+    fn dispatch_message<Message: ADIMessage>(
41
+        &self,
42
+        message: Message,
43
+    ) -> ADIResult<Message::ReturnType> {
44
+        let payload = ADIPayload {
45
+            encryption_type: EncryptionType::Clear,
46
+            marker: 1,
47
+            payload: message,
48
+        };
49
+
50
+        let config = config::standard()
51
+            .with_fixed_int_encoding()
52
+            .with_big_endian();
53
+
54
+        let payload = encode_to_vec(&payload, config).expect("ADI message encoding failed??");
55
+        let mut payload: Box<[u8]> = payload.into_boxed_slice();
56
+
57
+        let return_type_length: usize = size_of::<Message::ReturnType>();
58
+        let slice: *mut u8 = payload.as_mut_ptr();
59
+        let mut parameters = CoreADIParameters {
60
+            payload: slice,
61
+            input_size: payload.len() as u32,
62
+            output_size: return_type_length as u32, // HACK
63
+            flags: 0,
64
+        };
65
+
66
+        let dispatch_status = unsafe {
67
+            let params: *mut CoreADIParameters = &mut parameters;
68
+            self.dispatch(Message::MAGIC, params)
69
+        };
70
+
71
+        if dispatch_status < 0 {
72
+            Err(dispatch_status.into())
73
+        } else {
74
+            Ok(decode_from_slice(&payload[0..return_type_length], config)
75
+                .expect("ADI message decoding failed??")
76
+                .0)
77
+        }
78
+    }
79
+}
80
+
81
+impl<T: CoreADIProxyHelper + ?Sized> CoreADIADIProxy for T {
82
+    fn initialize(&self) -> ADIResult<()> {
83
+        let err = self.dispatch_message(InitializeMessage {})?;
84
+        if err < 0 { Err(err.into()) } else { Ok(()) }
85
+    }
86
+
87
+    fn is_machine_provisioned(&self, ds_id: i64) -> ADIResult<bool> {
88
+        let err = self.dispatch_message(IsMachineProvisionedMessage { ds_id })?;
89
+
90
+        match err {
91
+            0 => Ok(true),
92
+            -45061 => Ok(false),
93
+            err => Err(err.into()),
94
+        }
95
+    }
96
+
97
+    fn get_all_provisioned_accounts(&self) -> ADIResult<ADIBuffer<'_, CoreADIAccount>> {
98
+        let mut adi_accounts_ptr = MaybeUninit::uninit();
99
+        let mut adi_accounts_len = MaybeUninit::uninit();
100
+        let err = self.dispatch_message(GetAllProvisionedAccountsMessage {
101
+            account_list_ptr: adi_accounts_ptr.as_mut_ptr(),
102
+            account_list_len: adi_accounts_len.as_mut_ptr(),
103
+        })?;
104
+
105
+        if err < 0 {
106
+            Err(err.into())
107
+        } else {
108
+            Ok(ADIBuffer(unsafe {
109
+                slice::from_raw_parts(
110
+                    adi_accounts_ptr.assume_init(),
111
+                    adi_accounts_len.assume_init() as usize,
112
+                )
113
+            }))
114
+        }
115
+    }
116
+
117
+    fn start_provisioning(
118
+        &self,
119
+        ds_id: i64,
120
+        spim: &[u8],
121
+    ) -> ADIResult<(&[u8], ADIProvisioningSession<'_>)> {
122
+        let mut cpim_ptr = MaybeUninit::uninit();
123
+        let mut cpim_len = MaybeUninit::uninit();
124
+        let mut session = MaybeUninit::uninit();
125
+
126
+        let err = self.dispatch_message(ProvisioningStartMessage {
127
+            ds_id,
128
+            spim_ptr: spim.as_ptr(),
129
+            spim_len: spim.len() as u32,
130
+            cpim_ptr: cpim_ptr.as_mut_ptr(),
131
+            cpim_len: cpim_len.as_mut_ptr(),
132
+            session: session.as_mut_ptr(),
133
+        })?;
134
+
135
+        if err < 0 {
136
+            Err(err.into())
137
+        } else {
138
+            let cpim = unsafe {
139
+                slice::from_raw_parts(cpim_ptr.assume_init(), cpim_len.assume_init() as usize)
140
+            };
141
+            let session = ADIProvisioningSession {
142
+                val: unsafe { session.assume_init() },
143
+                proxy: PhantomData,
144
+            };
145
+            Ok((cpim, session))
146
+        }
147
+    }
148
+
149
+    fn end_provisioning(
150
+        &self,
151
+        session: ADIProvisioningSession,
152
+        ptm: &[u8],
153
+        tk: &[u8],
154
+    ) -> ADIResult<()> {
155
+        let err = self.dispatch_message(ProvisioningEndMessage {
156
+            session: session.val,
157
+            ptm_ptr: ptm.as_ptr(),
158
+            ptm_length: ptm.len() as u32,
159
+            tk_ptr: tk.as_ptr(),
160
+            tk_length: tk.len() as u32,
161
+        })?;
162
+        std::mem::forget(session);
163
+
164
+        if err < 0 { Err(err.into()) } else { Ok(()) }
165
+    }
166
+
167
+    fn destroy_provisioning_session(&self, session: ADIProvisioningSession) -> ADIResult<()> {
168
+        let err = self.dispatch_message(ProvisioningSessionDestroyMessage {
169
+            session: session.val,
170
+        })?;
171
+        std::mem::forget(session);
172
+
173
+        if err < 0 { Err(err.into()) } else { Ok(()) }
174
+    }
175
+
176
+    fn set_idms_routing(&self, ds_id: i64, routing_info: u64) -> ADIResult<()> {
177
+        let err = self.dispatch_message(SetIDMSRoutingMessage {
178
+            ds_id,
179
+            idms_routing: routing_info,
180
+        })?;
181
+
182
+        if err < 0 { Err(err.into()) } else { Ok(()) }
183
+    }
184
+
185
+    fn get_idms_routing(&self, ds_id: i64) -> ADIResult<u64> {
186
+        let mut routing_info = MaybeUninit::uninit();
187
+        let err = self.dispatch_message(GetIDMSRoutingMessage {
188
+            ds_id,
189
+            idms_routing: routing_info.as_mut_ptr(),
190
+        })?;
191
+
192
+        if err < 0 {
193
+            Err(err.into())
194
+        } else {
195
+            Ok(unsafe { routing_info.assume_init() })
196
+        }
197
+    }
198
+
199
+    fn synchronize(
200
+        &self,
201
+        ds_id: i64,
202
+        sim: &[u8],
203
+    ) -> ADIResult<(ADIBuffer<'_, u8>, ADIBuffer<'_, u8>)> {
204
+        let mut mid_ptr = MaybeUninit::uninit();
205
+        let mut mid_len = MaybeUninit::uninit();
206
+        let mut srm_ptr = MaybeUninit::uninit();
207
+        let mut srm_len = MaybeUninit::uninit();
208
+
209
+        let err = self.dispatch_message(SynchronizeMessage {
210
+            ds_id,
211
+            sim_ptr: sim.as_ptr(),
212
+            sim_len: sim.len() as u32,
213
+            mid_ptr: mid_ptr.as_mut_ptr(),
214
+            mid_len: mid_len.as_mut_ptr(),
215
+            srm_ptr: srm_ptr.as_mut_ptr(),
216
+            srm_len: srm_len.as_mut_ptr(),
217
+        })?;
218
+
219
+        if err < 0 {
220
+            Err(err.into())
221
+        } else {
222
+            Ok((
223
+                ADIBuffer(unsafe {
224
+                    slice::from_raw_parts(mid_ptr.assume_init(), mid_len.assume_init() as usize)
225
+                }),
226
+                ADIBuffer(unsafe {
227
+                    slice::from_raw_parts(srm_ptr.assume_init(), srm_len.assume_init() as usize)
228
+                }),
229
+            ))
230
+        }
231
+    }
232
+
233
+    fn erase_provisioning(&self, ds_id: i64) -> ADIResult<()> {
234
+        let err = self.dispatch_message(ProvisioningEraseMessage { ds_id })?;
235
+
236
+        if err < 0 { Err(err.into()) } else { Ok(()) }
237
+    }
238
+
239
+    fn request_otp(&self, ds_id: i64) -> ADIResult<(ADIBuffer<'_, u8>, ADIBuffer<'_, u8>)> {
240
+        let mut mid_ptr = MaybeUninit::uninit();
241
+        let mut mid_len = MaybeUninit::uninit();
242
+        let mut otp_ptr = MaybeUninit::uninit();
243
+        let mut otp_len = MaybeUninit::uninit();
244
+
245
+        let err = self.dispatch_message(RequestOTPMessage {
246
+            ds_id,
247
+            mid_ptr: mid_ptr.as_mut_ptr(),
248
+            mid_len: mid_len.as_mut_ptr(),
249
+            otp_ptr: otp_ptr.as_mut_ptr(),
250
+            otp_len: otp_len.as_mut_ptr(),
251
+        })?;
252
+
253
+        if err < 0 {
254
+            Err(err.into())
255
+        } else {
256
+            Ok((
257
+                ADIBuffer(unsafe {
258
+                    slice::from_raw_parts(mid_ptr.assume_init(), mid_len.assume_init() as usize)
259
+                }),
260
+                ADIBuffer(unsafe {
261
+                    slice::from_raw_parts(otp_ptr.assume_init(), otp_len.assume_init() as usize)
262
+                }),
263
+            ))
264
+        }
265
+    }
266
+
267
+    fn dispose(&self, buffer: ADIBuffer<'_, u8>) -> ADIResult<()> {
268
+        let buf = buffer.0;
269
+        std::mem::forget(buffer);
270
+        let err = self.dispatch_message(StorageDisposeMessage { ptr: buf.as_ptr() })?;
271
+        if err < 0 {
272
+            let err = err.into();
273
+            #[cfg(test)]
274
+            {
275
+                let ptr = buf.as_ptr();
276
+                let len = buf.len();
277
+                log::warn!("Leak of buf {ptr:p} of size {len}: {err:?}");
278
+            }
279
+            Err(err)
280
+        } else {
281
+            Ok(())
282
+        }
283
+    }
284
+
285
+    fn dispose_account_storage(&self, buffer: ADIBuffer<'_, CoreADIAccount>) -> ADIResult<()> {
286
+        let buf = buffer.0;
287
+        std::mem::forget(buffer);
288
+        let err = self.dispatch_message(AllProvisionedAcctStorageDisposeMessage {
289
+            ptr: buf.as_ptr(),
290
+            len: buf.len() as u32,
291
+        })?;
292
+        if err < 0 {
293
+            let err = err.into();
294
+            #[cfg(test)]
295
+            {
296
+                let ptr = buf.as_ptr();
297
+                let len = buf.len();
298
+                log::warn!("Leak of buf {ptr:p} of size {len}: {err:?}");
299
+            }
300
+            Err(err)
301
+        } else {
302
+            Ok(())
303
+        }
304
+    }
305
+
306
+    fn finalize(&self) -> ADIResult<()> {
307
+        let err = self.dispatch_message(TearDownLibraryMessage {})?;
308
+
309
+        if err < 0 { Err(err.into()) } else { Ok(()) }
310
+    }
311
+
312
+    fn set_provisioning_path(&self, path: &CStr) -> ADIResult<()> {
313
+        let err = self.dispatch_message(android::SetProvisioningPathMessage {
314
+            provisioning_path: path.as_ptr(),
315
+        })?;
316
+
317
+        if err < 0 { Err(err.into()) } else { Ok(()) }
318
+    }
319
+
320
+    fn set_android_id(&self, id: &str) -> ADIResult<()> {
321
+        assert_eq!(id.len(), 16, "The identifier must be 16 characters long.");
322
+        let err = self.dispatch_message(android::SetAndroidIDMessage {
323
+            android_id_ptr: id.as_ptr(),
324
+            android_id_len: id.len() as u32,
325
+        })?;
326
+
327
+        if err < 0 { Err(err.into()) } else { Ok(()) }
328
+    }
329
+
330
+    fn generate_2fa_code(&self, ds_id: i64) -> ADIResult<u32> {
331
+        let mut code = MaybeUninit::uninit();
332
+        let err = self.dispatch_message(apple::Gen2FACodeMessage {
333
+            ds_id,
334
+            code: code.as_mut_ptr(),
335
+        })?;
336
+
337
+        if err < 0 {
338
+            Err(err.into())
339
+        } else {
340
+            Ok(unsafe { code.assume_init() })
341
+        }
342
+    }
343
+}
344
+
345
+pub trait CoreADIADIProxy {
346
+    fn initialize(&self) -> ADIResult<()>;
347
+    fn is_machine_provisioned(&self, ds_id: i64) -> ADIResult<bool>;
348
+    fn get_all_provisioned_accounts(&self) -> ADIResult<ADIBuffer<'_, CoreADIAccount>>;
349
+    fn start_provisioning(
350
+        &self,
351
+        ds_id: i64,
352
+        spim: &[u8],
353
+    ) -> ADIResult<(&[u8], ADIProvisioningSession<'_>)>;
354
+    fn end_provisioning(
355
+        &self,
356
+        session: ADIProvisioningSession,
357
+        ptm: &[u8],
358
+        tk: &[u8],
359
+    ) -> ADIResult<()>;
360
+    fn destroy_provisioning_session(&self, session: ADIProvisioningSession) -> ADIResult<()>;
361
+    fn set_idms_routing(&self, ds_id: i64, routing_info: u64) -> ADIResult<()>;
362
+    fn get_idms_routing(&self, ds_id: i64) -> ADIResult<u64>;
363
+    fn synchronize(
364
+        &self,
365
+        ds_id: i64,
366
+        sim: &[u8],
367
+    ) -> ADIResult<(ADIBuffer<'_, u8>, ADIBuffer<'_, u8>)>;
368
+    fn erase_provisioning(&self, ds_id: i64) -> ADIResult<()>;
369
+    fn request_otp(&self, ds_id: i64) -> ADIResult<(ADIBuffer<'_, u8>, ADIBuffer<'_, u8>)>;
370
+
371
+    fn dispose(&self, buffer: ADIBuffer<'_, u8>) -> ADIResult<()>;
372
+    fn dispose_account_storage(&self, buffer: ADIBuffer<'_, CoreADIAccount>) -> ADIResult<()>;
373
+    fn finalize(&self) -> ADIResult<()>;
374
+    fn set_provisioning_path(&self, path: &CStr) -> ADIResult<()>;
375
+    fn set_android_id(&self, id: &str) -> ADIResult<()>;
376
+    fn generate_2fa_code(&self, ds_id: i64) -> ADIResult<u32>;
377
+}
378
+
379
+impl<T: CoreADIADIProxy> ADIProxy for T {
380
+    fn is_machine_provisioned(&self, ds_id: i64) -> ADIResult<bool> {
381
+        <Self as CoreADIADIProxy>::is_machine_provisioned(self, ds_id)
382
+    }
383
+
384
+    fn get_all_provisioned_accounts(&self) -> ADIResult<Vec<ADIAccount>> {
385
+        let coreadi_accounts = <Self as CoreADIADIProxy>::get_all_provisioned_accounts(self)?;
386
+        let accounts: Vec<ADIAccount> = unsafe {
387
+            coreadi_accounts.0.iter().map(
388
+                |&CoreADIAccount {
389
+                     ds_id,
390
+                     mid_len,
391
+                     otp_len,
392
+                     mid_ptr,
393
+                     otp_ptr,
394
+                 }| ADIAccount {
395
+                    ds_id,
396
+                    mid: slice::from_raw_parts(mid_ptr, mid_len as usize).to_vec(),
397
+                    otp: slice::from_raw_parts(otp_ptr, otp_len as usize).to_vec(),
398
+                },
399
+            )
400
+        }
401
+        .collect();
402
+        self.dispose_account_storage(coreadi_accounts)?;
403
+        Ok(accounts)
404
+    }
405
+
406
+    fn start_provisioning(
407
+        &self,
408
+        ds_id: i64,
409
+        spim: &[u8],
410
+    ) -> ADIResult<(Vec<u8>, ADIProvisioningSession<'_>)> {
411
+        let (cpim, session) = <Self as CoreADIADIProxy>::start_provisioning(self, ds_id, spim)?;
412
+        Ok((cpim.to_vec(), session))
413
+    }
414
+
415
+    fn end_provisioning(
416
+        &self,
417
+        session: ADIProvisioningSession,
418
+        ptm: &[u8],
419
+        tk: &[u8],
420
+    ) -> ADIResult<()> {
421
+        <Self as CoreADIADIProxy>::end_provisioning(self, session, ptm, tk)
422
+    }
423
+
424
+    fn destroy_provisioning_session(&self, session: ADIProvisioningSession) -> ADIResult<()> {
425
+        <Self as CoreADIADIProxy>::destroy_provisioning_session(self, session)
426
+    }
427
+
428
+    fn set_idms_routing(&self, ds_id: i64, routing_info: u64) -> ADIResult<()> {
429
+        <Self as CoreADIADIProxy>::set_idms_routing(self, ds_id, routing_info)
430
+    }
431
+
432
+    fn get_idms_routing(&self, ds_id: i64) -> ADIResult<u64> {
433
+        <Self as CoreADIADIProxy>::get_idms_routing(self, ds_id)
434
+    }
435
+
436
+    fn synchronize(&self, ds_id: i64, sim: &[u8]) -> ADIResult<(Vec<u8>, Vec<u8>)> {
437
+        let (mid_buf, srm_buf) = <Self as CoreADIADIProxy>::synchronize(self, ds_id, sim)?;
438
+        let (mid, srm) = (mid_buf.0.to_vec(), srm_buf.0.to_vec());
439
+        self.dispose(mid_buf).and_then(|()| self.dispose(srm_buf))?;
440
+        Ok((mid, srm))
441
+    }
442
+
443
+    fn erase_provisioning(&self, ds_id: i64) -> ADIResult<()> {
444
+        <Self as CoreADIADIProxy>::erase_provisioning(self, ds_id)
445
+    }
446
+
447
+    fn request_otp(&self, ds_id: i64) -> ADIResult<(Vec<u8>, Vec<u8>)> {
448
+        let (mid_buf, otp_buf) = <Self as CoreADIADIProxy>::request_otp(self, ds_id)?;
449
+        let (mid, otp) = (mid_buf.0.to_vec(), otp_buf.0.to_vec());
450
+        self.dispose(mid_buf).and_then(|()| self.dispose(otp_buf))?;
451
+        Ok((mid.into(), otp.into()))
452
+    }
453
+
454
+    fn set_provisioning_path(&self, path: &CStr) -> ADIResult<()> {
455
+        <Self as CoreADIADIProxy>::set_provisioning_path(self, path)
456
+    }
457
+
458
+    fn set_android_id(&self, id: &str) -> ADIResult<()> {
459
+        <Self as CoreADIADIProxy>::set_android_id(self, id)
460
+    }
461
+
462
+    fn generate_2fa_code(&self, ds_id: i64) -> ADIResult<u32> {
463
+        <Self as CoreADIADIProxy>::generate_2fa_code(self, ds_id)
464
+    }
465
+}
466
+
467
+#[cfg(test)]
468
+mod tests {
469
+    use super::*;
470
+    use std::ptr::slice_from_raw_parts;
471
+
472
+    struct ADITestProxy;
473
+
474
+    impl CoreADIProxy for ADITestProxy {
475
+        unsafe fn dispatch(&self, function_code: u32, parameters: *const CoreADIParameters) -> i32 {
476
+            unsafe {
477
+                let parameters = &*parameters;
478
+                println!(
479
+                    "{:08X?}({:?}) - \"{:02X?}\"",
480
+                    function_code,
481
+                    parameters,
482
+                    &*slice_from_raw_parts(parameters.payload, parameters.input_size as usize)
483
+                );
484
+            }
485
+            0
486
+        }
487
+    }
488
+
489
+    #[test]
490
+    fn it_works() {
491
+        let proxy = ADITestProxy {};
492
+        proxy.initialize().unwrap();
493
+        proxy.finalize().unwrap();
494
+    }
495
+}
... ...
@@ -0,0 +1,5 @@
1
+pub mod calls;
2
+pub mod core_adi;
3
+pub mod proxy;
4
+
5
+pub use proxy::ADIProxy;
... ...
@@ -0,0 +1,267 @@
1
+use crate::calls::ADIMessage;
2
+use serde::{Serialize, Serializer};
3
+use std::ffi::CStr;
4
+use std::fmt::{Debug, Display};
5
+use std::marker::PhantomData;
6
+
7
+#[derive(Copy, Clone, Debug, PartialEq)]
8
+pub enum EncryptionType {
9
+    Clear,
10
+    Encrypted,
11
+}
12
+
13
+impl From<EncryptionType> for u32 {
14
+    fn from(value: EncryptionType) -> Self {
15
+        match value {
16
+            EncryptionType::Clear => 1,
17
+            EncryptionType::Encrypted => 2,
18
+        }
19
+    }
20
+}
21
+
22
+impl Serialize for EncryptionType {
23
+    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
24
+    where
25
+        S: Serializer,
26
+    {
27
+        let encryption_type: u32 = (*self).into();
28
+        encryption_type.serialize(serializer)
29
+    }
30
+}
31
+
32
+#[repr(i32)]
33
+#[derive(Debug)]
34
+pub enum ADIError {
35
+    // -45001 - Invalid parameters, have all the library fields been properly initialized?
36
+    InvalidParameters = -45001,
37
+    // -45002 - Invalid parameters.
38
+    InvalidParameters2 = -45002,
39
+    // -45003 - Trust Key is invalid
40
+    InvalidTK = -45003,
41
+    // -45004 - Unknown, but observed in fm23w5mn5o
42
+    // <unknown = -45004>,
43
+    // -45006 - Valid PTM/TK pair, but not matching the inner ADI state.
44
+    PTMTKPairMismatch = -45006,
45
+    // -45012 - Thread error
46
+    ThreadingError = -45012,
47
+    // -45016 - Mach call failed, can't contact adid.
48
+    UnreachableADID = -45016,
49
+    // -45017 - Mach call cannot be sent to adid, have you got the right entitlements?
50
+    MachMessageError = -45017,
51
+    // -45018 - Unknown encryption scheme given to CoreADI.
52
+    InvalidEncryptionScheme = -45018,
53
+    // -45019 - Unimplemented call
54
+    InvalidFunctionCode = -45019,
55
+    // -45020 - Cannot decrypt the input parameter block.
56
+    InvalidParameterBody = -45020,
57
+    // -45025 - Unknown session number.
58
+    InvalidSession = -45025,
59
+    // -45026 - Empty session number.
60
+    EmptySession = -45026,
61
+    // -45031 - Cryptographic block: Invalid input header.
62
+    InvalidEncryptedBlockHeader = -45031,
63
+    // -45032 - Cryptographic block: Invalid input length.
64
+    InvalidEncryptedBlockLength = -45032,
65
+    // -45033 - Cryptographic block: Input has been tampered with.
66
+    InvalidEncryptedBlockContent = -45033,
67
+    // -45034 - Invalid ADI call: input buffer is too small.
68
+    InvalidADICall = -45034,
69
+    // -45036 - Invalid time.
70
+    InvalidTime = -45036,
71
+    // -45046 - Invalid hardware identifiers.
72
+    InvalidHardwareIdentifiers = -45046,
73
+    // -45054 - Filesystem error.
74
+    FilesystemError,
75
+    // -45061 - Device has not been provisioned.
76
+    NotProvisioned = -45061,
77
+    // -45062 - No provisioning data to erase.
78
+    NoProvisioningToErase = -45062,
79
+    // -45063 - Another provisioning session is pending.
80
+    PendingSession = -45063,
81
+    // -45066 - Session has been previously ended.
82
+    TerminatedSession = -45066,
83
+    // -45075 - Cannot load the CoreADI executable.
84
+    LibraryLoadingError = -45075,
85
+    // -45076 - This CoreADI distribution has been phased out in favor of adid. Downgrade CoreADI or switch to adid.
86
+    UnsupportedCoreADI = -45076,
87
+    UnknownError(i32) = -1,
88
+}
89
+
90
+impl From<i32> for ADIError {
91
+    fn from(value: i32) -> Self {
92
+        match value {
93
+            -45001 => ADIError::InvalidParameters,
94
+            -45002 => ADIError::InvalidParameters2,
95
+            -45003 => ADIError::InvalidTK,
96
+            -45006 => ADIError::PTMTKPairMismatch,
97
+            -45012 => ADIError::ThreadingError,
98
+            -45016 => ADIError::UnreachableADID,
99
+            -45017 => ADIError::MachMessageError,
100
+            -45018 => ADIError::InvalidEncryptionScheme,
101
+            -45019 => ADIError::InvalidFunctionCode,
102
+            -45020 => ADIError::InvalidParameterBody,
103
+            -45025 => ADIError::InvalidSession,
104
+            -45026 => ADIError::EmptySession,
105
+            -45031 => ADIError::InvalidEncryptedBlockHeader,
106
+            -45032 => ADIError::InvalidEncryptedBlockLength,
107
+            -45033 => ADIError::InvalidEncryptedBlockContent,
108
+            -45034 => ADIError::InvalidADICall,
109
+            -45036 => ADIError::InvalidTime,
110
+            -45046 => ADIError::InvalidHardwareIdentifiers,
111
+            -45054 => ADIError::FilesystemError,
112
+            -45061 => ADIError::NotProvisioned,
113
+            -45062 => ADIError::NoProvisioningToErase,
114
+            -45063 => ADIError::PendingSession,
115
+            -45066 => ADIError::TerminatedSession,
116
+            -45075 => ADIError::LibraryLoadingError,
117
+            -45076 => ADIError::UnsupportedCoreADI,
118
+            _ => ADIError::UnknownError(value),
119
+        }
120
+    }
121
+}
122
+
123
+impl Display for ADIError {
124
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
125
+        match self {
126
+            ADIError::InvalidParameters => write!(
127
+                f,
128
+                "Invalid parameters, have all the library fields been properly initialized? (-45001)"
129
+            ),
130
+            ADIError::InvalidParameters2 => write!(f, "Invalid parameters. (-45002)"),
131
+            ADIError::InvalidTK => write!(f, "Trust Key is invalid (-45003)"),
132
+            ADIError::PTMTKPairMismatch => write!(
133
+                f,
134
+                "Valid PTM/TK pair, but not matching the inner ADI state. (-45006)"
135
+            ),
136
+            ADIError::ThreadingError => write!(f, "Thread error (-45012)"),
137
+            ADIError::UnreachableADID => {
138
+                write!(f, "Mach call failed, can't contact adid. (-45016)")
139
+            }
140
+            ADIError::MachMessageError => write!(
141
+                f,
142
+                "Mach call cannot be sent to adid, have you got the right entitlements? (-45017)"
143
+            ),
144
+            ADIError::InvalidEncryptionScheme => {
145
+                write!(f, "Unknown encryption scheme given to CoreADI. (-45018)")
146
+            }
147
+            ADIError::InvalidFunctionCode => write!(f, "Unimplemented call (-45019)"),
148
+            ADIError::InvalidParameterBody => {
149
+                write!(f, "Cannot decrypt the input parameter block. (-45020)")
150
+            }
151
+            ADIError::InvalidSession => write!(f, "Unknown session number. (-45025)"),
152
+            ADIError::EmptySession => write!(f, "Empty session number. (-45026)"),
153
+            ADIError::InvalidEncryptedBlockHeader => {
154
+                write!(f, "Cryptographic block: Invalid input header. (-45031)")
155
+            }
156
+            ADIError::InvalidEncryptedBlockLength => {
157
+                write!(f, "Cryptographic block: Invalid input length. (-45032)")
158
+            }
159
+            ADIError::InvalidEncryptedBlockContent => write!(
160
+                f,
161
+                "Cryptographic block: Input has been tampered with. (-45033)"
162
+            ),
163
+            ADIError::InvalidADICall => {
164
+                write!(f, "Invalid ADI call: input buffer is too small. (-45034)")
165
+            }
166
+            ADIError::InvalidTime => write!(f, "Invalid time. (-45036)"),
167
+            ADIError::InvalidHardwareIdentifiers => {
168
+                write!(f, "Invalid hardware identifiers. (-45046)")
169
+            }
170
+            ADIError::FilesystemError => write!(f, "Filesystem error. (-45054)"),
171
+            ADIError::NotProvisioned => write!(f, "Device has not been provisioned. (-45061)"),
172
+            ADIError::NoProvisioningToErase => write!(f, "No provisioning data to erase. (-45062)"),
173
+            ADIError::PendingSession => {
174
+                write!(f, "Another provisioning session is pending. (-45063)")
175
+            }
176
+            ADIError::TerminatedSession => write!(f, "Session has been previously ended. (-45066)"),
177
+            ADIError::LibraryLoadingError => {
178
+                write!(f, "Cannot load the CoreADI executable. (-45075)")
179
+            }
180
+            ADIError::UnsupportedCoreADI => write!(
181
+                f,
182
+                "This CoreADI distribution has been phased out in favor of adid. Downgrade CoreADI or switch to adid. (-45076)"
183
+            ),
184
+            ADIError::UnknownError(n) => write!(f, "Unknown error. ({n})"),
185
+        }
186
+    }
187
+}
188
+
189
+impl std::error::Error for ADIError {}
190
+
191
+pub type ADIResult<T> = Result<T, ADIError>;
192
+
193
+#[derive(Serialize, PartialEq, Debug)]
194
+#[repr(C)]
195
+pub struct ADIPayload<Message: ADIMessage> {
196
+    pub encryption_type: EncryptionType,
197
+    pub marker: u32,
198
+    pub payload: Message,
199
+}
200
+
201
+pub struct ADIBuffer<'lt, T>(pub &'lt [T]);
202
+
203
+pub struct ADIProvisioningSession<'lt> {
204
+    pub val: u32,
205
+    pub proxy: PhantomData<&'lt dyn ADIProxy>,
206
+}
207
+
208
+impl<T> Drop for ADIBuffer<'_, T> {
209
+    fn drop(&mut self) {
210
+        // it should never be called :(
211
+        // in D we could have added a static assert here giving a compiling error and preventing misuse.
212
+        panic!("The ADIBuffer {self:p} has not been disposed properly.");
213
+    }
214
+}
215
+
216
+impl Drop for ADIProvisioningSession<'_> {
217
+    fn drop(&mut self) {
218
+        // it should never be called :(
219
+        // in D we could have added a static assert here giving a compiling error and preventing misuse.
220
+        panic!(
221
+            "The ADIProvisioningSession {} has not been terminated properly.",
222
+            self.val
223
+        );
224
+    }
225
+}
226
+
227
+#[derive(Debug, Clone)]
228
+pub struct ADIAccount {
229
+    pub ds_id: i64,
230
+    pub mid: Vec<u8>,
231
+    pub otp: Vec<u8>,
232
+}
233
+
234
+pub trait ADIProxy {
235
+    /// Returns whether ADI stores provisioning data for a given DSID.
236
+    fn is_machine_provisioned(&self, ds_id: i64) -> ADIResult<bool>;
237
+    /// Get a list of every provisioned DSID along with its associated MID and OTP.
238
+    fn get_all_provisioned_accounts(&self) -> ADIResult<Vec<ADIAccount>>;
239
+    /// Starts a provisioning session for the DSID.
240
+    fn start_provisioning(
241
+        &self,
242
+        ds_id: i64,
243
+        spim: &[u8],
244
+    ) -> ADIResult<(Vec<u8>, ADIProvisioningSession<'_>)>;
245
+    /// Ends a provisioning session.
246
+    fn end_provisioning(
247
+        &self,
248
+        session: ADIProvisioningSession,
249
+        ptm: &[u8],
250
+        tk: &[u8],
251
+    ) -> ADIResult<()>;
252
+    /// Cancels a provisioning session.
253
+    fn destroy_provisioning_session(&self, session: ADIProvisioningSession) -> ADIResult<()>;
254
+    fn set_idms_routing(&self, ds_id: i64, routing_info: u64) -> ADIResult<()>;
255
+    fn get_idms_routing(&self, ds_id: i64) -> ADIResult<u64>;
256
+    fn synchronize(&self, ds_id: i64, sim: &[u8]) -> ADIResult<(Vec<u8>, Vec<u8>)>;
257
+    fn erase_provisioning(&self, ds_id: i64) -> ADIResult<()>;
258
+    fn request_otp(&self, ds_id: i64) -> ADIResult<(Vec<u8>, Vec<u8>)>;
259
+
260
+    /// Exclusive to Android's CoreADI: set the provisioning path.
261
+    fn set_provisioning_path(&self, path: &CStr) -> ADIResult<()>;
262
+    /// Exclusive to Android's CoreADI: set the hardware identifier used by the library.
263
+    fn set_android_id(&self, id: &str) -> ADIResult<()>;
264
+
265
+    /// Exclusive to Apple's ADI implementations: compute a 2FA code.
266
+    fn generate_2fa_code(&self, ds_id: i64) -> ADIResult<u32>;
267
+}
... ...
@@ -0,0 +1,9 @@
1
+[package]
2
+name = "adid-proxy"
3
+version = "0.1.0"
4
+edition = "2024"
5
+
6
+[dependencies]
7
+adi.workspace = true
8
+xpc-connection-sys = "0.1.1"
9
+block = "0.1.6"
... ...
@@ -0,0 +1,3 @@
1
+# adid-proxy
2
+
3
+Contact the adid daemon to retrieve the data.
... ...
@@ -0,0 +1,354 @@
1
+extern crate core;
2
+
3
+use adi::calls::{
4
+    ADIMessage, GetAllProvisionedAccountsMessage, GetIDMSRoutingMessage,
5
+    IsMachineProvisionedMessage, ProvisioningEndMessage, ProvisioningEraseMessage,
6
+    ProvisioningSessionDestroyMessage, ProvisioningStartMessage, RequestOTPMessage,
7
+    SetIDMSRoutingMessage, SynchronizeMessage,
8
+};
9
+mod xpc;
10
+
11
+use crate::xpc::{XpcConnection, XpcData, XpcDictionary};
12
+use adi::calls::android::{SetAndroidIDMessage, SetProvisioningPathMessage};
13
+use adi::calls::apple::Gen2FACodeMessage;
14
+use adi::proxy::{
15
+    ADIAccount, ADIError, ADIProvisioningSession, ADIProxy, ADIResult, EncryptionType,
16
+};
17
+use block::ConcreteBlock;
18
+use std::ffi::CStr;
19
+use std::marker::PhantomData;
20
+use std::mem;
21
+use std::ops::Deref;
22
+use xpc_connection_sys::XPC_CONNECTION_MACH_SERVICE_PRIVILEGED;
23
+
24
+pub struct ADIdProxy {
25
+    connection: XpcConnection,
26
+}
27
+
28
+impl ADIdProxy {
29
+    pub fn connect() -> Self {
30
+        let connection = XpcConnection::create_mach_service(
31
+            c"com.apple.adid",
32
+            None,
33
+            XPC_CONNECTION_MACH_SERVICE_PRIVILEGED as u64,
34
+        );
35
+
36
+        let block = ConcreteBlock::new(move |_event| {}).copy();
37
+        connection.set_event_handler(block);
38
+        connection.resume();
39
+
40
+        // proxy.send(0x72096fe6, &[0, 0, 0, 1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE]).await;
41
+        ADIdProxy { connection }
42
+    }
43
+
44
+    pub fn send(&self, payload: ADIPayload) -> ADIResult<XpcDictionary> {
45
+        let data = payload.0;
46
+
47
+        let payload = XpcData::create(&data);
48
+        let message = XpcDictionary::create_empty();
49
+        message.set_value(c"data", payload.0);
50
+
51
+        let message = self
52
+            .connection
53
+            .send_message_with_reply_sync(&message)
54
+            .map_err(|_| ADIError::MachMessageError)?;
55
+
56
+        Ok(message)
57
+    }
58
+}
59
+
60
+pub fn check_response(data: &[u8]) -> ADIResult<&[u8]> {
61
+    let (adi_code, data) = i32::decode(data);
62
+    if adi_code != 0 {
63
+        Err(adi_code.into())
64
+    } else {
65
+        Ok(data)
66
+    }
67
+}
68
+
69
+impl ADIProxy for ADIdProxy {
70
+    fn is_machine_provisioned(&self, ds_id: i64) -> ADIResult<bool> {
71
+        let response =
72
+            self.send(ADIPayload::new(IsMachineProvisionedMessage::MAGIC).push(ds_id))?;
73
+        match check_response(response.get_data(c"data")) {
74
+            Ok(_) => Ok(true),
75
+            Err(ADIError::NotProvisioned) => Ok(false),
76
+            Err(e) => Err(e),
77
+        }
78
+    }
79
+
80
+    fn get_all_provisioned_accounts(&self) -> ADIResult<Vec<ADIAccount>> {
81
+        let response = self.send(ADIPayload::new(GetAllProvisionedAccountsMessage::MAGIC))?;
82
+        check_response(response.get_data(c"data"))
83
+            .map(Vec::decode)
84
+            .map(|(a, _)| a)
85
+    }
86
+
87
+    fn start_provisioning(
88
+        &self,
89
+        ds_id: i64,
90
+        spim: &[u8],
91
+    ) -> ADIResult<(Vec<u8>, ADIProvisioningSession<'_>)> {
92
+        let response = self.send(
93
+            ADIPayload::new(ProvisioningStartMessage::MAGIC)
94
+                .push(ds_id)
95
+                .push(spim),
96
+        )?;
97
+        check_response(response.get_data(c"data")).map(|data| {
98
+            let (cpim, data) = <Vec<u8>>::decode(data);
99
+            let (session, _) = u32::decode(data);
100
+            (
101
+                cpim,
102
+                ADIProvisioningSession {
103
+                    val: session,
104
+                    proxy: PhantomData,
105
+                },
106
+            )
107
+        })
108
+    }
109
+
110
+    fn end_provisioning(
111
+        &self,
112
+        session: ADIProvisioningSession,
113
+        ptm: &[u8],
114
+        tk: &[u8],
115
+    ) -> ADIResult<()> {
116
+        let response = self.send(
117
+            ADIPayload::new(ProvisioningEndMessage::MAGIC)
118
+                .push(session.val)
119
+                .push(ptm)
120
+                .push(tk),
121
+        )?;
122
+        check_response(response.get_data(c"data"))?;
123
+        Ok(())
124
+    }
125
+
126
+    fn destroy_provisioning_session(&self, session: ADIProvisioningSession) -> ADIResult<()> {
127
+        let response =
128
+            self.send(ADIPayload::new(ProvisioningSessionDestroyMessage::MAGIC).push(session.val))?;
129
+        check_response(response.get_data(c"data"))?;
130
+        Ok(())
131
+    }
132
+
133
+    fn set_idms_routing(&self, ds_id: i64, routing_info: u64) -> ADIResult<()> {
134
+        let response = self.send(
135
+            ADIPayload::new(SetIDMSRoutingMessage::MAGIC)
136
+                .push(ds_id)
137
+                .push(routing_info),
138
+        )?;
139
+        check_response(response.get_data(c"data"))?;
140
+        Ok(())
141
+    }
142
+
143
+    fn get_idms_routing(&self, ds_id: i64) -> ADIResult<u64> {
144
+        let response = self.send(ADIPayload::new(GetIDMSRoutingMessage::MAGIC).push(ds_id))?;
145
+        check_response(response.get_data(c"data")).map(|data| {
146
+            let (routing_info, _) = u64::decode(data);
147
+            routing_info
148
+        })
149
+    }
150
+
151
+    fn synchronize(&self, ds_id: i64, sim: &[u8]) -> ADIResult<(Vec<u8>, Vec<u8>)> {
152
+        let response = self.send(
153
+            ADIPayload::new(SynchronizeMessage::MAGIC)
154
+                .push(ds_id)
155
+                .push(sim),
156
+        )?;
157
+        check_response(response.get_data(c"data")).map(|data| {
158
+            let (mid, data) = <Vec<u8>>::decode(data);
159
+            let (srm, _) = <Vec<u8>>::decode(data);
160
+            (mid, srm)
161
+        })
162
+    }
163
+
164
+    fn erase_provisioning(&self, ds_id: i64) -> ADIResult<()> {
165
+        let response = self.send(ADIPayload::new(ProvisioningEraseMessage::MAGIC).push(ds_id))?;
166
+        check_response(response.get_data(c"data"))?;
167
+        Ok(())
168
+    }
169
+
170
+    fn request_otp(&self, ds_id: i64) -> ADIResult<(Vec<u8>, Vec<u8>)> {
171
+        let response = self.send(ADIPayload::new(RequestOTPMessage::MAGIC).push(ds_id))?;
172
+        check_response(response.get_data(c"data")).map(|data| {
173
+            let (mid, data) = <Vec<u8>>::decode(data);
174
+            let (otp, _) = <Vec<u8>>::decode(data);
175
+            (mid, otp)
176
+        })
177
+    }
178
+
179
+    fn set_provisioning_path(&self, path: &CStr) -> ADIResult<()> {
180
+        let response = self.send(ADIPayload::new(SetProvisioningPathMessage::MAGIC).push(path))?;
181
+        check_response(response.get_data(c"data"))?;
182
+        Ok(())
183
+    }
184
+
185
+    fn set_android_id(&self, id: &str) -> ADIResult<()> {
186
+        let response = self.send(ADIPayload::new(SetAndroidIDMessage::MAGIC).push(id))?;
187
+        check_response(response.get_data(c"data"))?;
188
+        Ok(())
189
+    }
190
+
191
+    fn generate_2fa_code(&self, ds_id: i64) -> ADIResult<u32> {
192
+        let response = self.send(ADIPayload::new(Gen2FACodeMessage::MAGIC).push(ds_id))?;
193
+        check_response(response.get_data(c"data")).map(|data| {
194
+            let (code, _) = u32::decode(data);
195
+            code
196
+        })
197
+    }
198
+}
199
+
200
+pub trait ADIdEncodable: Sized {
201
+    fn encode(&self) -> impl AsRef<[u8]>;
202
+}
203
+
204
+pub trait ADIdDecodable: Sized {
205
+    fn decode(data: &[u8]) -> (Self, &[u8]);
206
+}
207
+
208
+pub struct ADIPayload(Vec<u8>);
209
+
210
+impl ADIPayload {
211
+    pub fn new(magic: u32) -> Self {
212
+        let mut vec = Vec::with_capacity(12);
213
+        vec.extend_from_slice(&u32::from(EncryptionType::Clear).to_be_bytes());
214
+        vec.extend_from_slice(&magic.to_be_bytes());
215
+        vec.extend_from_slice(&[0, 0, 0, 1]);
216
+        Self(vec)
217
+    }
218
+
219
+    pub fn push(mut self, encodable: impl ADIdEncodable) -> Self {
220
+        self.0.extend_from_slice(encodable.encode().as_ref());
221
+        self
222
+    }
223
+}
224
+
225
+impl Deref for ADIPayload {
226
+    type Target = [u8];
227
+
228
+    fn deref(&self) -> &Self::Target {
229
+        &self.0
230
+    }
231
+}
232
+
233
+macro_rules! impl_integer_traits {
234
+    ($t:ty) => {
235
+        impl ADIdEncodable for $t {
236
+            fn encode(&self) -> impl AsRef<[u8]> {
237
+                self.to_be_bytes()
238
+            }
239
+        }
240
+
241
+        impl ADIdDecodable for $t {
242
+            fn decode(data: &[u8]) -> (Self, &[u8]) {
243
+                let integer_size = mem::size_of::<Self>();
244
+                let (integer, data) = data.split_at(integer_size);
245
+                (Self::from_be_bytes(integer.try_into().unwrap()), data)
246
+            }
247
+        }
248
+    };
249
+}
250
+
251
+impl_integer_traits!(u8);
252
+impl_integer_traits!(u16);
253
+impl_integer_traits!(u32);
254
+impl_integer_traits!(u64);
255
+
256
+impl_integer_traits!(i8);
257
+impl_integer_traits!(i16);
258
+impl_integer_traits!(i32);
259
+impl_integer_traits!(i64);
260
+
261
+impl<T: ADIdEncodable> ADIdEncodable for &[T] {
262
+    fn encode(&self) -> impl AsRef<[u8]> {
263
+        let count = self.len();
264
+        let mut data: Vec<u8> = (count as u32).to_be_bytes().into();
265
+        if count >= 1 {
266
+            let ([elem], self2) = self.split_at(1) else {
267
+                unreachable!()
268
+            };
269
+
270
+            {
271
+                let elem = elem.encode();
272
+                let size = elem.as_ref().len();
273
+                data.reserve(size * count);
274
+                data.extend_from_slice(elem.as_ref());
275
+            }
276
+
277
+            for elem in self2 {
278
+                data.extend_from_slice(elem.encode().as_ref());
279
+            }
280
+        }
281
+        data
282
+    }
283
+}
284
+
285
+impl<T: ADIdEncodable> ADIdEncodable for Vec<T> {
286
+    fn encode(&self) -> impl AsRef<[u8]> {
287
+        let count = self.len();
288
+        let mut data: Vec<u8> = (count as u32).to_be_bytes().into();
289
+        if count >= 1 {
290
+            let ([elem], self2) = self.split_at(1) else {
291
+                unreachable!()
292
+            };
293
+
294
+            {
295
+                let elem = elem.encode();
296
+                let size = elem.as_ref().len();
297
+                data.reserve(size * count);
298
+                data.extend_from_slice(elem.as_ref());
299
+            }
300
+
301
+            for elem in self2 {
302
+                data.extend_from_slice(elem.encode().as_ref());
303
+            }
304
+        }
305
+        data
306
+    }
307
+}
308
+
309
+impl<T: ADIdDecodable> ADIdDecodable for Vec<T> {
310
+    fn decode(data: &[u8]) -> (Self, &[u8]) {
311
+        let (len, mut data) = data.split_at(mem::size_of::<u32>());
312
+        let length = u32::from_be_bytes(len.try_into().unwrap());
313
+        let mut vec = Vec::with_capacity(length as usize);
314
+        for _ in 0..length {
315
+            let (elem, remaining) = T::decode(data);
316
+            data = remaining;
317
+            vec.push(elem);
318
+        }
319
+        assert_eq!(vec.capacity(), length as usize);
320
+        (vec, data)
321
+    }
322
+}
323
+
324
+impl ADIdDecodable for ADIAccount {
325
+    fn decode(data: &[u8]) -> (Self, &[u8]) {
326
+        let (ds_id, data) = i64::decode(data);
327
+        let (mid_len, data) = u32::decode(data);
328
+        let (otp_len, data) = u32::decode(data);
329
+        let (mid, data) = data.split_at(mid_len as usize);
330
+        let (otp, data) = data.split_at(otp_len as usize);
331
+        (
332
+            ADIAccount {
333
+                ds_id,
334
+                mid: mid.to_vec(),
335
+                otp: otp.to_vec(),
336
+            },
337
+            data,
338
+        )
339
+    }
340
+}
341
+
342
+impl ADIdEncodable for &CStr {
343
+    fn encode(&self) -> impl AsRef<[u8]> {
344
+        self.to_bytes_with_nul()
345
+    }
346
+}
347
+
348
+impl ADIdEncodable for &str {
349
+    fn encode(&self) -> impl AsRef<[u8]> {
350
+        let mut vec = self.len().to_be_bytes().to_vec();
351
+        vec.extend_from_slice(self.as_bytes());
352
+        vec
353
+    }
354
+}
... ...
@@ -0,0 +1,143 @@
1
+#![allow(unused)]
2
+
3
+use block::RcBlock;
4
+use std::cmp::PartialEq;
5
+use std::ffi::CStr;
6
+use std::mem::MaybeUninit;
7
+use std::ops::Deref;
8
+use std::ptr::null_mut;
9
+use std::{mem, slice};
10
+use xpc_connection_sys::{
11
+    _xpc_dictionary_s, _xpc_type_s, dispatch_queue_t, xpc_connection_create_mach_service,
12
+    xpc_connection_resume, xpc_connection_send_message_with_reply_sync,
13
+    xpc_connection_set_event_handler, xpc_connection_t, xpc_data_create,
14
+    xpc_dictionary_create_empty, xpc_dictionary_get_data, xpc_dictionary_get_value,
15
+    xpc_dictionary_set_value, xpc_get_type, xpc_object_t, xpc_release, xpc_type_t,
16
+};
17
+
18
+pub struct XpcConnection(xpc_connection_t);
19
+
20
+impl XpcConnection {
21
+    pub fn create_mach_service(name: &CStr, targetq: Option<dispatch_queue_t>, flags: u64) -> Self {
22
+        unsafe {
23
+            XpcConnection(xpc_connection_create_mach_service(
24
+                name.as_ptr(),
25
+                targetq.unwrap_or(null_mut()),
26
+                flags,
27
+            ))
28
+        }
29
+    }
30
+
31
+    pub fn set_event_handler(&self, block: RcBlock<(XpcObject,), ()>) {
32
+        unsafe {
33
+            xpc_connection_set_event_handler(self.0, block.deref() as *const _ as *mut _);
34
+        }
35
+    }
36
+
37
+    pub fn resume(&self) {
38
+        unsafe { xpc_connection_resume(self.0) }
39
+    }
40
+
41
+    pub fn send_message_with_reply_sync(
42
+        &self,
43
+        message: &XpcDictionary,
44
+    ) -> Result<XpcDictionary, XpcError> {
45
+        unsafe {
46
+            let ret = XpcObject(xpc_connection_send_message_with_reply_sync(
47
+                self.0,
48
+                message.0.0,
49
+            ));
50
+            let typ = ret.get_type();
51
+            if typ == XPC_TYPE_ERROR {
52
+                return Err(XpcError(ret));
53
+            }
54
+            assert_eq!(typ, XPC_TYPE_DICTIONARY);
55
+            Ok(XpcDictionary(ret))
56
+        }
57
+    }
58
+}
59
+
60
+impl Drop for XpcConnection {
61
+    fn drop(&mut self) {
62
+        unsafe { xpc_release(self.0 as xpc_object_t) }
63
+    }
64
+}
65
+
66
+#[derive(Debug, PartialEq)]
67
+pub struct XpcType(xpc_type_t);
68
+
69
+const XPC_TYPE_DICTIONARY: XpcType =
70
+    XpcType(unsafe { (&xpc_connection_sys::_xpc_type_dictionary) as *const _xpc_type_s });
71
+
72
+const XPC_TYPE_ERROR: XpcType =
73
+    XpcType(unsafe { (&xpc_connection_sys::_xpc_type_error) as *const _xpc_type_s });
74
+
75
+pub struct XpcError(pub XpcObject);
76
+
77
+const XPC_ERROR_CONNECTION_INTERRUPTED: XpcError = XpcError(XpcObject(
78
+    (unsafe {
79
+        (&xpc_connection_sys::_xpc_error_connection_interrupted) as *const _xpc_dictionary_s
80
+    }) as xpc_object_t,
81
+));
82
+
83
+const XPC_ERROR_CONNECTION_INVALID: XpcError = XpcError(XpcObject(
84
+    (unsafe { (&xpc_connection_sys::_xpc_error_connection_invalid) as *const _xpc_dictionary_s })
85
+        as xpc_object_t,
86
+));
87
+
88
+pub struct XpcObject(xpc_object_t);
89
+
90
+impl XpcObject {
91
+    pub fn get_type(&self) -> XpcType {
92
+        XpcType(unsafe { xpc_get_type(self.0) })
93
+    }
94
+}
95
+
96
+impl Drop for XpcObject {
97
+    fn drop(&mut self) {
98
+        unsafe { xpc_release(self.0) }
99
+    }
100
+}
101
+
102
+pub struct XpcData(pub XpcObject);
103
+
104
+impl XpcData {
105
+    pub fn create(bytes: &[u8]) -> Self {
106
+        unsafe {
107
+            XpcData(XpcObject(xpc_data_create(
108
+                bytes.as_ptr() as _,
109
+                bytes.len() as _,
110
+            )))
111
+        }
112
+    }
113
+}
114
+
115
+pub struct XpcDictionary(pub XpcObject);
116
+
117
+impl XpcDictionary {
118
+    pub fn create_empty() -> Self {
119
+        unsafe { XpcDictionary(XpcObject(xpc_dictionary_create_empty())) }
120
+    }
121
+
122
+    pub fn set_value(&self, key: &CStr, value: XpcObject) {
123
+        unsafe {
124
+            let object = value.0;
125
+            mem::forget(value);
126
+            xpc_dictionary_set_value(self.0.0, key.as_ptr(), object);
127
+        }
128
+    }
129
+
130
+    pub fn get_value(&self, key: &CStr) -> XpcObject {
131
+        unsafe { XpcObject(xpc_dictionary_get_value(self.0.0, key.as_ptr())) }
132
+    }
133
+
134
+    pub fn get_data(&self, key: &CStr) -> &[u8] {
135
+        unsafe {
136
+            let mut length = MaybeUninit::uninit();
137
+            let data =
138
+                xpc_dictionary_get_data(self.0.0, key.as_ptr(), length.as_mut_ptr()) as *const u8;
139
+
140
+            slice::from_raw_parts(data, length.assume_init() as _)
141
+        }
142
+    }
143
+}
... ...
@@ -0,0 +1,11 @@
1
+[package]
2
+name = "android-coreadi"
3
+version = "0.1.0"
4
+edition = "2024"
5
+
6
+[dependencies]
7
+adi.workspace = true
8
+elf-loader.workspace = true
9
+ouroboros = "0.18.5"
10
+libc = "0.2.176"
11
+rand = "0.9"
... ...
@@ -0,0 +1,153 @@
1
+#[cfg(target_os = "linux")]
2
+mod linux;
3
+mod linux_libc;
4
+#[cfg(all(target_family = "unix", not(target_os = "linux")))]
5
+mod unix;
6
+#[cfg(target_os = "windows")]
7
+mod windows;
8
+
9
+#[cfg(target_os = "linux")]
10
+use crate::linux::*;
11
+#[cfg(all(target_family = "unix", not(target_os = "linux")))]
12
+use crate::unix::*;
13
+#[cfg(target_os = "windows")]
14
+use crate::windows::*;
15
+use adi::core_adi::{CoreADIADIProxy, CoreADIParameters, CoreADIProxy};
16
+use adi::proxy::ADIError;
17
+use elf_loader::elf_library::{Library, LibraryLoadingError, Symbol};
18
+use elf_loader::{linux_cc, linux_fn};
19
+use ouroboros::self_referencing;
20
+use rand::Rng;
21
+use std::collections::HashMap;
22
+use std::error::Error;
23
+use std::ffi::{c_char, c_void};
24
+use std::fmt::Display;
25
+use std::ops::Deref;
26
+
27
+#[linux_cc]
28
+fn android_arc4random() -> u32 {
29
+    rand::rng().random()
30
+}
31
+
32
+#[linux_cc]
33
+unsafe fn android_system_property_get(_name: *const char, value: *mut char) -> i32 {
34
+    println!("android system_property_get");
35
+    unsafe {
36
+        let string = value as *mut [c_char; 2];
37
+        *string = ['0' as c_char, '\0' as c_char];
38
+    }
39
+    1
40
+}
41
+
42
+#[self_referencing]
43
+struct _AndroidCoreADIProxy<T: Deref<Target = [u8]> + 'static> {
44
+    data: T,
45
+
46
+    #[borrows(data)]
47
+    #[covariant]
48
+    library: Library<'this>,
49
+
50
+    #[borrows(library)]
51
+    #[covariant]
52
+    dispatch_symbol: Symbol<'this, 'this, linux_fn! { fn(u32, *const CoreADIParameters) -> i32 }>,
53
+}
54
+
55
+pub struct AndroidCoreADIProxy<T: Deref<Target = [u8]> + 'static>(_AndroidCoreADIProxy<T>);
56
+
57
+#[derive(Debug)]
58
+pub enum AndroidCoreADILoadingError {
59
+    InvalidLibrary(LibraryLoadingError),
60
+    InvalidCoreADI,
61
+    ADIError(ADIError),
62
+}
63
+
64
+impl Display for AndroidCoreADILoadingError {
65
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66
+        match self {
67
+            AndroidCoreADILoadingError::InvalidLibrary(e) => {
68
+                write!(f, "Provided data is not a valid library: {e}")
69
+            }
70
+            AndroidCoreADILoadingError::InvalidCoreADI => {
71
+                write!(f, "Provided library is not a CoreADI library.")
72
+            }
73
+            AndroidCoreADILoadingError::ADIError(e) => {
74
+                write!(f, "Failed to initialize CoreADI: {e}")
75
+            }
76
+        }
77
+    }
78
+}
79
+
80
+impl Error for AndroidCoreADILoadingError {}
81
+
82
+impl<T: Deref<Target = [u8]>> AndroidCoreADIProxy<T> {
83
+    pub fn load_library(core_adi_data: T) -> Result<Self, AndroidCoreADILoadingError> {
84
+        let mut hooks = HashMap::new();
85
+        hooks.insert("arc4random", android_arc4random as *const c_void);
86
+        hooks.insert("chmod", chmod as *const c_void);
87
+        hooks.insert("close", close as *const c_void);
88
+        hooks.insert("free", free as *const c_void);
89
+        hooks.insert("fstat", fstat as *const c_void);
90
+        hooks.insert("ftruncate", ftruncate as *const c_void);
91
+        hooks.insert("gettimeofday", gettimeofday as *const c_void);
92
+        hooks.insert("lstat", lstat as *const c_void);
93
+        hooks.insert("malloc", malloc as *const c_void);
94
+        hooks.insert("mkdir", mkdir as *const c_void);
95
+        hooks.insert("open", open as *const c_void);
96
+        hooks.insert("read", read as *const c_void);
97
+        hooks.insert("strncpy", strncpy as *const c_void);
98
+        hooks.insert("umask", umask as *const c_void);
99
+        hooks.insert("write", write as *const c_void);
100
+        hooks.insert(
101
+            "__system_property_get",
102
+            android_system_property_get as *const c_void,
103
+        );
104
+        hooks.insert("__errno", errno as *const c_void);
105
+        hooks.insert("__errno_location", errno as *const c_void);
106
+
107
+        // TODO: implement PThread functions
108
+        hooks.insert("pthread_rwlock_destroy", nil_fn as *const c_void);
109
+        hooks.insert("pthread_rwlock_init", nil_fn as *const c_void);
110
+        hooks.insert("pthread_rwlock_rdlock", nil_fn as *const c_void);
111
+        hooks.insert("pthread_rwlock_unlock", nil_fn as *const c_void);
112
+        hooks.insert("pthread_rwlock_wrlock", nil_fn as *const c_void);
113
+
114
+        let core_adi = AndroidCoreADIProxy(
115
+            _AndroidCoreADIProxyTryBuilder {
116
+                data: core_adi_data,
117
+                library_builder: |data| {
118
+                    Library::load(data, |sym| hooks.get(sym).copied())
119
+                        .map_err(AndroidCoreADILoadingError::InvalidLibrary)
120
+                },
121
+                dispatch_symbol_builder: |library| {
122
+                    library
123
+                        .get("vdfut768ig")
124
+                        .ok_or(AndroidCoreADILoadingError::InvalidCoreADI)
125
+                },
126
+            }
127
+            .try_build()?,
128
+        );
129
+
130
+        core_adi
131
+            .initialize()
132
+            .map_err(AndroidCoreADILoadingError::ADIError)?;
133
+
134
+        Ok(core_adi)
135
+    }
136
+}
137
+
138
+impl<T: Deref<Target = [u8]>> Drop for AndroidCoreADIProxy<T> {
139
+    fn drop(&mut self) {
140
+        let _ = self.finalize();
141
+    }
142
+}
143
+
144
+impl<T: Deref<Target = [u8]>> CoreADIProxy for AndroidCoreADIProxy<T> {
145
+    unsafe fn dispatch(&self, function_code: u32, parameters: *const CoreADIParameters) -> i32 {
146
+        (self.0.borrow_dispatch_symbol().ptr)(function_code, parameters)
147
+    }
148
+}
149
+
150
+#[linux_cc]
151
+unsafe fn nil_fn() -> i32 {
152
+    0
153
+}
... ...
@@ -0,0 +1,10 @@
1
+use elf_loader::linux_cc;
2
+pub use libc::{
3
+    chmod, close, free, fstat, ftruncate, gettimeofday, lstat, malloc, mkdir, open, read, strncpy,
4
+    umask, write,
5
+};
6
+
7
+#[linux_cc]
8
+pub unsafe fn errno() -> *mut libc::c_int {
9
+    unsafe { libc::__errno_location() }
10
+}
... ...
@@ -0,0 +1,99 @@
1
+#![allow(non_camel_case_types)]
2
+
3
+#[cfg(target_pointer_width = "32")]
4
+#[repr(C)]
5
+pub struct stat {
6
+    pub st_dev: libc::c_ulonglong,
7
+    pub __pad0: [libc::c_uchar; 4],
8
+    pub __st_ino: ino_t,
9
+    pub st_mode: libc::c_uint,
10
+    pub st_nlink: nlink_t,
11
+    pub st_uid: uid_t,
12
+    pub st_gid: gid_t,
13
+    pub st_rdev: libc::c_ulonglong,
14
+    pub __pad3: [libc::c_uchar; 4],
15
+    pub st_size: libc::c_longlong,
16
+    pub st_blksize: blksize_t,
17
+    pub st_blocks: libc::c_ulonglong,
18
+    pub st_atime: libc::c_long,
19
+    pub st_atime_nsec: libc::c_long,
20
+    pub st_mtime: libc::c_long,
21
+    pub st_mtime_nsec: libc::c_long,
22
+    pub st_ctime: libc::c_long,
23
+    pub st_ctime_nsec: libc::c_long,
24
+    pub st_ino: libc::c_ulonglong,
25
+}
26
+
27
+#[cfg(target_arch = "aarch64")]
28
+#[repr(C)]
29
+pub struct stat {
30
+    pub st_dev: dev_t,
31
+    pub st_ino: ino_t,
32
+    pub st_mode: libc::c_uint,
33
+    pub st_nlink: nlink_t,
34
+    pub st_uid: uid_t,
35
+    pub st_gid: gid_t,
36
+    pub st_rdev: dev_t,
37
+    pub __pad1: libc::c_ulong,
38
+    pub st_size: off64_t,
39
+    pub st_blksize: libc::c_int,
40
+    pub __pad2: libc::c_int,
41
+    pub st_blocks: libc::c_long,
42
+    pub st_atime: time_t,
43
+    pub st_atime_nsec: libc::c_long,
44
+    pub st_mtime: time_t,
45
+    pub st_mtime_nsec: libc::c_long,
46
+    pub st_ctime: time_t,
47
+    pub st_ctime_nsec: libc::c_long,
48
+    pub __unused4: libc::c_uint,
49
+    pub __unused5: libc::c_uint,
50
+}
51
+
52
+#[cfg(target_arch = "x86_64")]
53
+#[repr(C)]
54
+pub struct stat {
55
+    pub st_dev: dev_t,
56
+    pub st_ino: ino_t,
57
+    pub st_nlink: libc::c_ulong,
58
+    pub st_mode: libc::c_uint,
59
+    pub st_uid: uid_t,
60
+    pub st_gid: gid_t,
61
+    pub st_rdev: dev_t,
62
+    pub st_size: off64_t,
63
+    pub st_blksize: libc::c_long,
64
+    pub st_blocks: libc::c_long,
65
+    pub st_atime: libc::c_long,
66
+    pub st_atime_nsec: libc::c_long,
67
+    pub st_mtime: libc::c_long,
68
+    pub st_mtime_nsec: libc::c_long,
69
+    pub st_ctime: libc::c_long,
70
+    pub st_ctime_nsec: libc::c_long,
71
+    pub __unused: [libc::c_long; 3],
72
+}
73
+
74
+pub const O_RDONLY: libc::c_int = 0;
75
+pub const O_WRONLY: libc::c_int = 1;
76
+pub const O_RDWR: libc::c_int = 2;
77
+
78
+pub const O_CREAT: libc::c_int = 64;
79
+
80
+#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
81
+pub const O_NOFOLLOW: libc::c_int = 0x20000;
82
+#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
83
+pub const O_NOFOLLOW: libc::c_int = 0x8000;
84
+
85
+pub type dev_t = libc::c_ulong;
86
+pub type ino_t = libc::c_ulong;
87
+pub type nlink_t = u32;
88
+pub type uid_t = u32;
89
+pub type gid_t = u32;
90
+
91
+#[cfg(target_pointer_width = "32")]
92
+pub type off64_t = libc::c_longlong;
93
+#[cfg(target_pointer_width = "64")]
94
+pub type off64_t = i64;
95
+
96
+#[cfg(target_pointer_width = "32")]
97
+pub type mode_t = u16;
98
+
99
+pub type time_t = libc::c_long;
... ...
@@ -0,0 +1,77 @@
1
+#![allow(unsafe_op_in_unsafe_fn)]
2
+
3
+use crate::linux_libc::*;
4
+use elf_loader::linux_cc;
5
+pub use libc::{
6
+    chmod, close, free, ftruncate, gettimeofday, malloc, mkdir, read, strncpy, umask, write,
7
+};
8
+use std::mem;
9
+
10
+#[linux_cc]
11
+pub unsafe fn errno() -> *mut libc::c_int {
12
+    // HACK we should also translate the errnos, but eh it works fine now
13
+    libc::__error()
14
+}
15
+
16
+#[inline]
17
+unsafe fn local_stat_to_linux(buf: libc::stat) -> stat {
18
+    stat {
19
+        st_dev: buf.st_dev as _,
20
+        st_ino: buf.st_ino as _,
21
+        st_nlink: buf.st_nlink as _,
22
+        st_mode: buf.st_mode as _,
23
+        st_uid: buf.st_uid as _,
24
+        st_gid: buf.st_gid as _,
25
+        st_rdev: buf.st_rdev as _,
26
+        st_size: buf.st_size as _,
27
+        st_blksize: buf.st_blksize as _,
28
+        st_blocks: buf.st_blocks as _,
29
+        st_atime: buf.st_atime as _,
30
+        st_atime_nsec: buf.st_atime_nsec as _,
31
+        st_mtime: buf.st_mtime as _,
32
+        st_mtime_nsec: buf.st_mtime_nsec as _,
33
+        st_ctime: buf.st_ctime as _,
34
+        st_ctime_nsec: buf.st_ctime_nsec as _,
35
+        ..mem::zeroed()
36
+    }
37
+}
38
+
39
+#[linux_cc]
40
+pub unsafe fn lstat(path: *const libc::c_char, buf: *mut stat) -> libc::c_int {
41
+    let mut local_buf = mem::zeroed();
42
+    let return_code = libc::lstat(path, &mut local_buf);
43
+    *buf = local_stat_to_linux(local_buf);
44
+    return_code
45
+}
46
+
47
+#[linux_cc]
48
+pub unsafe fn fstat(fildes: libc::c_int, buf: *mut stat) -> libc::c_int {
49
+    let mut local_buf = mem::zeroed();
50
+    let return_code = libc::fstat(fildes, &mut local_buf);
51
+    *buf = local_stat_to_linux(local_buf);
52
+    return_code
53
+}
54
+
55
+#[linux_cc]
56
+pub unsafe extern "C" fn open(path: *const libc::c_char, oflag: libc::c_int) -> libc::c_int {
57
+    let mut local_flag = 0;
58
+
59
+    if oflag & 0b11 == O_WRONLY {
60
+        local_flag = libc::O_RDWR;
61
+    }
62
+    if oflag & 0b11 == O_RDWR {
63
+        local_flag = libc::O_RDWR;
64
+    }
65
+    if oflag & 0b11 == O_RDONLY {
66
+        local_flag = libc::O_RDWR;
67
+    }
68
+
69
+    if oflag & O_CREAT != 0 {
70
+        local_flag |= libc::O_CREAT;
71
+    }
72
+    if oflag & O_NOFOLLOW != 0 {
73
+        local_flag |= libc::O_NOFOLLOW;
74
+    }
75
+
76
+    libc::open(path, local_flag, 0o777)
77
+}
... ...
@@ -0,0 +1,6 @@
1
+pub use libc::{
2
+    chmod, close, free, fstat, ftruncate, gettimeofday, lstat, malloc, mkdir, open, read, strncpy,
3
+    umask, write,
4
+};
5
+
6
+todo!();
... ...
@@ -0,0 +1,30 @@
1
+[package]
2
+name = "apple-account"
3
+version = "0.1.0"
4
+edition = "2024"
5
+
6
+[dependencies]
7
+adi.workspace = true
8
+plist.workspace = true
9
+plist-macros.workspace = true
10
+
11
+reqwest.workspace = true
12
+
13
+aes.workspace = true
14
+aes-gcm.workspace = true
15
+cbc.workspace = true
16
+hmac.workspace = true
17
+pbkdf2.workspace = true
18
+sha2.workspace = true
19
+
20
+base64 = "0.22.1"
21
+serde = { version = "1.0.228", features = ["derive"] }
22
+chrono = "0.4.42"
23
+iana-time-zone = "0.1.64"
24
+sys-locale = "0.3.2"
25
+srp = { git = "https://github.com/RustCrypto/PAKEs" }
26
+# srp = "0.7"
27
+rand = "0.9.2"
28
+hex = "0.4.3"
29
+bytes = "1.10.1"
30
+log = "0.4.29"
... ...
@@ -0,0 +1,9 @@
1
+# apple-account
2
+
3
+A library reimplementing `grandslam` and `itunes` endpoints.
4
+
5
+`grandslam` is modeled mostly around concepts from AuthKitWin, 
6
+StoreServicesCore and AppleMediaServices.
7
+
8
+`itunes` is modeled after some personal reversing of iTunes, and 
9
+the code of [ipatool](https://github.com/majd/ipatool).
... ...
@@ -0,0 +1,26 @@
1
+pub struct BundleInformation<'lt> {
2
+    pub bundle_name: &'lt str,
3
+    pub bundle_identifier: &'lt str,
4
+    pub bundle_version: &'lt str,
5
+}
6
+
7
+/// AuthKit from macOS 15.6.1
8
+pub const AUTH_KIT_BUNDLE_INFORMATION: BundleInformation = BundleInformation {
9
+    bundle_name: "AuthKit",
10
+    bundle_identifier: "com.apple.AuthKit",
11
+    bundle_version: "1",
12
+};
13
+
14
+/// Xcode 16.4
15
+pub const XCODE_BUNDLE_INFORMATION: BundleInformation = BundleInformation {
16
+    bundle_name: "Xcode",
17
+    bundle_identifier: "com.apple.dt.Xcode",
18
+    bundle_version: "23792",
19
+};
20
+
21
+/// Apple TV 1.5.6 (macOS Sequoia 15.7.3)
22
+pub const APPLE_TV_BUNDLE_INFORMATION: BundleInformation = BundleInformation {
23
+    bundle_name: "TV",
24
+    bundle_identifier: "com.apple.TV",
25
+    bundle_version: "1.5.6",
26
+};
... ...
@@ -0,0 +1,26 @@
1
+use crate::bundle_information::BundleInformation;
2
+
3
+#[derive(Clone)]
4
+pub struct Device {
5
+    pub device_model: String,
6
+    pub operating_system_information: String,
7
+    pub device_uuid: String,
8
+}
9
+
10
+impl Device {
11
+    pub fn server_friendly_description(
12
+        &self,
13
+        authentication_framework: &BundleInformation,
14
+        application_information: &BundleInformation,
15
+    ) -> String {
16
+        format!(
17
+            "<{}> <{}> <{}/{} ({}/{})>",
18
+            self.device_model,
19
+            self.operating_system_information,
20
+            authentication_framework.bundle_name,
21
+            authentication_framework.bundle_version,
22
+            application_information.bundle_name,
23
+            application_information.bundle_version,
24
+        )
25
+    }
26
+}
... ...
@@ -0,0 +1,816 @@
1
+mod anisette;
2
+mod post_data;
3
+mod secondary_actions;
4
+mod url_switch;
5
+
6
+use crate::bundle_information::BundleInformation;
7
+use crate::device::Device;
8
+use crate::grandslam::AuthOutcome::AnisetteResyncRequired;
9
+use crate::http_session::{
10
+    AnisetteHTTPSession, AppleError, BasicHTTPSession, HTTPSession, HTTPSessionCreationError,
11
+    URLBagError, parse_status,
12
+};
13
+use adi::proxy::{ADIError, ADIResult};
14
+use aes::Aes256;
15
+use aes::cipher::block_padding;
16
+use aes::cipher::block_padding::Pkcs7;
17
+use aes_gcm::AesGcm;
18
+use aes_gcm::aead::consts::U16;
19
+use aes_gcm::aead::{Aead, Payload};
20
+pub use anisette::*;
21
+use base64::Engine;
22
+use base64::prelude::BASE64_STANDARD;
23
+use bytes::Bytes;
24
+use cbc::cipher::{BlockModeDecrypt, KeyIvInit};
25
+use chrono::{Local, SecondsFormat};
26
+use hmac::{Hmac, KeyInit, Mac};
27
+use log::trace;
28
+use plist::{Dictionary, Value};
29
+use plist_macros::{array, dict};
30
+pub use post_data::*;
31
+use reqwest::{Certificate, Method, RequestBuilder};
32
+use serde::Deserialize;
33
+use sha2::{Digest, Sha256};
34
+use srp::client::SrpClient;
35
+use srp::groups::G_2048;
36
+use srp::types::SrpAuthError;
37
+use std::fmt::{Display, Formatter};
38
+pub use url_switch::*;
39
+
40
+const ROOT_CA: &[u8] = include_bytes!("grandslam/root-ca.pem");
41
+
42
+/// Build an HTTP session for interacting with grandslam endpoints.
43
+/// It will connect to the default production servers, and identifies itself as the application
44
+/// described in `client_bundle_info` running on the device `device`.
45
+///
46
+/// # Arguments
47
+///
48
+/// * `device`: device information sent to Apple
49
+/// * `client_bundle_info`: application information sent to Apple
50
+///
51
+/// returns: Result<HTTPSession, HTTPSessionCreationError>
52
+///
53
+/// # Examples
54
+///
55
+/// ```
56
+/// let device = Device {
57
+///     device_model: "MacBookPro13,2".to_string(),
58
+///     operating_system_information: "macOS;15.6.1;24G90".to_string(),
59
+///     device_uuid: "A8B31C86-359B-4D95-8950-BA5DD8FFC46F".to_string(),
60
+/// };
61
+///
62
+/// let grandslam_http_session = grandslam::http_session(device, XCODE_BUNDLE_INFORMATION).await?;
63
+/// ```
64
+pub async fn http_session(
65
+    device: Device,
66
+    client_bundle_info: BundleInformation<'_>,
67
+) -> Result<HTTPSession<'_>, HTTPSessionCreationError> {
68
+    http_session_with_idms_env(device, client_bundle_info, 0).await
69
+}
70
+
71
+pub fn bag_url(idms_env: usize) -> &'static str {
72
+    const URL_FOR_IDMS_ENV: [&str; 4] = [
73
+        "https://gsa.apple.com/grandslam/GsService2/lookup",
74
+        // the other urls seem to be internal Apple servers.
75
+        "https://grandslam-uat.apple.com/grandslam/GsService2/lookup",
76
+        "https://grandslam-it.apple.com/grandslam/GsService2/lookup",
77
+        "https://grandslam-it3.apple.com/grandslam/GsService2/lookup",
78
+    ];
79
+
80
+    URL_FOR_IDMS_ENV[idms_env]
81
+}
82
+
83
+pub async fn http_session_with_idms_env(
84
+    device: Device,
85
+    client_bundle_info: BundleInformation<'_>,
86
+    idms_env: usize,
87
+) -> Result<HTTPSession<'_>, HTTPSessionCreationError> {
88
+    http_session_with_custom_bag_url(device, client_bundle_info, bag_url(idms_env)).await
89
+}
90
+
91
+pub(crate) fn parse_url_bag_response(url_bag_response: Bytes) -> Result<Dictionary, URLBagError> {
92
+    let url_bag_plist = plist::from_bytes::<Dictionary>(&url_bag_response)
93
+        .map_err(|_| URLBagError::Parsing)?
94
+        .get("urls")
95
+        .and_then(Value::as_dictionary)
96
+        .cloned()
97
+        .ok_or(URLBagError::InvalidUrlBag)?;
98
+
99
+    Ok(url_bag_plist)
100
+}
101
+
102
+pub async fn http_session_with_custom_bag_url<'lt>(
103
+    device: Device,
104
+    client_bundle_info: BundleInformation<'lt>,
105
+    url: &str,
106
+) -> Result<HTTPSession<'lt>, HTTPSessionCreationError> {
107
+    let http_session = BasicHTTPSession::new(
108
+        device,
109
+        client_bundle_info,
110
+        Some(Certificate::from_pem(ROOT_CA).expect("the bundled certificate is not valid??")),
111
+    )?;
112
+
113
+    let url_bag_response = http_session
114
+        .request_builder(Method::GET, url)
115
+        .send()
116
+        .await
117
+        .map_err(HTTPSessionCreationError::Reqwest)?
118
+        .error_for_status()
119
+        .map_err(HTTPSessionCreationError::Reqwest)?
120
+        .bytes()
121
+        .await
122
+        .map_err(HTTPSessionCreationError::Reqwest)?;
123
+
124
+    let url_bag = parse_url_bag_response(url_bag_response)
125
+        .map_err(|_| HTTPSessionCreationError::InvalidURLBagResponseStructure)?;
126
+
127
+    HTTPSession::new(http_session, url_bag)
128
+}
129
+
130
+pub struct Token<'lt, 'lt2, 'adi> {
131
+    http_session: &'lt AnisetteHTTPSession<'lt2, 'adi>,
132
+    alt_dsid: String,
133
+    token: String,
134
+}
135
+
136
+#[derive(Debug)]
137
+pub enum TokenError {
138
+    Expired,
139
+    ADI(ADIError),
140
+}
141
+
142
+impl Display for TokenError {
143
+    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
144
+        match self {
145
+            TokenError::Expired => {
146
+                write!(f, "The session has expired.")
147
+            }
148
+            TokenError::ADI(error) => error.fmt(f),
149
+        }
150
+    }
151
+}
152
+
153
+impl std::error::Error for TokenError {}
154
+
155
+impl<'lt, 'lt2, 'adi> Token<'lt, 'lt2, 'adi> {
156
+    pub fn new(
157
+        http_session: &'lt AnisetteHTTPSession<'lt2, 'adi>,
158
+        alt_dsid: String,
159
+        token: String,
160
+    ) -> Result<Self, TokenError> {
161
+        // TODO check the validity of the token.
162
+        Ok(Self {
163
+            http_session,
164
+            alt_dsid,
165
+            token,
166
+        })
167
+    }
168
+
169
+    pub fn authenticated_request_builder(
170
+        &self,
171
+        method: Method,
172
+        url: &str,
173
+    ) -> Result<RequestBuilder, TokenError> {
174
+        Ok(self
175
+            .http_session
176
+            .anisette_request_builder(GRANDSLAM_DSID, method, url)
177
+            .map_err(TokenError::ADI)?
178
+            .header("X-Apple-I-Identity-Id", &self.alt_dsid)
179
+            .header("X-Apple-GS-Token", &self.token))
180
+    }
181
+}
182
+#[derive(Debug)]
183
+pub enum AuthOutcome {
184
+    Success(Dictionary),
185
+    SecondaryActionRequired(Dictionary, String),
186
+    AnisetteResyncRequired(Vec<u8>),
187
+    AnisetteReprovisionRequired,
188
+    UrlSwitchingRequired(String),
189
+}
190
+
191
+#[derive(Debug)]
192
+pub enum AuthError {
193
+    InvalidURLBag,
194
+    Apple(AppleError),
195
+    Anisette(ADIError),
196
+    Network(reqwest::Error),
197
+    Parsing(u8, plist::Error),
198
+    Structure(Dictionary),
199
+    SRP(SrpAuthError),
200
+    UnknownProtocol(String),
201
+    Decryption(block_padding::Error),
202
+}
203
+
204
+/*
205
+impl From<SrpAuthError> for AuthError {
206
+    fn from(error: SrpAuthError) -> Self {
207
+        AuthError::SRP(error)
208
+    }
209
+}
210
+
211
+impl From<reqwest::Error> for AuthError {
212
+    fn from(error: reqwest::Error) -> Self {
213
+        Self::Network(error)
214
+    }
215
+}
216
+
217
+impl From<ADIError> for AuthError {
218
+    fn from(err: ADIError) -> AuthError {
219
+        AuthError::Anisette(err)
220
+    }
221
+}
222
+
223
+impl From<AppleError> for AuthError {
224
+    fn from(err: AppleError) -> AuthError {
225
+        AuthError::Apple(err)
226
+    }
227
+} // */
228
+
229
+impl Display for AuthError {
230
+    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
231
+        match self {
232
+            AuthError::InvalidURLBag => {
233
+                write!(f, "Invalid URL bag")
234
+            }
235
+            AuthError::Apple(err) => {
236
+                write!(f, "Could not log-in to Apple servers: {err}")
237
+            }
238
+            AuthError::Anisette(err) => {
239
+                write!(f, "Cannot generate device authentication data: {err}")
240
+            }
241
+            AuthError::Network(err) => {
242
+                write!(f, "Network error: {err}")
243
+            }
244
+            AuthError::Parsing(step, err) => {
245
+                write!(f, "Cannot parse server response from step {step}: {err}")
246
+            }
247
+            AuthError::Structure(dict) => {
248
+                write!(
249
+                    f,
250
+                    "Invalid server response structure (censor private data before reporting): {dict:?}"
251
+                )
252
+            }
253
+            AuthError::SRP(error) => {
254
+                write!(f, "Authentication protocol failure: {error}")
255
+            }
256
+            AuthError::UnknownProtocol(protocol) => {
257
+                write!(f, "Unknown server protocol: {protocol}")
258
+            }
259
+            AuthError::Decryption(block_padding) => {
260
+                write!(f, "Decryption error: {block_padding}")
261
+            }
262
+        }
263
+    }
264
+}
265
+
266
+impl std::error::Error for AuthError {}
267
+
268
+pub type AuthResult = Result<AuthOutcome, AuthError>;
269
+
270
+pub fn build_client_provided_data(
271
+    http_session: &AnisetteHTTPSession<'_, '_>,
272
+) -> ADIResult<Dictionary> {
273
+    let adi_proxy = http_session.adi_proxy();
274
+    let device = http_session.device();
275
+    let application_information = http_session.application_information();
276
+
277
+    let client_time = Local::now()
278
+        .to_utc()
279
+        .to_rfc3339_opts(SecondsFormat::Secs, true);
280
+
281
+    let timezone = iana_time_zone::get_timezone().unwrap_or_else(|_| "UTC".to_string());
282
+    let locale = sys_locale::get_locale()
283
+        .unwrap_or_else(|| String::from("en-US"))
284
+        .replace('-', "_");
285
+
286
+    let routing_info = adi_proxy.get_idms_routing(GRANDSLAM_DSID)?;
287
+
288
+    let (mid, otp) = {
289
+        let (mid_b, otp_b) = adi_proxy.request_otp(GRANDSLAM_DSID)?;
290
+
291
+        let mid = BASE64_STANDARD.encode(mid_b);
292
+        let otp = BASE64_STANDARD.encode(otp_b);
293
+
294
+        (mid, otp)
295
+    };
296
+
297
+    let client_provided_data = dict! {
298
+        "X-Apple-I-Client-Time": client_time,
299
+        "X-Apple-I-TimeZone": timezone,
300
+        "X-Apple-Locale": locale.clone(),
301
+
302
+        "X-Apple-I-MD": otp,
303
+        "X-Apple-I-MD-M": mid,
304
+        "X-Apple-I-MD-RINFO": routing_info.to_string(),
305
+
306
+        "X-Mme-Device-Id": device.device_uuid.clone(),
307
+
308
+        "bootstrap": true,
309
+        "capp": application_information.bundle_name,
310
+        "ckgen": true,
311
+        "icscrec": true,
312
+        "loc": locale,
313
+        "pbe": false,
314
+        "prkgen": true,
315
+        "svct": "iCloud",
316
+    };
317
+
318
+    Ok(client_provided_data)
319
+}
320
+
321
+#[repr(u64)]
322
+enum StatusCode {
323
+    Success = 0,
324
+    SecondaryActionRequired = 409,
325
+    AnisetteReprovisionRequired = 433,
326
+    AnisetteResyncRequired = 434,
327
+    UrlSwitchingRequired = 435,
328
+}
329
+
330
+impl TryFrom<u64> for StatusCode {
331
+    type Error = ();
332
+
333
+    fn try_from(v: u64) -> Result<Self, Self::Error> {
334
+        match v {
335
+            x if x == Self::Success as u64 => Ok(Self::Success),
336
+            x if x == Self::SecondaryActionRequired as u64 => Ok(Self::SecondaryActionRequired),
337
+            x if x == Self::AnisetteReprovisionRequired as u64 => {
338
+                Ok(Self::AnisetteReprovisionRequired)
339
+            }
340
+            x if x == Self::AnisetteResyncRequired as u64 => Ok(Self::AnisetteResyncRequired),
341
+            x if x == Self::UrlSwitchingRequired as u64 => Ok(Self::UrlSwitchingRequired),
342
+            _ => Err(()),
343
+        }
344
+    }
345
+}
346
+
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
+pub async fn login(
366
+    http_session: &AnisetteHTTPSession<'_, '_>,
367
+    apple_id: &str,
368
+    password: &str,
369
+) -> AuthResult {
370
+    let gs_service_url = http_session
371
+        .url_bag()
372
+        .get("gsService")
373
+        .and_then(Value::as_string)
374
+        .ok_or(AuthError::InvalidURLBag)?;
375
+
376
+    let cpd = build_client_provided_data(http_session).map_err(AuthError::Anisette)?;
377
+
378
+    let srp_client = SrpClient::<Sha256>::new_with_options(&G_2048, true);
379
+    let a: [u8; 256] = rand::random();
380
+    let a_pub = srp_client.compute_public_ephemeral(&a);
381
+
382
+    let request_plist = dict! {
383
+        "Header": dict!{
384
+            "Version": "1.0.1"
385
+        },
386
+        "Request": dict!{
387
+            "A2k": Value::Data(a_pub),
388
+            "cpd": cpd,
389
+            "o": "init",
390
+            "ps": array![
391
+                "s2k",
392
+                "s2k_fo" // most Apple servers seem to not even implement that protocol anymore.
393
+            ],
394
+            "u": apple_id
395
+        }
396
+    };
397
+
398
+    // TODO: make a function to easily send plist.
399
+    let mut request_body = Vec::new();
400
+    plist::to_writer_xml(&mut request_body, &request_plist).unwrap();
401
+
402
+    let response = http_session
403
+        .anisette_request_builder(GRANDSLAM_DSID, Method::POST, gs_service_url)
404
+        .map_err(AuthError::Anisette)?
405
+        .body(request_body)
406
+        .send()
407
+        .await
408
+        .map_err(AuthError::Network)?
409
+        .bytes()
410
+        .await
411
+        .map_err(AuthError::Network)?;
412
+
413
+    let response_plist: Dictionary =
414
+        plist::from_bytes(&response).map_err(|err| AuthError::Parsing(1, err))?;
415
+
416
+    let response_dict = response_plist
417
+        .get("Response")
418
+        .and_then(|response| response.as_dictionary())
419
+        .ok_or(AuthError::Structure(response_plist.clone()))?;
420
+
421
+    let status = response_dict
422
+        .get("Status")
423
+        .and_then(|status| status.as_dictionary())
424
+        .ok_or(AuthError::Structure(response_plist.clone()))?;
425
+
426
+    parse_status(status).map_err(AuthError::Apple)?;
427
+
428
+    let iteration_count = response_dict
429
+        .get("i")
430
+        .and_then(|iteration_count| iteration_count.as_unsigned_integer())
431
+        .ok_or(AuthError::Structure(response_plist.clone()))?;
432
+
433
+    let salt = response_dict
434
+        .get("s")
435
+        .and_then(|salt| salt.as_data())
436
+        .ok_or(AuthError::Structure(response_plist.clone()))?;
437
+
438
+    let selected_protocol = response_dict
439
+        .get("sp")
440
+        .and_then(|selected_protocol| selected_protocol.as_string())
441
+        .ok_or(AuthError::Structure(response_plist.clone()))?;
442
+
443
+    let cookie = response_dict
444
+        .get("c")
445
+        .and_then(|cookie| cookie.as_string())
446
+        .ok_or(AuthError::Structure(response_plist.clone()))?;
447
+
448
+    let b = response_dict
449
+        .get("B")
450
+        .and_then(|b| b.as_data())
451
+        .ok_or(AuthError::Structure(response_plist.clone()))?;
452
+
453
+    let hashed_password: Vec<u8> = match selected_protocol {
454
+        "s2k" => Sha256::digest(password.as_bytes()).to_vec(),
455
+        "s2k_fo" => hex::encode(Sha256::digest(password.as_bytes())).into_bytes(),
456
+        _ => {
457
+            return Err(AuthError::UnknownProtocol(selected_protocol.into()));
458
+        }
459
+    };
460
+
461
+    let processed_password = {
462
+        let mut buf = [0u8; 32];
463
+        pbkdf2::pbkdf2::<Hmac<Sha256>>(&hashed_password, salt, iteration_count as u32, &mut buf)
464
+            .expect("the length is wrong??");
465
+        buf
466
+    };
467
+
468
+    let verifier = srp_client
469
+        .process_reply_rfc5054(&a, apple_id.as_bytes(), &processed_password, salt, b)
470
+        .map_err(AuthError::SRP)?;
471
+
472
+    let cpd = build_client_provided_data(http_session).map_err(AuthError::Anisette)?;
473
+
474
+    let request_plist = dict! {
475
+        "Header": dict!{
476
+            "Version": "1.0.1"
477
+        },
478
+        "Request": dict!{
479
+            "M1": Value::Data(verifier.proof().to_vec()),
480
+            "c": cookie,
481
+            "cpd": cpd,
482
+            "o": "complete",
483
+            "u": apple_id
484
+        }
485
+    };
486
+
487
+    let mut request_body = Vec::new();
488
+    plist::to_writer_xml(&mut request_body, &request_plist).unwrap();
489
+
490
+    let response = http_session
491
+        .anisette_request_builder(GRANDSLAM_DSID, Method::POST, gs_service_url)
492
+        .map_err(AuthError::Anisette)?
493
+        .body(request_body)
494
+        .send()
495
+        .await
496
+        .map_err(AuthError::Network)?
497
+        .bytes()
498
+        .await
499
+        .map_err(AuthError::Network)?;
500
+
501
+    let response_plist: Dictionary =
502
+        plist::from_bytes(&response).map_err(|err| AuthError::Parsing(2, err))?;
503
+
504
+    let response_dict = response_plist
505
+        .get("Response")
506
+        .and_then(|response| response.as_dictionary())
507
+        .ok_or(AuthError::Structure(response_plist.clone()))?;
508
+
509
+    // println!("Response: {response_dict:?}");
510
+
511
+    let status = response_dict
512
+        .get("Status")
513
+        .and_then(|status| status.as_dictionary())
514
+        .ok_or(AuthError::Structure(response_plist.clone()))?;
515
+
516
+    parse_status(status).map_err(AuthError::Apple)?;
517
+
518
+    let status_code: StatusCode = status
519
+        .get("hsc")
520
+        .and_then(|status_code| status_code.as_unsigned_integer())
521
+        .unwrap_or(0)
522
+        .try_into()
523
+        .map_err(|_| AuthError::Structure(response_plist.clone()))?;
524
+
525
+    let server_provided_data = response_dict
526
+        .get("spd")
527
+        .and_then(|server_provided_data| server_provided_data.as_data())
528
+        .map(|server_provided_data| {
529
+            let server_reply = response_dict
530
+                .get("M2")
531
+                .and_then(|server_reply| server_reply.as_data())
532
+                .ok_or(AuthError::Structure(response_plist.clone()))?;
533
+
534
+            verifier
535
+                .verify_server(server_reply)
536
+                .map_err(AuthError::SRP)?;
537
+
538
+            // The session is now verified, let's grab those tokens!
539
+            let session_key = verifier.key();
540
+
541
+            // The session key here is of a known length, we know those can't fail.
542
+            let extra_data_key = Hmac::<Sha256>::new_from_slice(session_key)
543
+                .expect("the length is wrong??")
544
+                .chain_update("extra data key:")
545
+                .finalize()
546
+                .into_bytes();
547
+
548
+            let extra_data_iv = Hmac::<Sha256>::new_from_slice(session_key)
549
+                .expect("the length is wrong??")
550
+                .chain_update("extra data iv:")
551
+                .finalize()
552
+                .into_bytes();
553
+
554
+            let server_provided_data = cbc::Decryptor::<aes::Aes256>::new_from_slices(
555
+                &extra_data_key,
556
+                &extra_data_iv[..16],
557
+            )
558
+            .expect("the lengths are wrong??")
559
+            .decrypt_padded_vec::<Pkcs7>(server_provided_data)
560
+            .map_err(AuthError::Decryption)?;
561
+
562
+            let server_provided_data: Dictionary = plist::from_bytes(&server_provided_data)
563
+                .map_err(|err| AuthError::Parsing(2, err))?;
564
+
565
+            trace!("Parsed server provided data: {:#?}", server_provided_data);
566
+
567
+            Ok(server_provided_data)
568
+        })
569
+        .transpose()?;
570
+
571
+    match status_code {
572
+        StatusCode::Success => {
573
+            let server_provided_data = server_provided_data.unwrap_or_default();
574
+            Ok(AuthOutcome::Success(server_provided_data))
575
+        }
576
+        StatusCode::SecondaryActionRequired => {
577
+            let action_url = status
578
+                .get("au")
579
+                .and_then(|action_url| action_url.as_string())
580
+                .map(|action_url| action_url.to_string())
581
+                .ok_or(AuthError::Structure(response_plist))?;
582
+
583
+            let server_provided_data = server_provided_data.unwrap_or_default();
584
+
585
+            Ok(AuthOutcome::SecondaryActionRequired(
586
+                server_provided_data,
587
+                action_url,
588
+            ))
589
+        }
590
+        StatusCode::AnisetteReprovisionRequired => Ok(AuthOutcome::AnisetteReprovisionRequired),
591
+        StatusCode::AnisetteResyncRequired => {
592
+            let sim = status
593
+                .get("X-Apple-I-MD-DATA")
594
+                .and_then(|sim| sim.as_string())
595
+                .ok_or(AuthError::Structure(response_plist.clone()))?;
596
+
597
+            let sim = BASE64_STANDARD
598
+                .decode(sim)
599
+                .map_err(|_| AuthError::Structure(response_plist.clone()))?;
600
+
601
+            Ok(AnisetteResyncRequired(sim))
602
+        }
603
+        StatusCode::UrlSwitchingRequired => {
604
+            let url_switching_data = status
605
+                .get("X-Apple-I-Data")
606
+                .and_then(|data| data.as_string());
607
+
608
+            match url_switching_data {
609
+                Some(url_switching_data) => Ok(AuthOutcome::UrlSwitchingRequired(
610
+                    url_switching_data.to_string(),
611
+                )),
612
+                None => {
613
+                    panic!("URL Switching has been required but no data has been given for it.")
614
+                }
615
+            }
616
+        }
617
+    }
618
+}
619
+
620
+pub fn parse_tokens_from_server_provided_data(
621
+    server_provided_data: &Dictionary,
622
+) -> Option<(AuthToken, Vec<(String, GSToken)>)> {
623
+    let alt_dsid = server_provided_data
624
+        .get("adsid")
625
+        .and_then(|alt_dsid| alt_dsid.as_string())
626
+        .map(|alt_dsid| alt_dsid.to_string());
627
+
628
+    let idms_token = server_provided_data
629
+        .get("GsIdmsToken")
630
+        .and_then(|idms_token| idms_token.as_string())
631
+        .map(|idms_token| idms_token.to_string());
632
+
633
+    let session_key = server_provided_data
634
+        .get("sk")
635
+        .and_then(|session_key| session_key.as_data())
636
+        .map(|session_key| session_key.to_vec());
637
+
638
+    let cookie = server_provided_data
639
+        .get("c")
640
+        .and_then(|cookie| cookie.as_data())
641
+        .map(|cookie| cookie.to_vec());
642
+
643
+    let tokens = server_provided_data
644
+        .get("t")
645
+        .and_then(|tokens| tokens.as_dictionary())
646
+        .map(|tokens| {
647
+            tokens
648
+                .iter()
649
+                .filter_map(|(key, token)| {
650
+                    plist::from_value(token)
651
+                        .ok()
652
+                        .map(|token| (key.clone(), token))
653
+                })
654
+                .collect()
655
+        });
656
+
657
+    match (alt_dsid, idms_token, session_key, cookie) {
658
+        (Some(alt_dsid), Some(idms_token), Some(session_key), Some(cookie)) => Some((
659
+            AuthToken {
660
+                alt_dsid,
661
+                idms_token,
662
+                session_key,
663
+                cookie,
664
+            },
665
+            tokens.unwrap_or_default(),
666
+        )),
667
+        _ => None,
668
+    }
669
+}
670
+
671
+#[derive(Debug)]
672
+pub enum AppTokenRequestError {
673
+    InvalidURLBag,
674
+    Anisette(ADIError),
675
+    InvalidAuthToken,
676
+    Network(reqwest::Error),
677
+    Parsing(plist::Error),
678
+    Structure(Dictionary),
679
+    Apple(AppleError),
680
+    InvalidResponse,
681
+}
682
+
683
+impl std::fmt::Display for AppTokenRequestError {
684
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
685
+        match self {
686
+            AppTokenRequestError::InvalidURLBag => write!(f, "Invalid URL bag"),
687
+            AppTokenRequestError::Anisette(err) => {
688
+                write!(f, "Cannot generate device authentication data: {err}")
689
+            }
690
+            AppTokenRequestError::InvalidAuthToken => {
691
+                write!(f, "The provided authentication token is not valid")
692
+            }
693
+            AppTokenRequestError::Network(err) => write!(f, "Network error: {err}"),
694
+            AppTokenRequestError::Parsing(err) => {
695
+                write!(f, "Failed to parse the app token request response: {err}")
696
+            }
697
+            AppTokenRequestError::Structure(_) => {
698
+                write!(f, "Failed to parse the app token request response")
699
+            }
700
+            AppTokenRequestError::Apple(err) => write!(f, "Cannot proceed: {err}"),
701
+            AppTokenRequestError::InvalidResponse => {
702
+                write!(f, "Invalid token returned by the server")
703
+            }
704
+        }
705
+    }
706
+}
707
+
708
+impl std::error::Error for AppTokenRequestError {}
709
+
710
+pub async fn get_app_token(
711
+    http_session: &AnisetteHTTPSession<'_, '_>,
712
+    auth_token: &AuthToken,
713
+    app_token_identifier: &str,
714
+) -> Result<GSToken, AppTokenRequestError> {
715
+    let gs_service_url = http_session
716
+        .url_bag()
717
+        .get("gsService")
718
+        .and_then(Value::as_string)
719
+        .ok_or(AppTokenRequestError::InvalidURLBag)?;
720
+
721
+    let cpd = build_client_provided_data(http_session).map_err(AppTokenRequestError::Anisette)?;
722
+
723
+    let checksum = Hmac::<Sha256>::new_from_slice(&auth_token.session_key)
724
+        .map_err(|_| AppTokenRequestError::InvalidAuthToken)?
725
+        .chain_update("apptokens")
726
+        .chain_update(&auth_token.alt_dsid)
727
+        .chain_update(app_token_identifier)
728
+        .finalize()
729
+        .into_bytes()
730
+        .to_vec();
731
+
732
+    let request_plist = dict! {
733
+        "Header": dict!{
734
+            "Version": "1.0.1"
735
+        },
736
+        "Request": dict!{
737
+            "u": auth_token.alt_dsid.clone(),
738
+            "app": array![
739
+                app_token_identifier
740
+            ],
741
+            "c": Value::Data(auth_token.cookie.clone()),
742
+            "t": auth_token.idms_token.clone(),
743
+            "checksum": Value::Data(checksum),
744
+            "cpd": cpd,
745
+            "o": "apptokens",
746
+        }
747
+    };
748
+
749
+    let mut request_body = Vec::new();
750
+    plist::to_writer_xml(&mut request_body, &request_plist).unwrap();
751
+
752
+    let response = http_session
753
+        .anisette_request_builder(GRANDSLAM_DSID, Method::POST, gs_service_url)
754
+        .map_err(AppTokenRequestError::Anisette)?
755
+        .body(request_body)
756
+        .send()
757
+        .await
758
+        .map_err(AppTokenRequestError::Network)?
759
+        .bytes()
760
+        .await
761
+        .map_err(AppTokenRequestError::Network)?;
762
+
763
+    let response_plist: Dictionary =
764
+        plist::from_bytes(&response).map_err(AppTokenRequestError::Parsing)?;
765
+
766
+    let response_dict = response_plist
767
+        .get("Response")
768
+        .and_then(|response| response.as_dictionary())
769
+        .ok_or(AppTokenRequestError::Structure(response_plist.clone()))?;
770
+
771
+    // println!("Response: {response_dict:?}");
772
+
773
+    let status = response_dict
774
+        .get("Status")
775
+        .and_then(|status| status.as_dictionary())
776
+        .ok_or(AppTokenRequestError::Structure(response_plist.clone()))?;
777
+
778
+    parse_status(status).map_err(AppTokenRequestError::Apple)?;
779
+
780
+    let encrypted_tokens = response_dict
781
+        .get("et")
782
+        .and_then(|et| et.as_data())
783
+        .ok_or(AppTokenRequestError::Structure(response_plist.clone()))?;
784
+
785
+    let associated_data = &encrypted_tokens[0..3];
786
+    if associated_data != b"XYZ" {
787
+        return Err(AppTokenRequestError::InvalidResponse);
788
+    }
789
+
790
+    let iv = &encrypted_tokens[3..19];
791
+    let encrypted_token = &encrypted_tokens[19..];
792
+
793
+    let tokens_data = AesGcm::<Aes256, U16>::new_from_slice(&auth_token.session_key)
794
+        .map_err(|_| AppTokenRequestError::InvalidAuthToken)?
795
+        .decrypt(
796
+            // iv is of fixed size. It shall not fail.
797
+            iv.try_into().expect("Invalid IV size??"),
798
+            Payload {
799
+                msg: encrypted_token,
800
+                aad: associated_data,
801
+            },
802
+        )
803
+        .map_err(|_| AppTokenRequestError::InvalidResponse)?;
804
+
805
+    let tokens: Dictionary =
806
+        plist::from_bytes(&tokens_data).map_err(AppTokenRequestError::Parsing)?;
807
+
808
+    trace!("Decrypted token response: {:#?}", tokens);
809
+
810
+    tokens
811
+        .get("t")
812
+        .and_then(|token| token.as_dictionary())
813
+        .and_then(|token| token.get(app_token_identifier))
814
+        .and_then(|token| plist::from_value(token).ok())
815
+        .ok_or(AppTokenRequestError::InvalidResponse)
816
+}
... ...
@@ -0,0 +1,302 @@
1
+use crate::http_session::{AnisetteHTTPSession, AppleError, parse_status};
2
+use adi::proxy::ADIError;
3
+use base64::Engine;
4
+use base64::prelude::BASE64_STANDARD;
5
+use plist::{Dictionary, Value};
6
+use plist_macros::dict;
7
+use reqwest::Method;
8
+use std::error::Error;
9
+use std::fmt::{Display, Formatter};
10
+
11
+#[derive(Debug)]
12
+pub enum ProvisioningError {
13
+    ADIError(ADIError),
14
+    StartProvisioningRequest(reqwest::Error),
15
+    StartProvisioningRequestPlist(plist::Error),
16
+    StartProvisioningRequestStructure(Dictionary),
17
+    AppleError(AppleError),
18
+    FinishProvisioningRequest(reqwest::Error),
19
+    FinishProvisioningRequestPlist(plist::Error),
20
+    FinishProvisioningRequestStructure(Dictionary),
21
+    URLNotFound(String),
22
+}
23
+
24
+impl Display for ProvisioningError {
25
+    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
26
+        match self {
27
+            ProvisioningError::ADIError(err) => write!(
28
+                f,
29
+                "An internal error has been encountered while provisioning the device: {err}"
30
+            ),
31
+            ProvisioningError::StartProvisioningRequest(err) => {
32
+                write!(f, "The first provisioning request errored: {err}")
33
+            }
34
+            ProvisioningError::StartProvisioningRequestPlist(err) => write!(
35
+                f,
36
+                "The first provisioning request could not be parsed: {err}"
37
+            ),
38
+            ProvisioningError::StartProvisioningRequestStructure(plist) => write!(
39
+                f,
40
+                "The first provisioning request could not be parsed: {plist:?}"
41
+            ),
42
+            ProvisioningError::AppleError(err) => write!(f, "Provisioning failed: {err:?}"),
43
+            ProvisioningError::FinishProvisioningRequest(err) => {
44
+                write!(f, "The second provisioning request errored: {err}")
45
+            }
46
+            ProvisioningError::FinishProvisioningRequestPlist(err) => write!(
47
+                f,
48
+                "The second provisioning request could not be parsed: {err}"
49
+            ),
50
+            ProvisioningError::FinishProvisioningRequestStructure(plist) => write!(
51
+                f,
52
+                "The second provisioning request could not be parsed: {plist:?}"
53
+            ),
54
+            ProvisioningError::URLNotFound(url) => {
55
+                write!(f, "Endpoint not found in the URL bag: {url}")
56
+            }
57
+        }
58
+    }
59
+}
60
+
61
+impl Error for ProvisioningError {}
62
+
63
+pub const GRANDSLAM_DSID: i64 = -2;
64
+
65
+pub async fn provision(
66
+    http_session: &AnisetteHTTPSession<'_, '_>,
67
+) -> Result<(), ProvisioningError> {
68
+    let adi_proxy = http_session.adi_proxy();
69
+
70
+    let mid_start_provisioning_url = http_session
71
+        .url_bag()
72
+        .get("midStartProvisioning")
73
+        .and_then(Value::as_string)
74
+        .ok_or(ProvisioningError::URLNotFound(
75
+            "midStartProvisioning".into(),
76
+        ))?;
77
+
78
+    let start_provisioning_request_builder =
79
+        http_session.simple_request_builder(Method::GET, mid_start_provisioning_url);
80
+
81
+    let start_provisioning_response = start_provisioning_request_builder
82
+        .send()
83
+        .await
84
+        .map_err(ProvisioningError::StartProvisioningRequest)?;
85
+
86
+    let start_provisioning_plist: Dictionary = plist::from_bytes(
87
+        &start_provisioning_response
88
+            .bytes()
89
+            .await
90
+            .map_err(ProvisioningError::StartProvisioningRequest)?,
91
+    )
92
+    .map_err(ProvisioningError::StartProvisioningRequestPlist)?;
93
+
94
+    let spim = start_provisioning_plist
95
+        .get("Response")
96
+        .and_then(|response| response.as_dictionary())
97
+        .and_then(|response| response.get("spim"))
98
+        .and_then(|spim| spim.as_string())
99
+        .ok_or(ProvisioningError::StartProvisioningRequestStructure(
100
+            start_provisioning_plist.clone(),
101
+        ))?;
102
+
103
+    let spim = BASE64_STANDARD.decode(spim).map_err(|_| {
104
+        ProvisioningError::StartProvisioningRequestStructure(start_provisioning_plist.clone())
105
+    })?;
106
+
107
+    let (cpim, session) = adi_proxy
108
+        .start_provisioning(GRANDSLAM_DSID, &spim)
109
+        .map_err(ProvisioningError::ADIError)?;
110
+
111
+    let mid_finish_provisioning_url = http_session
112
+        .url_bag()
113
+        .get("midFinishProvisioning")
114
+        .and_then(Value::as_string)
115
+        .ok_or(ProvisioningError::URLNotFound(
116
+            "midFinishProvisioning".into(),
117
+        ))?;
118
+
119
+    // Soon try blocks will come to Rust :,)
120
+    let ptm_tk_result = async {
121
+        let finish_provisioning_request_builder =
122
+            http_session.simple_request_builder(Method::POST, mid_finish_provisioning_url);
123
+
124
+        let mut response = Dictionary::new();
125
+        response.insert("cpim".into(), Value::String(BASE64_STANDARD.encode(cpim)));
126
+
127
+        let mut finish_provisioning_request_dict = Dictionary::new();
128
+        finish_provisioning_request_dict.insert("Request".into(), Value::Dictionary(response));
129
+
130
+        let mut finish_provisioning_request_body = Vec::<u8>::new();
131
+        plist::to_writer_xml(
132
+            &mut finish_provisioning_request_body,
133
+            &finish_provisioning_request_dict,
134
+        )
135
+        .expect("Cannot write response plist??");
136
+
137
+        // println!("{}", String::from_utf8(finish_provisioning_request_body.clone()).unwrap());
138
+
139
+        let finish_provisioning_response = finish_provisioning_request_builder
140
+            .body(finish_provisioning_request_body)
141
+            .header("Content-Type", "application/x-www-form-urlencoded")
142
+            .send()
143
+            .await
144
+            .map_err(ProvisioningError::FinishProvisioningRequest)?;
145
+
146
+        let finish_provisioning_plist: Dictionary = plist::from_bytes(
147
+            &finish_provisioning_response
148
+                .bytes()
149
+                .await
150
+                .map_err(ProvisioningError::FinishProvisioningRequest)?,
151
+        )
152
+        .map_err(ProvisioningError::FinishProvisioningRequestPlist)?;
153
+
154
+        let finish_provisioning_response_plist = finish_provisioning_plist
155
+            .get("Response")
156
+            .and_then(|response| response.as_dictionary())
157
+            .ok_or(ProvisioningError::FinishProvisioningRequestStructure(
158
+                finish_provisioning_plist.clone(),
159
+            ))?;
160
+
161
+        finish_provisioning_response_plist
162
+            .get("Status")
163
+            .and_then(|status| status.as_dictionary())
164
+            .map(|status| parse_status(status).map_err(ProvisioningError::AppleError))
165
+            .transpose()?;
166
+
167
+        let ptm = finish_provisioning_response_plist
168
+            .get("ptm")
169
+            .and_then(|ptm| ptm.as_string())
170
+            .ok_or(ProvisioningError::FinishProvisioningRequestStructure(
171
+                finish_provisioning_plist.clone(),
172
+            ))?;
173
+        let ptm = BASE64_STANDARD.decode(ptm).map_err(|_| {
174
+            ProvisioningError::FinishProvisioningRequestStructure(finish_provisioning_plist.clone())
175
+        })?;
176
+
177
+        let tk = finish_provisioning_response_plist
178
+            .get("tk")
179
+            .and_then(|tk| tk.as_string())
180
+            .ok_or(ProvisioningError::FinishProvisioningRequestStructure(
181
+                finish_provisioning_plist.clone(),
182
+            ))?;
183
+        let tk = BASE64_STANDARD.decode(tk).map_err(|_| {
184
+            ProvisioningError::FinishProvisioningRequestStructure(finish_provisioning_plist.clone())
185
+        })?;
186
+
187
+        let routing_info = finish_provisioning_response_plist
188
+            .get("X-Apple-I-MD-RINFO")
189
+            .and_then(|tk| tk.as_string())
190
+            .ok_or(ProvisioningError::FinishProvisioningRequestStructure(
191
+                finish_provisioning_plist.clone(),
192
+            ))?
193
+            .parse()
194
+            .map_err(|_| {
195
+                ProvisioningError::FinishProvisioningRequestStructure(
196
+                    finish_provisioning_plist.clone(),
197
+                )
198
+            })?;
199
+
200
+        Ok((ptm, tk, routing_info))
201
+    }
202
+    .await;
203
+
204
+    match ptm_tk_result {
205
+        Ok((ptm, tk, routing_info)) => {
206
+            adi_proxy
207
+                .end_provisioning(session, &ptm, &tk)
208
+                .map_err(ProvisioningError::ADIError)?;
209
+
210
+            adi_proxy
211
+                .set_idms_routing(GRANDSLAM_DSID, routing_info)
212
+                .map_err(ProvisioningError::ADIError)
213
+        }
214
+        Err(e) => {
215
+            adi_proxy
216
+                .destroy_provisioning_session(session)
217
+                .map_err(ProvisioningError::ADIError)?;
218
+
219
+            Err(e)
220
+        }
221
+    }
222
+}
223
+
224
+#[derive(Debug)]
225
+pub enum SyncError {
226
+    ADI(ADIError),
227
+    Apple(AppleError),
228
+    Network(reqwest::Error),
229
+    Parsing(plist::Error),
230
+    ResponseStructure(Dictionary),
231
+    URLNotFound,
232
+}
233
+
234
+impl Display for SyncError {
235
+    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
236
+        match self {
237
+            Self::ADI(e) => write!(f, "ADI error: {e}"),
238
+            Self::Apple(e) => write!(f, "Apple error: {e}"),
239
+            Self::Network(e) => write!(f, "Network error: {e}"),
240
+            Self::Parsing(e) => write!(f, "Parsing error: {e}"),
241
+            Self::ResponseStructure(dict) => write!(f, "Invalid response: {dict:?}"),
242
+            Self::URLNotFound => write!(f, "URL not found"),
243
+        }
244
+    }
245
+}
246
+
247
+impl Error for SyncError {}
248
+
249
+pub async fn sync_machine(
250
+    http_session: &AnisetteHTTPSession<'_, '_>,
251
+    sim: &[u8],
252
+) -> Result<(), SyncError> {
253
+    let adi_proxy = http_session.adi_proxy();
254
+
255
+    let (mid, srm) = adi_proxy
256
+        .synchronize(GRANDSLAM_DSID, sim)
257
+        .map_err(SyncError::ADI)?;
258
+
259
+    let sync_machine_request_plist = dict! {
260
+        "Header": Dictionary::new(),
261
+        "Request": dict!{
262
+            "X-Apple-I-MD-M": BASE64_STANDARD.encode(mid),
263
+            "srm": BASE64_STANDARD.encode(srm)
264
+        }
265
+    };
266
+
267
+    let mid_sync_machine_url = http_session
268
+        .url_bag()
269
+        .get("midSyncMachine")
270
+        .and_then(Value::as_string)
271
+        .ok_or(SyncError::URLNotFound)?;
272
+
273
+    let sync_machine_request_builder =
274
+        http_session.simple_request_builder(Method::GET, mid_sync_machine_url);
275
+
276
+    let mut sync_machine_request_body = Vec::<u8>::new();
277
+    plist::to_writer_xml(&mut sync_machine_request_body, &sync_machine_request_plist)
278
+        .expect("Cannot write response plist??");
279
+
280
+    let sync_machine_response = sync_machine_request_builder
281
+        .body(sync_machine_request_body)
282
+        .header("Content-Type", "text/x-xml-plist")
283
+        .send()
284
+        .await
285
+        .map_err(SyncError::Network)?
286
+        .bytes()
287
+        .await
288
+        .map_err(SyncError::Network)?;
289
+
290
+    let sync_machine_response_plist: Dictionary =
291
+        plist::from_bytes(&sync_machine_response).map_err(SyncError::Parsing)?;
292
+
293
+    sync_machine_response_plist
294
+        .get("Response")
295
+        .and_then(|response| response.as_dictionary())
296
+        .and_then(|response| response.get("Status"))
297
+        .and_then(|response| response.as_dictionary())
298
+        .map(|status| parse_status(status).map_err(SyncError::Apple))
299
+        .ok_or(SyncError::ResponseStructure(
300
+            sync_machine_response_plist.clone(),
301
+        ))?
302
+}
... ...
@@ -0,0 +1,89 @@
1
+use crate::grandslam::{Token, TokenError};
2
+use crate::http_session::{AppleError, parse_status};
3
+use plist::{Dictionary, Value};
4
+use reqwest::Method;
5
+use serde::Serialize;
6
+use std::fmt::{Display, Formatter};
7
+
8
+#[derive(Debug)]
9
+pub enum PostDataError {
10
+    Serialization(plist::Error),
11
+    Reqwest(reqwest::Error),
12
+    Apple(AppleError),
13
+    Token(TokenError),
14
+    URLNotFound,
15
+}
16
+
17
+impl Display for PostDataError {
18
+    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
19
+        match self {
20
+            PostDataError::Serialization(err) => write!(f, "Serialization failure! {err}"),
21
+            PostDataError::Reqwest(err) => write!(f, "Failed to perform HTTP request! {err}"),
22
+            PostDataError::Apple(err) => err.fmt(f),
23
+            PostDataError::Token(err) => err.fmt(f),
24
+            PostDataError::URLNotFound => write!(f, "Endpoint not found"),
25
+        }
26
+    }
27
+}
28
+
29
+impl std::error::Error for PostDataError {}
30
+
31
+#[derive(Debug, Default, Serialize)]
32
+pub struct DeviceData {
33
+    #[serde(rename = "circleStatus")]
34
+    pub circle_status: Option<bool>,
35
+    #[serde(rename = "dc")]
36
+    pub device_color: Option<String>,
37
+    #[serde(rename = "dn")]
38
+    pub device_name: Option<String>,
39
+    #[serde(rename = "event")]
40
+    pub event: Option<String>,
41
+    #[serde(rename = "imei")]
42
+    pub imei: Option<String>,
43
+    #[serde(rename = "loc")]
44
+    pub locale: Option<String>,
45
+    #[serde(rename = "pn")]
46
+    pub phone_number: Option<String>,
47
+    #[serde(rename = "ptkn")]
48
+    pub push_token: Option<String>,
49
+    pub services: Option<Vec<String>>,
50
+    #[serde(rename = "sn")]
51
+    pub serial_number: Option<String>,
52
+}
53
+
54
+impl Token<'_, '_, '_> {
55
+    pub async fn post_data(&self, device_data: DeviceData) -> Result<(), PostDataError> {
56
+        let post_data = plist::to_value(&device_data).map_err(PostDataError::Serialization)?;
57
+        let post_data_url = self
58
+            .http_session
59
+            .url_bag()
60
+            .get("postData")
61
+            .and_then(Value::as_string)
62
+            .ok_or(PostDataError::URLNotFound)?;
63
+
64
+        let mut request_plist = Dictionary::new();
65
+        request_plist.insert("Request".into(), post_data);
66
+
67
+        let mut request_body = Vec::<u8>::new();
68
+        plist::to_writer_xml(&mut request_body, &request_plist)
69
+            .expect("Cannot write request plist??");
70
+
71
+        let request = self
72
+            .authenticated_request_builder(Method::POST, post_data_url)
73
+            .map_err(PostDataError::Token)?
74
+            .body(request_body);
75
+
76
+        let response = request
77
+            .send()
78
+            .await
79
+            .map_err(PostDataError::Reqwest)?
80
+            .bytes()
81
+            .await
82
+            .map_err(PostDataError::Reqwest)?;
83
+
84
+        let status: Dictionary =
85
+            plist::from_bytes(&response).map_err(PostDataError::Serialization)?;
86
+
87
+        parse_status(&status).map_err(PostDataError::Apple)
88
+    }
89
+}
... ...
@@ -0,0 +1,28 @@
1
+-----BEGIN CERTIFICATE-----
2
+MIIEuzCCA6OgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQGEwJVUzET
3
+MBEGA1UEChMKQXBwbGUgSW5jLjEmMCQGA1UECxMdQXBwbGUgQ2VydGlmaWNhdGlv
4
+biBBdXRob3JpdHkxFjAUBgNVBAMTDUFwcGxlIFJvb3QgQ0EwHhcNMDYwNDI1MjE0
5
+MDM2WhcNMzUwMjA5MjE0MDM2WjBiMQswCQYDVQQGEwJVUzETMBEGA1UEChMKQXBw
6
+bGUgSW5jLjEmMCQGA1UECxMdQXBwbGUgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx
7
+FjAUBgNVBAMTDUFwcGxlIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
8
+ggEKAoIBAQDkkakJH5HbHkdQ6wXtXnmELes2oldMVeyLGYne+Uts9QerIjAC6Bg+
9
++FAJ039BqJj50cpmnCRrEdCju+QbKsMflZ56DKRHi1vUFjczy8QPTc4UadHJGXL1
10
+XQ7Vf1+b8iUDulWPTV0N8WQ1IxVLFVkds5T39pyez1C6wVhQZ48ItCD3y6wsIG9w
11
+tj8BMIy3Q88PnT3zK0koGsj+zrW5DtleHNbLPbU6rfQPDgCSC7EhFi501TwN22IW
12
+q6NxkkdTVcGvL0Gz+PvjcM3mo0xFfh9Ma1CWQYnEdGILEINBhzOKgbEwWOxaBDKM
13
+aLOPHd5lc/9nXmW8Sdh2nzMUZaF3lMktAgMBAAGjggF6MIIBdjAOBgNVHQ8BAf8E
14
+BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUK9BpR5R2Cf70a40uQKb3
15
+R01/CF4wHwYDVR0jBBgwFoAUK9BpR5R2Cf70a40uQKb3R01/CF4wggERBgNVHSAE
16
+ggEIMIIBBDCCAQAGCSqGSIb3Y2QFATCB8jAqBggrBgEFBQcCARYeaHR0cHM6Ly93
17
+d3cuYXBwbGUuY29tL2FwcGxlY2EvMIHDBggrBgEFBQcCAjCBthqBs1JlbGlhbmNl
18
+IG9uIHRoaXMgY2VydGlmaWNhdGUgYnkgYW55IHBhcnR5IGFzc3VtZXMgYWNjZXB0
19
+YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5kYXJkIHRlcm1zIGFuZCBj
20
+b25kaXRpb25zIG9mIHVzZSwgY2VydGlmaWNhdGUgcG9saWN5IGFuZCBjZXJ0aWZp
21
+Y2F0aW9uIHByYWN0aWNlIHN0YXRlbWVudHMuMA0GCSqGSIb3DQEBBQUAA4IBAQBc
22
+NplMLXi37Yyb3PN3m/J20ncwT8EfhYOFG5k9RzfyqZtAjizUsZAS2L70c5vu0mQP
23
+y3lPNNiiPvl4/2vIB+x9OYOLUyDTOMSxv5pPCmv/K/xZpwUJfBdAVhEedNO3iyM7
24
+R6PVbyTi69G3cN8PReEnyvFteO3ntRcXqNx+IjXKJdXZD9Zr1KIkIxH3oayPc4Fg
25
+xhtbCS+SsvhESPBgOJ4V9T0mZyCKM2r3DYLP3uujL/lTaltkwGMzd/c6ByxW69oP
26
+IQ7aunMZT7XZNn/Bh1XZp5m5MkL72NVxnn6hUrcbvZNCJBIqxw8dtk2cXmPIS4AX
27
+UKqK1drk/NAJBzewdXUh
28
+-----END CERTIFICATE-----
... ...
@@ -0,0 +1,12 @@
1
+pub enum SecondaryActionType {
2
+    ServerDriven(String),
3
+}
4
+
5
+impl From<String> for SecondaryActionType {
6
+    fn from(value: String) -> Self {
7
+        match value {
8
+            // "".to_string() => SecondaryActionType::ServerDriven("")
9
+            server_drive_action => SecondaryActionType::ServerDriven(server_drive_action),
10
+        }
11
+    }
12
+}
... ...
@@ -0,0 +1,54 @@
1
+use crate::grandslam::parse_url_bag_response;
2
+use crate::http_session::{AppleError, HTTPSession, URLBagError};
3
+use reqwest::Method;
4
+use std::error::Error;
5
+use std::fmt::{Display, Formatter};
6
+
7
+#[derive(Debug)]
8
+pub enum URLSwitchingError {
9
+    Reqwest(reqwest::Error),
10
+    AppleError(AppleError),
11
+    URLBag(URLBagError),
12
+}
13
+
14
+impl Display for URLSwitchingError {
15
+    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
16
+        match self {
17
+            URLSwitchingError::Reqwest(err) => {
18
+                write!(f, "Failed to connect to server: {err}")
19
+            }
20
+            URLSwitchingError::AppleError(err) => {
21
+                write!(f, "Failed to perform the URL switch: {err}")
22
+            }
23
+            URLSwitchingError::URLBag(err) => {
24
+                write!(f, "Failed to parse the provided URL bag: {err}")
25
+            }
26
+        }
27
+    }
28
+}
29
+
30
+impl Error for URLSwitchingError {}
31
+
32
+pub async fn url_switch(
33
+    http_session: &mut HTTPSession<'_>,
34
+    url: &str,
35
+    idata: &str,
36
+) -> Result<(), URLSwitchingError> {
37
+    let url_bag_response = http_session
38
+        .request_builder(Method::GET, url)
39
+        .query(&[("idata", idata.to_string())])
40
+        .send()
41
+        .await
42
+        .map_err(URLSwitchingError::Reqwest)?
43
+        .error_for_status()
44
+        .map_err(URLSwitchingError::Reqwest)?
45
+        .bytes()
46
+        .await
47
+        .map_err(URLSwitchingError::Reqwest)?;
48
+
49
+    let url_bag = parse_url_bag_response(url_bag_response).map_err(URLSwitchingError::URLBag)?;
50
+
51
+    http_session.url_switch(url_bag);
52
+
53
+    Ok(())
54
+}
... ...
@@ -0,0 +1,270 @@
1
+use crate::bundle_information::{AUTH_KIT_BUNDLE_INFORMATION, BundleInformation};
2
+use crate::device::Device;
3
+use adi::proxy::{ADIProxy, ADIResult};
4
+use base64::Engine;
5
+use base64::prelude::BASE64_STANDARD;
6
+use chrono::{Local, SecondsFormat};
7
+use plist::Dictionary;
8
+use reqwest::header::{HeaderMap, InvalidHeaderValue};
9
+use reqwest::{Certificate, Client, Method, RequestBuilder};
10
+use std::error::Error;
11
+use std::fmt::{Display, Formatter};
12
+
13
+const SIMULATED_AUTHENTICATION_FRAMEWORK_INFORMATION: BundleInformation =
14
+    AUTH_KIT_BUNDLE_INFORMATION;
15
+
16
+/// Error returned by Apple servers' endpoints
17
+#[derive(Debug)]
18
+pub struct AppleError {
19
+    // description: String,
20
+    pub code: i64,
21
+    pub message: String,
22
+}
23
+
24
+impl Display for AppleError {
25
+    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
26
+        write!(f, "{} ({})", self.message, self.code)
27
+    }
28
+}
29
+
30
+impl Error for AppleError {}
31
+
32
+pub type URLBag = Dictionary;
33
+
34
+#[derive(Debug)]
35
+pub enum URLBagError {
36
+    InvalidUrlBag,
37
+    Parsing,
38
+}
39
+
40
+impl Display for URLBagError {
41
+    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
42
+        match self {
43
+            URLBagError::InvalidUrlBag => {
44
+                write!(f, "The provided URL bag is invalid")
45
+            }
46
+            URLBagError::Parsing => {
47
+                write!(f, "Unable to parse the provided URL bag")
48
+            }
49
+        }
50
+    }
51
+}
52
+
53
+impl Error for URLBagError {}
54
+
55
+/// Parse the Status field of an Apple server Response.
56
+/// Returns the AppleError if there is one reported.
57
+pub fn parse_status(status_dict: &Dictionary) -> Result<(), AppleError> {
58
+    match (
59
+        status_dict["ec"].as_signed_integer(),
60
+        // status_dict["ed"].as_string(),
61
+        status_dict["em"].as_string(),
62
+    ) {
63
+        (Some(ec), Some(em)) if ec != 0 => {
64
+            Err(AppleError {
65
+                // description: ed.to_string(),
66
+                code: ec,
67
+                message: em.to_string(),
68
+            })
69
+        }
70
+        _ => Ok(()),
71
+    }
72
+}
73
+
74
+/// Abstracts a session with Apple servers.
75
+pub struct BasicHTTPSession<'lt> {
76
+    client: Client,
77
+    device: Device,
78
+    application_info: BundleInformation<'lt>,
79
+}
80
+
81
+pub struct HTTPSession<'lt> {
82
+    http_session: BasicHTTPSession<'lt>,
83
+    url_bag: URLBag,
84
+}
85
+
86
+#[derive(Debug)]
87
+pub enum HTTPSessionCreationError {
88
+    InvalidHeader(InvalidHeaderValue),
89
+    Reqwest(reqwest::Error),
90
+    InvalidURLBagResponsePlist(URLBagError),
91
+    InvalidURLBagResponseStructure,
92
+}
93
+
94
+impl Display for HTTPSessionCreationError {
95
+    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
96
+        // TODO write better errors maybe?
97
+        write!(f, "{self:?}")
98
+    }
99
+}
100
+
101
+impl Error for HTTPSessionCreationError {}
102
+
103
+impl<'lt> BasicHTTPSession<'lt> {
104
+    pub fn new(
105
+        device: Device,
106
+        client_bundle_info: BundleInformation<'lt>,
107
+        custom_certificate: Option<Certificate>,
108
+    ) -> Result<Self, HTTPSessionCreationError> {
109
+        let client_builder = Client::builder();
110
+        let client_builder = match custom_certificate {
111
+            Some(certificate) => client_builder.add_root_certificate(certificate),
112
+            None => client_builder,
113
+        };
114
+
115
+        let headers = {
116
+            let mut headers = HeaderMap::new();
117
+            headers.insert(
118
+                "User-Agent",
119
+                client_bundle_info
120
+                    .bundle_name
121
+                    .parse()
122
+                    .map_err(HTTPSessionCreationError::InvalidHeader)?,
123
+            );
124
+            headers.insert(
125
+                "X-MMe-Client-Info",
126
+                device
127
+                    .server_friendly_description(
128
+                        &SIMULATED_AUTHENTICATION_FRAMEWORK_INFORMATION,
129
+                        &client_bundle_info,
130
+                    )
131
+                    .parse()
132
+                    .map_err(HTTPSessionCreationError::InvalidHeader)?,
133
+            );
134
+            headers.insert(
135
+                "X-Mme-Device-Id",
136
+                device
137
+                    .device_uuid
138
+                    .parse()
139
+                    .map_err(HTTPSessionCreationError::InvalidHeader)?,
140
+            );
141
+            headers.insert(
142
+                "X-Apple-Client-App-Name",
143
+                client_bundle_info
144
+                    .bundle_name
145
+                    .parse()
146
+                    .map_err(HTTPSessionCreationError::InvalidHeader)?,
147
+            );
148
+
149
+            headers
150
+        };
151
+
152
+        let client_builder = client_builder.default_headers(headers);
153
+        let client = client_builder
154
+            .build()
155
+            .map_err(HTTPSessionCreationError::Reqwest)?;
156
+
157
+        Ok(BasicHTTPSession {
158
+            client,
159
+            device,
160
+            application_info: client_bundle_info,
161
+        })
162
+    }
163
+
164
+    pub fn device(&self) -> &Device {
165
+        &self.device
166
+    }
167
+
168
+    pub fn application_information(&self) -> &BundleInformation<'_> {
169
+        &self.application_info
170
+    }
171
+
172
+    pub fn request_builder(&self, method: Method, url: &str) -> RequestBuilder {
173
+        let client_time = Local::now()
174
+            .to_utc()
175
+            .to_rfc3339_opts(SecondsFormat::Secs, true);
176
+        self.client
177
+            .request(method, url)
178
+            .header("X-Apple-I-Client-Time", client_time)
179
+    }
180
+}
181
+
182
+impl<'lt> HTTPSession<'lt> {
183
+    pub fn new(
184
+        http_session: BasicHTTPSession<'lt>,
185
+        url_bag: URLBag,
186
+    ) -> Result<Self, HTTPSessionCreationError> {
187
+        Ok(Self {
188
+            http_session,
189
+            url_bag,
190
+        })
191
+    }
192
+
193
+    pub fn url_switch(&mut self, url_bag: URLBag) {
194
+        self.url_bag = url_bag;
195
+    }
196
+
197
+    pub fn device(&self) -> &Device {
198
+        self.http_session.device()
199
+    }
200
+
201
+    pub fn application_information(&self) -> &BundleInformation<'_> {
202
+        self.http_session.application_information()
203
+    }
204
+
205
+    pub fn url_bag(&self) -> &URLBag {
206
+        &self.url_bag
207
+    }
208
+
209
+    pub fn request_builder(&self, method: Method, url: &str) -> RequestBuilder {
210
+        self.http_session.request_builder(method, url)
211
+    }
212
+}
213
+
214
+pub struct AnisetteHTTPSession<'lt, 'adi> {
215
+    http_session: HTTPSession<'lt>,
216
+    adi_proxy: &'adi dyn ADIProxy,
217
+}
218
+
219
+impl<'lt, 'adi> AnisetteHTTPSession<'lt, 'adi> {
220
+    pub fn new(http_session: HTTPSession<'lt>, adi_proxy: &'adi dyn ADIProxy) -> Self {
221
+        Self {
222
+            http_session,
223
+            adi_proxy,
224
+        }
225
+    }
226
+
227
+    pub fn url_bag(&self) -> &URLBag {
228
+        self.http_session.url_bag()
229
+    }
230
+
231
+    pub fn simple_request_builder(&self, method: Method, url: &str) -> RequestBuilder {
232
+        self.http_session.request_builder(method, url)
233
+    }
234
+
235
+    pub fn anisette_request_builder(
236
+        &self,
237
+        ds_id: i64,
238
+        method: Method,
239
+        url: &str,
240
+    ) -> ADIResult<RequestBuilder> {
241
+        let (mid_b, otp_b) = self.adi_proxy.request_otp(ds_id)?;
242
+
243
+        let mid = BASE64_STANDARD.encode(mid_b);
244
+        let otp = BASE64_STANDARD.encode(otp_b);
245
+
246
+        let rinfo = self.adi_proxy.get_idms_routing(ds_id)?;
247
+
248
+        Ok(self
249
+            .simple_request_builder(method, url)
250
+            .header("X-Apple-I-MD", otp)
251
+            .header("X-Apple-I-MD-M", mid)
252
+            .header("X-Apple-I-MD-RINFO", rinfo))
253
+    }
254
+
255
+    pub fn device(&self) -> &Device {
256
+        self.http_session.device()
257
+    }
258
+
259
+    pub fn application_information(&self) -> &BundleInformation<'_> {
260
+        self.http_session.application_information()
261
+    }
262
+
263
+    pub fn adi_proxy(&self) -> &dyn ADIProxy {
264
+        self.adi_proxy
265
+    }
266
+
267
+    pub fn url_switch(&mut self, url_bag: URLBag) {
268
+        self.http_session.url_switch(url_bag)
269
+    }
270
+}
... ...
@@ -0,0 +1,147 @@
1
+use crate::bundle_information::BundleInformation;
2
+use crate::device::Device;
3
+use crate::http_session::{
4
+    AnisetteHTTPSession, AppleError, BasicHTTPSession, HTTPSession, HTTPSessionCreationError,
5
+    URLBagError,
6
+};
7
+use adi::proxy::ADIError;
8
+use bytes::Bytes;
9
+use plist::{Dictionary, Value};
10
+use plist_macros::dict;
11
+use reqwest::Method;
12
+use std::fmt::{Display, Formatter};
13
+
14
+pub async fn http_session<'lt>(
15
+    device: Device,
16
+    client_bundle_info: BundleInformation<'lt>,
17
+) -> Result<HTTPSession<'lt>, HTTPSessionCreationError> {
18
+    let http_session = BasicHTTPSession::new(device, client_bundle_info, None)?;
19
+
20
+    let url_bag_response = http_session
21
+        .request_builder(Method::GET, "https://sandbox.itunes.apple.com/bag.xml")
22
+        .query(&[("ix", 6)])
23
+        .send()
24
+        .await
25
+        .map_err(HTTPSessionCreationError::Reqwest)?
26
+        .error_for_status()
27
+        .map_err(HTTPSessionCreationError::Reqwest)?
28
+        .bytes()
29
+        .await
30
+        .map_err(HTTPSessionCreationError::Reqwest)?;
31
+
32
+    let url_bag = parse_url_bag_response(url_bag_response)
33
+        .map_err(|_| HTTPSessionCreationError::InvalidURLBagResponseStructure)?;
34
+
35
+    HTTPSession::new(http_session, url_bag)
36
+}
37
+
38
+pub(crate) fn parse_url_bag_response(url_bag_response: Bytes) -> Result<Dictionary, URLBagError> {
39
+    let url_bag_plist =
40
+        plist::from_bytes::<Dictionary>(&url_bag_response).map_err(|_| URLBagError::Parsing)?;
41
+
42
+    Ok(url_bag_plist)
43
+}
44
+
45
+#[derive(Debug)]
46
+pub enum AuthError {
47
+    Apple(AppleError),
48
+    Anisette(ADIError),
49
+    Network(reqwest::Error),
50
+    InvalidURLBag,
51
+    Parsing,
52
+}
53
+
54
+impl Display for AuthError {
55
+    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
56
+        match self {
57
+            AuthError::Apple(err) => {
58
+                write!(f, "Could not log-in to Apple servers: {err}")
59
+            }
60
+            AuthError::Anisette(err) => {
61
+                write!(f, "Cannot generate device authentication data: {err}")
62
+            }
63
+            AuthError::Network(err) => {
64
+                write!(f, "Network error: {err}")
65
+            }
66
+            AuthError::InvalidURLBag => {
67
+                write!(f, "Cannot find the endpoint in the URL bag.")
68
+            }
69
+            AuthError::Parsing => {
70
+                write!(f, "Cannot parse HTTP response")
71
+            }
72
+        }
73
+    }
74
+}
75
+
76
+impl std::error::Error for AuthError {}
77
+
78
+pub async fn login(
79
+    http_session: &AnisetteHTTPSession<'_, '_>,
80
+    apple_id: &str,
81
+    password: &str,
82
+    attempt: i32,
83
+) -> Result<(), AuthError> {
84
+    let authenticate_url = http_session
85
+        .url_bag()
86
+        .get("authenticateAccount")
87
+        .and_then(Value::as_string)
88
+        .ok_or(AuthError::InvalidURLBag)?
89
+        .replace("sandbox", "p51-buy");
90
+
91
+    let adi_proxy = http_session.adi_proxy();
92
+
93
+    /*
94
+       "guid": "",
95
+       "kbsync": vec![],
96
+    */
97
+
98
+    let request_plist = dict! {
99
+        "appleId": apple_id,
100
+        "attempt": attempt,
101
+        "createSession": true,
102
+        "password": password,
103
+        "passwordSettings": dict! {
104
+            "free": "always",
105
+            "paid": "always"
106
+        },
107
+        "rmp": "0",
108
+        "why": "signIn",
109
+    };
110
+
111
+    let mut request_body = Vec::new();
112
+    plist::to_writer_xml(&mut request_body, &request_plist).unwrap();
113
+
114
+    /*
115
+    let response = http_session
116
+        .anisette_request_builder(GRANDSLAM_DSID, Method::POST, &authenticate_url)
117
+        .map_err(AuthError::Anisette)?
118
+        .body(request_body)
119
+        .send()
120
+        .await
121
+        .and_then(|response| response.error_for_status())
122
+        .map_err(AuthError::Network)?
123
+        .text()
124
+        .await
125
+        .map_err(AuthError::Network)?;
126
+
127
+    println!("response: {:?}", response);
128
+
129
+        .bytes()
130
+        .await
131
+        .map_err(AuthError::Network)?;
132
+
133
+
134
+
135
+    let response_plist: Dictionary =
136
+        plist::from_bytes(&response).map_err(|err| AuthError::Parsing)?;
137
+
138
+    let response_dict = response_plist
139
+        .get("Response")
140
+        .and_then(|response| response.as_dictionary())
141
+        .ok_or(AuthError::Parsing)?;
142
+
143
+    println!("{:#?}", response_dict);
144
+    // */
145
+
146
+    Ok(())
147
+}
... ...
@@ -0,0 +1,5 @@
1
+pub mod bundle_information;
2
+pub mod device;
3
+pub mod grandslam;
4
+pub mod http_session;
5
+pub mod itunes;
... ...
@@ -0,0 +1,14 @@
1
+[package]
2
+name = "apple-codesign"
3
+version = "0.1.0"
4
+edition = "2024"
5
+
6
+[dependencies]
7
+plist.workspace = true
8
+
9
+tokio.workspace = true
10
+lief = "0.17"
11
+sha1 = "0.11.0-rc.3"
12
+sha2 = "0.11.0-rc.3"
13
+futures = "0.3.31"
14
+log = "0.4.28"
... ...
@@ -0,0 +1,126 @@
1
+use futures::future::join_all;
2
+use futures::{FutureExt, future::BoxFuture};
3
+use log::warn;
4
+use plist::{Dictionary, Value};
5
+use sha1::Digest as _;
6
+use sha2::Digest as _;
7
+use std::fs;
8
+use std::path::{Path, PathBuf};
9
+use tokio::task::{block_in_place, spawn_blocking};
10
+
11
+struct Bundle {
12
+    path: PathBuf,
13
+}
14
+
15
+impl Bundle {
16
+    async fn code_resources(&self) -> Dictionary {
17
+        struct CodeResourceFile {
18
+            path: PathBuf,
19
+            sha1: Vec<u8>,
20
+            sha256: Vec<u8>,
21
+        }
22
+
23
+        async fn hash_file(relative_path: PathBuf, path: PathBuf) -> CodeResourceFile {
24
+            let file_data = fs::read(&path).unwrap(); // FIXME unwrap
25
+            let file_data2 = file_data.clone();
26
+            let sha1 = spawn_blocking(move || sha1::Sha1::digest(&file_data)[..].into());
27
+            let sha256 = spawn_blocking(move || sha2::Sha256::digest(&file_data2)[..].into());
28
+            CodeResourceFile {
29
+                path: relative_path,
30
+                sha1: sha1.await.unwrap(),
31
+                sha256: sha256.await.unwrap(),
32
+            }
33
+        }
34
+
35
+        fn resources_for_directory(
36
+            root: &Path,
37
+            directory: PathBuf,
38
+        ) -> Vec<BoxFuture<'static, CodeResourceFile>> {
39
+            let mut output = Vec::new();
40
+            let mut subfolders = Vec::new();
41
+            if let Ok(read_dir) = fs::read_dir(directory) {
42
+                for entry in read_dir {
43
+                    if let Ok(entry) = entry {
44
+                        let metadata = entry.metadata().expect("metadata call failed");
45
+                        let path = entry.path();
46
+                        if metadata.is_file() {
47
+                            if let Ok(relative_path) = entry.path().strip_prefix(root) {
48
+                                // TODO check rules
49
+                                output.push(hash_file(relative_path.to_path_buf(), path).boxed());
50
+                            } else {
51
+                                warn!("Skipping {:?} as its prefix is not correct", entry.path());
52
+                            }
53
+                        } else if metadata.is_dir() {
54
+                            subfolders.push(resources_for_directory(root, path));
55
+                        }
56
+                    }
57
+                }
58
+            }
59
+
60
+            for subfolder in subfolders {
61
+                let data = subfolder;
62
+                output.extend(data);
63
+            }
64
+            output
65
+        }
66
+
67
+        let path_buf = self.path.to_path_buf();
68
+        let resources = resources_for_directory(&self.path, path_buf);
69
+
70
+        let rules = Dictionary::new();
71
+        let rules2 = Dictionary::new();
72
+
73
+        let (files, files2) = {
74
+            let mut files = Dictionary::new();
75
+            let mut files2 = Dictionary::new();
76
+
77
+            for res in resources {
78
+                let CodeResourceFile { path, sha1, sha256 } = res.await;
79
+
80
+                let path = path.to_string_lossy().into_owned();
81
+
82
+                let sha1: Vec<u8> = sha1.into();
83
+                let sha256: Vec<u8> = sha256.into();
84
+
85
+                files.insert(path.clone(), Value::Data(sha1.clone()));
86
+
87
+                let mut file2 = Dictionary::new();
88
+                file2.insert("hash".to_string(), Value::Data(sha1));
89
+                file2.insert("hash2".to_string(), Value::Data(sha256));
90
+
91
+                files2.insert(path, Value::Dictionary(file2));
92
+            }
93
+
94
+            (files, files2)
95
+        };
96
+
97
+        let code_resources = {
98
+            let mut code_resources = Dictionary::new();
99
+            code_resources.insert("files".to_string(), Value::Dictionary(files));
100
+            code_resources.insert("files2".to_string(), Value::Dictionary(files2));
101
+            code_resources.insert("rules".to_string(), Value::Dictionary(rules));
102
+            code_resources.insert("rules2".to_string(), Value::Dictionary(rules2));
103
+
104
+            code_resources
105
+        };
106
+
107
+        code_resources
108
+    }
109
+
110
+    async fn sign(&self) {
111
+        let code_resources = self.code_resources().await;
112
+
113
+        let mut data = Vec::<u8>::new();
114
+        plist::to_writer_xml(&mut data, &code_resources).expect("TODO: panic message");
115
+        println!("{}", String::from_utf8(data).unwrap());
116
+    }
117
+}
118
+
119
+#[tokio::main]
120
+async fn main() {
121
+    Bundle {
122
+        path: "/home/dadoum/Téléchargements/YouTube.app/".into(),
123
+    }
124
+    .sign()
125
+    .await;
126
+}
... ...
@@ -0,0 +1,12 @@
1
+[package]
2
+name = "elf-loader"
3
+version = "2.0.0"
4
+edition = "2024"
5
+
6
+[dependencies]
7
+goblin = { version = "0.10", default-features = false, features = ["std", "endian_fd", "elf32", "elf64"] }
8
+memmap2 = "0.9.8"
9
+region = "3.0"
10
+log = "0.4"
11
+
12
+sysv64 = { path = "./sysv64" }
... ...
@@ -0,0 +1,126 @@
1
+use goblin::elf::{Sym, Symtab};
2
+use goblin::strtab::Strtab;
3
+use std::{mem, slice};
4
+
5
+pub trait Numeric: Copy + std::ops::BitAnd<Self, Output = Self> {}
6
+
7
+impl Numeric for u32 {}
8
+impl Numeric for u64 {}
9
+impl Numeric for usize {}
10
+
11
+#[allow(unused)]
12
+pub struct GnuHash<'a, T: Numeric> {
13
+    symindex: u32,
14
+    shift2: u32,
15
+    bloom_filter: &'a [T],
16
+    buckets: &'a [u32],
17
+    chains: &'a [u32],
18
+}
19
+
20
+impl<'a, T: Numeric> GnuHash<'a, T> {
21
+    pub unsafe fn from_raw_data(raw_data: &'a [u8]) -> Self {
22
+        assert!(raw_data.len() >= size_of::<[u32; 4]>());
23
+        let [nbuckets, symindex, maskwords, shift2] =
24
+            unsafe { (raw_data.as_ptr() as *const u32 as *const [u32; 4]).read() };
25
+
26
+        let hashtab: &'a [u8] = &raw_data[16..];
27
+
28
+        let (bloom_filter_bytes, hashtab) =
29
+            hashtab.split_at(maskwords as usize * mem::size_of::<T>());
30
+        let (buckets_bytes, chains_bytes) =
31
+            hashtab.split_at(nbuckets as usize * mem::size_of::<u32>());
32
+
33
+        unsafe {
34
+            Self {
35
+                symindex,
36
+                shift2,
37
+                bloom_filter: bloom_filter_bytes.transmute(),
38
+                buckets: buckets_bytes.transmute(),
39
+                chains: chains_bytes.transmute(),
40
+            }
41
+        }
42
+    }
43
+
44
+    fn lookup(&self, symbol: &str, hash: u32, dynsyms: &Symtab, dynstrtab: &Strtab) -> Option<Sym> {
45
+        const MASK_LOWEST_BIT: u32 = 0xffff_fffe;
46
+        let bucket = self.buckets[hash as usize % self.buckets.len()];
47
+
48
+        // Empty hash chain, symbol not present
49
+        if bucket < self.symindex {
50
+            return None;
51
+        }
52
+
53
+        // Walk the chain until the symbol is found or the chain is exhausted.
54
+        let chain_idx = bucket - self.symindex;
55
+        let hash = hash & MASK_LOWEST_BIT;
56
+        let chains = &self.chains.get((chain_idx as usize)..)?;
57
+        for (hash2, symb) in chains.iter().zip(dynsyms.iter().skip(bucket as usize)) {
58
+            if (hash == (hash2 & MASK_LOWEST_BIT)) && (symbol == &dynstrtab[symb.st_name]) {
59
+                return Some(symb);
60
+            }
61
+            // Chain ends with an element with the lowest bit set to 1.
62
+            if hash2 & 1 == 1 {
63
+                break;
64
+            }
65
+        }
66
+        None
67
+    }
68
+
69
+    // const ELFCLASS_BITS: u64 = (mem::size_of::<T>() * 8) as u64;
70
+    // const MASK: u64 = Self::ELFCLASS_BITS - 1;
71
+    //
72
+    // /// Check if symbol maybe is in the hash table, or definitely not in it.
73
+    // #[inline]
74
+    // fn check_maybe_match(&self, hash: u32) -> bool {
75
+    //     let hash = hash as u64;
76
+    //     let hash2: u64 = hash >> self.shift2;
77
+    //     // `x & (N - 1)` is equivalent to `x % N` iff `N = 2^y`.
78
+    //     let bitmask: u64 = 1 << (hash & (Self::MASK)) | 1 << (hash2 & Self::MASK);
79
+    //     let bloom_idx: u64 = (hash / Self::ELFCLASS_BITS) & (self.bloom_filter.len() as u64 - 1);
80
+    //     let bitmask_word: u64 = self.bloom_filter[bloom_idx as usize];
81
+    //     (bitmask_word & bitmask) == bitmask
82
+    // }
83
+
84
+    /// This function will not check if the passed `hash` is really
85
+    /// the hash of `symbol`
86
+    pub fn find_with_hash(
87
+        &self,
88
+        symbol: &str,
89
+        hash: u32,
90
+        dynsym: &Symtab,
91
+        dynstrtab: &Strtab,
92
+    ) -> Option<Sym> {
93
+        // HACK: Bloom filter has not been implemented.
94
+        // if self.check_maybe_match(hash) {
95
+        self.lookup(symbol, hash, dynsym, dynstrtab)
96
+        // } else {
97
+        //     None
98
+        // }
99
+    }
100
+
101
+    /// Given a symbol, a hash of that symbol, a dynamic string table and
102
+    /// a `dynstrtab` to cross-reference names, maybe returns a Sym.
103
+    pub(crate) fn find(&self, symbol: &str, dynsym: &Symtab, dynstrtab: &Strtab) -> Option<Sym> {
104
+        let hash = self::hash(symbol);
105
+        self.find_with_hash(symbol, hash, dynsym, dynstrtab)
106
+    }
107
+}
108
+
109
+pub fn hash(symbol: &str) -> u32 {
110
+    const HASH_SEED: u32 = 5381;
111
+    symbol.bytes().fold(HASH_SEED, |hash, b| {
112
+        hash.wrapping_mul(33).wrapping_add(u32::from(b))
113
+    })
114
+}
115
+
116
+trait Transmute<T: Sized> {
117
+    unsafe fn transmute(&self) -> &[T];
118
+}
119
+
120
+impl<T: Sized> Transmute<T> for [u8] {
121
+    unsafe fn transmute(&self) -> &[T] {
122
+        unsafe {
123
+            slice::from_raw_parts(self.as_ptr() as *const T, self.len() / mem::size_of::<T>())
124
+        }
125
+    }
126
+}
... ...
@@ -0,0 +1,276 @@
1
+use crate::elf_hash_table::GnuHash;
2
+use crate::elf_library::LibraryLoadingError::{IncompatibleArchitecture, IncompatiblePageLayout};
3
+use crate::*;
4
+use goblin::elf::program_header::{PF_R, PF_W, PF_X, PT_LOAD};
5
+use goblin::elf::section_header::SHT_GNU_HASH;
6
+use goblin::elf::{Elf, RelocSection};
7
+use log::{trace, warn};
8
+use memmap2::{MmapMut, MmapOptions};
9
+use std::error::Error;
10
+use std::fmt;
11
+use std::marker::PhantomData;
12
+use std::os::raw::c_void;
13
+
14
+#[allow(unused_imports)]
15
+use goblin::elf::header::{EM_386, EM_AARCH64, EM_ARM, EM_X86_64};
16
+
17
+pub struct Library<'data> {
18
+    elf: Elf<'data>,
19
+    gnu_hash_section: Option<GnuHash<'data, usize>>,
20
+    memory_map: MmapMut,
21
+}
22
+
23
+impl<'data> Library<'data> {
24
+    pub fn load<F: Fn(&str) -> Option<*const c_void>>(
25
+        data: &'data [u8],
26
+        symbols: F,
27
+    ) -> Result<Self, LibraryLoadingError> {
28
+        let elf = Elf::parse(data)?;
29
+
30
+        let (minimum_address, maximum_address) =
31
+            elf.program_headers
32
+                .iter()
33
+                .fold((usize::MAX, usize::MIN), |(min, max), header| {
34
+                    let start = region::page::floor(header.p_vaddr as *const u8) as usize;
35
+                    let end =
36
+                        region::page::ceil((header.p_vaddr + header.p_memsz) as *const u8) as usize;
37
+                    (usize::min(min, start), usize::max(max, end))
38
+                });
39
+
40
+        #[cfg(target_arch = "x86_64")]
41
+        if elf.header.e_machine != EM_X86_64 {
42
+            return Err(IncompatibleArchitecture(elf.header.e_machine));
43
+        }
44
+        #[cfg(target_arch = "aarch64")]
45
+        if elf.header.e_machine != EM_AARCH64 {
46
+            return Err(IncompatibleArchitecture(elf.header.e_machine));
47
+        }
48
+        #[cfg(target_arch = "x86")]
49
+        if elf.header.e_machine != EM_386 {
50
+            return Err(IncompatibleArchitecture(elf.header.e_machine));
51
+        }
52
+        #[cfg(target_arch = "arm")]
53
+        if elf.header.e_machine != EM_ARM {
54
+            return Err(IncompatibleArchitecture(elf.header.e_machine));
55
+        }
56
+        #[cfg(not(any(
57
+            target_arch = "x86_64",
58
+            target_arch = "aarch64",
59
+            target_arch = "x86",
60
+            target_arch = "arm"
61
+        )))]
62
+        warn!("Unknown host architecture.");
63
+
64
+        let mut memory_map = MmapOptions::new()
65
+            .len(maximum_address - minimum_address)
66
+            .map_anon()?;
67
+
68
+        // let page_size = region::page::size();
69
+        for header in &elf.program_headers {
70
+            if header.p_type != PT_LOAD {
71
+                continue;
72
+            }
73
+            // it's not p_align that we should check.
74
+            // if header.p_align < page_size as u64 {
75
+            //     // Technically, we could use the same tricks as elf-loader 1
76
+            //     // and try to load the library anyway, but it is hacky so for now
77
+            //     // it will just error out.
78
+            //     return Err(IncompatiblePageLayout(header.p_align));
79
+            // }
80
+
81
+            let header_data =
82
+                &data[header.p_offset as usize..(header.p_offset + header.p_filesz) as usize];
83
+            memory_map[header.p_vaddr as usize..(header.p_vaddr + header.p_filesz) as usize]
84
+                .copy_from_slice(header_data);
85
+        }
86
+
87
+        for header in &elf.program_headers {
88
+            if header.p_type != PT_LOAD {
89
+                continue;
90
+            }
91
+
92
+            let start = region::page::floor(&memory_map[header.p_vaddr as usize]);
93
+            let end = region::page::ceil(&memory_map[(header.p_vaddr + header.p_memsz) as usize]);
94
+
95
+            let mut flags = region::Protection::NONE.bits();
96
+            if header.p_flags & PF_R != 0 {
97
+                flags |= region::Protection::READ.bits();
98
+            }
99
+            if header.p_flags & PF_W != 0 {
100
+                flags |= region::Protection::WRITE.bits();
101
+            }
102
+            if header.p_flags & PF_X != 0 {
103
+                flags |= region::Protection::EXECUTE.bits();
104
+            }
105
+
106
+            unsafe {
107
+                trace!(
108
+                    "Protecting the section {:p} - {:p} with the protection {:03b}",
109
+                    start, end, flags
110
+                );
111
+                region::protect(
112
+                    start,
113
+                    end as usize - start as usize,
114
+                    region::Protection::from_bits_unchecked(flags),
115
+                )?;
116
+            }
117
+        }
118
+
119
+        let memory_map_ptr = memory_map.as_ptr() as usize;
120
+        let mut relocate = |relocation_section: &RelocSection| {
121
+            for relocation in relocation_section {
122
+                #[allow(unreachable_patterns)]
123
+                match relocation.r_type {
124
+                    goblin::elf::reloc::R_X86_64_RELATIVE
125
+                    | goblin::elf::reloc::R_386_RELATIVE
126
+                    | goblin::elf::reloc::R_AARCH64_RELATIVE
127
+                    | goblin::elf::reloc::R_ARM_RELATIVE => {
128
+                        let addend = relocation.r_addend.unwrap_or(0) as isize;
129
+                        let value = (memory_map_ptr.wrapping_add_signed(addend)).to_ne_bytes();
130
+
131
+                        let offset = relocation.r_offset as usize;
132
+
133
+                        memory_map[offset..offset + value.len()].copy_from_slice(&value);
134
+                    }
135
+
136
+                    goblin::elf::reloc::R_X86_64_GLOB_DAT
137
+                    | goblin::elf::reloc::R_386_GLOB_DAT
138
+                    | goblin::elf::reloc::R_AARCH64_GLOB_DAT
139
+                    | goblin::elf::reloc::R_ARM_GLOB_DAT
140
+                    | goblin::elf::reloc::R_X86_64_JUMP_SLOT
141
+                    | goblin::elf::reloc::R_386_JMP_SLOT
142
+                    | goblin::elf::reloc::R_AARCH64_JUMP_SLOT
143
+                    | goblin::elf::reloc::R_ARM_JUMP_SLOT
144
+                    | goblin::elf::reloc::R_X86_64_64
145
+                    | goblin::elf::reloc::R_386_32
146
+                    | goblin::elf::reloc::R_AARCH64_ABS64
147
+                    | goblin::elf::reloc::R_ARM_ABS32 => {
148
+                        let requested_symbol = elf
149
+                            .dynsyms
150
+                            .get(relocation.r_sym)
151
+                            .map(|sym| &elf.dynstrtab[sym.st_name])
152
+                            .and_then(&symbols)
153
+                            .unwrap_or(unknown_symbol as *const c_void)
154
+                            as usize;
155
+
156
+                        let addend = relocation.r_addend.unwrap_or(0) as isize;
157
+                        let value = requested_symbol.wrapping_add_signed(addend).to_ne_bytes();
158
+
159
+                        let offset = relocation.r_offset as usize;
160
+
161
+                        memory_map[offset..offset + value.len()].copy_from_slice(&value);
162
+                    }
163
+
164
+                    _ => {
165
+                        warn!("Unknown relocation: {:?}", relocation);
166
+                    }
167
+                }
168
+            }
169
+        };
170
+
171
+        relocate(&elf.dynrelas);
172
+        relocate(&elf.dynrels);
173
+
174
+        let gnu_hash_section = elf
175
+            .section_headers
176
+            .iter()
177
+            .find(|section| section.sh_type == SHT_GNU_HASH)
178
+            .map(|section| unsafe {
179
+                GnuHash::<usize>::from_raw_data(
180
+                    &data[section.sh_addr as usize
181
+                        ..section.sh_addr as usize + section.sh_size as usize],
182
+                )
183
+            });
184
+
185
+        Ok(Self {
186
+            elf,
187
+            gnu_hash_section, // TODO
188
+            memory_map,
189
+        })
190
+    }
191
+
192
+    pub fn get<'library, T: Copy>(
193
+        &'library self,
194
+        symbol_name: &str,
195
+    ) -> Option<Symbol<'library, 'data, T>> {
196
+        let sym = match &self.gnu_hash_section {
197
+            Some(hash_table) => {
198
+                hash_table.find(symbol_name, &self.elf.dynsyms, &self.elf.dynstrtab)
199
+            }
200
+            None => self
201
+                .elf
202
+                .dynsyms
203
+                .iter()
204
+                .find(|symbol| &self.elf.dynstrtab[symbol.st_name] == symbol_name),
205
+        };
206
+
207
+        sym.map(|sym| unsafe {
208
+            let value: *const T = std::mem::transmute(&&self.memory_map[sym.st_value as usize]);
209
+            Symbol {
210
+                ptr: *value,
211
+                library: PhantomData,
212
+            }
213
+        })
214
+    }
215
+}
216
+
217
+#[linux_cc]
218
+fn unknown_symbol() -> ! {
219
+    panic!("Unknown symbol called.");
220
+}
221
+
222
+#[derive(Debug)]
223
+pub enum LibraryLoadingError {
224
+    IncompatibleArchitecture(u16),
225
+    IncompatiblePageLayout(u64),
226
+    ElfLoadingError(goblin::error::Error),
227
+    IOError(std::io::Error),
228
+    MemoryProtectionError(region::Error),
229
+}
230
+
231
+impl std::fmt::Display for LibraryLoadingError {
232
+    #[inline]
233
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
234
+        match self {
235
+            IncompatibleArchitecture(architecture) => write!(
236
+                f,
237
+                "Incompatible architecture (e_machine = {})",
238
+                architecture
239
+            ),
240
+            IncompatiblePageLayout(page_size) => write!(
241
+                f,
242
+                "Incompatible page layout: The executable requires a page size aligned with {} bytes",
243
+                page_size
244
+            ),
245
+            LibraryLoadingError::ElfLoadingError(err) => write!(f, "Unable to load elf: {}", err),
246
+            LibraryLoadingError::IOError(err) => write!(f, "IO error: {}", err),
247
+            LibraryLoadingError::MemoryProtectionError(err) => {
248
+                write!(f, "Cannot protect the memory correctly: {}", err)
249
+            }
250
+        }
251
+    }
252
+}
253
+impl Error for LibraryLoadingError {}
254
+
255
+impl From<goblin::error::Error> for LibraryLoadingError {
256
+    fn from(err: goblin::error::Error) -> Self {
257
+        LibraryLoadingError::ElfLoadingError(err)
258
+    }
259
+}
260
+
261
+impl From<std::io::Error> for LibraryLoadingError {
262
+    fn from(err: std::io::Error) -> Self {
263
+        LibraryLoadingError::IOError(err)
264
+    }
265
+}
266
+
267
+impl From<region::Error> for LibraryLoadingError {
268
+    fn from(err: region::Error) -> Self {
269
+        LibraryLoadingError::MemoryProtectionError(err)
270
+    }
271
+}
272
+
273
+pub struct Symbol<'library, 'data, T: Copy> {
274
+    pub ptr: T,
275
+    library: PhantomData<&'library Library<'data>>,
276
+}
... ...
@@ -0,0 +1,4 @@
1
+mod elf_hash_table;
2
+pub mod elf_library;
3
+
4
+pub use sysv64::{sysv64 as linux_cc, sysv64_type as linux_fn};
... ...
@@ -0,0 +1,12 @@
1
+[package]
2
+name = "sysv64"
3
+version = "0.1.0"
4
+edition = "2021"
5
+
6
+[lib]
7
+proc-macro = true
8
+
9
+[dependencies]
10
+proc-macro2 = "1.0"
11
+quote = "1.0"
12
+syn = {  version = "2.0", features = ["full"] }
... ...
@@ -0,0 +1,4 @@
1
+fn main() {
2
+    let arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap();
3
+    println!("cargo:rustc-env=TARGET_ARCH={}", arch);
4
+}
... ...
@@ -0,0 +1,67 @@
1
+use proc_macro::TokenStream;
2
+use quote::quote;
3
+use syn::{parse_macro_input, ItemFn, Signature, TypeBareFn};
4
+
5
+#[proc_macro_attribute]
6
+pub fn sysv64(_attr: TokenStream, item: TokenStream) -> TokenStream {
7
+    let arch = env!("TARGET_ARCH");
8
+
9
+    let ItemFn {
10
+        attrs,
11
+        vis,
12
+        sig:
13
+            Signature {
14
+                constness,
15
+                asyncness,
16
+                unsafety,
17
+                abi: _,
18
+                fn_token,
19
+                ident,
20
+                generics,
21
+                paren_token: _,
22
+                inputs,
23
+                variadic,
24
+                output,
25
+            },
26
+        block,
27
+    } = parse_macro_input!(item as ItemFn);
28
+
29
+    if arch == "x86_64" {
30
+        quote! {
31
+            #(#attrs)*
32
+            #vis #constness #asyncness #unsafety extern "sysv64" #fn_token #ident #generics (#inputs) #variadic #output #block
33
+        }
34
+    } else {
35
+        quote! {
36
+            #(#attrs)*
37
+            #vis #constness #asyncness #unsafety extern "C" #fn_token #ident #generics (#inputs) #variadic #output #block
38
+        }
39
+    }.into()
40
+}
41
+
42
+#[proc_macro]
43
+pub fn sysv64_type(input: TokenStream) -> TokenStream {
44
+    let arch = env!("TARGET_ARCH");
45
+
46
+    let TypeBareFn {
47
+        lifetimes: _,
48
+        unsafety,
49
+        abi: _,
50
+        fn_token,
51
+        paren_token: _,
52
+        inputs,
53
+        variadic,
54
+        output,
55
+    } = parse_macro_input!(input as TypeBareFn);
56
+
57
+    if arch == "x86_64" {
58
+        quote! {
59
+            #unsafety extern "sysv64" #fn_token (#inputs) #variadic #output
60
+        }
61
+    } else {
62
+        quote! {
63
+            #unsafety extern "C" #fn_token (#inputs) #variadic #output
64
+        }
65
+    }
66
+    .into()
67
+}
... ...
@@ -0,0 +1,7 @@
1
+[package]
2
+name = "plist-macros"
3
+version = "0.1.0"
4
+edition = "2024"
5
+
6
+[dependencies]
7
+plist.workspace = true
... ...
@@ -0,0 +1,26 @@
1
+#[macro_export]
2
+macro_rules! dict {
3
+    {
4
+        $($key:literal : $value:expr),* $(,)?
5
+    } => {{
6
+        let mut dict = plist::Dictionary::new();
7
+        $(
8
+            dict.insert(
9
+                $key.to_string(),
10
+                plist::Value::from($value),
11
+            );
12
+        )*
13
+        dict
14
+    }};
15
+}
16
+
17
+#[macro_export]
18
+macro_rules! array {
19
+    [
20
+        $($value:expr),* $(,)?
21
+    ] => {{
22
+        vec![
23
+            $(plist::Value::from($value),)*
24
+        ]
25
+    }};
26
+}
... ...
@@ -0,0 +1,14 @@
1
+[package]
2
+name = "purple-builder"
3
+version = "0.1.0"
4
+edition = "2024"
5
+
6
+[dependencies]
7
+adi = { workspace = true }
8
+elf-loader = { workspace = true }
9
+env_logger = "0.11.8"
10
+
11
+# gpui = "0.2"
12
+# gpui-component = "0.3"
13
+# # adabraka-ui = "0.2"
14
+# anyhow = "1.0.100"
... ...
@@ -0,0 +1 @@
1
+pub const APP_NAME: &str = "Purple Builder";
... ...
@@ -0,0 +1,20 @@
1
+mod identity;
2
+mod main_window;
3
+mod welcome_window;
4
+
5
+use crate::main_window::MainWindow;
6
+use crate::welcome_window::WelcomeWindow;
7
+use gpui::*;
8
+use gpui_component::{ActiveTheme as _, Root, TitleBar, theme};
9
+
10
+fn main() {
11
+    let application = Application::new();
12
+
13
+    application.run(|cx: &mut App| {
14
+        gpui_component::init(cx);
15
+        // theme::init(cx);
16
+
17
+        //WelcomeWindow::new(cx).expect("Could not create WelcomeWindow.");
18
+        MainWindow::new(cx).expect("Could not create MainWindow.");
19
+    });
20
+}
... ...
@@ -0,0 +1,59 @@
1
+use gpui::{
2
+    App, AppContext, Bounds, Context, Entity, IntoElement, ParentElement, Render, Styled, Window,
3
+    WindowBounds, WindowHandle, WindowKind, WindowOptions, div, px, size,
4
+};
5
+use gpui_component::dock::{DockArea, DockAreaState};
6
+use gpui_component::menu::AppMenuBar;
7
+use gpui_component::{Root, StyledExt};
8
+
9
+pub struct MainWindow;
10
+
11
+impl MainWindow {
12
+    pub(crate) fn new(cx: &mut App) -> anyhow::Result<WindowHandle<Root>> {
13
+        let bounds = Bounds::centered(None, size(px(600.), px(400.)), cx);
14
+
15
+        let window_options = WindowOptions {
16
+            window_bounds: Some(WindowBounds::Windowed(bounds)),
17
+            #[cfg(not(target_os = "linux"))]
18
+            titlebar: Some(gpui_component::TitleBar::title_bar_options()),
19
+            window_min_size: Some(gpui::Size {
20
+                width: px(640.),
21
+                height: px(480.),
22
+            }),
23
+            #[cfg(target_os = "linux")]
24
+            window_background: gpui::WindowBackgroundAppearance::Transparent,
25
+            #[cfg(target_os = "linux")]
26
+            window_decorations: Some(gpui::WindowDecorations::Client),
27
+            kind: WindowKind::Normal,
28
+            ..Default::default()
29
+        };
30
+
31
+        cx.open_window(window_options, |win, cx| {
32
+            let welcome_view = MainView::new();
33
+
34
+            let view = cx.new(|_| welcome_view);
35
+            cx.new(|cx| Root::new(view.into(), win, cx))
36
+        })
37
+    }
38
+}
39
+
40
+struct MainView {
41
+    title_bar: Entity<AppMenuBar>,
42
+    dock_area: Entity<DockArea>,
43
+    last_layout_state: Option<DockAreaState>,
44
+}
45
+
46
+impl MainView {
47
+    fn new() -> Self {
48
+        Self {}
49
+    }
50
+}
51
+
52
+impl Render for MainView {
53
+    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
54
+        div()
55
+            .v_flex()
56
+            .size_full()
57
+            .child(div().flex().items_center().justify_center().child("Ready"))
58
+    }
59
+}
... ...
@@ -0,0 +1,179 @@
1
+use crate::identity::*;
2
+use gpui::*;
3
+use gpui_component::button::Button;
4
+use gpui_component::label::Label;
5
+use gpui_component::menu::AppMenuBar;
6
+use gpui_component::{Root, Theme, TitleBar, v_flex};
7
+
8
+pub struct WelcomeWindow;
9
+
10
+impl WelcomeWindow {
11
+    pub(crate) fn new(cx: &mut App) -> Result<WindowHandle<Root>> {
12
+        let bounds = Bounds::centered(None, size(px(600.), px(400.)), cx);
13
+
14
+        let window_options = WindowOptions {
15
+            window_bounds: Some(WindowBounds::Windowed(bounds)),
16
+            is_resizable: false,
17
+            // window_decorations: Some(WindowDecorations::Client),
18
+            // titlebar: Some(TitleBar::title_bar_options()),
19
+            ..Default::default()
20
+        };
21
+
22
+        cx.open_window(window_options, |win, cx| {
23
+            let welcome_view = WelcomeView::new();
24
+
25
+            let view = cx.new(|_| welcome_view);
26
+            cx.new(|cx| Root::new(view.into(), win, cx))
27
+        })
28
+    }
29
+}
30
+
31
+struct WelcomeView {
32
+    // recent_projects: Vec<String>,
33
+}
34
+
35
+impl WelcomeView {
36
+    pub(crate) fn new() -> Self {
37
+        Self {
38
+            // recent_projects: vec![
39
+            //     "MyApp".to_string(),
40
+            //     "MyGame".to_string(),
41
+            //     "MyLibrary".to_string(),
42
+            // ],
43
+        }
44
+    }
45
+}
46
+
47
+impl Render for WelcomeView {
48
+    fn render(&mut self, win: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
49
+        /*
50
+        let titlebar =
51
+            TitleBar::new()
52
+                .child(
53
+                    div()
54
+                        .flex()
55
+                        .items_center()
56
+                        .child(AppMenuBar::new(win, cx))
57
+                )
58
+                .child(
59
+                    div()
60
+                        .flex()
61
+                        .items_center()
62
+                        .justify_end()
63
+                        .gap_2()
64
+                        .child(win.window_title())
65
+                        // .child(Button::new("github")) // .icon(IconName::GitHub))
66
+                        // .child(Button::new("notifications")) // .icon(IconName::Bell))
67
+                );
68
+
69
+        // let state: Self = cx.;
70
+
71
+        /*
72
+        // Create editor state
73
+        let editor_state = cx.new(|cx| {
74
+            let mut state = EditorState::new(cx);
75
+            state.set_language(Language::Sql, cx);
76
+            state.set_content("SELECT * FROM users;", cx);
77
+            state
78
+        }); // */ // */
79
+
80
+        // Render editor
81
+
82
+        v_flex()
83
+            .size_full()
84
+            // .child(
85
+            //     div()
86
+            //         .child(
87
+            //             AppMenuBar::new(win, cx)
88
+            //         )
89
+            // )
90
+            .child(
91
+                div()
92
+                    .flex()
93
+                    .flex_row()
94
+                    .size_full()
95
+                    .p_4()
96
+                    .child(
97
+                        div()
98
+                            .flex()
99
+                            .flex_col()
100
+                            .size_full()
101
+                            .m_4()
102
+                            .gap_4()
103
+                            .child(
104
+                                div()
105
+                                    .flex()
106
+                                    .flex_col()
107
+                                    .gap_2()
108
+                                    .text_center()
109
+                                    .child(
110
+                                        Label::new(format!("Welcome to {}", APP_NAME))
111
+                                            .text_xl()
112
+                                            .font_weight(FontWeight::BOLD),
113
+                                    )
114
+                                    .child(
115
+                                        Label::new("Version 1.0.0")
116
+                                            .text_sm()
117
+                                            .text_color(rgb(0x666666)),
118
+                                    ),
119
+                            )
120
+                            .child(
121
+                                div()
122
+                                    .flex()
123
+                                    .flex_col()
124
+                                    .gap_2()
125
+                                    .child(
126
+                                        Button::new("create_project")
127
+                                            .text_left()
128
+                                            .label("Create New Project")
129
+                                            .on_click(|_, _, _| {
130
+                                                println!("Create New Project clicked")
131
+                                            }),
132
+                                    )
133
+                                    .child(
134
+                                        Button::new("open_project")
135
+                                            .text_left()
136
+                                            .label("Open Existing Project")
137
+                                            .on_click(|_, _, _| {
138
+                                                println!("Open Existing Project clicked")
139
+                                            }),
140
+                                    )
141
+                                    .child(
142
+                                        Button::new("clone_project")
143
+                                            .text_left()
144
+                                            .label("Clone Repository")
145
+                                            .on_click(|_, _, _| {
146
+                                                println!("Clone Repository clicked")
147
+                                            }),
148
+                                    ),
149
+                            ),
150
+                    )
151
+                    .child(
152
+                        div()
153
+                            .flex()
154
+                            .flex_col()
155
+                            .gap_2()
156
+                            .m_4()
157
+                            .child(
158
+                                Label::new("Recent Projects")
159
+                                    .text_lg()
160
+                                    .font_weight(FontWeight::SEMIBOLD),
161
+                            )
162
+                            .child(
163
+                                div().flex().flex_col().gap_1(), // .children(
164
+                                                                 //     state.recent_projects.iter().map(|project| {
165
+                                                                 //         div()
166
+                                                                 //             .p_2()
167
+                                                                 //             .rounded_md()
168
+                                                                 //             .hover(|s| s.bg(rgb(0xe5e5e5)))
169
+                                                                 //             .child(
170
+                                                                 //                 Label::new(project)
171
+                                                                 //                     .size_full()
172
+                                                                 //             )
173
+                                                                 //     })
174
+                                                                 // )
175
+                            ),
176
+                    ),
177
+            )
178
+    }
179
+}
... ...
@@ -0,0 +1,7 @@
1
+# This file is automatically @generated by Cargo.
2
+# It is not intended for manual editing.
3
+version = 3
4
+
5
+[[package]]
6
+name = "super-sideloader"
7
+version = "0.1.0"
... ...
@@ -0,0 +1,15 @@
1
+[package]
2
+name = "super-sideloader"
3
+version = "0.1.0"
4
+edition = "2021"
5
+
6
+[dependencies]
7
+adi.workspace = true
8
+adid-proxy.workspace = true
9
+android-coreadi.workspace = true
10
+apple-account.workspace = true
11
+elf-loader.workspace = true
12
+
13
+tokio.workspace = true
14
+libc = "0.2.176"
15
+env_logger = "0.11.8"
... ...
@@ -0,0 +1,112 @@
1
+use adi::proxy::ADIProxy;
2
+use android_coreadi::AndroidCoreADIProxy;
3
+use apple_account::bundle_information::{APPLE_TV_BUNDLE_INFORMATION, XCODE_BUNDLE_INFORMATION};
4
+use apple_account::device::Device;
5
+use apple_account::grandslam::AuthOutcome;
6
+use apple_account::http_session::AnisetteHTTPSession;
7
+use apple_account::{grandslam, itunes};
8
+use std::{env, fs};
9
+
10
+async fn grandslam_test(
11
+    proxy: &dyn ADIProxy,
12
+    apple_id: &str,
13
+    password: &str,
14
+) -> Result<(), Box<dyn std::error::Error>> {
15
+    // proxy.set_android_id("0123456789012345")?;
16
+    // proxy.set_provisioning_path(c"./adi_files")?;
17
+
18
+    let device = Device {
19
+        device_model: "MacBookPro13,2".to_string(),
20
+        operating_system_information: "macOS;15.6.1;24G90".to_string(),
21
+        device_uuid: "A8B31C86-359B-4D95-8950-BA5DD8FFC46F".to_string(),
22
+    };
23
+
24
+    // println!("{:#02X?}", proxy.get_all_provisioned_accounts());
25
+
26
+    let http_session = AnisetteHTTPSession::new(
27
+        grandslam::http_session(device, XCODE_BUNDLE_INFORMATION).await?,
28
+        proxy,
29
+    );
30
+
31
+    if !proxy.is_machine_provisioned(grandslam::GRANDSLAM_DSID)? {
32
+        grandslam::provision(&http_session).await?;
33
+    }
34
+
35
+    let auth_outcome = grandslam::login(&http_session, apple_id, password).await?;
36
+
37
+    match &auth_outcome {
38
+        AuthOutcome::Success(server_provided_data)
39
+        | AuthOutcome::SecondaryActionRequired(server_provided_data, _) => {
40
+            match grandslam::parse_tokens_from_server_provided_data(server_provided_data) {
41
+                Some((token, _)) => {
42
+                    let xcode_token =
43
+                        grandslam::get_app_token(&http_session, &token, "com.apple.gs.xcode.auth")
44
+                            .await?;
45
+                    println!("token: {:?}", xcode_token);
46
+                }
47
+                None => {
48
+                    let AuthOutcome::SecondaryActionRequired(_, _secondary_action) = auth_outcome
49
+                    else {
50
+                        panic!("Apple did not return tokens even though it didn't require any action from us??");
51
+                    };
52
+                    todo!()
53
+                }
54
+            }
55
+        }
56
+        AuthOutcome::AnisetteResyncRequired(_)
57
+        | AuthOutcome::AnisetteReprovisionRequired
58
+        | AuthOutcome::UrlSwitchingRequired(_) => todo!(),
59
+    }
60
+
61
+    Ok(())
62
+}
63
+
64
+async fn itunes_test(
65
+    proxy: &dyn ADIProxy,
66
+    apple_id: &str,
67
+    password: &str,
68
+) -> Result<(), Box<dyn std::error::Error>> {
69
+    let device = Device {
70
+        device_model: "Mac16,8".to_string(),
71
+        operating_system_information: "macOS;15.6.1;24G90".to_string(),
72
+        device_uuid: "A8B31C86-359B-4D95-8950-BA5DD8FFC46F".to_string(),
73
+    };
74
+
75
+    let http_session = AnisetteHTTPSession::new(
76
+        itunes::http_session(device, APPLE_TV_BUNDLE_INFORMATION).await?,
77
+        proxy,
78
+    );
79
+
80
+    let auth_outcome = itunes::login(&http_session, apple_id, password, 1).await?;
81
+
82
+    Ok(())
83
+}
84
+
85
+#[tokio::main]
86
+async fn main() -> Result<(), Box<dyn std::error::Error>> {
87
+    env_logger::init();
88
+
89
+    #[cfg(target_os = "macos")]
90
+    {
91
+        let proxy = adid_proxy::ADIdProxy::connect();
92
+        let code = proxy.generate_2fa_code(-2)?;
93
+        println!("{}", code);
94
+    }
95
+    let proxy = {
96
+        let core_adi_data = fs::read("nodistrib/lib/arm64-v8a/libCoreADI.so")?;
97
+        let proxy = AndroidCoreADIProxy::load_library(core_adi_data)?;
98
+
99
+        proxy.set_android_id("0123456789012345")?;
100
+        proxy.set_provisioning_path(c"./adi_files")?;
101
+
102
+        proxy
103
+    };
104
+
105
+    let apple_id = env::var("APPLE_ID")?;
106
+    let password = env::var("APPLE_PASSWORD")?;
107
+
108
+    grandslam_test(&proxy, &apple_id, &password).await?;
109
+    // itunes_test(&proxy, apple_id, password).await?;
110
+
111
+    Ok(())
112
+}
0 113