This commit is contained in:
Bernd Schoolmann 2024-04-25 22:47:18 +00:00 committed by GitHub
commit 8678ca82f6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 751 additions and 21 deletions

View File

@ -275,6 +275,14 @@ export abstract class BrowserPlatformUtilsService implements PlatformUtilsServic
return false;
}
async biometricsNeedsSetup(): Promise<boolean> {
return false;
}
async biometricsSetup(): Promise<void> {
return;
}
authenticateBiometric() {
return this.biometricCallback();
}

View File

@ -60,6 +60,183 @@ dependencies = [
"x11rb",
]
[[package]]
name = "async-broadcast"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c48ccdbf6ca6b121e0f586cbc0e73ae440e56c67c30fa0873b4e110d9c26d2b"
dependencies = [
"event-listener 2.5.3",
"futures-core",
]
[[package]]
name = "async-channel"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f28243a43d821d11341ab73c80bed182dc015c514b951616cf79bd4af39af0c3"
dependencies = [
"concurrent-queue",
"event-listener 5.3.0",
"event-listener-strategy 0.5.1",
"futures-core",
"pin-project-lite",
]
[[package]]
name = "async-executor"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f98c37cf288e302c16ef6c8472aad1e034c6c84ce5ea7b8101c98eb4a802fee"
dependencies = [
"async-lock 3.3.0",
"async-task",
"concurrent-queue",
"fastrand 2.0.1",
"futures-lite 2.3.0",
"slab",
]
[[package]]
name = "async-fs"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "279cf904654eeebfa37ac9bb1598880884924aab82e290aa65c9e77a0e142e06"
dependencies = [
"async-lock 2.8.0",
"autocfg",
"blocking",
"futures-lite 1.13.0",
]
[[package]]
name = "async-io"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af"
dependencies = [
"async-lock 2.8.0",
"autocfg",
"cfg-if",
"concurrent-queue",
"futures-lite 1.13.0",
"log",
"parking",
"polling 2.8.0",
"rustix 0.37.27",
"slab",
"socket2",
"waker-fn",
]
[[package]]
name = "async-io"
version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcccb0f599cfa2f8ace422d3555572f47424da5648a4382a9dd0310ff8210884"
dependencies = [
"async-lock 3.3.0",
"cfg-if",
"concurrent-queue",
"futures-io",
"futures-lite 2.3.0",
"parking",
"polling 3.4.0",
"rustix 0.38.28",
"slab",
"tracing",
"windows-sys 0.52.0",
]
[[package]]
name = "async-lock"
version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b"
dependencies = [
"event-listener 2.5.3",
]
[[package]]
name = "async-lock"
version = "3.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b"
dependencies = [
"event-listener 4.0.3",
"event-listener-strategy 0.4.0",
"pin-project-lite",
]
[[package]]
name = "async-process"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea6438ba0a08d81529c69b36700fa2f95837bfe3e776ab39cde9c14d9149da88"
dependencies = [
"async-io 1.13.0",
"async-lock 2.8.0",
"async-signal",
"blocking",
"cfg-if",
"event-listener 3.1.0",
"futures-lite 1.13.0",
"rustix 0.38.28",
"windows-sys 0.48.0",
]
[[package]]
name = "async-recursion"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30c5ef0ede93efbf733c1a727f3b6b5a1060bbedd5600183e66f6e4be4af0ec5"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.38",
]
[[package]]
name = "async-signal"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e47d90f65a225c4527103a8d747001fc56e375203592b25ad103e1ca13124c5"
dependencies = [
"async-io 2.3.2",
"async-lock 2.8.0",
"atomic-waker",
"cfg-if",
"futures-core",
"futures-io",
"rustix 0.38.28",
"signal-hook-registry",
"slab",
"windows-sys 0.48.0",
]
[[package]]
name = "async-task"
version = "4.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbb36e985947064623dbd357f727af08ffd077f93d696782f3c56365fa2e2799"
[[package]]
name = "async-trait"
version = "0.1.76"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "531b97fb4cd3dfdce92c35dedbfdc1f0b9d8091c8ca943d6dae340ef5012d514"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.38",
]
[[package]]
name = "atomic-waker"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
[[package]]
name = "autocfg"
version = "1.2.0"
@ -189,6 +366,15 @@ dependencies = [
"unicode-width",
]
[[package]]
name = "concurrent-queue"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363"
dependencies = [
"crossbeam-utils",
]
[[package]]
name = "convert_case"
version = "0.6.0"
@ -223,6 +409,12 @@ dependencies = [
"libc",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
[[package]]
name = "crypto-common"
version = "0.1.6"
@ -287,6 +479,17 @@ dependencies = [
"syn",
]
[[package]]
name = "derivative"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "derive-new"
version = "0.6.0"
@ -305,6 +508,7 @@ dependencies = [
"aes",
"anyhow",
"arboard",
"async-trait",
"base64",
"cbc",
"core-foundation",
@ -324,6 +528,8 @@ dependencies = [
"typenum",
"widestring",
"windows",
"zbus",
"zbus_polkit",
]
[[package]]
@ -351,6 +557,27 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
[[package]]
name = "enumflags2"
version = "0.7.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3278c9d5fb675e0a51dabcf4c0d355f692b064171535ba72361be1528a9d8e8d"
dependencies = [
"enumflags2_derive",
"serde",
]
[[package]]
name = "enumflags2_derive"
version = "0.7.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c785274071b1b420972453b306eeca06acf4633829db4223b58a2a8c5953bc4"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.38",
]
[[package]]
name = "equivalent"
version = "1.0.1"
@ -364,7 +591,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
dependencies = [
"libc",
"windows-sys",
"windows-sys 0.52.0",
]
[[package]]
@ -379,6 +606,74 @@ version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984"
[[package]]
name = "event-listener"
version = "2.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
[[package]]
name = "event-listener"
version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d93877bcde0eb80ca09131a08d23f0a5c18a620b01db137dba666d18cd9b30c2"
dependencies = [
"concurrent-queue",
"parking",
"pin-project-lite",
]
[[package]]
name = "event-listener"
version = "4.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e"
dependencies = [
"concurrent-queue",
"parking",
"pin-project-lite",
]
[[package]]
name = "event-listener"
version = "5.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d9944b8ca13534cdfb2800775f8dd4902ff3fc75a50101466decadfdf322a24"
dependencies = [
"concurrent-queue",
"parking",
"pin-project-lite",
]
[[package]]
name = "event-listener-strategy"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3"
dependencies = [
"event-listener 4.0.3",
"pin-project-lite",
]
[[package]]
name = "event-listener-strategy"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "332f51cb23d20b0de8458b86580878211da09bcd4503cb579c225b3d124cabb3"
dependencies = [
"event-listener 5.3.0",
"pin-project-lite",
]
[[package]]
name = "fastrand"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be"
dependencies = [
"instant",
]
[[package]]
name = "fixedbitset"
version = "0.4.2"
@ -434,12 +729,46 @@ dependencies = [
"syn",
]
[[package]]
name = "futures-lite"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce"
dependencies = [
"fastrand 1.9.0",
"futures-core",
"futures-io",
"memchr",
"parking",
"pin-project-lite",
"waker-fn",
]
[[package]]
name = "futures-lite"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5"
dependencies = [
"fastrand 2.0.1",
"futures-core",
"futures-io",
"parking",
"pin-project-lite",
]
[[package]]
name = "futures-task"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
[[package]]
name = "futures-sink"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
[[package]]
name = "futures-util"
version = "0.3.30"
@ -447,8 +776,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
dependencies = [
"futures-core",
"futures-io",
"futures-macro",
"futures-sink",
"futures-task",
"memchr",
"pin-project-lite",
"pin-utils",
"slab",
@ -551,7 +883,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9972bb91643d589c889654693a4f1d07697fdcb5d104b5c44fb68649ba1bf68d"
dependencies = [
"heck",
"proc-macro-crate",
"proc-macro-crate 3.1.0",
"proc-macro2",
"quote",
"syn",
@ -596,6 +928,12 @@ version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
[[package]]
name = "hex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "home"
version = "0.5.9"
@ -625,6 +963,26 @@ dependencies = [
"generic-array",
]
[[package]]
name = "instant"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
dependencies = [
"cfg-if",
]
[[package]]
name = "io-lifetimes"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
dependencies = [
"hermit-abi",
"libc",
"windows-sys 0.48.0",
]
[[package]]
name = "keytar"
version = "0.1.6"
@ -697,6 +1055,12 @@ dependencies = [
"cc",
]
[[package]]
name = "linux-raw-sys"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
[[package]]
name = "linux-raw-sys"
version = "0.4.13"
@ -740,6 +1104,15 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "memoffset"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
dependencies = [
"autocfg",
]
[[package]]
name = "miniz_oxide"
version = "0.7.2"
@ -893,6 +1266,16 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "ordered-stream"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50"
dependencies = [
"futures-core",
"pin-project-lite",
]
[[package]]
name = "parking_lot"
version = "0.12.1"
@ -1069,6 +1452,20 @@ version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
[[package]]
name = "rustix"
version = "0.37.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2"
dependencies = [
"bitflags 1.3.2",
"errno",
"io-lifetimes",
"libc",
"linux-raw-sys 0.3.8",
"windows-sys 0.48.0",
]
[[package]]
name = "rustix"
version = "0.38.32"
@ -1078,8 +1475,8 @@ dependencies = [
"bitflags 2.5.0",
"errno",
"libc",
"linux-raw-sys",
"windows-sys",
"linux-raw-sys 0.4.12",
"windows-sys 0.52.0",
]
[[package]]
@ -1149,6 +1546,17 @@ dependencies = [
"syn",
]
[[package]]
name = "serde_repr"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3081f5ffbb02284dda55132aa26daecedd7372a42417bbbab6f14ab7d6bb9145"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.38",
]
[[package]]
name = "serde_spanned"
version = "0.6.5"
@ -1158,6 +1566,17 @@ dependencies = [
"serde",
]
[[package]]
name = "sha1"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]]
name = "sha2"
version = "0.10.8"
@ -1169,6 +1588,15 @@ dependencies = [
"digest",
]
[[package]]
name = "signal-hook-registry"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
dependencies = [
"libc",
]
[[package]]
name = "slab"
version = "0.4.9"
@ -1184,6 +1612,22 @@ version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
[[package]]
name = "socket2"
version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d"
dependencies = [
"libc",
"winapi",
]
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "syn"
version = "2.0.58"
@ -1298,6 +1742,17 @@ dependencies = [
"winnow 0.5.40",
]
[[package]]
name = "toml_edit"
version = "0.19.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
dependencies = [
"indexmap",
"toml_datetime",
"winnow",
]
[[package]]
name = "toml_edit"
version = "0.22.9"
@ -1311,6 +1766,37 @@ dependencies = [
"winnow 0.6.5",
]
[[package]]
name = "tracing"
version = "0.1.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
dependencies = [
"pin-project-lite",
"tracing-attributes",
"tracing-core",
]
[[package]]
name = "tracing-attributes"
version = "0.1.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.38",
]
[[package]]
name = "tracing-core"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
dependencies = [
"once_cell",
]
[[package]]
name = "tree_magic_mini"
version = "3.1.4"
@ -1331,6 +1817,17 @@ version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]]
name = "uds_windows"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9"
dependencies = [
"memoffset 0.9.1",
"tempfile",
"winapi",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
@ -1361,6 +1858,12 @@ version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "waker-fn"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3c4517f54858c779bbcbf228f4fca63d121bf85fbecb2dc578cdf4a39395690"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
@ -1506,6 +2009,15 @@ dependencies = [
"windows-targets 0.52.4",
]
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets 0.48.5",
]
[[package]]
name = "windows-sys"
version = "0.52.0"

