diff options
-rw-r--r-- | CHANGELOG.md | 45 | ||||
-rw-r--r-- | Cargo.lock | 836 | ||||
-rw-r--r-- | Cargo.toml | 57 | ||||
-rw-r--r-- | README.md | 24 | ||||
-rw-r--r-- | deny.toml | 8 | ||||
-rw-r--r-- | src/actions.rs | 4 | ||||
-rw-r--r-- | src/api.rs | 138 | ||||
-rw-r--r-- | src/bin/rbw-agent/actions.rs | 5 | ||||
-rw-r--r-- | src/bin/rbw-agent/agent.rs | 7 | ||||
-rw-r--r-- | src/bin/rbw-agent/daemon.rs | 28 | ||||
-rw-r--r-- | src/bin/rbw-agent/debugger.rs | 2 | ||||
-rw-r--r-- | src/bin/rbw-agent/main.rs | 2 | ||||
-rw-r--r-- | src/bin/rbw/actions.rs | 44 | ||||
-rw-r--r-- | src/bin/rbw/commands.rs | 1016 | ||||
-rw-r--r-- | src/bin/rbw/main.rs | 33 | ||||
-rw-r--r-- | src/db.rs | 2 | ||||
-rw-r--r-- | src/dirs.rs | 2 | ||||
-rw-r--r-- | src/error.rs | 9 | ||||
-rw-r--r-- | src/identity.rs | 2 |
19 files changed, 1604 insertions, 660 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index e724e46..dde5fda 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,51 @@ # Changelog -## [Unreleased] +## [1.10.2] - 2024-05-20 + +* Fix logging into the official Bitwarden server due to changes on their end + (Gabriel Górski, #175) + +## [1.10.1] - 2024-05-08 + +### Added + +* `rbw code` supports TOTP codes which use a SHA256 or SHA512 hash (Jonas, #172) + +### Fixed + +* Fix `rbw code` searching by UUID (Robert Günzler, #169) + +## [1.10.0] - 2024-04-20 + +### Added + +* `rbw get` now supports searching by URL as well (proxict, #132) +* `rbw code` now supports `--clipboard`, and has an alias of `rbw totp` (#127) + +### Changed + +* Set a user agent for all API calls, not just logging in (#165) + +### Fixed + +* Also create runtime directories when running with `--no-daemonize` (Wim de With, #155) +* Fix builds on NetBSD (#105) +* Fix logging in when the configured email address differs in case from the email address used when registering (#158) +* Fix editing passwords inadvertently clearing custom field values (#142) + +## [1.9.0] - 2024-01-01 + +### Added + +* Secure notes can now be edited (Tin Lai, #137) +* Piping passwords to `rbw edit` is now possible (Tin Lai, #138) ### Fixed -* More consistent behavior from `rbw get --field`, and fix some panics (#131, Jörg Thalheim) +* More consistent behavior from `rbw get --field`, and fix some panics (Jörg Thalheim, #131) +* Fix handling of pinentry EOF (Jörg Thalheim, #140) +* Pass a user agent header to fix logging into the official bitwarden server (Maksim Karelov, #151) +* Support the official bitwarden.eu server (Edvin Åkerfeldt, #152) ## [1.8.3] - 2023-07-20 @@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aes" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ "cfg-if", "cipher", @@ -30,18 +30,18 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] name = "anstream" -version = "0.6.5" +version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d664a92ecae85fd0a7392615844904654d1d5f5514837f471ddef4a057aba1b6" +checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" dependencies = [ "anstyle", "anstyle-parse", @@ -53,9 +53,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" +checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" [[package]] name = "anstyle-parse" @@ -87,15 +87,15 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.78" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca87830a3e3fb156dc96cfbd31cb620265dd053be734723f22b760d6cc3c3051" +checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" [[package]] name = "argon2" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17ba4cac0a46bc1d2912652a751c47f2a9f3a7fe89bcae2275d418f5270402f9" +checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072" dependencies = [ "base64ct", "blake2", @@ -111,9 +111,9 @@ checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "async-trait" -version = "0.1.76" +version = "0.1.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "531b97fb4cd3dfdce92c35dedbfdc1f0b9d8091c8ca943d6dae340ef5012d514" +checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2", "quote", @@ -122,15 +122,15 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" [[package]] name = "backtrace" -version = "0.3.69" +version = "0.3.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" dependencies = [ "addr2line", "cc", @@ -149,9 +149,9 @@ checksum = "23ce669cd6c8588f79e15cf450314f9638f967fc5770ff1c7c1deb0925ea7cfa" [[package]] name = "base64" -version = "0.21.5" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" +checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51" [[package]] name = "base64ct" @@ -167,9 +167,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" [[package]] name = "blake2" @@ -206,9 +206,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.14.0" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "byteorder" @@ -218,17 +218,17 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "calloop" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b50b5a44d59a98c55a9eeb518f39bf7499ba19fd98ee7d22618687f3f10adbf" +checksum = "fba7adb4dd5aa98e5553510223000e7148f621165ec5f9acd7113f6ca4995298" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.5.0", "log", "polling", "rustix", @@ -259,12 +259,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.83" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" -dependencies = [ - "libc", -] +checksum = "d32a725bc159af97c3e629873bb9f88fb8cf8a4867175f76dc987815ea07c83b" [[package]] name = "cfg-if" @@ -284,9 +281,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.12" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcfab8ba68f3668e89f6ff60f5b205cea56aa7b769451a59f34b8682f51c056d" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" dependencies = [ "clap_builder", "clap_derive", @@ -294,9 +291,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.12" +version = "4.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb7fb5e4e979aec3be7791562fcba452f94ad85e954da024396433e0e25a79e9" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" dependencies = [ "anstream", "anstyle", @@ -307,18 +304,18 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.4.5" +version = "4.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a51919c5608a32e34ea1d6be321ad070065e17613e168c5b6977024290f2630b" +checksum = "dd79504325bf38b10165b02e89b4347300f855f273c4cb30c4a3209e6583275e" dependencies = [ "clap", ] [[package]] name = "clap_derive" -version = "4.4.7" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" dependencies = [ "heck", "proc-macro2", @@ -328,9 +325,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" [[package]] name = "clipboard-win" @@ -365,9 +362,9 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "copypasta" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d35364349bf9e9e1c3a035ddcb00d188d23a3c40c50244c03c27a99fc6a65ae" +checksum = "deb85422867ca93da58b7f95fb5c0c10f6183ed6e1ef8841568968a896d3a858" dependencies = [ "clipboard-win", "objc", @@ -395,21 +392,18 @@ checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "cpufeatures" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ "libc", ] [[package]] name = "crossbeam-utils" -version = "0.8.18" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3a430a770ebd84726f584a90ee7f020d28db52c6d02138900f22341f866d39c" -dependencies = [ - "cfg-if", -] +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" [[package]] name = "crypto-common" @@ -444,9 +438,9 @@ checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" [[package]] name = "der" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" dependencies = [ "const-oid", "pem-rfc7468", @@ -496,39 +490,34 @@ dependencies = [ [[package]] name = "downcast-rs" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" [[package]] -name = "encoding_rs" -version = "0.8.33" +name = "env_filter" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" dependencies = [ - "cfg-if", + "log", + "regex", ] [[package]] name = "env_logger" -version = "0.10.1" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece" +checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9" dependencies = [ + "anstream", + "anstyle", + "env_filter", "humantime", - "is-terminal", "log", - "regex", - "termcolor", ] [[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] name = "errno" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -540,9 +529,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.0.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" [[package]] name = "fnv" @@ -660,19 +649,19 @@ dependencies = [ [[package]] name = "gethostname" -version = "0.3.0" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb65d4ba3173c56a500b555b532f72c42e8d1fe64962b518897f8959fae2c177" +checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818" dependencies = [ "libc", - "winapi", + "windows-targets 0.48.5", ] [[package]] name = "getrandom" -version = "0.2.11" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" dependencies = [ "cfg-if", "libc", @@ -686,41 +675,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] -name = "h2" -version = "0.3.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "hashbrown" -version = "0.14.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" - -[[package]] name = "heck" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" -version = "0.3.3" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "hkdf" @@ -742,9 +706,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.11" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" dependencies = [ "bytes", "fnv", @@ -753,12 +717,24 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.6" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" dependencies = [ "bytes", "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", "pin-project-lite", ] @@ -769,12 +745,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] name = "humantime" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -782,60 +752,68 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.28" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" +checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d" dependencies = [ "bytes", "futures-channel", - "futures-core", "futures-util", - "h2", "http", "http-body", "httparse", - "httpdate", "itoa", "pin-project-lite", - "socket2", + "smallvec", "tokio", - "tower-service", - "tracing", "want", ] [[package]] name = "hyper-rustls" -version = "0.24.2" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +checksum = "a0bea761b46ae2b24eb4aef630d8d1c398157b6fc29e6350ecf090a0b70c952c" dependencies = [ "futures-util", "http", "hyper", + "hyper-util", "rustls", + "rustls-pki-types", "tokio", "tokio-rustls", + "tower-service", ] [[package]] -name = "idna" -version = "0.5.0" +name = "hyper-util" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "pin-project-lite", + "socket2", + "tokio", + "tower", + "tower-service", + "tracing", ] [[package]] -name = "indexmap" -version = "2.1.0" +name = "idna" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ - "equivalent", - "hashbrown", + "unicode-bidi", + "unicode-normalization", ] [[package]] @@ -856,26 +834,26 @@ checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "is-terminal" -version = "0.4.10" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455" +checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" dependencies = [ "hermit-abi", - "rustix", + "libc", "windows-sys 0.52.0", ] [[package]] name = "itoa" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "js-sys" -version = "0.3.66" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] @@ -897,18 +875,18 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.151" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "libloading" -version = "0.8.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" +checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" dependencies = [ "cfg-if", - "windows-sys 0.48.0", + "windows-targets 0.48.5", ] [[package]] @@ -919,20 +897,19 @@ checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "libredox" -version = "0.0.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.5.0", "libc", - "redox_syscall", ] [[package]] name = "linux-raw-sys" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" [[package]] name = "lock_api" @@ -946,15 +923,15 @@ dependencies = [ [[package]] name = "log" -version = "0.4.20" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] -name = "mach" -version = "0.3.2" +name = "mach2" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709" dependencies = [ "libc", ] @@ -970,29 +947,20 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "memmap2" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45fd3a57831bf88bc63f8cebc0cf956116276e97fef3966103e96416209f7c92" +checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" dependencies = [ "libc", ] [[package]] -name = "memoffset" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" -dependencies = [ - "autocfg", -] - -[[package]] name = "mime" version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1000,18 +968,18 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "miniz_oxide" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" dependencies = [ "adler", ] [[package]] name = "mio" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "wasi", @@ -1019,19 +987,6 @@ dependencies = [ ] [[package]] -name = "nix" -version = "0.26.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" -dependencies = [ - "bitflags 1.3.2", - "cfg-if", - "libc", - "memoffset", - "pin-utils", -] - -[[package]] name = "num-bigint-dig" version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1050,19 +1005,18 @@ dependencies = [ [[package]] name = "num-integer" -version = "0.1.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "autocfg", "num-traits", ] [[package]] name = "num-iter" -version = "0.1.43" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9" dependencies = [ "autocfg", "num-integer", @@ -1071,9 +1025,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.17" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" dependencies = [ "autocfg", "libm", @@ -1205,10 +1159,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] +name = "pin-project" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] name = "pin-project-lite" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -1239,18 +1213,19 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "polling" -version = "3.3.1" +version = "3.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf63fa624ab313c11656b4cda960bfc46c410187ad493c41f6ba2d8c1e991c9e" +checksum = "e0c976a60b2d7e99d6f229e414670a9b85d13ac305cc6d1e9c134de58c5aaaf6" dependencies = [ "cfg-if", "concurrent-queue", + "hermit-abi", "pin-project-lite", "rustix", "tracing", @@ -1265,27 +1240,27 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.73" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dd5e8a1f1029c43224ad5898e50140c2aebb1705f19e67c918ebf5b9e797fe1" +checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" dependencies = [ "unicode-ident", ] [[package]] name = "quick-xml" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eff6510e86862b57b210fd8cbe8ed3f0d7d600b9c2863cd4549a2e033c66e956" +checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33" dependencies = [ "memchr", ] [[package]] name = "quote" -version = "1.0.34" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22a37c9326af5ed140c86a46655b5278de879853be5573c01df185b6f49a580a" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -1322,7 +1297,7 @@ dependencies = [ [[package]] name = "rbw" -version = "1.8.3" +version = "1.10.2" dependencies = [ "aes", "anyhow", @@ -1348,15 +1323,16 @@ dependencies = [ "is-terminal", "libc", "log", - "nix", "pbkdf2", "percent-encoding", "pkcs8", "rand", + "regex", "region", "reqwest", "rmpv", "rsa", + "rustix", "serde", "serde_json", "serde_path_to_error", @@ -1387,9 +1363,9 @@ dependencies = [ [[package]] name = "redox_users" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" +checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" dependencies = [ "getrandom", "libredox", @@ -1398,9 +1374,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.2" +version = "1.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" dependencies = [ "aho-corasick", "memchr", @@ -1410,9 +1386,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.3" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ "aho-corasick", "memchr", @@ -1421,38 +1397,39 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" [[package]] name = "region" -version = "3.0.0" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76e189c2369884dce920945e2ddf79b3dff49e071a167dd1817fa9c4c00d512e" +checksum = "e6b6ebd13bc009aef9cd476c1310d49ac354d36e240cf1bd753290f3dc7199a7" dependencies = [ "bitflags 1.3.2", "libc", - "mach", - "winapi", + "mach2", + "windows-sys 0.52.0", ] [[package]] name = "reqwest" -version = "0.11.23" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41" +checksum = "566cafdd92868e0939d3fb961bd0dc25fcfaaed179291093b3d43e6b3150ea10" dependencies = [ "base64", "bytes", - "encoding_rs", + "futures-channel", "futures-core", "futures-util", - "h2", "http", "http-body", + "http-body-util", "hyper", "hyper-rustls", + "hyper-util", "ipnet", "js-sys", "log", @@ -1463,10 +1440,11 @@ dependencies = [ "rustls", "rustls-native-certs", "rustls-pemfile", + "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", - "system-configuration", + "sync_wrapper", "tokio", "tokio-rustls", "tower-service", @@ -1479,23 +1457,24 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.7" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", + "cfg-if", "getrandom", "libc", "spin 0.9.8", "untrusted", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "rmp" -version = "0.8.12" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f9860a6cc38ed1da53456442089b4dfa35e7cedaa326df63017af88385e6b20" +checksum = "228ed7c16fa39782c3b3468e974aec2795e9089153cd08ee2e9aefb3613334c4" dependencies = [ "byteorder", "num-traits", @@ -1504,9 +1483,9 @@ dependencies = [ [[package]] name = "rmpv" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e0e0214a4a2b444ecce41a4025792fc31f77c7bb89c46d253953ea8c65701ec" +checksum = "e540282f11751956c82bc5529a7fb71b871b998fbf9cf06c2419b22e1b4350df" dependencies = [ "num-traits", "rmp", @@ -1540,65 +1519,78 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.38.28" +version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.5.0", "errno", + "itoa", "libc", "linux-raw-sys", + "once_cell", "windows-sys 0.52.0", ] [[package]] name = "rustls" -version = "0.21.10" +version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" +checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" dependencies = [ "log", "ring", + "rustls-pki-types", "rustls-webpki", - "sct", + "subtle", + "zeroize", ] [[package]] name = "rustls-native-certs" -version = "0.6.3" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" +checksum = "8f1fb85efa936c42c6d5fc28d2629bb51e4b2f4b8a5211e297d599cc5a093792" dependencies = [ "openssl-probe", "rustls-pemfile", + "rustls-pki-types", "schannel", "security-framework", ] [[package]] name = "rustls-pemfile" -version = "1.0.4" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" dependencies = [ "base64", + "rustls-pki-types", ] [[package]] +name = "rustls-pki-types" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecd36cc4259e3e4514335c4a138c6b43171a8d61d8f5c9348f9fc7529416f247" + +[[package]] name = "rustls-webpki" -version = "0.101.7" +version = "0.102.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +checksum = "faaa0a62740bedb9b2ef5afa303da42764c012f743917351dc9a237ea1663610" dependencies = [ "ring", + "rustls-pki-types", "untrusted", ] [[package]] name = "ryu" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" [[package]] name = "schannel" @@ -1622,20 +1614,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] -name = "sct" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] name = "security-framework" -version = "2.9.2" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +checksum = "770452e37cad93e0a50d5abc3990d2bc351c36d0328f86cefec2f2fb206eaef6" dependencies = [ "bitflags 1.3.2", "core-foundation", @@ -1646,9 +1628,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.9.1" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +checksum = "41f3cc463c0ef97e11c3461a9d3787412d30e8e7eb907c79180c4a57bf7c04ef" dependencies = [ "core-foundation-sys", "libc", @@ -1656,18 +1638,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.193" +version = "1.0.198" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.193" +version = "1.0.198" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9" dependencies = [ "proc-macro2", "quote", @@ -1676,9 +1658,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.109" +version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb0652c533506ad7a2e353cce269330d6afd8bdfb6d75e0ace5b35aacbd7b9e9" +checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" dependencies = [ "itoa", "ryu", @@ -1687,9 +1669,9 @@ dependencies = [ [[package]] name = "serde_path_to_error" -version = "0.1.14" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4beec8bce849d58d06238cb50db2e1c417cfeafa4c63f692b15c82b7c80f8335" +checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" dependencies = [ "itoa", "serde", @@ -1697,9 +1679,9 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.17" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3081f5ffbb02284dda55132aa26daecedd7372a42417bbbab6f14ab7d6bb9145" +checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", @@ -1770,9 +1752,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.2" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "smawk" @@ -1782,11 +1764,11 @@ checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" [[package]] name = "smithay-client-toolkit" -version = "0.18.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60e3d9941fa3bacf7c2bf4b065304faa14164151254cd16ce1b1bc8fc381600f" +checksum = "922fd3eeab3bd820d76537ce8f582b1cf951eceb5475c28500c7457d9d17f53a" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.5.0", "calloop", "calloop-wayland-source", "cursor-icon", @@ -1807,9 +1789,9 @@ dependencies = [ [[package]] name = "smithay-clipboard" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb62b280ce5a5cba847669933a0948d00904cf83845c944eae96a4738cea1a6" +checksum = "c091e7354ea8059d6ad99eace06dd13ddeedbb0ac72d40a9a6e7ff790525882d" dependencies = [ "libc", "smithay-client-toolkit", @@ -1818,12 +1800,12 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -1850,9 +1832,9 @@ dependencies = [ [[package]] name = "strsim" -version = "0.10.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "subtle" @@ -1862,9 +1844,9 @@ checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] name = "syn" -version = "2.0.45" +version = "2.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eae3c679c56dc214320b67a1bc04ef3dfbd6411f6443974b5e4893231298e66" +checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" dependencies = [ "proc-macro2", "quote", @@ -1872,49 +1854,24 @@ dependencies = [ ] [[package]] -name = "system-configuration" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.5.0" +name = "sync_wrapper" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" -dependencies = [ - "core-foundation-sys", - "libc", -] +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" [[package]] name = "tempfile" -version = "3.9.0" +version = "3.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", "fastrand", - "redox_syscall", "rustix", "windows-sys 0.52.0", ] [[package]] -name = "termcolor" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" -dependencies = [ - "winapi-util", -] - -[[package]] name = "terminal_size" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1926,9 +1883,9 @@ dependencies = [ [[package]] name = "textwrap" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" +checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" dependencies = [ "smawk", "unicode-linebreak", @@ -1937,18 +1894,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.53" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2cd5904763bad08ad5513ddbb12cf2ae273ca53fa9f68e843e236ec6dfccc09" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.53" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dcf4a824cce0aeacd6f38ae6f24234c8e80d68632338ebaa1443b5df9e29e19" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", @@ -1972,9 +1929,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.35.1" +version = "1.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" +checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" dependencies = [ "backtrace", "bytes", @@ -2002,19 +1959,20 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.24.1" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" dependencies = [ "rustls", + "rustls-pki-types", "tokio", ] [[package]] name = "tokio-stream" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" dependencies = [ "futures-core", "pin-project-lite", @@ -2023,34 +1981,21 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.20.1" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" +checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38" dependencies = [ "futures-util", "log", "rustls", "rustls-native-certs", + "rustls-pki-types", "tokio", "tokio-rustls", "tungstenite", ] [[package]] -name = "tokio-util" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", - "tracing", -] - -[[package]] name = "totp-lite" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2063,6 +2008,28 @@ dependencies = [ ] [[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + +[[package]] name = "tower-service" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2074,6 +2041,7 @@ version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ + "log", "pin-project-lite", "tracing-core", ] @@ -2095,9 +2063,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "tungstenite" -version = "0.20.1" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" +checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" dependencies = [ "byteorder", "bytes", @@ -2107,6 +2075,7 @@ dependencies = [ "log", "rand", "rustls", + "rustls-pki-types", "sha1", "thiserror", "url", @@ -2121,9 +2090,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-bidi" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" @@ -2139,9 +2108,9 @@ checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" [[package]] name = "unicode-normalization" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" dependencies = [ "tinyvec", ] @@ -2183,9 +2152,9 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.6.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" +checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" dependencies = [ "getrandom", ] @@ -2213,9 +2182,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.89" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -2223,9 +2192,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.89" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", @@ -2238,9 +2207,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.39" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" dependencies = [ "cfg-if", "js-sys", @@ -2250,9 +2219,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.89" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2260,9 +2229,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.89" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", @@ -2273,19 +2242,19 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.89" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "wayland-backend" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19152ddd73f45f024ed4534d9ca2594e0ef252c1847695255dae47f34df9fbe4" +checksum = "9d50fa61ce90d76474c87f5fc002828d81b32677340112b4ef08079a9d459a40" dependencies = [ "cc", "downcast-rs", - "nix", + "rustix", "scoped-tls", "smallvec", "wayland-sys", @@ -2293,12 +2262,12 @@ dependencies = [ [[package]] name = "wayland-client" -version = "0.31.1" +version = "0.31.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ca7d52347346f5473bf2f56705f360e8440873052e575e55890c4fa57843ed3" +checksum = "82fb96ee935c2cea6668ccb470fb7771f6215d1691746c2d896b447a00ad3f1f" dependencies = [ - "bitflags 2.4.1", - "nix", + "bitflags 2.5.0", + "rustix", "wayland-backend", "wayland-scanner", ] @@ -2309,29 +2278,29 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.5.0", "cursor-icon", "wayland-backend", ] [[package]] name = "wayland-cursor" -version = "0.31.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44aa20ae986659d6c77d64d808a046996a932aa763913864dc40c359ef7ad5b" +checksum = "71ce5fa868dd13d11a0d04c5e2e65726d0897be8de247c0c5a65886e283231ba" dependencies = [ - "nix", + "rustix", "wayland-client", "xcursor", ] [[package]] name = "wayland-protocols" -version = "0.31.0" +version = "0.31.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e253d7107ba913923dc253967f35e8561a3c65f914543e46843c88ddd729e21c" +checksum = "8f81f365b8b4a97f422ac0e8737c438024b5951734506b0e1d775c73030561f4" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.5.0", "wayland-backend", "wayland-client", "wayland-scanner", @@ -2343,7 +2312,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad1f61b76b6c2d8742e10f9ba5c3737f6530b4c243132c2a2ccc8aa96fe25cd6" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.5.0", "wayland-backend", "wayland-client", "wayland-protocols", @@ -2352,9 +2321,9 @@ dependencies = [ [[package]] name = "wayland-scanner" -version = "0.31.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb8e28403665c9f9513202b7e1ed71ec56fde5c107816843fb14057910b2c09c" +checksum = "63b3a62929287001986fb58c789dce9b67604a397c15c611ad9f747300b6c283" dependencies = [ "proc-macro2", "quick-xml", @@ -2375,9 +2344,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.66" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" dependencies = [ "js-sys", "wasm-bindgen", @@ -2400,24 +2369,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] -name = "winapi-util" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-wsapoll" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c17110f57155602a80dca10be03852116403c9ff3cd25b079d666f2aa3df6e" -dependencies = [ - "winapi", -] - -[[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2447,7 +2398,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.5", ] [[package]] @@ -2482,17 +2433,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", ] [[package]] @@ -2509,9 +2461,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" [[package]] name = "windows_aarch64_msvc" @@ -2527,9 +2479,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" [[package]] name = "windows_i686_gnu" @@ -2545,9 +2497,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" [[package]] name = "windows_i686_msvc" @@ -2563,9 +2521,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" [[package]] name = "windows_x86_64_gnu" @@ -2581,9 +2539,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" [[package]] name = "windows_x86_64_gnullvm" @@ -2599,9 +2557,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" [[package]] name = "windows_x86_64_msvc" @@ -2617,15 +2575,15 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "winreg" -version = "0.50.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" dependencies = [ "cfg-if", "windows-sys 0.48.0", @@ -2633,34 +2591,30 @@ dependencies = [ [[package]] name = "x11-clipboard" -version = "0.8.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b41aca1115b1f195f21c541c5efb423470848d48143127d0f07f8b90c27440df" +checksum = "b98785a09322d7446e28a13203d2cae1059a0dd3dfb32cb06d0a225f023d8286" dependencies = [ + "libc", "x11rb", ] [[package]] name = "x11rb" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1641b26d4dec61337c35a1b1aaf9e3cba8f46f0b43636c609ab0291a648040a" +checksum = "f8f25ead8c7e4cba123243a6367da5d3990e0d3affa708ea19dce96356bd9f1a" dependencies = [ "gethostname", - "nix", - "winapi", - "winapi-wsapoll", + "rustix", "x11rb-protocol", ] [[package]] name = "x11rb-protocol" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82d6c3f9a0fb6701fab8f6cea9b0c0bd5d6876f1f89f7fada07e558077c344bc" -dependencies = [ - "nix", -] +checksum = "e63e71c4b8bd9ffec2c963173a4dc4cbde9ee96961d4fcb4429db9929b606c34" [[package]] name = "xcursor" @@ -1,6 +1,6 @@ [package] name = "rbw" -version = "1.8.3" +version = "1.10.2" authors = ["Jesse Luehrs <doy@tozt.net>"] edition = "2021" @@ -13,58 +13,59 @@ license = "MIT" include = ["src/**/*", "bin/**/*", "LICENSE", "README.md", "CHANGELOG.md"] [dependencies] -aes = "0.8.3" -anyhow = "1.0.78" -argon2 = "0.5.2" +aes = "0.8.4" +anyhow = "1.0.82" +argon2 = "0.5.3" arrayvec = "0.7.4" -async-trait = "0.1.76" +async-trait = "0.1.80" base32 = "0.4.0" -base64 = "0.21.5" +base64 = "0.22.0" block-padding = "0.3.3" cbc = { version = "0.1.2", features = ["alloc", "std"] } -clap = { version = "4.4.12", features = ["wrap_help", "derive"] } -clap_complete = "4.4.5" +clap = { version = "4.5.4", features = ["wrap_help", "derive"] } +clap_complete = "4.5.2" daemonize = "0.5.0" # TODO: directories 5.0.1 uses MPL code, which isn't license-compatible # we should switch to something else at some point directories = "=5.0.0" -env_logger = "0.10.1" +env_logger = "0.11.3" futures = "0.3.30" futures-channel = "0.3.30" futures-util = "0.3.30" hkdf = "0.12.4" hmac = { version = "0.12.1", features = ["std"] } humantime = "2.1.0" -libc = "0.2.151" -log = "0.4.20" -nix = "0.26" +libc = "0.2.153" +log = "0.4.21" pbkdf2 = "0.12.2" percent-encoding = "2.3.1" pkcs8 = "0.10.2" rand = "0.8.5" -region = "3.0.0" -reqwest = { version = "0.11.23", default-features = false, features = ["blocking", "json", "rustls-tls-native-roots"] } +region = "3.0.2" +reqwest = { version = "0.12.4", default-features = false, features = ["blocking", "json", "rustls-tls-native-roots"] } rsa = "0.9.6" -serde = { version = "1.0.193", features = ["derive"] } -serde_json = "1.0.109" -serde_path_to_error = "0.1.14" -serde_repr = "0.1.17" +serde = { version = "1.0.198", features = ["derive"] } +serde_json = "1.0.116" +serde_path_to_error = "0.1.16" +serde_repr = "0.1.19" sha1 = "0.10.6" sha2 = "0.10.8" -tempfile = "3.9.0" +tempfile = "3.10.1" terminal_size = "0.3.0" -textwrap = "0.16.0" -thiserror = "1.0.53" -tokio = { version = "1.35.1", features = ["full"] } -tokio-stream = { version = "0.1.14", features = ["net"] } +textwrap = "0.16.1" +thiserror = "1.0.58" +tokio = { version = "1.37.0", features = ["full"] } +tokio-stream = { version = "0.1.15", features = ["net"] } totp-lite = "2.0.1" url = "2.5.0" -uuid = { version = "1.6.1", features = ["v4"] } +uuid = { version = "1.8.0", features = ["v4"] } zeroize = "1.7.0" -copypasta = "0.10.0" -rmpv = "1.0.1" -tokio-tungstenite = { version = "0.20", features = ["rustls-tls-native-roots"] } -is-terminal = "0.4.10" +copypasta = "0.10.1" +rmpv = "1.0.2" +tokio-tungstenite = { version = "0.21", features = ["rustls-tls-native-roots"] } +is-terminal = "0.4.12" +regex = "1.10.4" +rustix = { version = "0.38.33", features = ["termios", "procfs", "process", "pipe"] } [package.metadata.deb] depends = "pinentry" @@ -37,6 +37,16 @@ You can download a Debian package from [`minisign`](https://github.com/jedisct1/minisign), and can be verified using the public key `RWTM0AZ5RpROOfAIWx1HvYQ6pw1+FKwN6526UFTKNImP/Hz3ynCFst3r`. +### Homebrew + +`rbw` is available in the [Homebrew repository](https://formulae.brew.sh/formula/rbw). You can install it via `brew install rbw`. + +### Nix + +`rbw` is available in the +[NixOS repository](https://search.nixos.org/packages?show=rbw). You can try +it out via `nix-shell -p rbw`. + ### Alpine `rbw` is available in the [testing repository](https://pkgs.alpinelinux.org/packages?name=rbw). @@ -45,7 +55,7 @@ If you are not using the `edge` version of alpine you have to [enable the reposi ### Other With a working Rust installation, `rbw` can be installed via `cargo install -rbw`. This requires that the +--locked rbw`. This requires that the [`pinentry`](https://www.gnupg.org/related_software/pinentry/index.en.html) program is installed (to display password prompts). @@ -74,6 +84,14 @@ configuration options: [pinentry](https://www.gnupg.org/related_software/pinentry/index.html) executable to use. Defaults to `pinentry`. +### Profiles + +`rbw` supports different configuration profiles, which can be switched +between by using the `RBW_PROFILE` environment variable. Setting it to a name +(for example, `RBW_PROFILE=work` or `RBW_PROFILE=personal`) can be used to +switch between several different vaults - each will use its own separate +configuration, local vault, and agent. + ## Usage Commands can generally be used directly, and will handle logging in or @@ -95,7 +113,9 @@ functionality. Run `rbw get <name>` to get your passwords. If you also want to get the username or the note associated, you can use the flag `--full`. You can also use the flag `--field={field}` to get whatever default or custom field you want. The `--raw` -flag will show the output as JSON. +flag will show the output as JSON. In addition to matching against the name, +you can pass a UUID as the name to search for the entry with that id, or a +URL to search for an entry with a matching website entry. *Note to users of the official Bitwarden server (at bitwarden.com)*: The official server has a tendency to detect command line traffic as bot traffic @@ -1,3 +1,4 @@ +[graph] targets = [ { triple = "x86_64-unknown-linux-musl" }, { triple = "x86_64-unknown-linux-gnu" }, @@ -6,12 +7,9 @@ targets = [ ] [advisories] +version = 2 yanked = "deny" -unsound = "deny" ignore = [ - # this is only an unmaintained warning, and will hopefully be addressed - # by https://github.com/darfink/region-rs/pull/27 - "RUSTSEC-2020-0168", # this is a timing attack against using the rsa crate for encryption, but # we only use rsa decryption here "RUSTSEC-2023-0071", @@ -37,6 +35,7 @@ skip = [ ] [licenses] +version = 2 allow = [ "MIT", "BSD-2-Clause", @@ -45,7 +44,6 @@ allow = [ "ISC", "Unicode-DFS-2016", ] -copyleft = "deny" exceptions = [ { name = "ring", allow = ["OpenSSL", "MIT", "ISC"] } ] diff --git a/src/actions.rs b/src/actions.rs index b07cf44..7ee1fa4 100644 --- a/src/actions.rs +++ b/src/actions.rs @@ -185,6 +185,7 @@ pub fn edit( org_id: Option<&str>, name: &str, data: &crate::db::EntryData, + fields: &[crate::db::Field], notes: Option<&str>, folder_uuid: Option<&str>, history: &[crate::db::HistoryEntry], @@ -196,6 +197,7 @@ pub fn edit( org_id, name, data, + fields, notes, folder_uuid, history, @@ -209,6 +211,7 @@ fn edit_once( org_id: Option<&str>, name: &str, data: &crate::db::EntryData, + fields: &[crate::db::Field], notes: Option<&str>, folder_uuid: Option<&str>, history: &[crate::db::HistoryEntry], @@ -220,6 +223,7 @@ fn edit_once( org_id, name, data, + fields, notes, folder_uuid, history, @@ -362,7 +362,7 @@ struct SyncResCipher { #[serde(rename = "PasswordHistory", alias = "passwordHistory")] password_history: Option<Vec<SyncResPasswordHistory>>, #[serde(rename = "Fields", alias = "fields")] - fields: Option<Vec<SyncResField>>, + fields: Option<Vec<CipherField>>, #[serde(rename = "DeletedDate", alias = "deletedDate")] deleted_date: Option<String>, } @@ -463,8 +463,10 @@ impl SyncResCipher { fields .iter() .map(|field| crate::db::Field { + ty: field.ty, name: field.name.clone(), value: field.value.clone(), + linked_id: field.linked_id, }) .collect() }); @@ -582,6 +584,75 @@ struct CipherIdentity { username: Option<String>, } +#[derive( + serde_repr::Serialize_repr, + serde_repr::Deserialize_repr, + Debug, + Clone, + Copy, + PartialEq, + Eq, +)] +#[repr(u16)] +pub enum FieldType { + Text = 0, + Hidden = 1, + Boolean = 2, + Linked = 3, +} + +#[derive( + serde_repr::Serialize_repr, + serde_repr::Deserialize_repr, + Debug, + Clone, + Copy, + PartialEq, + Eq, +)] +#[repr(u16)] +pub enum LinkedIdType { + LoginUsername = 100, + LoginPassword = 101, + CardCardholderName = 300, + CardExpMonth = 301, + CardExpYear = 302, + CardCode = 303, + CardBrand = 304, + CardNumber = 305, + IdentityTitle = 400, + IdentityMiddleName = 401, + IdentityAddress1 = 402, + IdentityAddress2 = 403, + IdentityAddress3 = 404, + IdentityCity = 405, + IdentityState = 406, + IdentityPostalCode = 407, + IdentityCountry = 408, + IdentityCompany = 409, + IdentityEmail = 410, + IdentityPhone = 411, + IdentitySsn = 412, + IdentityUsername = 413, + IdentityPassportNumber = 414, + IdentityLicenseNumber = 415, + IdentityFirstName = 416, + IdentityLastName = 417, + IdentityFullName = 418, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +struct CipherField { + #[serde(rename = "Type", alias = "type")] + ty: FieldType, + #[serde(rename = "Name", alias = "name")] + name: Option<String>, + #[serde(rename = "Value", alias = "value")] + value: Option<String>, + #[serde(rename = "LinkedId", alias = "linkedId")] + linked_id: Option<LinkedIdType>, +} + // this is just a name and some notes, both of which are already on the cipher // object #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] @@ -595,16 +666,6 @@ struct SyncResPasswordHistory { password: Option<String>, } -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -struct SyncResField { - #[serde(rename = "Type", alias = "type")] - ty: u32, - #[serde(rename = "Name", alias = "name")] - name: Option<String>, - #[serde(rename = "Value", alias = "value")] - value: Option<String>, -} - #[derive(serde::Serialize, Debug)] struct CiphersPostReq { #[serde(rename = "type")] @@ -633,6 +694,7 @@ struct CiphersPutReq { login: Option<CipherLogin>, card: Option<CipherCard>, identity: Option<CipherIdentity>, + fields: Vec<CipherField>, #[serde(rename = "secureNote")] secure_note: Option<CipherSecureNote>, #[serde(rename = "passwordHistory")] @@ -640,12 +702,6 @@ struct CiphersPutReq { } #[derive(serde::Serialize, Debug)] -struct CiphersPutReqLogin { - username: Option<String>, - password: Option<String>, -} - -#[derive(serde::Serialize, Debug)] struct CiphersPutReqHistory { #[serde(rename = "LastUsedDate")] last_used_date: String, @@ -709,20 +765,26 @@ impl Client { file: client_cert_path.clone(), } })?; - let pem = reqwest::Identity::from_pem(&buf).map_err(|e| { - Error::LoadClientCertReqwest { - source: e, - file: client_cert_path.clone(), - } - })?; - Ok(reqwest::Client::builder().identity(pem).build().map_err( - |e| Error::LoadClientCertReqwest { - source: e, - file: client_cert_path.clone(), - }, - )?) + let pem = reqwest::Identity::from_pem(&buf) + .map_err(|e| Error::CreateReqwestClient { source: e })?; + Ok(reqwest::Client::builder() + .user_agent(format!( + "{}/{}", + env!("CARGO_PKG_NAME"), + env!("CARGO_PKG_VERSION") + )) + .identity(pem) + .build() + .map_err(|e| Error::CreateReqwestClient { source: e })?) } else { - Ok(reqwest::Client::new()) + Ok(reqwest::Client::builder() + .user_agent(format!( + "{}/{}", + env!("CARGO_PKG_NAME"), + env!("CARGO_PKG_VERSION") + )) + .build() + .map_err(|e| Error::CreateReqwestClient { source: e })?) } } @@ -827,14 +889,12 @@ impl Client { let res = client .post(&self.identity_url("/connect/token")) .form(&connect_req) + .header("Bitwarden-Client-Name", env!("CARGO_PKG_NAME")) + .header("Bitwarden-Client-Version", env!("CARGO_PKG_VERSION")) .header( "auth-email", crate::base64::encode_url_safe_no_pad(email), ) - .header( - "user-agent", - format!("rbw/{}", env!("CARGO_PKG_VERSION")), - ) .send() .await .map_err(|source| Error::Reqwest { source })?; @@ -1040,6 +1100,7 @@ impl Client { org_id: Option<&str>, name: &str, data: &crate::db::EntryData, + fields: &[crate::db::Field], notes: Option<&str>, folder_uuid: Option<&str>, history: &[crate::db::HistoryEntry], @@ -1059,6 +1120,15 @@ impl Client { card: None, identity: None, secure_note: None, + fields: fields + .iter() + .map(|field| CipherField { + ty: field.ty, + name: field.name.clone(), + value: field.value.clone(), + linked_id: field.linked_id, + }) + .collect(), password_history: history .iter() .map(|entry| CiphersPutReqHistory { diff --git a/src/bin/rbw-agent/actions.rs b/src/bin/rbw-agent/actions.rs index ff39510..8966785 100644 --- a/src/bin/rbw-agent/actions.rs +++ b/src/bin/rbw-agent/actions.rs @@ -184,7 +184,9 @@ pub async fn login( break 'attempts; } } - return Err(anyhow::anyhow!("TODO")); + return Err(anyhow::anyhow!( + "unsupported two factor methods: {providers:?}" + )); } Err(rbw::error::Error::IncorrectPassword { message }) => { if i == 3 { @@ -474,7 +476,6 @@ pub async fn lock( pub async fn check_lock( sock: &mut crate::sock::Sock, state: std::sync::Arc<tokio::sync::Mutex<crate::agent::State>>, - _tty: Option<&str>, ) -> anyhow::Result<()> { if state.lock().await.needs_unlock() { return Err(anyhow::anyhow!("agent is locked")); diff --git a/src/bin/rbw-agent/agent.rs b/src/bin/rbw-agent/agent.rs index 1345967..a3fecb4 100644 --- a/src/bin/rbw-agent/agent.rs +++ b/src/bin/rbw-agent/agent.rs @@ -209,12 +209,7 @@ async fn handle_request( true } rbw::protocol::Action::CheckLock => { - crate::actions::check_lock( - sock, - state.clone(), - req.tty.as_deref(), - ) - .await?; + crate::actions::check_lock(sock, state.clone()).await?; false } rbw::protocol::Action::Lock => { diff --git a/src/bin/rbw-agent/daemon.rs b/src/bin/rbw-agent/daemon.rs index 8cb9998..06db891 100644 --- a/src/bin/rbw-agent/daemon.rs +++ b/src/bin/rbw-agent/daemon.rs @@ -1,25 +1,15 @@ pub struct StartupAck { - writer: std::os::unix::io::RawFd, + writer: std::os::unix::io::OwnedFd, } impl StartupAck { - pub fn ack(&self) -> anyhow::Result<()> { - nix::unistd::write(self.writer, &[0])?; - nix::unistd::close(self.writer)?; + pub fn ack(self) -> anyhow::Result<()> { + rustix::io::write(&self.writer, &[0])?; Ok(()) } } -impl Drop for StartupAck { - fn drop(&mut self) { - // best effort close here, can't do better in a destructor - let _ = nix::unistd::close(self.writer); - } -} - pub fn daemonize() -> anyhow::Result<StartupAck> { - rbw::dirs::make_all()?; - let stdout = std::fs::OpenOptions::new() .append(true) .create(true) @@ -29,25 +19,25 @@ pub fn daemonize() -> anyhow::Result<StartupAck> { .create(true) .open(rbw::dirs::agent_stderr_file())?; - let (r, w) = nix::unistd::pipe()?; + let (r, w) = rustix::pipe::pipe()?; let daemonize = daemonize::Daemonize::new() .pid_file(rbw::dirs::pid_file()) .stdout(stdout) .stderr(stderr); let res = match daemonize.execute() { daemonize::Outcome::Parent(_) => { + drop(w); + let mut buf = [0; 1]; // unwraps are necessary because not really a good way to handle // errors here otherwise - let _ = nix::unistd::close(w); - let mut buf = [0; 1]; - nix::unistd::read(r, &mut buf).unwrap(); - nix::unistd::close(r).unwrap(); + rustix::io::read(&r, &mut buf).unwrap(); + drop(r); std::process::exit(0); } daemonize::Outcome::Child(res) => res, }; - let _ = nix::unistd::close(r); + drop(r); match res { Ok(_) => (), diff --git a/src/bin/rbw-agent/debugger.rs b/src/bin/rbw-agent/debugger.rs index 59bbe50..be5260c 100644 --- a/src/bin/rbw-agent/debugger.rs +++ b/src/bin/rbw-agent/debugger.rs @@ -12,7 +12,7 @@ pub fn disable_tracing() -> anyhow::Result<()> { if ret == 0 { Ok(()) } else { - let e = nix::Error::last(); + let e = std::io::Error::last_os_error(); Err(anyhow::anyhow!("failed to disable PTRACE_ATTACH, agent memory may be dumpable by other processes: {}", e)) } } diff --git a/src/bin/rbw-agent/main.rs b/src/bin/rbw-agent/main.rs index 8434c72..d470e10 100644 --- a/src/bin/rbw-agent/main.rs +++ b/src/bin/rbw-agent/main.rs @@ -50,6 +50,8 @@ fn real_main() -> anyhow::Result<()> { .nth(1) .map_or(false, |arg| arg == "--no-daemonize"); + rbw::dirs::make_all()?; + let startup_ack = if no_daemonize { None } else { diff --git a/src/bin/rbw/actions.rs b/src/bin/rbw/actions.rs index e0e7a2e..c84ccd4 100644 --- a/src/bin/rbw/actions.rs +++ b/src/bin/rbw/actions.rs @@ -1,4 +1,4 @@ -use anyhow::Context as _; +use anyhow::{bail, Context as _}; use std::io::Read as _; pub fn register() -> anyhow::Result<()> { @@ -31,11 +31,17 @@ pub fn quit() -> anyhow::Result<()> { let pidfile = rbw::dirs::pid_file(); let mut pid = String::new(); std::fs::File::open(pidfile)?.read_to_string(&mut pid)?; - let pid = nix::unistd::Pid::from_raw(pid.trim_end().parse()?); + let Some(pid) = + rustix::process::Pid::from_raw(pid.trim_end().parse()?) + else { + bail!("failed to read pid from pidfile"); + }; sock.send(&rbw::protocol::Request { - tty: nix::unistd::ttyname(0).ok().and_then(|p| { - p.to_str().map(std::string::ToString::to_string) - }), + tty: rustix::termios::ttyname(std::io::stdin(), vec![]) + .ok() + .and_then(|p| { + p.to_str().map(std::string::ToString::to_string).ok() + }), action: rbw::protocol::Action::Quit, })?; wait_for_exit(pid); @@ -57,9 +63,11 @@ pub fn decrypt( ) -> anyhow::Result<String> { let mut sock = connect()?; sock.send(&rbw::protocol::Request { - tty: nix::unistd::ttyname(0) + tty: rustix::termios::ttyname(std::io::stdin(), vec![]) .ok() - .and_then(|p| p.to_str().map(std::string::ToString::to_string)), + .and_then(|p| { + p.to_str().map(std::string::ToString::to_string).ok() + }), action: rbw::protocol::Action::Decrypt { cipherstring: cipherstring.to_string(), org_id: org_id.map(std::string::ToString::to_string), @@ -82,9 +90,11 @@ pub fn encrypt( ) -> anyhow::Result<String> { let mut sock = connect()?; sock.send(&rbw::protocol::Request { - tty: nix::unistd::ttyname(0) + tty: rustix::termios::ttyname(std::io::stdin(), vec![]) .ok() - .and_then(|p| p.to_str().map(std::string::ToString::to_string)), + .and_then(|p| { + p.to_str().map(std::string::ToString::to_string).ok() + }), action: rbw::protocol::Action::Encrypt { plaintext: plaintext.to_string(), org_id: org_id.map(std::string::ToString::to_string), @@ -110,9 +120,11 @@ pub fn clipboard_store(text: &str) -> anyhow::Result<()> { pub fn version() -> anyhow::Result<u32> { let mut sock = connect()?; sock.send(&rbw::protocol::Request { - tty: nix::unistd::ttyname(0) + tty: rustix::termios::ttyname(std::io::stdin(), vec![]) .ok() - .and_then(|p| p.to_str().map(std::string::ToString::to_string)), + .and_then(|p| { + p.to_str().map(std::string::ToString::to_string).ok() + }), action: rbw::protocol::Action::Version, })?; @@ -130,9 +142,11 @@ fn simple_action(action: rbw::protocol::Action) -> anyhow::Result<()> { let mut sock = connect()?; sock.send(&rbw::protocol::Request { - tty: nix::unistd::ttyname(0) + tty: rustix::termios::ttyname(std::io::stdin(), vec![]) .ok() - .and_then(|p| p.to_str().map(std::string::ToString::to_string)), + .and_then(|p| { + p.to_str().map(std::string::ToString::to_string).ok() + }), action, })?; @@ -158,9 +172,9 @@ fn connect() -> anyhow::Result<crate::sock::Sock> { }) } -fn wait_for_exit(pid: nix::unistd::Pid) { +fn wait_for_exit(pid: rustix::process::Pid) { loop { - if nix::sys::signal::kill(pid, None).is_err() { + if rustix::process::test_kill_process(pid).is_err() { break; } std::thread::sleep(std::time::Duration::from_millis(10)); diff --git a/src/bin/rbw/commands.rs b/src/bin/rbw/commands.rs index a4c0a26..b42c6fc 100644 --- a/src/bin/rbw/commands.rs +++ b/src/bin/rbw/commands.rs @@ -1,7 +1,9 @@ use anyhow::Context as _; use serde::Serialize; +use std::fmt::{Display, Formatter, Result as FmtResult}; use std::io; use std::io::prelude::Write; +use url::Url; const MISSING_CONFIG_HELP: &str = "Before using rbw, you must configure the email address you would like to \ @@ -13,6 +15,36 @@ const MISSING_CONFIG_HELP: &str = and, if your server has a non-default identity url:\n\n \ rbw config set identity_url <url>\n"; +#[derive(Debug, Clone)] +pub enum Needle { + Name(String), + Uri(Url), + Uuid(uuid::Uuid), +} + +impl Display for Needle { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + let value = match &self { + Self::Name(name) => name.clone(), + Self::Uri(uri) => uri.to_string(), + Self::Uuid(uuid) => uuid.to_string(), + }; + write!(f, "{value}") + } +} + +#[allow(clippy::unnecessary_wraps)] +pub fn parse_needle(arg: &str) -> Result<Needle, std::convert::Infallible> { + if let Ok(uuid) = uuid::Uuid::parse_str(arg) { + return Ok(Needle::Uuid(uuid)); + } + if let Ok(url) = Url::parse(arg) { + return Ok(Needle::Uri(url)); + } + + Ok(Needle::Name(arg.to_string())) +} + #[derive(Debug, Clone, Serialize)] #[cfg_attr(test, derive(Eq, PartialEq))] struct DecryptedCipher { @@ -485,13 +517,38 @@ impl DecryptedCipher { fn exact_match( &self, - name: &str, + needle: &Needle, username: Option<&str>, folder: Option<&str>, try_match_folder: bool, ) -> bool { - if name != self.name { - return false; + match needle { + Needle::Name(name) => { + if &self.name != name { + return false; + } + } + Needle::Uri(given_uri) => { + match &self.data { + DecryptedData::Login { + uris: Some(uris), .. + } => { + if !uris.iter().any(|uri| uri.matches_url(given_uri)) + { + return false; + } + } + _ => { + // not sure what else to do here, but open to suggestions + return false; + } + } + } + Needle::Uuid(uuid) => { + if uuid::Uuid::parse_str(&self.id) != Ok(*uuid) { + return false; + } + } } if let Some(given_username) = username { @@ -650,6 +707,76 @@ struct DecryptedUri { match_type: Option<rbw::api::UriMatchType>, } +impl DecryptedUri { + fn matches_url(&self, url: &Url) -> bool { + match self.match_type.unwrap_or(rbw::api::UriMatchType::Domain) { + rbw::api::UriMatchType::Domain => { + let Some(given_domain_port) = domain_port(url) else { + return false; + }; + if let Ok(self_url) = url::Url::parse(&self.uri) { + if let Some(self_domain_port) = domain_port(&self_url) { + if self_url.scheme() == url.scheme() + && (self_domain_port == given_domain_port + || given_domain_port.ends_with(&format!( + ".{self_domain_port}" + ))) + { + return true; + } + } + } + self.uri == given_domain_port + || given_domain_port.ends_with(&format!(".{}", self.uri)) + } + rbw::api::UriMatchType::Host => { + let Some(given_host_port) = host_port(url) else { + return false; + }; + if let Ok(self_url) = url::Url::parse(&self.uri) { + if let Some(self_host_port) = host_port(&self_url) { + if self_url.scheme() == url.scheme() + && self_host_port == given_host_port + { + return true; + } + } + } + self.uri == given_host_port + } + rbw::api::UriMatchType::StartsWith => { + url.to_string().starts_with(&self.uri) + } + rbw::api::UriMatchType::Exact => url.to_string() == self.uri, + rbw::api::UriMatchType::RegularExpression => { + let Ok(rx) = regex::Regex::new(&self.uri) else { + return false; + }; + rx.is_match(url.as_ref()) + } + rbw::api::UriMatchType::Never => false, + } + } +} + +fn host_port(url: &Url) -> Option<String> { + let host = url.host_str()?; + Some( + url.port().map_or_else( + || host.to_string(), + |port| format!("{host}:{port}"), + ), + ) +} + +fn domain_port(url: &Url) -> Option<String> { + let domain = url.domain()?; + Some(url.port().map_or_else( + || domain.to_string(), + |port| format!("{domain}:{port}"), + )) +} + enum ListField { Name, Id, @@ -857,7 +984,7 @@ pub fn list(fields: &[String]) -> anyhow::Result<()> { } pub fn get( - name: &str, + needle: &Needle, user: Option<&str>, folder: Option<&str>, field: Option<&str>, @@ -872,10 +999,10 @@ pub fn get( let desc = format!( "{}{}", user.map_or_else(String::new, |s| format!("{s}@")), - name + needle ); - let (_, decrypted) = find_entry(&db, name, user, folder) + let (_, decrypted) = find_entry(&db, needle, user, folder) .with_context(|| format!("couldn't find entry for '{desc}'"))?; if raw { decrypted.display_json(&desc)?; @@ -891,9 +1018,10 @@ pub fn get( } pub fn code( - name: &str, + needle: &Needle, user: Option<&str>, folder: Option<&str>, + clipboard: bool, ) -> anyhow::Result<()> { unlock()?; @@ -902,15 +1030,15 @@ pub fn code( let desc = format!( "{}{}", user.map_or_else(String::new, |s| format!("{s}@")), - name + needle ); - let (_, decrypted) = find_entry(&db, name, user, folder) + let (_, decrypted) = find_entry(&db, needle, user, folder) .with_context(|| format!("couldn't find entry for '{desc}'"))?; if let DecryptedData::Login { totp, .. } = decrypted.data { if let Some(totp) = totp { - println!("{}", generate_totp(&totp)?); + val_display_or_store(clipboard, &generate_totp(&totp)?); } else { return Err(anyhow::anyhow!( "entry does not contain a totp secret" @@ -967,7 +1095,7 @@ pub fn add( let (new_access_token, folders) = rbw::actions::list_folders(&access_token, refresh_token)?; if let Some(new_access_token) = new_access_token { - access_token = new_access_token.clone(); + access_token.clone_from(&new_access_token); db.access_token = Some(new_access_token); save_db(&db)?; } @@ -990,7 +1118,7 @@ pub fn add( &crate::actions::encrypt(folder_name, None)?, )?; if let Some(new_access_token) = new_access_token { - access_token = new_access_token.clone(); + access_token.clone_from(&new_access_token); db.access_token = Some(new_access_token); save_db(&db)?; } @@ -1060,7 +1188,7 @@ pub fn generate( let (new_access_token, folders) = rbw::actions::list_folders(&access_token, refresh_token)?; if let Some(new_access_token) = new_access_token { - access_token = new_access_token.clone(); + access_token.clone_from(&new_access_token); db.access_token = Some(new_access_token); save_db(&db)?; } @@ -1085,7 +1213,7 @@ pub fn generate( &crate::actions::encrypt(folder_name, None)?, )?; if let Some(new_access_token) = new_access_token { - access_token = new_access_token.clone(); + access_token.clone_from(&new_access_token); db.access_token = Some(new_access_token); save_db(&db)?; } @@ -1133,10 +1261,11 @@ pub fn edit( name ); - let (entry, decrypted) = find_entry(&db, name, username, folder) - .with_context(|| format!("couldn't find entry for '{desc}'"))?; + let (entry, decrypted) = + find_entry(&db, &Needle::Name(name.to_string()), username, folder) + .with_context(|| format!("couldn't find entry for '{desc}'"))?; - let (data, notes, history) = match &decrypted.data { + let (data, fields, notes, history) = match &decrypted.data { DecryptedData::Login { password, .. } => { let mut contents = format!("{}\n", password.as_deref().unwrap_or("")); @@ -1144,7 +1273,7 @@ pub fn edit( contents.push_str(&format!("\n{notes}\n")); } - let contents = rbw::edit::edit(&contents, HELP_NOTES)?; + let contents = rbw::edit::edit(&contents, HELP_PW)?; let (password, notes) = parse_editor(&contents); let password = password @@ -1190,7 +1319,7 @@ pub fn edit( uris: entry_uris.clone(), totp: entry_totp.clone(), }; - (data, notes, history) + (data, entry.fields, notes, history) } DecryptedData::SecureNote {} => { let data = rbw::db::EntryData::SecureNote {}; @@ -1210,7 +1339,7 @@ pub fn edit( }) .transpose()?; - (data, notes, entry.history) + (data, entry.fields, notes, entry.history) } _ => { return Err(anyhow::anyhow!( @@ -1226,6 +1355,7 @@ pub fn edit( entry.org_id.as_deref(), &entry.name, &data, + &fields, notes.as_deref(), entry.folder_id.as_deref(), &history, @@ -1255,8 +1385,9 @@ pub fn remove( name ); - let (entry, _) = find_entry(&db, name, username, folder) - .with_context(|| format!("couldn't find entry for '{desc}'"))?; + let (entry, _) = + find_entry(&db, &Needle::Name(name.to_string()), username, folder) + .with_context(|| format!("couldn't find entry for '{desc}'"))?; if let (Some(access_token), ()) = rbw::actions::remove(access_token, refresh_token, &entry.id)? @@ -1285,8 +1416,9 @@ pub fn history( name ); - let (_, decrypted) = find_entry(&db, name, username, folder) - .with_context(|| format!("couldn't find entry for '{desc}'"))?; + let (_, decrypted) = + find_entry(&db, &Needle::Name(name.to_string()), username, folder) + .with_context(|| format!("couldn't find entry for '{desc}'"))?; for history in decrypted.history { println!("{}: {}", history.last_used_date, history.password); } @@ -1381,13 +1513,13 @@ fn version_or_quit() -> anyhow::Result<u32> { fn find_entry( db: &rbw::db::Db, - name: &str, + needle: &Needle, username: Option<&str>, folder: Option<&str>, ) -> anyhow::Result<(rbw::db::Entry, DecryptedCipher)> { - if uuid::Uuid::parse_str(name).is_ok() { + if let Needle::Uuid(uuid) = needle { for cipher in &db.entries { - if name == cipher.id { + if uuid::Uuid::parse_str(&cipher.id) == Ok(*uuid) { return Ok((cipher.clone(), decrypt_cipher(cipher)?)); } } @@ -1401,20 +1533,20 @@ fn find_entry( decrypt_cipher(&entry).map(|decrypted| (entry, decrypted)) }) .collect::<anyhow::Result<_>>()?; - find_entry_raw(&ciphers, name, username, folder) + find_entry_raw(&ciphers, needle, username, folder) } } fn find_entry_raw( entries: &[(rbw::db::Entry, DecryptedCipher)], - name: &str, + needle: &Needle, username: Option<&str>, folder: Option<&str>, ) -> anyhow::Result<(rbw::db::Entry, DecryptedCipher)> { let mut matches: Vec<(rbw::db::Entry, DecryptedCipher)> = entries .iter() .filter(|&(_, decrypted_cipher)| { - decrypted_cipher.exact_match(name, username, folder, true) + decrypted_cipher.exact_match(needle, username, folder, true) }) .cloned() .collect(); @@ -1427,7 +1559,7 @@ fn find_entry_raw( matches = entries .iter() .filter(|&(_, decrypted_cipher)| { - decrypted_cipher.exact_match(name, username, folder, false) + decrypted_cipher.exact_match(needle, username, folder, false) }) .cloned() .collect(); @@ -1437,29 +1569,32 @@ fn find_entry_raw( } } - matches = entries - .iter() - .filter(|&(_, decrypted_cipher)| { - decrypted_cipher.partial_match(name, username, folder, true) - }) - .cloned() - .collect(); - - if matches.len() == 1 { - return Ok(matches[0].clone()); - } - - if folder.is_none() { + if let Needle::Name(name) = needle { matches = entries .iter() .filter(|&(_, decrypted_cipher)| { - decrypted_cipher.partial_match(name, username, folder, false) + decrypted_cipher.partial_match(name, username, folder, true) }) .cloned() .collect(); + if matches.len() == 1 { return Ok(matches[0].clone()); } + + if folder.is_none() { + matches = entries + .iter() + .filter(|&(_, decrypted_cipher)| { + decrypted_cipher + .partial_match(name, username, folder, false) + }) + .cloned() + .collect(); + if matches.len() == 1 { + return Ok(matches[0].clone()); + } + } } if matches.is_empty() { @@ -1807,8 +1942,23 @@ fn remove_db() -> anyhow::Result<()> { ) } -fn parse_totp_secret(secret: &str) -> anyhow::Result<Vec<u8>> { - let secret_str = if let Ok(u) = url::Url::parse(secret) { +struct TotpParams { + secret: Vec<u8>, + algorithm: String, + digits: u32, + period: u64, +} + +fn decode_totp_secret(secret: &str) -> anyhow::Result<Vec<u8>> { + base32::decode( + base32::Alphabet::RFC4648 { padding: false }, + &secret.replace(' ', ""), + ) + .ok_or_else(|| anyhow::anyhow!("totp secret was not valid base32")) +} + +fn parse_totp_secret(secret: &str) -> anyhow::Result<TotpParams> { + if let Ok(u) = url::Url::parse(secret) { if u.scheme() != "otpauth" { return Err(anyhow::anyhow!( "totp secret url must have otpauth scheme" @@ -1821,32 +1971,73 @@ fn parse_totp_secret(secret: &str) -> anyhow::Result<Vec<u8>> { } let query: std::collections::HashMap<_, _> = u.query_pairs().collect(); - query - .get("secret") - .ok_or_else(|| { - anyhow::anyhow!("totp secret url must have secret") - })? - .to_string() + Ok(TotpParams { + secret: decode_totp_secret(query + .get("secret") + .ok_or_else(|| { + anyhow::anyhow!("totp secret url must have secret") + })?)?, + algorithm:query.get("algorithm").map_or_else(||{String::from("SHA1")},|alg|{alg.to_string()} ), + digits: match query.get("digits") { + Some(dig) => { + dig.parse::<u32>().map_err(|_|{ + anyhow::anyhow!("digits parameter in totp url must be a valid integer.") + })? + } + None => 6, + }, + period: match query.get("period") { + Some(dig) => { + dig.parse::<u64>().map_err(|_|{ + anyhow::anyhow!("period parameter in totp url must be a valid integer.") + })? + } + None => totp_lite::DEFAULT_STEP, + } + }) } else { - secret.to_string() - }; - base32::decode( - base32::Alphabet::RFC4648 { padding: false }, - &secret_str.replace(' ', ""), - ) - .ok_or_else(|| anyhow::anyhow!("totp secret was not valid base32")) + Ok(TotpParams { + secret: decode_totp_secret(secret)?, + algorithm: String::from("SHA1"), + digits: 6, + period: totp_lite::DEFAULT_STEP, + }) + } } fn generate_totp(secret: &str) -> anyhow::Result<String> { - let key = parse_totp_secret(secret)?; - Ok(totp_lite::totp_custom::<totp_lite::Sha1>( - totp_lite::DEFAULT_STEP, - 6, - &key, - std::time::SystemTime::now() - .duration_since(std::time::SystemTime::UNIX_EPOCH)? - .as_secs(), - )) + let totp_params = parse_totp_secret(secret)?; + let alg = totp_params.algorithm.as_str(); + match alg { + "SHA1" => Ok(totp_lite::totp_custom::<totp_lite::Sha1>( + totp_params.period, + totp_params.digits, + &totp_params.secret, + std::time::SystemTime::now() + .duration_since(std::time::SystemTime::UNIX_EPOCH)? + .as_secs(), + )), + "SHA256" => Ok(totp_lite::totp_custom::<totp_lite::Sha256>( + totp_params.period, + totp_params.digits, + &totp_params.secret, + std::time::SystemTime::now() + .duration_since(std::time::SystemTime::UNIX_EPOCH)? + .as_secs(), + )), + "SHA512" => Ok(totp_lite::totp_custom::<totp_lite::Sha512>( + totp_params.period, + totp_params.digits, + &totp_params.secret, + std::time::SystemTime::now() + .duration_since(std::time::SystemTime::UNIX_EPOCH)? + .as_secs(), + )), + _ => Err(anyhow::anyhow!(format!( + "{} is not a valid totp algorithm", + alg + ))), + } } fn display_field(name: &str, field: Option<&str>, clipboard: bool) -> bool { @@ -1863,15 +2054,15 @@ mod test { #[test] fn test_find_entry() { let entries = &[ - make_entry("github", Some("foo"), None), - make_entry("gitlab", Some("foo"), None), - make_entry("gitlab", Some("bar"), None), - make_entry("gitter", Some("baz"), None), - make_entry("git", Some("foo"), None), - make_entry("bitwarden", None, None), - make_entry("github", Some("foo"), Some("websites")), - make_entry("github", Some("foo"), Some("ssh")), - make_entry("github", Some("root"), Some("ssh")), + make_entry("github", Some("foo"), None, &[]), + make_entry("gitlab", Some("foo"), None, &[]), + make_entry("gitlab", Some("bar"), None, &[]), + make_entry("gitter", Some("baz"), None, &[]), + make_entry("git", Some("foo"), None, &[]), + make_entry("bitwarden", None, None, &[]), + make_entry("github", Some("foo"), Some("websites"), &[]), + make_entry("github", Some("foo"), Some("ssh"), &[]), + make_entry("github", Some("root"), Some("ssh"), &[]), ]; assert!( @@ -1930,26 +2121,653 @@ mod test { ); } + #[test] + fn test_find_by_uuid() { + let entries = &[ + make_entry("github", Some("foo"), None, &[]), + make_entry("gitlab", Some("foo"), None, &[]), + make_entry("gitlab", Some("bar"), None, &[]), + ]; + + assert!( + one_match(entries, &entries[0].0.id, None, None, 0), + "foo@github" + ); + assert!( + one_match(entries, &entries[1].0.id, None, None, 1), + "foo@gitlab" + ); + assert!( + one_match(entries, &entries[2].0.id, None, None, 2), + "bar@gitlab" + ); + + assert!( + one_match( + entries, + &entries[0].0.id.to_uppercase(), + None, + None, + 0 + ), + "foo@github" + ); + assert!( + one_match( + entries, + &entries[0].0.id.to_lowercase(), + None, + None, + 0 + ), + "foo@github" + ); + } + + #[test] + fn test_find_by_url_default() { + let entries = &[ + make_entry("one", None, None, &[("https://one.com/", None)]), + make_entry("two", None, None, &[("https://two.com/login", None)]), + make_entry( + "three", + None, + None, + &[("https://login.three.com/", None)], + ), + make_entry("four", None, None, &[("four.com", None)]), + make_entry( + "five", + None, + None, + &[("https://five.com:8080/", None)], + ), + make_entry("six", None, None, &[("six.com:8080", None)]), + ]; + + assert!(one_match(entries, "https://one.com/", None, None, 0), "one"); + assert!( + one_match(entries, "https://login.one.com/", None, None, 0), + "one" + ); + assert!( + one_match(entries, "https://one.com:443/", None, None, 0), + "one" + ); + assert!(no_matches(entries, "one.com", None, None), "one"); + assert!(no_matches(entries, "https", None, None), "one"); + assert!(no_matches(entries, "com", None, None), "one"); + assert!(no_matches(entries, "https://com/", None, None), "one"); + + assert!(one_match(entries, "https://two.com/", None, None, 1), "two"); + assert!( + one_match(entries, "https://two.com/other-page", None, None, 1), + "two" + ); + + assert!( + one_match(entries, "https://login.three.com/", None, None, 2), + "three" + ); + assert!( + no_matches(entries, "https://three.com/", None, None), + "three" + ); + + assert!( + one_match(entries, "https://four.com/", None, None, 3), + "four" + ); + + assert!( + one_match(entries, "https://five.com:8080/", None, None, 4), + "five" + ); + assert!(no_matches(entries, "https://five.com/", None, None), "five"); + + assert!( + one_match(entries, "https://six.com:8080/", None, None, 5), + "six" + ); + assert!(no_matches(entries, "https://six.com/", None, None), "six"); + } + + #[test] + fn test_find_by_url_domain() { + let entries = &[ + make_entry( + "one", + None, + None, + &[("https://one.com/", Some(rbw::api::UriMatchType::Domain))], + ), + make_entry( + "two", + None, + None, + &[( + "https://two.com/login", + Some(rbw::api::UriMatchType::Domain), + )], + ), + make_entry( + "three", + None, + None, + &[( + "https://login.three.com/", + Some(rbw::api::UriMatchType::Domain), + )], + ), + make_entry( + "four", + None, + None, + &[("four.com", Some(rbw::api::UriMatchType::Domain))], + ), + make_entry( + "five", + None, + None, + &[( + "https://five.com:8080/", + Some(rbw::api::UriMatchType::Domain), + )], + ), + make_entry( + "six", + None, + None, + &[("six.com:8080", Some(rbw::api::UriMatchType::Domain))], + ), + ]; + + assert!(one_match(entries, "https://one.com/", None, None, 0), "one"); + assert!( + one_match(entries, "https://login.one.com/", None, None, 0), + "one" + ); + assert!( + one_match(entries, "https://one.com:443/", None, None, 0), + "one" + ); + assert!(no_matches(entries, "one.com", None, None), "one"); + assert!(no_matches(entries, "https", None, None), "one"); + assert!(no_matches(entries, "com", None, None), "one"); + assert!(no_matches(entries, "https://com/", None, None), "one"); + + assert!(one_match(entries, "https://two.com/", None, None, 1), "two"); + assert!( + one_match(entries, "https://two.com/other-page", None, None, 1), + "two" + ); + + assert!( + one_match(entries, "https://login.three.com/", None, None, 2), + "three" + ); + assert!( + no_matches(entries, "https://three.com/", None, None), + "three" + ); + + assert!( + one_match(entries, "https://four.com/", None, None, 3), + "four" + ); + + assert!( + one_match(entries, "https://five.com:8080/", None, None, 4), + "five" + ); + assert!(no_matches(entries, "https://five.com/", None, None), "five"); + + assert!( + one_match(entries, "https://six.com:8080/", None, None, 5), + "six" + ); + assert!(no_matches(entries, "https://six.com/", None, None), "six"); + } + + #[test] + fn test_find_by_url_host() { + let entries = &[ + make_entry( + "one", + None, + None, + &[("https://one.com/", Some(rbw::api::UriMatchType::Host))], + ), + make_entry( + "two", + None, + None, + &[( + "https://two.com/login", + Some(rbw::api::UriMatchType::Host), + )], + ), + make_entry( + "three", + None, + None, + &[( + "https://login.three.com/", + Some(rbw::api::UriMatchType::Host), + )], + ), + make_entry( + "four", + None, + None, + &[("four.com", Some(rbw::api::UriMatchType::Host))], + ), + make_entry( + "five", + None, + None, + &[( + "https://five.com:8080/", + Some(rbw::api::UriMatchType::Host), + )], + ), + make_entry( + "six", + None, + None, + &[("six.com:8080", Some(rbw::api::UriMatchType::Host))], + ), + ]; + + assert!(one_match(entries, "https://one.com/", None, None, 0), "one"); + assert!( + no_matches(entries, "https://login.one.com/", None, None), + "one" + ); + assert!( + one_match(entries, "https://one.com:443/", None, None, 0), + "one" + ); + assert!(no_matches(entries, "one.com", None, None), "one"); + assert!(no_matches(entries, "https", None, None), "one"); + assert!(no_matches(entries, "com", None, None), "one"); + assert!(no_matches(entries, "https://com/", None, None), "one"); + + assert!(one_match(entries, "https://two.com/", None, None, 1), "two"); + assert!( + one_match(entries, "https://two.com/other-page", None, None, 1), + "two" + ); + + assert!( + one_match(entries, "https://login.three.com/", None, None, 2), + "three" + ); + assert!( + no_matches(entries, "https://three.com/", None, None), + "three" + ); + + assert!( + one_match(entries, "https://four.com/", None, None, 3), + "four" + ); + + assert!( + one_match(entries, "https://five.com:8080/", None, None, 4), + "five" + ); + assert!(no_matches(entries, "https://five.com/", None, None), "five"); + + assert!( + one_match(entries, "https://six.com:8080/", None, None, 5), + "six" + ); + assert!(no_matches(entries, "https://six.com/", None, None), "six"); + } + + #[test] + fn test_find_by_url_starts_with() { + let entries = &[ + make_entry( + "one", + None, + None, + &[( + "https://one.com/", + Some(rbw::api::UriMatchType::StartsWith), + )], + ), + make_entry( + "two", + None, + None, + &[( + "https://two.com/login", + Some(rbw::api::UriMatchType::StartsWith), + )], + ), + make_entry( + "three", + None, + None, + &[( + "https://login.three.com/", + Some(rbw::api::UriMatchType::StartsWith), + )], + ), + ]; + + assert!(one_match(entries, "https://one.com/", None, None, 0), "one"); + assert!( + no_matches(entries, "https://login.one.com/", None, None), + "one" + ); + assert!( + one_match(entries, "https://one.com:443/", None, None, 0), + "one" + ); + assert!(no_matches(entries, "one.com", None, None), "one"); + assert!(no_matches(entries, "https", None, None), "one"); + assert!(no_matches(entries, "com", None, None), "one"); + assert!(no_matches(entries, "https://com/", None, None), "one"); + + assert!( + one_match(entries, "https://two.com/login", None, None, 1), + "two" + ); + assert!( + one_match(entries, "https://two.com/login/sso", None, None, 1), + "two" + ); + assert!(no_matches(entries, "https://two.com/", None, None), "two"); + assert!( + no_matches(entries, "https://two.com/other-page", None, None), + "two" + ); + + assert!( + one_match(entries, "https://login.three.com/", None, None, 2), + "three" + ); + assert!( + no_matches(entries, "https://three.com/", None, None), + "three" + ); + } + + #[test] + fn test_find_by_url_exact() { + let entries = &[ + make_entry( + "one", + None, + None, + &[("https://one.com/", Some(rbw::api::UriMatchType::Exact))], + ), + make_entry( + "two", + None, + None, + &[( + "https://two.com/login", + Some(rbw::api::UriMatchType::Exact), + )], + ), + make_entry( + "three", + None, + None, + &[( + "https://login.three.com/", + Some(rbw::api::UriMatchType::Exact), + )], + ), + ]; + + assert!(one_match(entries, "https://one.com/", None, None, 0), "one"); + assert!( + no_matches(entries, "https://login.one.com/", None, None), + "one" + ); + assert!( + one_match(entries, "https://one.com:443/", None, None, 0), + "one" + ); + assert!(no_matches(entries, "one.com", None, None), "one"); + assert!(no_matches(entries, "https", None, None), "one"); + assert!(no_matches(entries, "com", None, None), "one"); + assert!(no_matches(entries, "https://com/", None, None), "one"); + + assert!( + one_match(entries, "https://two.com/login", None, None, 1), + "two" + ); + assert!( + no_matches(entries, "https://two.com/login/sso", None, None), + "two" + ); + assert!(no_matches(entries, "https://two.com/", None, None), "two"); + assert!( + no_matches(entries, "https://two.com/other-page", None, None), + "two" + ); + + assert!( + one_match(entries, "https://login.three.com/", None, None, 2), + "three" + ); + assert!( + no_matches(entries, "https://three.com/", None, None), + "three" + ); + } + + #[test] + fn test_find_by_url_regex() { + let entries = &[ + make_entry( + "one", + None, + None, + &[( + r"^https://one\.com/$", + Some(rbw::api::UriMatchType::RegularExpression), + )], + ), + make_entry( + "two", + None, + None, + &[( + r"^https://two\.com/(login|start)", + Some(rbw::api::UriMatchType::RegularExpression), + )], + ), + make_entry( + "three", + None, + None, + &[( + r"^https://(login\.)?three\.com/$", + Some(rbw::api::UriMatchType::RegularExpression), + )], + ), + ]; + + assert!(one_match(entries, "https://one.com/", None, None, 0), "one"); + assert!( + no_matches(entries, "https://login.one.com/", None, None), + "one" + ); + assert!( + one_match(entries, "https://one.com:443/", None, None, 0), + "one" + ); + assert!(no_matches(entries, "one.com", None, None), "one"); + assert!(no_matches(entries, "https", None, None), "one"); + assert!(no_matches(entries, "com", None, None), "one"); + assert!(no_matches(entries, "https://com/", None, None), "one"); + + assert!( + one_match(entries, "https://two.com/login", None, None, 1), + "two" + ); + assert!( + one_match(entries, "https://two.com/start", None, None, 1), + "two" + ); + assert!( + one_match(entries, "https://two.com/login/sso", None, None, 1), + "two" + ); + assert!(no_matches(entries, "https://two.com/", None, None), "two"); + assert!( + no_matches(entries, "https://two.com/other-page", None, None), + "two" + ); + + assert!( + one_match(entries, "https://login.three.com/", None, None, 2), + "three" + ); + assert!( + one_match(entries, "https://three.com/", None, None, 2), + "three" + ); + assert!( + no_matches(entries, "https://www.three.com/", None, None), + "three" + ); + } + + #[test] + fn test_find_by_url_never() { + let entries = &[ + make_entry( + "one", + None, + None, + &[("https://one.com/", Some(rbw::api::UriMatchType::Never))], + ), + make_entry( + "two", + None, + None, + &[( + "https://two.com/login", + Some(rbw::api::UriMatchType::Never), + )], + ), + make_entry( + "three", + None, + None, + &[( + "https://login.three.com/", + Some(rbw::api::UriMatchType::Never), + )], + ), + make_entry( + "four", + None, + None, + &[("four.com", Some(rbw::api::UriMatchType::Never))], + ), + make_entry( + "five", + None, + None, + &[( + "https://five.com:8080/", + Some(rbw::api::UriMatchType::Never), + )], + ), + make_entry( + "six", + None, + None, + &[("six.com:8080", Some(rbw::api::UriMatchType::Never))], + ), + ]; + + assert!(no_matches(entries, "https://one.com/", None, None), "one"); + assert!( + no_matches(entries, "https://login.one.com/", None, None), + "one" + ); + assert!( + no_matches(entries, "https://one.com:443/", None, None), + "one" + ); + assert!(no_matches(entries, "one.com", None, None), "one"); + assert!(no_matches(entries, "https", None, None), "one"); + assert!(no_matches(entries, "com", None, None), "one"); + assert!(no_matches(entries, "https://com/", None, None), "one"); + + assert!(no_matches(entries, "https://two.com/", None, None), "two"); + assert!( + no_matches(entries, "https://two.com/other-page", None, None), + "two" + ); + + assert!( + no_matches(entries, "https://login.three.com/", None, None), + "three" + ); + assert!( + no_matches(entries, "https://three.com/", None, None), + "three" + ); + + assert!(no_matches(entries, "https://four.com/", None, None), "four"); + + assert!( + no_matches(entries, "https://five.com:8080/", None, None), + "five" + ); + assert!(no_matches(entries, "https://five.com/", None, None), "five"); + + assert!( + no_matches(entries, "https://six.com:8080/", None, None), + "six" + ); + assert!(no_matches(entries, "https://six.com/", None, None), "six"); + } + + #[track_caller] fn one_match( entries: &[(rbw::db::Entry, DecryptedCipher)], - name: &str, + needle: &str, username: Option<&str>, folder: Option<&str>, idx: usize, ) -> bool { entries_eq( - &find_entry_raw(entries, name, username, folder).unwrap(), + &find_entry_raw( + entries, + &parse_needle(needle).unwrap(), + username, + folder, + ) + .unwrap(), &entries[idx], ) } + #[track_caller] fn no_matches( entries: &[(rbw::db::Entry, DecryptedCipher)], - name: &str, + needle: &str, username: Option<&str>, folder: Option<&str>, ) -> bool { - let res = find_entry_raw(entries, name, username, folder); + let res = find_entry_raw( + entries, + &parse_needle(needle).unwrap(), + username, + folder, + ); if let Err(e) = res { format!("{e}").contains("no entry found") } else { @@ -1957,13 +2775,19 @@ mod test { } } + #[track_caller] fn many_matches( entries: &[(rbw::db::Entry, DecryptedCipher)], - name: &str, + needle: &str, username: Option<&str>, folder: Option<&str>, ) -> bool { - let res = find_entry_raw(entries, name, username, folder); + let res = find_entry_raw( + entries, + &parse_needle(needle).unwrap(), + username, + folder, + ); if let Err(e) = res { format!("{e}").contains("multiple entries found") } else { @@ -1971,6 +2795,7 @@ mod test { } } + #[track_caller] fn entries_eq( a: &(rbw::db::Entry, DecryptedCipher), b: &(rbw::db::Entry, DecryptedCipher), @@ -1982,10 +2807,12 @@ mod test { name: &str, username: Option<&str>, folder: Option<&str>, + uris: &[(&str, Option<rbw::api::UriMatchType>)], ) -> (rbw::db::Entry, DecryptedCipher) { + let id = uuid::Uuid::new_v4(); ( rbw::db::Entry { - id: "irrelevant".to_string(), + id: id.to_string(), org_id: None, folder: folder.map(|_| "encrypted folder name".to_string()), folder_id: None, @@ -1995,7 +2822,13 @@ mod test { "this is the encrypted username".to_string() }), password: None, - uris: vec![], + uris: uris + .iter() + .map(|(_, match_type)| rbw::db::Uri { + uri: "this is the encrypted uri".to_string(), + match_type: *match_type, + }) + .collect(), totp: None, }, fields: vec![], @@ -2003,14 +2836,21 @@ mod test { history: vec![], }, DecryptedCipher { - id: "irrelevant".to_string(), + id: id.to_string(), folder: folder.map(std::string::ToString::to_string), name: name.to_string(), data: DecryptedData::Login { username: username.map(std::string::ToString::to_string), password: None, totp: None, - uris: None, + uris: Some( + uris.iter() + .map(|(uri, match_type)| DecryptedUri { + uri: (*uri).to_string(), + match_type: *match_type, + }) + .collect(), + ), }, fields: vec![], notes: None, diff --git a/src/bin/rbw/main.rs b/src/bin/rbw/main.rs index 72e4220..2fb96bf 100644 --- a/src/bin/rbw/main.rs +++ b/src/bin/rbw/main.rs @@ -71,8 +71,8 @@ enum Opt { #[command(about = "Display the password for a given entry")] Get { - #[arg(help = "Name or UUID of the entry to display")] - name: String, + #[arg(help = "Name, URI or UUID of the entry to display", value_parser = commands::parse_needle)] + needle: commands::Needle, #[arg(help = "Username of the entry to display")] user: Option<String>, #[arg(long, help = "Folder name to search in")] @@ -87,14 +87,19 @@ enum Opt { clipboard: bool, }, - #[command(about = "Display the authenticator code for a given entry")] + #[command( + about = "Display the authenticator code for a given entry", + visible_alias = "totp" + )] Code { - #[arg(help = "Name or UUID of the entry to display")] - name: String, + #[arg(help = "Name, URI or UUID of the entry to display", value_parser = commands::parse_needle)] + needle: commands::Needle, #[arg(help = "Username of the entry to display")] user: Option<String>, #[arg(long, help = "Folder name to search in")] folder: Option<String>, + #[structopt(long, help = "Copy result to clipboard")] + clipboard: bool, }, #[command( @@ -318,7 +323,7 @@ fn main() { Opt::Sync => commands::sync(), Opt::List { fields } => commands::list(fields), Opt::Get { - name, + needle, user, folder, field, @@ -326,7 +331,7 @@ fn main() { raw, clipboard, } => commands::get( - name, + needle, user.as_deref(), folder.as_deref(), field.as_deref(), @@ -334,9 +339,17 @@ fn main() { *raw, *clipboard, ), - Opt::Code { name, user, folder } => { - commands::code(name, user.as_deref(), folder.as_deref()) - } + Opt::Code { + needle, + user, + folder, + clipboard, + } => commands::code( + needle, + user.as_deref(), + folder.as_deref(), + *clipboard, + ), Opt::Add { name, user, @@ -147,8 +147,10 @@ pub enum EntryData { serde::Serialize, serde::Deserialize, Debug, Clone, Eq, PartialEq, )] pub struct Field { + pub ty: crate::api::FieldType, pub name: Option<String>, pub value: Option<String>, + pub linked_id: Option<crate::api::LinkedIdType>, } #[derive( diff --git a/src/dirs.rs b/src/dirs.rs index e838e12..2fa6e50 100644 --- a/src/dirs.rs +++ b/src/dirs.rs @@ -108,7 +108,7 @@ fn runtime_dir() -> std::path::PathBuf { "{}/{}-{}", std::env::temp_dir().to_string_lossy(), &profile(), - nix::unistd::getuid().as_raw() + rustix::process::getuid().as_raw() ) .into() }, diff --git a/src/error.rs b/src/error.rs index 8a3b5e2..db0503a 100644 --- a/src/error.rs +++ b/src/error.rs @@ -15,6 +15,9 @@ pub enum Error { file: std::path::PathBuf, }, + #[error("failed to create reqwest client")] + CreateReqwestClient { source: reqwest::Error }, + #[error("failed to decrypt")] Decrypt { source: block_padding::UnpadError }, @@ -127,12 +130,6 @@ pub enum Error { file: std::path::PathBuf, }, - #[error("failed to load client cert from {}", .file.display())] - LoadClientCertReqwest { - source: reqwest::Error, - file: std::path::PathBuf, - }, - #[error("invalid padding")] Padding, diff --git a/src/identity.rs b/src/identity.rs index 7836a11..fd46b85 100644 --- a/src/identity.rs +++ b/src/identity.rs @@ -17,6 +17,8 @@ impl Identity { memory: Option<u32>, parallelism: Option<u32>, ) -> Result<Self> { + let email = email.trim().to_lowercase(); + let iterations = std::num::NonZeroU32::new(iterations) .ok_or(Error::Pbkdf2ZeroIterations)?; |