diff --git a/.commitlintrc.json b/.commitlintrc.json index 9f92ea5b..52daaa18 100644 --- a/.commitlintrc.json +++ b/.commitlintrc.json @@ -13,6 +13,7 @@ "docs", "feat", "fix", + "merge", "refactor", "release", "revert", diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 78c02ba4..36fd05e7 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -125,11 +125,11 @@ jobs: - name: Build shell: bash - run: cargo build --verbose + run: cargo build --verbose --features tpm - name: Run tests shell: bash - run: cargo test --verbose + run: cargo test --verbose --features tpm - name: Extract crate information shell: bash diff --git a/Cargo.lock b/Cargo.lock index afbc2edc..b59be125 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + [[package]] name = "aead" version = "0.6.1" @@ -56,13 +62,40 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba" dependencies = [ "memchr", ] +[[package]] +name = "aligned" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee4508988c62edf04abd8d92897fca0c2995d907ce1dfeaf369dac3716a40685" +dependencies = [ + "as-slice", +] + +[[package]] +name = "aligned-vec" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b" +dependencies = [ + "equator", +] + +[[package]] +name = "android_system_properties" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae221649c9976a6f6c56ae1facf410f3ddb33cc661c4b7b61020a912d4237fbc" +dependencies = [ + "libc", +] + [[package]] name = "anstream" version = "1.0.0" @@ -115,9 +148,50 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.102" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" + +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + +[[package]] +name = "arbitrary" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bc62ac97cc33321f50863d514c3bc38a453947a8f9e781137e47c7401020aed" + +[[package]] +name = "arg_enum_proc_macro" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "arrayvec" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" + +[[package]] +name = "as-slice" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +checksum = "516b6b4f0e40d50dcda9365d53964ec74560ad4284da2e7fc97122cd83174516" +dependencies = [ + "stable_deref_trait", +] [[package]] name = "async-broadcast" @@ -164,13 +238,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" dependencies = [ "autocfg", - "cfg-if", + "cfg-if 1.0.5", "concurrent-queue", "futures-io", "futures-lite", "parking", "polling", - "rustix", + "rustix 1.1.5", "slab", "windows-sys 0.61.2", ] @@ -198,36 +272,36 @@ dependencies = [ "async-signal", "async-task", "blocking", - "cfg-if", + "cfg-if 1.0.5", "event-listener", "futures-lite", - "rustix", + "rustix 1.1.5", ] [[package]] name = "async-recursion" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" +checksum = "4f8abc12baad266b1c8cec146854c195b5864b4221d4b2ca7296a7ae82d9e451" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.9", ] [[package]] name = "async-signal" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43c070bbf59cd3570b6b2dd54cd772527c7c3620fce8be898406dd3ed6adc64c" +checksum = "52b5aaafa020cf5053a01f2a60e8ff5dccf550f0f77ec54a4e47285ac2bab485" dependencies = [ "async-io", "async-lock", "atomic-waker", - "cfg-if", + "cfg-if 1.0.5", "futures-core", "futures-io", - "rustix", + "rustix 1.1.5", "signal-hook-registry", "slab", "windows-sys 0.61.2", @@ -241,13 +315,13 @@ checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-trait" -version = "0.1.89" +version = "0.1.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +checksum = "82f6aeea286b8eb4dd3431a1be1b59d290ace00f5bfd8e2a159bc2a05e2c1667" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.9", ] [[package]] @@ -269,9 +343,75 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.5.0" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "av-scenechange" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f321d77c20e19b92c39e7471cf986812cbb46659d2af674adc4331ef3f18394" +dependencies = [ + "aligned", + "anyhow", + "arg_enum_proc_macro", + "arrayvec", + "log", + "num-rational", + "num-traits", + "pastey", + "rayon", + "thiserror 2.0.21", + "v_frame", + "y4m", +] + +[[package]] +name = "av1-grain" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cfddb07216410377231960af4fcab838eaa12e013417781b78bd95ee22077f8" +dependencies = [ + "anyhow", + "arrayvec", + "log", + "nom 8.0.0", + "num-rational", + "v_frame", +] + +[[package]] +name = "avif-serialize" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7178fe5f7d460b13895ebb9dcb28a3a6216d2df2574a0806cb51b555d297f38" +dependencies = [ + "arrayvec", +] + +[[package]] +name = "aws-lc-rs" +version = "1.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faac5829c2b74c28f830747e7818ccfb684261b5f48a1118b1e2a13d36dfab13" +dependencies = [ + "aws-lc-sys", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +checksum = "f1622d8446a2d4b2ce0c7eefc73dd43a99779028d5ee5c2dd8073a658ba8a2bc" +dependencies = [ + "cc", + "cmake", + "dunce", + "fs_extra", + "pkg-config", +] [[package]] name = "base16ct" @@ -297,37 +437,100 @@ version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" +[[package]] +name = "bindgen" +version = "0.65.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfdf7b466f9a4903edc73f95d6d2bcd5baf8ae620638762244d3f60143643cc5" +dependencies = [ + "bitflags 1.3.2", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "prettyplease 0.2.37", + "proc-macro2", + "quote", + "regex", + "rustc-hash 1.1.0", + "shlex 1.3.0", + "syn 2.0.119", + "which 4.4.2", +] + +[[package]] +name = "bit_field" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6" + [[package]] name = "bitfield" -version = "0.19.4" +version = "0.19.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21ba6517c6b0f2bf08be60e187ab64b038438f22dd755614d8fe4d4098c46419" +checksum = "b45721c9db4c7a20899d05efb7ad9235f50b256e980db30ffb229abf732934c3" dependencies = [ "bitfield-macros", ] [[package]] name = "bitfield-macros" -version = "0.19.4" +version = "0.19.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f48d6ace212fdf1b45fd6b566bb40808415344642b76c3224c07c8df9da81e97" +checksum = "c0cb6f3d4773a2107b94cbeccaa5b5f0b35a88389b5d522d13d659f64317b22d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.9", ] +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "bitflags" version = "2.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06" +[[package]] +name = "bitstream-io" +version = "4.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eff00be299a18769011411c9def0d827e8f2d7bf0c3dbf53633147a8867fd1f" +dependencies = [ + "no_std_io2", +] + +[[package]] +name = "blake3" +version = "1.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d9e454fc11f76977dc803893aff6304ed33d6a26efae8696573bea74baa27ae" +dependencies = [ + "arrayvec", + "cc", + "cfg-if 1.0.5", + "constant_time_eq", + "cpufeatures", +] + +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + [[package]] name = "block-buffer" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" dependencies = [ "hybrid-array", ] @@ -352,9 +555,9 @@ dependencies = [ [[package]] name = "blocking" -version = "1.6.2" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" +checksum = "a70e4329df6cb94385eed412ec92375c3cdd8a6e502493d1229b6414e4036dfa" dependencies = [ "async-channel", "async-task", @@ -363,11 +566,63 @@ dependencies = [ "piper", ] +[[package]] +name = "bon" +version = "3.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a05442cd7005532d0cfedec676b5b9333d2b4c7c3afabe2b1a9ce2742fbe2ee6" +dependencies = [ + "bon-macros", +] + +[[package]] +name = "bon-macros" +version = "3.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93833e97ac7c46ba97045afcf247238c27057538fcf2f06344662ddd5f567be6" +dependencies = [ + "darling", + "ident_case", + "prettyplease 0.3.0", + "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[package]] +name = "bstr" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bb31b46c14244e20ee9984b11bf5c992b91fb6939fea616e3512c8baecdbe5f" +dependencies = [ + "memchr", + "regex-automata", + "serde_core", +] + +[[package]] +name = "built" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c0e531d93d39c34eef561e929e8a7f86d77a5af08aac4f6d6e39976c51858e9" + [[package]] name = "bumpalo" -version = "3.20.2" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" + +[[package]] +name = "bytemuck" +version = "1.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797" + +[[package]] +name = "byteorder-lite" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" [[package]] name = "bytes" @@ -386,48 +641,76 @@ dependencies = [ [[package]] name = "cbor4ii" -version = "1.2.2" +version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faed1a83001dc2c9201451030cc317e35bef36c84d3781d7c5bb9f343c397da8" +checksum = "cae341ca01ee91c1e68cbcbd9f08e5c9fb6171c7daed060625563232520d37ae" dependencies = [ "serde", ] [[package]] name = "cc" -version = "1.2.56" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" +checksum = "86e055fa6e3e40ad6187ba25b6855eeb635d5271f8e0f0e1e9a5826b8d75bea0" dependencies = [ "find-msvc-tools", "jobserver", "libc", - "shlex 1.3.0", + "shlex 2.0.1", +] + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom 7.1.3", ] [[package]] name = "cfg-if" -version = "1.0.4" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cfg-if" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600" [[package]] name = "cfg_aliases" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527" [[package]] name = "chacha20" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81" +checksum = "65c35e4b699c7e15ccbe7ee35c005e4fc0a278d22238a2857e6ce2dadeda1b06" dependencies = [ - "cfg-if", + "cfg-if 1.0.5", "cpufeatures", "rand_core 0.10.1", ] +[[package]] +name = "chrono" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-link", +] + [[package]] name = "ciborium" version = "0.2.2" @@ -466,6 +749,17 @@ dependencies = [ "inout", ] +[[package]] +name = "clang-sys" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "157a8ba7b480713b56f4c09fd13fc3e0a22a5dfab8097ba61cbc5feef950788a" +dependencies = [ + "glob", + "libc", + "libloading", +] + [[package]] name = "clap" version = "4.6.7" @@ -533,21 +827,83 @@ dependencies = [ [[package]] name = "clap_lex" -version = "1.0.0" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c133bc6a41be0d194c306b5506d15e6feeea7b1d6604bd3f8310dfb2ca96486" + +[[package]] +name = "cmake" +version = "0.1.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831" +checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" +dependencies = [ + "cc", +] [[package]] name = "cmov" -version = "0.5.2" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a" + +[[package]] +name = "cocoa" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c49e86fc36d5704151f5996b7b3795385f50ce09e3be0f47a0cfde869681cf8" +dependencies = [ + "bitflags 1.3.2", + "block", + "core-foundation 0.7.0", + "core-graphics", + "foreign-types", + "libc", + "objc", +] + +[[package]] +name = "cocoa-foundation" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81411967c50ee9a1fc11365f8c585f863a22a9697c89239c452292c40ba79b0d" +dependencies = [ + "bitflags 2.13.2", + "block", + "core-foundation 0.10.1", + "core-graphics-types", + "objc", +] + +[[package]] +name = "color_quant" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de0758edba32d61d1fd9f4d69491b47604b91ee2f7e6b33de7e54ca4ebe55dc3" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[package]] name = "colorchoice" -version = "1.0.4" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" + +[[package]] +name = "colored" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "combine" +version = "4.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" +checksum = "4356eba6976435498d05a311ee9fc486da3bc81c200d3f0d7dd9703b41913f92" +dependencies = [ + "bytes", + "memchr", +] [[package]] name = "concurrent-queue" @@ -570,20 +926,27 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" +[[package]] +name = "const-str" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18f12cc9948ed9604230cdddc7c86e270f9401ccbe3c2e98a4378c5e7632212f" + [[package]] name = "const_format" -version = "0.2.35" +version = "0.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7faa7469a93a566e9ccc1c73fe783b4a65c274c5ace346038dca9c39fe0030ad" +checksum = "a3decb4d6965448659923544a634a0571ba44cede4e11ef15a5a317126840454" dependencies = [ "const_format_proc_macros", + "konst 0.2.20", ] [[package]] name = "const_format_proc_macros" -version = "0.2.34" +version = "0.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" +checksum = "941b570269a642506f08cb5b688c04bfa6cfd41a26f8bcdc49db8fd00c0ab659" dependencies = [ "proc-macro2", "quote", @@ -591,25 +954,182 @@ dependencies = [ ] [[package]] -name = "cpubits" -version = "0.1.1" +name = "const_panic" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15b85f9c39137c3a891689859392b1bd49812121d0d61c9caf00d46ed5ce06ae" +checksum = "9603f79528ece8163c496f8932121cb36cfe46259e9c907bb3d8205139d7caa3" +dependencies = [ + "typewit", +] [[package]] -name = "cpufeatures" +name = "constant_time_eq" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" + +[[package]] +name = "core-foundation" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171" +dependencies = [ + "core-foundation-sys 0.7.0", + "libc", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys 0.8.7", + "libc", +] + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys 0.8.7", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac" + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "core-graphics" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3889374e6ea6ab25dba90bb5d96202f61108058361f6dc72e8b03e6f8bbe923" +dependencies = [ + "bitflags 1.3.2", + "core-foundation 0.7.0", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" +dependencies = [ + "bitflags 2.13.2", + "core-foundation 0.10.1", + "libc", +] + +[[package]] +name = "core-media-sys" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "273bf3fc5bf51fd06a7766a84788c1540b6527130a0bce39e00567d6ab9f31f1" +dependencies = [ + "cfg-if 0.1.10", + "core-foundation-sys 0.7.0", + "libc", +] + +[[package]] +name = "core-video-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34ecad23610ad9757664d644e369246edde1803fcb43ed72876565098a5d3828" +dependencies = [ + "cfg-if 0.1.10", + "core-foundation-sys 0.7.0", + "core-graphics", + "libc", + "metal", + "objc", +] + +[[package]] +name = "core_detect" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f8f80099a98041a3d1622845c271458a2d73e688351bf3cb999266764b81d48" + +[[package]] +name = "countio" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +checksum = "b9702aee5d1d744c01d82f6915644f950f898e014903385464c773b96fefdecb" +dependencies = [ + "futures-io", +] + +[[package]] +name = "cpubits" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15b85f9c39137c3a891689859392b1bd49812121d0d61c9caf00d46ed5ce06ae" + +[[package]] +name = "cpufeatures" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566" dependencies = [ "libc", ] +[[package]] +name = "crc32fast" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ba106e844045ddc02c20768ac4b0b7cb45f2cc2ecbd833ac9f5dacb183c2055" +dependencies = [ + "cfg-if 1.0.5", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98b0cc327b5bc766e7fda9c9260cc0fa81b43a8e240440422dff70788e3f9ef1" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622f3fc73690be383c7214310406f28a90e6edeadc3cea882f9d71e495b9711a" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc74980687109a3b14c72fd458107bf0baa1da1a1a805e178d15501ba9b86d9d" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" -version = "0.8.21" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6" [[package]] name = "crunchy" @@ -619,13 +1139,13 @@ checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "crypto-bigint" -version = "0.7.5" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a52aa3fcda4e6302a9f48734f234d35d4721b96f8fe07d073f07ce9df4f0271" +checksum = "d726facc8b27e604391b232b970cdc19b5468c69f08b466b9734c759216c7415" dependencies = [ "cpubits", "ctutils", - "getrandom 0.4.2", + "getrandom 0.4.3", "hybrid-array", "num-traits", "rand_core 0.10.1", @@ -649,11 +1169,21 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" dependencies = [ - "getrandom 0.4.2", + "getrandom 0.4.3", "hybrid-array", "rand_core 0.10.1", ] +[[package]] +name = "ctor" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "914a755b7c2d4af2bdcff7ce1739e2db9a1b81a9b07123d8015786ae03c0980d" +dependencies = [ + "link-section", + "linktime-proc-macro", +] + [[package]] name = "ctr" version = "0.10.1" @@ -676,9 +1206,9 @@ dependencies = [ [[package]] name = "ctutils" -version = "0.4.0" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1005a6d4446f5120ef475ad3d2af2b30c49c2c9c6904258e3bb30219bebed5e4" +checksum = "38d28fb6aa7dd680b3ffd1a3e64e115c177bdba63c0ae7f9cd48129ff05c4fa0" dependencies = [ "cmov", "subtle", @@ -690,10 +1220,10 @@ version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5eed333089e2e1c1ac8c6c0398e5e2497b4c9926ca6d0365ed1e099afa5bc23" dependencies = [ - "cfg-if", + "cfg-if 1.0.5", "cpufeatures", "curve25519-dalek-derive", - "digest 0.11.2", + "digest 0.11.3", "fiat-crypto", "rustc_version", "subtle", @@ -745,6 +1275,37 @@ dependencies = [ "syn 3.0.9", ] +[[package]] +name = "defmt" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4a0795ac740cb54d7b3775c9c17345f6aaecf884c01733b39d6017738e0e3e1" +dependencies = [ + "bitflags 1.3.2", + "defmt-macros", +] + +[[package]] +name = "defmt-macros" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "840bb056bd99c495c9188198a258ab787c79f306d864db3e6e8451442d6d8366" +dependencies = [ + "defmt-parser", + "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[package]] +name = "defmt-parser" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71958f69fb2de856c5dd51ac9377e986ca1aa5919f931bf5395a807277f889a0" +dependencies = [ + "thiserror 2.0.21", +] + [[package]] name = "der" version = "0.7.10" @@ -758,9 +1319,9 @@ dependencies = [ [[package]] name = "der" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71fd89660b2dc699704064e59e9dba0147b903e85319429e131620d022be411b" +checksum = "a878c850e9e421b20262e9b41f9c860e4785fa07541c266b62ff9d1ef998a80a" dependencies = [ "const-oid 0.10.2", "pem-rfc7468 1.0.0", @@ -769,12 +1330,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.5.8" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" -dependencies = [ - "powerfmt", -] +checksum = "9e9de72ce2ad1f90dc62fa25f0f430ef85eb4b0d8fa0be4f30373bc40a21d28e" [[package]] name = "digest" @@ -788,9 +1346,9 @@ dependencies = [ [[package]] name = "digest" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4850db49bf08e663084f7fb5c87d202ef91a3907271aff24a94eb97ff039153c" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" dependencies = [ "block-buffer", "const-oid 0.10.2", @@ -834,7 +1392,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" dependencies = [ - "bitflags", + "bitflags 2.13.2", "block2", "libc", "objc2", @@ -842,27 +1400,33 @@ dependencies = [ [[package]] name = "displaydoc" -version = "0.2.5" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.9", ] +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + [[package]] name = "ecdsa" version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0681a4fc24c767085329728d8dfba959af91228aa4610cca4f8ce317ba46ae0" dependencies = [ - "der 0.8.0", - "digest 0.11.2", + "der 0.8.2", + "digest 0.11.3", "elliptic-curve", "rfc6979", "signature 3.0.0", - "spki 0.8.0", + "spki 0.8.1", "zeroize", ] @@ -888,16 +1452,22 @@ dependencies = [ "zeroize", ] +[[package]] +name = "either" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e9c71c2167ca323c882b99918929403426e2373ea17242ff5653e0d5e1058be" + [[package]] name = "elliptic-curve" -version = "0.14.1" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d65aa39b3a5c1c9c1b745c9a019234bb7a21b77abcb4f4d266d706e2d577d65" +checksum = "0ad4496221fcfc21015fd8c0e26fcfab00504832dc0604f52acdd7bad2a8dc81" dependencies = [ "base16ct", "crypto-bigint", "crypto-common 0.2.2", - "digest 0.11.2", + "digest 0.11.3", "ff", "group", "hkdf", @@ -910,6 +1480,20 @@ dependencies = [ "zeroize", ] +[[package]] +name = "encoding_rs" +version = "0.8.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e985e0451871ad22fb8d2b6b076e2028a502a0d3950998c2c5c0a4f9b5d9679" +dependencies = [ + "cfg-if 1.0.5", + "core_detect", + "multiversion_no_op", + "rustversion", + "scopeguard", + "simdutf8", +] + [[package]] name = "endi" version = "1.1.1" @@ -947,6 +1531,12 @@ dependencies = [ "regex", ] +[[package]] +name = "env_home" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe" + [[package]] name = "env_logger" version = "0.11.11" @@ -960,11 +1550,31 @@ dependencies = [ "log", ] +[[package]] +name = "equator" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc" +dependencies = [ + "equator-macro", +] + +[[package]] +name = "equator-macro" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "equivalent" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +checksum = "00d174d5400e5e8fd687ad1049e2f578285fa914201b1af7e8b112a4546bd826" [[package]] name = "errno" @@ -973,16 +1583,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] name = "event-listener" -version = "5.4.1" +version = "5.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +checksum = "5a23add41df1562121a9393cb065eab5146a1242410f23a644851e90cfd669d2" dependencies = [ - "concurrent-queue", "parking", "pin-project-lite", ] @@ -997,11 +1606,63 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "exr" +version = "1.74.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711fe42c9964295e01ee3fba3f9fe0e1d24b98886950d68efe81b1c76e21adf3" +dependencies = [ + "bit_field", + "half 2.7.1", + "lebe", + "miniz_oxide 0.8.9", + "num-complex", + "pulp", + "rayon-core", + "smallvec", + "zune-inflate", +] + +[[package]] +name = "face_id" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f49ff78a8489ebf1ce5fec3f76a330117940d35dbea8ac6047f9539c1720987c" +dependencies = [ + "bon", + "hdbscan", + "hf-hub", + "image", + "nalgebra", + "ndarray", + "ort", + "rayon", + "serde", + "serde_json", + "thiserror 2.0.21", + "tracing", +] + [[package]] name = "fastrand" -version = "2.3.0" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" + +[[package]] +name = "fax" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caf1079563223d5d59d83c85886a56e586cfd5c1a26292e971a0fa266531ac5a" + +[[package]] +name = "fdeflate" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +dependencies = [ + "simd-adler32", +] [[package]] name = "ff" @@ -1021,15 +1682,53 @@ checksum = "64cd1e32ddd350061ae6edb1b082d7c54915b5c672c389143b9a63403a109f24" [[package]] name = "find-msvc-tools" -version = "0.1.9" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +checksum = "1c66915cc5391097de7a2b0b972e8505aa33c0df401fd3a6811dbdb32881ba48" [[package]] -name = "foldhash" -version = "0.1.5" +name = "flate2" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e634e2e0ebac1ee034020da1ca582e17ffe4e0f5e985823721e168928136dcb" +dependencies = [ + "crc32fast", + "miniz_oxide 0.9.1", + "zlib-rs", +] + +[[package]] +name = "flume" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" +dependencies = [ + "futures-core", + "futures-sink", + "nanorand", + "spin 0.9.9", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" @@ -1040,12 +1739,54 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + +[[package]] +name = "futures" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a31d2a3fbaaeb2af2368bbdd904aa8e812d3c04a1ee10d3171f52d556e5d0a3" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f9e3d69d39e4862ffed03ed071a76f9a13ba1d9109d355b0f0aa6b15e393c4" +dependencies = [ + "futures-core", + "futures-sink", +] + [[package]] name = "futures-core" version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" +[[package]] +name = "futures-executor" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "031b47cf1a3c6cc8bc2fc76cd437f521619387907d469316e7c0bc278f1f5432" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + [[package]] name = "futures-io" version = "0.3.34" @@ -1066,8 +1807,54 @@ dependencies = [ ] [[package]] -name = "generic-array" -version = "0.14.7" +name = "futures-macro" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[package]] +name = "futures-sink" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1944426bf7d03f1d14f708785e4b33efd750b36d48a157b836b3efc15ede8e1d" + +[[package]] +name = "futures-task" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" + +[[package]] +name = "futures-util" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + +[[package]] +name = "gearhash" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616e8f476a586f1b078d9eece21f7a071f27997e709e2b471f5697deea53bda9" + +[[package]] +name = "generic-array" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ @@ -1081,9 +1868,11 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ - "cfg-if", + "cfg-if 1.0.5", + "js-sys", "libc", - "wasi", + "wasi 0.11.1+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] @@ -1092,7 +1881,7 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ - "cfg-if", + "cfg-if 1.0.5", "libc", "r-efi 5.3.0", "wasip2", @@ -1100,16 +1889,16 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" dependencies = [ - "cfg-if", + "cfg-if 1.0.5", + "js-sys", "libc", "r-efi 6.0.0", "rand_core 0.10.1", - "wasip2", - "wasip3", + "wasm-bindgen", ] [[package]] @@ -1121,19 +1910,49 @@ dependencies = [ "polyval", ] +[[package]] +name = "gif" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee8cfcc411d9adbbaba82fb72661cc1bcca13e8bba98b364e62b2dba8f960159" +dependencies = [ + "color_quant", + "weezl", +] + [[package]] name = "git-state" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7f0f3132e2c1356595caf0f85961a7cf21cac3734d40e54fe83fcdb3dd2fcbc" +[[package]] +name = "git-version" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad568aa3db0fcbc81f2f116137f263d7304f512a1209b35b85150d3ef88ad19" +dependencies = [ + "git-version-macro", +] + +[[package]] +name = "git-version-macro" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53010ccb100b96a67bc32c0175f0ed1426b31b655d562898e57325f81c023ac0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "git2" version = "0.20.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b88256088d75a56f8ecfa070513a775dd9107f6530ef14919dac831af9cfe2b" dependencies = [ - "bitflags", + "bitflags 2.13.2", "libc", "libgit2-sys", "log", @@ -1146,12 +1965,55 @@ version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddddbf932745a6be37109b6112d3ee09696106f848449069d3a57bba937ab82e" dependencies = [ - "bitflags", + "bitflags 2.13.2", "libc", "libgit2-sys", "log", ] +[[package]] +name = "glam" +version = "0.30.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19fc433e8437a212d1b6f1e68c7824af3aed907da60afa994e7f542d18d12aa9" + +[[package]] +name = "glam" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556f6b2ea90b8d15a74e0e7bb41671c9bdf38cd9f78c284d750b9ce58a2b5be7" + +[[package]] +name = "glam" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f70749695b063ecbf6b62949ccccde2e733ec3ecbbd71d467dca4e5c6c97cca0" + +[[package]] +name = "glam" +version = "0.33.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37bfe73dc8ec21f54d181e5a60554327ec3f1c600c455a75ccbfc65d2106a6c4" + +[[package]] +name = "glob" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4eba85ea1d0a966a983acd07deee566e67395d2d96b6fb39e62b5a833f1eb0b" + +[[package]] +name = "globset" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07c34a9410465b45bd9787443bc7370f37735bad04b0f0cd57ff1a3186c98988" +dependencies = [ + "aho-corasick", + "bstr", + "log", + "regex-automata", + "regex-syntax", +] + [[package]] name = "group" version = "0.14.0" @@ -1163,6 +2025,25 @@ dependencies = [ "subtle", ] +[[package]] +name = "h2" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d29020232d6aa3fb1daca64c1127cf662cf97f254ae16c18c05b8ab635fc118" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "half" version = "1.8.3" @@ -1175,25 +2056,32 @@ version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" dependencies = [ - "cfg-if", + "cfg-if 1.0.5", "crunchy", "zerocopy", ] [[package]] name = "hashbrown" -version = "0.15.5" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[package]] +name = "hdbscan" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +checksum = "466aa8bfaa22c81efcf67c84e6ad046de13a05c6cc9d41a5094361bff464247a" dependencies = [ - "foldhash", + "kdtree", + "num-traits", ] [[package]] -name = "hashbrown" -version = "0.16.1" +name = "heapify" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +checksum = "0049b265b7f201ca9ab25475b22b47fe444060126a51abe00f77d986fc5cc52e" [[package]] name = "heck" @@ -1212,9 +2100,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" +checksum = "e17592d60ebacc7d5e169f4663c5f84f9161cc90328abcfe8456f41e4dfcb284" [[package]] name = "hex" @@ -1222,14 +2110,68 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hf-hub" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ccb6bcc85dec15413ef5949879f9a5497ca4568ed702547eb83fac23376e5c" +dependencies = [ + "base64 0.22.1", + "bon", + "bytes", + "futures", + "getrandom 0.2.17", + "globset", + "hf-xet", + "hyper", + "pathdiff", + "percent-encoding", + "reqwest", + "serde", + "serde_json", + "sha2", + "thiserror 2.0.21", + "tokio", + "tokio-retry", + "tokio-util", + "tracing", + "url", + "wasm-bindgen-futures", +] + +[[package]] +name = "hf-xet" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f24754aef4f6c3d57bc4a0dc2648ca74487050eda01c361b3eefa11feeafd662" +dependencies = [ + "anyhow", + "async-trait", + "bytes", + "http", + "more-asserts", + "serde", + "serde_json", + "thiserror 2.0.21", + "tokio", + "tokio-util", + "tokio_with_wasm", + "tracing", + "uuid", + "xet-client", + "xet-core-structures", + "xet-data", + "xet-runtime", +] + [[package]] name = "hidapi" -version = "2.6.5" +version = "2.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1b71e1f4791fb9e93b9d7ee03d70b501ab48f6151432fbcadeabc30fe15396e" +checksum = "818c0e1d27887aaf76fe737042e27a66b796a7b099e6d2e1a72d106c2dff3fa6" dependencies = [ "cc", - "cfg-if", + "cfg-if 1.0.5", "libc", "pkg-config", "windows-sys 0.61.2", @@ -1250,7 +2192,22 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f" dependencies = [ - "digest 0.11.2", + "digest 0.11.3", +] + +[[package]] +name = "hmac-sha256" +version = "1.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad320b3b96fb2a455a0726d16efe0a5afdbd34b71dea5bc53b05ea057714d4e" + +[[package]] +name = "home" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" +dependencies = [ + "windows-sys 0.61.2", ] [[package]] @@ -1259,25 +2216,157 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f558a64ac9af88b5ba400d99b579451af0d39c6d360980045b91aac966d705e2" +[[package]] +name = "http" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "918d3568bebf352712bc2ef3d46a8bcf1a75b373be6539de198e9105cbbf9ce0" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2a8f2913ee65f60facd6a5905613afaa448497a0230cc41ce022d93290bc2c" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23169fe34a5fbcdd3f3862e78fb9b6fccd5f02a6dc6f732547005d45631ce71c" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "humantime" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15cdd26707701c53297e2fa6afb323d55fbc1d0810c3aec078ae3ef0424c3c15" + [[package]] name = "hybrid-array" -version = "0.4.13" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "818356c5132c1fede50f837ca96afbe78ff42413047f4abb886217845e1b6c8c" +checksum = "27f864f10dfb56725ce5ce5472bc52252c8f93a4ab86327122cebf62c5f59a17" dependencies = [ "subtle", "typenum", "zeroize", ] +[[package]] +name = "hyper" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c3e324da4c95177d6291d4c8730197c0d1822f8a9766814a4a44fa5ab797c9c" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "h2", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfa8e654703247911e29c23fbeaa261834bd9bb74efba2f9acddc37bfb127f53" +dependencies = [ + "http", + "hyper", + "hyper-util", + "rustls", + "tokio", + "tokio-rustls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddc03d96684f9226b8a787cdb71488417b53ab5ea8fdb1dac946cb9431cc8bff" +dependencies = [ + "base64 0.23.1", + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "httparse", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2", + "system-configuration", + "tokio", + "tower-service", + "tracing", + "windows-registry", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys 0.8.7", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "icu_collections" -version = "2.1.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +checksum = "fe090a42a0d3140fed8c63263ed1fecc02422cb2f4bfe55cd8de2de1b8e105dd" dependencies = [ "displaydoc", "potential_utf", + "utf8_iter", "yoke", "zerofrom", "zerovec", @@ -1285,9 +2374,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.1.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +checksum = "25d29b57c17c6528d0dc4c2141cfa2d08200465acb537a3909c8b9b8a4a984c0" dependencies = [ "displaydoc", "litemap", @@ -1298,9 +2387,9 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.1.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +checksum = "404a3b8c486f205c87fe7f23ab6894d84a4ad76d6e4671ae1981ba7def87c599" dependencies = [ "icu_collections", "icu_normalizer_data", @@ -1312,16 +2401,17 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.1.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" +checksum = "20f0088bfb7441f7a37fa0c9e20cb1e9cba1cac6b9ce8cd2a6dc44294f8e8cbc" [[package]] name = "icu_properties" -version = "2.1.2" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +checksum = "2ea83d991c56158f7cf898bf86436c1dfe7c07ee82fe88951f2695c9f37a379f" dependencies = [ + "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", @@ -1332,15 +2422,15 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "2.1.2" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" +checksum = "b98f29af82d02b163fe50161388350e743bb3107cc8e8c2f7314cb505faddfcf" [[package]] name = "icu_provider" -version = "2.1.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +checksum = "413099315636c588ee8f011190b329b971a09a8fae9d157e01dcae8379468514" dependencies = [ "displaydoc", "icu_locale_core", @@ -1351,12 +2441,6 @@ dependencies = [ "zerovec", ] -[[package]] -name = "id-arena" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" - [[package]] name = "ident_case" version = "1.0.1" @@ -1376,75 +2460,152 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" dependencies = [ "icu_normalizer", "icu_properties", ] [[package]] -name = "indexmap" -version = "2.13.0" +name = "image" +version = "0.25.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104" dependencies = [ - "equivalent", - "hashbrown 0.16.1", - "serde", - "serde_core", + "bytemuck", + "byteorder-lite", + "color_quant", + "exr", + "gif", + "image-webp", + "moxcms", + "num-traits", + "png", + "qoi", + "ravif", + "rayon", + "rgb", + "tiff", + "zune-core", + "zune-jpeg", ] [[package]] -name = "inout" -version = "0.2.2" +name = "image-webp" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4250ce6452e92010fdf7268ccc5d14faa80bb12fc741938534c58f16804e03c7" +checksum = "525e9ff3e1a4be2fbea1fdf0e98686a6d98b4d8f937e1bf7402245af1909e8c3" dependencies = [ - "block-padding", - "hybrid-array", + "byteorder-lite", + "quick-error", ] [[package]] -name = "is_debug" -version = "1.1.0" +name = "imgref" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fe266d2e243c931d8190177f20bf7f24eed45e96f39e87dc49a27b32d12d407" +checksum = "6e44b0a4eaa4c82f441d50a963f2d5f05a787240aeee097597033e72accfd22f" [[package]] -name = "is_terminal_polyfill" -version = "1.70.2" +name = "indexmap" +version = "2.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" +checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" +dependencies = [ + "equivalent", + "hashbrown", +] [[package]] -name = "itoa" -version = "1.0.17" +name = "inout" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" +checksum = "3b5cf4372d022092674a83b8febf5865f7a573cc0c5baec5e49c879b6a20978f" +dependencies = [ + "block-padding", + "hybrid-array", +] + +[[package]] +name = "interpolate_name" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "ipnet" +version = "2.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791930b43c0d5973160d90a8f3894509f2b273430f5c5c73b668636d0287c5c0" + +[[package]] +name = "is_debug" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fe266d2e243c931d8190177f20bf7f24eed45e96f39e87dc49a27b32d12d407" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "jiff" -version = "0.2.23" +version = "0.2.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a3546dc96b6d42c5f24902af9e2538e82e39ad350b0c766eb3fbf2d8f3d8359" +checksum = "b2b005715dcbeb0089a3c0dab99f2ff1cc3b2525323552703d648585d342a383" dependencies = [ + "defmt", + "jiff-core", "jiff-static", "jiff-tzdb-platform", "log", "portable-atomic", "portable-atomic-util", "serde_core", - "windows-sys 0.52.0", + "windows-link", +] + +[[package]] +name = "jiff-core" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e52fe76043ccecc9005d2305ebaadf7d7fc0cc89ca6baa10a94d6bc68c7128c" +dependencies = [ + "defmt", + "log", ] [[package]] name = "jiff-static" -version = "0.2.23" +version = "0.2.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a8c8b344124222efd714b73bb41f8b5120b27a7cc1c75593a6ff768d9d05aa4" +checksum = "2cc9817253cf7c7ee4684451bd327e88d6f3658014e54a29198625590650695c" dependencies = [ + "jiff-core", "proc-macro2", "quote", "syn 2.0.119", @@ -1452,9 +2613,9 @@ dependencies = [ [[package]] name = "jiff-tzdb" -version = "0.1.6" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c900ef84826f1338a557697dc8fc601df9ca9af4ac137c7fb61d4c6f2dfd3076" +checksum = "fa8377070c6bae868759445e5a77f66d84f0b72f3a054bfb00e6d038b8282da7" [[package]] name = "jiff-tzdb-platform" @@ -1465,40 +2626,138 @@ dependencies = [ "jiff-tzdb", ] +[[package]] +name = "jni" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498" +dependencies = [ + "cfg-if 1.0.5", + "combine", + "jni-macros", + "jni-sys", + "log", + "simd_cesu8", + "thiserror 2.0.21", + "walkdir", + "windows-link", +] + +[[package]] +name = "jni-macros" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "simd_cesu8", + "syn 2.0.119", +] + +[[package]] +name = "jni-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] + +[[package]] +name = "jni-sys-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn 2.0.119", +] + [[package]] name = "jobserver" -version = "0.1.34" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" dependencies = [ - "getrandom 0.3.4", + "getrandom 0.4.3", "libc", ] [[package]] name = "js-sys" -version = "0.3.91" +version = "0.3.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" +checksum = "7883d941dae510fb2d978fc3fe018c71c9e2892fd38854de3e8b92c2e5ad9cc5" dependencies = [ - "once_cell", + "cfg-if 1.0.5", + "futures-util", "wasm-bindgen", ] +[[package]] +name = "kdtree" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f0a0e9f770b65bac9aad00f97a67ab5c5319effed07f6da385da3c2115e47ba" +dependencies = [ + "num-traits", + "thiserror 1.0.69", +] + +[[package]] +name = "konst" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "128133ed7824fcd73d6e7b17957c5eb7bacb885649bd8c69708b2331a10bcefb" +dependencies = [ + "konst_macro_rules", +] + +[[package]] +name = "konst" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f660d5f887e3562f9ab6f4a14988795b694099d66b4f5dedc02d197ba9becb1d" +dependencies = [ + "const_panic", + "konst_proc_macros", + "typewit", +] + +[[package]] +name = "konst_macro_rules" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4933f3f57a8e9d9da04db23fb153356ecaf00cbd14aee46279c33dc80925c37" + +[[package]] +name = "konst_proc_macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e037a2e1d8d5fdbd49b16a4ea09d5d6401c1f29eca5ff29d03d3824dba16256a" + [[package]] name = "lazy_static" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +checksum = "20870f649af7073d53e38067b2a84312175d56ea15217e1b15bc83506ec50afb" dependencies = [ "spin 0.9.9", ] [[package]] -name = "leb128fmt" -version = "0.1.0" +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "lebe" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" +checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8" [[package]] name = "libc" @@ -1506,11 +2765,21 @@ version = "0.2.191" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "65cd87c9a6d60536580b316ad985726104730a5151c99845f2490428ef91240a" +[[package]] +name = "libfuzzer-sys" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9fd2f41a1cba099f79a0b6b6c35656cf7c03351a7bae8ff0f28f25270f929d2" +dependencies = [ + "arbitrary", + "cc", +] + [[package]] name = "libgit2-sys" -version = "0.18.4+1.9.3" +version = "0.18.8+1.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b26f66f35e1871b22efcf7191564123d2a446ca0538cde63c23adfefa9b15b7" +checksum = "7f7c568b25d7489bc3fb2988ed69ab111d2944d2f5fec3d5c987fe545ea97b50" dependencies = [ "cc", "libc", @@ -1518,6 +2787,16 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if 1.0.5", + "windows-link", +] + [[package]] name = "libm" version = "0.2.16" @@ -1526,18 +2805,18 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libredox" -version = "0.1.14" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1744e39d1d6a9948f4f388969627434e31128196de472883b39f148769bfe30a" +checksum = "61ff90caf6077a803a240f62fdbe88645a890bbca49ef8174c3cb0404362171d" dependencies = [ "libc", ] [[package]] name = "libz-sys" -version = "1.1.25" +version = "1.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52f4c29e2a68ac30c9087e1b772dc9f44a2b66ed44edf2266cf2be9b03dafc1" +checksum = "f710a23e6dbf193214fd46ca56a9d6864e550abe86202184532ae7275e46de19" dependencies = [ "cc", "libc", @@ -1545,6 +2824,24 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "link-section" +version = "0.19.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39c29a617ce3df32c08497bdc1ab6e2376e0b17948ac166a2fbe5977c5954cd9" + +[[package]] +name = "linktime-proc-macro" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e57c38c1e860fd37c604281cdfb1dd2216977fd76a50f85ba2f388ef3219616" + +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + [[package]] name = "linux-raw-sys" version = "0.12.1" @@ -1553,9 +2850,9 @@ checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] name = "litemap" -version = "0.8.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" +checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae" [[package]] name = "lock_api" @@ -1572,6 +2869,36 @@ version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" +[[package]] +name = "loop9" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062" +dependencies = [ + "imgref", +] + +[[package]] +name = "lru-slab" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4050469837a6ff301cd14c1f8f24f88549e6d548f24f64e2148eb0f72cebc51f" + +[[package]] +name = "lz4_flex" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef0d4ed8669f8f8826eb00dc878084aa8f253506c4fd5e8f58f5bce72ddb97e" +dependencies = [ + "twox-hash", +] + +[[package]] +name = "lzma-rust2" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e20f57f9918e5bd7bc58c22cdd70a6afc7375d4dd9683af5f2b34bd3d2bba619" + [[package]] name = "mac-notification-sys" version = "0.6.15" @@ -1586,6 +2913,44 @@ dependencies = [ "uuid", ] +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "matrixmultiply" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f607c237553f086e7043417a51df26b2eb899d3caff94e6a67592ff992fedc7" +dependencies = [ + "autocfg", + "rawpointer", +] + +[[package]] +name = "maybe-rayon" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" +dependencies = [ + "cfg-if 1.0.5", + "rayon", +] + [[package]] name = "mbox" version = "0.7.1" @@ -1598,9 +2963,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.8.0" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" [[package]] name = "memoffset" @@ -1612,27 +2977,320 @@ dependencies = [ ] [[package]] -name = "mio" -version = "1.2.1" +name = "metal" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e198a0ee42bdbe9ef2c09d0b9426f3b2b47d90d93a4a9b0395c4cea605e92dc0" +dependencies = [ + "bitflags 1.3.2", + "block", + "cocoa", + "core-graphics", + "foreign-types", + "log", + "objc", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + +[[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.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "miniz_oxide" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b63fbc4a50860e98e7b2aa7804ded1db5cbc3aff9193adaff57a6931bf7c4b4c" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "1.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1788edb87fdc09c7e26304471e2f5be8cdefb1b6930d6e3985fc02ff53bf86ee" +dependencies = [ + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.61.2", +] + +[[package]] +name = "more-asserts" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fafa6961cabd9c63bcd77a45d7e3b7f3b552b70417831fb0f56db717e72407e" + +[[package]] +name = "moxcms" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b" +dependencies = [ + "num-traits", + "pxfm", +] + +[[package]] +name = "mozjpeg" +version = "0.10.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7891b80aaa86097d38d276eb98b3805d6280708c4e0a1e6f6aed9380c51fec9" +dependencies = [ + "arrayvec", + "bytemuck", + "libc", + "mozjpeg-sys", + "rgb", +] + +[[package]] +name = "mozjpeg-sys" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f0dc668bf9bf888c88e2fb1ab16a406d2c380f1d082b20d51dd540ab2aa70c1" +dependencies = [ + "cc", + "dunce", + "libc", + "nasm-rs", +] + +[[package]] +name = "multiversion_no_op" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743fb55ba31b18fb1ecef6bdc9aa2743314978ac084044301a7eee33fb99a20d" + +[[package]] +name = "nalgebra" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc43a60c217b0c6ff46e47f26911015ad8d2e5a8be1af668c67e370d99a4346" +dependencies = [ + "approx", + "glam 0.30.10", + "glam 0.31.1", + "glam 0.32.1", + "glam 0.33.12", + "matrixmultiply", + "nalgebra-macros", + "num-complex", + "num-rational", + "num-traits", + "simba", + "typenum", +] + +[[package]] +name = "nalgebra-macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "973e7178a678cfd059ccec50887658d482ce16b0aa9da3888ddeab5cd5eb4889" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "nanorand" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "nasm-rs" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "706bf8a5e8c8ddb99128c3291d31bd21f4bcde17f0f4c20ec678d85c74faa149" +dependencies = [ + "jobserver", + "log", +] + +[[package]] +name = "native-tls" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "ndarray" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520080814a7a6b4a6e9070823bb24b4531daac8c4627e08ba5de8c5ef2f2752d" +dependencies = [ + "matrixmultiply", + "num-complex", + "num-integer", + "num-traits", + "portable-atomic", + "portable-atomic-util", + "rawpointer", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + +[[package]] +name = "nix" +version = "0.31.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d" +dependencies = [ + "bitflags 2.13.2", + "cfg-if 1.0.5", + "cfg_aliases", + "libc", +] + +[[package]] +name = "no_std_io2" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418abd1b6d34fbf6cae440dc874771b0525a604428704c76e48b29a5e67b8003" +dependencies = [ + "memchr", +] + +[[package]] +name = "nokhwa" +version = "0.10.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d63f10b450319a0ace7aa8e0e25477d1fdb345313a97e220e886175539a1dbb" +dependencies = [ + "flume", + "image", + "nokhwa-bindings-linux", + "nokhwa-bindings-macos", + "nokhwa-bindings-windows", + "nokhwa-core", + "paste", + "thiserror 2.0.21", +] + +[[package]] +name = "nokhwa-bindings-linux" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb67e22201a53322291740ca064b20eaaade7222ef0349f312d9b37b004e1984" +dependencies = [ + "libc", + "nokhwa-core", + "v4l", +] + +[[package]] +name = "nokhwa-bindings-macos" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f70d3908ea68324e44a6b3a0f885aa59e433fb1f6678839d09e0df7d226fb42d" +dependencies = [ + "block", + "cocoa-foundation", + "core-foundation 0.10.1", + "core-media-sys", + "core-video-sys", + "flume", + "nokhwa-core", + "objc", + "once_cell", +] + +[[package]] +name = "nokhwa-bindings-windows" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be28886bad8abcec3655c1f24b965b4cb596a72b23164c910c54439ce55d2a4" +dependencies = [ + "nokhwa-core", + "once_cell", + "windows", +] + +[[package]] +name = "nokhwa-core" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1cba20bebd3bd9ae22f9273ade5bbe49da3e047c8512b53fbaf8b4b9c80d496" +dependencies = [ + "bytes", + "image", + "mozjpeg", + "thiserror 2.0.21", +] + +[[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 = "nom" +version = "8.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda" +checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405" dependencies = [ - "libc", - "wasi", - "windows-sys 0.61.2", + "memchr", ] [[package]] -name = "nix" -version = "0.31.3" +name = "noop_proc_macro" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d" -dependencies = [ - "bitflags", - "cfg-if", - "cfg_aliases", - "libc", -] +checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" [[package]] name = "notify-rust" @@ -1648,6 +3306,34 @@ dependencies = [ "zbus 5.19.0", ] +[[package]] +name = "ntapi" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3b335231dfd352ffb0f8017f3b6027a4917f7df785ea2143d8af2adc66980ae" +dependencies = [ + "winapi", +] + +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "num-bigint" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c89e69e7e0f03bea5ef08013795c25018e101932225a656383bd384495ecc367" +dependencies = [ + "num-integer", + "num-traits", +] + [[package]] name = "num-bigint-dig" version = "0.8.6" @@ -1659,16 +3345,26 @@ dependencies = [ "num-integer", "num-iter", "num-traits", - "rand 0.8.5", + "rand 0.8.8", "smallvec", "zeroize", ] +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "bytemuck", + "num-traits", +] + [[package]] name = "num-conv" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" [[package]] name = "num-derive" @@ -1700,6 +3396,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -1710,11 +3417,21 @@ dependencies = [ "libm", ] +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", + "objc_exception", +] + [[package]] name = "objc2" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f" +checksum = "08849bbd4767dfae9457696856ae1c84fe4e0281bbe4a7abff2d0e06fb7981f8" dependencies = [ "objc2-encode", ] @@ -1725,7 +3442,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ - "bitflags", + "bitflags 2.13.2", "dispatch2", "objc2", ] @@ -1742,13 +3459,52 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ - "bitflags", + "bitflags 2.13.2", "block2", "libc", "objc2", "objc2-core-foundation", ] +[[package]] +name = "objc2-io-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33fafba39597d6dc1fb709123dfa8289d39406734be322956a69f0931c73bb15" +dependencies = [ + "libc", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-open-directory" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb82bed227edf5201dfedf072bba4015a33d3d4a98519837295a90f0a23f676d" +dependencies = [ + "objc2", + "objc2-core-foundation", + "objc2-foundation", +] + +[[package]] +name = "objc2-system-configuration" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7216bd11cbda54ccabcab84d523dc93b858ec75ecfb3a7d89513fa22464da396" +dependencies = [ + "objc2-core-foundation", +] + +[[package]] +name = "objc_exception" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4" +dependencies = [ + "cc", +] + [[package]] name = "oid" version = "0.2.1" @@ -1760,9 +3516,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.21.3" +version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] name = "once_cell_polyfill" @@ -1770,6 +3526,55 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" +[[package]] +name = "oneshot" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "269bca4c2591a28585d6bf10d9ed0332b7d76900a1b02bec41bdc3a2cdcda107" + +[[package]] +name = "openssl" +version = "0.10.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77823a27f0babb03091cb9ed9ef80af3b39dbc82f97e8fa530374b7dafd87a45" +dependencies = [ + "bitflags 2.13.2", + "cfg-if 1.0.5", + "foreign-types", + "libc", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + +[[package]] +name = "openssl-sys" +version = "0.9.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b47e7e6bb2c38cd930d25a23b40fa52e068c10e85f3e03a7f5ba5aaca5713695" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "option-ext" version = "0.2.0" @@ -1786,6 +3591,39 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "ort" +version = "2.0.0-rc.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37c87aa7a90b7ff3e0fe36cccd475df8d67f15f07f4d6c370c4b38464232813c" +dependencies = [ + "ndarray", + "ort-sys", + "smallvec", + "tracing", + "ureq", +] + +[[package]] +name = "ort-sys" +version = "2.0.0-rc.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d22b0417f1838db5a3ac0b3f98dfe39f6fb73624aa0a27c6bbb5040b9c7db2b" +dependencies = [ + "hmac-sha256", + "lzma-rust2", + "ureq", +] + +[[package]] +name = "os_str_bytes" +version = "6.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" +dependencies = [ + "memchr", +] + [[package]] name = "p256" version = "0.14.0" @@ -1829,13 +3667,13 @@ dependencies = [ "nix", "passless-config-doc", "psl", - "rand 0.8.5", + "rand 0.8.8", "serde", "serde_json", "sha2", "soft-fido2", "tempfile", - "thiserror", + "thiserror 2.0.21", "toml", ] @@ -1854,21 +3692,25 @@ dependencies = [ "ctrlc", "dirs 7.0.0", "env_logger", + "face_id", "futures-lite", + "futures-util", "git2 0.21.0", "hex", "hkdf", "hmac", + "image", "libc", "log", "nix", + "nokhwa", "notify-rust", "p256", "passless-config-doc", "passless-core", "passless-uhid", "prs-lib", - "rand 0.8.5", + "rand 0.8.8", "rpassword", "rsa", "serde", @@ -1883,9 +3725,11 @@ dependencies = [ "soft-fido2-transport", "systemd-journal-logger", "tempfile", + "thiserror 2.0.21", "tokio", "toml", "tss-esapi", + "which 7.0.3", "zbus 6.1.0", "zeroize", ] @@ -1895,9 +3739,33 @@ name = "passless-uhid" version = "0.20.2" dependencies = [ "libc", - "thiserror", + "thiserror 2.0.21", ] +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pastey" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35fb2e5f958ec131621fdd531e9fc186ed768cbe395337403ae56c17a74c68ec" + +[[package]] +name = "pathdiff" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" + +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + [[package]] name = "pem-rfc7468" version = "0.7.0" @@ -1935,9 +3803,9 @@ dependencies = [ [[package]] name = "picky-asn1-der" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d413165e4bf7f808b9a27cbaba657657a2921f0965db833f488c4d4be96dcd2e" +checksum = "b4467118a2c640f4040aea27d01293620984b0b3f3ef0c53577c3bbf6bab4256" dependencies = [ "picky-asn1", "serde", @@ -1946,17 +3814,37 @@ dependencies = [ [[package]] name = "picky-asn1-x509" -version = "0.15.4" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "859d4117bd1b1dc5646359ee7243c50c5000c0920ea2d1fb120335a2f4c684b8" +checksum = "3f110226d163cea4380b0e5ef698a107061d198b279cc27d2b2c1e95c08cd9b0" dependencies = [ - "base64 0.22.1", + "base64 0.23.1", "oid", "picky-asn1", "picky-asn1-der", "serde", ] +[[package]] +name = "pin-project" +version = "1.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2466b2336ed02bcdca6b294417127b90ec92038d1d5c4fbeac971a922e0e0924" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "pin-project-lite" version = "0.2.17" @@ -2001,15 +3889,28 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "451913da69c775a56034ea8d9003d27ee8948e12443eae7c038ba100a4f21cb7" dependencies = [ - "der 0.8.0", - "spki 0.8.0", + "der 0.8.2", + "spki 0.8.1", ] [[package]] name = "pkg-config" -version = "0.3.32" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548" + +[[package]] +name = "png" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" +dependencies = [ + "bitflags 2.13.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide 0.8.9", +] [[package]] name = "polling" @@ -2017,19 +3918,19 @@ version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" dependencies = [ - "cfg-if", + "cfg-if 1.0.5", "concurrent-queue", - "hermit-abi 0.5.2", + "hermit-abi 0.5.3", "pin-project-lite", - "rustix", + "rustix 1.1.5", "windows-sys 0.61.2", ] [[package]] name = "polyval" -version = "0.7.1" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dfc63250416fea14f5749b90725916a6c903f599d51cb635aa7a52bfd03eede" +checksum = "f0fa31d631f2b2cb2a544d0aa321ce847a94764d701ca2becc411138b93d49cd" dependencies = [ "cpubits", "cpufeatures", @@ -2038,33 +3939,33 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.13.1" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" +checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85" [[package]] name = "portable-atomic-util" -version = "0.2.5" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a9db96d7fa8782dd8c15ce32ffe8680bbd1e978a43bf51a34d39483540495f5" +checksum = "10ab3eb7f3becc3a1cbc4f2c6f20267996cfc1a6467a873763411b136a122715" dependencies = [ "portable-atomic", ] [[package]] name = "potential_utf" -version = "0.1.4" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +checksum = "d83eb9bc6d8e5cf568e7a1101d60ee05e81ed50ea106026f3d18deeb046d7661" dependencies = [ "zerovec", ] [[package]] name = "powerfmt" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" +checksum = "4a6394b9e965e73d0a289ee54f589087e2c676aedf60885baf52c76b771e4958" [[package]] name = "ppv-lite86" @@ -2085,6 +3986,16 @@ dependencies = [ "syn 2.0.119", ] +[[package]] +name = "prettyplease" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bfe0f4c752e450fc2faf62654f1c134747922825d5b04ca717b8874f41a40c0" +dependencies = [ + "proc-macro2", + "syn 3.0.9", +] + [[package]] name = "primefield" version = "0.14.0" @@ -2136,9 +4047,9 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25485360a54d6861439d60facef26de713b1e126bf015ec8f98239467a2b82f7" dependencies = [ - "bitflags", + "bitflags 2.13.2", "procfs-core", - "rustix", + "rustix 1.1.5", ] [[package]] @@ -2147,10 +4058,29 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6401bf7b6af22f78b563665d15a22e9aef27775b79b149a66ca022468a4e405" dependencies = [ - "bitflags", + "bitflags 2.13.2", "hex", ] +[[package]] +name = "profiling" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d595e54a326bc53c1c197b32d295e14b169e3cfeaa8dc82b529f947fba6bcf5" +dependencies = [ + "profiling-procmacros", +] + +[[package]] +name = "profiling-procmacros" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4488a4a36b9a4ba6b9334a32a39971f77c1436ec82c38707bce707699cc3bbcb" +dependencies = [ + "quote", + "syn 2.0.119", +] + [[package]] name = "prs-lib" version = "0.5.9" @@ -2166,10 +4096,10 @@ dependencies = [ "secstr", "shellexpand", "shlex 2.0.1", - "thiserror", + "thiserror 2.0.21", "version-compare", "walkdir", - "which", + "which 8.0.6", "zeroize", ] @@ -2188,6 +4118,107 @@ version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac" +[[package]] +name = "pulp" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046aa45b989642ec2e4717c8e72d677b13edd831a4d3b6cf37d9a3e54912496a" +dependencies = [ + "bytemuck", + "cfg-if 1.0.5", + "libm", + "num-complex", + "paste", + "pulp-wasm-simd-flag", + "raw-cpuid", + "reborrow", + "version_check", +] + +[[package]] +name = "pulp-wasm-simd-flag" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d8f70e07b9c3962945a74e59ca1c511bba65b6419468acc217c457d93f3c740" + +[[package]] +name = "pxfm" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d55d956fa96f5ec02be2e13af0e20391a5aa83d6a074e3ad368959d0fab299ea" + +[[package]] +name = "qoi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + +[[package]] +name = "quinn" +version = "0.11.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4051e23e9185c255a7e33ef59cdbca87a22d359052eecd22fc6b901fb37d9d11" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash 2.1.3", + "rustls", + "socket2", + "thiserror 2.0.21", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e750cca55fe4f0439a15d0bb529da9651e79993e8e72c61a899a36d462befbe" +dependencies = [ + "aws-lc-rs", + "bytes", + "getrandom 0.4.3", + "lru-slab", + "rand 0.10.3", + "rand_pcg", + "ring", + "rustc-hash 2.1.3", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.21", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af66907df18639dcf4db56ca65490cabc4b27a97dbadd96f2926cca73298f016" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.61.2", +] + [[package]] name = "quote" version = "1.0.47" @@ -2211,23 +4242,33 @@ checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" [[package]] name = "rand" -version = "0.8.5" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "e058c7de0b26af77780c769414d6257830bb240f3c38477dbc2c16e5f54d6d4c" dependencies = [ "libc", - "rand_chacha", + "rand_chacha 0.3.1", "rand_core 0.6.4", ] [[package]] name = "rand" -version = "0.10.2" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.5", +] + +[[package]] +name = "rand" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80" +checksum = "65c9fb96cbc91e3478eaae79a69fcd3f1ae4ad052e471fe6732fff548984b4af" dependencies = [ "chacha20", - "getrandom 0.4.2", + "getrandom 0.4.3", "rand_core 0.10.1", ] @@ -2241,6 +4282,16 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", +] + [[package]] name = "rand_core" version = "0.6.4" @@ -2250,28 +4301,145 @@ dependencies = [ "getrandom 0.2.17", ] +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + [[package]] name = "rand_core" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" +[[package]] +name = "rand_pcg" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caa0f4137e1c0a72f4c651489402276c8e8e1cf081f3b0ba156d2cbeef09e86a" +dependencies = [ + "rand_core 0.10.1", +] + +[[package]] +name = "rav1e" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43b6dd56e85d9483277cde964fd1bdb0428de4fec5ebba7540995639a21cb32b" +dependencies = [ + "aligned-vec", + "arbitrary", + "arg_enum_proc_macro", + "arrayvec", + "av-scenechange", + "av1-grain", + "bitstream-io", + "built", + "cfg-if 1.0.5", + "interpolate_name", + "itertools", + "libc", + "libfuzzer-sys", + "log", + "maybe-rayon", + "new_debug_unreachable", + "noop_proc_macro", + "num-derive", + "num-traits", + "paste", + "profiling", + "rand 0.9.5", + "rand_chacha 0.9.0", + "simd_helpers", + "thiserror 2.0.21", + "v_frame", + "wasm-bindgen", +] + +[[package]] +name = "ravif" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e52310197d971b0f5be7fe6b57530dcd27beb35c1b013f29d66c1ad73fbbcc45" +dependencies = [ + "avif-serialize", + "imgref", + "loop9", + "quick-error", + "rav1e", + "rayon", + "rgb", +] + +[[package]] +name = "raw-cpuid" +version = "11.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" +dependencies = [ + "bitflags 2.13.2", +] + +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + +[[package]] +name = "rayon" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "reborrow" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03251193000f4bd3b042892be858ee50e8b3719f2b08e5833ac4353724632430" + +[[package]] +name = "redb" +version = "3.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ba239c1c1693315d3cc0e601db3b3965543afbf48c41730fdca2f069f510f4a" +dependencies = [ + "libc", +] + [[package]] name = "redox_users" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" +checksum = "60dc65c0ff1a7ae1294b0c67b9f14baf70b644404010370171787bfac1038fc0" dependencies = [ - "getrandom 0.2.17", "libredox", - "thiserror", + "thiserror 2.0.21", ] [[package]] name = "regex" -version = "1.12.3" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d" dependencies = [ "aho-corasick", "memchr", @@ -2281,9 +4449,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.14" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2" dependencies = [ "aho-corasick", "memchr", @@ -2292,9 +4460,68 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.10" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" + +[[package]] +name = "reqwest" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16a1cfa75cc186dd73d5818e510e042e40927bccc9c236b061cea97e1eb08029" +dependencies = [ + "base64 0.23.1", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "js-sys", + "log", + "mime", + "mime_guess", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-pki-types", + "rustls-platform-verifier", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-rustls", + "tokio-util", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", +] + +[[package]] +name = "reqwest-middleware" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" +checksum = "07bc3f1384cffa4f274dad2d4ddd73aed32fed8f786d96c6be8aa4e5fd3c3b58" +dependencies = [ + "anyhow", + "async-trait", + "http", + "reqwest", + "thiserror 2.0.21", + "tower-service", +] [[package]] name = "rfc6979" @@ -2306,6 +4533,29 @@ dependencies = [ "hmac", ] +[[package]] +name = "rgb" +version = "0.8.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b34b781b31e5d73e9fbc8689c70551fd1ade9a19e3e28cfec8580a79290cc4" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if 1.0.5", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + [[package]] name = "rpassword" version = "7.5.4" @@ -2339,14 +4589,26 @@ dependencies = [ [[package]] name = "rtoolbox" -version = "0.0.3" +version = "0.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7cc970b249fbe527d6e02e0a227762c9108b2f49d81094fe357ffc6d14d7f6f" +checksum = "9a1efe12a1469752d0e6ff5ebec0b6ef4924cc5c4c71046b0ec730040535819d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc-hash" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" + [[package]] name = "rustc_version" version = "0.4.1" @@ -2356,24 +4618,133 @@ dependencies = [ "semver", ] +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags 2.13.2", + "errno", + "libc", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", +] + [[package]] name = "rustix" version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "891efababe418670775f199f0d233d84843c227a0949a883ce15b37c78d6629d" dependencies = [ - "bitflags", + "bitflags 2.13.2", "errno", "libc", - "linux-raw-sys", - "windows-sys 0.52.0", + "linux-raw-sys 0.12.1", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.23.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e13bd8c0e9365c43cfa5c9e8f9ad49d3c8444926c9aac819e0e4dc503c8fdf" +dependencies = [ + "aws-lc-rs", + "once_cell", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a073f5dc7469f984c52ad2752b63b0807745133b6de880b7b64c1ac4c48aec4" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pki-types" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4925028c7eb5d1fcdaf196971378ed9d2c1c4efc7dc5d011256f76c99c0a96" +dependencies = [ + "web-time", + "zeroize", +] + +[[package]] +name = "rustls-platform-verifier" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1167586491e2b18b8bfbb293e8180ec17c201c4f076d7cb3070ca964e7598f98" +dependencies = [ + "core-foundation 0.10.1", + "core-foundation-sys 0.8.7", + "jni", + "log", + "once_cell", + "rustls", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki", + "security-framework", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls-platform-verifier-android" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eec689c0bc40ff2458a5977b6619cb718087084a18e02a131c599b62d05e1a5f" + +[[package]] +name = "rustls-webpki" +version = "0.103.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443b1b6d39d7c663139942cc4558262562d2c84123bb6282ef177009ca8b281" +dependencies = [ + "aws-lc-rs", + "ring", + "rustls-pki-types", + "untrusted", ] [[package]] name = "rustversion" -version = "1.0.22" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "safe-transmute" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +checksum = "3944826ff8fa8093089aba3acb4ef44b9446a99a16f3bf4e74af3f77d340ab7d" + +[[package]] +name = "safe_arch" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42c6efa15875e6ecb39ca61fb0b0c1a40b84fac5a5ffe71eef7d1000c8eb3f5f" +dependencies = [ + "bytemuck", +] [[package]] name = "same-file" @@ -2384,6 +4755,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schannel" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cb23c424d8ee841bb4d813677ca237e2a610067d594fec130f87d6093495ab5" +dependencies = [ + "windows-sys 0.61.2", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -2398,7 +4778,7 @@ checksum = "d56d437c2f19203ce5f7122e507831de96f3d2d4d3be5af44a0b0a09d8a80e4d" dependencies = [ "base16ct", "ctutils", - "der 0.8.0", + "der 0.8.2", "hybrid-array", "subtle", "zeroize", @@ -2413,11 +4793,34 @@ dependencies = [ "libc", ] +[[package]] +name = "security-framework" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" +dependencies = [ + "bitflags 2.13.2", + "core-foundation 0.10.1", + "core-foundation-sys 0.8.7", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" +dependencies = [ + "core-foundation-sys 0.8.7", + "libc", +] + [[package]] name = "semver" -version = "1.0.27" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" [[package]] name = "serde" @@ -2484,13 +4887,13 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.20" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" +checksum = "8d3b1629de253c70a0508c3899572da79ca359fdab27c7920ff00406df418906" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.9", ] [[package]] @@ -2502,6 +4905,18 @@ dependencies = [ "serde_core", ] +[[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 = "serdect" version = "0.4.3" @@ -2518,9 +4933,9 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47d7069beb7d6ac7b9acd1039986e73443f24234f41074da099d6f994ac9ad19" dependencies = [ - "cfg-if", + "cfg-if 1.0.5", "cpufeatures", - "digest 0.11.2", + "digest 0.11.3", ] [[package]] @@ -2535,13 +4950,24 @@ dependencies = [ "jiff", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "shellexpand" version = "3.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32824fab5e16e6c4d86dc1ba84489390419a39f97699852b66480bb87d297ed8" dependencies = [ + "bstr", "dirs 6.0.0", + "os_str_bytes", ] [[package]] @@ -2567,35 +4993,78 @@ dependencies = [ ] [[package]] -name = "signal-hook-registry" -version = "1.4.8" +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest 0.10.7", + "rand_core 0.6.4", +] + +[[package]] +name = "signature" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d567dcbaf0049cb8ac2608a76cd95ff9e4412e1899d389ee400918ca7537f5" +dependencies = [ + "digest 0.11.3", + "rand_core 0.10.1", +] + +[[package]] +name = "simba" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +checksum = "f1a7200d82ff1c7b4235efd12f11e2537a402c91cf83a5cb97ce80eef787fde7" dependencies = [ - "errno", - "libc", + "approx", + "num-complex", + "num-traits", + "wide", ] [[package]] -name = "signature" -version = "2.2.0" +name = "simd-adler32" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" + +[[package]] +name = "simd_cesu8" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11031e251abf8611c80f460e19dbdeb54a66db918e49c65a7065b46ac7aec520" dependencies = [ - "digest 0.10.7", - "rand_core 0.6.4", + "rustc_version", + "simdutf8", ] [[package]] -name = "signature" -version = "3.0.0" +name = "simd_helpers" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d567dcbaf0049cb8ac2608a76cd95ff9e4412e1899d389ee400918ca7537f5" +checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6" dependencies = [ - "digest 0.11.2", - "rand_core 0.10.1", + "quote", ] +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + [[package]] name = "slab" version = "0.4.12" @@ -2604,9 +5073,9 @@ checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" -version = "1.15.1" +version = "1.16.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +checksum = "d0d5d4b1981b8bbbb7aed204cae5726d683d5d6ac7e74ec54122ea28f315e7c8" dependencies = [ "serde", ] @@ -2634,7 +5103,7 @@ dependencies = [ "hkdf", "hmac", "p256", - "rand 0.10.2", + "rand 0.10.3", "secstr", "serde", "serde_bytes", @@ -2643,7 +5112,7 @@ dependencies = [ "soft-fido2-crypto", "soft-fido2-ctap", "soft-fido2-transport", - "spin 0.12.1", + "spin 0.12.3", "zeroize", ] @@ -2659,10 +5128,10 @@ dependencies = [ "hkdf", "hmac", "p256", - "rand 0.10.2", + "rand 0.10.3", "sha2", "subtle", - "thiserror", + "thiserror 2.0.21", "zeroize", ] @@ -2673,7 +5142,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5eb91fe4b2a4b5af9587b41b527a5e7c284375fa9c3454e0200f8955326c38a9" dependencies = [ "cbor4ii", - "rand 0.10.2", + "rand 0.10.3", "secstr", "serde", "serde_bytes", @@ -2681,7 +5150,7 @@ dependencies = [ "smallvec", "soft-fido2-crypto", "subtle", - "thiserror", + "thiserror 2.0.21", "zeroize", ] @@ -2703,12 +5172,15 @@ name = "spin" version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3763264f6b73151db08c50ff20d7d8a0b8796e021cdea7ceedad07b80155fa0e" +dependencies = [ + "lock_api", +] [[package]] name = "spin" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd5231412d905519dca6a5deb0327d407be68d6c941feec004533401d3a0a715" +checksum = "0134f9043ed38b087ac4f7d4af44c79e2c9e5094421fe3164f435ce585953b10" dependencies = [ "lock_api", ] @@ -2725,12 +5197,12 @@ dependencies = [ [[package]] name = "spki" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d9efca8738c78ee9484207732f728b1ef517bbb1833d6fc0879ca898a522f6f" +checksum = "7ef958a98b9d5da290cfc78946e9f3e61e1e62a18db0d92cac0b83cc161491a9" dependencies = [ "base64ct", - "der 0.8.0", + "der 0.8.2", ] [[package]] @@ -2739,6 +5211,22 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "statrs" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a3fe7c28c6512e766b0874335db33c94ad7b8f9054228ae1c2abd47ce7d335e" +dependencies = [ + "approx", + "num-traits", +] + [[package]] name = "strsim" version = "0.11.1" @@ -2751,6 +5239,12 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" +[[package]] +name = "symlink" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7973cce6668464ea31f176d85b13c7ab3bba2cb3b77a2ed26abd7801688010a" + [[package]] name = "syn" version = "1.0.109" @@ -2784,15 +5278,60 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + [[package]] name = "synstructure" -version = "0.13.2" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +checksum = "901704edd0dfe137f1987838ee4f259e4e063c31371bdb423f7ae38ec6f77f02" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.9", +] + +[[package]] +name = "sysinfo" +version = "0.39.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2071df9448915b71c4fe6d25deaf1c22f12bd234f01540b77312bb8e41361e6" +dependencies = [ + "libc", + "memchr", + "ntapi", + "objc2-core-foundation", + "objc2-io-kit", + "objc2-open-directory", + "windows", +] + +[[package]] +name = "system-configuration" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" +dependencies = [ + "bitflags 2.13.2", + "core-foundation 0.9.4", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys 0.8.7", + "libc", ] [[package]] @@ -2802,7 +5341,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7266304d24ca5a4b230545fc558c80e18bd3e1d2eb1be149b6bcd04398d3e79c" dependencies = [ "log", - "rustix", + "rustix 1.1.5", ] [[package]] @@ -2817,7 +5356,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f37a6c354fd28fc9e322ed9bd47e3959576dad28c9d58ea1cf888cce1c7ccb36" dependencies = [ - "thiserror", + "thiserror 2.0.21", "windows", "windows-version", ] @@ -2829,10 +5368,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", - "getrandom 0.3.4", + "getrandom 0.4.3", "once_cell", - "rustix", - "windows-sys 0.52.0", + "rustix 1.1.5", + "windows-sys 0.61.2", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", ] [[package]] @@ -2841,7 +5389,18 @@ version = "2.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09e52cb86a36cede5cb101bf8908837b3e4c6e5e59fe7fd85c23fb56200d189e" dependencies = [ - "thiserror-impl", + "thiserror-impl 2.0.21", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", ] [[package]] @@ -2855,35 +5414,75 @@ dependencies = [ "syn 3.0.9", ] +[[package]] +name = "thread_local" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad99c4c6d32803332c548b1af0540b357b3f5fc0be8f6c6bfe8b2e6ae784070" +dependencies = [ + "cfg-if 1.0.5", +] + +[[package]] +name = "tiff" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b63feaf3343d35b6ca4d50483f94843803b0f51634937cc2ec519fc32232bc52" +dependencies = [ + "fax", + "flate2", + "half 2.7.1", + "quick-error", + "weezl", + "zune-jpeg", +] + [[package]] name = "time" -version = "0.3.47" +version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +checksum = "cdb87b95ec50ddfa440816d227a17b2ccbdda963a316a727fda0fc4334f7d134" dependencies = [ "deranged", "num-conv", "powerfmt", "serde_core", "time-core", + "time-macros", ] [[package]] name = "time-core" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" +checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" + +[[package]] +name = "time-macros" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e689342a48d2ea927c87ea50cabf8594854bf940e9310208848d680d668ed85" +dependencies = [ + "num-conv", + "time-core", +] [[package]] name = "tinystr" -version = "0.8.2" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +checksum = "abc840c238154d58f9e86b2792261edfde565a17696e1cda1a449de27979801a" dependencies = [ "displaydoc", "zerovec", ] +[[package]] +name = "tinyvec" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3ca314f692efd6c868f8408f53fe444634a845f96c028b97d35f6a1f79f0ee" + [[package]] name = "tokio" version = "1.54.1" @@ -2903,11 +5502,70 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.7.0" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" +checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e" dependencies = [ "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[package]] +name = "tokio-retry" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a129d95275ebf4c493ec53bf0f8cd95f5ac161bc4f381700809a54f595d4470" +dependencies = [ + "pin-project-lite", + "rand 0.10.3", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9cc2678c2cdd569ef8215e2afd7954ada2ae20b4fdd2c5fe6139a3b02d105db" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e464cf451ba96ebfc6f9b6542f17ee8b8956e33f1e40d9690624e59d7a7f8a4b" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "libc", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio_with_wasm" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34e40fbbbd95441133fe9483f522db15dbfd26dc636164ebd8f2dd28759a6aa6" +dependencies = [ + "js-sys", + "tokio", + "tokio_with_wasm_proc", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "tokio_with_wasm_proc" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d01145a2c788d6aae4cd653afec1e8332534d7d783d01897cefcafe4428de992" +dependencies = [ "quote", "syn 2.0.119", ] @@ -2924,7 +5582,7 @@ dependencies = [ "toml_datetime", "toml_parser", "toml_writer", - "winnow 1.0.0", + "winnow", ] [[package]] @@ -2938,14 +5596,14 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.25.4+spec-1.1.0" +version = "0.25.17+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7193cbd0ce53dc966037f54351dbbcf0d5a642c7f0038c382ef9e677ce8c13f2" +checksum = "e3641d5bbb5349a79e1020a242d251efbc546ad8048d133958323ce9c40a9c9c" dependencies = [ "indexmap", "toml_datetime", "toml_parser", - "winnow 0.7.15", + "winnow", ] [[package]] @@ -2954,7 +5612,7 @@ version = "1.1.5+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baa693a8032d7e1cada7d0041e96126df243179ff061456783ac7f12bda4744c" dependencies = [ - "winnow 1.0.0", + "winnow", ] [[package]] @@ -2963,6 +5621,51 @@ version = "1.1.3+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06bdbd8cfc056b8d2e2e85f29b56a3bdbecb527cef81eb39e3e7b98af4652770" +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" +dependencies = [ + "bitflags 2.13.2", + "bytes", + "futures-util", + "http", + "http-body", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", + "url", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + [[package]] name = "tracing" version = "0.1.44" @@ -2974,6 +5677,19 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-appender" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "050686193eb999b4bb3bc2acfa891a13da00f79734704c4b8b4ef1a10b368a3c" +dependencies = [ + "crossbeam-channel", + "symlink", + "thiserror 2.0.21", + "time", + "tracing-subscriber", +] + [[package]] name = "tracing-attributes" version = "0.1.31" @@ -2992,8 +5708,57 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", + "valuable", ] +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-serde" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" +dependencies = [ + "serde", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex-automata", + "serde", + "serde_json", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", + "tracing-serde", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + [[package]] name = "tss-esapi" version = "7.7.0" @@ -3002,7 +5767,7 @@ checksum = "3f10b25a84912b894d0e6d68f4a3771c923e9c44ddaaed7920cde92ed28aa84e" dependencies = [ "bitfield", "enumflags2", - "getrandom 0.4.2", + "getrandom 0.4.3", "hostname-validator", "log", "mbox", @@ -3027,43 +5792,96 @@ dependencies = [ "target-lexicon", ] +[[package]] +name = "twox-hash" +version = "2.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86a801b3cea342a06d468c8710662aa29e5e05e4f5c0d62f00bbb7f2ad7941c2" + [[package]] name = "typenum" version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" +[[package]] +name = "typewit" +version = "1.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "214ca0b2191785cbc06209b9ca1861e048e39b5ba33574b3cedd58363d5bb5f6" + [[package]] name = "uds_windows" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b70b87d15e91f553711b40df3048faf27a7a04e01e0ddc0cf9309f0af7c2ca" +checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e" dependencies = [ "memoffset", "tempfile", "windows-sys 0.61.2", ] +[[package]] +name = "unicase" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357cc3acc6a036009fd6c973ed009037c732d60d0b4f6c673e9041497482a28f" + [[package]] name = "unicode-ident" -version = "1.0.24" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "universal-hash" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4987bdc12753382e0bec4a65c50738ffaabc998b9cdd1f952fb5f39b0048a96" +dependencies = [ + "crypto-common 0.2.2", + "ctutils", +] + +[[package]] +name = "untrusted" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] -name = "unicode-xid" -version = "0.2.6" +name = "ureq" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +checksum = "cde93ff05758a36a851a398a772b0b79a82fbe3c186a46f2696baaeaf84c966b" +dependencies = [ + "base64 0.23.1", + "der 0.8.2", + "log", + "native-tls", + "percent-encoding", + "rustls-pki-types", + "ureq-proto", + "utf8-zero", + "webpki-root-certs", +] [[package]] -name = "universal-hash" -version = "0.6.1" +name = "ureq-proto" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4987bdc12753382e0bec4a65c50738ffaabc998b9cdd1f952fb5f39b0048a96" +checksum = "841583fc36089d7d59419568ae157f43a5a03a2e5a81ba87c77d1596ef46e922" dependencies = [ - "crypto-common 0.2.2", - "ctutils", + "base64 0.23.1", + "http", + "httparse", + "log", ] [[package]] @@ -3078,6 +5896,18 @@ dependencies = [ "serde", ] +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + +[[package]] +name = "utf8-zero" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8c0a043c9540bae7c578c88f91dda8bd82e59ae27c21baca69c8b191aaf5a6e" + [[package]] name = "utf8_iter" version = "1.0.4" @@ -3092,16 +5922,53 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.22.0" +version = "1.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a68d3c8f01c0cfa54a75291d83601161799e4a89a39e0929f4b0354d88757a37" +checksum = "4a0e2d11620c50695fe12bbbfde96b3477fe606e7284c22d505c12ce51214514" dependencies = [ - "getrandom 0.4.2", + "getrandom 0.4.3", "js-sys", "serde_core", "wasm-bindgen", ] +[[package]] +name = "v4l" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8fbfea44a46799d62c55323f3c55d06df722fbe577851d848d328a1041c3403" +dependencies = [ + "bitflags 1.3.2", + "libc", + "v4l2-sys-mit", +] + +[[package]] +name = "v4l2-sys-mit" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6779878362b9bacadc7893eac76abe69612e8837ef746573c4a5239daf11990b" +dependencies = [ + "bindgen", +] + +[[package]] +name = "v_frame" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "666b7727c8875d6ab5db9533418d7c764233ac9c0cff1d469aec8fa127597be2" +dependencies = [ + "aligned-vec", + "num-traits", + "wasm-bindgen", +] + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + [[package]] name = "vcpkg" version = "0.2.15" @@ -3130,48 +5997,77 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "want" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec4cdd0dd910afe868b7ef477227d8d538b46b3075031afee8a9f2acb0a2ed0b" +dependencies = [ + "try-lock", +] + [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" +[[package]] +name = "wasi" +version = "0.14.7+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" +dependencies = [ + "wasip2", +] + [[package]] name = "wasip2" -version = "1.0.2+wasi-0.2.9" +version = "1.0.4+wasi-0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" dependencies = [ "wit-bindgen", ] [[package]] -name = "wasip3" -version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +name = "wasite" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +checksum = "66fe902b4a6b8028a753d5424909b764ccf79b7a209eac9bf97e59cda9f71a42" dependencies = [ - "wit-bindgen", + "wasi 0.14.7+wasi-0.2.4", ] [[package]] name = "wasm-bindgen" -version = "0.2.114" +version = "0.2.129" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" +checksum = "9bb54f33acc68fd454578d9820b0bde1a1a3d17aa17bb7b6595806d02886d409" dependencies = [ - "cfg-if", + "cfg-if 1.0.5", "once_cell", "rustversion", "wasm-bindgen-macro", "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cbab34de2d982e9b48e18d216d04c4a6f641066ff19ffb699980f591ee3610e" +dependencies = [ + "js-sys", + "tokio", + "wasm-bindgen", +] + [[package]] name = "wasm-bindgen-macro" -version = "0.2.114" +version = "0.2.129" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" +checksum = "2e29d0c35b16e224a7eeb5cd2d25e3e1968fbd65604117b44d3b789d00ee8535" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3179,67 +6075,128 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.114" +version = "0.2.129" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" +checksum = "6f501a8bc3719dba86ef8ae4728879c08001bea749eb1333ac5b91e040e2a6b7" dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.9", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.114" +version = "0.2.129" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" +checksum = "23f0c9c52aa7cd7d77769a4cfe2a9adb1b331f489a41d912ce14513d5ab995c6" dependencies = [ "unicode-ident", ] [[package]] -name = "wasm-encoder" -version = "0.244.0" +name = "wasm-streams" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +checksum = "9d1ec4f6517c9e11ae630e200b2b65d193279042e28edd4a2cda233e46670bbb" dependencies = [ - "leb128fmt", - "wasmparser", + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", ] [[package]] -name = "wasm-metadata" -version = "0.244.0" +name = "web-sys" +version = "0.3.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +checksum = "88261b9deccee56594c11a3460c462c41f58d148598fe70ad77070126a68aba4" dependencies = [ - "anyhow", - "indexmap", - "wasm-encoder", - "wasmparser", + "js-sys", + "wasm-bindgen", ] [[package]] -name = "wasmparser" -version = "0.244.0" +name = "web-time" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" dependencies = [ - "bitflags", - "hashbrown 0.15.5", - "indexmap", - "semver", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-root-certs" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e49d0e65abc00c142e8f9428da991da9f1a250c39be97459901eb12b9b49f62a" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "weezl" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" + +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix 0.38.44", +] + +[[package]] +name = "which" +version = "7.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d643ce3fd3e5b54854602a080f34fb10ab75e0b813ee32d00ca2b44fa74762" +dependencies = [ + "either", + "env_home", + "rustix 1.1.5", + "winsafe", ] [[package]] name = "which" -version = "8.0.2" +version = "8.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bae2f2b2b816647a1cab1acc91f5bd20812d53cb344382635ec2181940c8034f" +dependencies = [ + "libc", +] + +[[package]] +name = "whoami" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81995fafaaaf6ae47a7d0cc83c67caf92aeb7e5331650ae6ff856f7c0c60c459" +checksum = "626c4bac6755d76ffc12cb01b2eac751db1996b9e0041de9aa02c8c211ddc82c" dependencies = [ "libc", + "libredox", + "objc2-system-configuration", + "wasite", + "web-sys", +] + +[[package]] +name = "wide" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d920ac99c3c8edce110cb8d07dbb324d6d026011dce85b1e9355b70f0adacc4f" +dependencies = [ + "bytemuck", + "safe_arch", ] [[package]] @@ -3264,7 +6221,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -3356,6 +6313,17 @@ dependencies = [ "windows-link", ] +[[package]] +name = "windows-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" +dependencies = [ + "windows-link", + "windows-result", + "windows-strings", +] + [[package]] name = "windows-result" version = "0.4.1" @@ -3383,6 +6351,15 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-sys" version = "0.61.2" @@ -3476,132 +6453,197 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.7.15" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" +checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" dependencies = [ "memchr", ] [[package]] -name = "winnow" -version = "1.0.0" +name = "winsafe" +version = "0.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a90e88e4667264a994d34e6d1ab2d26d398dcdca8b7f52bec8668957517fc7d8" -dependencies = [ - "memchr", -] +checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" [[package]] name = "wit-bindgen" -version = "0.51.0" +version = "0.57.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" -dependencies = [ - "wit-bindgen-rust-macro", -] +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" [[package]] -name = "wit-bindgen-core" -version = "0.51.0" +name = "wnaf" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +checksum = "795ca18b3fdb5e62bf982199278341ddcf7ebf7d32e25e212ad05d496e95f6fa" dependencies = [ - "anyhow", - "heck", - "wit-parser", + "ff", + "group", + "hybrid-array", + "primefield", ] [[package]] -name = "wit-bindgen-rust" -version = "0.51.0" +name = "writeable" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" -dependencies = [ - "anyhow", - "heck", - "indexmap", - "prettyplease", - "syn 2.0.119", - "wasm-metadata", - "wit-bindgen-core", - "wit-component", -] +checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc" [[package]] -name = "wit-bindgen-rust-macro" -version = "0.51.0" +name = "xet-client" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +checksum = "15500e5fc9e17be15224f9e34cb07d41fb2805d9dbbf7bd3507c982fd1eb3efd" dependencies = [ "anyhow", - "prettyplease", - "proc-macro2", - "quote", - "syn 2.0.119", - "wit-bindgen-core", - "wit-bindgen-rust", + "async-trait", + "base64 0.22.1", + "bytes", + "chrono", + "crc32fast", + "futures", + "http", + "hyper", + "more-asserts", + "rand 0.10.3", + "redb", + "reqwest", + "reqwest-middleware", + "serde", + "serde_json", + "serde_repr", + "statrs", + "tempfile", + "thiserror 2.0.21", + "tokio", + "tokio-retry", + "tokio_with_wasm", + "tracing", + "url", + "urlencoding", + "uuid", + "web-time", + "xet-core-structures", + "xet-runtime", ] [[package]] -name = "wit-component" -version = "0.244.0" +name = "xet-core-structures" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +checksum = "5080d5803c8bf15fa56ef934050a46b225801bad3ea4cb8bb3c46c5c37976516" dependencies = [ - "anyhow", - "bitflags", - "indexmap", - "log", + "async-trait", + "base64 0.22.1", + "blake3", + "bytemuck", + "bytes", + "countio", + "futures", + "futures-util", + "getrandom 0.4.3", + "heapify", + "itertools", + "lz4_flex", + "more-asserts", + "rand 0.10.3", + "regex", + "safe-transmute", "serde", - "serde_derive", - "serde_json", - "wasm-encoder", - "wasm-metadata", - "wasmparser", - "wit-parser", + "static_assertions", + "thiserror 2.0.21", + "tokio", + "tokio-util", + "tracing", + "uuid", + "web-time", + "xet-runtime", ] [[package]] -name = "wit-parser" -version = "0.244.0" +name = "xet-data" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +checksum = "1287a1657fb67de846030f6605a9960dcdad401c467b490657e6e909d2e0d1c0" dependencies = [ "anyhow", - "id-arena", - "indexmap", - "log", - "semver", + "async-trait", + "bytes", + "chrono", + "gearhash", + "http", + "itertools", + "more-asserts", + "rand 0.10.3", "serde", - "serde_derive", "serde_json", - "unicode-xid", - "wasmparser", + "sha2", + "tempfile", + "thiserror 2.0.21", + "tokio", + "tokio-util", + "tokio_with_wasm", + "tracing", + "url", + "uuid", + "web-time", + "xet-client", + "xet-core-structures", + "xet-runtime", ] [[package]] -name = "wnaf" -version = "0.14.0" +name = "xet-runtime" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab12e7090f27e2ffd9322651492942d50c2926094af30601e1964337db39daf1" +checksum = "921953c885ce83e02b21e8d26444b75c78c9e83076699ced08d5c6fc1cdb48ac" dependencies = [ - "ff", - "group", - "hybrid-array", + "anyhow", + "async-trait", + "bytes", + "chrono", + "colored", + "const-str", + "ctor", + "dirs 6.0.0", + "futures", + "git-version", + "humantime", + "konst 0.4.3", + "libc", + "more-asserts", + "oneshot", + "pin-project", + "rand 0.10.3", + "reqwest", + "serde", + "serde_json", + "shellexpand", + "sysinfo", + "thiserror 2.0.21", + "tokio", + "tokio-util", + "tokio_with_wasm", + "tracing", + "tracing-appender", + "tracing-subscriber", + "web-time", + "whoami", + "winapi", ] [[package]] -name = "writeable" -version = "0.6.2" +name = "y4m" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" +checksum = "7a5a4b21e1a62b67a2970e6831bc091d7b87e119e7f9791aef9702e3bef04448" [[package]] name = "yoke" -version = "0.8.1" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +checksum = "417ef3fcf6c300b7dbd25c85531a746931c02ad536f3cf4786ed1e88223340b3" dependencies = [ "stable_deref_trait", "yoke-derive", @@ -3610,13 +6652,13 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.1" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +checksum = "ec8ebde2db3681e8c9980cc27822030e68752690ddfa9473e739aeb4dbde6d71" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.9", "synstructure", ] @@ -3642,14 +6684,14 @@ dependencies = [ "hex", "libc", "ordered-stream", - "rustix", + "rustix 1.1.5", "serde", "serde_repr", "tracing", "uds_windows", "uuid", "windows-sys 0.61.2", - "winnow 1.0.0", + "winnow", "zbus_macros 5.19.0", "zbus_names", "zvariant", @@ -3662,13 +6704,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcff5faa63a63d5b81051740f7382017f10b3440b3f401d97f0cf0b3b39c62d9" dependencies = [ "async-trait", - "bitflags", + "bitflags 2.13.2", "endi", "futures-core", "hex", "libc", "ordered-stream", - "rustix", + "rustix 1.1.5", "serde", "serde_repr", "socket2", @@ -3677,7 +6719,7 @@ dependencies = [ "uds_windows", "uuid", "windows-sys 0.61.2", - "winnow 1.0.0", + "winnow", "zbus_macros 6.1.0", "zbus_utils", "zcheapstr", @@ -3713,12 +6755,12 @@ dependencies = [ [[package]] name = "zbus_names" -version = "4.3.4" +version = "4.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8bf88b4a3ff53e883001e0e0115b297a9d53c31b9c1edd2bfdd853e3428624e" +checksum = "812a12be4ead7a59e18ea8f047d08add0066b73bc62fc1467066a2472ae088dd" dependencies = [ "serde", - "winnow 1.0.0", + "winnow", "zvariant", ] @@ -3732,32 +6774,32 @@ dependencies = [ "quote", "serde", "syn 3.0.9", - "winnow 1.0.0", + "winnow", ] [[package]] name = "zcheapstr" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "769381976ea05c1f0abde0ca527b02e415bccbdbad148534a2b0c1901c9ab934" +checksum = "d1afec51604565183aeb5c54c20aeab286120d4e4460f7f76e3e8bb8c0d99473" dependencies = [ "serde", ] [[package]] name = "zerocopy" -version = "0.8.42" +version = "0.8.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2578b716f8a7a858b7f02d5bd870c14bf4ddbbcf3a4c05414ba6503640505e3" +checksum = "e5fe1f8f1b06191a00962174c61aa5005e0bb391a6d80d07e24d115c01a92ed8" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.42" +version = "0.8.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e6cc098ea4d3bd6246687de65af3f920c430e236bee1e3bf2e441463f08a02f" +checksum = "863ad3ac83293fb4d740aedbfdc9240dd8d1a50c1099acd76ce80ce7c7230c7f" dependencies = [ "proc-macro2", "quote", @@ -3766,22 +6808,22 @@ dependencies = [ [[package]] name = "zerofrom" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +checksum = "f75b4683f6c7f45248d4d64056a24298c6281e0993356d7d1b4a1a962ef10d4a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.9", "synstructure", ] @@ -3807,9 +6849,9 @@ dependencies = [ [[package]] name = "zerotrie" -version = "0.2.3" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +checksum = "4ea269c3bd32f0a32c321907a2ae912ba6f4649bb0fc764a15627e99a7095a3f" dependencies = [ "displaydoc", "yoke", @@ -3818,9 +6860,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.5" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +checksum = "f58a2799cfe9a1670c7ea8edbd52ef8edb93cb37a7f83bf31ba9e35d9dae6a40" dependencies = [ "yoke", "zerofrom", @@ -3829,45 +6871,75 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.2" +version = "0.11.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +checksum = "c3743ddbf47738d929cd1ae2e199d40d0162979dfe31aef8ae646d2bf00bf97a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.9", ] +[[package]] +name = "zlib-rs" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b268e58e7c693d7c271f93ffc4ba3b380412554231c85bf61ca7af91042a4112" + [[package]] name = "zmij" -version = "1.0.21" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" [[package]] name = "zruntime" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "467fd80a2014d186319f14b81aef027aa466712f355c90158a0e6b39de60726d" +checksum = "dfc035df602243402949ddf3dcc5bcfad7edeb732dd49ec6e605431c4eca54ce" dependencies = [ "futures-core", "futures-io", - "rustix", + "rustix 1.1.5", "socket2", "tracing", "windows-sys 0.61.2", ] +[[package]] +name = "zune-core" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56377fd46368984a170bc5aac5567e52ca5da874caa60bea39fcbca78fb658b" + +[[package]] +name = "zune-inflate" +version = "0.2.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "zune-jpeg" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27bc9d5b815bc103f142aa054f561d9187d191692ec7c2d1e2b4737f8dbd7296" +dependencies = [ + "zune-core", +] + [[package]] name = "zvariant" -version = "5.14.0" +version = "5.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e28c25bd8bb8da5a1f3e7065d0c156b9ee9a7973adf78b0e35eaefdf3b1b5c" +checksum = "80bf6d6cd6a4b601acb64cfb8284cdc643fcfa75ef26ae3c46ec8aa4e8a1fbb7" dependencies = [ "endi", "enumflags2", "serde", - "winnow 1.0.0", + "winnow", "zcheapstr", "zvariant_derive", "zvariant_utils", @@ -3875,9 +6947,9 @@ dependencies = [ [[package]] name = "zvariant_derive" -version = "5.14.0" +version = "5.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d496a145685283b67e232bd9e47377f6b60ad9d51e3601b23867f77c42477f96" +checksum = "ef2672456ba1cb54b5eaec136e63135b3c7495fb938e53b28a62e633496d486d" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -3888,13 +6960,13 @@ dependencies = [ [[package]] name = "zvariant_utils" -version = "4.0.0" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "629d80ece222cad20fe0e8741be493c4ab166acf3b85341bdc2cdbcfd8f3c2d6" +checksum = "bad0294361a320b694a328460dc73add56c306150f5cb6bfafc44446120008a3" dependencies = [ "proc-macro2", "quote", "serde", "syn 3.0.9", - "winnow 1.0.0", + "winnow", ] diff --git a/Cargo.toml b/Cargo.toml index bb0d1ed0..2471c547 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,6 +54,13 @@ psl = "2" zbus = "6.0" futures-lite = "2" +# UV provider dependencies +nokhwa = { version = "0.10", features = ["input-native"] } +face_id = "0.4" +image = "0.25" +tokio = { version = "1", features = ["rt-multi-thread", "macros", "time"] } +which = "7" + # Proc macro dependencies syn = { version = "3.0", features = ["full", "extra-traits"] } quote = "1.0" diff --git a/Makefile b/Makefile index 2425ecdb..7251c2c8 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,8 @@ CARGO_TARGET_DIR ?= target CARGO_TARGET ?= x86_64-unknown-linux-gnu PKG_BASE_NAME ?= passless-${CARGO_TARGET} PROJECT_VERSION := $(shell sed -n 's/^version = "\(.*\)"/\1/p' ./Cargo.toml | head -n1) +# Default to tpm feature only, face feature requires glibc 2.38+ +CARGO_FEATURES ?= tpm AGENT_FUZZ_SMOKE_SECS ?= 10 .DEFAULT: help diff --git a/cmd/passless/Cargo.toml b/cmd/passless/Cargo.toml index 62443419..e8aa3256 100644 --- a/cmd/passless/Cargo.toml +++ b/cmd/passless/Cargo.toml @@ -32,6 +32,7 @@ required-features = ["agent"] [features] default = [] tpm = ["passless-core/tpm", "tss-esapi", "p256", "hkdf", "aes", "cipher"] +face = ["dep:nokhwa", "dep:face_id", "dep:image"] agent = ["passless-core/agent", "passless-uhid"] agent-validation = ["agent"] @@ -63,6 +64,7 @@ zeroize.workspace = true hex.workspace = true shadow-rs.workspace = true dirs.workspace = true +thiserror.workspace = true ciborium = "0.2" git2 = { version = "0.21", default-features = false, features = ["vendored-libgit2"] } hmac = "0.13" @@ -78,6 +80,16 @@ cipher = { version = "0.5", optional = true } rsa = { version = "0.9", default-features = false, features = ["std", "pem"] } toml.workspace = true +# UV provider dependencies +tokio.workspace = true +which.workspace = true +futures-util = "0.3" + +# Face recognition (optional, heavy dependencies) +nokhwa = { workspace = true, optional = true } +face_id = { workspace = true, optional = true } +image = { workspace = true, optional = true } + [dev-dependencies] base64 = "0.23" ciborium = "0.2" diff --git a/cmd/passless/src/agent/runtime.rs b/cmd/passless/src/agent/runtime.rs index 4460c7c8..b317df60 100644 --- a/cmd/passless/src/agent/runtime.rs +++ b/cmd/passless/src/agent/runtime.rs @@ -22,7 +22,7 @@ use passless_core::agent::{ AgentConfig, AgentMode, AgentProfileConfig, BrowserLeaseId, BrowserScope, DaemonStatus, EndpointId, EndpointStatusResponse, GrantId, PendingRequestId, PrincipalSessionId, ProfileId, }; -use passless_core::config::{PinConfig, SecurityConfig}; +use passless_core::config::{PinConfig, SecurityConfig, UvConfig}; use super::audit::AuditGate; use super::audit_events::{ @@ -83,6 +83,7 @@ pub struct RuntimeStartParams<'a> { pub agent_config: &'a AgentConfig, pub security_config: SecurityConfig, pub pin_config: PinConfig, + pub uv_config: UvConfig, pub shutdown: Arc, pub endpoint_factory: Option, } @@ -122,6 +123,7 @@ pub struct EndpointSpec { pub profile_config: AgentProfileConfig, pub security_config: SecurityConfig, pub pin_config: PinConfig, + pub uv_config: UvConfig, pub interaction_manager: Arc, pub preparation_slot: Arc, pub operation_lock: Arc>, @@ -602,6 +604,7 @@ impl AgentRuntime { agent_config: &AgentConfig, security_config: SecurityConfig, pin_config: PinConfig, + uv_config: UvConfig, shutdown: Arc, ) -> Result, RuntimeError> { Self::start_with_factories(RuntimeStartParams { @@ -612,6 +615,7 @@ impl AgentRuntime { agent_config, security_config, pin_config, + uv_config, shutdown, endpoint_factory: None, }) @@ -626,6 +630,7 @@ impl AgentRuntime { agent_config, security_config, pin_config, + uv_config, shutdown, endpoint_factory, } = params; @@ -1093,6 +1098,7 @@ impl AgentRuntime { profile_config: profile.clone(), security_config: security_config.clone(), pin_config: pin_config.clone(), + uv_config: uv_config.clone(), interaction_manager: interaction_manager.clone(), preparation_slot: preparation_slot.clone(), operation_lock: backend.operation_lock.clone(), @@ -1152,6 +1158,7 @@ impl AgentRuntime { profile_config: profile.clone(), security_config: security_config.clone(), pin_config: effective_pin_config, + uv_config: uv_config.clone(), interaction_manager: interaction_manager.clone(), preparation_slot: preparation_slot.clone(), operation_lock, @@ -1408,6 +1415,7 @@ impl AgentRuntime { provider, spec.security_config.clone(), spec.pin_config.clone(), + spec.uv_config.clone(), spec.interaction_manager.clone(), ) .map_err(|e| { @@ -1504,6 +1512,7 @@ impl AgentRuntime { Some(deps.pin_storage.clone()), spec.security_config.clone(), spec.pin_config.clone(), + spec.uv_config.clone(), spec.interaction_manager.clone(), ) .map_err(|e| { @@ -1674,6 +1683,7 @@ impl AgentRuntime { Some(deps.pin_storage.clone()), spec.security_config.clone(), spec.pin_config.clone(), + spec.uv_config.clone(), spec.interaction_manager.clone(), ) .map_err(|e| { @@ -6136,6 +6146,7 @@ mod tests { }, security_config: SecurityConfig::default(), pin_config: PinConfig::default(), + uv_config: UvConfig::default(), interaction_manager: Arc::new(super::super::interaction::AgentInteractionManager::new()), preparation_slot: Arc::new(super::super::ceremony::CeremonyPreparationSlot::new()), operation_lock: Arc::new(Mutex::new(())), @@ -6417,6 +6428,7 @@ mod tests { profile_config: agent_config.profiles.get("test-isolated").unwrap().clone(), security_config: SecurityConfig::default(), pin_config: PinConfig::default(), + uv_config: UvConfig::default(), interaction_manager: interaction_manager.clone(), preparation_slot: preparation_slot.clone(), operation_lock: operation_lock.clone(), diff --git a/cmd/passless/src/authenticator.rs b/cmd/passless/src/authenticator.rs index bff62f0b..f74f34f5 100644 --- a/cmd/passless/src/authenticator.rs +++ b/cmd/passless/src/authenticator.rs @@ -5,12 +5,18 @@ use crate::credential_backup::{ CMD_PASSLESS_RESTORE, backup_commit_auth_data, backup_prepare_auth_data, bundle_token, decrypt_credential, encrypt_credential, restore_auth_data, }; -use crate::notification::{show_user_presence_notification, show_verification_notification}; use crate::pin_storage::PinStorage; use crate::storage::{CredentialFilter, CredentialStorage}; use crate::util::bytes_to_hex; +use crate::uv::{ + CommandProvider, FprintdProvider, NotificationProvider, UserVerificationManager, + UserVerificationProvider, VerificationContext, VerificationResult, +}; + +#[cfg(feature = "face")] +use crate::uv::FaceIdProvider; -use passless_core::config::{PinConfig, PinEnforcement, SecurityConfig}; +use passless_core::config::{PinConfig, PinEnforcement, SecurityConfig, UvConfig, UvProviderType}; use soft_fido2::{ Authenticator, AuthenticatorCallbacks, AuthenticatorConfig, AuthenticatorOptions, @@ -173,6 +179,7 @@ pub struct PasslessCallbacks { pin_storage: Option>>, security_config: SecurityConfig, pin_config: PinConfig, + uv_manager: UserVerificationManager, #[cfg(feature = "agent")] interaction_manager: Option>, #[cfg(feature = "agent")] @@ -185,12 +192,16 @@ impl PasslessCallbacks { pin_storage: Option>>, security_config: SecurityConfig, pin_config: PinConfig, + uv_config: UvConfig, ) -> Self { + let uv_manager = build_uv_manager(&uv_config); + Self { storage, pin_storage, security_config, pin_config, + uv_manager, #[cfg(feature = "agent")] interaction_manager: None, #[cfg(feature = "agent")] @@ -204,60 +215,38 @@ impl PasslessCallbacks { pin_storage: Option>>, security_config: SecurityConfig, pin_config: PinConfig, + uv_config: UvConfig, interaction_manager: Arc, isolated_mode: bool, ) -> Self { + let uv_manager = build_uv_manager(&uv_config); Self { storage, pin_storage, security_config, pin_config, + uv_manager, interaction_manager: Some(interaction_manager), isolated_mode, } } -} -impl AuthenticatorCallbacks for PasslessCallbacks { - fn request_up(&self, info: &str, user: Option<&str>, rp: &str) -> Result { - #[cfg(feature = "agent")] - { - if let Some(ref manager) = self.interaction_manager { - let action = action_from_info(info); - let generation = 0; - match manager.try_consume_up(rp, action, generation) { - Some(result) => { - debug!("Agent interaction override for UP: {:?}", result); - return Ok(result); - } - None => { - if manager.has_active_token() { - debug!( - "Agent interaction token active, auto-approving UP for rp={}", - rp - ); - return Ok(UpResult::Accepted); - } - } - } - if self.isolated_mode { - debug!("Isolated mode: auto-approving UP for rp={}", rp); - return Ok(UpResult::Accepted); - } - } - } - - // Check for E2E test mode (only available in debug builds) + fn do_user_verification( + &self, + operation: &str, + user: Option<&str>, + rp: &str, + ) -> Result { #[cfg(debug_assertions)] { if std::env::var("PASSLESS_E2E_AUTO_ACCEPT_UV").is_ok() { info!("E2E test mode: Auto-accepting user verification"); - return Ok(UpResult::Accepted); + return Ok(VerificationResult::Accepted); } } - let is_registration = info.to_lowercase().contains("registration") - && !info.to_lowercase().contains("credential excluded"); + let is_registration = operation.to_lowercase().contains("registration") + && !operation.to_lowercase().contains("credential excluded"); let should_verify = if is_registration { self.security_config.user_verification_registration @@ -274,8 +263,8 @@ impl AuthenticatorCallbacks for PasslessCal }; if storage.disable_user_verification() && !is_registration && !should_verify { - debug!("User verification handled by backend (e.g., GPG): {}", info); - return Ok(UpResult::Accepted); + debug!("User verification handled by backend (e.g., GPG): {}", operation); + return Ok(VerificationResult::Accepted); } if !should_verify { @@ -286,24 +275,99 @@ impl AuthenticatorCallbacks for PasslessCal } else { "authentication" }, - info + operation ); - return Ok(UpResult::Accepted); + return Ok(VerificationResult::Accepted); } - match show_user_presence_notification( - info, - Some(rp), - user, - self.security_config.notification_timeout, - ) { - Ok(crate::notification::NotificationResult::Accepted) => Ok(UpResult::Accepted), - Ok(crate::notification::NotificationResult::Denied) => Ok(UpResult::Denied), - Err(e) => { - error!("Failed to show notification: {}", e); - Err(soft_fido2::Error::Other) + let context = VerificationContext::new(operation) + .with_relying_party(rp) + .with_user(user.unwrap_or("")) + .with_timeout(self.security_config.notification_timeout); + + self.uv_manager.verify(&context).map_err(|e| { + warn!("User verification failed: {}", e); + soft_fido2::Error::Other + }) + } +} + +fn build_uv_manager(config: &UvConfig) -> UserVerificationManager { + let mut providers: Vec> = Vec::new(); + + match config.provider { + UvProviderType::Auto => { + providers.extend(FprintdProvider::from_config(config.fprintd.enabled)); + #[cfg(feature = "face")] + providers.extend(FaceIdProvider::from_config( + config.face.enabled, + config.face.camera_index, + config.face.threshold, + )); + providers.push(NotificationProvider::from_config(config.timeout_seconds)); + } + UvProviderType::Fprintd => { + providers.extend(FprintdProvider::from_config(config.fprintd.enabled)); + } + UvProviderType::Face => { + #[cfg(feature = "face")] + providers.extend(FaceIdProvider::from_config( + config.face.enabled, + config.face.camera_index, + config.face.threshold, + )); + #[cfg(not(feature = "face"))] + log::warn!("Face provider requested but 'face' feature not enabled"); + } + UvProviderType::Notification => { + providers.push(NotificationProvider::from_config(config.timeout_seconds)); + } + UvProviderType::Command => { + providers.extend(CommandProvider::from_config( + config.command.enabled, + config.command.command.clone(), + config.timeout_seconds, + )); + } + } + + UserVerificationManager::new(providers) +} + +impl AuthenticatorCallbacks for PasslessCallbacks { + fn request_up(&self, info: &str, user: Option<&str>, rp: &str) -> Result { + #[cfg(feature = "agent")] + { + if let Some(ref manager) = self.interaction_manager { + let action = action_from_info(info); + let generation = 0; + match manager.try_consume_up(rp, action, generation) { + Some(result) => { + debug!("Agent interaction override for UP: {:?}", result); + return Ok(result); + } + None => { + if manager.has_active_token() { + debug!( + "Agent interaction token active, auto-approving UP for rp={}", + rp + ); + return Ok(UpResult::Accepted); + } + } + } + if self.isolated_mode { + debug!("Isolated mode: auto-approving UP for rp={}", rp); + return Ok(UpResult::Accepted); + } } } + + match self.do_user_verification(info, user, rp)? { + VerificationResult::Accepted => Ok(UpResult::Accepted), + VerificationResult::Denied => Ok(UpResult::Denied), + VerificationResult::Timeout => Ok(UpResult::Denied), + } } fn request_uv(&self, info: &str, user: Option<&str>, rp: &str) -> Result { @@ -392,32 +456,29 @@ impl AuthenticatorCallbacks for PasslessCal return Ok(UvResult::Denied); } info!( - "PIN is set, always_uv=false, enforcement=optional, using notification fallback" + "PIN is set, always_uv=false, enforcement=optional, using biometric/notification fallback" ); } PinEnforcement::Never => { - info!("PIN is set but enforcement=never, using notification fallback"); + info!( + "PIN is set but enforcement=never, using biometric/notification fallback" + ); } } } - match show_verification_notification( - info, - Some(rp), - user, - self.security_config.notification_timeout, - ) { - Ok(crate::notification::NotificationResult::Accepted) => { - info!("User verification via notification: accepted"); + match self.do_user_verification(info, user, rp)? { + VerificationResult::Accepted => { + info!("User verification accepted"); Ok(UvResult::AcceptedWithUp) } - Ok(crate::notification::NotificationResult::Denied) => { - warn!("User verification via notification: denied"); + VerificationResult::Denied => { + warn!("User verification denied"); Ok(UvResult::Denied) } - Err(e) => { - error!("Failed to show notification: {}", e); - Err(soft_fido2::Error::Other) + VerificationResult::Timeout => { + warn!("User verification timed out"); + Ok(UvResult::Denied) } } } @@ -642,12 +703,18 @@ pub struct AuthenticatorService< impl AuthenticatorService { /// Create a new authenticator service without PIN storage #[allow(dead_code)] - pub fn new(storage: S, security_config: SecurityConfig, pin_config: PinConfig) -> Result { + pub fn new( + storage: S, + security_config: SecurityConfig, + pin_config: PinConfig, + uv_config: UvConfig, + ) -> Result { Self::with_shared_storage( Arc::new(Mutex::new(storage)), None, security_config, pin_config, + uv_config, ) } } @@ -660,6 +727,7 @@ impl pin_storage: Option>>, security_config: SecurityConfig, pin_config: PinConfig, + uv_config: UvConfig, ) -> Result>> { #[cfg(feature = "agent")] { @@ -668,6 +736,7 @@ impl pin_storage, security_config, pin_config, + uv_config, None, ) } @@ -721,6 +790,7 @@ impl pin_storage.clone(), security_config, pin_config.clone(), + uv_config, ); let authenticator = if let Some(ps) = pin_storage { @@ -747,6 +817,7 @@ impl pin_storage: Option>>, security_config: SecurityConfig, pin_config: PinConfig, + uv_config: UvConfig, interaction_manager: Option>, ) -> Result>> { Self::build_authenticator_with_interaction_and_options( @@ -754,6 +825,7 @@ impl pin_storage, security_config, pin_config, + uv_config, interaction_manager, true, ) @@ -765,6 +837,7 @@ impl pin_storage: Option>>, security_config: SecurityConfig, pin_config: PinConfig, + uv_config: UvConfig, interaction_manager: Option>, use_agent_options: bool, ) -> Result>> { @@ -804,7 +877,6 @@ impl let config = AuthenticatorConfig::builder() .aaguid([ - // "fido.passless.rs" 0x66, 0x69, 0x64, 0x6F, 0x2E, 0x70, 0x61, 0x73, 0x73, 0x6C, 0x65, 0x73, 0x73, 0x2E, 0x72, 0x73, ]) @@ -833,6 +905,7 @@ impl pin_storage.clone(), security_config, pin_config.clone(), + uv_config, mgr.clone(), use_agent_options, ), @@ -841,6 +914,7 @@ impl pin_storage.clone(), security_config, pin_config.clone(), + uv_config, ), }; @@ -867,9 +941,10 @@ impl pin_storage: Option>>, security_config: SecurityConfig, pin_config: PinConfig, + uv_config: UvConfig, ) -> Result { let storage = Arc::new(Mutex::new(storage)); - Self::with_shared_storage(storage, pin_storage, security_config, pin_config) + Self::with_shared_storage(storage, pin_storage, security_config, pin_config, uv_config) } /// Create a new authenticator service with shared (Arc-wrapped) storage @@ -883,12 +958,14 @@ impl pin_storage: Option>>, security_config: SecurityConfig, pin_config: PinConfig, + uv_config: UvConfig, ) -> Result { let authenticator = Self::build_authenticator( storage.clone(), pin_storage.clone(), security_config.clone(), pin_config.clone(), + uv_config, )?; let mut service = Self { @@ -918,6 +995,7 @@ impl pin_storage: Option>>, security_config: SecurityConfig, pin_config: PinConfig, + uv_config: UvConfig, interaction_manager: Arc, ) -> Result { let authenticator = Self::build_authenticator_with_interaction( @@ -925,6 +1003,7 @@ impl pin_storage.clone(), security_config.clone(), pin_config.clone(), + uv_config, Some(interaction_manager), )?; @@ -953,6 +1032,7 @@ impl< pin_storage: Option>>, security_config: SecurityConfig, pin_config: PinConfig, + uv_config: UvConfig, key_provider: K, ) -> Result, K>> { #[cfg(feature = "agent")] @@ -962,6 +1042,7 @@ impl< pin_storage, security_config, pin_config, + uv_config, None, key_provider, ) @@ -1016,6 +1097,7 @@ impl< pin_storage.clone(), security_config, pin_config.clone(), + uv_config, ); let authenticator = if let Some(ps) = pin_storage { @@ -1043,6 +1125,7 @@ impl< pin_storage: Option>>, security_config: SecurityConfig, pin_config: PinConfig, + uv_config: UvConfig, interaction_manager: Option>, key_provider: K, ) -> Result, K>> { @@ -1110,6 +1193,7 @@ impl< pin_storage.clone(), security_config, pin_config.clone(), + uv_config, mgr.clone(), is_agent, ), @@ -1118,6 +1202,7 @@ impl< pin_storage.clone(), security_config, pin_config.clone(), + uv_config, ), }; @@ -1147,6 +1232,7 @@ impl< key_provider: K, security_config: SecurityConfig, pin_config: PinConfig, + uv_config: UvConfig, ) -> Result { let storage = Arc::new(Mutex::new(storage)); Self::with_shared_storage_and_key_provider( @@ -1155,6 +1241,7 @@ impl< key_provider, security_config, pin_config, + uv_config, ) } @@ -1166,12 +1253,14 @@ impl< key_provider: K, security_config: SecurityConfig, pin_config: PinConfig, + uv_config: UvConfig, ) -> Result { let authenticator = Self::build_authenticator_with_key_provider( storage.clone(), pin_storage.clone(), security_config.clone(), pin_config.clone(), + uv_config, key_provider, )?; @@ -1196,6 +1285,7 @@ impl< key_provider: K, security_config: SecurityConfig, pin_config: PinConfig, + uv_config: UvConfig, interaction_manager: Arc, ) -> Result { let authenticator = Self::build_authenticator_with_interaction_and_key_provider( @@ -1203,6 +1293,7 @@ impl< pin_storage.clone(), security_config.clone(), pin_config.clone(), + uv_config, Some(interaction_manager), key_provider, )?; @@ -1772,6 +1863,7 @@ mod tests { Some(pin_storage.clone()), security_config, pin_config, + UvConfig::default(), ) .expect("create authenticator service"); @@ -1858,11 +1950,83 @@ mod tests { }; let pin_config = PinConfig::default(); + let uv_config = UvConfig::default(); - let service = AuthenticatorService::new(storage, security_config, pin_config); + let service = AuthenticatorService::new(storage, security_config, pin_config, uv_config); assert!(service.is_ok(), "Service creation should succeed"); - // Cleanup + let _ = std::fs::remove_dir_all(temp_dir); + } + + #[test] + fn test_service_with_custom_uv_config() { + let temp_dir = std::env::temp_dir().join("test_passless_uv"); + if let Err(e) = std::fs::create_dir_all(&temp_dir) { + panic!("Failed to create temp directory: {}", e); + } + let storage = match LocalStorageAdapter::new(temp_dir.clone()) { + Ok(s) => s, + Err(e) => panic!("Failed to create local storage: {}", e), + }; + + let security_config = SecurityConfig { + check_mlock: false, + disable_core_dumps: false, + constant_signature_counter: false, + always_uv: false, + user_verification_registration: false, + user_verification_authentication: false, + notification_timeout: 30, + enable_credential_backup: false, + }; + + let pin_config = PinConfig::default(); + let uv_config = UvConfig { + provider: passless_core::config::UvProviderType::Notification, + timeout_seconds: 60, + ..Default::default() + }; + + let service = AuthenticatorService::new(storage, security_config, pin_config, uv_config); + assert!( + service.is_ok(), + "Service creation with custom UV config should succeed" + ); + + let _ = std::fs::remove_dir_all(temp_dir); + } + + #[test] + fn test_service_with_uv_disabled() { + let temp_dir = std::env::temp_dir().join("test_passless_no_uv"); + if let Err(e) = std::fs::create_dir_all(&temp_dir) { + panic!("Failed to create temp directory: {}", e); + } + let storage = match LocalStorageAdapter::new(temp_dir.clone()) { + Ok(s) => s, + Err(e) => panic!("Failed to create local storage: {}", e), + }; + + let security_config = SecurityConfig { + check_mlock: false, + disable_core_dumps: false, + constant_signature_counter: false, + always_uv: false, + user_verification_registration: false, + user_verification_authentication: false, + notification_timeout: 30, + enable_credential_backup: false, + }; + + let pin_config = PinConfig::default(); + let uv_config = UvConfig::default(); + + let service = AuthenticatorService::new(storage, security_config, pin_config, uv_config); + assert!( + service.is_ok(), + "Service creation with UV disabled should succeed" + ); + let _ = std::fs::remove_dir_all(temp_dir); } @@ -1879,6 +2043,7 @@ mod tests { None::>>, SecurityConfig::default(), PinConfig::default(), + UvConfig::default(), ) .expect("Service creation should succeed"); diff --git a/cmd/passless/src/commands/client.rs b/cmd/passless/src/commands/client.rs index d8ca5aa0..c77cf69b 100644 --- a/cmd/passless/src/commands/client.rs +++ b/cmd/passless/src/commands/client.rs @@ -378,6 +378,7 @@ fn format_uv_blocked_message(error: &soft_fido2::Error) -> String { ) } + /// Fallback to PIN authentication when UV fails fn fallback_to_pin_auth( transport: &mut Transport, @@ -896,7 +897,7 @@ pub fn show(output: OutputFormat, device: Option<&str>, credential_id_hex: &str) let mut transport = open_authenticator(device)?; - let pin_uv_auth = authenticate_for_credential_management_opt(&mut transport, output); +let pin_uv_auth = authenticate_for_credential_management_opt(&mut transport, output); // Decode credential ID let credential_id = hex::decode(credential_id_hex) @@ -1046,7 +1047,7 @@ pub fn delete(output: OutputFormat, device: Option<&str>, credential_id_hex: &st println!("Deleting credential: {}\n", credential_id_hex); } - let mut transport = open_authenticator(device)?; +let mut transport = open_authenticator(device)?; let pin_uv_auth = authenticate_for_credential_management_opt(&mut transport, output); @@ -1102,7 +1103,7 @@ pub fn rename( println!("Renaming credential: {}\n", credential_id_hex); } - let mut transport = open_authenticator(device)?; +let mut transport = open_authenticator(device)?; let pin_uv_auth = authenticate_for_credential_management_opt(&mut transport, output); diff --git a/cmd/passless/src/commands/custom.rs b/cmd/passless/src/commands/custom.rs index 52a52d84..5fa4cc06 100644 --- a/cmd/passless/src/commands/custom.rs +++ b/cmd/passless/src/commands/custom.rs @@ -2,8 +2,6 @@ /// /// This module provides compatibility with the Yubikey credential management variant (0x41). /// The standard credential management (0x0a) is handled by soft-fido2's built-in implementation, -/// which properly calls the AuthenticatorCallbacks methods (enumerate_rps, list_credentials, etc.) -/// that read from the actual storage backend. use crate::authenticator::AuthenticatorService; use crate::pin_storage::PinStorage; use crate::storage::CredentialStorage; @@ -56,7 +54,7 @@ mod tests { #[test] fn test_register_yubikey_command() { - use passless_core::config::{PinConfig, SecurityConfig}; + use passless_core::config::{PinConfig, SecurityConfig, UvConfig}; let temp_dir = std::env::temp_dir().join("test_passless_custom"); if let Err(e) = std::fs::create_dir_all(&temp_dir) { @@ -67,8 +65,12 @@ mod tests { Err(e) => panic!("Failed to create local storage: {}", e), }; - let service = - AuthenticatorService::new(storage, SecurityConfig::default(), PinConfig::default()); + let service = AuthenticatorService::new( + storage, + SecurityConfig::default(), + PinConfig::default(), + UvConfig::default(), + ); assert!(service.is_ok(), "Service creation should succeed"); register_yubikey_credential_mgmt(&mut service.unwrap()); diff --git a/cmd/passless/src/main.rs b/cmd/passless/src/main.rs index 389ea599..ccdcbf01 100644 --- a/cmd/passless/src/main.rs +++ b/cmd/passless/src/main.rs @@ -9,6 +9,7 @@ mod notification; mod pin_storage; mod storage; mod util; +mod uv; mod worker; use passless_core::{ @@ -193,6 +194,7 @@ fn spawn_agent_runtime( agent_config: passless_core::agent::AgentConfig, security_config: passless_core::config::SecurityConfig, pin_config: passless_core::config::PinConfig, + uv_config: passless_core::config::UvConfig, shutdown: Arc, ) -> Option> { let shutdown_for_runtime = shutdown.clone(); @@ -207,6 +209,7 @@ fn spawn_agent_runtime( &agent_config, security_config, pin_config, + uv_config, shutdown_for_runtime.clone(), ) { Ok(runtime) => { @@ -444,6 +447,12 @@ fn run() -> Result<()> { return Err(e); } + // Validate configuration + if let Err(e) = config.validate() { + error!("Configuration validation failed: {}", e); + process::exit(1); + } + if config.verbose && log_level != log::LevelFilter::Debug { info!("Enabling verbose logging..."); log::set_max_level(log::LevelFilter::Debug); @@ -554,6 +563,7 @@ fn run() -> Result<()> { let security_config = config.security_config(); let pin_config = config.pin_config(); + let uv_config = config.uv_config(); let operation_lock = Arc::new(Mutex::new(())); let allow_storage_creation = allow_e2e_storage_creation(); @@ -574,6 +584,7 @@ fn run() -> Result<()> { Some(pin_storage.clone()), security_config.clone(), pin_config.clone(), + uv_config.clone(), )?; let agent_runtime = spawn_agent_runtime( @@ -584,6 +595,7 @@ fn run() -> Result<()> { config.agents.clone(), security_config, pin_config, + uv_config, shutdown.clone(), ); @@ -624,6 +636,7 @@ fn run() -> Result<()> { Some(pin_storage.clone()), security_config.clone(), pin_config.clone(), + uv_config.clone(), )?; let agent_runtime = spawn_agent_runtime( @@ -634,6 +647,7 @@ fn run() -> Result<()> { config.agents.clone(), security_config, pin_config, + uv_config, shutdown.clone(), ); @@ -672,6 +686,7 @@ fn run() -> Result<()> { provider, security_config.clone(), pin_config.clone(), + uv_config.clone(), )?; let agent_runtime = spawn_agent_runtime( @@ -682,6 +697,7 @@ fn run() -> Result<()> { config.agents.clone(), security_config, pin_config, + uv_config, shutdown.clone(), ); @@ -707,6 +723,7 @@ fn run() -> Result<()> { Some(pin_storage.clone()), security_config.clone(), pin_config.clone(), + uv_config.clone(), )?; let agent_runtime = spawn_agent_runtime( @@ -717,6 +734,7 @@ fn run() -> Result<()> { config.agents.clone(), security_config, pin_config, + uv_config, shutdown.clone(), ); @@ -791,6 +809,9 @@ fn run() -> Result<()> { let pin_config = config.pin_config(); let allow_storage_creation = allow_e2e_storage_creation(); + // Get UV config for biometric verification + let uv_config = config.uv_config(); + match backend { BackendConfig::Local { path } => { let storage = LocalStorageAdapter::new_with_options( @@ -804,6 +825,7 @@ fn run() -> Result<()> { Some(pin_storage), security_config, pin_config, + uv_config, )?; run_with_service(service, uhid, shutdown) } @@ -834,6 +856,7 @@ fn run() -> Result<()> { Some(pin_storage), security_config, pin_config, + uv_config, )?; run_with_service(service, uhid, shutdown) } @@ -858,6 +881,7 @@ fn run() -> Result<()> { provider, security_config, pin_config, + uv_config, )?; run_with_service(service, uhid, shutdown) } else { @@ -873,6 +897,7 @@ fn run() -> Result<()> { Some(pin_storage), security_config, pin_config, + uv_config, )?; run_with_service(service, uhid, shutdown) } diff --git a/cmd/passless/src/pin_storage/tpm.rs b/cmd/passless/src/pin_storage/tpm.rs index cd7713f1..c59683c7 100644 --- a/cmd/passless/src/pin_storage/tpm.rs +++ b/cmd/passless/src/pin_storage/tpm.rs @@ -77,7 +77,6 @@ impl PinStorage for TpmPinStorage { "Loading PIN state from TPM storage: {}", self.path.display() ); - let sealed_data = std::fs::read(&self.path).map_err(|e| { warn!("Failed to read sealed PIN state: {}", e); StatusCode::Other diff --git a/cmd/passless/src/uv/command.rs b/cmd/passless/src/uv/command.rs new file mode 100644 index 00000000..9f82f895 --- /dev/null +++ b/cmd/passless/src/uv/command.rs @@ -0,0 +1,273 @@ +//! Command-based User Verification Provider +//! +//! Executes a user-defined command/script for verification. +//! +//! # Configuration +//! +//! The command should: +//! - Exit with code 0 for accepted +//! - Exit with non-zero code for denied +//! - Receive operation context via environment variables +//! +//! # Environment Variables +//! +//! - `PASSLESS_UV_OPERATION`: Operation type (registration/authentication) +//! - `PASSLESS_UV_RELYING_PARTY`: Relying party ID (if available) +//! - `PASSLESS_UV_USER`: User identifier (if available) +//! - `PASSLESS_UV_TIMEOUT`: Timeout in seconds + +use super::{ + UserVerificationProvider, VerificationContext, VerificationError, VerificationResult, priority, +}; + +use log::{debug, info}; + +use std::process::Command; + +/// Command-based user verification provider +pub struct CommandProvider { + command: Vec, + #[allow(dead_code)] + timeout_seconds: u32, +} + +impl CommandProvider { + /// Create a new command provider + /// + /// # Arguments + /// + /// * `command` - Command and arguments to execute + /// * `timeout_seconds` - Timeout for the command + pub fn new(command: Vec, timeout_seconds: u32) -> Self { + Self { + command, + timeout_seconds, + } + } + + /// Create a provider if enabled and configured + pub fn from_config( + enabled: bool, + command: Vec, + timeout_seconds: u32, + ) -> Option> { + if enabled && !command.is_empty() { + Some(Box::new(Self::new(command, timeout_seconds))) + } else { + None + } + } + + /// Execute the verification command + fn execute( + &self, + context: &VerificationContext, + ) -> Result { + if self.command.is_empty() { + return Err(VerificationError::NotAvailable( + "No command configured".into(), + )); + } + + let program = &self.command[0]; + let args = &self.command[1..]; + + debug!("Executing UV command: {} {:?}", program, args); + + let mut cmd = Command::new(program); + cmd.args(args); + + cmd.env("PASSLESS_UV_OPERATION", &context.operation); + + if let Some(ref rp) = context.relying_party { + cmd.env("PASSLESS_UV_RELYING_PARTY", rp); + } + + if let Some(ref user) = context.user { + cmd.env("PASSLESS_UV_USER", user); + } + + cmd.env("PASSLESS_UV_TIMEOUT", context.timeout_seconds.to_string()); + + let result = cmd.output().map_err(|e| { + if e.kind() == std::io::ErrorKind::NotFound { + VerificationError::NotAvailable(format!("Command not found: {}", program)) + } else { + VerificationError::DeviceError(format!("Failed to execute command: {}", e)) + } + })?; + + debug!( + "Command exit code: {}, stdout: {}, stderr: {}", + result.status.code().unwrap_or(-1), + String::from_utf8_lossy(&result.stdout).trim(), + String::from_utf8_lossy(&result.stderr).trim() + ); + + if result.status.success() { + info!("User verification accepted via command"); + Ok(VerificationResult::Accepted) + } else { + info!( + "User verification denied via command (exit code: {:?})", + result.status.code() + ); + Ok(VerificationResult::Denied) + } + } +} + +impl UserVerificationProvider for CommandProvider { + fn name(&self) -> &str { + "command" + } + + fn available(&self) -> bool { + if self.command.is_empty() { + return false; + } + + let program = &self.command[0]; + + if program.contains('/') { + std::path::Path::new(program).exists() + } else { + which::which(program).is_ok() + } + } + + fn verify( + &self, + context: &VerificationContext, + ) -> Result { + self.execute(context) + } + + fn priority(&self) -> u8 { + priority::COMMAND + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_command_provider_name() { + let provider = CommandProvider::new(vec!["echo".to_string()], 30); + assert_eq!(provider.name(), "command"); + } + + #[test] + fn test_command_provider_priority() { + let provider = CommandProvider::new(vec!["echo".to_string()], 30); + assert_eq!(provider.priority(), priority::COMMAND); + } + + #[test] + fn test_command_provider_empty_unavailable() { + let provider = CommandProvider::new(vec![], 30); + assert!(!provider.available()); + } + + #[test] + fn test_command_provider_empty_verify_fails() { + let provider = CommandProvider::new(vec![], 30); + let ctx = VerificationContext::new("test"); + let result = provider.verify(&ctx); + assert!(result.is_err()); + match result.unwrap_err() { + VerificationError::NotAvailable(_) => {} + _ => panic!("Expected NotAvailable error"), + } + } + + #[test] + fn test_command_provider_echo() { + let provider = CommandProvider::new(vec!["echo".to_string(), "accepted".to_string()], 30); + assert!(provider.available()); + + let ctx = VerificationContext::new("test"); + let result = provider.verify(&ctx); + assert_eq!(result.unwrap(), VerificationResult::Accepted); + } + + #[test] + fn test_command_provider_false() { + let provider = CommandProvider::new(vec!["false".to_string()], 30); + + if !provider.available() { + return; + } + + let ctx = VerificationContext::new("test"); + let result = provider.verify(&ctx); + assert_eq!(result.unwrap(), VerificationResult::Denied); + } + + #[test] + fn test_command_provider_exit_1_denied() { + let provider = CommandProvider::new( + vec!["sh".to_string(), "-c".to_string(), "exit 1".to_string()], + 30, + ); + + if !provider.available() { + return; + } + + let ctx = VerificationContext::new("test"); + let result = provider.verify(&ctx); + assert_eq!(result.unwrap(), VerificationResult::Denied); + } + + #[test] + fn test_command_provider_nonexistent() { + let provider = CommandProvider::new(vec!["nonexistent_command_12345".to_string()], 30); + assert!(!provider.available()); + + let ctx = VerificationContext::new("test"); + let result = provider.verify(&ctx); + assert!(result.is_err()); + match result.unwrap_err() { + VerificationError::NotAvailable(_) => {} + _ => panic!("Expected NotAvailable error"), + } + } + + #[test] + fn test_command_provider_with_context() { + let provider = CommandProvider::new( + vec![ + "sh".to_string(), + "-c".to_string(), + "test \"$PASSLESS_UV_OPERATION\" = 'registration' && test -n \"$PASSLESS_UV_RELYING_PARTY\"".to_string(), + ], + 30, + ); + + if !provider.available() { + return; + } + + let ctx = VerificationContext::new("registration") + .with_relying_party("example.com") + .with_user("alice") + .with_timeout(60); + + let result = provider.verify(&ctx); + assert_eq!(result.unwrap(), VerificationResult::Accepted); + } + + #[test] + fn test_command_provider_absolute_path() { + let provider = CommandProvider::new(vec!["/bin/true".to_string()], 30); + + if std::path::Path::new("/bin/true").exists() { + assert!(provider.available()); + let ctx = VerificationContext::new("test"); + let result = provider.verify(&ctx); + assert_eq!(result.unwrap(), VerificationResult::Accepted); + } + } +} diff --git a/cmd/passless/src/uv/face.rs b/cmd/passless/src/uv/face.rs new file mode 100644 index 00000000..74198664 --- /dev/null +++ b/cmd/passless/src/uv/face.rs @@ -0,0 +1,462 @@ +//! Face Recognition-based User Verification Provider +//! +//! Uses webcam and face recognition for user verification. +//! +//! # Requirements +//! +//! - Webcam device (V4L2 on Linux) +//! - face_id crate for detection and recognition +//! - ONNX Runtime (downloaded automatically) +//! +//! # Enrollment +//! +//! During enrollment, multiple face embeddings are captured and averaged +//! to create a robust template. The template is stored securely. + +use super::{ + UserVerificationProvider, VerificationContext, VerificationError, VerificationResult, priority, +}; + +use log::{debug, info, warn}; + +use std::path::PathBuf; +use std::sync::{Arc, Mutex}; + +use image::DynamicImage; +use nokhwa::Camera; +use nokhwa::pixel_format::RgbFormat; +use nokhwa::utils::{CameraIndex, RequestedFormat, RequestedFormatType}; + +#[allow(dead_code)] +const DEFAULT_THRESHOLD: f32 = 0.6; +#[allow(dead_code)] +const ENROLLMENT_SAMPLES: usize = 5; + +/// Face recognition provider using webcam +pub struct FaceIdProvider { + camera_index: usize, + threshold: f32, + embeddings_path: PathBuf, + enrolled: Arc>>, + analyzer: Arc>>, +} + +impl FaceIdProvider { + /// Create a new face recognition provider + pub fn new(camera_index: usize, threshold: f32, embeddings_path: Option) -> Self { + let embeddings_path = embeddings_path.unwrap_or_else(|| { + dirs::data_local_dir() + .unwrap_or_else(|| PathBuf::from(".")) + .join("passless") + .join("face_embeddings") + }); + + Self { + camera_index, + threshold, + embeddings_path, + enrolled: Arc::new(Mutex::new(None)), + analyzer: Arc::new(Mutex::new(None)), + } + } + + /// Create a provider if enabled in config + pub fn from_config( + enabled: bool, + camera_index: usize, + threshold: f32, + ) -> Option> { + if enabled { + Some(Box::new(Self::new(camera_index, threshold, None))) + } else { + None + } + } + + /// Get path to the stored embeddings file + fn embeddings_file(&self) -> PathBuf { + self.embeddings_path.join("face_template.bin") + } + + /// Check if a camera is available + fn check_camera_available(&self) -> bool { + let index = CameraIndex::Index(self.camera_index as u32); + let format = + RequestedFormat::new::(RequestedFormatType::AbsoluteHighestFrameRate); + + Camera::new(index, format).is_ok() + } + + /// Initialize the face analyzer (downloads models if needed) + fn init_analyzer(&self) -> Result<(), VerificationError> { + let mut analyzer_guard = self.analyzer.lock().unwrap(); + + if analyzer_guard.is_some() { + return Ok(()); + } + + debug!("Initializing face analyzer (downloading models if needed)..."); + + let rt = tokio::runtime::Runtime::new().map_err(|e| { + VerificationError::DeviceError(format!("Failed to create runtime: {}", e)) + })?; + + let analyzer = rt.block_on(async { + face_id::analyzer::FaceAnalyzer::from_hf() + .build() + .await + .map_err(|e| { + VerificationError::DeviceError(format!( + "Failed to initialize face analyzer: {}", + e + )) + }) + })?; + + *analyzer_guard = Some(analyzer); + info!("Face analyzer initialized successfully"); + Ok(()) + } + + /// Capture a single frame from the camera + fn capture_frame(&self) -> Result { + debug!("Capturing frame from camera {}", self.camera_index); + + let index = CameraIndex::Index(self.camera_index as u32); + let format = + RequestedFormat::new::(RequestedFormatType::AbsoluteHighestFrameRate); + + let mut camera = Camera::new(index, format) + .map_err(|e| VerificationError::DeviceError(format!("Failed to open camera: {}", e)))?; + + camera.open_stream().map_err(|e| { + VerificationError::DeviceError(format!("Failed to start camera stream: {}", e)) + })?; + + let buffer = camera.frame().map_err(|e| { + VerificationError::DeviceError(format!("Failed to capture frame: {}", e)) + })?; + + let decoded = buffer.decode_image::().map_err(|e| { + VerificationError::DeviceError(format!("Failed to decode frame: {}", e)) + })?; + + camera + .stop_stream() + .map_err(|e| warn!("Failed to stop camera stream: {}", e)) + .ok(); + + Ok(DynamicImage::ImageRgb8(decoded)) + } + + /// Extract face embedding from an image + fn extract_embedding(&self, image: &DynamicImage) -> Result, VerificationError> { + self.init_analyzer()?; + + let analyzer_guard = self.analyzer.lock().unwrap(); + let analyzer = analyzer_guard.as_ref().unwrap(); + + debug!("Analyzing image for face"); + + let results = analyzer + .analyze(image) + .map_err(|e| VerificationError::DeviceError(format!("Face analysis failed: {}", e)))?; + + if results.is_empty() { + return Err(VerificationError::DeviceError("No face detected".into())); + } + + if results.len() > 1 { + warn!("Multiple faces detected, using the first one"); + } + + let face = &results[0]; + debug!( + "Extracted embedding with {} dimensions", + face.embedding.len() + ); + Ok(face.embedding.clone()) + } + + /// Load stored embeddings template + fn load_template(&self) -> Result, VerificationError> { + let path = self.embeddings_file(); + if !path.exists() { + return Err(VerificationError::NotEnrolled); + } + + let data = std::fs::read(&path).map_err(|e| { + VerificationError::DeviceError(format!("Failed to read template: {}", e)) + })?; + + let embedding_len = u64::from_le_bytes( + data.get(0..8) + .ok_or_else(|| VerificationError::DeviceError("Invalid template format".into()))? + .try_into() + .unwrap(), + ) as usize; + + let embedding: Vec = data[8..] + .chunks_exact(4) + .map(|chunk| f32::from_le_bytes(chunk.try_into().unwrap())) + .collect(); + + if embedding.len() != embedding_len { + return Err(VerificationError::DeviceError( + "Template length mismatch".into(), + )); + } + + Ok(embedding) + } + + /// Save embeddings template + #[allow(dead_code)] + fn save_template(&self, embedding: &[f32]) -> Result<(), VerificationError> { + std::fs::create_dir_all(&self.embeddings_path).map_err(|e| { + VerificationError::DeviceError(format!("Failed to create embeddings directory: {}", e)) + })?; + + let path = self.embeddings_file(); + + let mut data = Vec::with_capacity(8 + embedding.len() * 4); + data.extend_from_slice(&(embedding.len() as u64).to_le_bytes()); + for &val in embedding { + data.extend_from_slice(&val.to_le_bytes()); + } + + std::fs::write(&path, &data).map_err(|e| { + VerificationError::DeviceError(format!("Failed to write template: {}", e)) + })?; + + info!("Saved face template to {}", path.display()); + Ok(()) + } + + /// Calculate cosine similarity between two embeddings + fn cosine_similarity(a: &[f32], b: &[f32]) -> f32 { + if a.len() != b.len() { + return 0.0; + } + + let dot_product: f32 = a.iter().zip(b.iter()).map(|(x, y)| x * y).sum(); + let mag_a: f32 = a.iter().map(|x| x * x).sum::().sqrt(); + let mag_b: f32 = b.iter().map(|x| x * x).sum::().sqrt(); + + if mag_a == 0.0 || mag_b == 0.0 { + return 0.0; + } + + dot_product / (mag_a * mag_b) + } + + /// Perform face verification + fn do_verification(&self) -> Result { + let template = self.load_template()?; + + let frame = self.capture_frame()?; + let embedding = self.extract_embedding(&frame)?; + + let similarity = Self::cosine_similarity(&template, &embedding); + debug!("Face similarity score: {}", similarity); + + if similarity >= self.threshold { + info!("Face matched (similarity: {})", similarity); + Ok(VerificationResult::Accepted) + } else { + info!( + "Face not matched (similarity: {} < {})", + similarity, self.threshold + ); + Ok(VerificationResult::Denied) + } + } +} + +impl UserVerificationProvider for FaceIdProvider { + fn name(&self) -> &str { + "face" + } + + fn available(&self) -> bool { + self.check_camera_available() + } + + fn verify( + &self, + _context: &VerificationContext, + ) -> Result { + self.do_verification() + } + + fn priority(&self) -> u8 { + priority::FACE + } + + fn supports_enrollment(&self) -> bool { + true + } + + fn requires_enrollment(&self) -> bool { + true + } + + fn is_enrolled(&self) -> bool { + if let Some(enrolled) = *self.enrolled.lock().unwrap() { + return enrolled; + } + + let enrolled = self.embeddings_file().exists(); + *self.enrolled.lock().unwrap() = Some(enrolled); + enrolled + } + + fn enroll(&self) -> Result<(), VerificationError> { + info!( + "Starting face enrollment (capturing {} samples)", + ENROLLMENT_SAMPLES + ); + + self.init_analyzer()?; + + let mut embeddings: Vec> = Vec::with_capacity(ENROLLMENT_SAMPLES); + + for i in 0..ENROLLMENT_SAMPLES { + debug!( + "Capturing enrollment sample {}/{}", + i + 1, + ENROLLMENT_SAMPLES + ); + + let frame = self.capture_frame()?; + let embedding = self.extract_embedding(&frame)?; + embeddings.push(embedding); + + if i < ENROLLMENT_SAMPLES - 1 { + std::thread::sleep(std::time::Duration::from_millis(500)); + } + } + + let avg_embedding: Vec = { + let len = embeddings[0].len(); + let mut sum = vec![0.0f32; len]; + + for embedding in &embeddings { + for (i, &val) in embedding.iter().enumerate() { + sum[i] += val; + } + } + + let n = embeddings.len() as f32; + sum.into_iter().map(|x| x / n).collect() + }; + + self.save_template(&avg_embedding)?; + + *self.enrolled.lock().unwrap() = Some(true); + + info!("Face enrollment completed successfully"); + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_face_provider_name() { + let provider = FaceIdProvider::new(0, DEFAULT_THRESHOLD, None); + assert_eq!(provider.name(), "face"); + } + + #[test] + fn test_face_provider_priority() { + let provider = FaceIdProvider::new(0, DEFAULT_THRESHOLD, None); + assert_eq!(provider.priority(), priority::FACE); + } + + #[test] + fn test_face_provider_supports_enrollment() { + let provider = FaceIdProvider::new(0, DEFAULT_THRESHOLD, None); + assert!(provider.supports_enrollment()); + } + + #[test] + fn test_face_provider_requires_enrollment() { + let provider = FaceIdProvider::new(0, DEFAULT_THRESHOLD, None); + assert!(provider.requires_enrollment()); + } + + #[test] + fn test_face_provider_not_enrolled_initially() { + let temp_dir = tempfile::tempdir().unwrap(); + let provider = FaceIdProvider::new( + 0, + DEFAULT_THRESHOLD, + Some(temp_dir.path().join("face_embeddings")), + ); + assert!(!provider.is_enrolled()); + } + + #[test] + fn test_cosine_similarity_identical() { + let a = vec![1.0, 0.0, 0.0]; + let b = vec![1.0, 0.0, 0.0]; + let sim = FaceIdProvider::cosine_similarity(&a, &b); + assert!((sim - 1.0).abs() < 0.001); + } + + #[test] + fn test_cosine_similarity_orthogonal() { + let a = vec![1.0, 0.0, 0.0]; + let b = vec![0.0, 1.0, 0.0]; + let sim = FaceIdProvider::cosine_similarity(&a, &b); + assert!(sim.abs() < 0.001); + } + + #[test] + fn test_cosine_similarity_opposite() { + let a = vec![1.0, 0.0, 0.0]; + let b = vec![-1.0, 0.0, 0.0]; + let sim = FaceIdProvider::cosine_similarity(&a, &b); + assert!((sim - (-1.0)).abs() < 0.001); + } + + #[test] + fn test_cosine_similarity_partial() { + let a = vec![1.0, 0.0, 0.0]; + let b = vec![1.0, 1.0, 0.0]; + let sim = FaceIdProvider::cosine_similarity(&a, &b); + let expected = std::f32::consts::FRAC_1_SQRT_2; + assert!((sim - expected).abs() < 0.01); + } + + #[test] + fn test_cosine_similarity_different_lengths() { + let a = vec![1.0, 0.0, 0.0]; + let b = vec![1.0, 0.0]; + let sim = FaceIdProvider::cosine_similarity(&a, &b); + assert_eq!(sim, 0.0); + } + + #[test] + fn test_cosine_similarity_zero_vectors() { + let a = vec![0.0, 0.0, 0.0]; + let b = vec![1.0, 0.0, 0.0]; + let sim = FaceIdProvider::cosine_similarity(&a, &b); + assert_eq!(sim, 0.0); + } + + #[test] + fn test_cosine_similarity_high_dim() { + let a: Vec = (0..512) + .map(|i| if i % 2 == 0 { 1.0 } else { 0.0 }) + .collect(); + let b: Vec = (0..512) + .map(|i| if i % 2 == 0 { 1.0 } else { 0.5 }) + .collect(); + let sim = FaceIdProvider::cosine_similarity(&a, &b); + assert!(sim > 0.8 && sim < 1.0); + } +} diff --git a/cmd/passless/src/uv/fprintd.rs b/cmd/passless/src/uv/fprintd.rs new file mode 100644 index 00000000..d374ff63 --- /dev/null +++ b/cmd/passless/src/uv/fprintd.rs @@ -0,0 +1,333 @@ +//! fprintd-based User Verification Provider +//! +//! Uses the fprintd D-Bus service for fingerprint verification. +//! +//! # Requirements +//! +//! - fprintd service must be running +//! - A fingerprint reader must be connected +//! - User must have enrolled fingerprints + +use super::{ + UserVerificationProvider, VerificationContext, VerificationError, VerificationResult, priority, +}; + +use log::{debug, error, info, warn}; + +use std::sync::Arc; +use std::sync::Mutex; + +/// fprintd-based fingerprint verification provider +pub struct FprintdProvider { + available_cache: Mutex>, + runtime: Mutex>>, +} + +impl FprintdProvider { + /// Create a new fprintd provider + pub fn new() -> Self { + Self { + available_cache: Mutex::new(None), + runtime: Mutex::new(None), + } + } + + /// Create a provider if enabled in config + pub fn from_config(enabled: bool) -> Option> { + if enabled { + Some(Box::new(Self::new())) + } else { + None + } + } + + /// Get or create the tokio runtime + fn get_runtime(&self) -> Result, VerificationError> { + let mut runtime_guard = self.runtime.lock().unwrap(); + if runtime_guard.is_none() { + *runtime_guard = Some(Arc::new(tokio::runtime::Runtime::new().map_err(|e| { + VerificationError::DeviceError(format!("Failed to create runtime: {}", e)) + })?)); + } + Ok(runtime_guard.as_ref().unwrap().clone()) + } + + async fn do_verify(timeout_secs: u32) -> Result { + use zbus::Connection; + + debug!("Starting fprintd verification"); + + let conn = Connection::system().await.map_err(|e| { + VerificationError::DeviceError(format!("D-Bus connection failed: {}", e)) + })?; + + let device_path: zbus::OwnedObjectPath = conn + .call_method( + Some("net.reactivated.Fprint"), + "/net/reactivated/Fprint/Manager", + Some("net.reactivated.Fprint.Manager"), + "GetDefaultDevice", + &(), + ) + .await + .map_err(|e| VerificationError::NotAvailable(format!("No fingerprint device: {}", e)))? + .body() + .deserialize() + .map_err(|e| VerificationError::DeviceError(format!("Invalid response: {}", e)))?; + + debug!("Found device at path: {:?}", device_path); + + conn.call_method( + Some("net.reactivated.Fprint"), + device_path.as_str(), + Some("net.reactivated.Fprint.Device"), + "Claim", + &"", + ) + .await + .map_err(|e| VerificationError::DeviceError(format!("Failed to claim device: {}", e)))?; + + let result = Self::wait_for_verification(&conn, &device_path, timeout_secs).await; + + let _ = conn + .call_method( + Some("net.reactivated.Fprint"), + device_path.as_str(), + Some("net.reactivated.Fprint.Device"), + "Release", + &(), + ) + .await; + + result + } + + async fn wait_for_verification( + conn: &zbus::Connection, + device_path: &zbus::OwnedObjectPath, + timeout_secs: u32, + ) -> Result { + use futures_util::StreamExt; + use zbus::MessageStream; + + conn.call_method( + Some("net.reactivated.Fprint"), + device_path.as_str(), + Some("net.reactivated.Fprint.Device"), + "VerifyStart", + &"any", + ) + .await + .map_err(|e| { + VerificationError::DeviceError(format!("Failed to start verification: {}", e)) + })?; + + let mut stream = MessageStream::from(conn); + + let timeout = tokio::time::sleep(std::time::Duration::from_secs(timeout_secs as u64)); + tokio::pin!(timeout); + + let mut result = VerificationResult::Timeout; + + loop { + tokio::select! { + _ = &mut timeout => { + warn!("Fingerprint verification timed out"); + break; + } + msg = stream.next() => { + match msg { + Some(Ok(msg)) => { + let header = msg.header(); + + if header.interface().map(|i| i.as_str()) != Some("net.reactivated.Fprint.Device") { + continue; + } + if header.member().map(|m| m.as_str()) != Some("VerifyStatus") { + continue; + } + if header.path().map(|p| p.as_str()) != Some(device_path.as_str()) { + continue; + } + + match msg.body().deserialize::<(&str, bool)>() { + Ok((status, _done)) => { + debug!("fprintd status: {}", status); + + match status { + "verify-match" => { + info!("Fingerprint matched"); + result = VerificationResult::Accepted; + break; + } + "verify-no-match" => { + info!("Fingerprint not matched"); + result = VerificationResult::Denied; + break; + } + "verify-retry-scan" + | "verify-swipe-too-short" + | "verify-finger-not-entered" + | "verify-remove-and-retry" => { + debug!("Retry requested: {}", status); + continue; + } + "verify-disconnected" => { + error!("Device disconnected"); + result = VerificationResult::Denied; + break; + } + "verify-unknown-error" => { + error!("Unknown error"); + result = VerificationResult::Denied; + break; + } + _ => { + warn!("Unknown status: {}", status); + continue; + } + } + } + Err(e) => { + error!("Failed to parse signal: {}", e); + continue; + } + } + } + Some(Err(e)) => { + error!("Error receiving message: {}", e); + continue; + } + None => { + error!("Signal stream closed"); + break; + } + } + } + } + } + + let _ = conn + .call_method( + Some("net.reactivated.Fprint"), + device_path.as_str(), + Some("net.reactivated.Fprint.Device"), + "VerifyStop", + &(), + ) + .await; + + Ok(result) + } + + fn check_available(&self) -> bool { + let rt = match self.get_runtime() { + Ok(rt) => rt, + Err(_) => return false, + }; + + rt.block_on(async { + use zbus::Connection; + + match Connection::system().await { + Ok(conn) => { + match conn + .call_method( + Some("net.reactivated.Fprint"), + "/net/reactivated/Fprint/Manager", + Some("net.reactivated.Fprint.Manager"), + "GetDefaultDevice", + &(), + ) + .await + { + Ok(reply) => { + if let Ok(path) = reply + .body() + .deserialize::() + { + info!("fprintd device available at: {:?}", path); + true + } else { + false + } + } + Err(_) => false, + } + } + Err(_) => false, + } + }) + } +} + +impl Default for FprintdProvider { + fn default() -> Self { + Self::new() + } +} + +impl UserVerificationProvider for FprintdProvider { + fn name(&self) -> &str { + "fprintd" + } + + fn available(&self) -> bool { + if let Some(cached) = *self.available_cache.lock().unwrap() { + return cached; + } + + let available = self.check_available(); + *self.available_cache.lock().unwrap() = Some(available); + available + } + + fn verify( + &self, + context: &VerificationContext, + ) -> Result { + let timeout_secs = context.timeout_seconds; + let rt = self.get_runtime()?; + + rt.block_on(async { Self::do_verify(timeout_secs).await }) + } + + fn priority(&self) -> u8 { + priority::FPRINTD + } + + fn supports_enrollment(&self) -> bool { + true + } + + fn requires_enrollment(&self) -> bool { + true + } + + fn is_enrolled(&self) -> bool { + true + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_fprintd_provider_name() { + let provider = FprintdProvider::new(); + assert_eq!(provider.name(), "fprintd"); + } + + #[test] + fn test_fprintd_provider_priority() { + let provider = FprintdProvider::new(); + assert_eq!(provider.priority(), priority::FPRINTD); + } + + #[test] + fn test_fprintd_provider_supports_enrollment() { + let provider = FprintdProvider::new(); + assert!(provider.supports_enrollment()); + } +} diff --git a/cmd/passless/src/uv/manager.rs b/cmd/passless/src/uv/manager.rs new file mode 100644 index 00000000..e1e3b4f8 --- /dev/null +++ b/cmd/passless/src/uv/manager.rs @@ -0,0 +1,319 @@ +//! User Verification Manager +//! +//! Manages a chain of UV providers with automatic fallback. + +use super::{UserVerificationProvider, VerificationContext, VerificationError, VerificationResult}; + +use log::{debug, info, warn}; +use std::cmp::Reverse; + +/// Manages user verification providers with fallback chain +pub struct UserVerificationManager { + providers: Vec>, +} + +impl UserVerificationManager { + /// Create a new manager with the given providers + /// + /// Providers are sorted by priority (highest first) and will be tried in order. + pub fn new(providers: Vec>) -> Self { + let mut providers = providers; + providers.sort_by_key(|p| Reverse(p.priority())); + Self { providers } + } + + /// Create a manager with default providers (empty) + #[allow(dead_code)] + pub fn empty() -> Self { + Self { + providers: Vec::new(), + } + } + + /// Add a provider to the chain + #[allow(dead_code)] + pub fn add_provider(&mut self, provider: Box) { + self.providers.push(provider); + self.providers.sort_by_key(|p| Reverse(p.priority())); + } + + /// Get list of available providers + pub fn available_providers(&self) -> Vec<&dyn UserVerificationProvider> { + self.providers + .iter() + .filter(|p| p.available()) + .map(|p| p.as_ref()) + .collect() + } + + /// Perform user verification with automatic fallback + /// + /// Tries providers in priority order until one succeeds. + /// Falls back to next provider on error or timeout. + /// Returns first non-error result (Accepted, Denied, or Timeout from last provider). + pub fn verify( + &self, + context: &VerificationContext, + ) -> Result { + let available: Vec<_> = self.available_providers(); + + if available.is_empty() { + warn!("No UV providers available"); + return Err(VerificationError::NotAvailable( + "No user verification providers available".into(), + )); + } + + info!( + "Starting user verification with {} available provider(s)", + available.len() + ); + + let mut last_error: Option = None; + + for provider in &available { + debug!( + "Trying UV provider: {} (priority {})", + provider.name(), + provider.priority() + ); + + // Check enrollment + if provider.requires_enrollment() && !provider.is_enrolled() { + debug!("Provider {} not enrolled, skipping", provider.name()); + last_error = Some(VerificationError::NotEnrolled); + continue; + } + + match provider.verify(context) { + Ok(result @ VerificationResult::Accepted) => { + info!("User verification accepted via {}", provider.name()); + return Ok(result); + } + Ok(result @ VerificationResult::Denied) => { + info!("User verification denied via {}", provider.name()); + return Ok(result); + } + Ok(VerificationResult::Timeout) => { + warn!("UV provider {} timed out, trying next", provider.name()); + last_error = Some(VerificationError::Other("Timeout".into())); + continue; + } + Err(e) => { + warn!("UV provider {} failed: {}, trying next", provider.name(), e); + last_error = Some(e); + continue; + } + } + } + + // All providers failed + let error = last_error.unwrap_or_else(|| { + VerificationError::Other("All verification providers failed".into()) + }); + Err(error) + } + + /// Get a provider by name for enrollment + #[allow(dead_code)] + pub fn get_provider(&self, name: &str) -> Option<&dyn UserVerificationProvider> { + self.providers + .iter() + .find(|p| p.name() == name) + .map(|p| p.as_ref()) + } + + /// List all providers (for CLI status command) + #[allow(dead_code)] + pub fn list_providers(&self) -> &[Box] { + &self.providers + } +} + +#[cfg(test)] +mod tests { + use super::*; + + struct MockProvider { + name: &'static str, + priority: u8, + available: bool, + result: VerificationResult, + requires_enrollment: bool, + is_enrolled: bool, + } + + impl MockProvider { + fn new( + name: &'static str, + priority: u8, + available: bool, + result: VerificationResult, + ) -> Self { + Self { + name, + priority, + available, + result, + requires_enrollment: false, + is_enrolled: true, + } + } + + fn with_enrollment(mut self, requires: bool, enrolled: bool) -> Self { + self.requires_enrollment = requires; + self.is_enrolled = enrolled; + self + } + } + + impl UserVerificationProvider for MockProvider { + fn name(&self) -> &str { + self.name + } + + fn available(&self) -> bool { + self.available + } + + fn verify( + &self, + _context: &VerificationContext, + ) -> Result { + if !self.available { + return Err(VerificationError::NotAvailable("Not available".into())); + } + Ok(self.result) + } + + fn priority(&self) -> u8 { + self.priority + } + + fn requires_enrollment(&self) -> bool { + self.requires_enrollment + } + + fn is_enrolled(&self) -> bool { + self.is_enrolled + } + } + + #[test] + fn test_provider_ordering_by_priority() { + let low = MockProvider::new("low", 10, true, VerificationResult::Accepted); + let high = MockProvider::new("high", 100, true, VerificationResult::Accepted); + + let manager = UserVerificationManager::new(vec![Box::new(low), Box::new(high)]); + + assert_eq!(manager.list_providers()[0].name(), "high"); + assert_eq!(manager.list_providers()[1].name(), "low"); + } + + #[test] + fn test_fallback_on_timeout() { + let fail = MockProvider::new("fail", 100, true, VerificationResult::Timeout); + let succeed = MockProvider::new("succeed", 50, true, VerificationResult::Accepted); + + let manager = UserVerificationManager::new(vec![Box::new(fail), Box::new(succeed)]); + + let ctx = VerificationContext::new("test"); + let result = manager.verify(&ctx); + assert_eq!(result.unwrap(), VerificationResult::Accepted); + } + + #[test] + fn test_no_available_providers() { + let unavailable = + MockProvider::new("unavailable", 100, false, VerificationResult::Accepted); + + let manager = UserVerificationManager::new(vec![Box::new(unavailable)]); + let ctx = VerificationContext::new("test"); + let result = manager.verify(&ctx); + + assert!(result.is_err()); + match result.unwrap_err() { + VerificationError::NotAvailable(_) => {} + _ => panic!("Expected NotAvailable error"), + } + } + + #[test] + fn test_denied_returns_immediately() { + let deny = MockProvider::new("deny", 100, true, VerificationResult::Denied); + let accept = MockProvider::new("accept", 50, true, VerificationResult::Accepted); + + let manager = UserVerificationManager::new(vec![Box::new(deny), Box::new(accept)]); + + let ctx = VerificationContext::new("test"); + let result = manager.verify(&ctx); + assert_eq!(result.unwrap(), VerificationResult::Denied); + } + + #[test] + fn test_skip_unenrolled_provider() { + let unenrolled = MockProvider::new("unenrolled", 100, true, VerificationResult::Accepted) + .with_enrollment(true, false); + let fallback = MockProvider::new("fallback", 50, true, VerificationResult::Accepted); + + let manager = UserVerificationManager::new(vec![Box::new(unenrolled), Box::new(fallback)]); + + let ctx = VerificationContext::new("test"); + let result = manager.verify(&ctx); + assert_eq!(result.unwrap(), VerificationResult::Accepted); + } + + #[test] + fn test_all_providers_fail() { + let fail1 = MockProvider::new("fail1", 100, true, VerificationResult::Timeout); + let fail2 = MockProvider::new("fail2", 50, true, VerificationResult::Timeout); + + let manager = UserVerificationManager::new(vec![Box::new(fail1), Box::new(fail2)]); + + let ctx = VerificationContext::new("test"); + let result = manager.verify(&ctx); + assert!(result.is_err()); + } + + #[test] + fn test_available_providers_filter() { + let available = MockProvider::new("available", 100, true, VerificationResult::Accepted); + let unavailable = MockProvider::new("unavailable", 50, false, VerificationResult::Accepted); + + let manager = + UserVerificationManager::new(vec![Box::new(available), Box::new(unavailable)]); + + let available_list = manager.available_providers(); + assert_eq!(available_list.len(), 1); + assert_eq!(available_list[0].name(), "available"); + } + + #[test] + fn test_get_provider_by_name() { + let provider = MockProvider::new("test_provider", 100, true, VerificationResult::Accepted); + + let manager = UserVerificationManager::new(vec![Box::new(provider)]); + + assert!(manager.get_provider("test_provider").is_some()); + assert!(manager.get_provider("nonexistent").is_none()); + } + + #[test] + fn test_empty_manager() { + let manager = UserVerificationManager::empty(); + assert!(manager.list_providers().is_empty()); + + let ctx = VerificationContext::new("test"); + let result = manager.verify(&ctx); + assert!(result.is_err()); + } + + #[test] + fn test_add_provider() { + let mut manager = UserVerificationManager::empty(); + let provider = MockProvider::new("test", 100, true, VerificationResult::Accepted); + + manager.add_provider(Box::new(provider)); + assert_eq!(manager.list_providers().len(), 1); + } +} diff --git a/cmd/passless/src/uv/mod.rs b/cmd/passless/src/uv/mod.rs new file mode 100644 index 00000000..f2e1efac --- /dev/null +++ b/cmd/passless/src/uv/mod.rs @@ -0,0 +1,276 @@ +//! User Verification (UV) module for FIDO2 authenticator +//! +//! This module provides a pluggable user verification system with multiple providers: +//! - [`FprintdProvider`]: Fingerprint verification via D-Bus +//! - [`FaceIdProvider`]: Face recognition via webcam (requires "face" feature) +//! - [`NotificationProvider`]: Desktop notification (fallback) +//! - [`CommandProvider`]: Custom command/script execution +//! +//! # Architecture +//! +//! Providers implement the [`UserVerificationProvider`] trait and are managed by +//! [`UserVerificationManager`], which handles priority ordering and automatic fallback. +//! +//! # Example +//! +//! ```ignore +//! use passless::uv::{ +//! UserVerificationManager, FprintdProvider, NotificationProvider, +//! VerificationContext, UserVerificationProvider, +//! }; +//! +//! let manager = UserVerificationManager::new(vec![ +//! Box::new(FprintdProvider::new()), +//! Box::new(NotificationProvider::new(30)), +//! ]); +//! +//! let ctx = VerificationContext::new("authentication") +//! .with_relying_party("example.com"); +//! +//! match manager.verify(&ctx) { +//! Ok(VerificationResult::Accepted) => { /* success */ } +//! Ok(VerificationResult::Denied) => { /* denied */ } +//! Ok(VerificationResult::Timeout) => { /* timeout */ } +//! Err(e) => { /* error */ } +//! } +//! ``` + +mod command; +mod fprintd; +mod manager; +mod notification; + +#[cfg(feature = "face")] +mod face; + +pub use command::CommandProvider; +#[cfg(feature = "face")] +pub use face::FaceIdProvider; +pub use fprintd::FprintdProvider; +pub use manager::UserVerificationManager; +pub use notification::NotificationProvider; + +/// Default timeout for user verification (seconds) +pub const DEFAULT_TIMEOUT_SECONDS: u32 = 30; + +/// Provider priority constants (higher = preferred) +pub mod priority { + /// Fingerprint provider priority (highest - most secure biometric) + pub const FPRINTD: u8 = 100; + /// Face recognition provider priority + #[cfg(feature = "face")] + pub const FACE: u8 = 90; + /// Custom command provider priority (configurable) + pub const COMMAND: u8 = 50; + /// Notification provider priority (lowest - fallback) + pub const NOTIFICATION: u8 = 10; +} + +/// Result of a user verification attempt +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum VerificationResult { + /// User successfully verified + Accepted, + /// User explicitly denied verification + Denied, + /// Verification timed out + Timeout, +} + +/// Error during user verification +#[derive(Debug, Clone, thiserror::Error)] +pub enum VerificationError { + /// Provider is not available (not installed, no device, etc.) + #[error("Not available: {0}")] + NotAvailable(String), + /// Device or system error during verification + #[error("Device error: {0}")] + DeviceError(String), + /// User cancelled the operation + #[error("User cancelled")] + #[allow(dead_code)] + UserCancelled, + /// Provider is not enrolled (no biometric data registered) + #[error("Not enrolled")] + NotEnrolled, + /// Unknown error + #[error("Error: {0}")] + Other(String), +} + +impl From for VerificationError { + fn from(err: std::io::Error) -> Self { + VerificationError::DeviceError(err.to_string()) + } +} + +impl From for VerificationError { + fn from(err: zbus::Error) -> Self { + match err { + zbus::Error::MethodError(_, _, _) => { + VerificationError::DeviceError(format!("D-Bus method failed: {}", err)) + } + zbus::Error::InterfaceNotFound => { + VerificationError::NotAvailable("D-Bus interface not found".into()) + } + zbus::Error::FDO(e) => { + VerificationError::DeviceError(format!("D-Bus freedesktop error: {}", e)) + } + _ => VerificationError::DeviceError(format!("D-Bus error: {}", err)), + } + } +} + + + +/// Context for user verification request +#[derive(Debug, Clone)] +pub struct VerificationContext { + /// Type of operation (e.g., "registration", "authentication") + pub operation: String, + /// Relying party ID (domain) + pub relying_party: Option, + /// User identifier + pub user: Option, + /// Timeout in seconds + pub timeout_seconds: u32, +} + +impl VerificationContext { + /// Create a new verification context + pub fn new(operation: impl Into) -> Self { + Self { + operation: operation.into(), + relying_party: None, + user: None, + timeout_seconds: DEFAULT_TIMEOUT_SECONDS, + } + } + + /// Set the relying party + pub fn with_relying_party(mut self, rp: impl Into) -> Self { + self.relying_party = Some(rp.into()); + self + } + + /// Set the user + pub fn with_user(mut self, user: impl Into) -> Self { + self.user = Some(user.into()); + self + } + + /// Set the timeout + pub fn with_timeout(mut self, seconds: u32) -> Self { + self.timeout_seconds = seconds; + self + } +} + +/// Trait for user verification providers +/// +/// Each provider implements biometric or other verification methods. +/// Providers are tried in order of priority until one succeeds. +pub trait UserVerificationProvider: Send + Sync { + /// Unique name for this provider + fn name(&self) -> &str; + + /// Check if this provider is available (device present, service running, etc.) + fn available(&self) -> bool; + + /// Perform user verification + /// + /// Returns: + /// - `Ok(Accepted)` - User successfully verified + /// - `Ok(Denied)` - User explicitly denied + /// - `Ok(Timeout)` - Verification timed out + /// - `Err(_)` - Error occurred, try next provider + fn verify( + &self, + context: &VerificationContext, + ) -> Result; + + /// Priority of this provider (higher = preferred) + /// + /// See [`priority`] module for standard values. + fn priority(&self) -> u8 { + priority::COMMAND + } + + /// Whether this provider supports enrollment + fn supports_enrollment(&self) -> bool { + false + } + + /// Enroll user for verification (e.g., capture face, fingerprint) + #[allow(dead_code)] + fn enroll(&self) -> Result<(), VerificationError> { + Err(VerificationError::NotAvailable( + "Enrollment not supported".into(), + )) + } + + /// Whether this provider requires enrollment before use + fn requires_enrollment(&self) -> bool { + self.supports_enrollment() + } + + /// Check if the user is enrolled + fn is_enrolled(&self) -> bool { + true + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_context_new() { + let ctx = VerificationContext::new("registration"); + assert_eq!(ctx.operation, "registration"); + assert_eq!(ctx.relying_party, None); + assert_eq!(ctx.user, None); + assert_eq!(ctx.timeout_seconds, DEFAULT_TIMEOUT_SECONDS); + } + + #[test] + fn test_context_builder() { + let ctx = VerificationContext::new("authentication") + .with_relying_party("example.com") + .with_user("alice") + .with_timeout(60); + + assert_eq!(ctx.operation, "authentication"); + assert_eq!(ctx.relying_party, Some("example.com".to_string())); + assert_eq!(ctx.user, Some("alice".to_string())); + assert_eq!(ctx.timeout_seconds, 60); + } + + #[test] + fn test_verification_error_display() { + assert_eq!( + VerificationError::NotAvailable("test".into()).to_string(), + "Not available: test" + ); + assert_eq!( + VerificationError::DeviceError("failed".into()).to_string(), + "Device error: failed" + ); + assert_eq!( + VerificationError::UserCancelled.to_string(), + "User cancelled" + ); + assert_eq!(VerificationError::NotEnrolled.to_string(), "Not enrolled"); + assert_eq!( + VerificationError::Other("oops".into()).to_string(), + "Error: oops" + ); + } + + #[test] + fn test_verification_error_from_io() { + let err = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found"); + let uv_err: VerificationError = err.into(); + assert!(matches!(uv_err, VerificationError::DeviceError(_))); + } +} diff --git a/cmd/passless/src/uv/notification.rs b/cmd/passless/src/uv/notification.rs new file mode 100644 index 00000000..745fc4ac --- /dev/null +++ b/cmd/passless/src/uv/notification.rs @@ -0,0 +1,171 @@ +//! Notification-based User Verification Provider +//! +//! Uses desktop notifications for user verification. +//! This is the fallback provider when no biometric methods are available. + +use super::{ + UserVerificationProvider, VerificationContext, VerificationError, VerificationResult, priority, +}; + +use log::debug; + +use std::sync::{Arc, Mutex}; + +use notify_rust::{Notification, Timeout}; + +/// Check if the notification server requires special handling +fn requires_default_action() -> bool { + notify_rust::get_server_information() + .map(|info| { + let server_name = info.name.to_lowercase(); + debug!( + "Notification server: {} (version: {})", + info.name, info.version + ); + + match (server_name.as_str(), info.version.as_str()) { + ("notify-osd", "1.0") | ("mako", "0.0.0") => { + debug!("Detected {} - using default action mode", server_name); + true + } + _ => false, + } + }) + .unwrap_or_else(|e| { + debug!("Failed to get notification server info: {}", e); + false + }) +} + +/// Notification-based user verification provider +pub struct NotificationProvider { + #[allow(dead_code)] + timeout_seconds: u32, +} + +impl NotificationProvider { + /// Create a new notification provider + pub fn new(timeout_seconds: u32) -> Self { + Self { timeout_seconds } + } + + /// Create a provider with timeout + pub fn from_config(timeout_seconds: u32) -> Box { + Box::new(Self::new(timeout_seconds)) + } + + /// Show verification notification and wait for response + fn show_notification( + &self, + context: &VerificationContext, + ) -> Result { + let mut message = format!("Operation: {}", context.operation); + if let Some(rp) = &context.relying_party { + message.push_str(&format!("\nRelying Party: {}", rp)); + } + if let Some(user) = &context.user { + message.push_str(&format!("\nUser: {}", user)); + } + + debug!("Showing user verification notification"); + + let default_means_accept = requires_default_action(); + let action_result = Arc::new(Mutex::new(None)); + let action_result_clone = action_result.clone(); + + let mut notification = Notification::new(); + notification + .summary("User Verification Required") + .body(&message) + .icon("security-high") + .timeout(Timeout::Milliseconds(context.timeout_seconds * 1000)); + + if default_means_accept { + notification.action("default", ""); + } else { + notification.action("approve", "Accept"); + notification.action("deny", "Deny"); + } + + let handle = notification.show().map_err(|e| { + VerificationError::DeviceError(format!("Failed to show notification: {}", e)) + })?; + + handle.wait_for_action(|action| { + debug!("User action received: {}", action); + let mut result = action_result_clone + .lock() + .expect("Failed to lock action result"); + *result = Some(action.to_string()); + }); + + let action = action_result + .lock() + .expect("Failed to lock action result") + .clone() + .unwrap_or_else(|| "__closed".to_string()); + + let accepted = match action.as_str() { + "approve" => true, + "deny" => false, + "default" => default_means_accept, + "__closed" => false, + other => { + debug!("Unknown action '{}' - treating as denied", other); + false + } + }; + + if accepted { + debug!("User verification accepted via notification"); + Ok(VerificationResult::Accepted) + } else { + debug!("User verification denied or notification closed"); + Ok(VerificationResult::Denied) + } + } +} + +impl UserVerificationProvider for NotificationProvider { + fn name(&self) -> &str { + "notification" + } + + fn available(&self) -> bool { + true + } + + fn verify( + &self, + context: &VerificationContext, + ) -> Result { + self.show_notification(context) + } + + fn priority(&self) -> u8 { + priority::NOTIFICATION + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_notification_provider_always_available() { + let provider = NotificationProvider::new(30); + assert!(provider.available()); + } + + #[test] + fn test_notification_provider_priority() { + let provider = NotificationProvider::new(30); + assert_eq!(provider.priority(), priority::NOTIFICATION); + } + + #[test] + fn test_notification_provider_name() { + let provider = NotificationProvider::new(30); + assert_eq!(provider.name(), "notification"); + } +} diff --git a/docs/adr/001-biometric-user-verification.md b/docs/adr/001-biometric-user-verification.md new file mode 100644 index 00000000..71694182 --- /dev/null +++ b/docs/adr/001-biometric-user-verification.md @@ -0,0 +1,104 @@ +# ADR 001: Biometric User Verification + +## Status + +Accepted + +## Context + +Passless currently uses desktop notifications for user verification (UV) in FIDO2 operations. This is a "something you have" factor (the device with passless running). To provide true multi-factor authentication, we need "something you are" - biometric verification. + +Linux provides several options for biometric authentication: + +1. **fprintd** - Standard Linux fingerprint daemon with D-Bus interface +2. **Webcam face recognition** - Using modern ML models via ONNX +3. **External commands** - Allow users to integrate any biometric tool + +## Decision + +We will implement a pluggable user verification system with multiple providers: + +### Architecture + +``` +UserVerificationManager (chain of responsibility) +├── FprintdProvider (fingerprint via D-Bus) +├── FaceIdProvider (webcam + face recognition) +├── NotificationProvider (fallback, current behavior) +└── CommandProvider (user-defined script) +``` + +### Technology Choices + +1. **D-Bus Integration**: Use `zbus` crate (pure Rust, async-native) +2. **Webcam Capture**: Use `nokhwa` crate (cross-platform, no OpenCV dependency) +3. **Face Recognition**: Use `face_id` crate (SCRFD detection + ArcFace embeddings via ONNX Runtime) +4. **Provider Selection**: Configurable chain with automatic fallback + +### Configuration + +```toml +[uv] +providers = ["fprintd", "face", "notification"] # Try in order + +[uv.fprintd] +timeout_seconds = 30 + +[uv.face] +enabled = true +camera_index = 0 +threshold = 0.6 +``` + +## Consequences + +### Positive + +- True biometric verification for FIDO2 operations +- Multiple provider options for different hardware +- Automatic fallback ensures users aren't locked out +- Modern Rust stack (zbus, face_id) with minimal C dependencies + +### Negative + +- Increased binary size and dependencies +- face_id downloads ONNX models from HuggingFace on first use +- Webcam access requires proper permissions +- fprintd requires system-level setup + +### Neutral + +- Face recognition provider is feature-gated (`--features face`) to reduce binary size +- Other providers (fprintd, notification, command) are always included +- Face embeddings stored locally in user's storage backend + +## Implementation + +1. Create `uv/` module with `UserVerificationProvider` trait +2. Implement provider chain in `UserVerificationManager` +3. Implement each provider (fprintd, face, notification, command) +4. Update authenticator to use manager instead of direct notifications + +### Build Options + +```bash +# Standard build (fprintd + notification providers) +cargo build + +# With face recognition support (adds ~50MB+ due to ONNX Runtime) +cargo build --features face +``` + +## Alternatives Considered + +1. **All providers feature-gated**: Rejected - fprintd and notification are lightweight enough to include by default +2. **Howdy integration**: Rejected - Python-based, command provider allows users to integrate it themselves +3. **OpenCV for face recognition**: Rejected - heavy C++ dependency, face_id uses ONNX Runtime instead +4. **PAM integration**: Rejected - indirect, requires PAM conversation setup + +## References + +- [fprintd D-Bus API](https://fprint.freedesktop.org/) +- [nokhwa crate](https://crates.io/crates/nokhwa) +- [face_id crate](https://crates.io/crates/face_id) +- [zbus crate](https://crates.io/crates/zbus) diff --git a/passless-core/src/config.rs b/passless-core/src/config.rs index c4193851..0af73346 100644 --- a/passless-core/src/config.rs +++ b/passless-core/src/config.rs @@ -358,6 +358,126 @@ pub struct PinConfig { pub auto_lock_timeout: u32, } +/// User verification provider type +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)] +#[serde(rename_all = "lowercase")] +pub enum UvProviderType { + /// Fingerprint verification via fprintd D-Bus service + Fprintd, + /// Face recognition via webcam + Face, + /// Desktop notification (fallback) + Notification, + /// Custom command/script + Command, + /// Use all available providers in priority order + #[default] + Auto, +} + +impl std::str::FromStr for UvProviderType { + type Err = String; + + fn from_str(s: &str) -> Result { + match s.to_lowercase().as_str() { + "fprintd" | "fingerprint" => Ok(UvProviderType::Fprintd), + "face" | "faceid" => Ok(UvProviderType::Face), + "notification" | "notify" => Ok(UvProviderType::Notification), + "command" | "cmd" => Ok(UvProviderType::Command), + "auto" | "all" => Ok(UvProviderType::Auto), + _ => Err(format!( + "Invalid UV provider '{}'. Must be: fprintd, face, notification, command, or auto", + s + )), + } + } +} + +impl std::fmt::Display for UvProviderType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + UvProviderType::Fprintd => write!(f, "fprintd"), + UvProviderType::Face => write!(f, "face"), + UvProviderType::Notification => write!(f, "notification"), + UvProviderType::Command => write!(f, "command"), + UvProviderType::Auto => write!(f, "auto"), + } + } +} + +/// fprintd provider configuration +#[derive(ClapSerde, Debug, Clone, Serialize, Deserialize, ConfigDoc)] +#[group(id = "uv-fprintd")] +pub struct FprintdConfig { + /// Enable fprintd provider + #[arg( + long = "fprintd-enabled", + id = "fprintd-enabled", + env = "PASSLESS_FPRINTD_ENABLED", + action = ArgAction::Set, + require_equals = true, + num_args = 0..=1, + default_missing_value = "true" + )] + #[serde(default)] + #[default(true)] + pub enabled: bool, +} + +/// Face recognition provider configuration +#[derive(ClapSerde, Debug, Clone, Serialize, Deserialize, ConfigDoc)] +#[group(id = "uv-face")] +pub struct FaceConfig { + /// Enable face recognition provider + #[arg( + long = "face-enabled", + id = "face-enabled", + env = "PASSLESS_FACE_ENABLED", + action = ArgAction::Set, + require_equals = true, + num_args = 0..=1, + default_missing_value = "true" + )] + #[serde(default)] + #[default(true)] + pub enabled: bool, + + /// Camera device index (0 = first camera) + #[arg( + long = "face-camera-index", + id = "face-camera-index", + env = "PASSLESS_FACE_CAMERA_INDEX", + value_name = "INDEX" + )] + #[serde(default)] + #[default(0)] + pub camera_index: usize, + + /// Face matching threshold (0.0-1.0, higher = stricter) + #[arg( + long = "face-threshold", + id = "face-threshold", + env = "PASSLESS_FACE_THRESHOLD", + value_name = "THRESHOLD" + )] + #[serde(default)] + #[default(0.6)] + pub threshold: f32, +} + +impl FaceConfig { + /// Validate the configuration + pub fn validate(&self) -> Result<(), String> { + if self.threshold < 0.0 || self.threshold > 1.0 { + return Err(format!( + "Face threshold must be between 0.0 and 1.0, got {}", + self.threshold + )); + } + Ok(()) + } +} + impl PinConfig { /// Validate PIN configuration values pub fn validate(&self) -> crate::error::Result<()> { @@ -381,6 +501,87 @@ impl PinConfig { } } +/// Command provider configuration +#[derive(ClapSerde, Debug, Clone, Serialize, Deserialize, ConfigDoc)] +#[group(id = "uv-cmd")] +pub struct CommandConfig { + /// Enable command provider + #[arg( + long = "uv-command-enabled", + id = "uv-command-enabled", + env = "PASSLESS_UV_COMMAND_ENABLED", + action = ArgAction::Set, + require_equals = true, + num_args = 0..=1, + default_missing_value = "false" + )] + #[serde(default)] + #[default(false)] + pub enabled: bool, + + /// Command to execute for verification (exit 0 = accept, non-zero = deny) + /// Command receives context via environment variables: + /// PASSLESS_UV_OPERATION, PASSLESS_UV_RELYING_PARTY, PASSLESS_UV_USER + #[arg( + long = "uv-command", + id = "uv-command-arg", + env = "PASSLESS_UV_COMMAND", + value_name = "COMMAND", + value_delimiter = ' ' + )] + #[serde(default)] + pub command: Vec, +} + +/// User verification configuration +#[derive(ClapSerde, Debug, Clone, Serialize, Deserialize, ConfigDoc)] +#[group(id = "uv")] +pub struct UvConfig { + /// User verification provider selection + /// - "auto": Use all available providers in priority order (default) + /// - "fprintd": Fingerprint only + /// - "face": Face recognition only + /// - "notification": Desktop notification only + /// - "command": Custom command only + #[arg( + long = "uv-provider", + env = "PASSLESS_UV_PROVIDER", + value_name = "PROVIDER" + )] + #[serde(default)] + #[default(UvProviderType::Auto)] + pub provider: UvProviderType, + + /// Default timeout for verification (seconds) + #[arg( + long = "uv-timeout", + env = "PASSLESS_UV_TIMEOUT", + value_name = "SECONDS" + )] + #[serde(default)] + #[default(30)] + pub timeout_seconds: u32, + + /// fprintd configuration + #[clap_serde] + #[serde(default)] + #[command(flatten)] + pub fprintd: FprintdConfig, + + /// Face recognition configuration + #[clap_serde] + #[serde(default)] + #[command(flatten)] + pub face: FaceConfig, + + /// Command provider configuration + #[clap_serde] + #[serde(default)] + #[command(flatten)] + pub command: CommandConfig, +} + + impl SecurityConfig { /// Apply security hardening measures pub fn apply_hardening(&self) -> Result<(), Box> { @@ -420,7 +621,7 @@ impl SecurityConfig { } else { log::warn!( "mlock capability probe failed - memory locking may not be available.\n\ - Hint: grant CAP_IPC_LOCK to the binary with: 'sudo setcap cap_ipc_lock=+ep $(which passless)'" + Hint: grant CAP_IPC_LOCK to the binary with: 'sudo setcaps cap_ipc_lock=+ep $(which passless)'" ); } Ok(()) @@ -483,6 +684,12 @@ pub struct AppConfig { #[command(flatten)] pub pin: PinConfig, + /// User verification configuration + #[clap_serde] + #[serde(default)] + #[command(flatten)] + pub uv: UvConfig, + /// Agent configuration (only available with the `agent` feature) #[cfg(feature = "agent")] #[arg(skip)] @@ -736,9 +943,15 @@ impl AppConfig { self.pin.clone() } + /// Get user verification configuration + pub fn uv_config(&self) -> UvConfig { + self.uv.clone() + } + /// Validate the configuration pub fn validate(&self) -> crate::error::Result<()> { self.pin.validate()?; + self.uv.face.validate().map_err(crate::error::Error::Config)?; #[cfg(feature = "agent")] { let human_path = self.backend().ok().map(|b| b.state_path());