View File

@ -15,6 +15,7 @@ manual_test = []
[dependencies]
aes = "=0.8.4"
anyhow = "=1.0.80"
async-trait = "0.1.69"
arboard = { version = "=3.3.2", default-features = false, features = ["wayland-data-control"] }
base64 = "=0.22.0"
cbc = { version = "=0.1.2", features = ["alloc"] }
@ -26,6 +27,8 @@ scopeguard = "=1.2.0"
sha2 = "=0.10.8"
thiserror = "=1.0.58"
typenum = "=1.17.0"
zbus = "3.14.1"
zbus_polkit = "3.0.1"
[build-dependencies]
napi-build = "=2.1.2"

View File

@ -1,3 +1,4 @@
use async_trait::async_trait;
use anyhow::{bail, Result};
use crate::biometrics::{KeyMaterial, OsDerivedKey};
@ -5,8 +6,9 @@ use crate::biometrics::{KeyMaterial, OsDerivedKey};
/// The MacOS implementation of the biometric trait.
pub struct Biometric {}
#[async_trait]
impl super::BiometricTrait for Biometric {
fn prompt(_hwnd: Vec<u8>, _message: String) -> Result<bool> {
async fn prompt(_hwnd: Vec<u8>, _message: String) -> Result<bool> {
bail!("platform not supported");
}

View File

@ -1,3 +1,4 @@
use async_trait::async_trait;
use anyhow::Result;
#[cfg_attr(target_os = "linux", path = "unix.rs")]
@ -9,8 +10,9 @@ pub use biometric::Biometric;
use crate::biometrics::{KeyMaterial, OsDerivedKey};
#[async_trait]
pub trait BiometricTrait {
fn prompt(hwnd: Vec<u8>, message: String) -> Result<bool>;
async fn prompt(hwnd: Vec<u8>, message: String) -> Result<bool>;
fn available() -> Result<bool>;
fn derive_key_material(secret: Option<&str>) -> Result<OsDerivedKey>;
fn set_biometric_secret(

View File

@ -1,21 +1,35 @@
use async_trait::async_trait;
use anyhow::{bail, Result};
use crate::biometrics::{KeyMaterial, OsDerivedKey};
use zbus::Connection;
use zbus_polkit::policykit1::*;
/// The Unix implementation of the biometric trait.
pub struct Biometric {}
#[async_trait]
impl super::BiometricTrait for Biometric {
fn prompt(_hwnd: Vec<u8>, _message: String) -> Result<bool> {
bail!("platform not supported");
async fn prompt(_hwnd: Vec<u8>, _message: String) -> Result<bool> {
let connection = Connection::system().await?;
let proxy = AuthorityProxy::new(&connection).await?;
let subject = Subject::new_for_owner(std::process::id(), None, None)?;
let result = proxy.check_authorization(
&subject,
"com.bitwarden.Bitwarden.unlock",
&std::collections::HashMap::new(),
CheckAuthorizationFlags::AllowUserInteraction.into(),
"",
).await?;
return Ok(result.is_authorized);
}
fn available() -> Result<bool> {
bail!("platform not supported");
bail!("available not implemented");
}
fn derive_key_material(_iv_str: Option<&str>) -> Result<OsDerivedKey> {
bail!("platform not supported");
bail!("derive_key_material not implemented");
}
fn get_biometric_secret(
@ -23,7 +37,7 @@ impl super::BiometricTrait for Biometric {
_account: &str,
_key_material: Option<KeyMaterial>,
) -> Result<String> {
bail!("platform not supported");
bail!("get_biometric_secret not implemented");
}
fn set_biometric_secret(
@ -33,6 +47,6 @@ impl super::BiometricTrait for Biometric {
_key_material: Option<KeyMaterial>,
_iv_b64: &str,
) -> Result<String> {
bail!("platform not supported");
bail!("set_biometric_secret not implemented");
}
}
}

View File

@ -1,3 +1,5 @@
use async_trait::async_trait;
use std::str::FromStr;
use aes::cipher::generic_array::GenericArray;
@ -35,9 +37,10 @@ use crate::{
/// The Windows OS implementation of the biometric trait.
pub struct Biometric {}
#[async_trait]
impl super::BiometricTrait for Biometric {
fn prompt(hwnd: Vec<u8>, message: String) -> Result<bool> {
async fn prompt(hwnd: Vec<u8>, message: String) -> Result<bool> {
let h = isize::from_le_bytes(hwnd.clone().try_into().unwrap());
let window = HWND(h);

View File

@ -52,7 +52,7 @@ pub mod biometrics {
hwnd: napi::bindgen_prelude::Buffer,
message: String,
) -> napi::Result<bool> {
Biometric::prompt(hwnd.into(), message).map_err(|e| napi::Error::from_reason(e.to_string()))
Biometric::prompt(hwnd.into(), message).await.map_err(|e| napi::Error::from_reason(e.to_string()))
}
#[napi]

View File

@ -126,11 +126,14 @@
{{ biometricText | i18n }}
</label>
</div>
<small class="help-block" *ngIf="this.form.value.biometric">{{
<small class="help-block" *ngIf="this.form.value.biometric && !this.isLinux">{{
additionalBiometricSettingsText | i18n
}}</small>
</div>
<div class="form-group" *ngIf="supportsBiometric && this.form.value.biometric">
<div
class="form-group"
*ngIf="supportsBiometric && this.form.value.biometric && !this.isLinux"
>
<div class="checkbox form-group-child">
<label for="autoPromptBiometrics">
<input
@ -148,7 +151,8 @@
*ngIf="
supportsBiometric &&
this.form.value.biometric &&
(userHasMasterPassword || (this.form.value.pin && userHasPinSet))
(userHasMasterPassword || (this.form.value.pin && userHasPinSet)) &&
!this.isLinux
"
>
<div class="checkbox form-group-child">

View File

@ -49,6 +49,7 @@ export class SettingsComponent implements OnInit {
requireEnableTray = false;
showDuckDuckGoIntegrationOption = false;
isWindows: boolean;
isLinux: boolean;
enableTrayText: string;
enableTrayDescText: string;
@ -210,6 +211,7 @@ export class SettingsComponent implements OnInit {
this.userHasMasterPassword = await this.userVerificationService.hasMasterPassword();
this.isWindows = (await this.platformUtilsService.getDevice()) === DeviceType.WindowsDesktop;
this.isLinux = (await this.platformUtilsService.getDevice()) === DeviceType.LinuxDesktop;
if ((await this.stateService.getUserId()) == null) {
return;
@ -469,6 +471,13 @@ export class SettingsComponent implements OnInit {
await this.biometricStateService.setPromptAutomatically(false);
await this.biometricStateService.setRequirePasswordOnStart(true);
await this.biometricStateService.setDismissedRequirePasswordOnStartCallout();
} else if (this.isLinux) {
// Similar to Windows
this.form.controls.requirePasswordOnStart.setValue(true);
this.form.controls.autoPromptBiometrics.setValue(false);
await this.biometricStateService.setPromptAutomatically(false);
await this.biometricStateService.setRequirePasswordOnStart(true);
await this.biometricStateService.setDismissedRequirePasswordOnStartCallout();
}
await this.cryptoService.refreshAdditionalKeys();
@ -618,7 +627,7 @@ export class SettingsComponent implements OnInit {
this.form.controls.enableBrowserIntegration.setValue(false);
return;
} else if (ipc.platform.deviceType === DeviceType.LinuxDesktop) {
} else if (ipc.platform.isSnapStore || ipc.platform.isFlatpak) {
await this.dialogService.openSimpleDialog({
title: { key: "browserIntegrationUnsupportedTitle" },
content: { key: "browserIntegrationLinuxDesc" },
@ -714,6 +723,8 @@ export class SettingsComponent implements OnInit {
return "unlockWithTouchId";
case DeviceType.WindowsDesktop:
return "unlockWithWindowsHello";
case DeviceType.LinuxDesktop:
return "unlockWithPolkit";
default:
throw new Error("Unsupported platform");
}
@ -725,6 +736,8 @@ export class SettingsComponent implements OnInit {
return "autoPromptTouchId";
case DeviceType.WindowsDesktop:
return "autoPromptWindowsHello";
case DeviceType.LinuxDesktop:
return "autoPromptPolkit";
default:
throw new Error("Unsupported platform");
}
@ -736,6 +749,8 @@ export class SettingsComponent implements OnInit {
return "additionalTouchIdSettings";
case DeviceType.WindowsDesktop:
return "additionalWindowsHelloSettings";
case DeviceType.LinuxDesktop:
return "additionalPolkitSettings";
default:
throw new Error("Unsupported platform");
}

View File

@ -203,6 +203,8 @@ export class LockComponent extends BaseLockComponent {
return "unlockWithTouchId";
case DeviceType.WindowsDesktop:
return "unlockWithWindowsHello";
case DeviceType.LinuxDesktop:
return "unlockWithPolkit";
default:
throw new Error("Unsupported platform");
}

View File

@ -1410,9 +1410,18 @@
"additionalWindowsHelloSettings": {
"message": "Additional Windows Hello settings"
},
"unlockWithPolkit": {
"message": "Unlock with Polkit"
},
"additionalPolkitSettings": {
"message": "Additional Polkit settings"
},
"windowsHelloConsentMessage": {
"message": "Verify for Bitwarden."
},
"polkitConsentMessage": {
"message": "Verify for Bitwarden."
},
"unlockWithTouchId": {
"message": "Unlock with Touch ID"
},
@ -1425,6 +1434,9 @@
"autoPromptWindowsHello": {
"message": "Ask for Windows Hello on app start"
},
"autoPromptPolkit": {
"message": "Ask for Polkit on launch"
},
"autoPromptTouchId": {
"message": "Ask for Touch ID on app start"
},

View File

@ -51,4 +51,10 @@ export default class BiometricDarwinMain implements OsBiometricService {
return false;
}
}
async osBiometricsNeedsSetup() {
return false;
}
osBiometricsSetup: () => Promise<void>;
}

View File

@ -9,6 +9,12 @@ export default class NoopBiometricsService implements OsBiometricService {
return false;
}
async osBiometricsNeedsSetup(): Promise<boolean> {
return false;
}
async osBiometricsSetup(): Promise<void> {}
async getBiometricKey(
service: string,
storageKey: string,

View File

@ -0,0 +1,80 @@
import { spawn } from "child_process";
import { existsSync } from "fs";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { biometrics, passwords } from "@bitwarden/desktop-native";
import { WindowMain } from "../../../main/window.main";
import { OsBiometricService } from "./biometrics.service.abstraction";
const polkitPolicy = `<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE policyconfig PUBLIC
"-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
"http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd">
<policyconfig>
<action id="com.bitwarden.Bitwarden.unlock">
<description>Unlock Bitwarden</description>
<message>Authenticate to unlock Bitwarden</message>
<defaults>
<allow_any>auth_self</allow_any>
<allow_inactive>auth_self</allow_inactive>
<allow_active>auth_self</allow_active>
</defaults>
</action>
</policyconfig>`;
const policyFileName = "com.bitwarden.Bitwarden.policy";
const policyPath = "/usr/share/polkit-1/actions/";
export default class BiometricUnixMain implements OsBiometricService {
constructor(
private i18nservice: I18nService,
private windowMain: WindowMain,
) {}
async init() {}
async setBiometricKey(service: string, key: string, value: string): Promise<void> {
return await passwords.setPassword(service, key, value);
}
async deleteBiometricKey(service: string, key: string): Promise<void> {
await passwords.deletePassword(service, key);
}
async getBiometricKey(service: string, key: string): Promise<string> {
const success = await this.authenticateBiometric();
if (!success) {
throw new Error("Biometric authentication failed");
}
return await passwords.getPassword(service, key);
}
async authenticateBiometric(): Promise<boolean> {
const hwnd = this.windowMain.win.getNativeWindowHandle();
return await biometrics.prompt(hwnd, this.i18nservice.t("polkitConsentMessage"));
}
async osSupportsBiometric(): Promise<boolean> {
return existsSync(policyPath);
}
async osBiometricsNeedsSetup(): Promise<boolean> {
return !existsSync(policyPath + policyFileName);
}
async osBiometricsSetup(): Promise<void> {
const process = spawn("pkexec", [
"bash",
"-c",
`echo '${polkitPolicy}' > ${policyPath + policyFileName}`,
]);
process.on("close", (code) => {
if (code !== 0) {
throw new Error("Failed to set up polkit policy");
}
});
}
}

View File

@ -214,4 +214,9 @@ export default class BiometricWindowsMain implements OsBiometricService {
clientKeyPartB64,
};
}
async osBiometricsNeedsSetup() {
return false;
}
osBiometricsSetup: () => Promise<void>;
}

View File

@ -1,5 +1,7 @@
export abstract class BiometricsServiceAbstraction {
abstract osSupportsBiometric(): Promise<boolean>;
abstract osBiometricsNeedsSetup: () => Promise<boolean>;
abstract osBiometricsSetup: () => Promise<void>;
abstract canAuthBiometric({
service,
key,
@ -26,6 +28,8 @@ export abstract class BiometricsServiceAbstraction {
export interface OsBiometricService {
osSupportsBiometric(): Promise<boolean>;
osBiometricsNeedsSetup: () => Promise<boolean>;
osBiometricsSetup: () => Promise<void>;
authenticateBiometric(): Promise<boolean>;
getBiometricKey(
service: string,

View File

@ -28,6 +28,8 @@ export class BiometricsService implements BiometricsServiceAbstraction {
this.loadWindowsHelloService();
} else if (platform === "darwin") {
this.loadMacOSService();
} else if (platform === "linux") {
this.loadUnixService();
} else {
this.loadNoopBiometricsService();
}
@ -49,6 +51,16 @@ export class BiometricsService implements BiometricsServiceAbstraction {
this.platformSpecificService = new BiometricDarwinMain(this.i18nService);
}
private loadUnixService() {
// eslint-disable-next-line
const BiometricUnixMain = require("./biometric.unix.main").default;
this.platformSpecificService = new BiometricUnixMain(
this.i18nService,
this.windowMain,
this.logService,
);
}
private loadNoopBiometricsService() {
// eslint-disable-next-line
const NoopBiometricsService = require("./biometric.noop.main").default;
@ -59,6 +71,14 @@ export class BiometricsService implements BiometricsServiceAbstraction {
return await this.platformSpecificService.osSupportsBiometric();
}
async osBiometricsNeedsSetup() {
return await this.platformSpecificService.osBiometricsNeedsSetup();
}
async osBiometricsSetup() {
await this.platformSpecificService.osBiometricsSetup();
}
async canAuthBiometric({
service,
key,

View File

@ -79,6 +79,12 @@ export class DesktopCredentialStorageListener {
case BiometricAction.OsSupported:
val = await this.biometricService.osSupportsBiometric();
break;
case BiometricAction.NeedsSetup:
val = await this.biometricService.osBiometricsNeedsSetup();
break;
case BiometricAction.Setup:
await this.biometricService.osBiometricsSetup();
break;
default:
}

View File

@ -11,7 +11,7 @@ import {
UnencryptedMessageResponse,
} from "../models/native-messaging";
import { BiometricMessage, BiometricAction } from "../types/biometric-message";
import { isDev, isMacAppStore, isWindowsStore } from "../utils";
import { isDev, isFlatpak, isMacAppStore, isSnapStore, isWindowsStore } from "../utils";
import { ClipboardWriteMessage } from "./types/clipboard";
@ -48,6 +48,14 @@ const biometric = {
ipcRenderer.invoke("biometric", {
action: BiometricAction.OsSupported,
} satisfies BiometricMessage),
biometricsNeedsSetup: (): Promise<boolean> =>
ipcRenderer.invoke("biometric", {
action: BiometricAction.NeedsSetup,
} satisfies BiometricMessage),
biometricsSetup: (): Promise<void> =>
ipcRenderer.invoke("biometric", {
action: BiometricAction.Setup,
} satisfies BiometricMessage),
authenticate: (): Promise<boolean> =>
ipcRenderer.invoke("biometric", {
action: BiometricAction.Authenticate,
@ -102,6 +110,8 @@ export default {
isDev: isDev(),
isMacAppStore: isMacAppStore(),
isWindowsStore: isWindowsStore(),
isFlatpak: isFlatpak(),
isSnapStore: isSnapStore(),
reloadProcess: () => ipcRenderer.send("reload-process"),
log: (level: LogLevelType, message: string) => ipcRenderer.invoke("ipc.log", { level, message }),

View File

@ -135,6 +135,14 @@ export class ElectronPlatformUtilsService implements PlatformUtilsService {
return await ipc.platform.biometric.osSupported();
}
async biometricsNeedsSetup(): Promise<boolean> {
return await ipc.platform.biometric.biometricsNeedsSetup();
}
async biometricsSetup(): Promise<void> {
return await ipc.platform.biometric.biometricsSetup();
}
/** This method is used to authenticate the user presence _only_.
* It should not be used in the process to retrieve
* biometric keys, which has a separate authentication mechanism.

View File

@ -2,6 +2,8 @@ export enum BiometricAction {
EnabledForUser = "enabled",
OsSupported = "osSupported",
Authenticate = "authenticate",
NeedsSetup = "needsSetup",
Setup = "setup",
}
export type BiometricMessage = {

View File

@ -62,6 +62,10 @@ export function isWindowsStore() {
return windows && windowsStore === true;
}
export function isFlatpak() {
return process.platform === "linux" && process.env.container != null;
}
export function isWindowsPortable() {
return isWindows() && process.env.PORTABLE_EXECUTABLE_DIR != null;
}

View File

@ -44,6 +44,8 @@ export abstract class PlatformUtilsService {
abstract copyToClipboard(text: string, options?: ClipboardOptions): void | boolean;
abstract readFromClipboard(): Promise<string>;
abstract supportsBiometric(): Promise<boolean>;
abstract biometricsNeedsSetup: () => Promise<boolean>;
abstract biometricsSetup: () => Promise<void>;
abstract authenticateBiometric(): Promise<boolean>;
abstract supportsSecureStorage(): boolean;
abstract getAutofillKeyboardShortcut(): Promise<string>;