refactor: apk-parser crate
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,2 +1,2 @@
|
|||||||
/target
|
**/target
|
||||||
.idea/
|
.idea/
|
20
Cargo.lock
generated
20
Cargo.lock
generated
@ -124,6 +124,17 @@ dependencies = [
|
|||||||
"zip",
|
"zip",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "apk-parser"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"apk",
|
||||||
|
"byteorder",
|
||||||
|
"hex",
|
||||||
|
"log",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arraydeque"
|
name = "arraydeque"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
@ -978,6 +989,12 @@ version = "0.5.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hex"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hex-conservative"
|
name = "hex-conservative"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
@ -1463,9 +1480,8 @@ name = "nap"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"apk",
|
"apk-parser",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"byteorder",
|
|
||||||
"clap",
|
"clap",
|
||||||
"config",
|
"config",
|
||||||
"dialoguer",
|
"dialoguer",
|
||||||
|
@ -20,10 +20,9 @@ reqwest = { version = "0.12.12", features = ["json", "stream"] }
|
|||||||
tokio = { version = "1.43.0", features = ["fs", "rt", "macros", "rt-multi-thread"] }
|
tokio = { version = "1.43.0", features = ["fs", "rt", "macros", "rt-multi-thread"] }
|
||||||
serde = { version = "1.0.217", features = ["derive"] }
|
serde = { version = "1.0.217", features = ["derive"] }
|
||||||
async-trait = "0.1.86"
|
async-trait = "0.1.86"
|
||||||
apk = "0.4.0"
|
|
||||||
semver = "1.0.25"
|
semver = "1.0.25"
|
||||||
indicatif = "0.17.11"
|
indicatif = "0.17.11"
|
||||||
dialoguer = "0.11.0"
|
dialoguer = "0.11.0"
|
||||||
env_logger = "0.11.6"
|
env_logger = "0.11.6"
|
||||||
sha2 = "0.10.8"
|
sha2 = "0.10.8"
|
||||||
byteorder = "1.5.0"
|
apk-parser = { path = "./apk-parser" }
|
||||||
|
878
apk-parser/Cargo.lock
generated
Normal file
878
apk-parser/Cargo.lock
generated
Normal file
@ -0,0 +1,878 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "adler2"
|
||||||
|
version = "2.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anyhow"
|
||||||
|
version = "1.0.95"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "apk"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1cb37b529daddddf129612580831db21a538d1aa2798b367039e9316762c81a7"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"byteorder",
|
||||||
|
"quick-xml",
|
||||||
|
"rasn",
|
||||||
|
"rasn-pkix",
|
||||||
|
"roxmltree",
|
||||||
|
"rsa",
|
||||||
|
"serde",
|
||||||
|
"sha2",
|
||||||
|
"tracing",
|
||||||
|
"xcommon",
|
||||||
|
"zip",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "apk-parser"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"apk",
|
||||||
|
"byteorder",
|
||||||
|
"hex",
|
||||||
|
"log",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64"
|
||||||
|
version = "0.13.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64ct"
|
||||||
|
version = "1.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitvec"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c"
|
||||||
|
dependencies = [
|
||||||
|
"funty",
|
||||||
|
"radium",
|
||||||
|
"tap",
|
||||||
|
"wyz",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "block-buffer"
|
||||||
|
version = "0.10.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bytemuck"
|
||||||
|
version = "1.21.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3"
|
||||||
|
|
||||||
|
[[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.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chrono"
|
||||||
|
version = "0.4.39"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "color_quant"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "const-oid"
|
||||||
|
version = "0.9.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cpufeatures"
|
||||||
|
version = "0.2.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crc32fast"
|
||||||
|
version = "1.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-utils"
|
||||||
|
version = "0.8.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crypto-common"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
"typenum",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "der"
|
||||||
|
version = "0.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de"
|
||||||
|
dependencies = [
|
||||||
|
"const-oid",
|
||||||
|
"pem-rfc7468",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "digest"
|
||||||
|
version = "0.10.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||||
|
dependencies = [
|
||||||
|
"block-buffer",
|
||||||
|
"const-oid",
|
||||||
|
"crypto-common",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "doc-comment"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dunce"
|
||||||
|
version = "1.0.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fdeflate"
|
||||||
|
version = "0.3.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c"
|
||||||
|
dependencies = [
|
||||||
|
"simd-adler32",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "flate2"
|
||||||
|
version = "1.0.35"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c"
|
||||||
|
dependencies = [
|
||||||
|
"crc32fast",
|
||||||
|
"miniz_oxide",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "funty"
|
||||||
|
version = "2.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "generic-array"
|
||||||
|
version = "0.14.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||||
|
dependencies = [
|
||||||
|
"typenum",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getrandom"
|
||||||
|
version = "0.2.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"wasi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "heck"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hex"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "image"
|
||||||
|
version = "0.24.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d"
|
||||||
|
dependencies = [
|
||||||
|
"bytemuck",
|
||||||
|
"byteorder",
|
||||||
|
"color_quant",
|
||||||
|
"num-traits",
|
||||||
|
"png",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.10.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "konst"
|
||||||
|
version = "0.2.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "330f0e13e6483b8c34885f7e6c9f19b1a7bd449c673fbb948a51c99d66ef74f4"
|
||||||
|
dependencies = [
|
||||||
|
"konst_macro_rules",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "konst_macro_rules"
|
||||||
|
version = "0.2.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a4933f3f57a8e9d9da04db23fb153356ecaf00cbd14aee46279c33dc80925c37"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy_static"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||||
|
dependencies = [
|
||||||
|
"spin",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.169"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libm"
|
||||||
|
version = "0.2.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "log"
|
||||||
|
version = "0.4.25"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.7.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "minimal-lexical"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "miniz_oxide"
|
||||||
|
version = "0.8.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b3b1c9bd4fe1f0f8b387f6eb9eb3b4a1aa26185e5750efb9140301703f62cd1b"
|
||||||
|
dependencies = [
|
||||||
|
"adler2",
|
||||||
|
"simd-adler32",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nom"
|
||||||
|
version = "7.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
"minimal-lexical",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-bigint"
|
||||||
|
version = "0.4.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
|
||||||
|
dependencies = [
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-bigint-dig"
|
||||||
|
version = "0.8.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
"lazy_static",
|
||||||
|
"libm",
|
||||||
|
"num-integer",
|
||||||
|
"num-iter",
|
||||||
|
"num-traits",
|
||||||
|
"rand",
|
||||||
|
"smallvec",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-integer"
|
||||||
|
version = "0.1.46"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-iter"
|
||||||
|
version = "0.1.45"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"libm",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell"
|
||||||
|
version = "1.20.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pem"
|
||||||
|
version = "1.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8"
|
||||||
|
dependencies = [
|
||||||
|
"base64",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pem-rfc7468"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "24d159833a9105500e0398934e205e0773f0b27529557134ecfc51c27646adac"
|
||||||
|
dependencies = [
|
||||||
|
"base64ct",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pin-project-lite"
|
||||||
|
version = "0.2.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pkcs1"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eff33bdbdfc54cc98a2eca766ebdec3e1b8fb7387523d5c9c9a2891da856f719"
|
||||||
|
dependencies = [
|
||||||
|
"der",
|
||||||
|
"pkcs8",
|
||||||
|
"spki",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pkcs8"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba"
|
||||||
|
dependencies = [
|
||||||
|
"der",
|
||||||
|
"spki",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "png"
|
||||||
|
version = "0.17.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"crc32fast",
|
||||||
|
"fdeflate",
|
||||||
|
"flate2",
|
||||||
|
"miniz_oxide",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ppv-lite86"
|
||||||
|
version = "0.2.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
|
||||||
|
dependencies = [
|
||||||
|
"zerocopy",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.93"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quick-xml"
|
||||||
|
version = "0.26.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7f50b1c63b38611e7d4d7f68b82d3ad0cc71a2ad2e7f61fc10f1328d917c93cd"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.38"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "radium"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.8.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||||
|
dependencies = [
|
||||||
|
"rand_chacha",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_chacha"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||||
|
dependencies = [
|
||||||
|
"ppv-lite86",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rasn"
|
||||||
|
version = "0.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "417c93c4470c2637fd27307f046653c70a957f374caae89cb5c9fb35a5fdf147"
|
||||||
|
dependencies = [
|
||||||
|
"bitvec",
|
||||||
|
"bytes",
|
||||||
|
"chrono",
|
||||||
|
"konst",
|
||||||
|
"nom",
|
||||||
|
"num-bigint",
|
||||||
|
"num-traits",
|
||||||
|
"rasn-derive",
|
||||||
|
"snafu",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rasn-derive"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4e1c39006ee96ffe7c83f656a5d20269366098a3feb35ad4a7c022e3784643cb"
|
||||||
|
dependencies = [
|
||||||
|
"itertools",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 1.0.109",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rasn-pkix"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "88a7f32e03743ae0f691408246c7e1ce9065a345b6589e05df3b6c57138d4655"
|
||||||
|
dependencies = [
|
||||||
|
"rasn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "roxmltree"
|
||||||
|
version = "0.16.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fb6d47b59770b0ae88c7f270c68502832ec14d8c7ab5f7a584f204bb76dbfd8e"
|
||||||
|
dependencies = [
|
||||||
|
"xmlparser",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rsa"
|
||||||
|
version = "0.7.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "094052d5470cbcef561cb848a7209968c9f12dfa6d668f4bca048ac5de51099c"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
"digest",
|
||||||
|
"num-bigint-dig",
|
||||||
|
"num-integer",
|
||||||
|
"num-iter",
|
||||||
|
"num-traits",
|
||||||
|
"pkcs1",
|
||||||
|
"pkcs8",
|
||||||
|
"rand_core",
|
||||||
|
"signature",
|
||||||
|
"smallvec",
|
||||||
|
"subtle",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde"
|
||||||
|
version = "1.0.217"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_derive"
|
||||||
|
version = "1.0.217"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.98",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sha2"
|
||||||
|
version = "0.10.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cpufeatures",
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "signature"
|
||||||
|
version = "1.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c"
|
||||||
|
dependencies = [
|
||||||
|
"digest",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "simd-adler32"
|
||||||
|
version = "0.3.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "smallvec"
|
||||||
|
version = "1.13.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "snafu"
|
||||||
|
version = "0.7.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e4de37ad025c587a29e8f3f5605c00f70b98715ef90b9061a815b9e59e9042d6"
|
||||||
|
dependencies = [
|
||||||
|
"doc-comment",
|
||||||
|
"snafu-derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "snafu-derive"
|
||||||
|
version = "0.7.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "990079665f075b699031e9c08fd3ab99be5029b96f3b78dc0709e8f77e4efebf"
|
||||||
|
dependencies = [
|
||||||
|
"heck",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 1.0.109",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "spin"
|
||||||
|
version = "0.9.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "spki"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b"
|
||||||
|
dependencies = [
|
||||||
|
"base64ct",
|
||||||
|
"der",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "subtle"
|
||||||
|
version = "2.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "1.0.109"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "2.0.98"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tap"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing"
|
||||||
|
version = "0.1.41"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
|
||||||
|
dependencies = [
|
||||||
|
"pin-project-lite",
|
||||||
|
"tracing-attributes",
|
||||||
|
"tracing-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-attributes"
|
||||||
|
version = "0.1.28"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.98",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-core"
|
||||||
|
version = "0.1.33"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
|
||||||
|
dependencies = [
|
||||||
|
"once_cell",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typenum"
|
||||||
|
version = "1.17.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version_check"
|
||||||
|
version = "0.9.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wyz"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
|
||||||
|
dependencies = [
|
||||||
|
"tap",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "xcommon"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5cd8830f4fbeb328f04d29d48af5f2b968395542d6046c9bf55f5b59ebbc342f"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"byteorder",
|
||||||
|
"dunce",
|
||||||
|
"image",
|
||||||
|
"pem",
|
||||||
|
"rasn",
|
||||||
|
"rasn-pkix",
|
||||||
|
"rsa",
|
||||||
|
"sha2",
|
||||||
|
"zip",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "xmlparser"
|
||||||
|
version = "0.13.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy"
|
||||||
|
version = "0.7.35"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
"zerocopy-derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy-derive"
|
||||||
|
version = "0.7.35"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.98",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zeroize"
|
||||||
|
version = "1.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zip"
|
||||||
|
version = "0.6.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
"crc32fast",
|
||||||
|
"crossbeam-utils",
|
||||||
|
"flate2",
|
||||||
|
]
|
11
apk-parser/Cargo.toml
Normal file
11
apk-parser/Cargo.toml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
[package]
|
||||||
|
name = "apk-parser"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anyhow = "1.0.95"
|
||||||
|
log = "0.4.25"
|
||||||
|
hex = "0.4.3"
|
||||||
|
byteorder = "1.5.0"
|
||||||
|
apk = "0.4.0"
|
6
apk-parser/src/lib.rs
Normal file
6
apk-parser/src/lib.rs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
mod manifest;
|
||||||
|
mod signing_block;
|
||||||
|
|
||||||
|
pub use apk::*;
|
||||||
|
pub use manifest::*;
|
||||||
|
pub use signing_block::*;
|
99
apk-parser/src/manifest.rs
Normal file
99
apk-parser/src/manifest.rs
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
use anyhow::{bail, Result};
|
||||||
|
use apk::res::Chunk;
|
||||||
|
use apk::AndroidManifest;
|
||||||
|
use log::debug;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::io::Cursor;
|
||||||
|
|
||||||
|
/// Parse android manifest from AndroidManifest.xml file data
|
||||||
|
pub fn parse_android_manifest(data: &[u8]) -> Result<AndroidManifest> {
|
||||||
|
let chunks = if let Chunk::Xml(chunks) = Chunk::parse(&mut Cursor::new(data))? {
|
||||||
|
chunks
|
||||||
|
} else {
|
||||||
|
bail!("Invalid AndroidManifest file");
|
||||||
|
};
|
||||||
|
|
||||||
|
let strings = if let Chunk::StringPool(strings, _) = &chunks[0] {
|
||||||
|
HashMap::from_iter(
|
||||||
|
strings
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, s)| (s.to_string(), i as i32)),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
bail!("invalid manifest 1");
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut res = AndroidManifest::default();
|
||||||
|
res.package = find_value_in(&strings, &chunks, "manifest", "package");
|
||||||
|
res.version_code =
|
||||||
|
find_value_in(&strings, &chunks, "manifest", "versionCode").and_then(|v| v.parse().ok());
|
||||||
|
res.version_name = find_value_in(&strings, &chunks, "manifest", "versionName");
|
||||||
|
res.compile_sdk_version = find_value_in(&strings, &chunks, "manifest", "compileSdkVersion")
|
||||||
|
.and_then(|v| v.parse().ok());
|
||||||
|
res.compile_sdk_version_codename =
|
||||||
|
find_value_in(&strings, &chunks, "manifest", "compileSdkVersionCodename")
|
||||||
|
.and_then(|v| v.parse().ok());
|
||||||
|
res.platform_build_version_code =
|
||||||
|
find_value_in(&strings, &chunks, "manifest", "platformBuildVersionCode")
|
||||||
|
.and_then(|v| v.parse().ok());
|
||||||
|
res.platform_build_version_name =
|
||||||
|
find_value_in(&strings, &chunks, "manifest", "platformBuildVersionName")
|
||||||
|
.and_then(|v| v.parse().ok());
|
||||||
|
|
||||||
|
res.sdk.min_sdk_version =
|
||||||
|
find_value_in(&strings, &chunks, "uses-sdk", "minSdkVersion").and_then(|v| v.parse().ok());
|
||||||
|
res.sdk.target_sdk_version = find_value_in(&strings, &chunks, "uses-sdk", "targetSdkVersion")
|
||||||
|
.and_then(|v| v.parse().ok());
|
||||||
|
res.sdk.max_sdk_version =
|
||||||
|
find_value_in(&strings, &chunks, "uses-sdk", "maxSdkVersion").and_then(|v| v.parse().ok());
|
||||||
|
|
||||||
|
res.application.theme = find_value_in(&strings, &chunks, "application", "theme");
|
||||||
|
res.application.label = find_value_in(&strings, &chunks, "application", "label");
|
||||||
|
res.application.icon = find_value_in(&strings, &chunks, "application", "icon");
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_value_in(
|
||||||
|
strings: &HashMap<String, i32>,
|
||||||
|
chunks: &Vec<Chunk>,
|
||||||
|
node: &str,
|
||||||
|
attr: &str,
|
||||||
|
) -> Option<String> {
|
||||||
|
let idx_node = if let Some(i) = strings.get(node) {
|
||||||
|
*i
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
let idx_attr = if let Some(i) = strings.get(attr) {
|
||||||
|
*i
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
chunks.iter().find_map(|chunk| {
|
||||||
|
if let Chunk::XmlStartElement(_, el, attrs) = chunk {
|
||||||
|
match el.name {
|
||||||
|
x if x == idx_node => attrs.iter().find(|e| e.name == idx_attr).and_then(|e| {
|
||||||
|
debug!("{}, {}, {:?}", node, attr, e);
|
||||||
|
match e.typed_value.data_type {
|
||||||
|
3 => strings
|
||||||
|
.iter()
|
||||||
|
.find(|(_, v)| **v == e.raw_value)
|
||||||
|
.map(|(k, _)| k.clone()),
|
||||||
|
16 => Some(e.typed_value.data.to_string()),
|
||||||
|
_ => {
|
||||||
|
debug!("unknown data type {},{},{:?}", node, attr, e);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
358
apk-parser/src/signing_block.rs
Normal file
358
apk-parser/src/signing_block.rs
Normal file
@ -0,0 +1,358 @@
|
|||||||
|
use anyhow::{bail, ensure, Result};
|
||||||
|
use byteorder::{LittleEndian, ReadBytesExt};
|
||||||
|
use log::{debug, warn};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::convert::TryInto;
|
||||||
|
use std::fmt::{Display, Formatter};
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{Read, Seek, SeekFrom};
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
/// APK Signing block storage type
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct ApkSigningBlock {
|
||||||
|
pub data: Vec<(u32, Vec<u8>)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ApkSigningBlock {
|
||||||
|
/// Load the signing block from and APK file
|
||||||
|
pub fn from_path(path: impl AsRef<Path>) -> Result<Self> {
|
||||||
|
let mut file = File::open(path)?;
|
||||||
|
ApkSigningBlock::from_reader(&mut file)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Load the signing block from an APK file
|
||||||
|
pub fn from_reader<R: Read + Seek>(reader: &mut R) -> Result<Self> {
|
||||||
|
load_signing_block(reader)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse signatures from signing block
|
||||||
|
pub fn get_signatures(&self) -> Result<Vec<ApkSignatureBlock>> {
|
||||||
|
const V2_SIG_BLOCK_ID: u32 = 0x7109871a;
|
||||||
|
const V3_SIG_BLOCK_ID: u32 = 0xf05368c0;
|
||||||
|
|
||||||
|
let mut sigs = vec![];
|
||||||
|
for (k, v) in &self.data {
|
||||||
|
match *k {
|
||||||
|
V2_SIG_BLOCK_ID => {
|
||||||
|
let v2 = get_length_prefixed_u32_sequence(v)?;
|
||||||
|
ensure!(
|
||||||
|
v2.len() == 1,
|
||||||
|
"Expected 1 element in signing block got {}",
|
||||||
|
v2.len()
|
||||||
|
);
|
||||||
|
|
||||||
|
let v2 = get_length_prefixed_u32_sequence(v2[0])?;
|
||||||
|
let signed_data = get_sequence(v2[0])?;
|
||||||
|
let digests = get_sequence_kv(signed_data[0])?;
|
||||||
|
let certificates = get_sequence(signed_data[1])?;
|
||||||
|
let attributes = get_sequence_kv(signed_data[2])?;
|
||||||
|
let signatures = get_sequence_kv(v2[1])?;
|
||||||
|
let public_key = v2[2];
|
||||||
|
let digests: HashMap<u32, &[u8]> = HashMap::from_iter(digests);
|
||||||
|
sigs.push(ApkSignatureBlock::V2 {
|
||||||
|
attributes: HashMap::from_iter(
|
||||||
|
attributes.into_iter().map(|(k, v)| (k, v.to_vec())),
|
||||||
|
),
|
||||||
|
certificates: certificates.into_iter().map(|v| v.to_vec()).collect(),
|
||||||
|
signatures: parse_sigs(&signatures, &digests),
|
||||||
|
public_key: public_key.to_vec(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
V3_SIG_BLOCK_ID => {
|
||||||
|
let v3 = get_length_prefixed_u32_sequence(v)?;
|
||||||
|
ensure!(
|
||||||
|
v3.len() == 1,
|
||||||
|
"Expected 1 element in signing block got {}",
|
||||||
|
v3.len()
|
||||||
|
);
|
||||||
|
|
||||||
|
let v3 = get_length_prefixed_u32_sequence(v3[0])?;
|
||||||
|
let signed_data = get_sequence(v3[0])?;
|
||||||
|
let digests = get_sequence_kv(signed_data[0])?;
|
||||||
|
let certificates = get_sequence(signed_data[1])?;
|
||||||
|
let min_sdk_signed = u32::from_le_bytes(signed_data[2].try_into()?);
|
||||||
|
let max_sdk_signed = u32::from_le_bytes(signed_data[3].try_into()?);
|
||||||
|
let attributes = get_sequence_kv(signed_data[4])?;
|
||||||
|
|
||||||
|
let min_sdk = u32::from_le_bytes(v3[1].try_into()?);
|
||||||
|
let max_sdk = u32::from_le_bytes(v3[2].try_into()?);
|
||||||
|
|
||||||
|
ensure!(
|
||||||
|
min_sdk_signed == min_sdk,
|
||||||
|
"Invalid min_sdk in signing block V3 {} != {}",
|
||||||
|
min_sdk_signed,
|
||||||
|
min_sdk
|
||||||
|
);
|
||||||
|
ensure!(
|
||||||
|
max_sdk_signed == max_sdk,
|
||||||
|
"Invalid max_sdk in signing block V3 {} != {}",
|
||||||
|
max_sdk_signed,
|
||||||
|
max_sdk
|
||||||
|
);
|
||||||
|
|
||||||
|
let signatures = get_sequence_kv(v3[3])?;
|
||||||
|
let public_key = v3[4];
|
||||||
|
let digests: HashMap<u32, &[u8]> = HashMap::from_iter(digests);
|
||||||
|
|
||||||
|
sigs.push(ApkSignatureBlock::V3 {
|
||||||
|
min_sdk,
|
||||||
|
max_sdk,
|
||||||
|
attributes: HashMap::from_iter(
|
||||||
|
attributes.into_iter().map(|(k, v)| (k, v.to_vec())),
|
||||||
|
),
|
||||||
|
certificates: certificates.into_iter().map(|v| v.to_vec()).collect(),
|
||||||
|
signatures: parse_sigs(&signatures, &digests),
|
||||||
|
public_key: public_key.to_vec(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
v => debug!("Unknown block id {}", v),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(sigs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_sigs(signatures: &Vec<(u32, &[u8])>, digests: &HashMap<u32, &[u8]>) -> Vec<ApkSignature> {
|
||||||
|
signatures
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|(k, v)| {
|
||||||
|
let sig_len = u32::from_le_bytes(v[..4].try_into().ok()?) as usize;
|
||||||
|
if sig_len > v.len() - 4 {
|
||||||
|
warn!("Invalid signature length: {} > {}", sig_len, v.len());
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
if let Ok(a) = ApkSignatureAlgo::try_from(*k) {
|
||||||
|
Some(ApkSignature {
|
||||||
|
algo: a,
|
||||||
|
digest: digests.get(&k).map(|v| v[4..].to_vec())?,
|
||||||
|
signature: v[4..sig_len + 4].to_vec(),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum ApkSignatureBlock {
|
||||||
|
/// Unknown block
|
||||||
|
Unknown { data: Vec<u8> },
|
||||||
|
|
||||||
|
/// Android V2 Signature Block
|
||||||
|
///
|
||||||
|
/// https://source.android.com/docs/security/features/apksigning/v2#apk-signature-scheme-v2-block-format
|
||||||
|
V2 {
|
||||||
|
signatures: Vec<ApkSignature>,
|
||||||
|
public_key: Vec<u8>,
|
||||||
|
certificates: Vec<Vec<u8>>,
|
||||||
|
attributes: HashMap<u32, Vec<u8>>,
|
||||||
|
},
|
||||||
|
|
||||||
|
/// Android V3 Signature Block
|
||||||
|
///
|
||||||
|
/// https://source.android.com/docs/security/features/apksigning/v3#format
|
||||||
|
V3 {
|
||||||
|
signatures: Vec<ApkSignature>,
|
||||||
|
certificates: Vec<Vec<u8>>,
|
||||||
|
public_key: Vec<u8>,
|
||||||
|
attributes: HashMap<u32, Vec<u8>>,
|
||||||
|
min_sdk: u32,
|
||||||
|
max_sdk: u32,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for ApkSignatureBlock {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
ApkSignatureBlock::Unknown { .. } => write!(f, "unknown"),
|
||||||
|
ApkSignatureBlock::V2 { signatures, .. } => {
|
||||||
|
write!(f, "v2: ")?;
|
||||||
|
for sig in signatures {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"algo={}, digest={}, sig={}",
|
||||||
|
sig.algo,
|
||||||
|
hex::encode(&sig.digest),
|
||||||
|
hex::encode(&sig.signature)
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
ApkSignatureBlock::V3 { signatures, .. } => {
|
||||||
|
write!(f, "V3: ")?;
|
||||||
|
for sig in signatures {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"algo={}, digest={}, sig={}",
|
||||||
|
sig.algo,
|
||||||
|
hex::encode(&sig.digest),
|
||||||
|
hex::encode(&sig.signature)
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct ApkSignature {
|
||||||
|
pub algo: ApkSignatureAlgo,
|
||||||
|
pub signature: Vec<u8>,
|
||||||
|
pub digest: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum ApkSignatureAlgo {
|
||||||
|
RsaSsaPssSha256,
|
||||||
|
RsaSsaPssSha512,
|
||||||
|
RsaSsaPkcs1Sha256,
|
||||||
|
RsaSsaPkcs1Sha512,
|
||||||
|
EcdsaSha256,
|
||||||
|
EcdsaSha512,
|
||||||
|
DsaSha256,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for ApkSignatureAlgo {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
ApkSignatureAlgo::RsaSsaPssSha256 => write!(f, "RSASSA-PSS-SHA256"),
|
||||||
|
ApkSignatureAlgo::RsaSsaPssSha512 => write!(f, "RSASSA-PSS-SHA512"),
|
||||||
|
ApkSignatureAlgo::RsaSsaPkcs1Sha256 => write!(f, "RSASSA-PKCS1-SHA256"),
|
||||||
|
ApkSignatureAlgo::RsaSsaPkcs1Sha512 => write!(f, "RSASSA-PKCS1-SHA512"),
|
||||||
|
ApkSignatureAlgo::EcdsaSha256 => write!(f, "ECDSA-SHA256"),
|
||||||
|
ApkSignatureAlgo::EcdsaSha512 => write!(f, "ECDSA-SHA512"),
|
||||||
|
ApkSignatureAlgo::DsaSha256 => write!(f, "DSA-SHA256"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<u32> for ApkSignatureAlgo {
|
||||||
|
type Error = anyhow::Error;
|
||||||
|
|
||||||
|
fn try_from(value: u32) -> std::result::Result<Self, Self::Error> {
|
||||||
|
match value {
|
||||||
|
0x0101 => Ok(ApkSignatureAlgo::RsaSsaPssSha256),
|
||||||
|
0x0102 => Ok(ApkSignatureAlgo::RsaSsaPssSha512),
|
||||||
|
0x0103 => Ok(ApkSignatureAlgo::RsaSsaPkcs1Sha256),
|
||||||
|
0x0104 => Ok(ApkSignatureAlgo::RsaSsaPkcs1Sha512),
|
||||||
|
0x0201 => Ok(ApkSignatureAlgo::EcdsaSha256),
|
||||||
|
0x0202 => Ok(ApkSignatureAlgo::EcdsaSha512),
|
||||||
|
0x0301 => Ok(ApkSignatureAlgo::DsaSha256),
|
||||||
|
_ => bail!("Unknown signature algo"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_signing_block<R>(zip: &mut R) -> Result<ApkSigningBlock>
|
||||||
|
where
|
||||||
|
R: Read + Seek,
|
||||||
|
{
|
||||||
|
const SIG_BLOCK_MAGIC: &[u8] = b"APK Sig Block 42";
|
||||||
|
|
||||||
|
// scan backwards until we find the singing block
|
||||||
|
let flen = zip.seek(SeekFrom::End(0))?;
|
||||||
|
let mut magic_buf = [0u8; 16];
|
||||||
|
loop {
|
||||||
|
let magic_pos = zip.seek(SeekFrom::Current(-17))?;
|
||||||
|
if magic_pos <= 4 {
|
||||||
|
bail!("Failed to find signing block");
|
||||||
|
}
|
||||||
|
|
||||||
|
zip.read_exact(&mut magic_buf)?;
|
||||||
|
if magic_buf == SIG_BLOCK_MAGIC {
|
||||||
|
zip.seek(SeekFrom::Current(-(16 + 8)))?;
|
||||||
|
let size1 = zip.read_u64::<LittleEndian>()?;
|
||||||
|
ensure!(size1 <= flen, "Signing block is larger than entire file");
|
||||||
|
|
||||||
|
zip.seek(SeekFrom::Current(-(size1 as i64 - 8)))?;
|
||||||
|
let size2 = zip.read_u64::<LittleEndian>()?;
|
||||||
|
ensure!(
|
||||||
|
size2 == size1,
|
||||||
|
"Invalid block sizes, {} != {}",
|
||||||
|
size1,
|
||||||
|
size2
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut data_bytes = size1 - 8 - 16;
|
||||||
|
let mut sigs = Vec::new();
|
||||||
|
loop {
|
||||||
|
let (k, v) = read_u64_length_prefixed_kv(zip)?;
|
||||||
|
data_bytes -= (v.len() + 4 + 8) as u64;
|
||||||
|
sigs.push((k, v));
|
||||||
|
if data_bytes == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
zip.seek(SeekFrom::Start(0))?;
|
||||||
|
return Ok(ApkSigningBlock { data: sigs });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn read_u64_length_prefixed_kv<T>(file: &mut T) -> Result<(u32, Vec<u8>)>
|
||||||
|
where
|
||||||
|
T: Read + Seek,
|
||||||
|
{
|
||||||
|
let kv_len = file.read_u64::<LittleEndian>()?;
|
||||||
|
let k = file.read_u32::<LittleEndian>()?;
|
||||||
|
let v_len = kv_len as usize - 4;
|
||||||
|
let mut v = vec![0; v_len];
|
||||||
|
file.read_exact(v.as_mut_slice())?;
|
||||||
|
Ok((k, v))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_u64_length_prefixed_kv(slice: &[u8]) -> Result<(u32, &[u8])> {
|
||||||
|
let kv_len = u64::from_le_bytes(slice[..8].try_into()?);
|
||||||
|
let k = u32::from_le_bytes(slice[8..12].try_into()?);
|
||||||
|
Ok((k, &slice[12..(kv_len as usize - 12)]))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_u32_length_prefixed_kv(slice: &[u8]) -> Result<(u32, &[u8])> {
|
||||||
|
let kv_len = u32::from_le_bytes(slice[..4].try_into()?);
|
||||||
|
let k = u32::from_le_bytes(slice[4..8].try_into()?);
|
||||||
|
Ok((k, &slice[8..(kv_len as usize - 8)]))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_length_prefixed_u32(slice: &[u8]) -> Result<&[u8]> {
|
||||||
|
let len = u32::from_le_bytes(slice[..4].try_into()?);
|
||||||
|
Ok(&slice[4..4 + len as usize])
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_length_prefixed_u32_sequence(slice: &[u8]) -> Result<Vec<&[u8]>> {
|
||||||
|
let sequence_len = u32::from_le_bytes(slice[..4].try_into()?);
|
||||||
|
get_sequence(&slice[4..4 + sequence_len as usize])
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_sequence(mut slice: &[u8]) -> Result<Vec<&[u8]>> {
|
||||||
|
let mut ret = Vec::new();
|
||||||
|
while slice.len() >= 4 {
|
||||||
|
let data = get_length_prefixed_u32(slice)?;
|
||||||
|
let r_len = data.len() + 4;
|
||||||
|
slice = &slice[r_len..];
|
||||||
|
ret.push(data);
|
||||||
|
}
|
||||||
|
Ok(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_sequence_kv(slice: &[u8]) -> Result<Vec<(u32, &[u8])>> {
|
||||||
|
let seq = get_sequence(slice)?;
|
||||||
|
Ok(seq
|
||||||
|
.into_iter()
|
||||||
|
.map(|s| {
|
||||||
|
let k = u32::from_le_bytes(s[..4].try_into().unwrap());
|
||||||
|
let v = &s[4..];
|
||||||
|
(k, v)
|
||||||
|
})
|
||||||
|
.collect())
|
||||||
|
}
|
447
src/repo/mod.rs
447
src/repo/mod.rs
@ -1,22 +1,19 @@
|
|||||||
use crate::manifest::Manifest;
|
use crate::manifest::Manifest;
|
||||||
use crate::repo::github::GithubRepo;
|
use crate::repo::github::GithubRepo;
|
||||||
use anyhow::{anyhow, bail, ensure, Result};
|
use anyhow::{anyhow, bail, ensure, Result};
|
||||||
use apk::res::Chunk;
|
use apk_parser::zip::ZipArchive;
|
||||||
use apk::zip::ZipArchive;
|
use apk_parser::{parse_android_manifest, AndroidManifest, ApkSignatureBlock, ApkSigningBlock};
|
||||||
use apk::AndroidManifest;
|
use log::{info, warn};
|
||||||
use byteorder::LittleEndian;
|
|
||||||
use byteorder::ReadBytesExt;
|
|
||||||
use log::{debug, info, warn};
|
|
||||||
use nostr_sdk::prelude::{hex, Coordinate, StreamExt};
|
use nostr_sdk::prelude::{hex, Coordinate, StreamExt};
|
||||||
use nostr_sdk::{Event, EventBuilder, Kind, NostrSigner, Tag};
|
use nostr_sdk::{Event, EventBuilder, Kind, NostrSigner, Tag};
|
||||||
use reqwest::Url;
|
use reqwest::Url;
|
||||||
use semver::Version;
|
use semver::Version;
|
||||||
use sha2::{Digest, Sha256};
|
use sha2::{Digest, Sha256};
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::HashSet;
|
||||||
use std::env::temp_dir;
|
use std::env::temp_dir;
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{Cursor, Read, Seek, SeekFrom};
|
use std::io::{Read, Seek};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use tokio::io::AsyncWriteExt;
|
use tokio::io::AsyncWriteExt;
|
||||||
|
|
||||||
@ -66,7 +63,7 @@ impl TryInto<EventBuilder> for RepoArtifact {
|
|||||||
Tag::parse(["f", self.platform.to_string().as_str()])?,
|
Tag::parse(["f", self.platform.to_string().as_str()])?,
|
||||||
Tag::parse(["m", self.content_type.as_str()])?,
|
Tag::parse(["m", self.content_type.as_str()])?,
|
||||||
Tag::parse(["size", self.size.to_string().as_str()])?,
|
Tag::parse(["size", self.size.to_string().as_str()])?,
|
||||||
Tag::parse(["x", &hex::encode(self.hash)])?
|
Tag::parse(["x", &hex::encode(self.hash)])?,
|
||||||
]);
|
]);
|
||||||
if let RepoResource::Remote(u) = self.location {
|
if let RepoResource::Remote(u) = self.location {
|
||||||
b = b.tag(Tag::parse(["url", u.as_str()])?);
|
b = b.tag(Tag::parse(["url", u.as_str()])?);
|
||||||
@ -74,26 +71,28 @@ impl TryInto<EventBuilder> for RepoArtifact {
|
|||||||
match self.metadata {
|
match self.metadata {
|
||||||
ArtifactMetadata::APK {
|
ArtifactMetadata::APK {
|
||||||
manifest,
|
manifest,
|
||||||
signature,
|
signatures,
|
||||||
} => {
|
} => {
|
||||||
match signature {
|
for signature in signatures {
|
||||||
ApkSignatureBlock::None => {
|
match signature {
|
||||||
warn!("No signature found in metadata");
|
ApkSignatureBlock::Unknown { .. } => {
|
||||||
}
|
warn!("No signature found in metadata");
|
||||||
ApkSignatureBlock::V2 { signatures, .. } => {
|
|
||||||
for signature in signatures {
|
|
||||||
b = b.tag(Tag::parse([
|
|
||||||
"apk_signature_hash",
|
|
||||||
&hex::encode(signature.digest),
|
|
||||||
])?);
|
|
||||||
}
|
}
|
||||||
}
|
ApkSignatureBlock::V2 { signatures, .. } => {
|
||||||
ApkSignatureBlock::V3 { signatures, .. } => {
|
for signature in signatures {
|
||||||
for signature in signatures {
|
b = b.tag(Tag::parse([
|
||||||
b = b.tag(Tag::parse([
|
"apk_signature_hash",
|
||||||
"apk_signature_hash",
|
&hex::encode(signature.digest),
|
||||||
&hex::encode(signature.digest),
|
])?);
|
||||||
])?);
|
}
|
||||||
|
}
|
||||||
|
ApkSignatureBlock::V3 { signatures, .. } => {
|
||||||
|
for signature in signatures {
|
||||||
|
b = b.tag(Tag::parse([
|
||||||
|
"apk_signature_hash",
|
||||||
|
&hex::encode(signature.digest),
|
||||||
|
])?);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -115,7 +114,6 @@ impl TryInto<EventBuilder> for RepoArtifact {
|
|||||||
target_sdk.to_string().as_str(),
|
target_sdk.to_string().as_str(),
|
||||||
])?);
|
])?);
|
||||||
}
|
}
|
||||||
//TODO: apk sig
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(b)
|
Ok(b)
|
||||||
@ -126,117 +124,16 @@ impl TryInto<EventBuilder> for RepoArtifact {
|
|||||||
pub enum ArtifactMetadata {
|
pub enum ArtifactMetadata {
|
||||||
APK {
|
APK {
|
||||||
manifest: AndroidManifest,
|
manifest: AndroidManifest,
|
||||||
signature: ApkSignatureBlock,
|
signatures: Vec<ApkSignatureBlock>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum ApkSignatureBlock {
|
|
||||||
None,
|
|
||||||
/// Android V2 Signature Block
|
|
||||||
///
|
|
||||||
/// https://source.android.com/docs/security/features/apksigning/v2#apk-signature-scheme-v2-block-format
|
|
||||||
V2 {
|
|
||||||
signatures: Vec<ApkSignature>,
|
|
||||||
public_key: Vec<u8>,
|
|
||||||
certificates: Vec<Vec<u8>>,
|
|
||||||
attributes: HashMap<u32, Vec<u8>>,
|
|
||||||
},
|
|
||||||
V3 {
|
|
||||||
signatures: Vec<ApkSignature>,
|
|
||||||
public_key: Vec<u8>,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for ApkSignatureBlock {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
ApkSignatureBlock::None => write!(f, "none"),
|
|
||||||
ApkSignatureBlock::V2 { signatures, .. } => {
|
|
||||||
write!(f, "v2: ")?;
|
|
||||||
for sig in signatures {
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"algo={}, digest={}, sig={}",
|
|
||||||
sig.algo,
|
|
||||||
hex::encode(&sig.digest),
|
|
||||||
hex::encode(&sig.signature)
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
ApkSignatureBlock::V3 { signatures, .. } => {
|
|
||||||
write!(f, "V3: ")?;
|
|
||||||
for sig in signatures {
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"algo={}, digest={}, sig={}",
|
|
||||||
sig.algo,
|
|
||||||
hex::encode(&sig.digest),
|
|
||||||
hex::encode(&sig.signature)
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct ApkSignature {
|
|
||||||
pub algo: ApkSignatureAlgo,
|
|
||||||
pub signature: Vec<u8>,
|
|
||||||
pub digest: Vec<u8>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum ApkSignatureAlgo {
|
|
||||||
RsaSsaPssSha256,
|
|
||||||
RsaSsaPssSha512,
|
|
||||||
RsaSsaPkcs1Sha256,
|
|
||||||
RsaSsaPkcs1Sha512,
|
|
||||||
EcdsaSha256,
|
|
||||||
EcdsaSha512,
|
|
||||||
DsaSha256,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for ApkSignatureAlgo {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
ApkSignatureAlgo::RsaSsaPssSha256 => write!(f, "RSASSA-PSS-SHA256"),
|
|
||||||
ApkSignatureAlgo::RsaSsaPssSha512 => write!(f, "RSASSA-PSS-SHA512"),
|
|
||||||
ApkSignatureAlgo::RsaSsaPkcs1Sha256 => write!(f, "RSASSA-PKCS1-SHA256"),
|
|
||||||
ApkSignatureAlgo::RsaSsaPkcs1Sha512 => write!(f, "RSASSA-PKCS1-SHA512"),
|
|
||||||
ApkSignatureAlgo::EcdsaSha256 => write!(f, "ECDSA-SHA256"),
|
|
||||||
ApkSignatureAlgo::EcdsaSha512 => write!(f, "ECDSA-SHA512"),
|
|
||||||
ApkSignatureAlgo::DsaSha256 => write!(f, "DSA-SHA256"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<u32> for ApkSignatureAlgo {
|
|
||||||
type Error = anyhow::Error;
|
|
||||||
|
|
||||||
fn try_from(value: u32) -> std::result::Result<Self, Self::Error> {
|
|
||||||
match value {
|
|
||||||
0x0101 => Ok(ApkSignatureAlgo::RsaSsaPssSha256),
|
|
||||||
0x0102 => Ok(ApkSignatureAlgo::RsaSsaPssSha512),
|
|
||||||
0x0103 => Ok(ApkSignatureAlgo::RsaSsaPkcs1Sha256),
|
|
||||||
0x0104 => Ok(ApkSignatureAlgo::RsaSsaPkcs1Sha512),
|
|
||||||
0x0201 => Ok(ApkSignatureAlgo::EcdsaSha256),
|
|
||||||
0x0202 => Ok(ApkSignatureAlgo::EcdsaSha512),
|
|
||||||
0x0301 => Ok(ApkSignatureAlgo::DsaSha256),
|
|
||||||
_ => bail!("Unknown signature algo"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for ArtifactMetadata {
|
impl Display for ArtifactMetadata {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
ArtifactMetadata::APK {
|
ArtifactMetadata::APK {
|
||||||
manifest,
|
manifest,
|
||||||
signature,
|
signatures,
|
||||||
} => {
|
} => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
@ -244,7 +141,11 @@ impl Display for ArtifactMetadata {
|
|||||||
manifest.package.as_ref().unwrap_or(&"missing".to_string()),
|
manifest.package.as_ref().unwrap_or(&"missing".to_string()),
|
||||||
manifest.version_name.as_ref().unwrap_or(&String::new()),
|
manifest.version_name.as_ref().unwrap_or(&String::new()),
|
||||||
manifest.version_code.as_ref().unwrap_or(&0),
|
manifest.version_code.as_ref().unwrap_or(&0),
|
||||||
signature
|
signatures
|
||||||
|
.iter()
|
||||||
|
.map(|b| b.to_string())
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join(", ")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -441,7 +342,7 @@ async fn load_artifact_url(url: &str) -> Result<RepoArtifact> {
|
|||||||
info!("Downloading artifact {}", url);
|
info!("Downloading artifact {}", url);
|
||||||
let u = Url::parse(url)?;
|
let u = Url::parse(url)?;
|
||||||
let rsp = reqwest::get(u.clone()).await?;
|
let rsp = reqwest::get(u.clone()).await?;
|
||||||
let id = hex::encode(sha2::Sha256::digest(url.as_bytes()));
|
let id = hex::encode(Sha256::digest(url.as_bytes()));
|
||||||
let mut tmp = temp_dir().join(id);
|
let mut tmp = temp_dir().join(id);
|
||||||
tmp.set_extension(
|
tmp.set_extension(
|
||||||
PathBuf::from(u.path())
|
PathBuf::from(u.path())
|
||||||
@ -480,7 +381,7 @@ fn load_artifact(path: &Path) -> Result<RepoArtifact> {
|
|||||||
fn load_apk_artifact(path: &Path) -> Result<RepoArtifact> {
|
fn load_apk_artifact(path: &Path) -> Result<RepoArtifact> {
|
||||||
let file = File::open(path)?;
|
let file = File::open(path)?;
|
||||||
let mut file = std::io::BufReader::new(file);
|
let mut file = std::io::BufReader::new(file);
|
||||||
let sig_block = load_signing_block(&mut file)?;
|
let sig_block = ApkSigningBlock::from_reader(&mut file)?;
|
||||||
|
|
||||||
let mut zip = ZipArchive::new(file)?;
|
let mut zip = ZipArchive::new(file)?;
|
||||||
let manifest = load_manifest(&mut zip)?;
|
let manifest = load_manifest(&mut zip)?;
|
||||||
@ -514,7 +415,7 @@ fn load_apk_artifact(path: &Path) -> Result<RepoArtifact> {
|
|||||||
},
|
},
|
||||||
metadata: ArtifactMetadata::APK {
|
metadata: ArtifactMetadata::APK {
|
||||||
manifest,
|
manifest,
|
||||||
signature: sig_block.try_into()?,
|
signatures: sig_block.get_signatures()?,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -545,180 +446,6 @@ where
|
|||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
struct ApkSigningBlock {
|
|
||||||
pub data: Vec<(u32, Vec<u8>)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryInto<ApkSignatureBlock> for ApkSigningBlock {
|
|
||||||
type Error = anyhow::Error;
|
|
||||||
|
|
||||||
fn try_into(self) -> std::result::Result<ApkSignatureBlock, Self::Error> {
|
|
||||||
const V2_SIG_BLOCK_ID: u32 = 0x7109871a;
|
|
||||||
const V3_SIG_BLOCK_ID: u32 = 0xf05368c0;
|
|
||||||
|
|
||||||
if let Some(v3) =
|
|
||||||
self.data
|
|
||||||
.iter()
|
|
||||||
.find_map(|(k, v)| if *k == V3_SIG_BLOCK_ID { Some(v) } else { None })
|
|
||||||
{
|
|
||||||
todo!("Not done yet")
|
|
||||||
}
|
|
||||||
if let Some(v2) =
|
|
||||||
self.data
|
|
||||||
.iter()
|
|
||||||
.find_map(|(k, v)| if *k == V2_SIG_BLOCK_ID { Some(v) } else { None })
|
|
||||||
{
|
|
||||||
let v2 = get_length_prefixed_u32_sequence(&v2[4..])?;
|
|
||||||
let signed_data = get_sequence(v2[0])?;
|
|
||||||
let digests = get_sequence_kv(signed_data[0])?;
|
|
||||||
let certificates = get_sequence(signed_data[1])?;
|
|
||||||
let attributes = get_sequence_kv(signed_data[2])?;
|
|
||||||
let signatures = get_sequence_kv(v2[1])?;
|
|
||||||
let public_key = v2[2];
|
|
||||||
let digests: HashMap<u32, &[u8]> = HashMap::from_iter(digests);
|
|
||||||
return Ok(ApkSignatureBlock::V2 {
|
|
||||||
attributes: HashMap::from_iter(
|
|
||||||
attributes.into_iter().map(|(k, v)| (k, v.to_vec())),
|
|
||||||
),
|
|
||||||
certificates: certificates.into_iter().map(|v| v.to_vec()).collect(),
|
|
||||||
signatures: signatures
|
|
||||||
.into_iter()
|
|
||||||
.filter_map(|(k, v)| {
|
|
||||||
let sig_len = u32::from_le_bytes(v[..4].try_into().ok()?) as usize;
|
|
||||||
if sig_len > v.len() - 4 {
|
|
||||||
warn!("Invalid signature length: {} > {}", sig_len, v.len());
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
if let Ok(a) = ApkSignatureAlgo::try_from(k) {
|
|
||||||
Some(ApkSignature {
|
|
||||||
algo: a,
|
|
||||||
digest: digests.get(&k).map(|v| v[4..].to_vec())?,
|
|
||||||
signature: v[4..sig_len + 4].to_vec(),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
public_key: public_key.to_vec(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Ok(ApkSignatureBlock::None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn load_signing_block<R>(zip: &mut R) -> Result<ApkSigningBlock>
|
|
||||||
where
|
|
||||||
R: Read + Seek,
|
|
||||||
{
|
|
||||||
const SIG_BLOCK_MAGIC: &[u8] = b"APK Sig Block 42";
|
|
||||||
|
|
||||||
// scan backwards until we find the singing block
|
|
||||||
let flen = zip.seek(SeekFrom::End(0))?;
|
|
||||||
let mut magic_buf = [0u8; 16];
|
|
||||||
loop {
|
|
||||||
let magic_pos = zip.seek(SeekFrom::Current(-17))?;
|
|
||||||
if magic_pos <= 4 {
|
|
||||||
bail!("Failed to find signing block");
|
|
||||||
}
|
|
||||||
|
|
||||||
zip.read_exact(&mut magic_buf)?;
|
|
||||||
if magic_buf == SIG_BLOCK_MAGIC {
|
|
||||||
zip.seek(SeekFrom::Current(-(16 + 8)))?;
|
|
||||||
let size1 = zip.read_u64::<LittleEndian>()?;
|
|
||||||
ensure!(size1 <= flen, "Signing block is larger than entire file");
|
|
||||||
|
|
||||||
zip.seek(SeekFrom::Current(-(size1 as i64 - 8)))?;
|
|
||||||
let size2 = zip.read_u64::<LittleEndian>()?;
|
|
||||||
ensure!(
|
|
||||||
size2 == size1,
|
|
||||||
"Invalid block sizes, {} != {}",
|
|
||||||
size1,
|
|
||||||
size2
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut data_bytes = size1 - 8 - 16;
|
|
||||||
let mut sigs = Vec::new();
|
|
||||||
loop {
|
|
||||||
let (k, v) = read_u64_length_prefixed_kv(zip)?;
|
|
||||||
data_bytes -= (v.len() + 4 + 8) as u64;
|
|
||||||
sigs.push((k, v));
|
|
||||||
if data_bytes == 0 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
zip.seek(SeekFrom::Start(0))?;
|
|
||||||
return Ok(ApkSigningBlock { data: sigs });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn read_u64_length_prefixed_kv<T>(file: &mut T) -> Result<(u32, Vec<u8>)>
|
|
||||||
where
|
|
||||||
T: Read + Seek,
|
|
||||||
{
|
|
||||||
let kv_len = file.read_u64::<LittleEndian>()?;
|
|
||||||
let k = file.read_u32::<LittleEndian>()?;
|
|
||||||
let v_len = kv_len as usize - 4;
|
|
||||||
let mut v = vec![0; v_len];
|
|
||||||
file.read_exact(v.as_mut_slice())?;
|
|
||||||
Ok((k, v))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn get_u64_length_prefixed_kv(slice: &[u8]) -> Result<(u32, &[u8])> {
|
|
||||||
let kv_len = u64::from_le_bytes(slice[..8].try_into()?);
|
|
||||||
let k = u32::from_le_bytes(slice[8..12].try_into()?);
|
|
||||||
Ok((k, &slice[12..(kv_len as usize - 12)]))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn get_u32_length_prefixed_kv(slice: &[u8]) -> Result<(u32, &[u8])> {
|
|
||||||
let kv_len = u32::from_le_bytes(slice[..4].try_into()?);
|
|
||||||
let k = u32::from_le_bytes(slice[4..8].try_into()?);
|
|
||||||
Ok((k, &slice[8..(kv_len as usize - 8)]))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn get_length_prefixed_u32(slice: &[u8]) -> Result<&[u8]> {
|
|
||||||
let len = u32::from_le_bytes(slice[..4].try_into()?);
|
|
||||||
Ok(&slice[4..4 + len as usize])
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn get_length_prefixed_u32_sequence(slice: &[u8]) -> Result<Vec<&[u8]>> {
|
|
||||||
let sequence_len = u32::from_le_bytes(slice[..4].try_into()?);
|
|
||||||
get_sequence(&slice[4..4 + sequence_len as usize])
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn get_sequence(mut slice: &[u8]) -> Result<Vec<&[u8]>> {
|
|
||||||
let mut ret = Vec::new();
|
|
||||||
while slice.len() >= 4 {
|
|
||||||
let data = get_length_prefixed_u32(slice)?;
|
|
||||||
let r_len = data.len() + 4;
|
|
||||||
slice = &slice[r_len..];
|
|
||||||
ret.push(data);
|
|
||||||
}
|
|
||||||
Ok(ret)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn get_sequence_kv(slice: &[u8]) -> Result<Vec<(u32, &[u8])>> {
|
|
||||||
let seq = get_sequence(slice)?;
|
|
||||||
Ok(seq
|
|
||||||
.into_iter()
|
|
||||||
.map(|s| {
|
|
||||||
let k = u32::from_le_bytes(s[..4].try_into().unwrap());
|
|
||||||
let v = &s[4..];
|
|
||||||
(k, v)
|
|
||||||
})
|
|
||||||
.collect())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn list_libs<T>(zip: &mut ZipArchive<T>) -> Vec<String>
|
fn list_libs<T>(zip: &mut ZipArchive<T>) -> Vec<String>
|
||||||
where
|
where
|
||||||
T: Read + Seek,
|
T: Read + Seek,
|
||||||
@ -734,98 +461,6 @@ where
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_android_manifest(data: &[u8]) -> Result<AndroidManifest> {
|
|
||||||
let chunks = if let Chunk::Xml(chunks) = Chunk::parse(&mut Cursor::new(data))? {
|
|
||||||
chunks
|
|
||||||
} else {
|
|
||||||
bail!("Invalid AndroidManifest file");
|
|
||||||
};
|
|
||||||
|
|
||||||
let strings = if let Chunk::StringPool(strings, _) = &chunks[0] {
|
|
||||||
HashMap::from_iter(
|
|
||||||
strings
|
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.map(|(i, s)| (s.to_string(), i as i32)),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
bail!("invalid manifest 1");
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut res = AndroidManifest::default();
|
|
||||||
res.package = find_value_in(&strings, &chunks, "manifest", "package");
|
|
||||||
res.version_code =
|
|
||||||
find_value_in(&strings, &chunks, "manifest", "versionCode").and_then(|v| v.parse().ok());
|
|
||||||
res.version_name = find_value_in(&strings, &chunks, "manifest", "versionName");
|
|
||||||
res.compile_sdk_version = find_value_in(&strings, &chunks, "manifest", "compileSdkVersion")
|
|
||||||
.and_then(|v| v.parse().ok());
|
|
||||||
res.compile_sdk_version_codename =
|
|
||||||
find_value_in(&strings, &chunks, "manifest", "compileSdkVersionCodename")
|
|
||||||
.and_then(|v| v.parse().ok());
|
|
||||||
res.platform_build_version_code =
|
|
||||||
find_value_in(&strings, &chunks, "manifest", "platformBuildVersionCode")
|
|
||||||
.and_then(|v| v.parse().ok());
|
|
||||||
res.platform_build_version_name =
|
|
||||||
find_value_in(&strings, &chunks, "manifest", "platformBuildVersionName")
|
|
||||||
.and_then(|v| v.parse().ok());
|
|
||||||
|
|
||||||
res.sdk.min_sdk_version =
|
|
||||||
find_value_in(&strings, &chunks, "uses-sdk", "minSdkVersion").and_then(|v| v.parse().ok());
|
|
||||||
res.sdk.target_sdk_version = find_value_in(&strings, &chunks, "uses-sdk", "targetSdkVersion")
|
|
||||||
.and_then(|v| v.parse().ok());
|
|
||||||
res.sdk.max_sdk_version =
|
|
||||||
find_value_in(&strings, &chunks, "uses-sdk", "maxSdkVersion").and_then(|v| v.parse().ok());
|
|
||||||
|
|
||||||
res.application.theme = find_value_in(&strings, &chunks, "application", "theme");
|
|
||||||
res.application.label = find_value_in(&strings, &chunks, "application", "label");
|
|
||||||
res.application.icon = find_value_in(&strings, &chunks, "application", "icon");
|
|
||||||
|
|
||||||
Ok(res)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_value_in(
|
|
||||||
strings: &HashMap<String, i32>,
|
|
||||||
chunks: &Vec<Chunk>,
|
|
||||||
node: &str,
|
|
||||||
attr: &str,
|
|
||||||
) -> Option<String> {
|
|
||||||
let idx_node = if let Some(i) = strings.get(node) {
|
|
||||||
*i
|
|
||||||
} else {
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
let idx_attr = if let Some(i) = strings.get(attr) {
|
|
||||||
*i
|
|
||||||
} else {
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
chunks.iter().find_map(|chunk| {
|
|
||||||
if let Chunk::XmlStartElement(_, el, attrs) = chunk {
|
|
||||||
match el.name {
|
|
||||||
x if x == idx_node => attrs.iter().find(|e| e.name == idx_attr).and_then(|e| {
|
|
||||||
debug!("{}, {}, {:?}", node, attr, e);
|
|
||||||
match e.typed_value.data_type {
|
|
||||||
3 => strings
|
|
||||||
.iter()
|
|
||||||
.find(|(_, v)| **v == e.raw_value)
|
|
||||||
.map(|(k, _)| k.clone()),
|
|
||||||
16 => Some(e.typed_value.data.to_string()),
|
|
||||||
_ => {
|
|
||||||
debug!("unknown data type {},{},{:?}", node, attr, e);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -833,17 +468,9 @@ mod tests {
|
|||||||
#[ignore]
|
#[ignore]
|
||||||
#[test]
|
#[test]
|
||||||
fn read_apk() -> Result<()> {
|
fn read_apk() -> Result<()> {
|
||||||
let path = "/home/kieran/Downloads/app-arm64-v8a-release.apk";
|
let path = "/home/kieran/Downloads/snort-arm64-v8a-v0.3.0.apk";
|
||||||
|
|
||||||
let apk = load_apk_artifact(&PathBuf::from(path))?;
|
let apk = load_apk_artifact(&PathBuf::from(path))?;
|
||||||
assert!(
|
|
||||||
matches!(&apk.platform, Platform::Android { arch } if matches!(arch, Architecture::ARM64 { .. }))
|
|
||||||
);
|
|
||||||
assert!(matches!(&apk.metadata,
|
|
||||||
ArtifactMetadata::APK { signature, .. } if matches!(signature,
|
|
||||||
ApkSignatureBlock::V2 { signatures, .. } if signatures.len() == 1 &&
|
|
||||||
matches!(signatures[0].algo, ApkSignatureAlgo::RsaSsaPkcs1Sha256))));
|
|
||||||
|
|
||||||
eprint!("{}", apk);
|
eprint!("{}", apk);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user