forked from trashmodern/vaultwarden
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 |
+10
-6
@@ -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
|
||||
|
||||
@@ -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
|
||||
Generated
+101
-106
File diff suppressed because it is too large
Load Diff
+5
-8
@@ -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;
|
||||
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 8.7 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 8.4 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 17 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 12 KiB |
+44
-19
@@ -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 {
|
||||
let data: PasswordHintData = data.into_inner().data;
|
||||
|
||||
let hint = match User::find_by_mail(&data.Email, &conn) {
|
||||
Some(user) => user.password_hint,
|
||||
None => return Ok(()),
|
||||
};
|
||||
|
||||
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...");
|
||||
}
|
||||
if !CONFIG.mail_enabled() && !CONFIG.show_password_hint() {
|
||||
err!("This server is not configured to provide password hints.");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
const NO_HINT: &str = "Sorry, you have no password hint...";
|
||||
|
||||
let data: PasswordHintData = data.into_inner().data;
|
||||
let email = &data.Email;
|
||||
|
||||
match User::find_by_mail(email, &conn) {
|
||||
None => {
|
||||
// To prevent user enumeration, act as if the user exists.
|
||||
if CONFIG.mail_enabled() {
|
||||
// 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) => {
|
||||
|
||||
@@ -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)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user