diff --git a/Cargo.lock b/Cargo.lock index b498827..077a69b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -180,7 +180,7 @@ version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbfd150b5dbdb988bcc8fb1fe787eb6b7ee6180ca24da683b61ea5405f3d43ff" dependencies = [ - "bindgen", + "bindgen 0.69.5", "cc", "cmake", "dunce", @@ -202,12 +202,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - [[package]] name = "base64" version = "0.21.7" @@ -235,7 +229,7 @@ dependencies = [ "bitflags 2.9.1", "cexpr", "clang-sys", - "itertools", + "itertools 0.12.1", "lazy_static", "lazycell", "log", @@ -243,12 +237,32 @@ dependencies = [ "proc-macro2", "quote", "regex", - "rustc-hash", + "rustc-hash 1.1.0", "shlex", "syn 2.0.104", "which", ] +[[package]] +name = "bindgen" +version = "0.72.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f72209734318d0b619a5e0f5129918b848c416e122a3c4ce054e03cb87b726f" +dependencies = [ + "bitflags 2.9.1", + "cexpr", + "clang-sys", + "itertools 0.13.0", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash 2.1.1", + "shlex", + "syn 2.0.104", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -273,7 +287,7 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array", + "generic-array 0.14.7", ] [[package]] @@ -282,31 +296,32 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" dependencies = [ - "generic-array", + "generic-array 0.14.7", ] [[package]] name = "botan" -version = "0.11.1" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d4c7647d67c53194fa0740404c6c508880aef2bfe99a9868dbb4b86f090377" +checksum = "f23e39f9dbdfec8b4b6ba8509c8202a573b5d52fe213349c385d86656c89d7b5" dependencies = [ "botan-sys", ] [[package]] name = "botan-src" -version = "0.30701.2" +version = "0.30900.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c4e1c7910f3b4712aed10e4259eca77e79ed84c1b023098c8eac596b993fc44" +checksum = "9bc24a437ed9a438eaace54677eead87931fcdf5cb9fef85567be2f82d8c5d92" [[package]] name = "botan-sys" -version = "0.11.1" +version = "1.20250506.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04285fa0c094cc9961fe435b1b279183db9394844ad82ce483aa6196c0e6da38" +checksum = "9a68b2bca80766adc60e9d88e99d958bba278a99ed616bf92b9d266c89dd2a9e" dependencies = [ "botan-src", + "cc", ] [[package]] @@ -315,12 +330,6 @@ version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - [[package]] name = "bytes" version = "1.10.1" @@ -347,9 +356,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.31" +version = "1.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3a42d84bb6b69d3a8b3eaacf0d88f179e1929695e1ad012b6cf64d9caaa5fd2" +checksum = "2352e5597e9c544d5e6d9c95190d5d27738ade584fa8db0a16e130e5c2b5296e" dependencies = [ "jobserver", "libc", @@ -381,7 +390,6 @@ dependencies = [ "iana-time-zone", "js-sys", "num-traits", - "serde", "wasm-bindgen", "windows-link", ] @@ -424,9 +432,9 @@ checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] name = "const-oid" -version = "0.7.1" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "constant_time_eq" @@ -474,7 +482,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array", + "generic-array 0.14.7", "typenum", ] @@ -492,11 +500,25 @@ checksum = "da692b8d1080ea3045efaab14434d40468c3d8657e42abddfffca87b428f4c1b" [[package]] name = "der" -version = "0.5.1" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6919815d73839e7ad218de758883aae3a257ba6759ce7a9992501efbb53d705c" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ "const-oid", + "der_derive", + "flagset", + "zeroize", +] + +[[package]] +name = "der_derive" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8034092389675178f570469e6c3b0465d3d30b4505c294a6550db47f3c17ad18" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", ] [[package]] @@ -630,6 +652,12 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "flagset" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7ac824320a75a52197e8f2d787f6a38b6718bb6897a35142d749af3c0e8f4fe" + [[package]] name = "flate2" version = "1.1.2" @@ -776,6 +804,15 @@ dependencies = [ "version_check", ] +[[package]] +name = "generic-array" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8c8444bc9d71b935156cc0ccab7f622180808af7867b1daae6547d773591703" +dependencies = [ + "typenum", +] + [[package]] name = "getrandom" version = "0.2.16" @@ -822,7 +859,7 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http", + "http 0.2.12", "indexmap", "slab", "tokio", @@ -832,9 +869,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.4" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" [[package]] name = "hex" @@ -871,6 +908,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http-body" version = "0.4.6" @@ -878,7 +926,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", - "http", + "http 0.2.12", "pin-project-lite", ] @@ -905,7 +953,7 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", + "http 0.2.12", "http-body", "httparse", "httpdate", @@ -925,7 +973,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", - "http", + "http 0.2.12", "hyper", "rustls 0.21.12", "tokio", @@ -974,25 +1022,24 @@ name = "icloud_auth" version = "0.1.0" dependencies = [ "aes", - "base64 0.13.1", + "base64 0.22.1", "botan", "cbc", - "chrono", "hmac", "num-bigint", "omnisette", "pbkdf2 0.11.0", "pkcs7", "plist", - "rand 0.8.5", + "rand 0.9.2", "reqwest", - "rustls 0.20.9", - "rustls-pemfile", + "rustls 0.23.31", + "rustls-pemfile 2.2.0", "serde", "serde_json", "sha2", "srp", - "thiserror 1.0.69", + "thiserror", "tokio", ] @@ -1095,7 +1142,7 @@ dependencies = [ "plist", "rustls 0.23.31", "serde", - "thiserror 2.0.12", + "thiserror", "tokio", "tokio-rustls 0.26.2", ] @@ -1138,7 +1185,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" dependencies = [ "block-padding", - "generic-array", + "generic-array 0.14.7", ] [[package]] @@ -1176,8 +1223,10 @@ dependencies = [ "plist", "serde", "sha1", + "thiserror", "uuid", "zip", + "zsign-rust", ] [[package]] @@ -1189,6 +1238,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.15" @@ -1497,7 +1555,7 @@ dependencies = [ "android-loader", "anyhow", "async-trait", - "base64 0.21.7", + "base64 0.22.1", "chrono", "dlopen2", "futures-util", @@ -1507,13 +1565,13 @@ dependencies = [ "objc", "objc-foundation", "plist", - "rand 0.8.5", + "rand 0.9.2", "remove-async-await", "reqwest", "serde", "serde_json", "sha2", - "thiserror 1.0.69", + "thiserror", "tokio-tungstenite", "uuid", ] @@ -1564,9 +1622,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-src" -version = "300.5.1+3.5.1" +version = "300.5.2+3.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "735230c832b28c000e3bc117119e6466a663ec73506bc0a9907ea4187508e42a" +checksum = "d270b79e2926f5150189d475bc7e9d2c69f9c4697b185fa917d5a32b792d21b4" dependencies = [ "cc", ] @@ -1637,12 +1695,13 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkcs7" -version = "0.3.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f7364e6d0e236473de91e042395d71e0e64715f99a60620b014a4a4c7d1619b" +checksum = "d79178be066405e0602bf3035946edef6b11b3f9dde46dfe5f8bfd7dea4b77e7" dependencies = [ "der", "spki", + "x509-cert", ] [[package]] @@ -1875,7 +1934,7 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", + "http 0.2.12", "http-body", "hyper", "hyper-rustls", @@ -1889,7 +1948,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "rustls 0.21.12", - "rustls-pemfile", + "rustls-pemfile 1.0.4", "serde", "serde_json", "serde_urlencoded", @@ -1904,25 +1963,10 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots", + "webpki-roots 0.25.4", "winreg", ] -[[package]] -name = "ring" -version = "0.16.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" -dependencies = [ - "cc", - "libc", - "once_cell", - "spin", - "untrusted 0.7.1", - "web-sys", - "winapi", -] - [[package]] name = "ring" version = "0.17.14" @@ -1933,7 +1977,7 @@ dependencies = [ "cfg-if", "getrandom 0.2.16", "libc", - "untrusted 0.9.0", + "untrusted", "windows-sys 0.52.0", ] @@ -1949,6 +1993,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + [[package]] name = "rustix" version = "0.38.44" @@ -1975,18 +2025,6 @@ dependencies = [ "windows-sys 0.60.2", ] -[[package]] -name = "rustls" -version = "0.20.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b80e3dec595989ea8510028f30c408a4630db12c9cbb8de34203b89d6577e99" -dependencies = [ - "log", - "ring 0.16.20", - "sct", - "webpki", -] - [[package]] name = "rustls" version = "0.21.12" @@ -1994,7 +2032,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", - "ring 0.17.14", + "ring", "rustls-webpki 0.101.7", "sct", ] @@ -2023,6 +2061,15 @@ dependencies = [ "base64 0.21.7", ] +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "rustls-pki-types" version = "1.12.0" @@ -2038,8 +2085,8 @@ version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "ring 0.17.14", - "untrusted 0.9.0", + "ring", + "untrusted", ] [[package]] @@ -2049,16 +2096,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc" dependencies = [ "aws-lc-rs", - "ring 0.17.14", + "ring", "rustls-pki-types", - "untrusted 0.9.0", + "untrusted", ] [[package]] name = "rustversion" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" @@ -2081,8 +2128,8 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "ring 0.17.14", - "untrusted 0.9.0", + "ring", + "untrusted", ] [[package]] @@ -2188,9 +2235,9 @@ checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" [[package]] name = "slab" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" [[package]] name = "smallvec" @@ -2218,18 +2265,13 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - [[package]] name = "spki" -version = "0.5.4" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d01ac02a6ccf3e07db148d2be087da624fea0221a16152ed01f0496a6b0a27" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" dependencies = [ + "base64ct", "der", ] @@ -2237,9 +2279,9 @@ dependencies = [ name = "srp" version = "0.6.0" dependencies = [ - "base64 0.21.7", + "base64 0.22.1", "digest", - "generic-array", + "generic-array 1.2.0", "lazy_static", "num-bigint", "subtle", @@ -2335,33 +2377,13 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "thiserror" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" -dependencies = [ - "thiserror-impl 1.0.69", -] - [[package]] name = "thiserror" version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" dependencies = [ - "thiserror-impl 2.0.12", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", + "thiserror-impl", ] [[package]] @@ -2465,17 +2487,18 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.20.1" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" +checksum = "489a59b6730eda1b0171fcfda8b121f4bee2b35cba8645ca35c5f7ba3eb736c1" dependencies = [ "futures-util", "log", - "rustls 0.21.12", + "rustls 0.23.31", + "rustls-pki-types", "tokio", - "tokio-rustls 0.24.1", + "tokio-rustls 0.26.2", "tungstenite", - "webpki-roots", + "webpki-roots 0.26.11", ] [[package]] @@ -2524,21 +2547,20 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "tungstenite" -version = "0.20.1" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" +checksum = "eadc29d668c91fcc564941132e17b28a7ceb2f3ebf0b9dae3e03fd7a6748eb0d" dependencies = [ - "byteorder", "bytes", "data-encoding", - "http", + "http 1.3.1", "httparse", "log", - "rand 0.8.5", - "rustls 0.21.12", + "rand 0.9.2", + "rustls 0.23.31", + "rustls-pki-types", "sha1", - "thiserror 1.0.69", - "url", + "thiserror", "utf-8", ] @@ -2554,12 +2576,6 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" -[[package]] -name = "untrusted" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" - [[package]] name = "untrusted" version = "0.9.0" @@ -2736,22 +2752,30 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webpki" -version = "0.22.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed63aea5ce73d0ff405984102c42de94fc55a6b75765d621c65262469b3c9b53" -dependencies = [ - "ring 0.17.14", - "untrusted 0.9.0", -] - [[package]] name = "webpki-roots" version = "0.25.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" +[[package]] +name = "webpki-roots" +version = "0.26.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" +dependencies = [ + "webpki-roots 1.0.2", +] + +[[package]] +name = "webpki-roots" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e8983c3ab33d6fb807cfcdad2491c4ea8cbc8ed839181c7dfd9c67c83e261b2" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "which" version = "4.4.2" @@ -3092,6 +3116,17 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" +[[package]] +name = "x509-cert" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1301e935010a701ae5f8655edc0ad17c44bad3ac5ce8c39185f75453b720ae94" +dependencies = [ + "const-oid", + "der", + "spki", +] + [[package]] name = "xmas-elf" version = "0.9.1" @@ -3270,6 +3305,17 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "zsign-rust" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9190123f81d18e157f6f3aab47f19b786538b158417f06ee9348c63163b23fca" +dependencies = [ + "bindgen 0.72.0", + "cc", + "openssl-sys", +] + [[package]] name = "zstd" version = "0.13.3" diff --git a/Cargo.toml b/Cargo.toml index f846b3f..324833f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,13 +9,15 @@ vendored-openssl = ["openssl/vendored"] vendored-botan = ["icloud_auth/vendored-botan"] [dependencies] -serde = { version = "1.0.219", features = ["derive"] } +serde = { version = "1", features = ["derive"] } plist = { version = "1.7.2" } icloud_auth = {path = "./apple-private-apis/icloud-auth" } uuid = "1.17.0" zip = "4.3.0" hex = "0.4.3" -sha1 = "0.10.6" +sha1 = "0.10" idevice = { version = "0.1.37", features = ["afc", "usbmuxd", "installation_proxy"] } openssl = "0.10.73" futures = "0.3.31" +zsign-rust = "0.1" +thiserror = "2.0.12" diff --git a/apple-private-apis/icloud-auth/Cargo.toml b/apple-private-apis/icloud-auth/Cargo.toml index d5210b5..1c78eb8 100644 --- a/apple-private-apis/icloud-auth/Cargo.toml +++ b/apple-private-apis/icloud-auth/Cargo.toml @@ -8,27 +8,26 @@ default = [] vendored-botan = ["botan/vendored"] [dependencies] -serde = { version = "1.0.219", features = ["derive"] } -serde_json = { version = "1.0.142" } -base64 = "0.13.1" +serde = { version = "1", features = ["derive"] } +serde_json = { version = "1" } +base64 = "0.22" srp = { version = "0.6.0", path = "./rustcrypto-srp" } -pbkdf2 = { version = "0.11.0" } -sha2 = { version = "0.10.6" } -rand = { version = "0.8.5" } -rustls = { version = "0.20.7" } -rustls-pemfile = { version = "1.0.1" } -plist = { version = "1.7.2" } +pbkdf2 = "0.11" +sha2 = "0.10" +rand = "0.9" +rustls = "0.23" +rustls-pemfile = "2.2" +plist = "1.7.2" hmac = "0.12.1" num-bigint = "0.4.3" cbc = { version = "0.1.2", features = ["std"] } aes = "0.8.2" -pkcs7 = "0.3.0" +pkcs7 = "0.4.1" reqwest = { version = "0.11.14", features = ["blocking", "json", "default-tls"] } omnisette = {path = "../omnisette", features = ["remote-anisette-v3"]} -thiserror = "1.0.58" +thiserror = "2" tokio = "1" -botan = { version = "0.11.1" } -chrono = { version = "0.4", features = ["serde"] } +botan = "0.12.0" [dev-dependencies] tokio = { version = "1", features = ["rt", "macros"] } diff --git a/apple-private-apis/icloud-auth/rustcrypto-srp/Cargo.toml b/apple-private-apis/icloud-auth/rustcrypto-srp/Cargo.toml index aeae6fc..63f7808 100644 --- a/apple-private-apis/icloud-auth/rustcrypto-srp/Cargo.toml +++ b/apple-private-apis/icloud-auth/rustcrypto-srp/Cargo.toml @@ -14,15 +14,15 @@ rust-version = "1.56" [dependencies] num-bigint = "0.4" -generic-array = "0.14" +generic-array = "1" digest = "0.10" lazy_static = "1.2" subtle = "2.4" -base64 = "0.21.0" +base64 = "0.22" [dev-dependencies] -hex-literal = "0.3" +hex-literal = "1" num-traits = "0.2" -rand = "0.8" -sha1 = "0.10.6" -sha2 = "0.10.8" +rand = "0.9" +sha1 = "0.10" +sha2 = "0.10" diff --git a/apple-private-apis/icloud-auth/src/anisette.rs b/apple-private-apis/icloud-auth/src/anisette.rs index 3349f91..d11601a 100644 --- a/apple-private-apis/icloud-auth/src/anisette.rs +++ b/apple-private-apis/icloud-auth/src/anisette.rs @@ -15,11 +15,7 @@ impl AnisetteData { let mut b = AnisetteHeaders::get_anisette_headers_provider(config.clone())?; let base_headers = b.provider.get_authentication_headers().await?; - Ok(AnisetteData { - base_headers, - generated_at: SystemTime::now(), - config, - }) + Ok(AnisetteData { base_headers, generated_at: SystemTime::now(), config }) } pub fn needs_refresh(&self) -> bool { @@ -69,7 +65,7 @@ impl AnisetteData { "X-Apple-App-Info".to_owned(), "com.apple.gs.xcode.auth".to_owned(), ); - headers.insert("X-Xcode-Version".to_owned(), "14.2 (14C18)".to_owned()); + headers.insert("X-Xcode-Version".to_owned(), "11.2 (11B41)".to_owned()); } if cpd { diff --git a/apple-private-apis/icloud-auth/src/client.rs b/apple-private-apis/icloud-auth/src/client.rs index 08c88e0..a69141f 100644 --- a/apple-private-apis/icloud-auth/src/client.rs +++ b/apple-private-apis/icloud-auth/src/client.rs @@ -1,5 +1,6 @@ use crate::{anisette::AnisetteData, Error}; use aes::cipher::block_padding::Pkcs7; +use base64::{engine::general_purpose, Engine}; use botan::Cipher; use cbc::cipher::{BlockDecryptMut, KeyIvInit}; use hmac::{Hmac, Mac}; @@ -269,7 +270,6 @@ impl AppleAccount { return Err(err_check.err().unwrap()); } - // --- D code logic starts here --- let encrypted_token = res .get("et") .ok_or(Error::Parse)? @@ -286,7 +286,7 @@ impl AppleAccount { "Encrypted token is in an unknown format.".to_string(), )); } - let iv = &encrypted_token[3..19]; // 16 bytes + let iv = &encrypted_token[3..19]; let ciphertext_and_tag = &encrypted_token[19..]; if sk.len() != 32 { @@ -296,8 +296,6 @@ impl AppleAccount { return Err(Error::Parse); } - // Botan AES-256/GCM decryption with 16-byte IV and 3-byte AAD - // true = encrypt, false = decrypt let mut cipher = Cipher::new("AES-256/GCM", botan::CipherDirection::Decrypt) .map_err(|_| Error::Parse)?; cipher.set_key(sk).map_err(|_| Error::Parse)?; @@ -357,14 +355,17 @@ impl AppleAccount { /// /// let anisette = AnisetteData::new(); /// let account = AppleAccount::login( - /// || ("test@waffle.me", "password") - /// || "123123", + /// || Ok(("test@waffle.me", "password")) + /// || Ok("123123"), /// anisette /// ); /// ``` /// Note: You would not provide the 2FA code like this, you would have to actually ask input for it. //TODO: add login_with_anisette and login, where login autodetcts anisette - pub async fn login_with_anisette Result<(String, String), String>, G: Fn() -> Result>( + pub async fn login_with_anisette< + F: Fn() -> Result<(String, String), String>, + G: Fn() -> Result, + >( appleid_closure: F, tfa_closure: G, anisette: AnisetteData, @@ -378,15 +379,25 @@ impl AppleAccount { match response { LoginState::NeedsDevice2FA => response = _self.send_2fa_to_devices().await?, LoginState::Needs2FAVerification => { - response = _self.verify_2fa(tfa_closure().map_err(|e| { - Error::AuthSrpWithMessage(0, format!("Failed to get 2FA code: {}", e)) - })?).await? + response = _self + .verify_2fa(tfa_closure().map_err(|e| { + Error::AuthSrpWithMessage(0, format!("Failed to get 2FA code: {}", e)) + })?) + .await? } LoginState::NeedsSMS2FA => response = _self.send_sms_2fa_to_devices(1).await?, LoginState::NeedsSMS2FAVerification(body) => { - response = _self.verify_sms_2fa(tfa_closure().map_err(|e| { - Error::AuthSrpWithMessage(0, format!("Failed to get SMS 2FA code: {}", e)) - })?, body).await? + response = _self + .verify_sms_2fa( + tfa_closure().map_err(|e| { + Error::AuthSrpWithMessage( + 0, + format!("Failed to get SMS 2FA code: {}", e), + ) + })?, + body, + ) + .await? } LoginState::NeedsLogin => { response = _self.login_email_pass(&username, &password).await? @@ -735,7 +746,7 @@ impl AppleAccount { let dsid = spd.get("adsid").unwrap().as_string().unwrap(); let token = spd.get("GsIdmsToken").unwrap().as_string().unwrap(); - let identity_token = base64::encode(format!("{}:{}", dsid, token)); + let identity_token = general_purpose::STANDARD.encode(format!("{}:{}", dsid, token)); let valid_anisette = self.get_anisette().await; diff --git a/apple-private-apis/icloud-auth/tests/auth_debug.rs b/apple-private-apis/icloud-auth/tests/auth_debug.rs index c68c392..aeb3b1c 100644 --- a/apple-private-apis/icloud-auth/tests/auth_debug.rs +++ b/apple-private-apis/icloud-auth/tests/auth_debug.rs @@ -1,8 +1,5 @@ -// use icloud_auth::ani -use std::sync::Arc; - +use base64::engine::{general_purpose, Engine}; use num_bigint::BigUint; -use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; use srp::{ client::{SrpClient, SrpClientVerifier}, @@ -11,15 +8,18 @@ use srp::{ #[cfg(test)] mod tests { + use super::*; #[test] fn auth_debug() { // not a real account - let bytes_a = base64::decode("XChHXELsQ+ljxTFbvRMUsGJxiDIlOh9f8e+JzoegmVcOdAXXtPNzkHpAbAgSjyA+vXrTA93+BUu8EJ9+4xZu9g==").unwrap(); + let bytes_a = general_purpose::STANDARD.decode("XChHXELsQ+ljxTFbvRMUsGJxiDIlOh9f8e+JzoegmVcOdAXXtPNzkHpAbAgSjyA+vXrTA93+BUu8EJ9+4xZu9g==").unwrap(); let username = "apple3@f1sh.me"; let password = "WaffleTest123"; - let salt = base64::decode("6fK6ailLUcp2kJswJVrKjQ==").unwrap(); + let salt = general_purpose::STANDARD + .decode("6fK6ailLUcp2kJswJVrKjQ==") + .unwrap(); let iters = 20832; let mut password_hasher = sha2::Sha256::new(); @@ -41,7 +41,9 @@ mod tests { // apub: N2XHuh/4P1urPoBvDocF0RCRIl2pliZYqg9p6wGH0nnJdckJPn3M00jEqoM4teqH03HjG1murdcZiNHb5YayufW//+asW01XB7nYIIVvGiUFLRypYITEKYWBQ6h2q02GaZspYJKy98V8Fwcvr0ri+al7zJo1X1aoRKINyjV5TywhhwmTleI1qJkf+JBRYKKqO1XFtOTpQsysWD3ZJdK3K78kSgT3q0kXE3oDRMiHPAO77GFJZErYTuvI6QPRbOgcrn+RKV6AsjR5tUQAoSGRdtibdZTAQijJg788qVg+OFVCNZoY9GYVxa+Ze1bPGdkkgCYicTE8iNFG9KlJ+QpKgQ== - let a_random = base64::decode("ywN1O32vmBogb5Fyt9M7Tn8bbzLtDDbcYgPFpSy8n9E=").unwrap(); + let a_random = general_purpose::STANDARD + .decode("ywN1O32vmBogb5Fyt9M7Tn8bbzLtDDbcYgPFpSy8n9E=") + .unwrap(); let client = SrpClient::::new(&G_2048); let a_pub_compute = @@ -49,14 +51,21 @@ mod tests { // expect it to be same to a_pub println!( "compute a_pub: {:?}", - base64::encode(&a_pub_compute.to_bytes_be()) + general_purpose::STANDARD.encode(&a_pub_compute.to_bytes_be()) ); - let b_pub = base64::decode("HlWxsRmNi/9DCGxYCoqCTfdSvpbx3mrgFLQfOsgf3Rojn7MQQN/g63PwlBghUcVVB4//yAaRRnz/VIByl8thA9AKuVZl8k52PAHKSh4e7TuXSeYCFr0+GYu8/hFdMDl42219uzSuOXuaKGVKq6hxEAf3n3uXXgQRkXWtLFJ5nn1wq/emf46hYAHzc/pYyvckAdh9WDCw95IXbzKD8LcPw/0ZQoydMuXgW2ZKZ52fiyEs94IZ7L5RLL7jY1nVdwtsp2fxeqiZ3DNmVZ2GdNrbJGT//160tyd2evtUtehr8ygXNzjWdjV0cc4+1F38ywSPFyieVzVTYzDywRllgo3A5A==").unwrap(); - println!("fixed b_pub: {:?}", base64::encode(&b_pub)); + let b_pub = general_purpose::STANDARD.decode("HlWxsRmNi/9DCGxYCoqCTfdSvpbx3mrgFLQfOsgf3Rojn7MQQN/g63PwlBghUcVVB4//yAaRRnz/VIByl8thA9AKuVZl8k52PAHKSh4e7TuXSeYCFr0+GYu8/hFdMDl42219uzSuOXuaKGVKq6hxEAf3n3uXXgQRkXWtLFJ5nn1wq/emf46hYAHzc/pYyvckAdh9WDCw95IXbzKD8LcPw/0ZQoydMuXgW2ZKZ52fiyEs94IZ7L5RLL7jY1nVdwtsp2fxeqiZ3DNmVZ2GdNrbJGT//160tyd2evtUtehr8ygXNzjWdjV0cc4+1F38ywSPFyieVzVTYzDywRllgo3A5A==").unwrap(); + println!( + "fixed b_pub: {:?}", + general_purpose::STANDARD.encode(&b_pub) + ); println!(""); - println!("salt: {:?} iterations: {:?}", base64::encode(&salt), iters); + println!( + "salt: {:?} iterations: {:?}", + general_purpose::STANDARD.encode(&salt), + iters + ); let verifier: SrpClientVerifier = SrpClient::::process_reply( &client, diff --git a/apple-private-apis/omnisette/Cargo.toml b/apple-private-apis/omnisette/Cargo.toml index 1c6dc12..d0fe13f 100644 --- a/apple-private-apis/omnisette/Cargo.toml +++ b/apple-private-apis/omnisette/Cargo.toml @@ -10,12 +10,12 @@ default = ["remote-anisette", "dep:remove-async-await"] remote-anisette-v3 = ["async", "dep:serde", "dep:serde_json", "dep:tokio-tungstenite", "dep:futures-util", "dep:chrono"] [dependencies] -base64 = "0.21" -hex = "0.4.3" +base64 = "0.22" +hex = "0.4" plist = "1.4" reqwest = { version = "0.11", default-features = false, features = ["blocking", "json", "rustls-tls", "gzip"] } -rand = "0.8" -sha2 = "0.10.8" +rand = "0.9" +sha2 = "0.10" uuid = { version = "1.3", features = [ "v4", "fast-rng", "macro-diagnostics" ] } android-loader = { git = "https://github.com/Dadoum/android-loader", branch = "bigger_pages" } libc = "0.2" @@ -23,11 +23,11 @@ log = "0.4" async-trait = { version = "0.1", optional = true } remove-async-await = { version = "1.0", optional = true } serde = { version = "1.0", features = ["derive"], optional = true } -serde_json = { version = "1.0.142", optional = true } -tokio-tungstenite = { version = "0.20.1", optional = true, features = ["rustls-tls-webpki-roots"] } +serde_json = { version = "1.0.115", optional = true } +tokio-tungstenite = { version = "0.27.0", optional = true, features = ["rustls-tls-webpki-roots"] } futures-util = { version = "0.3.28", optional = true } chrono = { version = "0.4.37", optional = true } -thiserror = "1.0.58" +thiserror = "2" anyhow = "1.0.81" [target.'cfg(target_os = "macos")'.dependencies] diff --git a/apple-private-apis/omnisette/src/adi_proxy.rs b/apple-private-apis/omnisette/src/adi_proxy.rs index 617af58..ccaa3b9 100644 --- a/apple-private-apis/omnisette/src/adi_proxy.rs +++ b/apple-private-apis/omnisette/src/adi_proxy.rs @@ -46,7 +46,7 @@ pub enum ADIError { ReqwestError(#[from] reqwest::Error), Base64Error(#[from] base64::DecodeError), InvalidHeaderValue(#[from] InvalidHeaderValue), - IOError(#[from] io::Error) + IOError(#[from] io::Error), } impl ADIError { @@ -95,7 +95,7 @@ pub struct RequestOTPData { } #[cfg_attr(feature = "async", async_trait::async_trait(?Send))] -pub trait ADIProxy: Send + Sync { +pub trait ADIProxy: Send + Sync { fn erase_provisioning(&mut self, ds_id: i64) -> Result<(), ADIError>; fn synchronize(&mut self, ds_id: i64, sim: &[u8]) -> Result; fn destroy_provisioning_session(&mut self, session: u32) -> Result<(), ADIError>; @@ -291,7 +291,9 @@ pub struct ADIProxyAnisetteProvider { impl ADIProxyAnisetteProvider { /// If you use this method, you are expected to set the identifier yourself. - pub fn without_identifier(adi_proxy: ProxyType) -> Result, ADIError> { + pub fn without_identifier( + adi_proxy: ProxyType, + ) -> Result, ADIError> { Ok(ADIProxyAnisetteProvider { adi_proxy }) } @@ -309,7 +311,7 @@ impl ADIProxyAnisetteProvider { if identifier_file.metadata()?.len() == IDENTIFIER_LENGTH as u64 { identifier_file.read_exact(&mut identifier)?; } else { - rand::thread_rng().fill_bytes(&mut identifier); + rand::rng().fill_bytes(&mut identifier); identifier_file.write_all(&identifier)?; } diff --git a/apple-private-apis/omnisette/src/lib.rs b/apple-private-apis/omnisette/src/lib.rs index af770c2..bfd2681 100644 --- a/apple-private-apis/omnisette/src/lib.rs +++ b/apple-private-apis/omnisette/src/lib.rs @@ -6,9 +6,9 @@ use crate::adi_proxy::{ADIProxyAnisetteProvider, ConfigurableADIProxy}; use crate::anisette_headers_provider::AnisetteHeadersProvider; -use adi_proxy::ADIError; use std::io; use std::path::PathBuf; +use adi_proxy::ADIError; use thiserror::Error; pub mod adi_proxy; @@ -58,7 +58,7 @@ pub enum AnisetteError { #[error("Missing Libraries")] MissingLibraries, #[error("{0}")] - Anyhow(#[from] anyhow::Error), + Anyhow(#[from] anyhow::Error) } pub const DEFAULT_ANISETTE_URL: &str = "https://ani.f1sh.me/"; @@ -85,7 +85,7 @@ impl AnisetteConfiguration { anisette_url: DEFAULT_ANISETTE_URL.to_string(), anisette_url_v3: DEFAULT_ANISETTE_URL_V3.to_string(), configuration_path: PathBuf::new(), - macos_serial: "0".to_string(), + macos_serial: "0".to_string() } } @@ -157,15 +157,10 @@ impl AnisetteHeaders { #[cfg(feature = "remote-anisette-v3")] return Ok(AnisetteHeadersProviderRes::remote(Box::new( - remote_anisette_v3::RemoteAnisetteProviderV3::new( - configuration.anisette_url_v3, - configuration.configuration_path.clone(), - configuration.macos_serial.clone(), - ), + remote_anisette_v3::RemoteAnisetteProviderV3::new(configuration.anisette_url_v3, configuration.configuration_path.clone(), configuration.macos_serial.clone()), ))); #[cfg(feature = "remote-anisette")] - #[allow(unreachable_code)] return Ok(AnisetteHeadersProviderRes::remote(Box::new( remote_anisette::RemoteAnisetteProvider::new(configuration.anisette_url), ))); diff --git a/apple-private-apis/omnisette/src/remote_anisette_v3.rs b/apple-private-apis/omnisette/src/remote_anisette_v3.rs index e41573c..5f30bfc 100644 --- a/apple-private-apis/omnisette/src/remote_anisette_v3.rs +++ b/apple-private-apis/omnisette/src/remote_anisette_v3.rs @@ -99,7 +99,7 @@ pub struct AnisetteState { impl Default for AnisetteState { fn default() -> Self { AnisetteState { - keychain_identifier: rand::thread_rng().gen::<[u8; 16]>(), + keychain_identifier: rand::rng().random::<[u8; 16]>(), adi_pb: None, } } @@ -211,7 +211,7 @@ impl AnisetteClient { .header("X-Apple-I-MD-LU", encode_hex(&state.md_lu())) .header("X-Mme-Device-Id", state.device_id()) .header("X-Apple-I-Client-Time", dt.format("%+").to_string()) - .header("X-Apple-I-TimeZone", "EDT") + .header("X-Apple-I-TimeZone", "UTC") .header("X-Apple-Locale", "en_US") } @@ -352,7 +352,7 @@ impl AnisetteClient { identifier: base64_encode(&state.keychain_identifier), }; connection - .send(Message::Text(serde_json::to_string(&identifier)?)) + .send(Message::Text(serde_json::to_string(&identifier)?.into())) .await?; } ProvisionInput::GiveStartProvisioningData => { @@ -390,7 +390,7 @@ impl AnisetteClient { spim: spim.to_string(), }; connection - .send(Message::Text(serde_json::to_string(&spim)?)) + .send(Message::Text(serde_json::to_string(&spim)?.into())) .await?; } ProvisionInput::GiveEndProvisioningData { cpim } => { @@ -427,7 +427,9 @@ impl AnisetteClient { tk: response.get("tk").unwrap().as_string().unwrap(), }; connection - .send(Message::Text(serde_json::to_string(&end_provisioning)?)) + .send(Message::Text( + serde_json::to_string(&end_provisioning)?.into(), + )) .await?; } ProvisionInput::ProvisioningSuccess { adi_pb } => { diff --git a/apple-private-apis/omnisette/src/store_services_core.rs b/apple-private-apis/omnisette/src/store_services_core.rs index 5782c03..b81d223 100644 --- a/apple-private-apis/omnisette/src/store_services_core.rs +++ b/apple-private-apis/omnisette/src/store_services_core.rs @@ -66,11 +66,16 @@ pub struct StoreServicesCoreADIProxy<'lt> { } impl StoreServicesCoreADIProxy<'_> { - pub fn new<'lt>(library_path: &PathBuf) -> Result, AnisetteError> { + pub fn new<'lt>( + library_path: &PathBuf, + ) -> Result, AnisetteError> { Self::with_custom_provisioning_path(library_path, library_path) } - pub fn with_custom_provisioning_path<'lt>(library_path: &PathBuf, provisioning_path: &PathBuf) -> Result, AnisetteError> { + pub fn with_custom_provisioning_path<'lt>( + library_path: &PathBuf, + provisioning_path: &PathBuf, + ) -> Result, AnisetteError> { // Should be safe if the library is correct. unsafe { LoaderHelpers::setup_hooks(); @@ -104,12 +109,8 @@ impl StoreServicesCoreADIProxy<'_> { .ok_or(AnisetteError::InvalidLibraryFormat)?, ); - let path = CString::new( - native_library_path - .to_str() - .ok_or(AnisetteError::Misc)?, - ) - .unwrap(); + let path = + CString::new(native_library_path.to_str().ok_or(AnisetteError::Misc)?).unwrap(); assert_eq!((adi_load_library_with_path)(path.as_ptr() as *const u8), 0); let adi_set_android_id = store_services_core @@ -163,9 +164,7 @@ impl StoreServicesCoreADIProxy<'_> { adi_otp_request: std::mem::transmute(adi_otp_request), }; - proxy.set_provisioning_path( - provisioning_path.to_str().ok_or(AnisetteError::Misc)?, - )?; + proxy.set_provisioning_path(provisioning_path.to_str().ok_or(AnisetteError::Misc)?)?; Ok(proxy) } @@ -370,7 +369,7 @@ unsafe fn __errno_location() -> *mut i32 { #[sysv64] fn arc4random() -> u32 { - rand::thread_rng().gen() + rand::rng().random() } #[sysv64] @@ -412,10 +411,10 @@ impl LoaderHelpers { #[cfg(test)] mod tests { + use crate::AnisetteError; use crate::{AnisetteConfiguration, AnisetteHeaders}; use log::info; use std::path::PathBuf; - use crate::AnisetteError; #[cfg(not(feature = "async"))] #[test] @@ -436,7 +435,6 @@ mod tests { #[cfg(feature = "async")] #[tokio::test] async fn fetch_anisette_ssc_async() -> Result<(), AnisetteError> { - crate::tests::init_logger(); let mut provider = AnisetteHeaders::get_ssc_anisette_headers_provider( diff --git a/src/certificate.rs b/src/certificate.rs index 4d23955..dd4b449 100644 --- a/src/certificate.rs +++ b/src/certificate.rs @@ -32,7 +32,7 @@ impl CertificateIdentity { let hash_string = hex::encode(hasher.finalize()).to_lowercase(); let key_path = configuration_path.join("keys").join(hash_string); fs::create_dir_all(&key_path) - .map_err(|e| Error::Certificate(format!("Failed to create key directory: {}", e)))?; + .map_err(|e| Error::Filesystem(format!("Failed to create key directory: {}", e)))?; let key_file = key_path.join("key.pem"); let cert_file = key_path.join("cert.pem"); @@ -54,7 +54,7 @@ impl CertificateIdentity { .private_key_to_pem_pkcs8() .map_err(|e| Error::Certificate(format!("Failed to encode private key: {}", e)))?; fs::write(&key_file, pem_data) - .map_err(|e| Error::Certificate(format!("Failed to save key file: {}", e)))?; + .map_err(|e| Error::Filesystem(format!("Failed to save key file: {}", e)))?; key }; @@ -75,7 +75,7 @@ impl CertificateIdentity { Error::Certificate(format!("Failed to encode certificate to PEM: {}", e)) })?; fs::write(&cert_identity.cert_file, cert_pem).map_err(|e| { - Error::Certificate(format!("Failed to save certificate file: {}", e)) + Error::Filesystem(format!("Failed to save certificate file: {}", e)) })?; return Ok(cert_identity); @@ -200,7 +200,7 @@ impl CertificateIdentity { Error::Certificate(format!("Failed to encode certificate to PEM: {}", e)) })?; fs::write(&self.cert_file, cert_pem) - .map_err(|e| Error::Certificate(format!("Failed to save certificate file: {}", e)))?; + .map_err(|e| Error::Filesystem(format!("Failed to save certificate file: {}", e)))?; self.certificate = Some(certificate); diff --git a/src/developer_session.rs b/src/developer_session.rs index 3d3fb49..a3ed585 100644 --- a/src/developer_session.rs +++ b/src/developer_session.rs @@ -56,7 +56,7 @@ impl DeveloperSession { if let ICloudError::AuthSrpWithMessage(code, message) = e { Error::DeveloperSession(code, format!("Developer request failed: {}", message)) } else { - Error::Generic + Error::Generic("Failed to send developer request".to_string()) } })?; @@ -85,20 +85,22 @@ impl DeveloperSession { let teams = response .get("teams") .and_then(|v| v.as_array()) - .ok_or(Error::Parse)?; + .ok_or(Error::Parse("teams".to_string()))?; let mut result = Vec::new(); for team in teams { - let dict = team.as_dictionary().ok_or(Error::Parse)?; + let dict = team + .as_dictionary() + .ok_or(Error::Parse("team".to_string()))?; let name = dict .get("name") .and_then(|v| v.as_string()) - .ok_or(Error::Parse)? + .ok_or(Error::Parse("name".to_string()))? .to_string(); let team_id = dict .get("teamId") .and_then(|v| v.as_string()) - .ok_or(Error::Parse)? + .ok_or(Error::Parse("teamId".to_string()))? .to_string(); result.push(DeveloperTeam { _name: name, @@ -140,25 +142,27 @@ impl DeveloperSession { let devices = response .get("devices") .and_then(|v| v.as_array()) - .ok_or(Error::Parse)?; + .ok_or(Error::Parse("devices".to_string()))?; let mut result = Vec::new(); for device in devices { - let dict = device.as_dictionary().ok_or(Error::Parse)?; + let dict = device + .as_dictionary() + .ok_or(Error::Parse("device".to_string()))?; let device_id = dict .get("deviceId") .and_then(|v| v.as_string()) - .ok_or(Error::Parse)? + .ok_or(Error::Parse("deviceId".to_string()))? .to_string(); let name = dict .get("name") .and_then(|v| v.as_string()) - .ok_or(Error::Parse)? + .ok_or(Error::Parse("name".to_string()))? .to_string(); let device_number = dict .get("deviceNumber") .and_then(|v| v.as_string()) - .ok_or(Error::Parse)? + .ok_or(Error::Parse("deviceNumber".to_string()))? .to_string(); result.push(DeveloperDevice { _device_id: device_id, @@ -187,22 +191,22 @@ impl DeveloperSession { let device_dict = response .get("device") .and_then(|v| v.as_dictionary()) - .ok_or(Error::Parse)?; + .ok_or(Error::Parse("device".to_string()))?; let device_id = device_dict .get("deviceId") .and_then(|v| v.as_string()) - .ok_or(Error::Parse)? + .ok_or(Error::Parse("deviceId".to_string()))? .to_string(); let name = device_dict .get("name") .and_then(|v| v.as_string()) - .ok_or(Error::Parse)? + .ok_or(Error::Parse("name".to_string()))? .to_string(); let device_number = device_dict .get("deviceNumber") .and_then(|v| v.as_string()) - .ok_or(Error::Parse)? + .ok_or(Error::Parse("deviceNumber".to_string()))? .to_string(); Ok(DeveloperDevice { @@ -226,25 +230,27 @@ impl DeveloperSession { let certs = response .get("certificates") .and_then(|v| v.as_array()) - .ok_or(Error::Parse)?; + .ok_or(Error::Parse("certificates".to_string()))?; let mut result = Vec::new(); for cert in certs { - let dict = cert.as_dictionary().ok_or(Error::Parse)?; + let dict = cert + .as_dictionary() + .ok_or(Error::Parse("certificate".to_string()))?; let name = dict .get("name") .and_then(|v| v.as_string()) - .ok_or(Error::Parse)? + .ok_or(Error::Parse("name".to_string()))? .to_string(); let certificate_id = dict .get("certificateId") .and_then(|v| v.as_string()) - .ok_or(Error::Parse)? + .ok_or(Error::Parse("certificateId".to_string()))? .to_string(); let serial_number = dict .get("serialNumber") .and_then(|v| v.as_string()) - .ok_or(Error::Parse)? + .ok_or(Error::Parse("serialNumber".to_string()))? .to_string(); let machine_name = dict .get("machineName") @@ -254,7 +260,7 @@ impl DeveloperSession { let cert_content = dict .get("certContent") .and_then(|v| v.as_data()) - .ok_or(Error::Parse)? + .ok_or(Error::Parse("certContent".to_string()))? .to_vec(); result.push(DevelopmentCertificate { @@ -309,11 +315,11 @@ impl DeveloperSession { let cert_dict = response .get("certRequest") .and_then(|v| v.as_dictionary()) - .ok_or(Error::Parse)?; + .ok_or(Error::Parse("certRequest".to_string()))?; let id = cert_dict .get("certRequestId") .and_then(|v| v.as_string()) - .ok_or(Error::Parse)? + .ok_or(Error::Parse("certRequestId".to_string()))? .to_string(); Ok(id) @@ -333,35 +339,37 @@ impl DeveloperSession { let app_ids = response .get("appIds") .and_then(|v| v.as_array()) - .ok_or(Error::Parse)?; + .ok_or(Error::Parse("appIds".to_string()))?; let mut result = Vec::new(); for app_id in app_ids { - let dict = app_id.as_dictionary().ok_or(Error::Parse)?; + let dict = app_id + .as_dictionary() + .ok_or(Error::Parse("appId".to_string()))?; let name = dict .get("name") .and_then(|v| v.as_string()) - .ok_or(Error::Parse)? + .ok_or(Error::Parse("name".to_string()))? .to_string(); let app_id_id = dict .get("appIdId") .and_then(|v| v.as_string()) - .ok_or(Error::Parse)? + .ok_or(Error::Parse("appIdId".to_string()))? .to_string(); let identifier = dict .get("identifier") .and_then(|v| v.as_string()) - .ok_or(Error::Parse)? + .ok_or(Error::Parse("identifier".to_string()))? .to_string(); let features = dict .get("features") .and_then(|v| v.as_dictionary()) - .ok_or(Error::Parse)?; + .ok_or(Error::Parse("features".to_string()))?; let expiration_date = if dict.contains_key("expirationDate") { Some( dict.get("expirationDate") .and_then(|v| v.as_date()) - .ok_or(Error::Parse)?, + .ok_or(Error::Parse("expirationDate".to_string()))?, ) } else { None @@ -379,11 +387,11 @@ impl DeveloperSession { let max_quantity = response .get("maxQuantity") .and_then(|v| v.as_unsigned_integer()) - .ok_or(Error::Parse)?; + .ok_or(Error::Parse("maxQuantity".to_string()))?; let available_quantity = response .get("availableQuantity") .and_then(|v| v.as_unsigned_integer()) - .ok_or(Error::Parse)?; + .ok_or(Error::Parse("availableQuantity".to_string()))?; Ok(ListAppIdsResponse { app_ids: result, @@ -436,11 +444,11 @@ impl DeveloperSession { let cert_dict = response .get("appId") .and_then(|v| v.as_dictionary()) - .ok_or(Error::Parse)?; + .ok_or(Error::Parse("appId".to_string()))?; let feats = cert_dict .get("features") .and_then(|v| v.as_dictionary()) - .ok_or(Error::Parse)?; + .ok_or(Error::Parse("features".to_string()))?; Ok(feats.clone()) } @@ -475,25 +483,27 @@ impl DeveloperSession { let app_groups = response .get("applicationGroupList") .and_then(|v| v.as_array()) - .ok_or(Error::Parse)?; + .ok_or(Error::Parse("applicationGroupList".to_string()))?; let mut result = Vec::new(); for app_group in app_groups { - let dict = app_group.as_dictionary().ok_or(Error::Parse)?; + let dict = app_group + .as_dictionary() + .ok_or(Error::Parse("applicationGroup".to_string()))?; let application_group = dict .get("applicationGroup") .and_then(|v| v.as_string()) - .ok_or(Error::Parse)? + .ok_or(Error::Parse("applicationGroup".to_string()))? .to_string(); let name = dict .get("name") .and_then(|v| v.as_string()) - .ok_or(Error::Parse)? + .ok_or(Error::Parse("name".to_string()))? .to_string(); let identifier = dict .get("identifier") .and_then(|v| v.as_string()) - .ok_or(Error::Parse)? + .ok_or(Error::Parse("identifier".to_string()))? .to_string(); result.push(ApplicationGroup { @@ -526,21 +536,21 @@ impl DeveloperSession { let app_group_dict = response .get("applicationGroup") .and_then(|v| v.as_dictionary()) - .ok_or(Error::Parse)?; + .ok_or(Error::Parse("applicationGroup".to_string()))?; let application_group = app_group_dict .get("applicationGroup") .and_then(|v| v.as_string()) - .ok_or(Error::Parse)? + .ok_or(Error::Parse("applicationGroup".to_string()))? .to_string(); let name = app_group_dict .get("name") .and_then(|v| v.as_string()) - .ok_or(Error::Parse)? + .ok_or(Error::Parse("name".to_string()))? .to_string(); let identifier = app_group_dict .get("identifier") .and_then(|v| v.as_string()) - .ok_or(Error::Parse)? + .ok_or(Error::Parse("identifier".to_string()))? .to_string(); Ok(ApplicationGroup { @@ -593,21 +603,21 @@ impl DeveloperSession { let profile = response .get("provisioningProfile") .and_then(|v| v.as_dictionary()) - .ok_or(Error::Parse)?; + .ok_or(Error::Parse("provisioningProfile".to_string()))?; let name = profile .get("name") .and_then(|v| v.as_string()) - .ok_or(Error::Parse)? + .ok_or(Error::Parse("name".to_string()))? .to_string(); let provisioning_profile_id = profile .get("provisioningProfileId") .and_then(|v| v.as_string()) - .ok_or(Error::Parse)? + .ok_or(Error::Parse("provisioningProfileId".to_string()))? .to_string(); let encoded_profile = profile .get("encodedProfile") .and_then(|v| v.as_data()) - .ok_or(Error::Parse)? + .ok_or(Error::Parse("encodedProfile".to_string()))? .to_vec(); Ok(ProvisioningProfile { diff --git a/src/lib.rs b/src/lib.rs index 13a5335..93c8176 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,12 +10,39 @@ pub use developer_session::{ DevelopmentCertificate, ListAppIdsResponse, ProvisioningProfile, }; -#[derive(Debug)] +use thiserror::Error as ThisError; + +#[derive(Debug, Clone, ThisError)] pub enum Error { + #[error("Authentication error {0}: {1}")] Auth(i64, String), + #[error("Developer session error {0}: {1}")] DeveloperSession(i64, String), - Generic, - Parse, + #[error("Error: {0}")] + Generic(String), + #[error("Failed to parse: {0}")] + Parse(String), + #[error("Invalid bundle: {0}")] InvalidBundle(String), + #[error("Certificate error: {0}")] Certificate(String), + #[error("Failed to use files: {0}")] + Filesystem(String), +} + +pub trait SideloadLogger { + async fn log(&self, message: &str); + async fn error(&self, error: &Error); +} + +pub struct DefaultLogger; + +impl SideloadLogger for DefaultLogger { + async fn log(&self, message: &str) { + println!("{message}"); + } + + async fn error(&self, error: &Error) { + eprintln!("Error: {}", error); + } } diff --git a/src/sideload.rs b/src/sideload.rs index 2152c5b..2a6af2c 100644 --- a/src/sideload.rs +++ b/src/sideload.rs @@ -1,85 +1,81 @@ // This file was made using https://github.com/Dadoum/Sideloader as a reference. -use crate::Error; +use zsign_rust::ZSignOptions; + +use crate::application::Application; +use crate::{Error, SideloadLogger}; use crate::{ certificate::CertificateIdentity, - developer_session::DeveloperDeviceType, + developer_session::{DeveloperDeviceType, DeveloperSession}, device::{DeviceInfo, install_app}, }; use std::{io::Write, path::PathBuf}; +fn error_and_return(logger: &impl SideloadLogger, error: Error) -> Result<(), Error> { + logger.error(&error); + Err(error) +} + pub async fn sideload_app( - handle: &tauri::AppHandle, - window: &tauri::Window, - anisette_server: String, - device: DeviceInfo, + logger: impl SideloadLogger, + dev_session: &DeveloperSession, + device: &DeviceInfo, app_path: PathBuf, ) -> Result<(), Error> { if device.uuid.is_empty() { - return emit_error_and_return(window, "No device selected"); + return error_and_return(&logger, Error::Generic("No device selected".to_string())); } - let dev_session = match crate::sideloader::apple::get_developer_session( - &handle, - window, - anisette_server.clone(), - ) - .await - { - Ok(acc) => acc, - Err(e) => { - return emit_error_and_return( - window, - &format!("Failed to login to Apple account: {:?}", e), - ); - } - }; + let team = match dev_session.get_team().await { Ok(t) => t, Err(e) => { - return emit_error_and_return(window, &format!("Failed to get team: {:?}", e)); + return error_and_return(&logger, e); } }; - window - .emit("build-output", "Successfully retrieved team".to_string()) - .ok(); + + logger.log("Successfully retrieved team"); + ensure_device_registered(&dev_session, window, &team, &device).await?; let config_dir = handle.path().app_config_dir().map_err(|e| e.to_string())?; let cert = match CertificateIdentity::new(config_dir, &dev_session, get_apple_email()).await { Ok(c) => c, Err(e) => { - return emit_error_and_return(window, &format!("Failed to get certificate: {:?}", e)); + return error_and_return(&logger, e); } }; - window - .emit( - "build-output", - "Certificate acquired succesfully".to_string(), - ) - .ok(); + + logger.log("Successfully acquired certificate"); + let mut list_app_id_response = match dev_session .list_app_ids(DeveloperDeviceType::Ios, &team) .await { Ok(ids) => ids, Err(e) => { - return emit_error_and_return(window, &format!("Failed to list app IDs: {:?}", e)); + return error_and_return(&logger, e); } }; - let mut app = crate::sideloader::application::Application::new(app_path); + let mut app = Application::new(app_path); let is_sidestore = app.bundle.bundle_identifier().unwrap_or("") == "com.SideStore.SideStore"; let main_app_bundle_id = match app.bundle.bundle_identifier() { Some(id) => id.to_string(), None => { - return emit_error_and_return(window, "No bundle identifier found in IPA"); + return error_and_return( + &logger, + Error::InvalidBundle("No bundle identifier found in IPA".to_string()), + ); } }; let main_app_id_str = format!("{}.{}", main_app_bundle_id, team.team_id); let main_app_name = match app.bundle.bundle_name() { Some(name) => name.to_string(), None => { - return emit_error_and_return(window, "No bundle name found in IPA"); + return error_and_return( + &logger, + Error::InvalidBundle("No bundle name found in IPA".to_string()), + ); } }; @@ -88,13 +84,13 @@ pub async fn sideload_app( for ext in extensions.iter_mut() { if let Some(id) = ext.bundle_identifier() { if !(id.starts_with(&main_app_bundle_id) && id.len() > main_app_bundle_id.len()) { - return emit_error_and_return( - window, - &format!( + return error_and_return( + &logger, + Error::InvalidBundle(format!( "Extension {} is not part of the main app bundle identifier: {}", ext.bundle_name().unwrap_or("Unknown"), id - ), + )), ); } else { ext.set_bundle_identifier(&format!( @@ -123,13 +119,13 @@ pub async fn sideload_app( .collect::>(); if app_ids_to_register.len() > list_app_id_response.available_quantity.try_into().unwrap() { - return emit_error_and_return( - window, - &format!( + return error_and_return( + &logger, + Error::InvalidBundle(format!( "This app requires {} app ids, but you only have {} available", app_ids_to_register.len(), list_app_id_response.available_quantity - ), + )), ); } @@ -140,7 +136,7 @@ pub async fn sideload_app( .add_app_id(DeveloperDeviceType::Ios, &team, &name, &id) .await { - return emit_error_and_return(window, &format!("Failed to register app ID: {:?}", e)); + return error_and_return(&logger, e); } } list_app_id_response = match dev_session @@ -149,7 +145,7 @@ pub async fn sideload_app( { Ok(ids) => ids, Err(e) => { - return emit_error_and_return(window, &format!("Failed to list app IDs: {:?}", e)); + return error_and_return(&logger, e); } }; @@ -169,19 +165,17 @@ pub async fn sideload_app( { Some(id) => id, None => { - return emit_error_and_return( - window, - &format!( + return error_and_return( + &logger, + Error::Generic(format!( "Main app ID {} not found in registered app IDs", main_app_id_str - ), + )), ); } }; - window - .emit("build-output", "Registered app IDs".to_string()) - .ok(); + logger.log("Successfully registered app IDs"); for app_id in app_ids.iter_mut() { let app_group_feature_enabled = app_id @@ -190,7 +184,9 @@ pub async fn sideload_app( "APG3427HIY", /* Gotta love apple and their magic strings! */ ) .and_then(|v| v.as_boolean()) - .ok_or("App group feature not found in app id")?; + .ok_or(Error::Generic( + "App group feature not found in app id".to_string(), + ))?; if !app_group_feature_enabled { let mut body = plist::Dictionary::new(); body.insert("APG3427HIY".to_string(), plist::Value::Boolean(true)); @@ -200,10 +196,7 @@ pub async fn sideload_app( { Ok(new_feats) => new_feats, Err(e) => { - return emit_error_and_return( - window, - &format!("Failed to update app ID features: {:?}", e), - ); + return error_and_return(&logger, e); } }; app_id.features = new_features; @@ -225,7 +218,7 @@ pub async fn sideload_app( { Ok(groups) => groups, Err(e) => { - return emit_error_and_return(window, &format!("Failed to list app groups: {:?}", e)); + return error_and_return(&logger, e); } }; @@ -246,10 +239,7 @@ pub async fn sideload_app( { Ok(group) => group, Err(e) => { - return emit_error_and_return( - window, - &format!("Failed to register app group: {:?}", e), - ); + return error_and_return(&logger, e); } } } else { @@ -267,13 +257,7 @@ pub async fn sideload_app( ) .await; if assign_res.is_err() { - return emit_error_and_return( - window, - &format!( - "Failed to assign app group to app ID: {:?}", - assign_res.err() - ), - ); + return error_and_return(&logger, assign_res.err().unwrap()); } // let provisioning_profile = match account // // This doesn't seem right to me, but it's what Sideloader does... Shouldn't it be downloading the provisioning profile for this app ID, not the main? @@ -291,9 +275,7 @@ pub async fn sideload_app( // provisioning_profiles.insert(app_id.identifier.clone(), provisioning_profile); } - window - .emit("build-output", "Registered app groups".to_string()) - .ok(); + logger.log("Successfully registered app groups"); let provisioning_profile = match dev_session .download_team_provisioning_profile(DeveloperDeviceType::Ios, &team, &main_app_id) @@ -301,10 +283,7 @@ pub async fn sideload_app( { Ok(pp /* tee hee */) => pp, Err(e) => { - return emit_error_and_return( - window, - &format!("Failed to download provisioning profile: {:?}", e), - ); + return error_and_return(&logger, e); } }; @@ -318,9 +297,10 @@ pub async fn sideload_app( std::fs::remove_file(&profile_path).map_err(|e| e.to_string())?; } - let mut file = std::fs::File::create(&profile_path).map_err(|e| e.to_string())?; + let mut file = + std::fs::File::create(&profile_path).map_err(|e| Error::Filesystem(e.to_string()))?; file.write_all(&provisioning_profile.encoded_profile) - .map_err(|e| e.to_string())?; + .map_err(|e| Error::Filesystem(e.to_string()))?; // Without this, zsign complains it can't find the provision file #[cfg(target_os = "windows")] @@ -332,67 +312,28 @@ pub async fn sideload_app( // TODO: Recursive for sub-bundles? app.bundle.write_info().map_err(|e| e.to_string())?; - window - .emit("build-output", "Signining app...".to_string()) - .ok(); - - let zsign_command = handle.shell().sidecar("zsign").unwrap().args([ - "-k", - cert.get_private_key_file_path().to_str().unwrap(), - "-c", - cert.get_certificate_file_path().to_str().unwrap(), - "-m", - profile_path.to_str().unwrap(), - app.bundle.bundle_dir.to_str().unwrap(), - ]); - let (mut rx, mut _child) = zsign_command.spawn().expect("Failed to spawn zsign"); - - let mut signing_failed = false; - while let Some(event) = rx.recv().await { - match event { - CommandEvent::Stdout(line_bytes) | CommandEvent::Stderr(line_bytes) => { - let line = String::from_utf8_lossy(&line_bytes); - window - .emit("build-output", Some(line)) - .expect("failed to emit event"); - } - CommandEvent::Terminated(result) => { - if result.code != Some(0) { - window - .emit("build-output", "App signing failed!".to_string()) - .ok(); - signing_failed = true; - break; - } - window.emit("build-output", "App signed!").ok(); - - window - .emit( - "build-output", - "Installing app (Transfer)... 0%".to_string(), - ) - .ok(); - - let res = install_app(&device, &app.bundle.bundle_dir, |percentage| { - window - .emit("build-output", format!("Installing app... {}%", percentage)) - .expect("failed to emit event"); - }) - .await; - if let Err(e) = res { - window - .emit("build-output", format!("Failed to install app: {:?}", e)) - .ok(); - signing_failed = true; - } - break; - } - _ => {} + match ZSignOptions::new(app.bundle.bundle_dir.to_str().unwrap()) + .with_cert_file(cert.get_certificate_file_path().to_str().unwrap()) + .with_pkey_file(cert.get_private_key_file_path().to_str().unwrap()) + .with_prov_file(profile_path.to_str().unwrap()) + .sign() + { + Ok(_) => {} + Err(e) => { + return error_and_return(&logger, &format!("Failed to sign app: {:?}", e)); } - } + }; - if signing_failed { - return Err("Signing or installation failed".to_string()); + logger.log("App signed!"); + + logger.log("Installing app (Transfer)... 0%"); + + let res = install_app(&device, &app.bundle.bundle_dir, |percentage| { + logger.log(format!("Installing app... {}%", percentage)); + }) + .await; + if let Err(e) = res { + return error_and_return(&logger, &format!("Failed to install app: {:?}", e)); } Ok(())