aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md7
-rw-r--r--Cargo.lock449
-rw-r--r--Cargo.toml18
-rw-r--r--README.md8
-rwxr-xr-xbin/git-credential-rbw34
-rwxr-xr-xbin/rbw-fzf2
-rw-r--r--src/actions.rs33
-rw-r--r--src/api.rs76
-rw-r--r--src/bin/rbw-agent/actions.rs109
-rw-r--r--src/bin/rbw-agent/agent.rs8
-rw-r--r--src/bin/rbw/actions.rs4
-rw-r--r--src/bin/rbw/commands.rs47
-rw-r--r--src/bin/rbw/main.rs33
-rw-r--r--src/cipherstring.rs116
-rw-r--r--src/config.rs17
-rw-r--r--src/edit.rs2
-rw-r--r--src/error.rs9
-rw-r--r--src/lib.rs1
-rw-r--r--src/locked.rs37
-rw-r--r--src/pinentry.rs10
-rw-r--r--src/protocol.rs1
21 files changed, 659 insertions, 362 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3b6fd96..e34f769 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,12 @@
# Changelog
+## [1.4.0] - 2021-10-27
+
+### Fixed
+
+* Add `rbw register` to allow `rbw` to work with the official Bitwarden server
+ again - see the README for details (#71)
+
## [1.3.0] - 2021-07-05
### Changed
diff --git a/Cargo.lock b/Cargo.lock
index cc2277a..19d9f83 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1,10 +1,12 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
+version = 3
+
[[package]]
name = "aes"
-version = "0.7.4"
+version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "495ee669413bfbe9e8cace80f4d3d78e6d8c8d99579f97fb93bde351b185f2d4"
+checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8"
dependencies = [
"cfg-if",
"cipher",
@@ -32,9 +34,9 @@ dependencies = [
[[package]]
name = "anyhow"
-version = "1.0.41"
+version = "1.0.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "15af2628f6890fe2609a3b91bef4c83450512802e59489f9c1cb1fa5df064a61"
+checksum = "61604a8f862e1d5c3229fdd78f8b02c68dcf73a4c4b05fd636d12240aaa242c1"
[[package]]
name = "arrayvec"
@@ -44,9 +46,9 @@ checksum = "be4dc07131ffa69b8072d35f5007352af944213cde02545e2103680baed38fcd"
[[package]]
name = "async-trait"
-version = "0.1.50"
+version = "0.1.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b98e84bbb4cbcdd97da190ba0c58a1bb0de2c1fdf67d159e192ed766aeca722"
+checksum = "44318e776df68115a881de9a8fd1b9e53368d7a4a5ce4cc48517da3393233a5e"
dependencies = [
"proc-macro2",
"quote",
@@ -90,15 +92,15 @@ checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
[[package]]
name = "base64ct"
-version = "1.0.0"
+version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d0d27fb6b6f1e43147af148af49d49329413ba781aa0d5e10979831c210173b5"
+checksum = "8a32fd6af2b5827bce66c29053ba0e7c42b9dcab01835835058558c10851a46b"
[[package]]
name = "bitflags"
-version = "1.2.1"
+version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "block-buffer"
@@ -133,9 +135,9 @@ checksum = "5988cb1d626264ac94100be357308f29ff7cbdd3b36bda27f450a4ee3f713426"
[[package]]
name = "bumpalo"
-version = "3.7.0"
+version = "3.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c59e7af012c713f529e7a3ee57ce9b31ddd858d4b512923602f74608b009631"
+checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c"
[[package]]
name = "byteorder"
@@ -145,15 +147,15 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "bytes"
-version = "1.0.1"
+version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040"
+checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8"
[[package]]
name = "cc"
-version = "1.0.68"
+version = "1.0.71"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787"
+checksum = "79c2681d6594606957bbb8631c4b90a7fcaaa72cdb714743a437b156d6a7eedd"
[[package]]
name = "cfg-if"
@@ -162,16 +164,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
-name = "chrono"
-version = "0.4.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
-dependencies = [
- "num-integer",
- "num-traits",
-]
-
-[[package]]
name = "cipher"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -197,10 +189,16 @@ dependencies = [
]
[[package]]
+name = "const-oid"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9d6f2aa4d0537bcc1c74df8755072bd31c1ef1a3a1b85a68e8404a8c353b7b8b"
+
+[[package]]
name = "core-foundation"
-version = "0.9.1"
+version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0a89e2ae426ea83155dccf10c0fa6b1463ef6d5fcb44cee0b224a408fa640a62"
+checksum = "6888e10551bb93e424d8df1d07f1a8b4fceb0001a3a4b048bfc47554946f47b3"
dependencies = [
"core-foundation-sys",
"libc",
@@ -208,24 +206,35 @@ dependencies = [
[[package]]
name = "core-foundation-sys"
-version = "0.8.2"
+version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b"
+checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
[[package]]
name = "cpufeatures"
-version = "0.1.5"
+version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "66c99696f6c9dd7f35d486b9d04d7e6e202aa3e8c40d553f2fdf5e7e0c6a71ef"
+checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469"
dependencies = [
"libc",
]
[[package]]
+name = "crypto-bigint"
+version = "0.2.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f83bd3bb4314701c568e340cd8cf78c975aa0ca79e03d3f6d1677d5b0c9c0c03"
+dependencies = [
+ "generic-array",
+ "rand_core",
+ "subtle",
+]
+
+[[package]]
name = "crypto-mac"
-version = "0.11.0"
+version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "25fab6889090c8133f3deb8f73ba3c65a7f456f66436fc012a1b1e272b1e103e"
+checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714"
dependencies = [
"generic-array",
"subtle",
@@ -242,6 +251,16 @@ dependencies = [
]
[[package]]
+name = "der"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28e98c534e9c8a0483aa01d6f6913bc063de254311bd267c9cf535e9b70e15b2"
+dependencies = [
+ "const-oid",
+ "crypto-bigint",
+]
+
+[[package]]
name = "digest"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -252,9 +271,9 @@ dependencies = [
[[package]]
name = "directories"
-version = "3.0.2"
+version = "4.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e69600ff1703123957937708eb27f7a564e48885c537782722ed0ba3189ce1d7"
+checksum = "f51c5d4ddabd36886dd3e1438cb358cdcb0d7c499cb99cb4ac2e38e18b5cb210"
dependencies = [
"dirs-sys",
]
@@ -272,18 +291,18 @@ dependencies = [
[[package]]
name = "encoding_rs"
-version = "0.8.28"
+version = "0.8.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "80df024fbc5ac80f87dfef0d9f5209a252f2a497f7f42944cff24d8253cac065"
+checksum = "a74ea89a0a1b98f6332de42c95baff457ada66d1cb4030f9ff151b2041a1c746"
dependencies = [
"cfg-if",
]
[[package]]
name = "env_logger"
-version = "0.8.4"
+version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3"
+checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3"
dependencies = [
"atty",
"humantime",
@@ -310,30 +329,30 @@ dependencies = [
[[package]]
name = "futures-channel"
-version = "0.3.15"
+version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e682a68b29a882df0545c143dc3646daefe80ba479bcdede94d5a703de2871e2"
+checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888"
dependencies = [
"futures-core",
]
[[package]]
name = "futures-core"
-version = "0.3.15"
+version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0402f765d8a89a26043b889b26ce3c4679d268fa6bb22cd7c6aad98340e179d1"
+checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d"
[[package]]
name = "futures-io"
-version = "0.3.15"
+version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "acc499defb3b348f8d8f3f66415835a9131856ff7714bf10dadfc4ec4bdb29a1"
+checksum = "522de2a0fe3e380f1bc577ba0474108faf3f6b18321dbf60b3b9c39a75073377"
[[package]]
name = "futures-macro"
-version = "0.3.15"
+version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4c40298486cdf52cc00cd6d6987892ba502c7656a16a4192a9992b1ccedd121"
+checksum = "18e4a4b95cea4b4ccbcf1c5675ca7c4ee4e9e75eb79944d07defde18068f79bb"
dependencies = [
"autocfg 1.0.1",
"proc-macro-hack",
@@ -344,21 +363,21 @@ dependencies = [
[[package]]
name = "futures-sink"
-version = "0.3.15"
+version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a57bead0ceff0d6dde8f465ecd96c9338121bb7717d3e7b108059531870c4282"
+checksum = "36ea153c13024fe480590b3e3d4cad89a0cfacecc24577b68f86c6ced9c2bc11"
[[package]]
name = "futures-task"
-version = "0.3.15"
+version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a16bef9fc1a4dddb5bee51c989e3fbba26569cbb0e31f5b303c184e3dd33dae"
+checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99"
[[package]]
name = "futures-util"
-version = "0.3.15"
+version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "feb5c238d27e2bf94ffdfd27b2c29e3df4a68c4193bb6427384259e2bf191967"
+checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481"
dependencies = [
"autocfg 1.0.1",
"futures-core",
@@ -396,9 +415,9 @@ dependencies = [
[[package]]
name = "h2"
-version = "0.3.3"
+version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "825343c4eef0b63f541f8903f395dc5beb362a979b5799a84062527ef1e37726"
+checksum = "7fd819562fcebdac5afc5c113c3ec36f902840b70fd4fc458799c8ce4607ae55"
dependencies = [
"bytes",
"fnv",
@@ -459,9 +478,9 @@ dependencies = [
[[package]]
name = "http"
-version = "0.2.4"
+version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "527e8c9ac747e28542699a951517aa9a6945af506cd1f2e1b53a576c17b6cc11"
+checksum = "1323096b05d41827dadeaee54c9981958c0f94e670bc94ed80037d1a7b8b186b"
dependencies = [
"bytes",
"fnv",
@@ -470,9 +489,9 @@ dependencies = [
[[package]]
name = "http-body"
-version = "0.4.2"
+version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "60daa14be0e0786db0f03a9e57cb404c9d756eed2b6c62b9ea98ec5743ec75a9"
+checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6"
dependencies = [
"bytes",
"http",
@@ -481,9 +500,9 @@ dependencies = [
[[package]]
name = "httparse"
-version = "1.4.1"
+version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f3a87b616e37e93c22fb19bcd386f02f3af5ea98a25670ad0fce773de23c5e68"
+checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503"
[[package]]
name = "httpdate"
@@ -499,9 +518,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "hyper"
-version = "0.14.9"
+version = "0.14.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07d6baa1b441335f3ce5098ac421fb6547c46dda735ca1bc6d0153c838f9dd83"
+checksum = "2b91bb1f221b6ea1f1e4371216b70f40748774c2fb5971b450c07773fb92d26b"
dependencies = [
"bytes",
"futures-channel",
@@ -559,9 +578,9 @@ dependencies = [
[[package]]
name = "instant"
-version = "0.1.9"
+version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec"
+checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
dependencies = [
"cfg-if",
]
@@ -574,15 +593,15 @@ checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9"
[[package]]
name = "itoa"
-version = "0.4.7"
+version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
+checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
[[package]]
name = "js-sys"
-version = "0.3.51"
+version = "0.3.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "83bdfbace3a0e81a4253f73b49e960b053e396a11012cbd49b9b74d6a2b67062"
+checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84"
dependencies = [
"wasm-bindgen",
]
@@ -598,9 +617,9 @@ dependencies = [
[[package]]
name = "libc"
-version = "0.2.97"
+version = "0.2.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6"
+checksum = "869d572136620d55835903746bcb5cdc54cb2851fd0aeec53220b4bb65ef3013"
[[package]]
name = "libm"
@@ -610,9 +629,9 @@ checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a"
[[package]]
name = "lock_api"
-version = "0.4.4"
+version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb"
+checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109"
dependencies = [
"scopeguard",
]
@@ -637,15 +656,15 @@ dependencies = [
[[package]]
name = "matches"
-version = "0.1.8"
+version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
+checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
[[package]]
name = "memchr"
-version = "2.4.0"
+version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
+checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
[[package]]
name = "memoffset"
@@ -664,9 +683,9 @@ checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
[[package]]
name = "mio"
-version = "0.7.13"
+version = "0.7.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8c2bdb6314ec10835cd3293dd268473a835c02b7b352e788be788b3c6ca6bb16"
+checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc"
dependencies = [
"libc",
"log",
@@ -686,9 +705,9 @@ dependencies = [
[[package]]
name = "nix"
-version = "0.21.0"
+version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c3728fec49d363a50a8828a190b379a446cc5cf085c06259bbbeb34447e4ec7"
+checksum = "f305c2c2e4c39a82f7bf0bf65fb557f9070ce06781d4f2454295cc34b1c43188"
dependencies = [
"bitflags",
"cc",
@@ -707,17 +726,6 @@ dependencies = [
]
[[package]]
-name = "num-bigint"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4e0d047c1062aa51e256408c560894e5251f08925980e53cf1aa5bd00eec6512"
-dependencies = [
- "autocfg 1.0.1",
- "num-integer",
- "num-traits",
-]
-
-[[package]]
name = "num-bigint-dig"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -796,9 +804,9 @@ checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a"
[[package]]
name = "parking_lot"
-version = "0.11.1"
+version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb"
+checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
dependencies = [
"instant",
"lock_api",
@@ -807,9 +815,9 @@ dependencies = [
[[package]]
name = "parking_lot_core"
-version = "0.8.3"
+version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018"
+checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"
dependencies = [
"cfg-if",
"instant",
@@ -821,9 +829,9 @@ dependencies = [
[[package]]
name = "password-hash"
-version = "0.2.1"
+version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1a5d4e9c205d2c1ae73b84aab6240e98218c0e72e63b50422cfb2d1ca952282"
+checksum = "1d791538a6dcc1e7cb7fe6f6b58aca40e7f79403c45b2bc274008b5e647af1d8"
dependencies = [
"base64ct",
"rand_core",
@@ -859,11 +867,10 @@ checksum = "7f0b59668fe80c5afe998f0c0bf93322bf2cd66cafeeb80581f291716f3467f2"
[[package]]
name = "pbkdf2"
-version = "0.8.0"
+version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d95f5254224e617595d2cc3cc73ff0a5eaf2637519e25f03388154e9378b6ffa"
+checksum = "f05894bce6a1ba4be299d0c5f29563e08af2bc18bb7d48313113bed71e904739"
dependencies = [
- "base64ct",
"crypto-mac",
"hmac",
"password-hash",
@@ -871,14 +878,12 @@ dependencies = [
]
[[package]]
-name = "pem"
-version = "0.8.3"
+name = "pem-rfc7468"
+version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fd56cbd21fea48d0c440b41cd69c589faacade08c992d9a54e471b79d0fd13eb"
+checksum = "8f22eb0e3c593294a99e9ff4b24cf6b752d43f193aa4415fe5077c159996d497"
dependencies = [
- "base64",
- "once_cell",
- "regex",
+ "base64ct",
]
[[package]]
@@ -900,10 +905,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
+name = "pkcs1"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "116bee8279d783c0cf370efa1a94632f2108e5ef0bb32df31f051647810a4e2c"
+dependencies = [
+ "der",
+ "pem-rfc7468",
+ "zeroize",
+]
+
+[[package]]
+name = "pkcs8"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee3ef9b64d26bad0536099c816c6734379e45bbd5f14798def6809e5cc350447"
+dependencies = [
+ "der",
+ "pem-rfc7468",
+ "pkcs1",
+ "spki",
+ "zeroize",
+]
+
+[[package]]
name = "ppv-lite86"
-version = "0.2.10"
+version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
+checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba"
[[package]]
name = "proc-macro-error"
@@ -943,18 +972,18 @@ checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086"
[[package]]
name = "proc-macro2"
-version = "1.0.27"
+version = "1.0.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038"
+checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
-version = "1.0.9"
+version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
+checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
dependencies = [
"proc-macro2",
]
@@ -1001,7 +1030,7 @@ dependencies = [
[[package]]
name = "rbw"
-version = "1.3.0"
+version = "1.4.0"
dependencies = [
"aes",
"anyhow",
@@ -1047,9 +1076,9 @@ dependencies = [
[[package]]
name = "redox_syscall"
-version = "0.2.9"
+version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ab49abadf3f9e1c4bc499e8845e152ad87d2ad2d30371841171169e9d75feee"
+checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
dependencies = [
"bitflags",
]
@@ -1083,9 +1112,9 @@ checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
[[package]]
name = "region"
-version = "2.2.0"
+version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "877e54ea2adcd70d80e9179344c97f93ef0dffd6b03e1f4529e6e83ab2fa9ae0"
+checksum = "76e189c2369884dce920945e2ddf79b3dff49e071a167dd1817fa9c4c00d512e"
dependencies = [
"bitflags",
"libc",
@@ -1104,9 +1133,9 @@ dependencies = [
[[package]]
name = "reqwest"
-version = "0.11.4"
+version = "0.11.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "246e9f61b9bb77df069a947682be06e31ac43ea37862e244a69f177694ea6d22"
+checksum = "66d2927ca2f685faf0fc620ac4834690d29e7abb153add10f5812eef20b5e280"
dependencies = [
"base64",
"bytes",
@@ -1155,9 +1184,9 @@ dependencies = [
[[package]]
name = "rsa"
-version = "0.4.0"
+version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68ef841a26fc5d040ced0417c6c6a64ee851f42489df11cdf0218e545b6f8d28"
+checksum = "e05c2603e2823634ab331437001b411b9ed11660fbc4066f3908c84a9439260d"
dependencies = [
"byteorder",
"digest",
@@ -1166,9 +1195,9 @@ dependencies = [
"num-integer",
"num-iter",
"num-traits",
- "pem",
+ "pkcs1",
+ "pkcs8",
"rand",
- "simple_asn1",
"subtle",
"zeroize",
]
@@ -1232,9 +1261,9 @@ dependencies = [
[[package]]
name = "security-framework"
-version = "2.3.1"
+version = "2.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23a2ac85147a3a11d77ecf1bc7166ec0b92febfa4461c37944e180f319ece467"
+checksum = "525bc1abfda2e1998d152c45cf13e696f76d0a4972310b22fac1658b05df7c87"
dependencies = [
"bitflags",
"core-foundation",
@@ -1245,9 +1274,9 @@ dependencies = [
[[package]]
name = "security-framework-sys"
-version = "2.3.0"
+version = "2.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e4effb91b4b8b6fb7732e670b6cee160278ff8e6bf485c7805d9e319d76e284"
+checksum = "a9dd14d83160b528b7bfd66439110573efcfbe281b17fc2ca9f39f550d619c7e"
dependencies = [
"core-foundation-sys",
"libc",
@@ -1255,18 +1284,18 @@ dependencies = [
[[package]]
name = "serde"
-version = "1.0.126"
+version = "1.0.130"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03"
+checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.126"
+version = "1.0.130"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43"
+checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b"
dependencies = [
"proc-macro2",
"quote",
@@ -1275,9 +1304,9 @@ dependencies = [
[[package]]
name = "serde_json"
-version = "1.0.64"
+version = "1.0.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79"
+checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8"
dependencies = [
"itoa",
"ryu",
@@ -1286,9 +1315,9 @@ dependencies = [
[[package]]
name = "serde_path_to_error"
-version = "0.1.4"
+version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "42f6109f0506e20f7e0f910e51a0079acf41da8e0694e6442527c4ddf5a2b158"
+checksum = "d0421d4f173fab82d72d6babf36d57fae38b994ca5c2d78e704260ba6d12118b"
dependencies = [
"serde",
]
@@ -1318,9 +1347,9 @@ dependencies = [
[[package]]
name = "sha-1"
-version = "0.9.6"
+version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8c4cfa741c5832d0ef7fab46cabed29c2aae926db0b11bb2069edd8db5e64e16"
+checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6"
dependencies = [
"block-buffer",
"cfg-if",
@@ -1331,9 +1360,9 @@ dependencies = [
[[package]]
name = "sha2"
-version = "0.9.5"
+version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b362ae5752fd2137731f9fa25fd4d9058af34666ca1966fb969119cc35719f12"
+checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa"
dependencies = [
"block-buffer",
"cfg-if",
@@ -1352,34 +1381,22 @@ dependencies = [
]
[[package]]
-name = "simple_asn1"
-version = "0.5.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8eb4ea60fb301dc81dfc113df680571045d375ab7345d171c5dc7d7e13107a80"
-dependencies = [
- "chrono",
- "num-bigint",
- "num-traits",
- "thiserror",
-]
-
-[[package]]
name = "slab"
-version = "0.4.3"
+version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f173ac3d1a7e3b28003f40de0b5ce7fe2710f9b9dc3fc38664cebee46b3b6527"
+checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5"
[[package]]
name = "smallvec"
-version = "1.6.1"
+version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
+checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309"
[[package]]
name = "socket2"
-version = "0.4.0"
+version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9e3dfc207c526015c632472a77be09cf1b6e46866581aecae5cc38fb4235dea2"
+checksum = "5dc90fe6c7be1a323296982db1836d1ea9e47b6839496dde9a541bc496df3516"
dependencies = [
"libc",
"winapi",
@@ -1392,6 +1409,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
[[package]]
+name = "spki"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c01a0c15da1b0b0e1494112e7af814a678fec9bd157881b49beac661e9b6f32"
+dependencies = [
+ "der",
+]
+
+[[package]]
name = "strsim"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1399,9 +1425,9 @@ checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]]
name = "structopt"
-version = "0.3.22"
+version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "69b041cdcb67226aca307e6e7be44c8806423d83e018bd662360a93dabce4d71"
+checksum = "40b9788f4202aa75c240ecc9c15c65185e6a39ccdeb0fd5d008b98825464c87c"
dependencies = [
"clap",
"lazy_static",
@@ -1411,9 +1437,9 @@ dependencies = [
[[package]]
name = "structopt-derive"
-version = "0.4.15"
+version = "0.4.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7813934aecf5f51a54775e00068c237de98489463968231a51746bbbc03f9c10"
+checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0"
dependencies = [
"heck",
"proc-macro-error",
@@ -1424,15 +1450,15 @@ dependencies = [
[[package]]
name = "subtle"
-version = "2.4.0"
+version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2"
+checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
[[package]]
name = "syn"
-version = "1.0.73"
+version = "1.0.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f71489ff30030d2ae598524f61326b902466f72a0fb1a8564c001cc63425bcc7"
+checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966"
dependencies = [
"proc-macro2",
"quote",
@@ -1441,9 +1467,9 @@ dependencies = [
[[package]]
name = "synstructure"
-version = "0.12.4"
+version = "0.12.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701"
+checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f"
dependencies = [
"proc-macro2",
"quote",
@@ -1496,18 +1522,18 @@ dependencies = [
[[package]]
name = "thiserror"
-version = "1.0.26"
+version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93119e4feac1cbe6c798c34d3a53ea0026b0b1de6a120deef895137c0529bfe2"
+checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
-version = "1.0.26"
+version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745"
+checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
dependencies = [
"proc-macro2",
"quote",
@@ -1516,9 +1542,9 @@ dependencies = [
[[package]]
name = "tinyvec"
-version = "1.2.0"
+version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b5220f05bb7de7f3f53c7c065e1199b3172696fe2db9f9c4d8ad9b4ee74c342"
+checksum = "f83b2a3d4d9091d0abd7eba4dc2710b1718583bd4d8992e2190720ea38f391f7"
dependencies = [
"tinyvec_macros",
]
@@ -1531,9 +1557,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "tokio"
-version = "1.8.0"
+version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "570c2eb13b3ab38208130eccd41be92520388791207fde783bda7c1e8ace28d4"
+checksum = "c2c2416fdedca8443ae44b4527de1ea633af61d8f7169ffa6e72c5b53d24efcc"
dependencies = [
"autocfg 1.0.1",
"bytes",
@@ -1551,9 +1577,9 @@ dependencies = [
[[package]]
name = "tokio-macros"
-version = "1.2.0"
+version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c49e3df43841dafb86046472506755d8501c5615673955f6aa17181125d13c37"
+checksum = "b2dd85aeaba7b68df939bd357c6afb36c87951be9e80bf9c859f2fc3e9fca0fd"
dependencies = [
"proc-macro2",
"quote",
@@ -1573,9 +1599,9 @@ dependencies = [
[[package]]
name = "tokio-util"
-version = "0.6.7"
+version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1caa0b0c8d94a049db56b5acf8cba99dc0623aab1b26d5b5f5e2d945846b3592"
+checksum = "08d3725d3efa29485e87311c5b699de63cde14b00ed4d256b8318aa30ca452cd"
dependencies = [
"bytes",
"futures-core",
@@ -1605,9 +1631,9 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6"
[[package]]
name = "tracing"
-version = "0.1.26"
+version = "0.1.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09adeb8c97449311ccd28a427f96fb563e7fd31aabf994189879d9da2394b89d"
+checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105"
dependencies = [
"cfg-if",
"pin-project-lite",
@@ -1616,9 +1642,9 @@ dependencies = [
[[package]]
name = "tracing-core"
-version = "0.1.18"
+version = "0.1.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9ff14f98b1a4b289c6248a023c1c2fa1491062964e9fed67ab29c4e4da4a052"
+checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4"
dependencies = [
"lazy_static",
]
@@ -1631,18 +1657,15 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
[[package]]
name = "typenum"
-version = "1.13.0"
+version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06"
+checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec"
[[package]]
name = "unicode-bidi"
-version = "0.3.5"
+version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eeb8be209bb1c96b7c177c7420d26e04eccacb0eeae6b980e35fcb74678107e0"
-dependencies = [
- "matches",
-]
+checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f"
[[package]]
name = "unicode-normalization"
@@ -1661,9 +1684,9 @@ checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
[[package]]
name = "unicode-width"
-version = "0.1.8"
+version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
+checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
[[package]]
name = "unicode-xid"
@@ -1728,21 +1751,19 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]]
name = "wasm-bindgen"
-version = "0.2.74"
+version = "0.2.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d54ee1d4ed486f78874278e63e4069fc1ab9f6a18ca492076ffb90c5eb2997fd"
+checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce"
dependencies = [
"cfg-if",
- "serde",
- "serde_json",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
-version = "0.2.74"
+version = "0.2.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3b33f6a0694ccfea53d94db8b2ed1c3a8a4c86dd936b13b9f0a15ec4a451b900"
+checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b"
dependencies = [
"bumpalo",
"lazy_static",
@@ -1755,9 +1776,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-futures"
-version = "0.4.24"
+version = "0.4.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5fba7978c679d53ce2d0ac80c8c175840feb849a161664365d1287b41f2e67f1"
+checksum = "8e8d7523cb1f2a4c96c1317ca690031b714a51cc14e05f712446691f413f5d39"
dependencies = [
"cfg-if",
"js-sys",
@@ -1767,9 +1788,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
-version = "0.2.74"
+version = "0.2.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "088169ca61430fe1e58b8096c24975251700e7b1f6fd91cc9d59b04fb9b18bd4"
+checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -1777,9 +1798,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
-version = "0.2.74"
+version = "0.2.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be2241542ff3d9f241f5e2cb6dd09b37efe786df8851c54957683a49f0987a97"
+checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab"
dependencies = [
"proc-macro2",
"quote",
@@ -1790,15 +1811,15 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
-version = "0.2.74"
+version = "0.2.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d7cff876b8f18eed75a66cf49b65e7f967cb354a7aa16003fb55dbfd25b44b4f"
+checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc"
[[package]]
name = "web-sys"
-version = "0.3.51"
+version = "0.3.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e828417b379f3df7111d3a2a9e5753706cae29c41f7c4029ee9fd77f3e09e582"
+checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb"
dependencies = [
"js-sys",
"wasm-bindgen",
@@ -1856,18 +1877,18 @@ dependencies = [
[[package]]
name = "zeroize"
-version = "1.3.0"
+version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd"
+checksum = "bf68b08513768deaa790264a7fac27a58cbf2705cfcdc9448362229217d7e970"
dependencies = [
"zeroize_derive",
]
[[package]]
name = "zeroize_derive"
-version = "1.1.0"
+version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a2c1e130bebaeab2f23886bf9acbaca14b092408c452543c857f66399cd6dab1"
+checksum = "bdff2024a851a322b08f179173ae2ba620445aef1e838f0c196820eade4ae0c7"
dependencies = [
"proc-macro2",
"quote",
diff --git a/Cargo.toml b/Cargo.toml
index cc20fe9..a9d0f19 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "rbw"
-version = "1.3.0"
+version = "1.4.0"
authors = ["Jesse Luehrs <doy@tozt.net>"]
edition = "2018"
@@ -21,21 +21,21 @@ base64 = "0.13"
block-modes = "0.8"
block-padding = "0.2"
daemonize = "0.4"
-directories = "3.0"
-env_logger = "0.8"
+directories = "4.0"
+env_logger = "0.9"
hkdf = "0.11"
hmac = { version = "0.11", features = ["std"] }
humantime = "2.1"
libc = "0.2"
log = "0.4"
-nix = "0.21"
+nix = "0.23"
paw = "1.0"
-pbkdf2 = "0.8"
+pbkdf2 = "0.9"
percent-encoding = "2.1"
rand = "0.8"
-region = "2.2"
+region = "3.0"
reqwest = { version = "0.11", default-features = false, features = ["blocking", "json", "rustls-tls-native-roots"] }
-rsa = "0.4"
+rsa = "0.5"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
serde_path_to_error = "0.1"
@@ -47,11 +47,11 @@ tempfile = "3.2"
term_size = "0.3"
textwrap = "0.11"
thiserror = "1.0"
-tokio = { version = "1.8", features = ["full"] }
+tokio = { version = "1.12", features = ["full"] }
totp-lite = "1.0"
url = "2.2"
uuid = { version = "0.8", features = ["v4"] }
-zeroize = "1.3"
+zeroize = "1.4"
[package.metadata.deb]
depends = "pinentry"
diff --git a/README.md b/README.md
index bc493a0..5f35d3b 100644
--- a/README.md
+++ b/README.md
@@ -84,6 +84,14 @@ 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`.
+*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
+(see [this issue](https://github.com/bitwarden/cli/issues/383) for details). In
+order to use `rbw` with the official Bitwarden server, you will need to first
+run `rbw register` to register each device using `rbw` with the Bitwarden
+server. This will prompt you for your personal API key which you can find using
+the instructions [here](https://bitwarden.com/help/article/personal-api-key/).
+
## Related projects
* [rofi-rbw](https://github.com/fdw/rofi-rbw): A rofi frontend for Bitwarden
diff --git a/bin/git-credential-rbw b/bin/git-credential-rbw
new file mode 100755
index 0000000..102aade
--- /dev/null
+++ b/bin/git-credential-rbw
@@ -0,0 +1,34 @@
+#!/bin/sh
+set -f
+
+[ "$1" = get ] || exit
+
+while read -r line; do
+ case $line in
+ protocol=*)
+ protocol=${line#*=} ;;
+ host=*)
+ host=${line#*=} ;;
+ username=*)
+ user=${line#*=} ;;
+ esac
+done
+
+output=
+#shellcheck disable=2154
+for arg in \
+ "${protocol:+$protocol://}$host" \
+ "$host" \
+ "${host2=${host%.*}}" \
+ "${host2#*.}"
+do
+ # exit on first good result
+ [ -n "$user" ] && output=$(rbw get --full "$arg" "$user") && break
+ output=$(rbw get --full "$arg") && break
+done || exit
+
+printf '%s\n' "$output" | sed -n '
+ 1{ s/^/password=/p }
+ s/^Username: /username=/p
+ s/^URI: /host=/p
+ '
diff --git a/bin/rbw-fzf b/bin/rbw-fzf
index dc0ba9c..cbf15c4 100755
--- a/bin/rbw-fzf
+++ b/bin/rbw-fzf
@@ -2,4 +2,4 @@
set -eu
set -o pipefail
-rbw ls --fields name,user,folder | perl -plE'/^([^\t]*)\t([^\t]*)\t([^\t]*)$/; $_ = join("/", grep { length } ($3, $1, $2)) . "\t$_"' | sort | fzf --with-nth=1 | perl -ple'/^([^\t]*)\t([^\t]*)\t([^\t]*)\t([^\t]*)$/; $_ = "$2 $3"' | xargs -r rbw get
+rbw ls --fields name,user,folder | perl -plE'/^([^\t]*)\t([^\t]*)\t([^\t]*)$/; $_ = join("/", grep { length } ($3, $1, $2)) . "\0$_"' | sort | fzf --with-nth=1 -d '\x00' | perl -ple'/^([^\0]*)\0([^\t]*)\t([^\t]*)\t([^\t]*)$/; $_ = "$2 $3"; $_ .= " --folder=\"$4\"" if length $4' | xargs -r rbw get
diff --git a/src/actions.rs b/src/actions.rs
index 0d8c88d..02ec854 100644
--- a/src/actions.rs
+++ b/src/actions.rs
@@ -1,37 +1,42 @@
use crate::prelude::*;
+pub async fn register(
+ email: &str,
+ apikey: crate::locked::ApiKey,
+) -> Result<()> {
+ let config = crate::config::Config::load_async().await?;
+ let client =
+ crate::api::Client::new(&config.base_url(), &config.identity_url());
+
+ client.register(email, &config.device_id, &apikey).await?;
+
+ Ok(())
+}
+
pub async fn login(
email: &str,
- password: &crate::locked::Password,
+ password: crate::locked::Password,
two_factor_token: Option<&str>,
two_factor_provider: Option<crate::api::TwoFactorProviderType>,
-) -> Result<(String, String, u32, String, crate::locked::Keys)> {
+) -> Result<(String, String, u32, String)> {
let config = crate::config::Config::load_async().await?;
let client =
crate::api::Client::new(&config.base_url(), &config.identity_url());
let iterations = client.prelogin(email).await?;
let identity =
- crate::identity::Identity::new(email, password, iterations)?;
-
+ crate::identity::Identity::new(email, &password, iterations)?;
let (access_token, refresh_token, protected_key) = client
.login(
- &identity.email,
+ email,
+ &config.device_id,
&identity.master_password_hash,
two_factor_token,
two_factor_provider,
)
.await?;
- let master_keys = crate::cipherstring::CipherString::new(&protected_key)?
- .decrypt_locked_symmetric(&identity.keys)?;
- Ok((
- access_token,
- refresh_token,
- iterations,
- protected_key,
- crate::locked::Keys::new(master_keys),
- ))
+ Ok((access_token, refresh_token, iterations, protected_key))
}
pub async fn unlock(
diff --git a/src/api.rs b/src/api.rs
index ef0f73d..14c11fd 100644
--- a/src/api.rs
+++ b/src/api.rs
@@ -148,9 +148,10 @@ struct PreloginRes {
struct ConnectPasswordReq {
grant_type: String,
username: String,
- password: String,
+ password: Option<String>,
scope: String,
client_id: String,
+ client_secret: Option<String>,
#[serde(rename = "deviceType")]
device_type: u32,
#[serde(rename = "deviceIdentifier")]
@@ -178,7 +179,7 @@ struct ConnectPasswordRes {
#[derive(serde::Deserialize, Debug)]
struct ConnectErrorRes {
error: String,
- error_description: String,
+ error_description: Option<String>,
#[serde(rename = "ErrorModel")]
error_model: Option<ConnectErrorResErrorModel>,
#[serde(rename = "TwoFactorProviders")]
@@ -575,23 +576,62 @@ impl Client {
Ok(prelogin_res.kdf_iterations)
}
+ pub async fn register(
+ &self,
+ email: &str,
+ device_id: &str,
+ apikey: &crate::locked::ApiKey,
+ ) -> Result<()> {
+ let connect_req = ConnectPasswordReq {
+ grant_type: "client_credentials".to_string(),
+ username: email.to_string(),
+ password: None,
+ scope: "api".to_string(),
+ // XXX unwraps here are not necessarily safe
+ client_id: String::from_utf8(apikey.client_id().to_vec())
+ .unwrap(),
+ client_secret: Some(
+ String::from_utf8(apikey.client_secret().to_vec()).unwrap(),
+ ),
+ device_type: 8,
+ device_identifier: device_id.to_string(),
+ device_name: "rbw".to_string(),
+ device_push_token: "".to_string(),
+ two_factor_token: None,
+ two_factor_provider: None,
+ };
+ let client = reqwest::Client::new();
+ let res = client
+ .post(&self.identity_url("/connect/token"))
+ .form(&connect_req)
+ .send()
+ .await
+ .map_err(|source| Error::Reqwest { source })?;
+ if let reqwest::StatusCode::OK = res.status() {
+ Ok(())
+ } else {
+ let code = res.status().as_u16();
+ Err(classify_login_error(&res.json_with_path().await?, code))
+ }
+ }
+
pub async fn login(
&self,
email: &str,
- master_password_hash: &crate::locked::PasswordHash,
+ device_id: &str,
+ password_hash: &crate::locked::PasswordHash,
two_factor_token: Option<&str>,
two_factor_provider: Option<TwoFactorProviderType>,
) -> Result<(String, String, String)> {
let connect_req = ConnectPasswordReq {
grant_type: "password".to_string(),
username: email.to_string(),
- password: base64::encode(master_password_hash.hash()),
+ password: Some(base64::encode(password_hash.hash())),
scope: "api offline_access".to_string(),
client_id: "desktop".to_string(),
+ client_secret: None,
device_type: 8,
- device_identifier: uuid::Uuid::new_v4()
- .to_hyphenated()
- .to_string(),
+ device_identifier: device_id.to_string(),
device_name: "rbw".to_string(),
device_push_token: "".to_string(),
two_factor_token: two_factor_token
@@ -602,6 +642,10 @@ impl Client {
let res = client
.post(&self.identity_url("/connect/token"))
.form(&connect_req)
+ .header(
+ "auth-email",
+ base64::encode_config(email, base64::URL_SAFE_NO_PAD),
+ )
.send()
.await
.map_err(|source| Error::Reqwest { source })?;
@@ -708,7 +752,7 @@ impl Client {
password: password.clone(),
totp: totp.clone(),
uris,
- })
+ });
}
crate::db::EntryData::Card {
cardholder_name,
@@ -1046,15 +1090,17 @@ impl Client {
}
fn classify_login_error(error_res: &ConnectErrorRes, code: u16) -> Error {
+ let error_desc = error_res.error_description.clone();
+ let error_desc = error_desc.as_deref();
match error_res.error.as_str() {
- "invalid_grant" => match error_res.error_description.as_str() {
- "invalid_username_or_password" => {
+ "invalid_grant" => match error_desc {
+ Some("invalid_username_or_password") => {
if let Some(error_model) = error_res.error_model.as_ref() {
let message = error_model.message.as_str().to_string();
return Error::IncorrectPassword { message };
}
}
- "Two factor required." => {
+ Some("Two factor required.") => {
if let Some(providers) =
error_res.two_factor_providers.as_ref()
{
@@ -1063,12 +1109,18 @@ fn classify_login_error(error_res: &ConnectErrorRes, code: u16) -> Error {
};
}
}
+ Some("Captcha required.") => {
+ return Error::RegistrationRequired;
+ }
_ => {}
},
+ "invalid_client" => {
+ return Error::IncorrectApiKey;
+ }
"" => {
// bitwarden_rs returns an empty error and error_description for
// this case, for some reason
- if error_res.error_description.is_empty() {
+ if error_desc.is_none() || error_desc == Some("") {
if let Some(error_model) = error_res.error_model.as_ref() {
let message = error_model.message.as_str().to_string();
match message.as_str() {
diff --git a/src/bin/rbw-agent/actions.rs b/src/bin/rbw-agent/actions.rs
index 4f4096e..1cc71c3 100644
--- a/src/bin/rbw-agent/actions.rs
+++ b/src/bin/rbw-agent/actions.rs
@@ -1,5 +1,84 @@
use anyhow::Context as _;
+pub async fn register(
+ sock: &mut crate::sock::Sock,
+ tty: Option<&str>,
+) -> anyhow::Result<()> {
+ let db = load_db().await.unwrap_or_else(|_| rbw::db::Db::new());
+
+ if db.needs_login() {
+ let url_str = config_base_url().await?;
+ let url = reqwest::Url::parse(&url_str)
+ .context("failed to parse base url")?;
+ let host = if let Some(host) = url.host_str() {
+ host
+ } else {
+ return Err(anyhow::anyhow!(
+ "couldn't find host in rbw base url {}",
+ url_str
+ ));
+ };
+
+ let email = config_email().await?;
+
+ let mut err_msg = None;
+ for i in 1_u8..=3 {
+ let err = if i > 1 {
+ // this unwrap is safe because we only ever continue the loop
+ // if we have set err_msg
+ Some(format!("{} (attempt {}/3)", err_msg.unwrap(), i))
+ } else {
+ None
+ };
+ let client_id = rbw::pinentry::getpin(
+ &config_pinentry().await?,
+ "API key client__id",
+ &format!("Log in to {}", host),
+ err.as_deref(),
+ tty,
+ false,
+ )
+ .await
+ .context("failed to read client_id from pinentry")?;
+ let client_secret = rbw::pinentry::getpin(
+ &config_pinentry().await?,
+ "API key client__secret",
+ &format!("Log in to {}", host),
+ err.as_deref(),
+ tty,
+ false,
+ )
+ .await
+ .context("failed to read client_secret from pinentry")?;
+ let apikey = rbw::locked::ApiKey::new(client_id, client_secret);
+ match rbw::actions::register(&email, apikey.clone()).await {
+ Ok(()) => {
+ break;
+ }
+ Err(rbw::error::Error::IncorrectPassword { message }) => {
+ if i == 3 {
+ return Err(rbw::error::Error::IncorrectPassword {
+ message,
+ })
+ .context("failed to log in to bitwarden instance");
+ } else {
+ err_msg = Some(message);
+ continue;
+ }
+ }
+ Err(e) => {
+ return Err(e)
+ .context("failed to log in to bitwarden instance")
+ }
+ }
+ }
+ }
+
+ respond_ack(sock).await?;
+
+ Ok(())
+}
+
pub async fn login(
sock: &mut crate::sock::Sock,
state: std::sync::Arc<tokio::sync::RwLock<crate::agent::State>>,
@@ -37,16 +116,18 @@ pub async fn login(
&format!("Log in to {}", host),
err.as_deref(),
tty,
+ true,
)
.await
.context("failed to read password from pinentry")?;
- match rbw::actions::login(&email, &password, None, None).await {
+ match rbw::actions::login(&email, password.clone(), None, None)
+ .await
+ {
Ok((
access_token,
refresh_token,
iterations,
protected_key,
- _,
)) => {
login_success(
sock,
@@ -74,7 +155,7 @@ pub async fn login(
) = two_factor(
tty,
&email,
- &password,
+ password.clone(),
rbw::api::TwoFactorProviderType::Authenticator,
)
.await?;
@@ -122,7 +203,7 @@ pub async fn login(
async fn two_factor(
tty: Option<&str>,
email: &str,
- password: &rbw::locked::Password,
+ password: rbw::locked::Password,
provider: rbw::api::TwoFactorProviderType,
) -> anyhow::Result<(String, String, u32, String)> {
let mut err_msg = None;
@@ -140,26 +221,21 @@ async fn two_factor(
"Enter the 6 digit verification code from your authenticator app.",
err.as_deref(),
tty,
+ true,
)
.await
.context("failed to read code from pinentry")?;
let code = std::str::from_utf8(code.password())
.context("code was not valid utf8")?;
match rbw::actions::login(
- &email,
- &password,
+ email,
+ password.clone(),
Some(code),
Some(provider),
)
.await
{
- Ok((
- access_token,
- refresh_token,
- iterations,
- protected_key,
- _,
- )) => {
+ Ok((access_token, refresh_token, iterations, protected_key)) => {
return Ok((
access_token,
refresh_token,
@@ -300,6 +376,7 @@ pub async fn unlock(
"Unlock the local database",
err.as_deref(),
tty,
+ true,
)
.await
.context("failed to read password from pinentry")?;
@@ -430,7 +507,7 @@ pub async fn decrypt(
.context("failed to parse encrypted secret")?;
let plaintext = String::from_utf8(
cipherstring
- .decrypt_symmetric(&keys)
+ .decrypt_symmetric(keys)
.context("failed to decrypt encrypted secret")?,
)
.context("failed to parse decrypted secret")?;
@@ -512,7 +589,7 @@ async fn config_email() -> anyhow::Result<String> {
async fn load_db() -> anyhow::Result<rbw::db::Db> {
let config = rbw::config::Config::load_async().await?;
if let Some(email) = &config.email {
- rbw::db::Db::load_async(&config.server_name(), &email)
+ rbw::db::Db::load_async(&config.server_name(), email)
.await
.map_err(anyhow::Error::new)
} else {
@@ -523,7 +600,7 @@ async fn load_db() -> anyhow::Result<rbw::db::Db> {
async fn save_db(db: &rbw::db::Db) -> anyhow::Result<()> {
let config = rbw::config::Config::load_async().await?;
if let Some(email) = &config.email {
- db.save_async(&config.server_name(), &email)
+ db.save_async(&config.server_name(), email)
.await
.map_err(anyhow::Error::new)
} else {
diff --git a/src/bin/rbw-agent/agent.rs b/src/bin/rbw-agent/agent.rs
index 760a1fc..fae8c7b 100644
--- a/src/bin/rbw-agent/agent.rs
+++ b/src/bin/rbw-agent/agent.rs
@@ -133,6 +133,10 @@ async fn handle_request(
}
};
let set_timeout = match &req.action {
+ rbw::protocol::Action::Register => {
+ crate::actions::register(sock, req.tty.as_deref()).await?;
+ true
+ }
rbw::protocol::Action::Login => {
crate::actions::login(sock, state.clone(), req.tty.as_deref())
.await?;
@@ -167,7 +171,7 @@ async fn handle_request(
crate::actions::decrypt(
sock,
state.clone(),
- &cipherstring,
+ cipherstring,
org_id.as_deref(),
)
.await?;
@@ -177,7 +181,7 @@ async fn handle_request(
crate::actions::encrypt(
sock,
state.clone(),
- &plaintext,
+ plaintext,
org_id.as_deref(),
)
.await?;
diff --git a/src/bin/rbw/actions.rs b/src/bin/rbw/actions.rs
index 75703f9..39fde15 100644
--- a/src/bin/rbw/actions.rs
+++ b/src/bin/rbw/actions.rs
@@ -1,6 +1,10 @@
use anyhow::Context as _;
use std::io::Read as _;
+pub fn register() -> anyhow::Result<()> {
+ simple_action(rbw::protocol::Action::Register)
+}
+
pub fn login() -> anyhow::Result<()> {
simple_action(rbw::protocol::Action::Login)
}
diff --git a/src/bin/rbw/commands.rs b/src/bin/rbw/commands.rs
index c1f9291..9efd966 100644
--- a/src/bin/rbw/commands.rs
+++ b/src/bin/rbw/commands.rs
@@ -465,6 +465,13 @@ pub fn config_unset(key: &str) -> anyhow::Result<()> {
Ok(())
}
+pub fn register() -> anyhow::Result<()> {
+ ensure_agent()?;
+ crate::actions::register()?;
+
+ Ok(())
+}
+
pub fn login() -> anyhow::Result<()> {
ensure_agent()?;
crate::actions::login()?;
@@ -642,7 +649,7 @@ pub fn add(
let mut folder_id = None;
if let Some(folder_name) = folder {
let (new_access_token, folders) =
- rbw::actions::list_folders(&access_token, &refresh_token)?;
+ rbw::actions::list_folders(&access_token, refresh_token)?;
if let Some(new_access_token) = new_access_token {
access_token = new_access_token.clone();
db.access_token = Some(new_access_token);
@@ -663,7 +670,7 @@ pub fn add(
if folder_id.is_none() {
let (new_access_token, id) = rbw::actions::create_folder(
&access_token,
- &refresh_token,
+ refresh_token,
&crate::actions::encrypt(folder_name, None)?,
)?;
if let Some(new_access_token) = new_access_token {
@@ -677,7 +684,7 @@ pub fn add(
if let (Some(access_token), ()) = rbw::actions::add(
&access_token,
- &refresh_token,
+ refresh_token,
&name,
&rbw::db::EntryData::Login {
username,
@@ -735,7 +742,7 @@ pub fn generate(
let mut folder_id = None;
if let Some(folder_name) = folder {
let (new_access_token, folders) =
- rbw::actions::list_folders(&access_token, &refresh_token)?;
+ rbw::actions::list_folders(&access_token, refresh_token)?;
if let Some(new_access_token) = new_access_token {
access_token = new_access_token.clone();
db.access_token = Some(new_access_token);
@@ -758,7 +765,7 @@ pub fn generate(
if folder_id.is_none() {
let (new_access_token, id) = rbw::actions::create_folder(
&access_token,
- &refresh_token,
+ refresh_token,
&crate::actions::encrypt(folder_name, None)?,
)?;
if let Some(new_access_token) = new_access_token {
@@ -772,7 +779,7 @@ pub fn generate(
if let (Some(access_token), ()) = rbw::actions::add(
&access_token,
- &refresh_token,
+ refresh_token,
&name,
&rbw::db::EntryData::Login {
username,
@@ -880,8 +887,8 @@ pub fn edit(
};
if let (Some(access_token), ()) = rbw::actions::edit(
- &access_token,
- &refresh_token,
+ access_token,
+ refresh_token,
&entry.id,
entry.org_id.as_deref(),
&entry.name,
@@ -921,7 +928,7 @@ pub fn remove(
.with_context(|| format!("couldn't find entry for '{}'", desc))?;
if let (Some(access_token), ()) =
- rbw::actions::remove(&access_token, &refresh_token, &entry.id)?
+ rbw::actions::remove(access_token, refresh_token, &entry.id)?
{
db.access_token = Some(access_token);
save_db(&db)?;
@@ -1053,7 +1060,7 @@ fn find_entry(
Ok(_) => {
for cipher in &db.entries {
if name == cipher.id {
- return Ok((cipher.clone(), decrypt_cipher(&cipher)?));
+ return Ok((cipher.clone(), decrypt_cipher(cipher)?));
}
}
Err(anyhow::anyhow!("no entry found"))
@@ -1183,10 +1190,7 @@ fn decrypt_cipher(entry: &rbw::db::Entry) -> anyhow::Result<DecryptedCipher> {
.name
.as_ref()
.map(|name| {
- crate::actions::decrypt(
- &name,
- entry.org_id.as_deref(),
- )
+ crate::actions::decrypt(name, entry.org_id.as_deref())
})
.transpose()?,
value: field
@@ -1194,7 +1198,7 @@ fn decrypt_cipher(entry: &rbw::db::Entry) -> anyhow::Result<DecryptedCipher> {
.as_ref()
.map(|value| {
crate::actions::decrypt(
- &value,
+ value,
entry.org_id.as_deref(),
)
})
@@ -1444,7 +1448,7 @@ fn parse_editor(contents: &str) -> (Option<String>, Option<String>) {
fn load_db() -> anyhow::Result<rbw::db::Db> {
let config = rbw::config::Config::load()?;
if let Some(email) = &config.email {
- rbw::db::Db::load(&config.server_name(), &email)
+ rbw::db::Db::load(&config.server_name(), email)
.map_err(anyhow::Error::new)
} else {
Err(anyhow::anyhow!("failed to find email address in config"))
@@ -1454,7 +1458,7 @@ fn load_db() -> anyhow::Result<rbw::db::Db> {
fn save_db(db: &rbw::db::Db) -> anyhow::Result<()> {
let config = rbw::config::Config::load()?;
if let Some(email) = &config.email {
- db.save(&config.server_name(), &email)
+ db.save(&config.server_name(), email)
.map_err(anyhow::Error::new)
} else {
Err(anyhow::anyhow!("failed to find email address in config"))
@@ -1464,7 +1468,7 @@ fn save_db(db: &rbw::db::Db) -> anyhow::Result<()> {
fn remove_db() -> anyhow::Result<()> {
let config = rbw::config::Config::load()?;
if let Some(email) = &config.email {
- rbw::db::Db::remove(&config.server_name(), &email)
+ rbw::db::Db::remove(&config.server_name(), email)
.map_err(anyhow::Error::new)
} else {
Err(anyhow::anyhow!("failed to find email address in config"))
@@ -1494,8 +1498,11 @@ fn parse_totp_secret(secret: &str) -> anyhow::Result<Vec<u8>> {
} 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"))
+ base32::decode(
+ base32::Alphabet::RFC4648 { padding: false },
+ &secret_str.replace(" ", ""),
+ )
+ .ok_or_else(|| anyhow::anyhow!("totp secret was not valid base32"))
}
fn generate_totp(secret: &str) -> anyhow::Result<String> {
diff --git a/src/bin/rbw/main.rs b/src/bin/rbw/main.rs
index 6c6c33e..85631c5 100644
--- a/src/bin/rbw/main.rs
+++ b/src/bin/rbw/main.rs
@@ -17,6 +17,17 @@ enum Opt {
config: Config,
},
+ #[structopt(
+ about = "Register this device with the Bitwarden server",
+ long_about = "Register this device with the Bitwarden server\n\n\
+ The official Bitwarden server includes bot detection to prevent \
+ brute force attacks. In order to avoid being detected as bot \
+ traffic, you will need to use this command to log in with your \
+ personal API key (instead of your password) first before regular \
+ logins will work."
+ )]
+ Register,
+
#[structopt(about = "Log in to the Bitwarden server")]
Login,
@@ -214,6 +225,7 @@ impl Opt {
Self::Config { config } => {
format!("config {}", config.subcommand_name())
}
+ Self::Register => "register".to_string(),
Self::Login => "login".to_string(),
Self::Unlock => "unlock".to_string(),
Self::Unlocked => "unlocked".to_string(),
@@ -281,22 +293,23 @@ fn main(opt: Opt) {
let res = match &opt {
Opt::Config { config } => match config {
Config::Show => commands::config_show(),
- Config::Set { key, value } => commands::config_set(&key, &value),
- Config::Unset { key } => commands::config_unset(&key),
+ Config::Set { key, value } => commands::config_set(key, value),
+ Config::Unset { key } => commands::config_unset(key),
},
+ Opt::Register => commands::register(),
Opt::Login => commands::login(),
Opt::Unlock => commands::unlock(),
Opt::Unlocked => commands::unlocked(),
Opt::Sync => commands::sync(),
- Opt::List { fields } => commands::list(&fields),
+ Opt::List { fields } => commands::list(fields),
Opt::Get {
name,
user,
folder,
full,
- } => commands::get(&name, user.as_deref(), folder.as_deref(), *full),
+ } => commands::get(name, user.as_deref(), folder.as_deref(), *full),
Opt::Code { name, user, folder } => {
- commands::code(&name, user.as_deref(), folder.as_deref())
+ commands::code(name, user.as_deref(), folder.as_deref())
}
Opt::Add {
name,
@@ -304,7 +317,7 @@ fn main(opt: Opt) {
uri,
folder,
} => commands::add(
- &name,
+ name,
user.as_deref(),
uri.iter()
// XXX not sure what the ui for specifying the match type
@@ -349,18 +362,18 @@ fn main(opt: Opt) {
)
}
Opt::Edit { name, user, folder } => {
- commands::edit(&name, user.as_deref(), folder.as_deref())
+ commands::edit(name, user.as_deref(), folder.as_deref())
}
Opt::Remove { name, user, folder } => {
- commands::remove(&name, user.as_deref(), folder.as_deref())
+ commands::remove(name, user.as_deref(), folder.as_deref())
}
Opt::History { name, user, folder } => {
- commands::history(&name, user.as_deref(), folder.as_deref())
+ commands::history(name, user.as_deref(), folder.as_deref())
}
Opt::Lock => commands::lock(),
Opt::Purge => commands::purge(),
Opt::StopAgent => commands::stop_agent(),
- Opt::GenCompletions { shell } => gen_completions(&shell),
+ Opt::GenCompletions { shell } => gen_completions(shell),
}
.context(format!("rbw {}", opt.subcommand_name()));
diff --git a/src/cipherstring.rs b/src/cipherstring.rs
index 73eeeb6..39254c7 100644
--- a/src/cipherstring.rs
+++ b/src/cipherstring.rs
@@ -4,6 +4,7 @@ use block_modes::BlockMode as _;
use block_padding::Padding as _;
use hmac::{Mac as _, NewMac as _};
use rand::RngCore as _;
+use rsa::pkcs8::FromPrivateKey as _;
use zeroize::Zeroize as _;
pub enum CipherString {
@@ -122,27 +123,27 @@ impl CipherString {
&self,
keys: &crate::locked::Keys,
) -> Result<Vec<u8>> {
- match self {
- Self::Symmetric {
+ if let Self::Symmetric {
+ iv,
+ ciphertext,
+ mac,
+ } = self
+ {
+ let cipher = decrypt_common_symmetric(
+ keys,
iv,
ciphertext,
- mac,
- } => {
- let cipher = decrypt_common_symmetric(
- keys,
- iv,
- ciphertext,
- mac.as_deref(),
- )?;
- cipher
- .decrypt_vec(ciphertext)
- .map_err(|source| Error::Decrypt { source })
- }
- _ => Err(Error::InvalidCipherString {
+ mac.as_deref(),
+ )?;
+ cipher
+ .decrypt_vec(ciphertext)
+ .map_err(|source| Error::Decrypt { source })
+ } else {
+ Err(Error::InvalidCipherString {
reason:
"found an asymmetric cipherstring, expecting symmetric"
.to_string(),
- }),
+ })
}
}
@@ -150,30 +151,30 @@ impl CipherString {
&self,
keys: &crate::locked::Keys,
) -> Result<crate::locked::Vec> {
- match self {
- Self::Symmetric {
+ if let Self::Symmetric {
+ iv,
+ ciphertext,
+ mac,
+ } = self
+ {
+ let mut res = crate::locked::Vec::new();
+ res.extend(ciphertext.iter().copied());
+ let cipher = decrypt_common_symmetric(
+ keys,
iv,
ciphertext,
- mac,
- } => {
- let mut res = crate::locked::Vec::new();
- res.extend(ciphertext.iter().copied());
- let cipher = decrypt_common_symmetric(
- keys,
- iv,
- ciphertext,
- mac.as_deref(),
- )?;
- cipher
- .decrypt(res.data_mut())
- .map_err(|source| Error::Decrypt { source })?;
- Ok(res)
- }
- _ => Err(Error::InvalidCipherString {
+ mac.as_deref(),
+ )?;
+ cipher
+ .decrypt(res.data_mut())
+ .map_err(|source| Error::Decrypt { source })?;
+ Ok(res)
+ } else {
+ Err(Error::InvalidCipherString {
reason:
"found an asymmetric cipherstring, expecting symmetric"
.to_string(),
- }),
+ })
}
}
@@ -181,34 +182,33 @@ impl CipherString {
&self,
private_key: &crate::locked::PrivateKey,
) -> Result<crate::locked::Vec> {
- match self {
- Self::Asymmetric { ciphertext } => {
- let privkey_data = private_key.private_key();
- let privkey_data = block_padding::Pkcs7::unpad(privkey_data)
- .map_err(|_| Error::Padding)?;
- let pkey = rsa::RSAPrivateKey::from_pkcs8(privkey_data)
- .map_err(|source| Error::Rsa { source })?;
- let mut bytes = pkey
- .decrypt(
- rsa::padding::PaddingScheme::new_oaep::<sha1::Sha1>(),
- ciphertext,
- )
- .map_err(|source| Error::Rsa { source })?;
+ if let Self::Asymmetric { ciphertext } = self {
+ let privkey_data = private_key.private_key();
+ let privkey_data = block_padding::Pkcs7::unpad(privkey_data)
+ .map_err(|_| Error::Padding)?;
+ let pkey = rsa::RsaPrivateKey::from_pkcs8_der(privkey_data)
+ .map_err(|source| Error::RsaPkcs8 { source })?;
+ let mut bytes = pkey
+ .decrypt(
+ rsa::padding::PaddingScheme::new_oaep::<sha1::Sha1>(),
+ ciphertext,
+ )
+ .map_err(|source| Error::Rsa { source })?;
- // XXX it'd be great if the rsa crate would let us decrypt
- // into a preallocated buffer directly to avoid the
- // intermediate vec that needs to be manually zeroized, etc
- let mut res = crate::locked::Vec::new();
- res.extend(bytes.iter().copied());
- bytes.zeroize();
+ // XXX it'd be great if the rsa crate would let us decrypt
+ // into a preallocated buffer directly to avoid the
+ // intermediate vec that needs to be manually zeroized, etc
+ let mut res = crate::locked::Vec::new();
+ res.extend(bytes.iter().copied());
+ bytes.zeroize();
- Ok(res)
- }
- _ => Err(Error::InvalidCipherString {
+ Ok(res)
+ } else {
+ Err(Error::InvalidCipherString {
reason:
"found a symmetric cipherstring, expecting asymmetric"
.to_string(),
- }),
+ })
}
}
}
diff --git a/src/config.rs b/src/config.rs
index c6e0787..bbc39f7 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -12,6 +12,8 @@ pub struct Config {
pub lock_timeout: u64,
#[serde(default = "default_pinentry")]
pub pinentry: String,
+ #[serde(default = "stub_device_id")]
+ pub device_id: String,
}
impl Default for Config {
@@ -22,6 +24,7 @@ impl Default for Config {
identity_url: Default::default(),
lock_timeout: default_lock_timeout(),
pinentry: default_pinentry(),
+ device_id: default_device_id(),
}
}
}
@@ -34,6 +37,14 @@ pub fn default_pinentry() -> String {
"pinentry".to_string()
}
+fn default_device_id() -> String {
+ uuid::Uuid::new_v4().to_hyphenated().to_string()
+}
+
+fn stub_device_id() -> String {
+ String::from("fix")
+}
+
impl Config {
pub fn new() -> Self {
Self::default()
@@ -116,10 +127,14 @@ impl Config {
}
pub fn validate() -> Result<()> {
- let config = Self::load()?;
+ let mut config = Self::load()?;
if config.email.is_none() {
return Err(Error::ConfigMissingEmail);
}
+ if config.device_id == stub_device_id() {
+ config.device_id = default_device_id();
+ config.save()?;
+ }
Ok(())
}
diff --git a/src/edit.rs b/src/edit.rs
index 45e9534..f7d8131 100644
--- a/src/edit.rs
+++ b/src/edit.rs
@@ -13,7 +13,7 @@ pub fn edit(contents: &str, help: &str) -> Result<String> {
let mut args = vec![];
match editor.file_name() {
Some(editor) => match editor.to_str() {
- Some("vim") => {
+ Some("vim") | Some("nvim") => {
// disable swap files and viminfo for password entry
args.push(std::ffi::OsStr::new("-ni"));
args.push(std::ffi::OsStr::new("NONE"));
diff --git a/src/error.rs b/src/error.rs
index bc97087..d584e53 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -46,6 +46,9 @@ pub enum Error {
#[error("failed to expand with hkdf")]
HkdfExpand,
+ #[error("incorrect api key")]
+ IncorrectApiKey,
+
#[error("{message}")]
IncorrectPassword { message: String },
@@ -132,6 +135,9 @@ pub enum Error {
#[error("error waiting for pinentry to exit")]
PinentryWait { source: tokio::io::Error },
+ #[error("This device has not yet been registered with the Bitwarden server. Run `rbw register` first, and then try again.")]
+ RegistrationRequired,
+
#[error("failed to remove db at {}", .file.display())]
RemoveDb {
source: std::io::Error,
@@ -150,6 +156,9 @@ pub enum Error {
#[error("failed to decrypt")]
Rsa { source: rsa::errors::Error },
+ #[error("failed to decrypt")]
+ RsaPkcs8 { source: rsa::pkcs8::Error },
+
#[error("failed to save config to {}", .file.display())]
SaveConfig {
source: std::io::Error,
diff --git a/src/lib.rs b/src/lib.rs
index 91869e4..4a13e25 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -12,6 +12,7 @@
#![allow(clippy::too_many_arguments)]
#![allow(clippy::too_many_lines)]
#![allow(clippy::type_complexity)]
+#![allow(clippy::unused_async)]
pub mod actions;
pub mod api;
diff --git a/src/locked.rs b/src/locked.rs
index 611e57e..4ddf021 100644
--- a/src/locked.rs
+++ b/src/locked.rs
@@ -32,7 +32,7 @@ impl Vec {
pub fn zero(&mut self) {
self.truncate(0);
- self.data.extend(std::iter::repeat(0).take(LEN))
+ self.data.extend(std::iter::repeat(0).take(LEN));
}
pub fn extend(&mut self, it: impl Iterator<Item = u8>) {
@@ -51,6 +51,15 @@ impl Drop for Vec {
}
}
+impl Clone for Vec {
+ fn clone(&self) -> Self {
+ let mut new_vec = Self::new();
+ new_vec.extend(self.data().iter().copied());
+ new_vec
+ }
+}
+
+#[derive(Clone)]
pub struct Password {
password: Vec,
}
@@ -65,6 +74,7 @@ impl Password {
}
}
+#[derive(Clone)]
pub struct Keys {
keys: Vec,
}
@@ -83,6 +93,7 @@ impl Keys {
}
}
+#[derive(Clone)]
pub struct PasswordHash {
hash: Vec,
}
@@ -97,6 +108,7 @@ impl PasswordHash {
}
}
+#[derive(Clone)]
pub struct PrivateKey {
private_key: Vec,
}
@@ -110,3 +122,26 @@ impl PrivateKey {
self.private_key.data()
}
}
+
+#[derive(Clone)]
+pub struct ApiKey {
+ client_id: Password,
+ client_secret: Password,
+}
+
+impl ApiKey {
+ pub fn new(client_id: Password, client_secret: Password) -> Self {
+ Self {
+ client_id,
+ client_secret,
+ }
+ }
+
+ pub fn client_id(&self) -> &[u8] {
+ self.client_id.password()
+ }
+
+ pub fn client_secret(&self) -> &[u8] {
+ self.client_secret.password()
+ }
+}
diff --git a/src/pinentry.rs b/src/pinentry.rs
index d62d4b2..b4d2bb0 100644
--- a/src/pinentry.rs
+++ b/src/pinentry.rs
@@ -8,15 +8,19 @@ pub async fn getpin(
desc: &str,
err: Option<&str>,
tty: Option<&str>,
+ grab: bool,
) -> Result<crate::locked::Password> {
let mut opts = tokio::process::Command::new(pinentry);
opts.stdin(std::process::Stdio::piped())
.stdout(std::process::Stdio::piped());
+ let mut args = vec!["-o", "0"];
if let Some(tty) = tty {
- opts.args(&["-T", tty, "-o", "0"]);
- } else {
- opts.args(&["-o", "0"]);
+ args.extend(&["-T", tty]);
}
+ if !grab {
+ args.push("-g");
+ }
+ opts.args(args);
let mut child = opts.spawn().map_err(|source| Error::Spawn { source })?;
// unwrap is safe because we specified stdin as piped in the command opts
// above
diff --git a/src/protocol.rs b/src/protocol.rs
index a4b9722..14fa7f9 100644
--- a/src/protocol.rs
+++ b/src/protocol.rs
@@ -23,6 +23,7 @@ pub struct Request {
#[serde(tag = "type")]
pub enum Action {
Login,
+ Register,
Unlock,
CheckLock,
Lock,