mirror of
https://github.com/dani-garcia/vaultwarden.git
synced 2025-09-10 10:45:57 +03:00
Compare commits
38 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
c666497130 | ||
|
2620a1ac8c | ||
|
ffdcafa044 | ||
|
56ffec40f4 | ||
|
96c2416903 | ||
|
340d42a1ca | ||
|
e19420160f | ||
|
1741316f42 | ||
|
4f08167d6f | ||
|
fef76e2f6f | ||
|
f16d56cb27 | ||
|
120b286f2b | ||
|
7f437b6947 | ||
|
8d6e62e18b | ||
|
d0ec410b73 | ||
|
c546a59c38 | ||
|
e5ec245626 | ||
|
6ea95d1ede | ||
|
88bea44dd8 | ||
|
8ee5d51bd4 | ||
|
c640abbcd7 | ||
|
13598c098f | ||
|
a622b4d2fb | ||
|
403f35b571 | ||
|
3968bc8016 | ||
|
ff66368cb6 | ||
|
3fb419e704 | ||
|
832f838ddd | ||
|
18703bf195 | ||
|
ff8e88a5df | ||
|
39167d333a | ||
|
f707f86c8e | ||
|
cc021a4784 | ||
|
e3c4609c2a | ||
|
89a68741d6 | ||
|
2421d49d9a | ||
|
1db37bf3d0 | ||
|
d75a80bd2d |
@@ -194,11 +194,13 @@
|
||||
## Name shown in the invitation emails that don't come from a specific organization
|
||||
# INVITATION_ORG_NAME=Vaultwarden
|
||||
|
||||
## Per-organization attachment limit (KB)
|
||||
## Limit in kilobytes for an organization attachments, once the limit is exceeded it won't be possible to upload more
|
||||
## Per-organization attachment storage limit (KB)
|
||||
## Max kilobytes of attachment storage allowed per organization.
|
||||
## When this limit is reached, organization members will not be allowed to upload further attachments for ciphers owned by that organization.
|
||||
# ORG_ATTACHMENT_LIMIT=
|
||||
## Per-user attachment limit (KB).
|
||||
## Limit in kilobytes for a users attachments, once the limit is exceeded it won't be possible to upload more
|
||||
## Per-user attachment storage limit (KB)
|
||||
## Max kilobytes of attachment storage allowed per user.
|
||||
## When this limit is reached, the user will not be allowed to upload further attachments.
|
||||
# USER_ATTACHMENT_LIMIT=
|
||||
|
||||
## Number of days to wait before auto-deleting a trashed item.
|
||||
@@ -210,8 +212,10 @@
|
||||
## The change only applies when the password is changed
|
||||
# PASSWORD_ITERATIONS=100000
|
||||
|
||||
## Whether password hint should be sent into the error response when the client request it
|
||||
# SHOW_PASSWORD_HINT=true
|
||||
## Controls whether a password hint should be shown directly in the web page if
|
||||
## SMTP service is not configured. Not recommended for publicly-accessible instances
|
||||
## as this provides unauthenticated access to potentially sensitive data.
|
||||
# SHOW_PASSWORD_HINT=false
|
||||
|
||||
## Domain settings
|
||||
## The domain must match the address from where you access the server
|
||||
|
37
.pre-commit-config.yaml
Normal file
37
.pre-commit-config.yaml
Normal file
@@ -0,0 +1,37 @@
|
||||
---
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.0.1
|
||||
hooks:
|
||||
- id: check-yaml
|
||||
- id: check-json
|
||||
- id: check-toml
|
||||
- id: end-of-file-fixer
|
||||
- id: check-case-conflict
|
||||
- id: check-merge-conflict
|
||||
- id: detect-private-key
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: fmt
|
||||
name: fmt
|
||||
description: Format files with cargo fmt.
|
||||
entry: cargo fmt
|
||||
language: system
|
||||
types: [rust]
|
||||
args: ["--", "--check"]
|
||||
- id: cargo-test
|
||||
name: cargo test
|
||||
description: Test the package for errors.
|
||||
entry: cargo test
|
||||
language: system
|
||||
args: ["--features", "sqlite,mysql,postgresql", "--"]
|
||||
types: [rust]
|
||||
pass_filenames: false
|
||||
- id: cargo-clippy
|
||||
name: cargo clippy
|
||||
description: Lint Rust sources
|
||||
entry: cargo clippy
|
||||
language: system
|
||||
args: ["--features", "sqlite,mysql,postgresql", "--", "-D", "warnings"]
|
||||
types: [rust]
|
||||
pass_filenames: false
|
207
Cargo.lock
generated
207
Cargo.lock
generated
@@ -248,9 +248,9 @@ checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.68"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787"
|
||||
checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
@@ -323,9 +323,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cookie"
|
||||
version = "0.15.0"
|
||||
version = "0.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffdf8865bac3d9a3bde5bde9088ca431b11f5d37c7a578b8086af77248b76627"
|
||||
checksum = "d5f1c7727e460397e56abc4bddc1d49e07a1ad78fc98eb2e1c8f032a58a2f80d"
|
||||
dependencies = [
|
||||
"percent-encoding 2.1.0",
|
||||
"time 0.2.27",
|
||||
@@ -354,7 +354,7 @@ version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55b4ac5559dd39f7bdc516f769cb412b151585d8886d216871a8435ed7f862cd"
|
||||
dependencies = [
|
||||
"cookie 0.15.0",
|
||||
"cookie 0.15.1",
|
||||
"idna 0.2.3",
|
||||
"log 0.4.14",
|
||||
"publicsuffix 2.1.0",
|
||||
@@ -421,9 +421,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "crypto-mac"
|
||||
version = "0.10.0"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4857fd85a0c34b3c3297875b747c1e02e06b6a0ea32dd892d8192b9ce0813ea6"
|
||||
checksum = "bff07008ec701e8028e2ceb8f83f0e4274ee62bd2dbdc4fefff2e9a91824081a"
|
||||
dependencies = [
|
||||
"generic-array 0.14.4",
|
||||
"subtle",
|
||||
@@ -467,9 +467,9 @@ version = "0.3.0"
|
||||
source = "git+https://github.com/SergioBenitez/Devise.git?rev=e58b3ac9a#e58b3ac9afc3b6ff10a8aaf02a3e768a8f530089"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"proc-macro2 1.0.27",
|
||||
"proc-macro2 1.0.28",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.73",
|
||||
"syn 1.0.74",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -495,9 +495,9 @@ version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "45f5098f628d02a7a0f68ddba586fb61e80edec3bdc1be3b921f4ceec60858d3"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.27",
|
||||
"proc-macro2 1.0.28",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.73",
|
||||
"syn 1.0.74",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -591,9 +591,9 @@ checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "1.4.1"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77b705829d1e87f762c2df6da140b26af5839e1033aa84aa5f56bb688e4e1bdb"
|
||||
checksum = "b394ed3d285a429378d3b384b9eb1285267e7df4b166df24b7a6939a04dc392e"
|
||||
dependencies = [
|
||||
"instant",
|
||||
]
|
||||
@@ -691,9 +691,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.15"
|
||||
version = "0.3.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e7e43a803dae2fa37c1f6a8fe121e1f7bf9548b4dfc0522a42f34145dadfc27"
|
||||
checksum = "1adc00f486adfc9ce99f77d717836f0c5aa84965eb0b4f051f4e83f7cab53f8b"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
@@ -706,9 +706,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.15"
|
||||
version = "0.3.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e682a68b29a882df0545c143dc3646daefe80ba479bcdede94d5a703de2871e2"
|
||||
checksum = "74ed2411805f6e4e3d9bc904c95d5d423b89b3b25dc0250aa74729de20629ff9"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
@@ -716,15 +716,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.15"
|
||||
version = "0.3.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0402f765d8a89a26043b889b26ce3c4679d268fa6bb22cd7c6aad98340e179d1"
|
||||
checksum = "af51b1b4a7fdff033703db39de8802c673eb91855f2e0d47dcf3bf2c0ef01f99"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
version = "0.3.15"
|
||||
version = "0.3.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "badaa6a909fac9e7236d0620a2f57f7664640c56575b71a7552fbd68deafab79"
|
||||
checksum = "4d0d535a57b87e1ae31437b892713aee90cd2d7b0ee48727cd11fc72ef54761c"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
@@ -733,40 +733,40 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.15"
|
||||
version = "0.3.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acc499defb3b348f8d8f3f66415835a9131856ff7714bf10dadfc4ec4bdb29a1"
|
||||
checksum = "0b0e06c393068f3a6ef246c75cdca793d6a46347e75286933e5e75fd2fd11582"
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.15"
|
||||
version = "0.3.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4c40298486cdf52cc00cd6d6987892ba502c7656a16a4192a9992b1ccedd121"
|
||||
checksum = "c54913bae956fb8df7f4dc6fc90362aa72e69148e3f39041fbe8742d21e0ac57"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"proc-macro-hack",
|
||||
"proc-macro2 1.0.27",
|
||||
"proc-macro2 1.0.28",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.73",
|
||||
"syn 1.0.74",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.15"
|
||||
version = "0.3.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a57bead0ceff0d6dde8f465ecd96c9338121bb7717d3e7b108059531870c4282"
|
||||
checksum = "c0f30aaa67363d119812743aa5f33c201a7a66329f97d1a887022971feea4b53"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.15"
|
||||
version = "0.3.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a16bef9fc1a4dddb5bee51c989e3fbba26569cbb0e31f5b303c184e3dd33dae"
|
||||
checksum = "bbe54a98670017f3be909561f6ad13e810d9a51f3f061b902062ca3da80799f2"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.15"
|
||||
version = "0.3.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "feb5c238d27e2bf94ffdfd27b2c29e3df4a68c4193bb6427384259e2bf191967"
|
||||
checksum = "67eb846bfd58e44a8481a00049e82c43e0ccb5d61f8dc071057cb19249dd4d78"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"futures-channel",
|
||||
@@ -873,9 +873,9 @@ checksum = "62aca2aba2d62b4a7f5b33f3712cb1b0692779a56fb510499d5c0aa594daeaf3"
|
||||
|
||||
[[package]]
|
||||
name = "handlebars"
|
||||
version = "4.0.1"
|
||||
version = "4.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2060119114dd8a8bc87facce6384751af8280a7adc8e203c023c95cbb11f5663"
|
||||
checksum = "72a0ffab8c36d0436114310c7e10b59b3307e650ddfabf6d006028e29a70c6e6"
|
||||
dependencies = [
|
||||
"log 0.4.14",
|
||||
"pest",
|
||||
@@ -886,12 +886,6 @@ dependencies = [
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.11.2"
|
||||
@@ -924,7 +918,7 @@ version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15"
|
||||
dependencies = [
|
||||
"crypto-mac 0.10.0",
|
||||
"crypto-mac 0.10.1",
|
||||
"digest 0.9.0",
|
||||
]
|
||||
|
||||
@@ -948,9 +942,9 @@ dependencies = [
|
||||
"log 0.4.14",
|
||||
"mac",
|
||||
"markup5ever",
|
||||
"proc-macro2 1.0.27",
|
||||
"proc-macro2 1.0.28",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.73",
|
||||
"syn 1.0.74",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1008,9 +1002,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "0.14.9"
|
||||
version = "0.14.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07d6baa1b441335f3ce5098ac421fb6547c46dda735ca1bc6d0153c838f9dd83"
|
||||
checksum = "0b61cf2d1aebcf6e6352c97b81dc2244ca29194be1b276f5d8ad5c6330fffb11"
|
||||
dependencies = [
|
||||
"bytes 1.0.1",
|
||||
"futures-channel",
|
||||
@@ -1049,7 +1043,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
|
||||
dependencies = [
|
||||
"bytes 1.0.1",
|
||||
"hyper 0.14.9",
|
||||
"hyper 0.14.11",
|
||||
"native-tls",
|
||||
"tokio",
|
||||
"tokio-native-tls",
|
||||
@@ -1079,19 +1073,19 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.6.2"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3"
|
||||
checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown 0.9.1",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.9"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec"
|
||||
checksum = "bee0328b1209d157ef001c94dd85b4f8f64139adb0eac2659f4b08382b2f474d"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
]
|
||||
@@ -1201,9 +1195,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.97"
|
||||
version = "0.2.98"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6"
|
||||
checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790"
|
||||
|
||||
[[package]]
|
||||
name = "libsqlite3-sys"
|
||||
@@ -1321,9 +1315,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9753f12909fd8d923f75ae5c3258cae1ed3c8ec052e1b38c93c21a6d157f789c"
|
||||
dependencies = [
|
||||
"migrations_internals",
|
||||
"proc-macro2 1.0.27",
|
||||
"proc-macro2 1.0.28",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.73",
|
||||
"syn 1.0.74",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1542,9 +1536,9 @@ version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.27",
|
||||
"proc-macro2 1.0.28",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.73",
|
||||
"syn 1.0.74",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1670,9 +1664,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "parity-ws"
|
||||
version = "0.10.0"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e02a625dd75084c2a7024f07c575b61b782f729d18702dabb3cdbf31911dc61"
|
||||
checksum = "d0ab8a461779bd022964cae2b4989fa9c99deb270bec162da2125ec03c09fcaa"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"bytes 0.4.12",
|
||||
@@ -1820,9 +1814,9 @@ checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55"
|
||||
dependencies = [
|
||||
"pest",
|
||||
"pest_meta",
|
||||
"proc-macro2 1.0.27",
|
||||
"proc-macro2 1.0.28",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.73",
|
||||
"syn 1.0.74",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1882,9 +1876,9 @@ checksum = "db8bcd96cb740d03149cbad5518db9fd87126a10ab519c011893b1754134c468"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.6"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc0e1f259c92177c30a4c9d177246edd0a3568b25756a977d0632cf8fa37e905"
|
||||
checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
@@ -1942,9 +1936,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.27"
|
||||
version = "1.0.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038"
|
||||
checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612"
|
||||
dependencies = [
|
||||
"unicode-xid 0.2.2",
|
||||
]
|
||||
@@ -1972,7 +1966,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3ac055aef7cc7a1caefbc65144be879e862467dcd9b8a8d57b64a13e7dce15d"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"hashbrown 0.11.2",
|
||||
"hashbrown",
|
||||
"idna 0.2.3",
|
||||
"psl-types",
|
||||
]
|
||||
@@ -2004,7 +1998,7 @@ version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.27",
|
||||
"proc-macro2 1.0.28",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2209,7 +2203,7 @@ dependencies = [
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"hyper 0.14.9",
|
||||
"hyper 0.14.11",
|
||||
"hyper-tls",
|
||||
"ipnet",
|
||||
"js-sys",
|
||||
@@ -2494,9 +2488,9 @@ version = "1.0.126"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.27",
|
||||
"proc-macro2 1.0.28",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.73",
|
||||
"syn 1.0.74",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2549,9 +2543,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sha-1"
|
||||
version = "0.9.6"
|
||||
version = "0.9.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c4cfa741c5832d0ef7fab46cabed29c2aae926db0b11bb2069edd8db5e64e16"
|
||||
checksum = "1a0c8611594e2ab4ebbf06ec7cbbf0a99450b8570e96cbf5188b5d5f6ef18d81"
|
||||
dependencies = [
|
||||
"block-buffer 0.9.0",
|
||||
"cfg-if 1.0.0",
|
||||
@@ -2674,11 +2668,11 @@ version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.27",
|
||||
"proc-macro2 1.0.28",
|
||||
"quote 1.0.9",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"syn 1.0.73",
|
||||
"syn 1.0.74",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2688,13 +2682,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11"
|
||||
dependencies = [
|
||||
"base-x",
|
||||
"proc-macro2 1.0.27",
|
||||
"proc-macro2 1.0.28",
|
||||
"quote 1.0.9",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"sha1",
|
||||
"syn 1.0.73",
|
||||
"syn 1.0.74",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2724,15 +2718,15 @@ checksum = "f24c8e5e19d22a726626f1a5e16fe15b132dcf21d10177fa5a45ce7962996b97"
|
||||
dependencies = [
|
||||
"phf_generator",
|
||||
"phf_shared",
|
||||
"proc-macro2 1.0.27",
|
||||
"proc-macro2 1.0.28",
|
||||
"quote 1.0.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.4.0"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2"
|
||||
checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
@@ -2747,11 +2741,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.73"
|
||||
version = "1.0.74"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f71489ff30030d2ae598524f61326b902466f72a0fb1a8564c001cc63425bcc7"
|
||||
checksum = "1873d832550d4588c3dbc20f01361ab00bfe741048f71e3fecf145a7cc18b29c"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.27",
|
||||
"proc-macro2 1.0.28",
|
||||
"quote 1.0.9",
|
||||
"unicode-xid 0.2.2",
|
||||
]
|
||||
@@ -2801,22 +2795,22 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.25"
|
||||
version = "1.0.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa6f76457f59514c7eeb4e59d891395fab0b2fd1d40723ae737d64153392e9c6"
|
||||
checksum = "93119e4feac1cbe6c798c34d3a53ea0026b0b1de6a120deef895137c0529bfe2"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.25"
|
||||
version = "1.0.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a36768c0fbf1bb15eca10defa29526bda730a2376c2ab4393ccfa16fb1a318d"
|
||||
checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.27",
|
||||
"proc-macro2 1.0.28",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.73",
|
||||
"syn 1.0.74",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2871,17 +2865,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f"
|
||||
dependencies = [
|
||||
"proc-macro-hack",
|
||||
"proc-macro2 1.0.27",
|
||||
"proc-macro2 1.0.28",
|
||||
"quote 1.0.9",
|
||||
"standback",
|
||||
"syn 1.0.73",
|
||||
"syn 1.0.74",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.2.0"
|
||||
version = "1.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b5220f05bb7de7f3f53c7c065e1199b3172696fe2db9f9c4d8ad9b4ee74c342"
|
||||
checksum = "848a1e1181b9f6753b5e96a092749e29b11d19ede67dfbbd6c7dc7e0f49b5338"
|
||||
dependencies = [
|
||||
"tinyvec_macros",
|
||||
]
|
||||
@@ -2894,9 +2888,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.7.1"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5fb2ed024293bb19f7a5dc54fe83bf86532a44c12a2bb8ba40d64a4509395ca2"
|
||||
checksum = "4b7b349f11a7047e6d1276853e612d152f5e8a352c61917887cc2169e2366b4c"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"bytes 1.0.1",
|
||||
@@ -2978,9 +2972,9 @@ version = "0.1.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c42e6fa53307c8a17e4ccd4dc81cf5ec38db9209f59b222210375b54ee40d1e2"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.27",
|
||||
"proc-macro2 1.0.28",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.73",
|
||||
"syn 1.0.74",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3149,7 +3143,7 @@ dependencies = [
|
||||
"chashmap",
|
||||
"chrono",
|
||||
"chrono-tz",
|
||||
"cookie 0.15.0",
|
||||
"cookie 0.15.1",
|
||||
"cookie_store 0.15.0",
|
||||
"data-encoding",
|
||||
"data-url",
|
||||
@@ -3267,9 +3261,9 @@ dependencies = [
|
||||
"bumpalo",
|
||||
"lazy_static",
|
||||
"log 0.4.14",
|
||||
"proc-macro2 1.0.27",
|
||||
"proc-macro2 1.0.28",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.73",
|
||||
"syn 1.0.74",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
@@ -3301,9 +3295,9 @@ version = "0.2.74"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be2241542ff3d9f241f5e2cb6dd09b37efe786df8851c54957683a49f0987a97"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.27",
|
||||
"proc-macro2 1.0.28",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.73",
|
||||
"syn 1.0.74",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
@@ -3326,8 +3320,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "webauthn-rs"
|
||||
version = "0.3.0-alpha.7"
|
||||
source = "git+https://github.com/kanidm/webauthn-rs?rev=02a99f534127b30c6f4df7f2d42bc24f76dc4211#02a99f534127b30c6f4df7f2d42bc24f76dc4211"
|
||||
version = "0.3.0-alpha.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4bbb2b77105c3b25ef0187146d80824648da0645f650c4d2080e3815d6cbbb87"
|
||||
dependencies = [
|
||||
"base64 0.13.0",
|
||||
"log 0.4.14",
|
||||
@@ -3454,12 +3449,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d3c3f584739059f479ca4de114cbfe032315752abb3be60afb30db40a802169"
|
||||
dependencies = [
|
||||
"base64 0.13.0",
|
||||
"crypto-mac 0.10.0",
|
||||
"crypto-mac 0.10.1",
|
||||
"futures",
|
||||
"hmac 0.10.1",
|
||||
"rand 0.8.4",
|
||||
"reqwest",
|
||||
"sha-1 0.9.6",
|
||||
"sha-1 0.9.7",
|
||||
"threadpool",
|
||||
"url 1.7.2",
|
||||
]
|
||||
|
13
Cargo.toml
13
Cargo.toml
@@ -35,7 +35,7 @@ rocket_contrib = "=0.5.0-dev"
|
||||
reqwest = { version = "0.11.4", features = ["blocking", "json", "gzip", "brotli", "socks", "cookies"] }
|
||||
|
||||
# Used for custom short lived cookie jar
|
||||
cookie = "0.15.0"
|
||||
cookie = "0.15.1"
|
||||
cookie_store = "0.15.0"
|
||||
bytes = "1.0.1"
|
||||
url = "2.2.2"
|
||||
@@ -44,7 +44,7 @@ url = "2.2.2"
|
||||
multipart = { version = "0.18.0", features = ["server"], default-features = false }
|
||||
|
||||
# WebSockets library
|
||||
ws = { version = "0.10.0", package = "parity-ws" }
|
||||
ws = { version = "0.11.0", package = "parity-ws" }
|
||||
|
||||
# MessagePack library
|
||||
rmpv = "0.4.7"
|
||||
@@ -93,7 +93,7 @@ jsonwebtoken = "7.2.0"
|
||||
|
||||
# U2F library
|
||||
u2f = "0.2.0"
|
||||
webauthn-rs = "0.3.0-alpha.7"
|
||||
webauthn-rs = "=0.3.0-alpha.9"
|
||||
|
||||
# Yubico Library
|
||||
yubico = { version = "0.10.0", features = ["online-tokio"], default-features = false }
|
||||
@@ -113,7 +113,7 @@ tracing = { version = "0.1.26", features = ["log"] } # Needed to have lettre tra
|
||||
lettre = { version = "0.10.0-rc.3", features = ["smtp-transport", "builder", "serde", "native-tls", "hostname", "tracing"], default-features = false }
|
||||
|
||||
# Template library
|
||||
handlebars = { version = "4.0.1", features = ["dir_source"] }
|
||||
handlebars = { version = "4.1.0", features = ["dir_source"] }
|
||||
|
||||
# For favicon extraction from main website
|
||||
html5ever = "0.25.1"
|
||||
@@ -122,7 +122,7 @@ regex = { version = "1.5.4", features = ["std", "perf"], default-features = fals
|
||||
data-url = "0.1.0"
|
||||
|
||||
# Used by U2F, JWT and Postgres
|
||||
openssl = "0.10.34"
|
||||
openssl = "0.10.35"
|
||||
|
||||
# URL encoding library
|
||||
percent-encoding = "2.1.0"
|
||||
@@ -152,6 +152,3 @@ data-url = { git = 'https://github.com/servo/rust-url', package="data-url", rev
|
||||
# In particular, `cron` has since implemented parsing of some common syntax
|
||||
# that wasn't previously supported (https://github.com/zslayton/cron/pull/64).
|
||||
job_scheduler = { git = 'https://github.com/jjlin/job_scheduler', rev = 'ee023418dbba2bfe1e30a5fd7d937f9e33739806' }
|
||||
|
||||
# Add support for U2F appid extension compatibility
|
||||
webauthn-rs = { git = 'https://github.com/kanidm/webauthn-rs', rev = '02a99f534127b30c6f4df7f2d42bc24f76dc4211' }
|
||||
|
@@ -44,8 +44,8 @@
|
||||
# https://docs.docker.com/develop/develop-images/multistage-build/
|
||||
# https://whitfin.io/speeding-up-rust-docker-builds/
|
||||
####################### VAULT BUILD IMAGE #######################
|
||||
{% set vault_version = "2.20.4b" %}
|
||||
{% set vault_image_digest = "sha256:894e266d4491494dd5a8a736855a6772aa146fa14206853b11b41cf3f3f64d05" %}
|
||||
{% set vault_version = "2.21.1" %}
|
||||
{% set vault_image_digest = "sha256:29a4fa7bf3790fff9d908b02ac5a154913491f4bf30c95b87b06d8cf1c5516b5" %}
|
||||
# The web-vault digest specifies a particular web-vault build on Docker Hub.
|
||||
# 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
|
||||
@@ -75,7 +75,8 @@ ARG DB=sqlite,postgresql
|
||||
{% set features = "sqlite,postgresql" %}
|
||||
{% else %}
|
||||
# Alpine-based ARM (musl) only supports sqlite during compile time.
|
||||
ARG DB=sqlite
|
||||
# We now also need to add vendored_openssl, because the current base image we use to build has OpenSSL removed.
|
||||
ARG DB=sqlite,vendored_openssl
|
||||
{% set features = "sqlite" %}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
|
@@ -14,15 +14,15 @@
|
||||
# - 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.
|
||||
# - From the command line:
|
||||
# $ docker pull vaultwarden/web-vault:v2.20.4b
|
||||
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.20.4b
|
||||
# [vaultwarden/web-vault@sha256:894e266d4491494dd5a8a736855a6772aa146fa14206853b11b41cf3f3f64d05]
|
||||
# $ docker pull vaultwarden/web-vault:v2.21.1
|
||||
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.21.1
|
||||
# [vaultwarden/web-vault@sha256:29a4fa7bf3790fff9d908b02ac5a154913491f4bf30c95b87b06d8cf1c5516b5]
|
||||
#
|
||||
# - Conversely, to get the tag name from the digest:
|
||||
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:894e266d4491494dd5a8a736855a6772aa146fa14206853b11b41cf3f3f64d05
|
||||
# [vaultwarden/web-vault:v2.20.4b]
|
||||
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:29a4fa7bf3790fff9d908b02ac5a154913491f4bf30c95b87b06d8cf1c5516b5
|
||||
# [vaultwarden/web-vault:v2.21.1]
|
||||
#
|
||||
FROM vaultwarden/web-vault@sha256:894e266d4491494dd5a8a736855a6772aa146fa14206853b11b41cf3f3f64d05 as vault
|
||||
FROM vaultwarden/web-vault@sha256:29a4fa7bf3790fff9d908b02ac5a154913491f4bf30c95b87b06d8cf1c5516b5 as vault
|
||||
|
||||
########################## BUILD IMAGE ##########################
|
||||
FROM rust:1.53 as build
|
||||
|
@@ -14,15 +14,15 @@
|
||||
# - 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.
|
||||
# - From the command line:
|
||||
# $ docker pull vaultwarden/web-vault:v2.20.4b
|
||||
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.20.4b
|
||||
# [vaultwarden/web-vault@sha256:894e266d4491494dd5a8a736855a6772aa146fa14206853b11b41cf3f3f64d05]
|
||||
# $ docker pull vaultwarden/web-vault:v2.21.1
|
||||
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.21.1
|
||||
# [vaultwarden/web-vault@sha256:29a4fa7bf3790fff9d908b02ac5a154913491f4bf30c95b87b06d8cf1c5516b5]
|
||||
#
|
||||
# - Conversely, to get the tag name from the digest:
|
||||
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:894e266d4491494dd5a8a736855a6772aa146fa14206853b11b41cf3f3f64d05
|
||||
# [vaultwarden/web-vault:v2.20.4b]
|
||||
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:29a4fa7bf3790fff9d908b02ac5a154913491f4bf30c95b87b06d8cf1c5516b5
|
||||
# [vaultwarden/web-vault:v2.21.1]
|
||||
#
|
||||
FROM vaultwarden/web-vault@sha256:894e266d4491494dd5a8a736855a6772aa146fa14206853b11b41cf3f3f64d05 as vault
|
||||
FROM vaultwarden/web-vault@sha256:29a4fa7bf3790fff9d908b02ac5a154913491f4bf30c95b87b06d8cf1c5516b5 as vault
|
||||
|
||||
########################## BUILD IMAGE ##########################
|
||||
FROM clux/muslrust:nightly-2021-06-24 as build
|
||||
|
@@ -14,15 +14,15 @@
|
||||
# - 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.
|
||||
# - From the command line:
|
||||
# $ docker pull vaultwarden/web-vault:v2.20.4b
|
||||
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.20.4b
|
||||
# [vaultwarden/web-vault@sha256:894e266d4491494dd5a8a736855a6772aa146fa14206853b11b41cf3f3f64d05]
|
||||
# $ docker pull vaultwarden/web-vault:v2.21.1
|
||||
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.21.1
|
||||
# [vaultwarden/web-vault@sha256:29a4fa7bf3790fff9d908b02ac5a154913491f4bf30c95b87b06d8cf1c5516b5]
|
||||
#
|
||||
# - Conversely, to get the tag name from the digest:
|
||||
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:894e266d4491494dd5a8a736855a6772aa146fa14206853b11b41cf3f3f64d05
|
||||
# [vaultwarden/web-vault:v2.20.4b]
|
||||
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:29a4fa7bf3790fff9d908b02ac5a154913491f4bf30c95b87b06d8cf1c5516b5
|
||||
# [vaultwarden/web-vault:v2.21.1]
|
||||
#
|
||||
FROM vaultwarden/web-vault@sha256:894e266d4491494dd5a8a736855a6772aa146fa14206853b11b41cf3f3f64d05 as vault
|
||||
FROM vaultwarden/web-vault@sha256:29a4fa7bf3790fff9d908b02ac5a154913491f4bf30c95b87b06d8cf1c5516b5 as vault
|
||||
|
||||
########################## BUILD IMAGE ##########################
|
||||
FROM rust:1.53 as build
|
||||
|
@@ -14,15 +14,15 @@
|
||||
# - 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.
|
||||
# - From the command line:
|
||||
# $ docker pull vaultwarden/web-vault:v2.20.4b
|
||||
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.20.4b
|
||||
# [vaultwarden/web-vault@sha256:894e266d4491494dd5a8a736855a6772aa146fa14206853b11b41cf3f3f64d05]
|
||||
# $ docker pull vaultwarden/web-vault:v2.21.1
|
||||
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.21.1
|
||||
# [vaultwarden/web-vault@sha256:29a4fa7bf3790fff9d908b02ac5a154913491f4bf30c95b87b06d8cf1c5516b5]
|
||||
#
|
||||
# - Conversely, to get the tag name from the digest:
|
||||
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:894e266d4491494dd5a8a736855a6772aa146fa14206853b11b41cf3f3f64d05
|
||||
# [vaultwarden/web-vault:v2.20.4b]
|
||||
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:29a4fa7bf3790fff9d908b02ac5a154913491f4bf30c95b87b06d8cf1c5516b5
|
||||
# [vaultwarden/web-vault:v2.21.1]
|
||||
#
|
||||
FROM vaultwarden/web-vault@sha256:894e266d4491494dd5a8a736855a6772aa146fa14206853b11b41cf3f3f64d05 as vault
|
||||
FROM vaultwarden/web-vault@sha256:29a4fa7bf3790fff9d908b02ac5a154913491f4bf30c95b87b06d8cf1c5516b5 as vault
|
||||
|
||||
########################## BUILD IMAGE ##########################
|
||||
FROM rust:1.53 as build
|
||||
|
@@ -14,15 +14,15 @@
|
||||
# - 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.
|
||||
# - From the command line:
|
||||
# $ docker pull vaultwarden/web-vault:v2.20.4b
|
||||
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.20.4b
|
||||
# [vaultwarden/web-vault@sha256:894e266d4491494dd5a8a736855a6772aa146fa14206853b11b41cf3f3f64d05]
|
||||
# $ docker pull vaultwarden/web-vault:v2.21.1
|
||||
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.21.1
|
||||
# [vaultwarden/web-vault@sha256:29a4fa7bf3790fff9d908b02ac5a154913491f4bf30c95b87b06d8cf1c5516b5]
|
||||
#
|
||||
# - Conversely, to get the tag name from the digest:
|
||||
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:894e266d4491494dd5a8a736855a6772aa146fa14206853b11b41cf3f3f64d05
|
||||
# [vaultwarden/web-vault:v2.20.4b]
|
||||
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:29a4fa7bf3790fff9d908b02ac5a154913491f4bf30c95b87b06d8cf1c5516b5
|
||||
# [vaultwarden/web-vault:v2.21.1]
|
||||
#
|
||||
FROM vaultwarden/web-vault@sha256:894e266d4491494dd5a8a736855a6772aa146fa14206853b11b41cf3f3f64d05 as vault
|
||||
FROM vaultwarden/web-vault@sha256:29a4fa7bf3790fff9d908b02ac5a154913491f4bf30c95b87b06d8cf1c5516b5 as vault
|
||||
|
||||
########################## BUILD IMAGE ##########################
|
||||
FROM rust:1.53 as build
|
||||
|
@@ -14,21 +14,22 @@
|
||||
# - 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.
|
||||
# - From the command line:
|
||||
# $ docker pull vaultwarden/web-vault:v2.20.4b
|
||||
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.20.4b
|
||||
# [vaultwarden/web-vault@sha256:894e266d4491494dd5a8a736855a6772aa146fa14206853b11b41cf3f3f64d05]
|
||||
# $ docker pull vaultwarden/web-vault:v2.21.1
|
||||
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.21.1
|
||||
# [vaultwarden/web-vault@sha256:29a4fa7bf3790fff9d908b02ac5a154913491f4bf30c95b87b06d8cf1c5516b5]
|
||||
#
|
||||
# - Conversely, to get the tag name from the digest:
|
||||
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:894e266d4491494dd5a8a736855a6772aa146fa14206853b11b41cf3f3f64d05
|
||||
# [vaultwarden/web-vault:v2.20.4b]
|
||||
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:29a4fa7bf3790fff9d908b02ac5a154913491f4bf30c95b87b06d8cf1c5516b5
|
||||
# [vaultwarden/web-vault:v2.21.1]
|
||||
#
|
||||
FROM vaultwarden/web-vault@sha256:894e266d4491494dd5a8a736855a6772aa146fa14206853b11b41cf3f3f64d05 as vault
|
||||
FROM vaultwarden/web-vault@sha256:29a4fa7bf3790fff9d908b02ac5a154913491f4bf30c95b87b06d8cf1c5516b5 as vault
|
||||
|
||||
########################## BUILD IMAGE ##########################
|
||||
FROM messense/rust-musl-cross:armv7-musleabihf as build
|
||||
|
||||
# Alpine-based ARM (musl) only supports sqlite during compile time.
|
||||
ARG DB=sqlite
|
||||
# We now also need to add vendored_openssl, because the current base image we use to build has OpenSSL removed.
|
||||
ARG DB=sqlite,vendored_openssl
|
||||
|
||||
# Build time options to avoid dpkg warnings and help with reproducible builds.
|
||||
ENV DEBIAN_FRONTEND=noninteractive LANG=C.UTF-8 TZ=UTC TERM=xterm-256color
|
||||
|
@@ -0,0 +1,5 @@
|
||||
ALTER TABLE organizations
|
||||
ADD COLUMN private_key TEXT;
|
||||
|
||||
ALTER TABLE organizations
|
||||
ADD COLUMN public_key TEXT;
|
@@ -0,0 +1,5 @@
|
||||
ALTER TABLE organizations
|
||||
ADD COLUMN private_key TEXT;
|
||||
|
||||
ALTER TABLE organizations
|
||||
ADD COLUMN public_key TEXT;
|
@@ -0,0 +1,5 @@
|
||||
ALTER TABLE organizations
|
||||
ADD COLUMN private_key TEXT;
|
||||
|
||||
ALTER TABLE organizations
|
||||
ADD COLUMN public_key TEXT;
|
99
resources/vaultwarden-icon-white.svg
Normal file
99
resources/vaultwarden-icon-white.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 8.7 KiB |
86
resources/vaultwarden-icon.svg
Normal file
86
resources/vaultwarden-icon.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 8.4 KiB |
271
resources/vaultwarden-logo-white.svg
Normal file
271
resources/vaultwarden-logo-white.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 17 KiB |
151
resources/vaultwarden-logo.svg
Normal file
151
resources/vaultwarden-logo.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 12 KiB |
@@ -231,7 +231,10 @@ fn post_password(data: JsonUpcase<ChangePassData>, headers: Headers, conn: DbCon
|
||||
err!("Invalid password")
|
||||
}
|
||||
|
||||
user.set_password(&data.NewMasterPasswordHash, Some("post_rotatekey"));
|
||||
user.set_password(
|
||||
&data.NewMasterPasswordHash,
|
||||
Some(vec![String::from("post_rotatekey"), String::from("get_contacts")]),
|
||||
);
|
||||
user.akey = data.Key;
|
||||
user.save(&conn)
|
||||
}
|
||||
@@ -320,7 +323,9 @@ fn post_rotatekey(data: JsonUpcase<KeyData>, headers: Headers, conn: DbConn, nt:
|
||||
err!("The cipher is not owned by the user")
|
||||
}
|
||||
|
||||
update_cipher_from_data(&mut saved_cipher, cipher_data, &headers, false, &conn, &nt, UpdateType::CipherUpdate)?
|
||||
// Prevent triggering cipher updates via WebSockets by settings UpdateType::None
|
||||
// The user sessions are invalidated because all the ciphers were re-encrypted and thus triggering an update could cause issues.
|
||||
update_cipher_from_data(&mut saved_cipher, cipher_data, &headers, false, &conn, &nt, UpdateType::None)?
|
||||
}
|
||||
|
||||
// Update user data
|
||||
@@ -329,7 +334,6 @@ fn post_rotatekey(data: JsonUpcase<KeyData>, headers: Headers, conn: DbConn, nt:
|
||||
user.akey = data.Key;
|
||||
user.private_key = Some(data.PrivateKey);
|
||||
user.reset_security_stamp();
|
||||
user.reset_stamp_exception();
|
||||
|
||||
user.save(&conn)
|
||||
}
|
||||
@@ -576,24 +580,45 @@ struct PasswordHintData {
|
||||
|
||||
#[post("/accounts/password-hint", data = "<data>")]
|
||||
fn password_hint(data: JsonUpcase<PasswordHintData>, conn: DbConn) -> EmptyResult {
|
||||
if !CONFIG.mail_enabled() && !CONFIG.show_password_hint() {
|
||||
err!("This server is not configured to provide password hints.");
|
||||
}
|
||||
|
||||
const NO_HINT: &str = "Sorry, you have no password hint...";
|
||||
|
||||
let data: PasswordHintData = data.into_inner().data;
|
||||
let email = &data.Email;
|
||||
|
||||
let hint = match User::find_by_mail(&data.Email, &conn) {
|
||||
Some(user) => user.password_hint,
|
||||
None => return Ok(()),
|
||||
};
|
||||
|
||||
match User::find_by_mail(email, &conn) {
|
||||
None => {
|
||||
// To prevent user enumeration, act as if the user exists.
|
||||
if CONFIG.mail_enabled() {
|
||||
mail::send_password_hint(&data.Email, hint)?;
|
||||
} else if CONFIG.show_password_hint() {
|
||||
if let Some(hint) = hint {
|
||||
err!(format!("Your password hint is: {}", &hint));
|
||||
} else {
|
||||
err!("Sorry, you have no password hint...");
|
||||
}
|
||||
}
|
||||
|
||||
// There is still a timing side channel here in that the code
|
||||
// paths that send mail take noticeably longer than ones that
|
||||
// don't. Add a randomized sleep to mitigate this somewhat.
|
||||
use rand::{thread_rng, Rng};
|
||||
let mut rng = thread_rng();
|
||||
let base = 1000;
|
||||
let delta: i32 = 100;
|
||||
let sleep_ms = (base + rng.gen_range(-delta..=delta)) as u64;
|
||||
std::thread::sleep(std::time::Duration::from_millis(sleep_ms));
|
||||
Ok(())
|
||||
} else {
|
||||
err!(NO_HINT);
|
||||
}
|
||||
}
|
||||
Some(user) => {
|
||||
let hint: Option<String> = user.password_hint;
|
||||
if CONFIG.mail_enabled() {
|
||||
mail::send_password_hint(email, hint)?;
|
||||
Ok(())
|
||||
} else if let Some(hint) = hint {
|
||||
err!(format!("Your password hint is: {}", hint));
|
||||
} else {
|
||||
err!(NO_HINT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
|
@@ -871,7 +871,7 @@ fn save_attachment(
|
||||
Some(limit_kb) => {
|
||||
let left = (limit_kb * 1024) - Attachment::size_by_user(user_uuid, conn) + size_adjust;
|
||||
if left <= 0 {
|
||||
err_discard!("Attachment size limit reached! Delete some files to open space", data)
|
||||
err_discard!("Attachment storage limit reached! Delete some attachments to free up space", data)
|
||||
}
|
||||
Some(left as u64)
|
||||
}
|
||||
@@ -883,7 +883,7 @@ fn save_attachment(
|
||||
Some(limit_kb) => {
|
||||
let left = (limit_kb * 1024) - Attachment::size_by_org(org_uuid, conn) + size_adjust;
|
||||
if left <= 0 {
|
||||
err_discard!("Attachment size limit reached! Delete some files to open space", data)
|
||||
err_discard!("Attachment storage limit reached! Delete some attachments to free up space", data)
|
||||
}
|
||||
Some(left as u64)
|
||||
}
|
||||
@@ -937,7 +937,7 @@ fn save_attachment(
|
||||
return;
|
||||
}
|
||||
SaveResult::Partial(_, reason) => {
|
||||
error = Some(format!("Attachment size limit exceeded with this file: {:?}", reason));
|
||||
error = Some(format!("Attachment storage limit exceeded with this file: {:?}", reason));
|
||||
return;
|
||||
}
|
||||
SaveResult::Error(e) => {
|
||||
|
24
src/api/core/emergency_access.rs
Normal file
24
src/api/core/emergency_access.rs
Normal file
@@ -0,0 +1,24 @@
|
||||
use rocket::Route;
|
||||
use rocket_contrib::json::Json;
|
||||
|
||||
use crate::{api::JsonResult, auth::Headers, db::DbConn};
|
||||
|
||||
pub fn routes() -> Vec<Route> {
|
||||
routes![get_contacts,]
|
||||
}
|
||||
|
||||
/// This endpoint is expected to return at least something.
|
||||
/// If we return an error message that will trigger error toasts for the user.
|
||||
/// To prevent this we just return an empty json result with no Data.
|
||||
/// When this feature is going to be implemented it also needs to return this empty Data
|
||||
/// instead of throwing an error/4XX unless it really is an error.
|
||||
#[get("/emergency-access/trusted")]
|
||||
fn get_contacts(_headers: Headers, _conn: DbConn) -> JsonResult {
|
||||
debug!("Emergency access is not supported.");
|
||||
|
||||
Ok(Json(json!({
|
||||
"Data": [],
|
||||
"Object": "list",
|
||||
"ContinuationToken": null
|
||||
})))
|
||||
}
|
@@ -1,5 +1,6 @@
|
||||
mod accounts;
|
||||
mod ciphers;
|
||||
mod emergency_access;
|
||||
mod folders;
|
||||
mod organizations;
|
||||
mod sends;
|
||||
@@ -15,6 +16,7 @@ pub fn routes() -> Vec<Route> {
|
||||
let mut routes = Vec::new();
|
||||
routes.append(&mut accounts::routes());
|
||||
routes.append(&mut ciphers::routes());
|
||||
routes.append(&mut emergency_access::routes());
|
||||
routes.append(&mut folders::routes());
|
||||
routes.append(&mut organizations::routes());
|
||||
routes.append(&mut two_factor::routes());
|
||||
|
@@ -51,6 +51,7 @@ pub fn routes() -> Vec<Route> {
|
||||
get_plans,
|
||||
get_plans_tax_rates,
|
||||
import,
|
||||
post_org_keys,
|
||||
]
|
||||
}
|
||||
|
||||
@@ -61,6 +62,7 @@ struct OrgData {
|
||||
CollectionName: String,
|
||||
Key: String,
|
||||
Name: String,
|
||||
Keys: Option<OrgKeyData>,
|
||||
#[serde(rename = "PlanType")]
|
||||
_PlanType: NumberOrString, // Ignored, always use the same plan
|
||||
}
|
||||
@@ -78,6 +80,13 @@ struct NewCollectionData {
|
||||
Name: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[allow(non_snake_case)]
|
||||
struct OrgKeyData {
|
||||
EncryptedPrivateKey: String,
|
||||
PublicKey: String,
|
||||
}
|
||||
|
||||
#[post("/organizations", data = "<data>")]
|
||||
fn create_organization(headers: Headers, data: JsonUpcase<OrgData>, conn: DbConn) -> JsonResult {
|
||||
if !CONFIG.is_org_creation_allowed(&headers.user.email) {
|
||||
@@ -85,8 +94,14 @@ fn create_organization(headers: Headers, data: JsonUpcase<OrgData>, conn: DbConn
|
||||
}
|
||||
|
||||
let data: OrgData = data.into_inner().data;
|
||||
let (private_key, public_key) = if data.Keys.is_some() {
|
||||
let keys: OrgKeyData = data.Keys.unwrap();
|
||||
(Some(keys.EncryptedPrivateKey), Some(keys.PublicKey))
|
||||
} else {
|
||||
(None, None)
|
||||
};
|
||||
|
||||
let org = Organization::new(data.Name, data.BillingEmail);
|
||||
let org = Organization::new(data.Name, data.BillingEmail, private_key, public_key);
|
||||
let mut user_org = UserOrganization::new(headers.user.uuid, org.uuid.clone());
|
||||
let collection = Collection::new(org.uuid.clone(), data.CollectionName);
|
||||
|
||||
@@ -468,6 +483,32 @@ fn get_org_users(org_id: String, _headers: ManagerHeadersLoose, conn: DbConn) ->
|
||||
}))
|
||||
}
|
||||
|
||||
#[post("/organizations/<org_id>/keys", data = "<data>")]
|
||||
fn post_org_keys(org_id: String, data: JsonUpcase<OrgKeyData>, _headers: AdminHeaders, conn: DbConn) -> JsonResult {
|
||||
let data: OrgKeyData = data.into_inner().data;
|
||||
|
||||
let mut org = match Organization::find_by_uuid(&org_id, &conn) {
|
||||
Some(organization) => {
|
||||
if organization.private_key.is_some() && organization.public_key.is_some() {
|
||||
err!("Organization Keys already exist")
|
||||
}
|
||||
organization
|
||||
}
|
||||
None => err!("Can't find organization details"),
|
||||
};
|
||||
|
||||
org.private_key = Some(data.EncryptedPrivateKey);
|
||||
org.public_key = Some(data.PublicKey);
|
||||
|
||||
org.save(&conn)?;
|
||||
|
||||
Ok(Json(json!({
|
||||
"Object": "organizationKeys",
|
||||
"PublicKey": org.public_key,
|
||||
"PrivateKey": org.private_key,
|
||||
})))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[allow(non_snake_case)]
|
||||
struct CollectionData {
|
||||
@@ -646,6 +687,19 @@ fn accept_invite(_org_id: String, _org_user_id: String, data: JsonUpcase<AcceptD
|
||||
err!("User already accepted the invitation")
|
||||
}
|
||||
|
||||
let user_twofactor_disabled = TwoFactor::find_by_user(&user_org.user_uuid, &conn).is_empty();
|
||||
|
||||
let policy = OrgPolicyType::TwoFactorAuthentication as i32;
|
||||
let org_twofactor_policy_enabled =
|
||||
match OrgPolicy::find_by_org_and_type(&user_org.org_uuid, policy, &conn) {
|
||||
Some(p) => p.enabled,
|
||||
None => false,
|
||||
};
|
||||
|
||||
if org_twofactor_policy_enabled && user_twofactor_disabled {
|
||||
err!("You cannot join this organization until you enable two-step login on your user account.")
|
||||
}
|
||||
|
||||
user_org.status = UserOrgStatus::Accepted as i32;
|
||||
user_org.save(&conn)?;
|
||||
}
|
||||
@@ -998,6 +1052,24 @@ fn put_policy(
|
||||
None => err!("Invalid policy type"),
|
||||
};
|
||||
|
||||
if pol_type_enum == OrgPolicyType::TwoFactorAuthentication && data.enabled {
|
||||
let org_list = UserOrganization::find_by_org(&org_id, &conn);
|
||||
|
||||
for user_org in org_list.into_iter() {
|
||||
let user_twofactor_disabled = TwoFactor::find_by_user(&user_org.user_uuid, &conn).is_empty();
|
||||
|
||||
if user_twofactor_disabled && user_org.atype < UserOrgType::Admin {
|
||||
if CONFIG.mail_enabled() {
|
||||
let org = Organization::find_by_uuid(&user_org.org_uuid, &conn).unwrap();
|
||||
let user = User::find_by_uuid(&user_org.user_uuid, &conn).unwrap();
|
||||
|
||||
mail::send_2fa_removed_from_org(&user.email, &org.name)?;
|
||||
}
|
||||
user_org.delete(&conn)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut policy = match OrgPolicy::find_by_org_and_type(&org_id, pol_type, &conn) {
|
||||
Some(p) => p,
|
||||
None => OrgPolicy::new(org_id, pol_type_enum, "{}".to_string()),
|
||||
|
@@ -10,6 +10,7 @@ use crate::{
|
||||
api::{ApiResult, EmptyResult, JsonResult, JsonUpcase, Notify, UpdateType},
|
||||
auth::{Headers, Host},
|
||||
db::{models::*, DbConn, DbPool},
|
||||
util::SafeString,
|
||||
CONFIG,
|
||||
};
|
||||
|
||||
@@ -165,19 +166,19 @@ fn post_send_file(data: Data, content_type: &ContentType, headers: Headers, conn
|
||||
let data = serde_json::from_str::<crate::util::UpCase<SendData>>(&buf)?;
|
||||
enforce_disable_hide_email_policy(&data.data, &headers, &conn)?;
|
||||
|
||||
// Get the file length and add an extra 10% to avoid issues
|
||||
const SIZE_110_MB: u64 = 115_343_360;
|
||||
// Get the file length and add an extra 5% to avoid issues
|
||||
const SIZE_525_MB: u64 = 550_502_400;
|
||||
|
||||
let size_limit = match CONFIG.user_attachment_limit() {
|
||||
Some(0) => err!("File uploads are disabled"),
|
||||
Some(limit_kb) => {
|
||||
let left = (limit_kb * 1024) - Attachment::size_by_user(&headers.user.uuid, &conn);
|
||||
if left <= 0 {
|
||||
err!("Attachment size limit reached! Delete some files to open space")
|
||||
err!("Attachment storage limit reached! Delete some attachments to free up space")
|
||||
}
|
||||
std::cmp::Ord::max(left as u64, SIZE_110_MB)
|
||||
std::cmp::Ord::max(left as u64, SIZE_525_MB)
|
||||
}
|
||||
None => SIZE_110_MB,
|
||||
None => SIZE_525_MB,
|
||||
};
|
||||
|
||||
// Create the Send
|
||||
@@ -205,7 +206,7 @@ fn post_send_file(data: Data, content_type: &ContentType, headers: Headers, conn
|
||||
}
|
||||
SaveResult::Partial(_, reason) => {
|
||||
std::fs::remove_file(&file_path).ok();
|
||||
err!(format!("Attachment size limit exceeded with this file: {:?}", reason));
|
||||
err!(format!("Attachment storage limit exceeded with this file: {:?}", reason));
|
||||
}
|
||||
SaveResult::Error(e) => {
|
||||
std::fs::remove_file(&file_path).ok();
|
||||
@@ -335,7 +336,7 @@ fn post_access_file(
|
||||
}
|
||||
|
||||
#[get("/sends/<send_id>/<file_id>?<t>")]
|
||||
fn download_send(send_id: String, file_id: String, t: String) -> Option<NamedFile> {
|
||||
fn download_send(send_id: SafeString, file_id: SafeString, t: String) -> Option<NamedFile> {
|
||||
if let Ok(claims) = crate::auth::decode_send(&t) {
|
||||
if claims.sub == format!("{}/{}", send_id, file_id) {
|
||||
return NamedFile::open(Path::new(&CONFIG.sends_folder()).join(send_id).join(file_id)).ok();
|
||||
|
@@ -7,10 +7,8 @@ use crate::{
|
||||
api::{JsonResult, JsonUpcase, NumberOrString, PasswordData},
|
||||
auth::Headers,
|
||||
crypto,
|
||||
db::{
|
||||
models::{TwoFactor, User},
|
||||
DbConn,
|
||||
},
|
||||
db::{models::*, DbConn},
|
||||
mail, CONFIG,
|
||||
};
|
||||
|
||||
pub mod authenticator;
|
||||
@@ -130,6 +128,23 @@ fn disable_twofactor(data: JsonUpcase<DisableTwoFactorData>, headers: Headers, c
|
||||
twofactor.delete(&conn)?;
|
||||
}
|
||||
|
||||
let twofactor_disabled = TwoFactor::find_by_user(&user.uuid, &conn).is_empty();
|
||||
|
||||
if twofactor_disabled {
|
||||
let policy_type = OrgPolicyType::TwoFactorAuthentication;
|
||||
let org_list = UserOrganization::find_by_user_and_policy(&user.uuid, policy_type, &conn);
|
||||
|
||||
for user_org in org_list.into_iter() {
|
||||
if user_org.atype < UserOrgType::Admin {
|
||||
if CONFIG.mail_enabled() {
|
||||
let org = Organization::find_by_uuid(&user_org.org_uuid, &conn).unwrap();
|
||||
mail::send_2fa_removed_from_org(&user.email, &org.name)?;
|
||||
}
|
||||
user_org.delete(&conn)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Json(json!({
|
||||
"Enabled": false,
|
||||
"Type": type_,
|
||||
|
@@ -51,19 +51,12 @@ impl webauthn_rs::WebauthnConfig for WebauthnConfig {
|
||||
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
|
||||
/// We have WebAuthn configured to discourage user verification
|
||||
/// if we leave this enabled, it will cause verification issues when a keys send UV=1.
|
||||
/// Upstream (the library they use) ignores this when set to discouraged, so we should too.
|
||||
fn get_require_uv_consistency(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -289,15 +282,14 @@ fn delete_webauthn(data: JsonUpcase<DeleteU2FData>, headers: Headers, conn: DbCo
|
||||
err!("Invalid password");
|
||||
}
|
||||
|
||||
let type_ = TwoFactorType::Webauthn as i32;
|
||||
let mut tf = match TwoFactor::find_by_user_and_type(&headers.user.uuid, type_, &conn) {
|
||||
let mut tf = match TwoFactor::find_by_user_and_type(&headers.user.uuid, TwoFactorType::Webauthn as i32, &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) {
|
||||
let item_pos = match data.iter().position(|r| r.id == id) {
|
||||
Some(p) => p,
|
||||
None => err!("Webauthn entry not found"),
|
||||
};
|
||||
|
@@ -408,12 +408,10 @@ pub fn start_notification_server() -> WebSocketUsers {
|
||||
|
||||
if CONFIG.websocket_enabled() {
|
||||
thread::spawn(move || {
|
||||
let settings = ws::Settings {
|
||||
max_connections: 500,
|
||||
queue_size: 2,
|
||||
panic_on_internal: false,
|
||||
..Default::default()
|
||||
};
|
||||
let mut settings = ws::Settings::default();
|
||||
settings.max_connections = 500;
|
||||
settings.queue_size = 2;
|
||||
settings.panic_on_internal = false;
|
||||
|
||||
ws::Builder::new()
|
||||
.with_settings(settings)
|
||||
|
@@ -4,7 +4,11 @@ use rocket::{http::ContentType, response::content::Content, response::NamedFile,
|
||||
use rocket_contrib::json::Json;
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::{error::Error, util::Cached, CONFIG};
|
||||
use crate::{
|
||||
error::Error,
|
||||
util::{Cached, SafeString},
|
||||
CONFIG,
|
||||
};
|
||||
|
||||
pub fn routes() -> Vec<Route> {
|
||||
// If addding more routes here, consider also adding them to
|
||||
@@ -56,7 +60,7 @@ fn web_files(p: PathBuf) -> Cached<Option<NamedFile>> {
|
||||
}
|
||||
|
||||
#[get("/attachments/<uuid>/<file_id>")]
|
||||
fn attachments(uuid: String, file_id: String) -> Option<NamedFile> {
|
||||
fn attachments(uuid: SafeString, file_id: SafeString) -> Option<NamedFile> {
|
||||
NamedFile::open(Path::new(&CONFIG.attachments_folder()).join(uuid).join(file_id)).ok()
|
||||
}
|
||||
|
||||
|
15
src/auth.rs
15
src/auth.rs
@@ -325,8 +325,19 @@ impl<'a, 'r> FromRequest<'a, 'r> for Headers {
|
||||
_ => err_handler!("Error getting current route for stamp exception"),
|
||||
};
|
||||
|
||||
// Check if both match, if not this route is not allowed with the current security stamp.
|
||||
if stamp_exception.route != current_route {
|
||||
// Check if the stamp exception has expired first.
|
||||
// Then, check if the current route matches any of the allowed routes.
|
||||
// After that check the stamp in exception matches the one in the claims.
|
||||
if Utc::now().naive_utc().timestamp() > stamp_exception.expire {
|
||||
// If the stamp exception has been expired remove it from the database.
|
||||
// This prevents checking this stamp exception for new requests.
|
||||
let mut user = user;
|
||||
user.reset_stamp_exception();
|
||||
if let Err(e) = user.save(&conn) {
|
||||
error!("Error updating user: {:#?}", e);
|
||||
}
|
||||
err_handler!("Stamp exception is expired")
|
||||
} else if !stamp_exception.routes.contains(¤t_route.to_string()) {
|
||||
err_handler!("Invalid security stamp: Current route and exception route do not match")
|
||||
} else if stamp_exception.security_stamp != claims.sstamp {
|
||||
err_handler!("Invalid security stamp for matched stamp exception")
|
||||
|
@@ -356,9 +356,9 @@ make_config! {
|
||||
/// HIBP Api Key |> HaveIBeenPwned API Key, request it here: https://haveibeenpwned.com/API/Key
|
||||
hibp_api_key: Pass, true, option;
|
||||
|
||||
/// Per-user attachment limit (KB) |> Limit in kilobytes for a users attachments, once the limit is exceeded it won't be possible to upload more
|
||||
/// Per-user attachment storage limit (KB) |> Max kilobytes of attachment storage allowed per user. When this limit is reached, the user will not be allowed to upload further attachments.
|
||||
user_attachment_limit: i64, true, option;
|
||||
/// Per-organization attachment limit (KB) |> Limit in kilobytes for an organization attachments, once the limit is exceeded it won't be possible to upload more
|
||||
/// Per-organization attachment storage limit (KB) |> Max kilobytes of attachment storage allowed per org. When this limit is reached, org members will not be allowed to upload further attachments for ciphers owned by that org.
|
||||
org_attachment_limit: i64, true, option;
|
||||
|
||||
/// Trash auto-delete days |> Number of days to wait before auto-deleting a trashed item.
|
||||
@@ -388,9 +388,10 @@ make_config! {
|
||||
/// Password iterations |> Number of server-side passwords hashing iterations.
|
||||
/// The changes only apply when a user changes their password. Not recommended to lower the value
|
||||
password_iterations: i32, true, def, 100_000;
|
||||
/// Show password hints |> Controls if the password hint should be shown directly in the web page.
|
||||
/// Otherwise, if email is disabled, there is no way to see the password hint
|
||||
show_password_hint: bool, true, def, true;
|
||||
/// Show password hint |> Controls whether a password hint should be shown directly in the web page
|
||||
/// if SMTP service is not configured. Not recommended for publicly-accessible instances as this
|
||||
/// provides unauthenticated access to potentially sensitive data.
|
||||
show_password_hint: bool, true, def, false;
|
||||
|
||||
/// Admin page token |> The token used to authenticate in this very same page. Changing it here won't deauthorize the current session
|
||||
admin_token: Pass, true, option;
|
||||
@@ -857,6 +858,7 @@ where
|
||||
reg!("email/new_device_logged_in", ".html");
|
||||
reg!("email/pw_hint_none", ".html");
|
||||
reg!("email/pw_hint_some", ".html");
|
||||
reg!("email/send_2fa_removed_from_org", ".html");
|
||||
reg!("email/send_org_invite", ".html");
|
||||
reg!("email/twofactor_email", ".html");
|
||||
reg!("email/verify_email", ".html");
|
||||
|
@@ -22,7 +22,7 @@ db_object! {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, num_derive::FromPrimitive)]
|
||||
#[derive(Copy, Clone, PartialEq, num_derive::FromPrimitive)]
|
||||
pub enum OrgPolicyType {
|
||||
TwoFactorAuthentication = 0,
|
||||
MasterPassword = 1,
|
||||
|
@@ -2,7 +2,7 @@ use num_traits::FromPrimitive;
|
||||
use serde_json::Value;
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use super::{CollectionUser, OrgPolicy, User};
|
||||
use super::{CollectionUser, OrgPolicy, OrgPolicyType, User};
|
||||
|
||||
db_object! {
|
||||
#[derive(Identifiable, Queryable, Insertable, AsChangeset)]
|
||||
@@ -12,6 +12,8 @@ db_object! {
|
||||
pub uuid: String,
|
||||
pub name: String,
|
||||
pub billing_email: String,
|
||||
pub private_key: Option<String>,
|
||||
pub public_key: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Identifiable, Queryable, Insertable, AsChangeset)]
|
||||
@@ -122,12 +124,13 @@ impl PartialOrd<UserOrgType> for i32 {
|
||||
|
||||
/// Local methods
|
||||
impl Organization {
|
||||
pub fn new(name: String, billing_email: String) -> Self {
|
||||
pub fn new(name: String, billing_email: String, private_key: Option<String>, public_key: Option<String>) -> Self {
|
||||
Self {
|
||||
uuid: crate::util::get_uuid(),
|
||||
|
||||
name,
|
||||
billing_email,
|
||||
private_key,
|
||||
public_key,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,14 +143,16 @@ impl Organization {
|
||||
"MaxCollections": 10, // The value doesn't matter, we don't check server-side
|
||||
"MaxStorageGb": 10, // The value doesn't matter, we don't check server-side
|
||||
"Use2fa": true,
|
||||
"UseDirectory": false,
|
||||
"UseEvents": false,
|
||||
"UseGroups": false,
|
||||
"UseDirectory": false, // Is supported, but this value isn't checked anywhere (yet)
|
||||
"UseEvents": false, // not supported by us
|
||||
"UseGroups": false, // not supported by us
|
||||
"UseTotp": true,
|
||||
"UsePolicies": true,
|
||||
"UseSso": false, // We do not support SSO
|
||||
"SelfHost": true,
|
||||
"UseApi": false, // not supported by us
|
||||
"HasPublicAndPrivateKeys": self.private_key.is_some() && self.public_key.is_some(),
|
||||
"ResetPasswordEnrolled": false, // not supported by us
|
||||
|
||||
"BusinessName": null,
|
||||
"BusinessAddress1": null,
|
||||
@@ -269,13 +274,15 @@ impl UserOrganization {
|
||||
"UsersGetPremium": true,
|
||||
|
||||
"Use2fa": true,
|
||||
"UseDirectory": false,
|
||||
"UseEvents": false,
|
||||
"UseGroups": false,
|
||||
"UseDirectory": false, // Is supported, but this value isn't checked anywhere (yet)
|
||||
"UseEvents": false, // not supported by us
|
||||
"UseGroups": false, // not supported by us
|
||||
"UseTotp": true,
|
||||
"UsePolicies": true,
|
||||
"UseApi": false, // not supported by us
|
||||
"SelfHost": true,
|
||||
"HasPublicAndPrivateKeys": org.private_key.is_some() && org.public_key.is_some(),
|
||||
"ResetPasswordEnrolled": false, // not supported by us
|
||||
"SsoBound": false, // We do not support SSO
|
||||
"UseSso": false, // We do not support SSO
|
||||
// TODO: Add support for Business Portal
|
||||
@@ -293,10 +300,12 @@ impl UserOrganization {
|
||||
// "AccessReports": false,
|
||||
// "ManageAllCollections": false,
|
||||
// "ManageAssignedCollections": false,
|
||||
// "ManageCiphers": false,
|
||||
// "ManageGroups": false,
|
||||
// "ManagePolicies": false,
|
||||
// "ManageResetPassword": false,
|
||||
// "ManageSso": false,
|
||||
// "ManageUsers": false
|
||||
// "ManageUsers": false,
|
||||
// },
|
||||
|
||||
"MaxStorageGb": 10, // The value doesn't matter, we don't check server-side
|
||||
@@ -535,6 +544,25 @@ impl UserOrganization {
|
||||
}}
|
||||
}
|
||||
|
||||
pub fn find_by_user_and_policy(user_uuid: &str, policy_type: OrgPolicyType, conn: &DbConn) -> Vec<Self> {
|
||||
db_run! { conn: {
|
||||
users_organizations::table
|
||||
.inner_join(
|
||||
org_policies::table.on(
|
||||
org_policies::org_uuid.eq(users_organizations::org_uuid)
|
||||
.and(users_organizations::user_uuid.eq(user_uuid))
|
||||
.and(org_policies::atype.eq(policy_type as i32))
|
||||
.and(org_policies::enabled.eq(true)))
|
||||
)
|
||||
.filter(
|
||||
users_organizations::status.eq(UserOrgStatus::Confirmed as i32)
|
||||
)
|
||||
.select(users_organizations::all_columns)
|
||||
.load::<UserOrganizationDb>(conn)
|
||||
.unwrap_or_default().from_db()
|
||||
}}
|
||||
}
|
||||
|
||||
pub fn find_by_cipher_and_org(cipher_uuid: &str, org_uuid: &str, conn: &DbConn) -> Vec<Self> {
|
||||
db_run! { conn: {
|
||||
users_organizations::table
|
||||
|
@@ -1,4 +1,4 @@
|
||||
use chrono::{NaiveDateTime, Utc};
|
||||
use chrono::{Duration, NaiveDateTime, Utc};
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::crypto;
|
||||
@@ -63,8 +63,9 @@ enum UserStatus {
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct UserStampException {
|
||||
pub route: String,
|
||||
pub routes: Vec<String>,
|
||||
pub security_stamp: String,
|
||||
pub expire: i64,
|
||||
}
|
||||
|
||||
/// Local methods
|
||||
@@ -135,9 +136,11 @@ impl User {
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `password` - A str which contains a hashed version of the users master password.
|
||||
/// * `allow_next_route` - A Option<&str> with the function name of the next allowed (rocket) route.
|
||||
/// * `allow_next_route` - A Option<Vec<String>> with the function names of the next allowed (rocket) routes.
|
||||
/// These routes are able to use the previous stamp id for the next 2 minutes.
|
||||
/// After these 2 minutes this stamp will expire.
|
||||
///
|
||||
pub fn set_password(&mut self, password: &str, allow_next_route: Option<&str>) {
|
||||
pub fn set_password(&mut self, password: &str, allow_next_route: Option<Vec<String>>) {
|
||||
self.password_hash = crypto::hash_password(password.as_bytes(), &self.salt, self.password_iterations as u32);
|
||||
|
||||
if let Some(route) = allow_next_route {
|
||||
@@ -154,24 +157,20 @@ impl User {
|
||||
/// Set the stamp_exception to only allow a subsequent request matching a specific route using the current security-stamp.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `route_exception` - A str with the function name of the next allowed (rocket) route.
|
||||
/// * `route_exception` - A Vec<String> with the function names of the next allowed (rocket) routes.
|
||||
/// These routes are able to use the previous stamp id for the next 2 minutes.
|
||||
/// After these 2 minutes this stamp will expire.
|
||||
///
|
||||
/// ### Future
|
||||
/// In the future it could be posible that we need more of these exception routes.
|
||||
/// In that case we could use an Vec<UserStampException> and add multiple exceptions.
|
||||
pub fn set_stamp_exception(&mut self, route_exception: &str) {
|
||||
pub fn set_stamp_exception(&mut self, route_exception: Vec<String>) {
|
||||
let stamp_exception = UserStampException {
|
||||
route: route_exception.to_string(),
|
||||
routes: route_exception,
|
||||
security_stamp: self.security_stamp.to_string(),
|
||||
expire: (Utc::now().naive_utc() + Duration::minutes(2)).timestamp(),
|
||||
};
|
||||
self.stamp_exception = Some(serde_json::to_string(&stamp_exception).unwrap_or_default());
|
||||
}
|
||||
|
||||
/// Resets the stamp_exception to prevent re-use of the previous security-stamp
|
||||
///
|
||||
/// ### Future
|
||||
/// In the future it could be posible that we need more of these exception routes.
|
||||
/// In that case we could use an Vec<UserStampException> and add multiple exceptions.
|
||||
pub fn reset_stamp_exception(&mut self) {
|
||||
self.stamp_exception = None;
|
||||
}
|
||||
|
@@ -100,6 +100,8 @@ table! {
|
||||
uuid -> Text,
|
||||
name -> Text,
|
||||
billing_email -> Text,
|
||||
private_key -> Nullable<Text>,
|
||||
public_key -> Nullable<Text>,
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -100,6 +100,8 @@ table! {
|
||||
uuid -> Text,
|
||||
name -> Text,
|
||||
billing_email -> Text,
|
||||
private_key -> Nullable<Text>,
|
||||
public_key -> Nullable<Text>,
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -100,6 +100,8 @@ table! {
|
||||
uuid -> Text,
|
||||
name -> Text,
|
||||
billing_email -> Text,
|
||||
private_key -> Nullable<Text>,
|
||||
public_key -> Nullable<Text>,
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -166,7 +166,7 @@ fn _serialize(e: &impl serde::Serialize, _msg: &str) -> String {
|
||||
|
||||
fn _api_error(_: &impl std::any::Any, msg: &str) -> String {
|
||||
let json = json!({
|
||||
"Message": "",
|
||||
"Message": msg,
|
||||
"error": "",
|
||||
"error_description": "",
|
||||
"ValidationErrors": {"": [ msg ]},
|
||||
@@ -174,6 +174,9 @@ fn _api_error(_: &impl std::any::Any, msg: &str) -> String {
|
||||
"Message": msg,
|
||||
"Object": "error"
|
||||
},
|
||||
"ExceptionMessage": null,
|
||||
"ExceptionStackTrace": null,
|
||||
"InnerExceptionMessage": null,
|
||||
"Object": "error"
|
||||
});
|
||||
_serialize(&json, "")
|
||||
|
12
src/mail.rs
12
src/mail.rs
@@ -180,6 +180,18 @@ pub fn send_welcome_must_verify(address: &str, uuid: &str) -> EmptyResult {
|
||||
send_email(address, &subject, body_html, body_text)
|
||||
}
|
||||
|
||||
pub fn send_2fa_removed_from_org(address: &str, org_name: &str) -> EmptyResult {
|
||||
let (subject, body_html, body_text) = get_text(
|
||||
"email/send_2fa_removed_from_org",
|
||||
json!({
|
||||
"url": CONFIG.domain(),
|
||||
"org_name": org_name,
|
||||
}),
|
||||
)?;
|
||||
|
||||
send_email(address, &subject, body_html, body_text)
|
||||
}
|
||||
|
||||
pub fn send_invite(
|
||||
address: &str,
|
||||
uuid: &str,
|
||||
|
@@ -4,6 +4,7 @@
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table class="footer" cellpadding="0" cellspacing="0" width="100%" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; clear: both; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; width: 100%;">
|
||||
<tr style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0;">
|
||||
<td class="aligncenter social-icons" align="center" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; padding: 15px 0 0 0;" valign="top">
|
||||
@@ -15,9 +16,7 @@
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
9
src/static/templates/email/send_2fa_removed_from_org.hbs
Normal file
9
src/static/templates/email/send_2fa_removed_from_org.hbs
Normal file
@@ -0,0 +1,9 @@
|
||||
Removed from {{{org_name}}}
|
||||
<!---------------->
|
||||
You have been removed from organization *{{org_name}}* because your account does not have Two-step Login enabled.
|
||||
|
||||
|
||||
You can enable Two-step Login in your account settings.
|
||||
|
||||
===
|
||||
Github: https://github.com/dani-garcia/vaultwarden
|
@@ -0,0 +1,16 @@
|
||||
Removed from {{{org_name}}}
|
||||
<!---------------->
|
||||
{{> email/email_header }}
|
||||
<table width="100%" cellpadding="0" cellspacing="0" style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
|
||||
<tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
|
||||
<td class="content-block" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; margin: 0; -webkit-font-smoothing: antialiased; padding: 0 0 10px; -webkit-text-size-adjust: none; text-align: center;" valign="top" align="center">
|
||||
You have been removed from organization <b style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">{{org_name}}</b> because your account does not have Two-step Login enabled.
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
|
||||
<td class="content-block last" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; margin: 0; -webkit-font-smoothing: antialiased; padding: 0; -webkit-text-size-adjust: none; text-align: center;" valign="top" align="center">
|
||||
You can enable Two-step Login in your account settings.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
{{> email/email_footer }}
|
38
src/util.rs
38
src/util.rs
@@ -5,7 +5,8 @@ use std::io::Cursor;
|
||||
|
||||
use rocket::{
|
||||
fairing::{Fairing, Info, Kind},
|
||||
http::{ContentType, Header, HeaderMap, Method, Status},
|
||||
http::{ContentType, Header, HeaderMap, Method, RawStr, Status},
|
||||
request::FromParam,
|
||||
response::{self, Responder},
|
||||
Data, Request, Response, Rocket,
|
||||
};
|
||||
@@ -29,7 +30,10 @@ impl Fairing for AppHeaders {
|
||||
res.set_raw_header("X-Content-Type-Options", "nosniff");
|
||||
res.set_raw_header("X-XSS-Protection", "1; mode=block");
|
||||
let csp = format!(
|
||||
"frame-ancestors 'self' chrome-extension://nngceckbapebfimnlniiiahkandclblb moz-extension://* {};",
|
||||
// Chrome Web Store: https://chrome.google.com/webstore/detail/bitwarden-free-password-m/nngceckbapebfimnlniiiahkandclblb
|
||||
// Edge Add-ons: https://microsoftedge.microsoft.com/addons/detail/bitwarden-free-password/jbkfoedolllekgbhcbcoahefnbanhhlh?hl=en-US
|
||||
// Firefox Browser Add-ons: https://addons.mozilla.org/en-US/firefox/addon/bitwarden-password-manager/
|
||||
"frame-ancestors 'self' chrome-extension://nngceckbapebfimnlniiiahkandclblb chrome-extension://jbkfoedolllekgbhcbcoahefnbanhhlh moz-extension://* {};",
|
||||
CONFIG.allowed_iframe_ancestors()
|
||||
);
|
||||
res.set_raw_header("Content-Security-Policy", csp);
|
||||
@@ -125,6 +129,36 @@ impl<'r, R: Responder<'r>> Responder<'r> for Cached<R> {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SafeString(String);
|
||||
|
||||
impl std::fmt::Display for SafeString {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<Path> for SafeString {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &Path {
|
||||
Path::new(&self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'r> FromParam<'r> for SafeString {
|
||||
type Error = ();
|
||||
|
||||
#[inline(always)]
|
||||
fn from_param(param: &'r RawStr) -> Result<Self, Self::Error> {
|
||||
let s = param.percent_decode().map(|cow| cow.into_owned()).map_err(|_| ())?;
|
||||
|
||||
if s.chars().all(|c| matches!(c, 'a'..='z' | 'A'..='Z' |'0'..='9' | '-')) {
|
||||
Ok(SafeString(s))
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Log all the routes from the main paths list, and the attachments endpoint
|
||||
// Effectively ignores, any static file route, and the alive endpoint
|
||||
const LOGGED_ROUTES: [&str; 6] =
|
||||
|
Reference in New Issue
Block a user