commit 96eff29088458b1a131947c320aba8831f4cd48a Author: uh wot Date: Mon Apr 4 22:46:13 2022 +0200 piss diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..5681796 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1132 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aes" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfe0133578c0986e1fe3dfcd4af1cc5b2dd6c3dbf534d69916ce16a2701d40ba" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "block-buffer" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-padding" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a90ec2df9600c28a01c56c4784c9207a96d2451833aeceb8cc97e4c9548bb78" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" + +[[package]] +name = "cbc" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" +dependencies = [ + "cipher", +] + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cipher" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1873270f8f7942c191139cb8a40fd228da6c3fd2fc376d7e92d47aa14aeb59e" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "clap" +version = "3.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8c93436c21e4698bacadf42917db28b23017027a4deccb35dbe47a7e7840123" +dependencies = [ + "atty", + "bitflags", + "clap_derive", + "indexmap", + "lazy_static", + "os_str_bytes", + "strsim", + "termcolor", + "textwrap", +] + +[[package]] +name = "clap_derive" +version = "3.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da95d038ede1a964ce99f49cbe27a7fb538d1da595e4b4f70b8c8f338d17bf16" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "cpufeatures" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "ctr" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d14f329cfbaf5d0e06b5e87fff7e265d2673c5ea7d2c27691a2c107db1442a0" +dependencies = [ + "cipher", +] + +[[package]] +name = "digest" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + +[[package]] +name = "encoding_rs" +version = "0.8.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dc8abb250ffdda33912550faa54c88ec8b998dec0b2c55ab224921ce11df" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +dependencies = [ + "matches", + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" + +[[package]] +name = "futures-sink" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" + +[[package]] +name = "futures-task" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" + +[[package]] +name = "futures-util" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "pin-utils", +] + +[[package]] +name = "generic-array" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "h2" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62eeb471aa3e3c9197aa4bfeabfe02982f6dc96f750486c0bb0009ac58b26d2b" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" + +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hkdf" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "http" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31f4c6746584866f0feabcc69893c5b51beef3831656a968ed7ae254cdc4fd03" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9100414882e15fb7feccb4897e5f0ff0ff1ca7d1a86a23208ada4d7a18e6c6c4" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "hyper" +version = "0.14.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b26ae0a80afebe130861d90abf98e3814a4f28a4c6ffeb5ab8ebb2be311e0ef2" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d87c48c02e0dc5e3b849a2041db3029fd066650f8f717c07bf8ed78ccb895cac" +dependencies = [ + "http", + "hyper", + "rustls", + "tokio", + "tokio-rustls", +] + +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "inout" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1f03d4ab4d5dc9ec2d219f86c15d2a15fc08239d1cd3b2d6a19717c0a2f443" +dependencies = [ + "block-padding", + "generic-array", +] + +[[package]] +name = "ipnet" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35e70ee094dc02fd9c13fdad4940090f22dbd6ac7c9e7094a46cf0232a50bc7c" + +[[package]] +name = "itoa" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" + +[[package]] +name = "js-sys" +version = "0.3.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a38fc24e30fd564ce974c02bf1d337caddff65be6cc4735a1f7eab22a7440f04" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.121" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f" + +[[package]] +name = "log" +version = "0.4.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "matches" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" + +[[package]] +name = "md-5" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "658646b21e0b72f7866c7038ab086d3d5e1cd6271f060fd37defb241949d0582" +dependencies = [ + "digest", +] + +[[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + +[[package]] +name = "mime" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" + +[[package]] +name = "mio" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52da4364ffb0e4fe33a9841a98a3f3014fb964045ce4f7a45a398243c8d6b0c9" +dependencies = [ + "libc", + "log", + "miow", + "ntapi", + "wasi", + "winapi", +] + +[[package]] +name = "miow" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" +dependencies = [ + "winapi", +] + +[[package]] +name = "ntapi" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f" +dependencies = [ + "winapi", +] + +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" + +[[package]] +name = "os_str_bytes" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" +dependencies = [ + "memchr", +] + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "pin-project-lite" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "632d02bff7f874a36f33ea8bb416cd484b90cc66c1194b1a1110d067a7013f58" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "reqwest" +version = "0.11.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46a1f7aa4f35e5e8b4160449f51afc758f0ce6454315a9fa7d0d113e958c41eb" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-rustls", + "ipnet", + "js-sys", + "lazy_static", + "log", + "mime", + "percent-encoding", + "pin-project-lite", + "rustls", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-rustls", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots", + "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", + "web-sys", + "winapi", +] + +[[package]] +name = "rustls" +version = "0.20.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fbfeb8d0ddb84706bc597a5574ab8912817c52a397f819e5b614e2265206921" +dependencies = [ + "log", + "ring", + "sct", + "webpki", +] + +[[package]] +name = "rustls-pemfile" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ee86d63972a7c661d1536fefe8c3c8407321c3df668891286de28abcd087360" +dependencies = [ + "base64", +] + +[[package]] +name = "ryu" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" + +[[package]] +name = "sct" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "serde" +version = "1.0.136" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.136" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "slab" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" + +[[package]] +name = "socket2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "syn" +version = "1.0.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "704df27628939572cd88d33f171cd6f896f4eaca85252c6e0a72d8d8287ee86f" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "termcolor" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" + +[[package]] +name = "tinyvec" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "tokio" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af73ac49756f3f7c01172e34a23e5d0216f6c32333757c2c61feb2bbff5a5ee" +dependencies = [ + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", + "pin-project-lite", + "socket2", + "tokio-macros", + "winapi", +] + +[[package]] +name = "tokio-macros" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-rustls" +version = "0.23.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4151fda0cf2798550ad0b34bcfc9b9dcc2a9d2471c895c68f3a8818e54f2389e" +dependencies = [ + "rustls", + "tokio", + "webpki", +] + +[[package]] +name = "tokio-util" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "log", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tower-service" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" + +[[package]] +name = "tracing" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a1bdf54a7c28a2bbf701e1d2233f6c77f473486b94bee4f9678da5a148dca7f" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa31669fa42c09c34d94d8165dd2012e8ff3c66aca50f3bb226b68f216f2706c" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "trk_dec" +version = "0.1.0" +dependencies = [ + "aes", + "base64", + "byteorder", + "cbc", + "clap", + "ctr", + "hex", + "hkdf", + "md-5", + "reqwest", + "serde", + "serde_json", + "serde_urlencoded", + "sha2", + "tokio", +] + +[[package]] +name = "try-lock" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "unicode-bidi" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" + +[[package]] +name = "unicode-normalization" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "url" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" +dependencies = [ + "form_urlencoded", + "idna", + "matches", + "percent-encoding", +] + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25f1af7423d8588a3d840681122e72e6a24ddbcb3f0ec385cac0d12d24256c06" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b21c0df030f5a177f3cba22e9bc4322695ec43e7257d865302900290bcdedca" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eb6ec270a31b1d3c7e266b999739109abce8b6c87e4b31fcfcd788b65267395" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4203d69e40a52ee523b2529a773d5ffc1dc0071801c87b3d270b471b80ed01" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa8a30d46208db204854cadbb5d4baf5fcf8071ba5bf48190c3e59937962ebc" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d958d035c4438e28c70e4321a2911302f10135ce78a9c7834c0cab4123d06a2" + +[[package]] +name = "web-sys" +version = "0.3.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c060b319f29dd25724f09a2ba1418f142f539b2be99fbf4d2d5a8f7330afb8eb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "webpki-roots" +version = "0.22.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552ceb903e957524388c4d3475725ff2c8b7960922063af6ce53c9a43da07449" +dependencies = [ + "webpki", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "winreg" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +dependencies = [ + "winapi", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..cb7cc69 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "trk_dec" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +clap = { version = "3.0", features = ["derive"] } +reqwest = { version = "0.11", features = ["rustls-tls", "json"], default-features = false } +serde = { version = "1.0", features = ["derive"] } +serde_urlencoded = "0.7" +serde_json = "1.0" +tokio = { version = "1.17", features = ["rt-multi-thread", "macros"] } +md-5 = "0.10" +hex = "0.4" +byteorder = "1.4" + +base64 = "0.13" +hkdf = "0.12" +sha2 = "0.10" +aes = "0.8" +cbc = "0.1" +ctr = "0.9" \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..5dd81c9 --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# qobuz decryptor crap + +build: it's `cargo build` u ass + +usage: `./trk_dec ` \ No newline at end of file diff --git a/src/api.rs b/src/api.rs new file mode 100644 index 0000000..201d56f --- /dev/null +++ b/src/api.rs @@ -0,0 +1,202 @@ +use std::{time::{SystemTime, UNIX_EPOCH}, io::Write}; + +use reqwest::Client; +use serde::Deserialize; +use serde::{Serialize, de::DeserializeOwned}; +use serde_json::json; +use clap::ArgEnum; + +use crate::crypto::{gen_signed_req, get_session_key, get_track_key, decrypt_frame}; +use crate::mp4::{parse_segment, BoxType, ExtBoxType}; + +const API_URL: &str = "https://www.qobuz.com/api.json/0.2/"; + +const APP_ID: u32 = 950096963; + +const USER_AGENT: &str = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36"; + +#[derive(Clone, ArgEnum, Debug)] +pub enum Method { + GET, + POST +} + +pub struct APIClient { + client: Client, + auth_token: Option, + session: Session +} + +impl APIClient { + pub fn new() -> Self { + let client = Client::builder() + .user_agent(USER_AGENT) + .build() + .unwrap(); + + Self { + client, + auth_token: None, + session: Session { + id: String::new(), + key: [0u8; 16], + expiry: 0 + } + } + } + + pub fn set_auth_token(&mut self, auth_token: &str) { + self.auth_token = Some(auth_token.to_string()); + } + + pub async fn api_call(&self, object: &str, method: &str, params: &T, req_method: Method, signed: bool) -> Result + where T: Serialize + ?Sized, + R: DeserializeOwned { + let url = format!("{API_URL}{object}/{method}"); + let reqwest_method = match req_method { + Method::GET => reqwest::Method::GET, + Method::POST => reqwest::Method::POST + }; + + let mut req = self.client.request(reqwest_method, url) + .header("x-app-id", APP_ID); + + if let Some(token) = &self.auth_token { + req = req.header("x-user-auth-token", token); + } + + match req_method { + Method::GET => { + if signed { + req = req.query(&gen_signed_req(object, method, params)); + } + req = req.query(params); + }, + Method::POST => { + let mut form_data = String::new(); + if signed { + form_data.push_str(&serde_urlencoded::to_string(&gen_signed_req(object, method, params)).unwrap()); + } + let params_form = serde_urlencoded::to_string(params).unwrap(); + if !params_form.is_empty() { + form_data.push('&'); + form_data.push_str(¶ms_form); + } + req = req.body(form_data) + .header("content-type", "application/x-www-form-urlencoded"); + } + } + + if object == "file" && method == "url" { + req = req.header("x-session-id", &self.session.id); + } + + let resp = req.send().await? + .error_for_status()?; + + resp.json().await + } + + pub async fn renew_session(&mut self) { + let timestamp = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_secs(); + + if timestamp >= self.session.expiry { + let resp: SessionResp = self.api_call("session", "start", &json!({"profile":"qbz-1"}), Method::POST, true).await.unwrap(); + + self.session.id = resp.session_id; + get_session_key(&resp.infos, &mut self.session.key); + self.session.expiry = resp.expires_at; + } + } + + pub async fn get_track_url(&mut self, track_id: u32, format_id: u32) -> Result { + self.renew_session().await; + + let params = json!( + { + "track_id": track_id, + "format_id": format_id, + "intent": "stream" + } + ); + + let resp: TrackUrlResp = self.api_call("file", "url", ¶ms, Method::GET, true).await?; + let mut key = [0u8; 16]; + get_track_key(&resp.key, &self.session.key, &mut key); + + Ok(TrackUrl { + url_template: resp.url_template, + key, + n_segments: resp.n_segments + }) + } + + pub async fn dl_track(&self, url_template: &str, key: &[u8; 16], n_segments: u64, out: &mut T) -> Result<(), reqwest::Error> + where T: Write { + for seg in 0..n_segments + 1 { + let resp = self.client.get(url_template.replace("$SEGMENT$", &seg.to_string())) + .send().await? + .error_for_status()?; + + let block = resp.bytes().await?; + + let boxes = parse_segment(&block); + println!("segment {}", seg); + //println!("{:#?}", boxes); + for atom in &boxes { + println!("box size {}", atom.box_data.len()); + if let BoxType::ExtendedBox {ext_box_type, ..} = &atom.box_type { + match ext_box_type { + ExtBoxType::Init { initial_data, .. } => { + out.write_all(initial_data).unwrap(); + }, + ExtBoxType::Segment {frames, ..} => { + for frame in frames { + if frame.flags != 0 { + let frame_data = decrypt_frame(&frame.frame_data, &key, &frame.iv_raw); + out.write_all(&frame_data).unwrap(); + } else { + out.write_all(frame.frame_data).unwrap(); + } + } + } + } + } + } + /*for b in boxes { + out.write_all(b.box_data).unwrap(); + }*/ + }; + + Ok(()) + } +} + +#[derive(Deserialize)] +struct TrackUrlResp { + url_template: String, + key: String, + n_segments: u64 +} + +pub struct TrackUrl { + pub url_template: String, + pub key: [u8; 16], + pub n_segments: u64 +} + +#[derive(Deserialize)] +struct SessionResp { + session_id: String, + infos: String, + expires_at: u64 +} + +struct Session { + id: String, + key: [u8; 16], + expiry: u64 +} \ No newline at end of file diff --git a/src/crypto.rs b/src/crypto.rs new file mode 100644 index 0000000..996ea9b --- /dev/null +++ b/src/crypto.rs @@ -0,0 +1,84 @@ +use std::collections::BTreeMap; +use std::time::{SystemTime, UNIX_EPOCH}; + +use serde::{ser, Serialize}; +use md5::{Md5, Digest}; +use aes::cipher::{KeyIvInit, BlockDecryptMut, block_padding::NoPadding, StreamCipher}; +use sha2::Sha256; +use hkdf::Hkdf; + +const APP_SECRET: &str = "979549437fcc4a3faad4867b5cd25dcb"; + +type Aes128CbcDec = cbc::Decryptor; +type Aes128Ctr64BE = ctr::Ctr64BE; + +#[derive(Serialize)] +pub struct SignedReq { + pub request_ts: u64, + pub request_sig: String, +} + +pub fn gen_signed_req(object: &str, method: &str, params: &T) -> SignedReq +where T: ser::Serialize + ?Sized { + let timestamp = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_secs(); + + let mut signature = format!("{object}{method}"); + + let params = serde_urlencoded::to_string(params).unwrap(); + let params: BTreeMap = serde_urlencoded::from_str(¶ms).unwrap(); + for (key, val) in params { + signature.push_str(&key); + signature.push_str(&val); + }; + + signature.push_str(×tamp.to_string()); + signature.push_str(APP_SECRET); + + let mut hasher = Md5::new(); + hasher.update(signature); + let signature = hex::encode(hasher.finalize()); + + SignedReq {request_ts: timestamp, request_sig: signature} +} + +pub fn get_session_key(infos: &str, out: &mut [u8; 16]) { + let mut infos = infos.split('.'); + let salt = infos.next().unwrap(); + let info = infos.next().unwrap(); + + let salt = base64::decode_config(salt, base64::URL_SAFE_NO_PAD).unwrap(); + let info = base64::decode_config(info, base64::URL_SAFE_NO_PAD).unwrap(); + + let hk = Hkdf::::new(Some(&salt), &hex::decode(APP_SECRET).unwrap()); + hk.expand(&info, out).unwrap(); +} + +pub fn get_track_key(key_str: &str, session_key: &[u8; 16], out: &mut [u8; 16]) { + let mut key = key_str.split('.'); + key.next(); + + let mut trk_key = [0u8; 32]; + let mut iv = [0u8; 16]; + + base64::decode_config_slice(key.next().unwrap(), base64::URL_SAFE_NO_PAD, &mut trk_key).unwrap(); + base64::decode_config_slice(key.next().unwrap(), base64::URL_SAFE_NO_PAD, &mut iv).unwrap(); + + Aes128CbcDec::new(session_key.into(), &iv.into()) + .decrypt_padded_b2b_mut::(&trk_key[..16], out) + .unwrap(); +} + +pub fn decrypt_frame(frame: &[u8], key: &[u8; 16], iv_raw: &[u8]) -> Vec { + let mut out = vec![0u8; frame.len()]; + + let mut iv = [0u8; 16]; + iv[..iv_raw.len()].copy_from_slice(iv_raw); + + Aes128Ctr64BE::new(key.into(), &iv.into()) + .apply_keystream_b2b(frame, &mut out) + .unwrap(); + out +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..30751d9 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,38 @@ +use std::fs::File; + +use clap::Parser; + +mod api; +use api::APIClient; + +mod crypto; +mod mp4; + +#[derive(Parser, Debug)] +struct Args { + auth_token: String, + track_id: u32, + format_id: u32 +} + +#[tokio::main] +async fn main() { + let args = Args::parse(); + + let mut client = APIClient::new(); + client.set_auth_token(&args.auth_token); + + let url_resp = client.get_track_url(args.track_id, args.format_id).await.unwrap(); + + println!("{}", url_resp.url_template); + println!("{}", hex::encode(url_resp.key)); + println!("{}", url_resp.n_segments); + + let track_id = args.track_id; + let format_id = args.format_id; + + let path = format!("{track_id}-{format_id}"); + let mut file = File::create(path).unwrap(); + + client.dl_track(&url_resp.url_template, &url_resp.key, url_resp.n_segments, &mut file).await.unwrap(); +} \ No newline at end of file diff --git a/src/mp4.rs b/src/mp4.rs new file mode 100644 index 0000000..2088304 --- /dev/null +++ b/src/mp4.rs @@ -0,0 +1,188 @@ +use std::io::{Cursor, Read}; +use byteorder::{BigEndian, ReadBytesExt}; + +#[derive(Debug)] +pub struct Box<'a> { + pub box_data: &'a [u8], + pub box_type: BoxType<'a>, +} + +#[derive(Debug)] +pub enum BoxType<'a> { + Box { box_type: String }, + ExtendedBox { ext_box_type: ExtBoxType<'a>, version: u8, flags: u32 }, +} + +#[derive(Debug)] +pub enum ExtBoxType<'a> { + Init { + track_id: u32, + file_id: u32, + sample_rate: u32, + bits_per_sample: u8, + channels_count: u8, + samples_count: u64, + initial_data_size: u16, + initial_data: &'a [u8], + key_id_size: u8, + key_id: &'a [u8], + segments_count: u16, + segment_infos: Vec + }, + Segment { + base_offset: u32, + iv_size: u8, + n_frames: u32, + frames: Vec> + } +} + +#[derive(Debug)] +pub struct SegmentInfo { + pub length: u32, + pub samples_count: u32 +} + +#[derive(Debug)] +pub struct Frame<'a> { + pub length: u32, + pub samples_count: u16, + pub flags: u16, + pub iv_raw: &'a [u8], + pub frame_data: &'a [u8] +} + +pub fn parse_segment(buf: &[u8]) -> Vec { + let mut reader = Cursor::new(buf); + let mut boxes: Vec = Vec::new(); + + while reader.position() < buf.len() as u64 { + let size = reader.read_u32::().unwrap(); + + let box_start = reader.position() - 4; + let box_end = box_start + size as u64; + + let box_data = &buf[reader.position() as usize..box_end as usize]; + let mut box_reader = Cursor::new(box_data); + + let mut box_type = [0u8; 4]; + box_reader.read_exact(&mut box_type).unwrap(); + let box_type = String::from_utf8(box_type.to_vec()).unwrap(); + + let box_type_enum; + + if box_type == "uuid" { + let uuid = box_reader.read_u128::().unwrap(); + let uuid = format!("{:016x}", uuid); + let version = box_reader.read_u8().unwrap(); + let flags = box_reader.read_u24::().unwrap(); + + let ext_box_data = &box_data[box_reader.position() as usize..]; + + let ext_box_type = match uuid.as_str() { + "c7c75df0fdd951e98fc22971e4acf8d2" => parse_init_box(ext_box_data), + "3b42129256f35f75923663b69a1f52b2" => parse_segment_box(ext_box_data, box_start, buf), + _ => panic!("Unknown extended box type: {}", uuid) + }; + + box_type_enum = BoxType::ExtendedBox { + ext_box_type, + version, + flags + }; + } else { + box_type_enum = BoxType::Box { + box_type + }; + } + + boxes.push(Box { + box_data, + box_type: box_type_enum + }); + + reader.set_position(box_end); + } + + boxes +} + +fn parse_init_box<'a>(buf: &'a [u8]) -> ExtBoxType<'a> { + let mut reader = Cursor::new(buf); + + let track_id = reader.read_u32::().unwrap(); + let file_id = reader.read_u32::().unwrap(); + let sample_rate = reader.read_u32::().unwrap(); + let bits_per_sample = reader.read_u8().unwrap(); + let channels_count = reader.read_u8().unwrap(); + let samples_count = reader.read_u64::().unwrap(); + let initial_data_size = reader.read_u16::().unwrap(); + let initial_data = &buf[reader.position() as usize..reader.position() as usize + initial_data_size as usize]; + reader.set_position(reader.position() + initial_data_size as u64); + let key_id_size = reader.read_u8().unwrap(); + let key_id = &buf[reader.position() as usize..reader.position() as usize + key_id_size as usize]; + reader.set_position(reader.position() + key_id_size as u64); + let segments_count = reader.read_u16::().unwrap(); + + let mut segment_infos: Vec = Vec::new(); + for _ in 0..segments_count { + segment_infos.push(SegmentInfo { + length: reader.read_u32::().unwrap(), + samples_count: reader.read_u32::().unwrap() + }); + } + + ExtBoxType::Init { + track_id, + file_id, + sample_rate, + bits_per_sample, + channels_count, + samples_count, + initial_data_size, + initial_data, + key_id_size, + key_id, + segments_count, + segment_infos + } +} + +fn parse_segment_box<'a>(buf: &'a [u8], box_start: u64, seg_buf: &'a [u8]) -> ExtBoxType<'a> { + let mut reader = Cursor::new(buf); + + let base_offset = reader.read_u32::().unwrap(); + let iv_size = reader.read_u8().unwrap(); + let n_frames = reader.read_u24::().unwrap(); + + let mut frames: Vec> = Vec::new(); + let mut frame_start = box_start as usize + base_offset as usize; + for _ in 0..n_frames { + let length = reader.read_u32::().unwrap(); + let samples_count = reader.read_u16::().unwrap(); + let flags = reader.read_u16::().unwrap(); + let iv_raw = &buf[reader.position() as usize..reader.position() as usize + iv_size as usize]; + reader.set_position(reader.position() + iv_size as u64); + + let frame_end = frame_start + length as usize; + + let frame_data = &seg_buf[frame_start..frame_end]; + + frames.push(Frame { + length, + samples_count, + flags, + iv_raw, + frame_data + }); + + frame_start = frame_end; + } + + ExtBoxType::Segment { + base_offset, + iv_size, + n_frames, + frames + } +} \ No newline at end of file