mirror of
https://github.com/dani-garcia/vaultwarden.git
synced 2024-12-26 23:25:56 -05:00
Support for webauthn and u2f->webauthn migrations
This commit is contained in:
parent
cea7a30d82
commit
c380d9c379
177
Cargo.lock
generated
177
Cargo.lock
generated
@ -317,7 +317,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "03a5d7b21829bc7b4bf4754a978a241ae54ea55a40f92bb20216e54096f4b951"
|
checksum = "03a5d7b21829bc7b4bf4754a978a241ae54ea55a40f92bb20216e54096f4b951"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"percent-encoding 2.1.0",
|
"percent-encoding 2.1.0",
|
||||||
"time 0.2.26",
|
"time 0.2.27",
|
||||||
"version_check 0.9.3",
|
"version_check 0.9.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -328,7 +328,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "ffdf8865bac3d9a3bde5bde9088ca431b11f5d37c7a578b8086af77248b76627"
|
checksum = "ffdf8865bac3d9a3bde5bde9088ca431b11f5d37c7a578b8086af77248b76627"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"percent-encoding 2.1.0",
|
"percent-encoding 2.1.0",
|
||||||
"time 0.2.26",
|
"time 0.2.27",
|
||||||
"version_check 0.9.3",
|
"version_check 0.9.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -344,7 +344,7 @@ dependencies = [
|
|||||||
"publicsuffix 1.5.6",
|
"publicsuffix 1.5.6",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"time 0.2.26",
|
"time 0.2.27",
|
||||||
"url 2.2.2",
|
"url 2.2.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -360,7 +360,7 @@ dependencies = [
|
|||||||
"publicsuffix 2.1.0",
|
"publicsuffix 2.1.0",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"time 0.2.26",
|
"time 0.2.27",
|
||||||
"url 2.2.2",
|
"url 2.2.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -469,7 +469,7 @@ dependencies = [
|
|||||||
"bitflags",
|
"bitflags",
|
||||||
"proc-macro2 1.0.27",
|
"proc-macro2 1.0.27",
|
||||||
"quote 1.0.9",
|
"quote 1.0.9",
|
||||||
"syn 1.0.72",
|
"syn 1.0.73",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -497,7 +497,7 @@ checksum = "45f5098f628d02a7a0f68ddba586fb61e80edec3bdc1be3b921f4ceec60858d3"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.27",
|
"proc-macro2 1.0.27",
|
||||||
"quote 1.0.9",
|
"quote 1.0.9",
|
||||||
"syn 1.0.72",
|
"syn 1.0.73",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -747,7 +747,7 @@ dependencies = [
|
|||||||
"proc-macro-hack",
|
"proc-macro-hack",
|
||||||
"proc-macro2 1.0.27",
|
"proc-macro2 1.0.27",
|
||||||
"quote 1.0.9",
|
"quote 1.0.9",
|
||||||
"syn 1.0.72",
|
"syn 1.0.73",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -866,10 +866,16 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "handlebars"
|
name = "half"
|
||||||
version = "3.5.5"
|
version = "1.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4498fc115fa7d34de968184e473529abb40eeb6be8bc5f7faba3d08c316cb3e3"
|
checksum = "62aca2aba2d62b4a7f5b33f3712cb1b0692779a56fb510499d5c0aa594daeaf3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "handlebars"
|
||||||
|
version = "4.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2060119114dd8a8bc87facce6384751af8280a7adc8e203c023c95cbb11f5663"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log 0.4.14",
|
"log 0.4.14",
|
||||||
"pest",
|
"pest",
|
||||||
@ -944,7 +950,7 @@ dependencies = [
|
|||||||
"markup5ever",
|
"markup5ever",
|
||||||
"proc-macro2 1.0.27",
|
"proc-macro2 1.0.27",
|
||||||
"quote 1.0.9",
|
"quote 1.0.9",
|
||||||
"syn 1.0.72",
|
"syn 1.0.73",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1101,9 +1107,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ipnet"
|
name = "ipnet"
|
||||||
version = "2.3.0"
|
version = "2.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "47be2f14c678be2fdcab04ab1171db51b2762ce6f0a8ee87c8dd4a04ed216135"
|
checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
@ -1195,9 +1201,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.96"
|
version = "0.2.97"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5600b4e6efc5421841a2138a6b082e07fe12f9aaa12783d50e5d13325b26b4fc"
|
checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libsqlite3-sys"
|
name = "libsqlite3-sys"
|
||||||
@ -1317,7 +1323,7 @@ dependencies = [
|
|||||||
"migrations_internals",
|
"migrations_internals",
|
||||||
"proc-macro2 1.0.27",
|
"proc-macro2 1.0.27",
|
||||||
"quote 1.0.9",
|
"quote 1.0.9",
|
||||||
"syn 1.0.72",
|
"syn 1.0.73",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1376,9 +1382,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mio"
|
name = "mio"
|
||||||
version = "0.7.11"
|
version = "0.7.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cf80d3e903b34e0bd7282b218398aec54e082c840d9baf8339e0080a0c542956"
|
checksum = "8c2bdb6314ec10835cd3293dd268473a835c02b7b352e788be788b3c6ca6bb16"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"log 0.4.14",
|
"log 0.4.14",
|
||||||
@ -1422,9 +1428,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "multipart"
|
name = "multipart"
|
||||||
version = "0.17.1"
|
version = "0.18.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d050aeedc89243f5347c3e237e3e13dc76fbe4ae3742a57b94dc14f69acf76d4"
|
checksum = "00dec633863867f29cb39df64a397cdf4a6354708ddd7759f70c7fb51c5f9182"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"buf_redux",
|
"buf_redux",
|
||||||
"httparse",
|
"httparse",
|
||||||
@ -1432,7 +1438,7 @@ dependencies = [
|
|||||||
"mime 0.3.16",
|
"mime 0.3.16",
|
||||||
"mime_guess",
|
"mime_guess",
|
||||||
"quick-error 1.2.3",
|
"quick-error 1.2.3",
|
||||||
"rand 0.7.3",
|
"rand 0.8.4",
|
||||||
"safemem",
|
"safemem",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"twoway",
|
"twoway",
|
||||||
@ -1538,7 +1544,7 @@ checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.27",
|
"proc-macro2 1.0.27",
|
||||||
"quote 1.0.9",
|
"quote 1.0.9",
|
||||||
"syn 1.0.72",
|
"syn 1.0.73",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1585,18 +1591,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "object"
|
name = "object"
|
||||||
version = "0.25.2"
|
version = "0.25.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f8bc1d42047cf336f0f939c99e97183cf31551bf0f2865a2ec9c8d91fd4ffb5e"
|
checksum = "a38f2be3697a57b4060074ff41b44c16870d916ad7877c17696e063257482bc7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.7.2"
|
version = "1.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3"
|
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "opaque-debug"
|
name = "opaque-debug"
|
||||||
@ -1816,7 +1822,7 @@ dependencies = [
|
|||||||
"pest_meta",
|
"pest_meta",
|
||||||
"proc-macro2 1.0.27",
|
"proc-macro2 1.0.27",
|
||||||
"quote 1.0.9",
|
"quote 1.0.9",
|
||||||
"syn 1.0.72",
|
"syn 1.0.73",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2053,14 +2059,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand"
|
name = "rand"
|
||||||
version = "0.8.3"
|
version = "0.8.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e"
|
checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"rand_chacha 0.3.0",
|
"rand_chacha 0.3.1",
|
||||||
"rand_core 0.6.2",
|
"rand_core 0.6.3",
|
||||||
"rand_hc 0.3.0",
|
"rand_hc 0.3.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2075,12 +2081,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand_chacha"
|
name = "rand_chacha"
|
||||||
version = "0.3.0"
|
version = "0.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d"
|
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ppv-lite86",
|
"ppv-lite86",
|
||||||
"rand_core 0.6.2",
|
"rand_core 0.6.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2109,9 +2115,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand_core"
|
name = "rand_core"
|
||||||
version = "0.6.2"
|
version = "0.6.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7"
|
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom 0.2.3",
|
"getrandom 0.2.3",
|
||||||
]
|
]
|
||||||
@ -2127,11 +2133,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand_hc"
|
name = "rand_hc"
|
||||||
version = "0.3.0"
|
version = "0.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73"
|
checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rand_core 0.6.2",
|
"rand_core 0.6.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2154,9 +2160,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.2.8"
|
version = "0.2.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "742739e41cd49414de871ea5e549afb7e2a3ac77b589bcbebe8c82fab37147fc"
|
checksum = "5ab49abadf3f9e1c4bc499e8845e152ad87d2ad2d30371841171169e9d75feee"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
]
|
]
|
||||||
@ -2216,7 +2222,7 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_urlencoded",
|
"serde_urlencoded",
|
||||||
"time 0.2.26",
|
"time 0.2.27",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-native-tls",
|
"tokio-native-tls",
|
||||||
"tokio-socks",
|
"tokio-socks",
|
||||||
@ -2277,7 +2283,7 @@ dependencies = [
|
|||||||
"rocket_codegen",
|
"rocket_codegen",
|
||||||
"rocket_http",
|
"rocket_http",
|
||||||
"state",
|
"state",
|
||||||
"time 0.2.26",
|
"time 0.2.27",
|
||||||
"toml",
|
"toml",
|
||||||
"version_check 0.9.3",
|
"version_check 0.9.3",
|
||||||
"yansi",
|
"yansi",
|
||||||
@ -2322,7 +2328,7 @@ dependencies = [
|
|||||||
"rustls",
|
"rustls",
|
||||||
"smallvec 1.6.1",
|
"smallvec 1.6.1",
|
||||||
"state",
|
"state",
|
||||||
"time 0.2.26",
|
"time 0.2.27",
|
||||||
"unicode-xid 0.2.2",
|
"unicode-xid 0.2.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -2463,6 +2469,25 @@ dependencies = [
|
|||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_bytes"
|
||||||
|
version = "0.11.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "16ae07dd2f88a366f15bd0632ba725227018c69a1c8550a927324f8eb8368bb9"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_cbor"
|
||||||
|
version = "0.11.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e18acfa2f90e8b735b2836ab8d538de304cbb6729a7360729ea5a895d15a622"
|
||||||
|
dependencies = [
|
||||||
|
"half",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.126"
|
version = "1.0.126"
|
||||||
@ -2471,7 +2496,7 @@ checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.27",
|
"proc-macro2 1.0.27",
|
||||||
"quote 1.0.9",
|
"quote 1.0.9",
|
||||||
"syn 1.0.72",
|
"syn 1.0.73",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2653,7 +2678,7 @@ dependencies = [
|
|||||||
"quote 1.0.9",
|
"quote 1.0.9",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"syn 1.0.72",
|
"syn 1.0.73",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2669,7 +2694,7 @@ dependencies = [
|
|||||||
"serde_derive",
|
"serde_derive",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sha1",
|
"sha1",
|
||||||
"syn 1.0.72",
|
"syn 1.0.73",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2722,9 +2747,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.72"
|
version = "1.0.73"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82"
|
checksum = "f71489ff30030d2ae598524f61326b902466f72a0fb1a8564c001cc63425bcc7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.27",
|
"proc-macro2 1.0.27",
|
||||||
"quote 1.0.9",
|
"quote 1.0.9",
|
||||||
@ -2757,7 +2782,7 @@ checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
"libc",
|
"libc",
|
||||||
"rand 0.8.3",
|
"rand 0.8.4",
|
||||||
"redox_syscall",
|
"redox_syscall",
|
||||||
"remove_dir_all",
|
"remove_dir_all",
|
||||||
"winapi 0.3.9",
|
"winapi 0.3.9",
|
||||||
@ -2791,7 +2816,7 @@ checksum = "8a36768c0fbf1bb15eca10defa29526bda730a2376c2ab4393ccfa16fb1a318d"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.27",
|
"proc-macro2 1.0.27",
|
||||||
"quote 1.0.9",
|
"quote 1.0.9",
|
||||||
"syn 1.0.72",
|
"syn 1.0.73",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2816,9 +2841,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time"
|
name = "time"
|
||||||
version = "0.2.26"
|
version = "0.2.27"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "08a8cbfbf47955132d0202d1662f49b2423ae35862aee471f3ba4b133358f372"
|
checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"const_fn",
|
"const_fn",
|
||||||
"libc",
|
"libc",
|
||||||
@ -2841,15 +2866,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time-macros-impl"
|
name = "time-macros-impl"
|
||||||
version = "0.1.1"
|
version = "0.1.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e5c3be1edfad6027c69f5491cf4cb310d1a71ecd6af742788c6ff8bced86b8fa"
|
checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro-hack",
|
"proc-macro-hack",
|
||||||
"proc-macro2 1.0.27",
|
"proc-macro2 1.0.27",
|
||||||
"quote 1.0.9",
|
"quote 1.0.9",
|
||||||
"standback",
|
"standback",
|
||||||
"syn 1.0.72",
|
"syn 1.0.73",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2869,17 +2894,18 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.6.1"
|
version = "1.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0a38d31d7831c6ed7aad00aa4c12d9375fd225a6dd77da1d25b707346319a975"
|
checksum = "c79ba603c337335df6ba6dd6afc38c38a7d5e1b0c871678439ea973cd62a118e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"bytes 1.0.1",
|
"bytes 1.0.1",
|
||||||
"libc",
|
"libc",
|
||||||
"memchr",
|
"memchr",
|
||||||
"mio 0.7.11",
|
"mio 0.7.13",
|
||||||
"num_cpus",
|
"num_cpus",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
|
"winapi 0.3.9",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2954,7 +2980,7 @@ checksum = "c42e6fa53307c8a17e4ccd4dc81cf5ec38db9209f59b222210375b54ee40d1e2"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.27",
|
"proc-macro2 1.0.27",
|
||||||
"quote 1.0.9",
|
"quote 1.0.9",
|
||||||
"syn 1.0.72",
|
"syn 1.0.73",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -3150,7 +3176,7 @@ dependencies = [
|
|||||||
"paste",
|
"paste",
|
||||||
"percent-encoding 2.1.0",
|
"percent-encoding 2.1.0",
|
||||||
"pico-args",
|
"pico-args",
|
||||||
"rand 0.8.3",
|
"rand 0.8.4",
|
||||||
"regex",
|
"regex",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"ring",
|
"ring",
|
||||||
@ -3160,11 +3186,12 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"syslog",
|
"syslog",
|
||||||
"time 0.2.26",
|
"time 0.2.27",
|
||||||
"tracing",
|
"tracing",
|
||||||
"u2f",
|
"u2f",
|
||||||
"url 2.2.2",
|
"url 2.2.2",
|
||||||
"uuid",
|
"uuid",
|
||||||
|
"webauthn-rs",
|
||||||
"yubico",
|
"yubico",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -3242,7 +3269,7 @@ dependencies = [
|
|||||||
"log 0.4.14",
|
"log 0.4.14",
|
||||||
"proc-macro2 1.0.27",
|
"proc-macro2 1.0.27",
|
||||||
"quote 1.0.9",
|
"quote 1.0.9",
|
||||||
"syn 1.0.72",
|
"syn 1.0.73",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -3276,7 +3303,7 @@ checksum = "be2241542ff3d9f241f5e2cb6dd09b37efe786df8851c54957683a49f0987a97"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.27",
|
"proc-macro2 1.0.27",
|
||||||
"quote 1.0.9",
|
"quote 1.0.9",
|
||||||
"syn 1.0.72",
|
"syn 1.0.73",
|
||||||
"wasm-bindgen-backend",
|
"wasm-bindgen-backend",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
@ -3297,6 +3324,24 @@ dependencies = [
|
|||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "webauthn-rs"
|
||||||
|
version = "0.3.0-alpha.7"
|
||||||
|
source = "git+https://github.com/dani-garcia/webauthn-rs?rev=70b458f246d207e5b6333ada9f1d5794c5e01da1#70b458f246d207e5b6333ada9f1d5794c5e01da1"
|
||||||
|
dependencies = [
|
||||||
|
"base64 0.13.0",
|
||||||
|
"log 0.4.14",
|
||||||
|
"nom 4.1.1",
|
||||||
|
"openssl",
|
||||||
|
"rand 0.8.4",
|
||||||
|
"serde",
|
||||||
|
"serde_bytes",
|
||||||
|
"serde_cbor",
|
||||||
|
"serde_derive",
|
||||||
|
"serde_json",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "webpki"
|
name = "webpki"
|
||||||
version = "0.21.4"
|
version = "0.21.4"
|
||||||
@ -3412,7 +3457,7 @@ dependencies = [
|
|||||||
"crypto-mac 0.10.0",
|
"crypto-mac 0.10.0",
|
||||||
"futures",
|
"futures",
|
||||||
"hmac 0.10.1",
|
"hmac 0.10.1",
|
||||||
"rand 0.8.3",
|
"rand 0.8.4",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"sha-1 0.9.6",
|
"sha-1 0.9.6",
|
||||||
"threadpool",
|
"threadpool",
|
||||||
|
22
Cargo.toml
22
Cargo.toml
@ -28,8 +28,8 @@ syslog = "4.0.1"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# Web framework for nightly with a focus on ease-of-use, expressibility, and speed.
|
# Web framework for nightly with a focus on ease-of-use, expressibility, and speed.
|
||||||
rocket = { version = "0.5.0-dev", features = ["tls"], default-features = false }
|
rocket = { version = "=0.5.0-dev", features = ["tls"], default-features = false }
|
||||||
rocket_contrib = "0.5.0-dev"
|
rocket_contrib = "=0.5.0-dev"
|
||||||
|
|
||||||
# HTTP client
|
# HTTP client
|
||||||
reqwest = { version = "0.11.3", features = ["blocking", "json", "gzip", "brotli", "socks", "cookies"] }
|
reqwest = { version = "0.11.3", features = ["blocking", "json", "gzip", "brotli", "socks", "cookies"] }
|
||||||
@ -41,7 +41,7 @@ bytes = "1.0.1"
|
|||||||
url = "2.2.2"
|
url = "2.2.2"
|
||||||
|
|
||||||
# multipart/form-data support
|
# multipart/form-data support
|
||||||
multipart = { version = "0.17.1", features = ["server"], default-features = false }
|
multipart = { version = "0.18.0", features = ["server"], default-features = false }
|
||||||
|
|
||||||
# WebSockets library
|
# WebSockets library
|
||||||
ws = { version = "0.10.0", package = "parity-ws" }
|
ws = { version = "0.10.0", package = "parity-ws" }
|
||||||
@ -77,7 +77,7 @@ uuid = { version = "0.8.2", features = ["v4"] }
|
|||||||
# Date and time libraries
|
# Date and time libraries
|
||||||
chrono = { version = "0.4.19", features = ["serde"] }
|
chrono = { version = "0.4.19", features = ["serde"] }
|
||||||
chrono-tz = "0.5.3"
|
chrono-tz = "0.5.3"
|
||||||
time = "0.2.26"
|
time = "0.2.27"
|
||||||
|
|
||||||
# Job scheduler
|
# Job scheduler
|
||||||
job_scheduler = "1.2.1"
|
job_scheduler = "1.2.1"
|
||||||
@ -93,6 +93,7 @@ jsonwebtoken = "7.2.0"
|
|||||||
|
|
||||||
# U2F library
|
# U2F library
|
||||||
u2f = "0.2.0"
|
u2f = "0.2.0"
|
||||||
|
webauthn-rs = "0.3.0-alpha.7"
|
||||||
|
|
||||||
# Yubico Library
|
# Yubico Library
|
||||||
yubico = { version = "0.10.0", features = ["online-tokio"], default-features = false }
|
yubico = { version = "0.10.0", features = ["online-tokio"], default-features = false }
|
||||||
@ -101,7 +102,7 @@ yubico = { version = "0.10.0", features = ["online-tokio"], default-features = f
|
|||||||
dotenv = { version = "0.15.0", default-features = false }
|
dotenv = { version = "0.15.0", default-features = false }
|
||||||
|
|
||||||
# Lazy initialization
|
# Lazy initialization
|
||||||
once_cell = "1.7.2"
|
once_cell = "1.8.0"
|
||||||
|
|
||||||
# Numerical libraries
|
# Numerical libraries
|
||||||
num-traits = "0.2.14"
|
num-traits = "0.2.14"
|
||||||
@ -109,10 +110,10 @@ num-derive = "0.3.3"
|
|||||||
|
|
||||||
# Email libraries
|
# Email libraries
|
||||||
tracing = { version = "0.1.26", features = ["log"] } # Needed to have lettre trace logging used when SMTP_DEBUG is enabled.
|
tracing = { version = "0.1.26", features = ["log"] } # Needed to have lettre trace logging used when SMTP_DEBUG is enabled.
|
||||||
lettre = { version = "0.10.0-rc.1", features = ["smtp-transport", "builder", "serde", "native-tls", "hostname", "tracing"], default-features = false }
|
lettre = { version = "0.10.0-rc.3", features = ["smtp-transport", "builder", "serde", "native-tls", "hostname", "tracing"], default-features = false }
|
||||||
|
|
||||||
# Template library
|
# Template library
|
||||||
handlebars = { version = "3.5.5", features = ["dir_source"] }
|
handlebars = { version = "4.0.0", features = ["dir_source"] }
|
||||||
|
|
||||||
# For favicon extraction from main website
|
# For favicon extraction from main website
|
||||||
html5ever = "0.25.1"
|
html5ever = "0.25.1"
|
||||||
@ -129,10 +130,10 @@ percent-encoding = "2.1.0"
|
|||||||
idna = "0.2.3"
|
idna = "0.2.3"
|
||||||
|
|
||||||
# CLI argument parsing
|
# CLI argument parsing
|
||||||
pico-args = "0.4.1"
|
pico-args = "0.4.2"
|
||||||
|
|
||||||
# Logging panics to logfile instead stderr only
|
# Logging panics to logfile instead stderr only
|
||||||
backtrace = "0.3.59"
|
backtrace = "0.3.60"
|
||||||
|
|
||||||
# Macro ident concatenation
|
# Macro ident concatenation
|
||||||
paste = "1.0.5"
|
paste = "1.0.5"
|
||||||
@ -151,3 +152,6 @@ data-url = { git = 'https://github.com/servo/rust-url', package="data-url", rev
|
|||||||
# In particular, `cron` has since implemented parsing of some common syntax
|
# In particular, `cron` has since implemented parsing of some common syntax
|
||||||
# that wasn't previously supported (https://github.com/zslayton/cron/pull/64).
|
# that wasn't previously supported (https://github.com/zslayton/cron/pull/64).
|
||||||
job_scheduler = { git = 'https://github.com/jjlin/job_scheduler', rev = 'ee023418dbba2bfe1e30a5fd7d937f9e33739806' }
|
job_scheduler = { git = 'https://github.com/jjlin/job_scheduler', rev = 'ee023418dbba2bfe1e30a5fd7d937f9e33739806' }
|
||||||
|
|
||||||
|
# Add support for U2F appid extension compatibility
|
||||||
|
webauthn-rs = { git = 'https://github.com/dani-garcia/webauthn-rs', rev = '70b458f246d207e5b6333ada9f1d5794c5e01da1' }
|
||||||
|
@ -44,8 +44,8 @@
|
|||||||
# https://docs.docker.com/develop/develop-images/multistage-build/
|
# https://docs.docker.com/develop/develop-images/multistage-build/
|
||||||
# https://whitfin.io/speeding-up-rust-docker-builds/
|
# https://whitfin.io/speeding-up-rust-docker-builds/
|
||||||
####################### VAULT BUILD IMAGE #######################
|
####################### VAULT BUILD IMAGE #######################
|
||||||
{% set vault_version = "2.19.0d" %}
|
{% set vault_version = "2.20.4" %}
|
||||||
{% set vault_image_digest = "sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233" %}
|
{% set vault_image_digest = "sha256:810919341388a50d3a88225ce234333f72eb80382953997e9fd5590cca829e1b" %}
|
||||||
# The web-vault digest specifies a particular web-vault build on Docker Hub.
|
# The web-vault digest specifies a particular web-vault build on Docker Hub.
|
||||||
# Using the digest instead of the tag name provides better security,
|
# Using the digest instead of the tag name provides better security,
|
||||||
# as the digest of an image is immutable, whereas a tag name can later
|
# as the digest of an image is immutable, whereas a tag name can later
|
||||||
|
@ -14,15 +14,15 @@
|
|||||||
# - From https://hub.docker.com/r/vaultwarden/web-vault/tags,
|
# - From https://hub.docker.com/r/vaultwarden/web-vault/tags,
|
||||||
# click the tag name to view the digest of the image it currently points to.
|
# click the tag name to view the digest of the image it currently points to.
|
||||||
# - From the command line:
|
# - From the command line:
|
||||||
# $ docker pull vaultwarden/web-vault:v2.19.0d
|
# $ docker pull vaultwarden/web-vault:v2.20.4
|
||||||
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.19.0d
|
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.20.4
|
||||||
# [vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233]
|
# [vaultwarden/web-vault@sha256:810919341388a50d3a88225ce234333f72eb80382953997e9fd5590cca829e1b]
|
||||||
#
|
#
|
||||||
# - Conversely, to get the tag name from the digest:
|
# - Conversely, to get the tag name from the digest:
|
||||||
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233
|
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:810919341388a50d3a88225ce234333f72eb80382953997e9fd5590cca829e1b
|
||||||
# [vaultwarden/web-vault:v2.19.0d]
|
# [vaultwarden/web-vault:v2.20.4]
|
||||||
#
|
#
|
||||||
FROM vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233 as vault
|
FROM vaultwarden/web-vault@sha256:810919341388a50d3a88225ce234333f72eb80382953997e9fd5590cca829e1b as vault
|
||||||
|
|
||||||
########################## BUILD IMAGE ##########################
|
########################## BUILD IMAGE ##########################
|
||||||
FROM rust:1.51 as build
|
FROM rust:1.51 as build
|
||||||
|
@ -14,15 +14,15 @@
|
|||||||
# - From https://hub.docker.com/r/vaultwarden/web-vault/tags,
|
# - From https://hub.docker.com/r/vaultwarden/web-vault/tags,
|
||||||
# click the tag name to view the digest of the image it currently points to.
|
# click the tag name to view the digest of the image it currently points to.
|
||||||
# - From the command line:
|
# - From the command line:
|
||||||
# $ docker pull vaultwarden/web-vault:v2.19.0d
|
# $ docker pull vaultwarden/web-vault:v2.20.4
|
||||||
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.19.0d
|
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.20.4
|
||||||
# [vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233]
|
# [vaultwarden/web-vault@sha256:810919341388a50d3a88225ce234333f72eb80382953997e9fd5590cca829e1b]
|
||||||
#
|
#
|
||||||
# - Conversely, to get the tag name from the digest:
|
# - Conversely, to get the tag name from the digest:
|
||||||
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233
|
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:810919341388a50d3a88225ce234333f72eb80382953997e9fd5590cca829e1b
|
||||||
# [vaultwarden/web-vault:v2.19.0d]
|
# [vaultwarden/web-vault:v2.20.4]
|
||||||
#
|
#
|
||||||
FROM vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233 as vault
|
FROM vaultwarden/web-vault@sha256:810919341388a50d3a88225ce234333f72eb80382953997e9fd5590cca829e1b as vault
|
||||||
|
|
||||||
########################## BUILD IMAGE ##########################
|
########################## BUILD IMAGE ##########################
|
||||||
FROM clux/muslrust:nightly-2021-04-14 as build
|
FROM clux/muslrust:nightly-2021-04-14 as build
|
||||||
|
@ -14,15 +14,15 @@
|
|||||||
# - From https://hub.docker.com/r/vaultwarden/web-vault/tags,
|
# - From https://hub.docker.com/r/vaultwarden/web-vault/tags,
|
||||||
# click the tag name to view the digest of the image it currently points to.
|
# click the tag name to view the digest of the image it currently points to.
|
||||||
# - From the command line:
|
# - From the command line:
|
||||||
# $ docker pull vaultwarden/web-vault:v2.19.0d
|
# $ docker pull vaultwarden/web-vault:v2.20.4
|
||||||
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.19.0d
|
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.20.4
|
||||||
# [vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233]
|
# [vaultwarden/web-vault@sha256:810919341388a50d3a88225ce234333f72eb80382953997e9fd5590cca829e1b]
|
||||||
#
|
#
|
||||||
# - Conversely, to get the tag name from the digest:
|
# - Conversely, to get the tag name from the digest:
|
||||||
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233
|
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:810919341388a50d3a88225ce234333f72eb80382953997e9fd5590cca829e1b
|
||||||
# [vaultwarden/web-vault:v2.19.0d]
|
# [vaultwarden/web-vault:v2.20.4]
|
||||||
#
|
#
|
||||||
FROM vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233 as vault
|
FROM vaultwarden/web-vault@sha256:810919341388a50d3a88225ce234333f72eb80382953997e9fd5590cca829e1b as vault
|
||||||
|
|
||||||
########################## BUILD IMAGE ##########################
|
########################## BUILD IMAGE ##########################
|
||||||
FROM rust:1.51 as build
|
FROM rust:1.51 as build
|
||||||
|
@ -14,15 +14,15 @@
|
|||||||
# - From https://hub.docker.com/r/vaultwarden/web-vault/tags,
|
# - From https://hub.docker.com/r/vaultwarden/web-vault/tags,
|
||||||
# click the tag name to view the digest of the image it currently points to.
|
# click the tag name to view the digest of the image it currently points to.
|
||||||
# - From the command line:
|
# - From the command line:
|
||||||
# $ docker pull vaultwarden/web-vault:v2.19.0d
|
# $ docker pull vaultwarden/web-vault:v2.20.4
|
||||||
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.19.0d
|
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.20.4
|
||||||
# [vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233]
|
# [vaultwarden/web-vault@sha256:810919341388a50d3a88225ce234333f72eb80382953997e9fd5590cca829e1b]
|
||||||
#
|
#
|
||||||
# - Conversely, to get the tag name from the digest:
|
# - Conversely, to get the tag name from the digest:
|
||||||
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233
|
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:810919341388a50d3a88225ce234333f72eb80382953997e9fd5590cca829e1b
|
||||||
# [vaultwarden/web-vault:v2.19.0d]
|
# [vaultwarden/web-vault:v2.20.4]
|
||||||
#
|
#
|
||||||
FROM vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233 as vault
|
FROM vaultwarden/web-vault@sha256:810919341388a50d3a88225ce234333f72eb80382953997e9fd5590cca829e1b as vault
|
||||||
|
|
||||||
########################## BUILD IMAGE ##########################
|
########################## BUILD IMAGE ##########################
|
||||||
FROM rust:1.51 as build
|
FROM rust:1.51 as build
|
||||||
|
@ -14,15 +14,15 @@
|
|||||||
# - From https://hub.docker.com/r/vaultwarden/web-vault/tags,
|
# - From https://hub.docker.com/r/vaultwarden/web-vault/tags,
|
||||||
# click the tag name to view the digest of the image it currently points to.
|
# click the tag name to view the digest of the image it currently points to.
|
||||||
# - From the command line:
|
# - From the command line:
|
||||||
# $ docker pull vaultwarden/web-vault:v2.19.0d
|
# $ docker pull vaultwarden/web-vault:v2.20.4
|
||||||
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.19.0d
|
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.20.4
|
||||||
# [vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233]
|
# [vaultwarden/web-vault@sha256:810919341388a50d3a88225ce234333f72eb80382953997e9fd5590cca829e1b]
|
||||||
#
|
#
|
||||||
# - Conversely, to get the tag name from the digest:
|
# - Conversely, to get the tag name from the digest:
|
||||||
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233
|
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:810919341388a50d3a88225ce234333f72eb80382953997e9fd5590cca829e1b
|
||||||
# [vaultwarden/web-vault:v2.19.0d]
|
# [vaultwarden/web-vault:v2.20.4]
|
||||||
#
|
#
|
||||||
FROM vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233 as vault
|
FROM vaultwarden/web-vault@sha256:810919341388a50d3a88225ce234333f72eb80382953997e9fd5590cca829e1b as vault
|
||||||
|
|
||||||
########################## BUILD IMAGE ##########################
|
########################## BUILD IMAGE ##########################
|
||||||
FROM rust:1.51 as build
|
FROM rust:1.51 as build
|
||||||
|
@ -14,15 +14,15 @@
|
|||||||
# - From https://hub.docker.com/r/vaultwarden/web-vault/tags,
|
# - From https://hub.docker.com/r/vaultwarden/web-vault/tags,
|
||||||
# click the tag name to view the digest of the image it currently points to.
|
# click the tag name to view the digest of the image it currently points to.
|
||||||
# - From the command line:
|
# - From the command line:
|
||||||
# $ docker pull vaultwarden/web-vault:v2.19.0d
|
# $ docker pull vaultwarden/web-vault:v2.20.4
|
||||||
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.19.0d
|
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.20.4
|
||||||
# [vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233]
|
# [vaultwarden/web-vault@sha256:810919341388a50d3a88225ce234333f72eb80382953997e9fd5590cca829e1b]
|
||||||
#
|
#
|
||||||
# - Conversely, to get the tag name from the digest:
|
# - Conversely, to get the tag name from the digest:
|
||||||
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233
|
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:810919341388a50d3a88225ce234333f72eb80382953997e9fd5590cca829e1b
|
||||||
# [vaultwarden/web-vault:v2.19.0d]
|
# [vaultwarden/web-vault:v2.20.4]
|
||||||
#
|
#
|
||||||
FROM vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233 as vault
|
FROM vaultwarden/web-vault@sha256:810919341388a50d3a88225ce234333f72eb80382953997e9fd5590cca829e1b as vault
|
||||||
|
|
||||||
########################## BUILD IMAGE ##########################
|
########################## BUILD IMAGE ##########################
|
||||||
FROM messense/rust-musl-cross:armv7-musleabihf as build
|
FROM messense/rust-musl-cross:armv7-musleabihf as build
|
||||||
|
@ -17,6 +17,7 @@ pub mod authenticator;
|
|||||||
pub mod duo;
|
pub mod duo;
|
||||||
pub mod email;
|
pub mod email;
|
||||||
pub mod u2f;
|
pub mod u2f;
|
||||||
|
pub mod webauthn;
|
||||||
pub mod yubikey;
|
pub mod yubikey;
|
||||||
|
|
||||||
pub fn routes() -> Vec<Route> {
|
pub fn routes() -> Vec<Route> {
|
||||||
@ -26,6 +27,7 @@ pub fn routes() -> Vec<Route> {
|
|||||||
routes.append(&mut duo::routes());
|
routes.append(&mut duo::routes());
|
||||||
routes.append(&mut email::routes());
|
routes.append(&mut email::routes());
|
||||||
routes.append(&mut u2f::routes());
|
routes.append(&mut u2f::routes());
|
||||||
|
routes.append(&mut webauthn::routes());
|
||||||
routes.append(&mut yubikey::routes());
|
routes.append(&mut yubikey::routes());
|
||||||
|
|
||||||
routes
|
routes
|
||||||
|
@ -94,13 +94,14 @@ struct RegistrationDef {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
struct U2FRegistration {
|
pub struct U2FRegistration {
|
||||||
id: i32,
|
pub id: i32,
|
||||||
name: String,
|
pub name: String,
|
||||||
#[serde(with = "RegistrationDef")]
|
#[serde(with = "RegistrationDef")]
|
||||||
reg: Registration,
|
pub reg: Registration,
|
||||||
counter: u32,
|
pub counter: u32,
|
||||||
compromised: bool,
|
compromised: bool,
|
||||||
|
pub migrated: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl U2FRegistration {
|
impl U2FRegistration {
|
||||||
@ -168,6 +169,7 @@ fn activate_u2f(data: JsonUpcase<EnableU2FData>, headers: Headers, conn: DbConn)
|
|||||||
reg: registration,
|
reg: registration,
|
||||||
compromised: false,
|
compromised: false,
|
||||||
counter: 0,
|
counter: 0,
|
||||||
|
migrated: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut regs = get_u2f_registrations(&user.uuid, &conn)?.1;
|
let mut regs = get_u2f_registrations(&user.uuid, &conn)?.1;
|
||||||
@ -273,6 +275,7 @@ fn get_u2f_registrations(user_uuid: &str, conn: &DbConn) -> Result<(bool, Vec<U2
|
|||||||
reg: old_regs.remove(0),
|
reg: old_regs.remove(0),
|
||||||
compromised: false,
|
compromised: false,
|
||||||
counter: 0,
|
counter: 0,
|
||||||
|
migrated: None,
|
||||||
}];
|
}];
|
||||||
|
|
||||||
// Save new format
|
// Save new format
|
||||||
|
394
src/api/core/two_factor/webauthn.rs
Normal file
394
src/api/core/two_factor/webauthn.rs
Normal file
@ -0,0 +1,394 @@
|
|||||||
|
use rocket::Route;
|
||||||
|
use rocket_contrib::json::Json;
|
||||||
|
use serde_json::Value;
|
||||||
|
use webauthn_rs::{base64_data::Base64UrlSafeData, proto::*, AuthenticationState, RegistrationState, Webauthn};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
api::{
|
||||||
|
core::two_factor::_generate_recover_code, EmptyResult, JsonResult, JsonUpcase, NumberOrString, PasswordData,
|
||||||
|
},
|
||||||
|
auth::Headers,
|
||||||
|
db::{
|
||||||
|
models::{TwoFactor, TwoFactorType},
|
||||||
|
DbConn,
|
||||||
|
},
|
||||||
|
error::Error,
|
||||||
|
CONFIG,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn routes() -> Vec<Route> {
|
||||||
|
routes![get_webauthn, generate_webauthn_challenge, activate_webauthn, activate_webauthn_put, delete_webauthn,]
|
||||||
|
}
|
||||||
|
|
||||||
|
struct WebauthnConfig {
|
||||||
|
url: String,
|
||||||
|
rpid: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebauthnConfig {
|
||||||
|
fn load() -> Webauthn<Self> {
|
||||||
|
let domain = CONFIG.domain();
|
||||||
|
Webauthn::new(Self {
|
||||||
|
rpid: reqwest::Url::parse(&domain)
|
||||||
|
.map(|u| u.domain().map(str::to_owned))
|
||||||
|
.ok()
|
||||||
|
.flatten()
|
||||||
|
.unwrap_or_default(),
|
||||||
|
url: domain,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl webauthn_rs::WebauthnConfig for WebauthnConfig {
|
||||||
|
fn get_relying_party_name(&self) -> &str {
|
||||||
|
&self.url
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_origin(&self) -> &str {
|
||||||
|
&self.url
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_relying_party_id(&self) -> &str {
|
||||||
|
&self.rpid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl webauthn_rs::WebauthnConfig for &WebauthnConfig {
|
||||||
|
fn get_relying_party_name(&self) -> &str {
|
||||||
|
&self.url
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_origin(&self) -> &str {
|
||||||
|
&self.url
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_relying_party_id(&self) -> &str {
|
||||||
|
&self.rpid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct WebauthnRegistration {
|
||||||
|
pub id: i32,
|
||||||
|
pub name: String,
|
||||||
|
pub migrated: bool,
|
||||||
|
|
||||||
|
pub credential: Credential,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WebauthnRegistration {
|
||||||
|
fn to_json(&self) -> Value {
|
||||||
|
json!({
|
||||||
|
"Id": self.id,
|
||||||
|
"Name": self.name,
|
||||||
|
"migrated": self.migrated,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[post("/two-factor/get-webauthn", data = "<data>")]
|
||||||
|
fn get_webauthn(data: JsonUpcase<PasswordData>, headers: Headers, conn: DbConn) -> JsonResult {
|
||||||
|
if !CONFIG.domain_set() {
|
||||||
|
err!("`DOMAIN` environment variable is not set. Webauthn disabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !headers.user.check_valid_password(&data.data.MasterPasswordHash) {
|
||||||
|
err!("Invalid password");
|
||||||
|
}
|
||||||
|
|
||||||
|
let (enabled, registrations) = get_webauthn_registrations(&headers.user.uuid, &conn)?;
|
||||||
|
let registrations_json: Vec<Value> = registrations.iter().map(WebauthnRegistration::to_json).collect();
|
||||||
|
|
||||||
|
Ok(Json(json!({
|
||||||
|
"Enabled": enabled,
|
||||||
|
"Keys": registrations_json,
|
||||||
|
"Object": "twoFactorWebAuthn"
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[post("/two-factor/get-webauthn-challenge", data = "<data>")]
|
||||||
|
fn generate_webauthn_challenge(data: JsonUpcase<PasswordData>, headers: Headers, conn: DbConn) -> JsonResult {
|
||||||
|
if !headers.user.check_valid_password(&data.data.MasterPasswordHash) {
|
||||||
|
err!("Invalid password");
|
||||||
|
}
|
||||||
|
|
||||||
|
let registrations = get_webauthn_registrations(&headers.user.uuid, &conn)?
|
||||||
|
.1
|
||||||
|
.into_iter()
|
||||||
|
.map(|r| r.credential.cred_id) // We return the credentialIds to the clients to avoid double registering
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let (challenge, state) = WebauthnConfig::load().generate_challenge_register_options(
|
||||||
|
headers.user.uuid.as_bytes().to_vec(),
|
||||||
|
headers.user.email,
|
||||||
|
headers.user.name,
|
||||||
|
Some(registrations),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let type_ = TwoFactorType::WebauthnRegisterChallenge;
|
||||||
|
TwoFactor::new(headers.user.uuid.clone(), type_, serde_json::to_string(&state)?).save(&conn)?;
|
||||||
|
|
||||||
|
let mut challenge_value = serde_json::to_value(challenge.public_key)?;
|
||||||
|
challenge_value["status"] = "ok".into();
|
||||||
|
challenge_value["errorMessage"] = "".into();
|
||||||
|
Ok(Json(challenge_value))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
struct EnableWebauthnData {
|
||||||
|
Id: NumberOrString, // 1..5
|
||||||
|
Name: String,
|
||||||
|
MasterPasswordHash: String,
|
||||||
|
DeviceResponse: RegisterPublicKeyCredentialCopy,
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is copied from RegisterPublicKeyCredential to change the Response objects casing
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
struct RegisterPublicKeyCredentialCopy {
|
||||||
|
pub Id: String,
|
||||||
|
pub RawId: Base64UrlSafeData,
|
||||||
|
pub Response: AuthenticatorAttestationResponseRawCopy,
|
||||||
|
pub Type: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is copied from AuthenticatorAttestationResponseRaw to change clientDataJSON to clientDataJson
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub struct AuthenticatorAttestationResponseRawCopy {
|
||||||
|
pub AttestationObject: Base64UrlSafeData,
|
||||||
|
pub ClientDataJson: Base64UrlSafeData,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<RegisterPublicKeyCredentialCopy> for RegisterPublicKeyCredential {
|
||||||
|
fn from(r: RegisterPublicKeyCredentialCopy) -> Self {
|
||||||
|
Self {
|
||||||
|
id: r.Id,
|
||||||
|
raw_id: r.RawId,
|
||||||
|
response: AuthenticatorAttestationResponseRaw {
|
||||||
|
attestation_object: r.Response.AttestationObject,
|
||||||
|
client_data_json: r.Response.ClientDataJson,
|
||||||
|
},
|
||||||
|
type_: r.Type,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is copied from PublicKeyCredential to change the Response objects casing
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub struct PublicKeyCredentialCopy {
|
||||||
|
pub Id: String,
|
||||||
|
pub RawId: Base64UrlSafeData,
|
||||||
|
pub Response: AuthenticatorAssertionResponseRawCopy,
|
||||||
|
pub Extensions: Option<AuthenticationExtensionsClientOutputsCopy>,
|
||||||
|
pub Type: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is copied from AuthenticatorAssertionResponseRaw to change clientDataJSON to clientDataJson
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub struct AuthenticatorAssertionResponseRawCopy {
|
||||||
|
pub AuthenticatorData: Base64UrlSafeData,
|
||||||
|
pub ClientDataJson: Base64UrlSafeData,
|
||||||
|
pub Signature: Base64UrlSafeData,
|
||||||
|
pub UserHandle: Option<Base64UrlSafeData>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub struct AuthenticationExtensionsClientOutputsCopy {
|
||||||
|
#[serde(default)]
|
||||||
|
pub Appid: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<PublicKeyCredentialCopy> for PublicKeyCredential {
|
||||||
|
fn from(r: PublicKeyCredentialCopy) -> Self {
|
||||||
|
Self {
|
||||||
|
id: r.Id,
|
||||||
|
raw_id: r.RawId,
|
||||||
|
response: AuthenticatorAssertionResponseRaw {
|
||||||
|
authenticator_data: r.Response.AuthenticatorData,
|
||||||
|
client_data_json: r.Response.ClientDataJson,
|
||||||
|
signature: r.Response.Signature,
|
||||||
|
user_handle: r.Response.UserHandle,
|
||||||
|
},
|
||||||
|
extensions: r.Extensions.map(|e| AuthenticationExtensionsClientOutputs {
|
||||||
|
appid: e.Appid,
|
||||||
|
}),
|
||||||
|
type_: r.Type,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[post("/two-factor/webauthn", data = "<data>")]
|
||||||
|
fn activate_webauthn(data: JsonUpcase<EnableWebauthnData>, headers: Headers, conn: DbConn) -> JsonResult {
|
||||||
|
let data: EnableWebauthnData = data.into_inner().data;
|
||||||
|
let mut user = headers.user;
|
||||||
|
|
||||||
|
if !user.check_valid_password(&data.MasterPasswordHash) {
|
||||||
|
err!("Invalid password");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve and delete the saved challenge state
|
||||||
|
let type_ = TwoFactorType::WebauthnRegisterChallenge as i32;
|
||||||
|
let state = match TwoFactor::find_by_user_and_type(&user.uuid, type_, &conn) {
|
||||||
|
Some(tf) => {
|
||||||
|
let state: RegistrationState = serde_json::from_str(&tf.data)?;
|
||||||
|
tf.delete(&conn)?;
|
||||||
|
state
|
||||||
|
}
|
||||||
|
None => err!("Can't recover challenge"),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Verify the credentials with the saved state
|
||||||
|
let (credential, _data) =
|
||||||
|
WebauthnConfig::load().register_credential(&data.DeviceResponse.into(), &state, |_| Ok(false))?;
|
||||||
|
|
||||||
|
let mut registrations: Vec<_> = get_webauthn_registrations(&user.uuid, &conn)?.1;
|
||||||
|
// TODO: Check for repeated ID's
|
||||||
|
registrations.push(WebauthnRegistration {
|
||||||
|
id: data.Id.into_i32()?,
|
||||||
|
name: data.Name,
|
||||||
|
migrated: false,
|
||||||
|
|
||||||
|
credential,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Save the registrations and return them
|
||||||
|
TwoFactor::new(user.uuid.clone(), TwoFactorType::Webauthn, serde_json::to_string(®istrations)?).save(&conn)?;
|
||||||
|
_generate_recover_code(&mut user, &conn);
|
||||||
|
|
||||||
|
let keys_json: Vec<Value> = registrations.iter().map(WebauthnRegistration::to_json).collect();
|
||||||
|
Ok(Json(json!({
|
||||||
|
"Enabled": true,
|
||||||
|
"Keys": keys_json,
|
||||||
|
"Object": "twoFactorU2f"
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[put("/two-factor/webauthn", data = "<data>")]
|
||||||
|
fn activate_webauthn_put(data: JsonUpcase<EnableWebauthnData>, headers: Headers, conn: DbConn) -> JsonResult {
|
||||||
|
activate_webauthn(data, headers, conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
struct DeleteU2FData {
|
||||||
|
Id: NumberOrString,
|
||||||
|
MasterPasswordHash: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[delete("/two-factor/webauthn", data = "<data>")]
|
||||||
|
fn delete_webauthn(data: JsonUpcase<DeleteU2FData>, headers: Headers, conn: DbConn) -> JsonResult {
|
||||||
|
let id = data.data.Id.into_i32()?;
|
||||||
|
if !headers.user.check_valid_password(&data.data.MasterPasswordHash) {
|
||||||
|
err!("Invalid password");
|
||||||
|
}
|
||||||
|
|
||||||
|
let type_ = TwoFactorType::Webauthn as i32;
|
||||||
|
let mut tf = match TwoFactor::find_by_user_and_type(&headers.user.uuid, type_, &conn) {
|
||||||
|
Some(tf) => tf,
|
||||||
|
None => err!("Webauthn data not found!"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut data: Vec<WebauthnRegistration> = serde_json::from_str(&tf.data)?;
|
||||||
|
|
||||||
|
let item_pos = match data.iter().position(|r| r.id != id) {
|
||||||
|
Some(p) => p,
|
||||||
|
None => err!("Webauthn entry not found"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let removed_item = data.remove(item_pos);
|
||||||
|
tf.data = serde_json::to_string(&data)?;
|
||||||
|
tf.save(&conn)?;
|
||||||
|
drop(tf);
|
||||||
|
|
||||||
|
// If entry is migrated from u2f, delete the u2f entry as well
|
||||||
|
if let Some(mut u2f) = TwoFactor::find_by_user_and_type(&headers.user.uuid, TwoFactorType::U2f as i32, &conn) {
|
||||||
|
use crate::api::core::two_factor::u2f::U2FRegistration;
|
||||||
|
let mut data: Vec<U2FRegistration> = match serde_json::from_str(&u2f.data) {
|
||||||
|
Ok(d) => d,
|
||||||
|
Err(_) => err!("Error parsing U2F data"),
|
||||||
|
};
|
||||||
|
|
||||||
|
data.retain(|r| r.reg.key_handle != removed_item.credential.cred_id);
|
||||||
|
let new_data_str = serde_json::to_string(&data)?;
|
||||||
|
|
||||||
|
u2f.data = new_data_str;
|
||||||
|
u2f.save(&conn)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let keys_json: Vec<Value> = data.iter().map(WebauthnRegistration::to_json).collect();
|
||||||
|
|
||||||
|
Ok(Json(json!({
|
||||||
|
"Enabled": true,
|
||||||
|
"Keys": keys_json,
|
||||||
|
"Object": "twoFactorU2f"
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_webauthn_registrations(user_uuid: &str, conn: &DbConn) -> Result<(bool, Vec<WebauthnRegistration>), Error> {
|
||||||
|
let type_ = TwoFactorType::Webauthn as i32;
|
||||||
|
match TwoFactor::find_by_user_and_type(user_uuid, type_, conn) {
|
||||||
|
Some(tf) => Ok((tf.enabled, serde_json::from_str(&tf.data)?)),
|
||||||
|
None => Ok((false, Vec::new())), // If no data, return empty list
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generate_webauthn_login(user_uuid: &str, conn: &DbConn) -> JsonResult {
|
||||||
|
// Load saved credentials
|
||||||
|
let creds: Vec<Credential> =
|
||||||
|
get_webauthn_registrations(user_uuid, conn)?.1.into_iter().map(|r| r.credential).collect();
|
||||||
|
|
||||||
|
if creds.is_empty() {
|
||||||
|
err!("No Webauthn devices registered")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate a challenge based on the credentials
|
||||||
|
let ext = RequestAuthenticationExtensions::builder().appid(format!("{}/app-id.json", &CONFIG.domain())).build();
|
||||||
|
let (response, state) = WebauthnConfig::load().generate_challenge_authenticate_options(creds, Some(ext))?;
|
||||||
|
|
||||||
|
// Save the challenge state for later validation
|
||||||
|
TwoFactor::new(user_uuid.into(), TwoFactorType::WebauthnLoginChallenge, serde_json::to_string(&state)?)
|
||||||
|
.save(&conn)?;
|
||||||
|
|
||||||
|
// Return challenge to the clients
|
||||||
|
Ok(Json(serde_json::to_value(response.public_key)?))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn validate_webauthn_login(user_uuid: &str, response: &str, conn: &DbConn) -> EmptyResult {
|
||||||
|
let type_ = TwoFactorType::WebauthnLoginChallenge as i32;
|
||||||
|
let state = match TwoFactor::find_by_user_and_type(user_uuid, type_, conn) {
|
||||||
|
Some(tf) => {
|
||||||
|
let state: AuthenticationState = serde_json::from_str(&tf.data)?;
|
||||||
|
tf.delete(&conn)?;
|
||||||
|
state
|
||||||
|
}
|
||||||
|
None => err!("Can't recover login challenge"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let rsp: crate::util::UpCase<PublicKeyCredentialCopy> = serde_json::from_str(response)?;
|
||||||
|
let rsp: PublicKeyCredential = rsp.data.into();
|
||||||
|
|
||||||
|
let mut registrations = get_webauthn_registrations(user_uuid, conn)?.1;
|
||||||
|
|
||||||
|
// If the credential we received is migrated from U2F, enable the U2F compatibility
|
||||||
|
//let use_u2f = registrations.iter().any(|r| r.migrated && r.credential.cred_id == rsp.raw_id.0);
|
||||||
|
let (cred_id, auth_data) = WebauthnConfig::load().authenticate_credential(&rsp, &state)?;
|
||||||
|
|
||||||
|
for reg in &mut registrations {
|
||||||
|
if ®.credential.cred_id == cred_id {
|
||||||
|
reg.credential.counter = auth_data.counter;
|
||||||
|
|
||||||
|
TwoFactor::new(user_uuid.to_string(), TwoFactorType::Webauthn, serde_json::to_string(®istrations)?)
|
||||||
|
.save(&conn)?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err!("Credential not present")
|
||||||
|
}
|
@ -240,6 +240,7 @@ fn twofactor_auth(
|
|||||||
_tf::authenticator::validate_totp_code_str(user_uuid, twofactor_code, &selected_data?, ip, conn)?
|
_tf::authenticator::validate_totp_code_str(user_uuid, twofactor_code, &selected_data?, ip, conn)?
|
||||||
}
|
}
|
||||||
Some(TwoFactorType::U2f) => _tf::u2f::validate_u2f_login(user_uuid, twofactor_code, conn)?,
|
Some(TwoFactorType::U2f) => _tf::u2f::validate_u2f_login(user_uuid, twofactor_code, conn)?,
|
||||||
|
Some(TwoFactorType::Webauthn) => _tf::webauthn::validate_webauthn_login(user_uuid, twofactor_code, conn)?,
|
||||||
Some(TwoFactorType::YubiKey) => _tf::yubikey::validate_yubikey_login(twofactor_code, &selected_data?)?,
|
Some(TwoFactorType::YubiKey) => _tf::yubikey::validate_yubikey_login(twofactor_code, &selected_data?)?,
|
||||||
Some(TwoFactorType::Duo) => {
|
Some(TwoFactorType::Duo) => {
|
||||||
_tf::duo::validate_duo_login(data.username.as_ref().unwrap(), twofactor_code, conn)?
|
_tf::duo::validate_duo_login(data.username.as_ref().unwrap(), twofactor_code, conn)?
|
||||||
@ -309,6 +310,11 @@ fn _json_err_twofactor(providers: &[i32], user_uuid: &str, conn: &DbConn) -> Api
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some(TwoFactorType::Webauthn) if CONFIG.domain_set() => {
|
||||||
|
let request = two_factor::webauthn::generate_webauthn_login(user_uuid, conn)?;
|
||||||
|
result["TwoFactorProviders2"][provider.to_string()] = request.0;
|
||||||
|
}
|
||||||
|
|
||||||
Some(TwoFactorType::Duo) => {
|
Some(TwoFactorType::Duo) => {
|
||||||
let email = match User::find_by_uuid(user_uuid, &conn) {
|
let email = match User::find_by_uuid(user_uuid, &conn) {
|
||||||
Some(u) => u.email,
|
Some(u) => u.email,
|
||||||
|
@ -51,10 +51,10 @@ impl NumberOrString {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_i32(self) -> ApiResult<i32> {
|
fn into_i32(&self) -> ApiResult<i32> {
|
||||||
use std::num::ParseIntError as PIE;
|
use std::num::ParseIntError as PIE;
|
||||||
match self {
|
match self {
|
||||||
NumberOrString::Number(n) => Ok(n),
|
NumberOrString::Number(n) => Ok(*n),
|
||||||
NumberOrString::String(s) => {
|
NumberOrString::String(s) => {
|
||||||
s.parse().map_err(|e: PIE| crate::Error::new("Can't convert to number", e.to_string()))
|
s.parse().map_err(|e: PIE| crate::Error::new("Can't convert to number", e.to_string()))
|
||||||
}
|
}
|
||||||
|
@ -114,7 +114,7 @@ macro_rules! db_run {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Different code for each db
|
// Different code for each db
|
||||||
( $conn:ident: $( $($db:ident),+ $body:block )+ ) => {
|
( $conn:ident: $( $($db:ident),+ $body:block )+ ) => {{
|
||||||
#[allow(unused)] use diesel::prelude::*;
|
#[allow(unused)] use diesel::prelude::*;
|
||||||
match $conn {
|
match $conn {
|
||||||
$($(
|
$($(
|
||||||
@ -128,7 +128,7 @@ macro_rules! db_run {
|
|||||||
$body
|
$body
|
||||||
},
|
},
|
||||||
)+)+
|
)+)+
|
||||||
}
|
}}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Same for all dbs
|
// Same for all dbs
|
||||||
|
@ -31,11 +31,14 @@ pub enum TwoFactorType {
|
|||||||
U2f = 4,
|
U2f = 4,
|
||||||
Remember = 5,
|
Remember = 5,
|
||||||
OrganizationDuo = 6,
|
OrganizationDuo = 6,
|
||||||
|
Webauthn = 7,
|
||||||
|
|
||||||
// These are implementation details
|
// These are implementation details
|
||||||
U2fRegisterChallenge = 1000,
|
U2fRegisterChallenge = 1000,
|
||||||
U2fLoginChallenge = 1001,
|
U2fLoginChallenge = 1001,
|
||||||
EmailVerificationChallenge = 1002,
|
EmailVerificationChallenge = 1002,
|
||||||
|
WebauthnRegisterChallenge = 1003,
|
||||||
|
WebauthnLoginChallenge = 1004,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Local methods
|
/// Local methods
|
||||||
@ -146,4 +149,73 @@ impl TwoFactor {
|
|||||||
.map_res("Error deleting twofactors")
|
.map_res("Error deleting twofactors")
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn migrate_u2f_to_webauthn(conn: &DbConn) -> EmptyResult {
|
||||||
|
let u2f_factors = db_run! { conn: {
|
||||||
|
twofactor::table
|
||||||
|
.filter(twofactor::atype.eq(TwoFactorType::U2f as i32))
|
||||||
|
.load::<TwoFactorDb>(conn)
|
||||||
|
.expect("Error loading twofactor")
|
||||||
|
.from_db()
|
||||||
|
}};
|
||||||
|
|
||||||
|
use crate::api::core::two_factor::u2f::U2FRegistration;
|
||||||
|
use crate::api::core::two_factor::webauthn::{get_webauthn_registrations, WebauthnRegistration};
|
||||||
|
use std::convert::TryInto;
|
||||||
|
use webauthn_rs::proto::*;
|
||||||
|
|
||||||
|
for mut u2f in u2f_factors {
|
||||||
|
let mut regs: Vec<U2FRegistration> = serde_json::from_str(&u2f.data)?;
|
||||||
|
// If there are no registrations or they are migrated (we do the migration in batch so we can consider them all migrated when the first one is)
|
||||||
|
if regs.is_empty() || regs[0].migrated == Some(true) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (_, mut webauthn_regs) = get_webauthn_registrations(&u2f.user_uuid, &conn)?;
|
||||||
|
|
||||||
|
// If the user already has webauthn registrations saved, don't overwrite them
|
||||||
|
if !webauthn_regs.is_empty() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for reg in &mut regs {
|
||||||
|
let x: [u8; 32] = reg.reg.pub_key[1..33].try_into().unwrap();
|
||||||
|
let y: [u8; 32] = reg.reg.pub_key[33..65].try_into().unwrap();
|
||||||
|
|
||||||
|
let key = COSEKey {
|
||||||
|
type_: COSEAlgorithm::ES256,
|
||||||
|
key: COSEKeyType::EC_EC2(COSEEC2Key {
|
||||||
|
curve: ECDSACurve::SECP256R1,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
let new_reg = WebauthnRegistration {
|
||||||
|
id: reg.id,
|
||||||
|
migrated: true,
|
||||||
|
name: reg.name.clone(),
|
||||||
|
credential: Credential {
|
||||||
|
counter: reg.counter,
|
||||||
|
verified: false,
|
||||||
|
cred: key,
|
||||||
|
cred_id: reg.reg.key_handle.clone(),
|
||||||
|
registration_policy: UserVerificationPolicy::Discouraged,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
webauthn_regs.push(new_reg);
|
||||||
|
|
||||||
|
reg.migrated = Some(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
u2f.data = serde_json::to_string(®s)?;
|
||||||
|
u2f.save(&conn)?;
|
||||||
|
|
||||||
|
TwoFactor::new(u2f.user_uuid.clone(), TwoFactorType::Webauthn, serde_json::to_string(&webauthn_regs)?)
|
||||||
|
.save(&conn)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
10
src/error.rs
10
src/error.rs
@ -39,19 +39,18 @@ use diesel::ConnectionError as DieselConErr;
|
|||||||
use diesel_migrations::RunMigrationsError as DieselMigErr;
|
use diesel_migrations::RunMigrationsError as DieselMigErr;
|
||||||
use handlebars::RenderError as HbErr;
|
use handlebars::RenderError as HbErr;
|
||||||
use jsonwebtoken::errors::Error as JwtErr;
|
use jsonwebtoken::errors::Error as JwtErr;
|
||||||
|
use lettre::address::AddressError as AddrErr;
|
||||||
|
use lettre::error::Error as LettreErr;
|
||||||
|
use lettre::transport::smtp::Error as SmtpErr;
|
||||||
use regex::Error as RegexErr;
|
use regex::Error as RegexErr;
|
||||||
use reqwest::Error as ReqErr;
|
use reqwest::Error as ReqErr;
|
||||||
use serde_json::{Error as SerdeErr, Value};
|
use serde_json::{Error as SerdeErr, Value};
|
||||||
use std::io::Error as IoErr;
|
use std::io::Error as IoErr;
|
||||||
|
|
||||||
use std::time::SystemTimeError as TimeErr;
|
use std::time::SystemTimeError as TimeErr;
|
||||||
use u2f::u2ferror::U2fError as U2fErr;
|
use u2f::u2ferror::U2fError as U2fErr;
|
||||||
|
use webauthn_rs::error::WebauthnError as WebauthnErr;
|
||||||
use yubico::yubicoerror::YubicoError as YubiErr;
|
use yubico::yubicoerror::YubicoError as YubiErr;
|
||||||
|
|
||||||
use lettre::address::AddressError as AddrErr;
|
|
||||||
use lettre::error::Error as LettreErr;
|
|
||||||
use lettre::transport::smtp::Error as SmtpErr;
|
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
pub struct Empty {}
|
pub struct Empty {}
|
||||||
|
|
||||||
@ -86,6 +85,7 @@ make_error! {
|
|||||||
|
|
||||||
DieselConError(DieselConErr): _has_source, _api_error,
|
DieselConError(DieselConErr): _has_source, _api_error,
|
||||||
DieselMigError(DieselMigErr): _has_source, _api_error,
|
DieselMigError(DieselMigErr): _has_source, _api_error,
|
||||||
|
WebauthnError(WebauthnErr): _has_source, _api_error,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Debug for Error {
|
impl std::fmt::Debug for Error {
|
||||||
|
@ -60,6 +60,8 @@ fn main() {
|
|||||||
|
|
||||||
let pool = create_db_pool();
|
let pool = create_db_pool();
|
||||||
schedule_jobs(pool.clone());
|
schedule_jobs(pool.clone());
|
||||||
|
crate::db::models::TwoFactor::migrate_u2f_to_webauthn(&pool.get().unwrap()).unwrap();
|
||||||
|
|
||||||
launch_rocket(pool, extra_debug); // Blocks until program termination.
|
launch_rocket(pool, extra_debug); // Blocks until program termination.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user