mirror of
https://github.com/dani-garcia/vaultwarden.git
synced 2024-12-12 09:51:23 +01:00
Disable groups by default and Some optimizations
- Put groups support behind a feature flag, and disabled by default. The reason is that it has some known issues, but we want to keep optimizing this feature. Putting it behind a feature flag could help some users, and the developers into optimizing this feature without to much trouble. Further: - Updates Rust to v1.66.0 - Updated GHA workflows - Updated Alpine to 3.17 - Updated jquery to v3.6.2 - Moved jdenticon.js to load at the bottom, fixes an issue on chromium - Added autocomplete attribute to admin login password field - Added some extra CSP options (Tested this on Safari, Firefox, Chrome, Bitwarden Desktop) - Moved uppercase convertion from runtime to compile-time using `paste` for building the environment variables, lowers heap allocations.
This commit is contained in:
parent
8e5f03972e
commit
67a584c1d4
35 changed files with 229 additions and 94 deletions
|
@ -90,6 +90,13 @@
|
||||||
## If unset (the default), events are kept indefinitely and the scheduled job is disabled!
|
## If unset (the default), events are kept indefinitely and the scheduled job is disabled!
|
||||||
# EVENTS_DAYS_RETAIN=
|
# EVENTS_DAYS_RETAIN=
|
||||||
|
|
||||||
|
## BETA FEATURE: Groups
|
||||||
|
## Controls whether group support is enabled for organizations
|
||||||
|
## This setting applies to organizations.
|
||||||
|
## Disabled by default because this is a beta feature, it contains known issues!
|
||||||
|
## KNOW WHAT YOU ARE DOING!
|
||||||
|
# ORG_GROUPS_ENABLED=false
|
||||||
|
|
||||||
## Job scheduler settings
|
## Job scheduler settings
|
||||||
##
|
##
|
||||||
## Job schedules use a cron-like syntax (as parsed by https://crates.io/crates/cron),
|
## Job schedules use a cron-like syntax (as parsed by https://crates.io/crates/cron),
|
||||||
|
|
5
.github/workflows/build.yml
vendored
5
.github/workflows/build.yml
vendored
|
@ -21,6 +21,7 @@ on:
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
|
timeout-minutes: 120
|
||||||
# Make warnings errors, this is to prevent warnings slipping through.
|
# Make warnings errors, this is to prevent warnings slipping through.
|
||||||
# This is done globally to prevent rebuilds when the RUSTFLAGS env variable changes.
|
# This is done globally to prevent rebuilds when the RUSTFLAGS env variable changes.
|
||||||
env:
|
env:
|
||||||
|
@ -40,7 +41,7 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
# Checkout the repo
|
# Checkout the repo
|
||||||
- name: "Checkout"
|
- name: "Checkout"
|
||||||
uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0
|
uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0
|
||||||
# End Checkout the repo
|
# End Checkout the repo
|
||||||
|
|
||||||
# Install dependencies
|
# Install dependencies
|
||||||
|
@ -78,7 +79,7 @@ jobs:
|
||||||
|
|
||||||
|
|
||||||
# Enable Rust Caching
|
# Enable Rust Caching
|
||||||
- uses: Swatinem/rust-cache@b5ec9edd911d3bf82c74038b0a28791e0aa24d6f # v2.0.2
|
- uses: Swatinem/rust-cache@359a70e43a0bb8a13953b04a90f76428b4959bb6 # v2.2.0
|
||||||
# End Enable Rust Caching
|
# End Enable Rust Caching
|
||||||
|
|
||||||
|
|
||||||
|
|
5
.github/workflows/hadolint.yml
vendored
5
.github/workflows/hadolint.yml
vendored
|
@ -9,10 +9,11 @@ jobs:
|
||||||
hadolint:
|
hadolint:
|
||||||
name: Validate Dockerfile syntax
|
name: Validate Dockerfile syntax
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
|
timeout-minutes: 30
|
||||||
steps:
|
steps:
|
||||||
# Checkout the repo
|
# Checkout the repo
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0
|
uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0
|
||||||
# End Checkout the repo
|
# End Checkout the repo
|
||||||
|
|
||||||
|
|
||||||
|
@ -23,7 +24,7 @@ jobs:
|
||||||
sudo curl -L https://github.com/hadolint/hadolint/releases/download/v${HADOLINT_VERSION}/hadolint-$(uname -s)-$(uname -m) -o /usr/local/bin/hadolint && \
|
sudo curl -L https://github.com/hadolint/hadolint/releases/download/v${HADOLINT_VERSION}/hadolint-$(uname -s)-$(uname -m) -o /usr/local/bin/hadolint && \
|
||||||
sudo chmod +x /usr/local/bin/hadolint
|
sudo chmod +x /usr/local/bin/hadolint
|
||||||
env:
|
env:
|
||||||
HADOLINT_VERSION: 2.10.0
|
HADOLINT_VERSION: 2.12.0
|
||||||
# End Download hadolint
|
# End Download hadolint
|
||||||
|
|
||||||
# Test Dockerfiles
|
# Test Dockerfiles
|
||||||
|
|
5
.github/workflows/release.yml
vendored
5
.github/workflows/release.yml
vendored
|
@ -31,7 +31,7 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
- name: Skip Duplicates Actions
|
- name: Skip Duplicates Actions
|
||||||
id: skip_check
|
id: skip_check
|
||||||
uses: fkirc/skip-duplicate-actions@f11521568414503656a5af807dc3018c012552c4 # v5.2.0
|
uses: fkirc/skip-duplicate-actions@12aca0a884f6137d619d6a8a09fcc3406ced5281 # v5.3.0
|
||||||
with:
|
with:
|
||||||
cancel_others: 'true'
|
cancel_others: 'true'
|
||||||
# Only run this when not creating a tag
|
# Only run this when not creating a tag
|
||||||
|
@ -39,6 +39,7 @@ jobs:
|
||||||
|
|
||||||
docker-build:
|
docker-build:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
|
timeout-minutes: 120
|
||||||
needs: skip_check
|
needs: skip_check
|
||||||
# Start a local docker registry to be used to generate multi-arch images.
|
# Start a local docker registry to be used to generate multi-arch images.
|
||||||
services:
|
services:
|
||||||
|
@ -60,7 +61,7 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
# Checkout the repo
|
# Checkout the repo
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0
|
uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ repos:
|
||||||
language: system
|
language: system
|
||||||
args: ["--features", "sqlite,mysql,postgresql,enable_mimalloc", "--"]
|
args: ["--features", "sqlite,mysql,postgresql,enable_mimalloc", "--"]
|
||||||
types_or: [rust, file]
|
types_or: [rust, file]
|
||||||
files: (Cargo.toml|Cargo.lock|.*\.rs$)
|
files: (Cargo.toml|Cargo.lock|rust-toolchain|.*\.rs$)
|
||||||
pass_filenames: false
|
pass_filenames: false
|
||||||
- id: cargo-clippy
|
- id: cargo-clippy
|
||||||
name: cargo clippy
|
name: cargo clippy
|
||||||
|
@ -36,5 +36,5 @@ repos:
|
||||||
language: system
|
language: system
|
||||||
args: ["--features", "sqlite,mysql,postgresql,enable_mimalloc", "--", "-D", "warnings"]
|
args: ["--features", "sqlite,mysql,postgresql,enable_mimalloc", "--", "-D", "warnings"]
|
||||||
types_or: [rust, file]
|
types_or: [rust, file]
|
||||||
files: (Cargo.toml|Cargo.lock|.*\.rs$)
|
files: (Cargo.toml|Cargo.lock|rust-toolchain|.*\.rs$)
|
||||||
pass_filenames: false
|
pass_filenames: false
|
||||||
|
|
41
Cargo.lock
generated
41
Cargo.lock
generated
|
@ -4,9 +4,9 @@ version = 3
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "addr2line"
|
name = "addr2line"
|
||||||
version = "0.17.0"
|
version = "0.19.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b"
|
checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gimli",
|
"gimli",
|
||||||
]
|
]
|
||||||
|
@ -165,15 +165,15 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "backtrace"
|
name = "backtrace"
|
||||||
version = "0.3.66"
|
version = "0.3.67"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cab84319d616cfb654d03394f38ab7e6f0919e181b1b57e1fd15e7fb4077d9a7"
|
checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"addr2line",
|
"addr2line",
|
||||||
"cc",
|
"cc",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
"miniz_oxide 0.5.4",
|
"miniz_oxide",
|
||||||
"object",
|
"object",
|
||||||
"rustc-demangle",
|
"rustc-demangle",
|
||||||
]
|
]
|
||||||
|
@ -283,9 +283,9 @@ checksum = "3a4f925191b4367301851c6d99b09890311d74b0d43f274c0b34c86d308a3663"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.0.77"
|
version = "1.0.78"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4"
|
checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
|
@ -773,7 +773,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841"
|
checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crc32fast",
|
"crc32fast",
|
||||||
"miniz_oxide 0.6.2",
|
"miniz_oxide",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -947,9 +947,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gimli"
|
name = "gimli"
|
||||||
version = "0.26.2"
|
version = "0.27.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d"
|
checksum = "dec7af912d60cdbd3677c1af9352ebae6fb8394d165568a2234df0fa00f87793"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "glob"
|
name = "glob"
|
||||||
|
@ -1492,15 +1492,6 @@ version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "miniz_oxide"
|
|
||||||
version = "0.5.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34"
|
|
||||||
dependencies = [
|
|
||||||
"adler",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "miniz_oxide"
|
name = "miniz_oxide"
|
||||||
version = "0.6.2"
|
version = "0.6.2"
|
||||||
|
@ -1663,9 +1654,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "object"
|
name = "object"
|
||||||
version = "0.29.0"
|
version = "0.30.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53"
|
checksum = "239da7f290cfa979f43f85a8efeee9a8a76d0827c356d37f9d3d7254d6b537fb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
@ -1777,9 +1768,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "paste"
|
name = "paste"
|
||||||
version = "1.0.9"
|
version = "1.0.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1"
|
checksum = "cf1c2c742266c2f1041c914ba65355a83ae8747b05f208319784083583494b4b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pear"
|
name = "pear"
|
||||||
|
@ -2891,9 +2882,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml"
|
name = "toml"
|
||||||
version = "0.5.9"
|
version = "0.5.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7"
|
checksum = "1333c76748e868a4d9d1017b5ab53171dfd095f70c712fdb4653a406547f598f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
|
@ -44,7 +44,7 @@ log = "0.4.17"
|
||||||
fern = { version = "0.6.1", features = ["syslog-6"] }
|
fern = { version = "0.6.1", features = ["syslog-6"] }
|
||||||
tracing = { version = "0.1.37", features = ["log"] } # Needed to have lettre and webauthn-rs trace logging to work
|
tracing = { version = "0.1.37", features = ["log"] } # Needed to have lettre and webauthn-rs trace logging to work
|
||||||
|
|
||||||
backtrace = "0.3.66" # Logging panics to logfile instead stderr only
|
backtrace = "0.3.67" # Logging panics to logfile instead stderr only
|
||||||
|
|
||||||
# A `dotenv` implementation for Rust
|
# A `dotenv` implementation for Rust
|
||||||
dotenvy = { version = "0.15.6", default-features = false }
|
dotenvy = { version = "0.15.6", default-features = false }
|
||||||
|
@ -142,7 +142,7 @@ openssl = "0.10.44"
|
||||||
pico-args = "0.5.0"
|
pico-args = "0.5.0"
|
||||||
|
|
||||||
# Macro ident concatenation
|
# Macro ident concatenation
|
||||||
paste = "1.0.9"
|
paste = "1.0.10"
|
||||||
governor = "0.5.1"
|
governor = "0.5.1"
|
||||||
|
|
||||||
# Check client versions for specific features.
|
# Check client versions for specific features.
|
||||||
|
|
|
@ -3,23 +3,23 @@
|
||||||
# This file was generated using a Jinja2 template.
|
# This file was generated using a Jinja2 template.
|
||||||
# Please make your changes in `Dockerfile.j2` and then `make` the individual Dockerfiles.
|
# Please make your changes in `Dockerfile.j2` and then `make` the individual Dockerfiles.
|
||||||
|
|
||||||
{% set build_stage_base_image = "rust:1.65-bullseye" %}
|
{% set build_stage_base_image = "rust:1.66-bullseye" %}
|
||||||
{% if "alpine" in target_file %}
|
{% if "alpine" in target_file %}
|
||||||
{% if "amd64" in target_file %}
|
{% if "amd64" in target_file %}
|
||||||
{% set build_stage_base_image = "blackdex/rust-musl:x86_64-musl-stable-1.65.0" %}
|
{% set build_stage_base_image = "blackdex/rust-musl:x86_64-musl-stable-1.66.0" %}
|
||||||
{% set runtime_stage_base_image = "alpine:3.16" %}
|
{% set runtime_stage_base_image = "alpine:3.17" %}
|
||||||
{% set package_arch_target = "x86_64-unknown-linux-musl" %}
|
{% set package_arch_target = "x86_64-unknown-linux-musl" %}
|
||||||
{% elif "armv7" in target_file %}
|
{% elif "armv7" in target_file %}
|
||||||
{% set build_stage_base_image = "blackdex/rust-musl:armv7-musleabihf-stable-1.65.0" %}
|
{% set build_stage_base_image = "blackdex/rust-musl:armv7-musleabihf-stable-1.66.0" %}
|
||||||
{% set runtime_stage_base_image = "balenalib/armv7hf-alpine:3.16" %}
|
{% set runtime_stage_base_image = "balenalib/armv7hf-alpine:3.17" %}
|
||||||
{% set package_arch_target = "armv7-unknown-linux-musleabihf" %}
|
{% set package_arch_target = "armv7-unknown-linux-musleabihf" %}
|
||||||
{% elif "armv6" in target_file %}
|
{% elif "armv6" in target_file %}
|
||||||
{% set build_stage_base_image = "blackdex/rust-musl:arm-musleabi-stable-1.65.0" %}
|
{% set build_stage_base_image = "blackdex/rust-musl:arm-musleabi-stable-1.66.0" %}
|
||||||
{% set runtime_stage_base_image = "balenalib/rpi-alpine:3.16" %}
|
{% set runtime_stage_base_image = "balenalib/rpi-alpine:3.17" %}
|
||||||
{% set package_arch_target = "arm-unknown-linux-musleabi" %}
|
{% set package_arch_target = "arm-unknown-linux-musleabi" %}
|
||||||
{% elif "arm64" in target_file %}
|
{% elif "arm64" in target_file %}
|
||||||
{% set build_stage_base_image = "blackdex/rust-musl:aarch64-musl-stable-1.65.0" %}
|
{% set build_stage_base_image = "blackdex/rust-musl:aarch64-musl-stable-1.66.0" %}
|
||||||
{% set runtime_stage_base_image = "balenalib/aarch64-alpine:3.16" %}
|
{% set runtime_stage_base_image = "balenalib/aarch64-alpine:3.17" %}
|
||||||
{% set package_arch_target = "aarch64-unknown-linux-musl" %}
|
{% set package_arch_target = "aarch64-unknown-linux-musl" %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% elif "amd64" in target_file %}
|
{% elif "amd64" in target_file %}
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
FROM vaultwarden/web-vault@sha256:1f124e2d1a8e9678d7b9d17587b6340fba0db298e96995552698108a43f5c1c1 as vault
|
FROM vaultwarden/web-vault@sha256:1f124e2d1a8e9678d7b9d17587b6340fba0db298e96995552698108a43f5c1c1 as vault
|
||||||
|
|
||||||
########################## BUILD IMAGE ##########################
|
########################## BUILD IMAGE ##########################
|
||||||
FROM rust:1.65-bullseye as build
|
FROM rust:1.66-bullseye as build
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
FROM vaultwarden/web-vault@sha256:1f124e2d1a8e9678d7b9d17587b6340fba0db298e96995552698108a43f5c1c1 as vault
|
FROM vaultwarden/web-vault@sha256:1f124e2d1a8e9678d7b9d17587b6340fba0db298e96995552698108a43f5c1c1 as vault
|
||||||
|
|
||||||
########################## BUILD IMAGE ##########################
|
########################## BUILD IMAGE ##########################
|
||||||
FROM blackdex/rust-musl:x86_64-musl-stable-1.65.0 as build
|
FROM blackdex/rust-musl:x86_64-musl-stable-1.66.0 as build
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ RUN cargo build --features ${DB} --release --target=x86_64-unknown-linux-musl
|
||||||
######################## RUNTIME IMAGE ########################
|
######################## RUNTIME IMAGE ########################
|
||||||
# Create a new stage with a minimal image
|
# Create a new stage with a minimal image
|
||||||
# because we already have a binary built
|
# because we already have a binary built
|
||||||
FROM alpine:3.16
|
FROM alpine:3.17
|
||||||
|
|
||||||
ENV ROCKET_PROFILE="release" \
|
ENV ROCKET_PROFILE="release" \
|
||||||
ROCKET_ADDRESS=0.0.0.0 \
|
ROCKET_ADDRESS=0.0.0.0 \
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
FROM vaultwarden/web-vault@sha256:1f124e2d1a8e9678d7b9d17587b6340fba0db298e96995552698108a43f5c1c1 as vault
|
FROM vaultwarden/web-vault@sha256:1f124e2d1a8e9678d7b9d17587b6340fba0db298e96995552698108a43f5c1c1 as vault
|
||||||
|
|
||||||
########################## BUILD IMAGE ##########################
|
########################## BUILD IMAGE ##########################
|
||||||
FROM rust:1.65-bullseye as build
|
FROM rust:1.66-bullseye as build
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
FROM vaultwarden/web-vault@sha256:1f124e2d1a8e9678d7b9d17587b6340fba0db298e96995552698108a43f5c1c1 as vault
|
FROM vaultwarden/web-vault@sha256:1f124e2d1a8e9678d7b9d17587b6340fba0db298e96995552698108a43f5c1c1 as vault
|
||||||
|
|
||||||
########################## BUILD IMAGE ##########################
|
########################## BUILD IMAGE ##########################
|
||||||
FROM blackdex/rust-musl:x86_64-musl-stable-1.65.0 as build
|
FROM blackdex/rust-musl:x86_64-musl-stable-1.66.0 as build
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.
|
||||||
######################## RUNTIME IMAGE ########################
|
######################## RUNTIME IMAGE ########################
|
||||||
# Create a new stage with a minimal image
|
# Create a new stage with a minimal image
|
||||||
# because we already have a binary built
|
# because we already have a binary built
|
||||||
FROM alpine:3.16
|
FROM alpine:3.17
|
||||||
|
|
||||||
ENV ROCKET_PROFILE="release" \
|
ENV ROCKET_PROFILE="release" \
|
||||||
ROCKET_ADDRESS=0.0.0.0 \
|
ROCKET_ADDRESS=0.0.0.0 \
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
FROM vaultwarden/web-vault@sha256:1f124e2d1a8e9678d7b9d17587b6340fba0db298e96995552698108a43f5c1c1 as vault
|
FROM vaultwarden/web-vault@sha256:1f124e2d1a8e9678d7b9d17587b6340fba0db298e96995552698108a43f5c1c1 as vault
|
||||||
|
|
||||||
########################## BUILD IMAGE ##########################
|
########################## BUILD IMAGE ##########################
|
||||||
FROM rust:1.65-bullseye as build
|
FROM rust:1.66-bullseye as build
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
FROM vaultwarden/web-vault@sha256:1f124e2d1a8e9678d7b9d17587b6340fba0db298e96995552698108a43f5c1c1 as vault
|
FROM vaultwarden/web-vault@sha256:1f124e2d1a8e9678d7b9d17587b6340fba0db298e96995552698108a43f5c1c1 as vault
|
||||||
|
|
||||||
########################## BUILD IMAGE ##########################
|
########################## BUILD IMAGE ##########################
|
||||||
FROM blackdex/rust-musl:aarch64-musl-stable-1.65.0 as build
|
FROM blackdex/rust-musl:aarch64-musl-stable-1.66.0 as build
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ RUN cargo build --features ${DB} --release --target=aarch64-unknown-linux-musl
|
||||||
######################## RUNTIME IMAGE ########################
|
######################## RUNTIME IMAGE ########################
|
||||||
# Create a new stage with a minimal image
|
# Create a new stage with a minimal image
|
||||||
# because we already have a binary built
|
# because we already have a binary built
|
||||||
FROM balenalib/aarch64-alpine:3.16
|
FROM balenalib/aarch64-alpine:3.17
|
||||||
|
|
||||||
ENV ROCKET_PROFILE="release" \
|
ENV ROCKET_PROFILE="release" \
|
||||||
ROCKET_ADDRESS=0.0.0.0 \
|
ROCKET_ADDRESS=0.0.0.0 \
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
FROM vaultwarden/web-vault@sha256:1f124e2d1a8e9678d7b9d17587b6340fba0db298e96995552698108a43f5c1c1 as vault
|
FROM vaultwarden/web-vault@sha256:1f124e2d1a8e9678d7b9d17587b6340fba0db298e96995552698108a43f5c1c1 as vault
|
||||||
|
|
||||||
########################## BUILD IMAGE ##########################
|
########################## BUILD IMAGE ##########################
|
||||||
FROM rust:1.65-bullseye as build
|
FROM rust:1.66-bullseye as build
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
FROM vaultwarden/web-vault@sha256:1f124e2d1a8e9678d7b9d17587b6340fba0db298e96995552698108a43f5c1c1 as vault
|
FROM vaultwarden/web-vault@sha256:1f124e2d1a8e9678d7b9d17587b6340fba0db298e96995552698108a43f5c1c1 as vault
|
||||||
|
|
||||||
########################## BUILD IMAGE ##########################
|
########################## BUILD IMAGE ##########################
|
||||||
FROM blackdex/rust-musl:aarch64-musl-stable-1.65.0 as build
|
FROM blackdex/rust-musl:aarch64-musl-stable-1.66.0 as build
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.
|
||||||
######################## RUNTIME IMAGE ########################
|
######################## RUNTIME IMAGE ########################
|
||||||
# Create a new stage with a minimal image
|
# Create a new stage with a minimal image
|
||||||
# because we already have a binary built
|
# because we already have a binary built
|
||||||
FROM balenalib/aarch64-alpine:3.16
|
FROM balenalib/aarch64-alpine:3.17
|
||||||
|
|
||||||
ENV ROCKET_PROFILE="release" \
|
ENV ROCKET_PROFILE="release" \
|
||||||
ROCKET_ADDRESS=0.0.0.0 \
|
ROCKET_ADDRESS=0.0.0.0 \
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
FROM vaultwarden/web-vault@sha256:1f124e2d1a8e9678d7b9d17587b6340fba0db298e96995552698108a43f5c1c1 as vault
|
FROM vaultwarden/web-vault@sha256:1f124e2d1a8e9678d7b9d17587b6340fba0db298e96995552698108a43f5c1c1 as vault
|
||||||
|
|
||||||
########################## BUILD IMAGE ##########################
|
########################## BUILD IMAGE ##########################
|
||||||
FROM rust:1.65-bullseye as build
|
FROM rust:1.66-bullseye as build
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
FROM vaultwarden/web-vault@sha256:1f124e2d1a8e9678d7b9d17587b6340fba0db298e96995552698108a43f5c1c1 as vault
|
FROM vaultwarden/web-vault@sha256:1f124e2d1a8e9678d7b9d17587b6340fba0db298e96995552698108a43f5c1c1 as vault
|
||||||
|
|
||||||
########################## BUILD IMAGE ##########################
|
########################## BUILD IMAGE ##########################
|
||||||
FROM blackdex/rust-musl:arm-musleabi-stable-1.65.0 as build
|
FROM blackdex/rust-musl:arm-musleabi-stable-1.66.0 as build
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ RUN cargo build --features ${DB} --release --target=arm-unknown-linux-musleabi
|
||||||
######################## RUNTIME IMAGE ########################
|
######################## RUNTIME IMAGE ########################
|
||||||
# Create a new stage with a minimal image
|
# Create a new stage with a minimal image
|
||||||
# because we already have a binary built
|
# because we already have a binary built
|
||||||
FROM balenalib/rpi-alpine:3.16
|
FROM balenalib/rpi-alpine:3.17
|
||||||
|
|
||||||
ENV ROCKET_PROFILE="release" \
|
ENV ROCKET_PROFILE="release" \
|
||||||
ROCKET_ADDRESS=0.0.0.0 \
|
ROCKET_ADDRESS=0.0.0.0 \
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
FROM vaultwarden/web-vault@sha256:1f124e2d1a8e9678d7b9d17587b6340fba0db298e96995552698108a43f5c1c1 as vault
|
FROM vaultwarden/web-vault@sha256:1f124e2d1a8e9678d7b9d17587b6340fba0db298e96995552698108a43f5c1c1 as vault
|
||||||
|
|
||||||
########################## BUILD IMAGE ##########################
|
########################## BUILD IMAGE ##########################
|
||||||
FROM rust:1.65-bullseye as build
|
FROM rust:1.66-bullseye as build
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
FROM vaultwarden/web-vault@sha256:1f124e2d1a8e9678d7b9d17587b6340fba0db298e96995552698108a43f5c1c1 as vault
|
FROM vaultwarden/web-vault@sha256:1f124e2d1a8e9678d7b9d17587b6340fba0db298e96995552698108a43f5c1c1 as vault
|
||||||
|
|
||||||
########################## BUILD IMAGE ##########################
|
########################## BUILD IMAGE ##########################
|
||||||
FROM blackdex/rust-musl:arm-musleabi-stable-1.65.0 as build
|
FROM blackdex/rust-musl:arm-musleabi-stable-1.66.0 as build
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.
|
||||||
######################## RUNTIME IMAGE ########################
|
######################## RUNTIME IMAGE ########################
|
||||||
# Create a new stage with a minimal image
|
# Create a new stage with a minimal image
|
||||||
# because we already have a binary built
|
# because we already have a binary built
|
||||||
FROM balenalib/rpi-alpine:3.16
|
FROM balenalib/rpi-alpine:3.17
|
||||||
|
|
||||||
ENV ROCKET_PROFILE="release" \
|
ENV ROCKET_PROFILE="release" \
|
||||||
ROCKET_ADDRESS=0.0.0.0 \
|
ROCKET_ADDRESS=0.0.0.0 \
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
FROM vaultwarden/web-vault@sha256:1f124e2d1a8e9678d7b9d17587b6340fba0db298e96995552698108a43f5c1c1 as vault
|
FROM vaultwarden/web-vault@sha256:1f124e2d1a8e9678d7b9d17587b6340fba0db298e96995552698108a43f5c1c1 as vault
|
||||||
|
|
||||||
########################## BUILD IMAGE ##########################
|
########################## BUILD IMAGE ##########################
|
||||||
FROM rust:1.65-bullseye as build
|
FROM rust:1.66-bullseye as build
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
FROM vaultwarden/web-vault@sha256:1f124e2d1a8e9678d7b9d17587b6340fba0db298e96995552698108a43f5c1c1 as vault
|
FROM vaultwarden/web-vault@sha256:1f124e2d1a8e9678d7b9d17587b6340fba0db298e96995552698108a43f5c1c1 as vault
|
||||||
|
|
||||||
########################## BUILD IMAGE ##########################
|
########################## BUILD IMAGE ##########################
|
||||||
FROM blackdex/rust-musl:armv7-musleabihf-stable-1.65.0 as build
|
FROM blackdex/rust-musl:armv7-musleabihf-stable-1.66.0 as build
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ RUN cargo build --features ${DB} --release --target=armv7-unknown-linux-musleabi
|
||||||
######################## RUNTIME IMAGE ########################
|
######################## RUNTIME IMAGE ########################
|
||||||
# Create a new stage with a minimal image
|
# Create a new stage with a minimal image
|
||||||
# because we already have a binary built
|
# because we already have a binary built
|
||||||
FROM balenalib/armv7hf-alpine:3.16
|
FROM balenalib/armv7hf-alpine:3.17
|
||||||
|
|
||||||
ENV ROCKET_PROFILE="release" \
|
ENV ROCKET_PROFILE="release" \
|
||||||
ROCKET_ADDRESS=0.0.0.0 \
|
ROCKET_ADDRESS=0.0.0.0 \
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
FROM vaultwarden/web-vault@sha256:1f124e2d1a8e9678d7b9d17587b6340fba0db298e96995552698108a43f5c1c1 as vault
|
FROM vaultwarden/web-vault@sha256:1f124e2d1a8e9678d7b9d17587b6340fba0db298e96995552698108a43f5c1c1 as vault
|
||||||
|
|
||||||
########################## BUILD IMAGE ##########################
|
########################## BUILD IMAGE ##########################
|
||||||
FROM rust:1.65-bullseye as build
|
FROM rust:1.66-bullseye as build
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
FROM vaultwarden/web-vault@sha256:1f124e2d1a8e9678d7b9d17587b6340fba0db298e96995552698108a43f5c1c1 as vault
|
FROM vaultwarden/web-vault@sha256:1f124e2d1a8e9678d7b9d17587b6340fba0db298e96995552698108a43f5c1c1 as vault
|
||||||
|
|
||||||
########################## BUILD IMAGE ##########################
|
########################## BUILD IMAGE ##########################
|
||||||
FROM blackdex/rust-musl:armv7-musleabihf-stable-1.65.0 as build
|
FROM blackdex/rust-musl:armv7-musleabihf-stable-1.66.0 as build
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.
|
||||||
######################## RUNTIME IMAGE ########################
|
######################## RUNTIME IMAGE ########################
|
||||||
# Create a new stage with a minimal image
|
# Create a new stage with a minimal image
|
||||||
# because we already have a binary built
|
# because we already have a binary built
|
||||||
FROM balenalib/armv7hf-alpine:3.16
|
FROM balenalib/armv7hf-alpine:3.17
|
||||||
|
|
||||||
ENV ROCKET_PROFILE="release" \
|
ENV ROCKET_PROFILE="release" \
|
||||||
ROCKET_ADDRESS=0.0.0.0 \
|
ROCKET_ADDRESS=0.0.0.0 \
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
1.65.0
|
1.66.0
|
||||||
|
|
|
@ -1990,6 +1990,10 @@ async fn _restore_organization_user(
|
||||||
|
|
||||||
#[get("/organizations/<org_id>/groups")]
|
#[get("/organizations/<org_id>/groups")]
|
||||||
async fn get_groups(org_id: String, _headers: ManagerHeadersLoose, mut conn: DbConn) -> JsonResult {
|
async fn get_groups(org_id: String, _headers: ManagerHeadersLoose, mut conn: DbConn) -> JsonResult {
|
||||||
|
if !CONFIG.org_groups_enabled() {
|
||||||
|
err!("Group support is disabled");
|
||||||
|
}
|
||||||
|
|
||||||
let groups = Group::find_by_organization(&org_id, &mut conn).await.iter().map(Group::to_json).collect::<Value>();
|
let groups = Group::find_by_organization(&org_id, &mut conn).await.iter().map(Group::to_json).collect::<Value>();
|
||||||
|
|
||||||
Ok(Json(json!({
|
Ok(Json(json!({
|
||||||
|
@ -2089,6 +2093,10 @@ async fn post_groups(
|
||||||
mut conn: DbConn,
|
mut conn: DbConn,
|
||||||
ip: ClientIp,
|
ip: ClientIp,
|
||||||
) -> JsonResult {
|
) -> JsonResult {
|
||||||
|
if !CONFIG.org_groups_enabled() {
|
||||||
|
err!("Group support is disabled");
|
||||||
|
}
|
||||||
|
|
||||||
let group_request = data.into_inner().data;
|
let group_request = data.into_inner().data;
|
||||||
let group = group_request.to_group(&org_id)?;
|
let group = group_request.to_group(&org_id)?;
|
||||||
|
|
||||||
|
@ -2115,6 +2123,10 @@ async fn put_group(
|
||||||
mut conn: DbConn,
|
mut conn: DbConn,
|
||||||
ip: ClientIp,
|
ip: ClientIp,
|
||||||
) -> JsonResult {
|
) -> JsonResult {
|
||||||
|
if !CONFIG.org_groups_enabled() {
|
||||||
|
err!("Group support is disabled");
|
||||||
|
}
|
||||||
|
|
||||||
let group = match Group::find_by_uuid(&group_id, &mut conn).await {
|
let group = match Group::find_by_uuid(&group_id, &mut conn).await {
|
||||||
Some(group) => group,
|
Some(group) => group,
|
||||||
None => err!("Group not found"),
|
None => err!("Group not found"),
|
||||||
|
@ -2159,6 +2171,10 @@ async fn add_update_group(mut group: Group, collections: Vec<SelectionReadOnly>,
|
||||||
|
|
||||||
#[get("/organizations/<_org_id>/groups/<group_id>/details")]
|
#[get("/organizations/<_org_id>/groups/<group_id>/details")]
|
||||||
async fn get_group_details(_org_id: String, group_id: String, _headers: AdminHeaders, mut conn: DbConn) -> JsonResult {
|
async fn get_group_details(_org_id: String, group_id: String, _headers: AdminHeaders, mut conn: DbConn) -> JsonResult {
|
||||||
|
if !CONFIG.org_groups_enabled() {
|
||||||
|
err!("Group support is disabled");
|
||||||
|
}
|
||||||
|
|
||||||
let group = match Group::find_by_uuid(&group_id, &mut conn).await {
|
let group = match Group::find_by_uuid(&group_id, &mut conn).await {
|
||||||
Some(group) => group,
|
Some(group) => group,
|
||||||
_ => err!("Group could not be found!"),
|
_ => err!("Group could not be found!"),
|
||||||
|
@ -2199,6 +2215,10 @@ async fn delete_group(
|
||||||
mut conn: DbConn,
|
mut conn: DbConn,
|
||||||
ip: ClientIp,
|
ip: ClientIp,
|
||||||
) -> EmptyResult {
|
) -> EmptyResult {
|
||||||
|
if !CONFIG.org_groups_enabled() {
|
||||||
|
err!("Group support is disabled");
|
||||||
|
}
|
||||||
|
|
||||||
let group = match Group::find_by_uuid(&group_id, &mut conn).await {
|
let group = match Group::find_by_uuid(&group_id, &mut conn).await {
|
||||||
Some(group) => group,
|
Some(group) => group,
|
||||||
_ => err!("Group not found"),
|
_ => err!("Group not found"),
|
||||||
|
@ -2220,6 +2240,10 @@ async fn delete_group(
|
||||||
|
|
||||||
#[get("/organizations/<_org_id>/groups/<group_id>")]
|
#[get("/organizations/<_org_id>/groups/<group_id>")]
|
||||||
async fn get_group(_org_id: String, group_id: String, _headers: AdminHeaders, mut conn: DbConn) -> JsonResult {
|
async fn get_group(_org_id: String, group_id: String, _headers: AdminHeaders, mut conn: DbConn) -> JsonResult {
|
||||||
|
if !CONFIG.org_groups_enabled() {
|
||||||
|
err!("Group support is disabled");
|
||||||
|
}
|
||||||
|
|
||||||
let group = match Group::find_by_uuid(&group_id, &mut conn).await {
|
let group = match Group::find_by_uuid(&group_id, &mut conn).await {
|
||||||
Some(group) => group,
|
Some(group) => group,
|
||||||
_ => err!("Group not found"),
|
_ => err!("Group not found"),
|
||||||
|
@ -2230,6 +2254,10 @@ async fn get_group(_org_id: String, group_id: String, _headers: AdminHeaders, mu
|
||||||
|
|
||||||
#[get("/organizations/<_org_id>/groups/<group_id>/users")]
|
#[get("/organizations/<_org_id>/groups/<group_id>/users")]
|
||||||
async fn get_group_users(_org_id: String, group_id: String, _headers: AdminHeaders, mut conn: DbConn) -> JsonResult {
|
async fn get_group_users(_org_id: String, group_id: String, _headers: AdminHeaders, mut conn: DbConn) -> JsonResult {
|
||||||
|
if !CONFIG.org_groups_enabled() {
|
||||||
|
err!("Group support is disabled");
|
||||||
|
}
|
||||||
|
|
||||||
match Group::find_by_uuid(&group_id, &mut conn).await {
|
match Group::find_by_uuid(&group_id, &mut conn).await {
|
||||||
Some(_) => { /* Do nothing */ }
|
Some(_) => { /* Do nothing */ }
|
||||||
_ => err!("Group could not be found!"),
|
_ => err!("Group could not be found!"),
|
||||||
|
@ -2253,6 +2281,10 @@ async fn put_group_users(
|
||||||
mut conn: DbConn,
|
mut conn: DbConn,
|
||||||
ip: ClientIp,
|
ip: ClientIp,
|
||||||
) -> EmptyResult {
|
) -> EmptyResult {
|
||||||
|
if !CONFIG.org_groups_enabled() {
|
||||||
|
err!("Group support is disabled");
|
||||||
|
}
|
||||||
|
|
||||||
match Group::find_by_uuid(&group_id, &mut conn).await {
|
match Group::find_by_uuid(&group_id, &mut conn).await {
|
||||||
Some(_) => { /* Do nothing */ }
|
Some(_) => { /* Do nothing */ }
|
||||||
_ => err!("Group could not be found!"),
|
_ => err!("Group could not be found!"),
|
||||||
|
@ -2282,6 +2314,10 @@ async fn put_group_users(
|
||||||
|
|
||||||
#[get("/organizations/<_org_id>/users/<user_id>/groups")]
|
#[get("/organizations/<_org_id>/users/<user_id>/groups")]
|
||||||
async fn get_user_groups(_org_id: String, user_id: String, _headers: AdminHeaders, mut conn: DbConn) -> JsonResult {
|
async fn get_user_groups(_org_id: String, user_id: String, _headers: AdminHeaders, mut conn: DbConn) -> JsonResult {
|
||||||
|
if !CONFIG.org_groups_enabled() {
|
||||||
|
err!("Group support is disabled");
|
||||||
|
}
|
||||||
|
|
||||||
match UserOrganization::find_by_uuid(&user_id, &mut conn).await {
|
match UserOrganization::find_by_uuid(&user_id, &mut conn).await {
|
||||||
Some(_) => { /* Do nothing */ }
|
Some(_) => { /* Do nothing */ }
|
||||||
_ => err!("User could not be found!"),
|
_ => err!("User could not be found!"),
|
||||||
|
@ -2320,6 +2356,10 @@ async fn put_user_groups(
|
||||||
mut conn: DbConn,
|
mut conn: DbConn,
|
||||||
ip: ClientIp,
|
ip: ClientIp,
|
||||||
) -> EmptyResult {
|
) -> EmptyResult {
|
||||||
|
if !CONFIG.org_groups_enabled() {
|
||||||
|
err!("Group support is disabled");
|
||||||
|
}
|
||||||
|
|
||||||
match UserOrganization::find_by_uuid(&org_user_id, &mut conn).await {
|
match UserOrganization::find_by_uuid(&org_user_id, &mut conn).await {
|
||||||
Some(_) => { /* Do nothing */ }
|
Some(_) => { /* Do nothing */ }
|
||||||
_ => err!("User could not be found!"),
|
_ => err!("User could not be found!"),
|
||||||
|
@ -2368,6 +2408,10 @@ async fn delete_group_user(
|
||||||
mut conn: DbConn,
|
mut conn: DbConn,
|
||||||
ip: ClientIp,
|
ip: ClientIp,
|
||||||
) -> EmptyResult {
|
) -> EmptyResult {
|
||||||
|
if !CONFIG.org_groups_enabled() {
|
||||||
|
err!("Group support is disabled");
|
||||||
|
}
|
||||||
|
|
||||||
match UserOrganization::find_by_uuid(&org_user_id, &mut conn).await {
|
match UserOrganization::find_by_uuid(&org_user_id, &mut conn).await {
|
||||||
Some(_) => { /* Do nothing */ }
|
Some(_) => { /* Do nothing */ }
|
||||||
_ => err!("User could not be found!"),
|
_ => err!("User could not be found!"),
|
||||||
|
|
|
@ -107,8 +107,8 @@ pub fn static_files(filename: String) -> Result<(ContentType, &'static [u8]), Er
|
||||||
"jdenticon.js" => Ok((ContentType::JavaScript, include_bytes!("../static/scripts/jdenticon.js"))),
|
"jdenticon.js" => Ok((ContentType::JavaScript, include_bytes!("../static/scripts/jdenticon.js"))),
|
||||||
"datatables.js" => Ok((ContentType::JavaScript, include_bytes!("../static/scripts/datatables.js"))),
|
"datatables.js" => Ok((ContentType::JavaScript, include_bytes!("../static/scripts/datatables.js"))),
|
||||||
"datatables.css" => Ok((ContentType::CSS, include_bytes!("../static/scripts/datatables.css"))),
|
"datatables.css" => Ok((ContentType::CSS, include_bytes!("../static/scripts/datatables.css"))),
|
||||||
"jquery-3.6.1.slim.js" => {
|
"jquery-3.6.2.slim.js" => {
|
||||||
Ok((ContentType::JavaScript, include_bytes!("../static/scripts/jquery-3.6.1.slim.js")))
|
Ok((ContentType::JavaScript, include_bytes!("../static/scripts/jquery-3.6.2.slim.js")))
|
||||||
}
|
}
|
||||||
_ => err!(format!("Static file not found: {}", filename)),
|
_ => err!(format!("Static file not found: {}", filename)),
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,7 +85,7 @@ macro_rules! make_config {
|
||||||
|
|
||||||
let mut builder = ConfigBuilder::default();
|
let mut builder = ConfigBuilder::default();
|
||||||
$($(
|
$($(
|
||||||
builder.$name = make_config! { @getenv &stringify!($name).to_uppercase(), $ty };
|
builder.$name = make_config! { @getenv paste::paste!(stringify!([<$name:upper>])), $ty };
|
||||||
)+)+
|
)+)+
|
||||||
|
|
||||||
builder
|
builder
|
||||||
|
@ -105,7 +105,7 @@ macro_rules! make_config {
|
||||||
builder.$name = v.clone();
|
builder.$name = v.clone();
|
||||||
|
|
||||||
if self.$name.is_some() {
|
if self.$name.is_some() {
|
||||||
overrides.push(stringify!($name).to_uppercase());
|
overrides.push(paste::paste!(stringify!([<$name:upper>])).into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)+)+
|
)+)+
|
||||||
|
@ -195,7 +195,7 @@ macro_rules! make_config {
|
||||||
element.insert("default".into(), serde_json::to_value(def.$name).unwrap());
|
element.insert("default".into(), serde_json::to_value(def.$name).unwrap());
|
||||||
element.insert("type".into(), (_get_form_type(stringify!($ty))).into());
|
element.insert("type".into(), (_get_form_type(stringify!($ty))).into());
|
||||||
element.insert("doc".into(), (_get_doc(concat!($($doc),+))).into());
|
element.insert("doc".into(), (_get_doc(concat!($($doc),+))).into());
|
||||||
element.insert("overridden".into(), (overriden.contains(&stringify!($name).to_uppercase())).into());
|
element.insert("overridden".into(), (overriden.contains(&paste::paste!(stringify!([<$name:upper>])).into())).into());
|
||||||
element
|
element
|
||||||
}),
|
}),
|
||||||
)+
|
)+
|
||||||
|
@ -564,6 +564,9 @@ make_config! {
|
||||||
admin_ratelimit_seconds: u64, false, def, 300;
|
admin_ratelimit_seconds: u64, false, def, 300;
|
||||||
/// Max burst size for admin login requests |> Allow a burst of requests of up to this size, while maintaining the average indicated by `admin_ratelimit_seconds`
|
/// Max burst size for admin login requests |> Allow a burst of requests of up to this size, while maintaining the average indicated by `admin_ratelimit_seconds`
|
||||||
admin_ratelimit_max_burst: u32, false, def, 3;
|
admin_ratelimit_max_burst: u32, false, def, 3;
|
||||||
|
|
||||||
|
/// Enable groups (BETA!) (Know the risks!) |> Enables groups support for organizations (Currently contains known issues!).
|
||||||
|
org_groups_enabled: bool, false, def, false;
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Yubikey settings
|
/// Yubikey settings
|
||||||
|
|
|
@ -149,7 +149,7 @@ impl Organization {
|
||||||
"Use2fa": true,
|
"Use2fa": true,
|
||||||
"UseDirectory": false, // Is supported, but this value isn't checked anywhere (yet)
|
"UseDirectory": false, // Is supported, but this value isn't checked anywhere (yet)
|
||||||
"UseEvents": CONFIG.org_events_enabled(),
|
"UseEvents": CONFIG.org_events_enabled(),
|
||||||
"UseGroups": true,
|
"UseGroups": CONFIG.org_groups_enabled(),
|
||||||
"UseTotp": true,
|
"UseTotp": true,
|
||||||
"UsePolicies": true,
|
"UsePolicies": true,
|
||||||
// "UseScim": false, // Not supported (Not AGPLv3 Licensed)
|
// "UseScim": false, // Not supported (Not AGPLv3 Licensed)
|
||||||
|
@ -304,7 +304,7 @@ impl UserOrganization {
|
||||||
"Use2fa": true,
|
"Use2fa": true,
|
||||||
"UseDirectory": false, // Is supported, but this value isn't checked anywhere (yet)
|
"UseDirectory": false, // Is supported, but this value isn't checked anywhere (yet)
|
||||||
"UseEvents": CONFIG.org_events_enabled(),
|
"UseEvents": CONFIG.org_events_enabled(),
|
||||||
"UseGroups": true,
|
"UseGroups": CONFIG.org_groups_enabled(),
|
||||||
"UseTotp": true,
|
"UseTotp": true,
|
||||||
// "UseScim": false, // Not supported (Not AGPLv3 Licensed)
|
// "UseScim": false, // Not supported (Not AGPLv3 Licensed)
|
||||||
"UsePolicies": true,
|
"UsePolicies": true,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*!
|
/*!
|
||||||
* jQuery JavaScript Library v3.6.1 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/Tween,-effects/animatedSelector
|
* jQuery JavaScript Library v3.6.2 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/Tween,-effects/animatedSelector
|
||||||
* https://jquery.com/
|
* https://jquery.com/
|
||||||
*
|
*
|
||||||
* Includes Sizzle.js
|
* Includes Sizzle.js
|
||||||
|
@ -9,7 +9,7 @@
|
||||||
* Released under the MIT license
|
* Released under the MIT license
|
||||||
* https://jquery.org/license
|
* https://jquery.org/license
|
||||||
*
|
*
|
||||||
* Date: 2022-08-26T17:52Z
|
* Date: 2022-12-13T14:56Z
|
||||||
*/
|
*/
|
||||||
( function( global, factory ) {
|
( function( global, factory ) {
|
||||||
|
|
||||||
|
@ -151,7 +151,7 @@ function toType( obj ) {
|
||||||
|
|
||||||
|
|
||||||
var
|
var
|
||||||
version = "3.6.1 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/Tween,-effects/animatedSelector",
|
version = "3.6.2 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/Tween,-effects/animatedSelector",
|
||||||
|
|
||||||
// Define a local copy of jQuery
|
// Define a local copy of jQuery
|
||||||
jQuery = function( selector, context ) {
|
jQuery = function( selector, context ) {
|
||||||
|
@ -522,14 +522,14 @@ function isArrayLike( obj ) {
|
||||||
}
|
}
|
||||||
var Sizzle =
|
var Sizzle =
|
||||||
/*!
|
/*!
|
||||||
* Sizzle CSS Selector Engine v2.3.6
|
* Sizzle CSS Selector Engine v2.3.8
|
||||||
* https://sizzlejs.com/
|
* https://sizzlejs.com/
|
||||||
*
|
*
|
||||||
* Copyright JS Foundation and other contributors
|
* Copyright JS Foundation and other contributors
|
||||||
* Released under the MIT license
|
* Released under the MIT license
|
||||||
* https://js.foundation/
|
* https://js.foundation/
|
||||||
*
|
*
|
||||||
* Date: 2021-02-16
|
* Date: 2022-11-16
|
||||||
*/
|
*/
|
||||||
( function( window ) {
|
( function( window ) {
|
||||||
var i,
|
var i,
|
||||||
|
@ -879,6 +879,27 @@ function Sizzle( selector, context, results, seed ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
// `qSA` may not throw for unrecognized parts using forgiving parsing:
|
||||||
|
// https://drafts.csswg.org/selectors/#forgiving-selector
|
||||||
|
// like the `:has()` pseudo-class:
|
||||||
|
// https://drafts.csswg.org/selectors/#relational
|
||||||
|
// `CSS.supports` is still expected to return `false` then:
|
||||||
|
// https://drafts.csswg.org/css-conditional-4/#typedef-supports-selector-fn
|
||||||
|
// https://drafts.csswg.org/css-conditional-4/#dfn-support-selector
|
||||||
|
if ( support.cssSupportsSelector &&
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
!CSS.supports( "selector(" + newSelector + ")" ) ) {
|
||||||
|
|
||||||
|
// Support: IE 11+
|
||||||
|
// Throw to get to the same code path as an error directly in qSA.
|
||||||
|
// Note: once we only support browser supporting
|
||||||
|
// `CSS.supports('selector(...)')`, we can most likely drop
|
||||||
|
// the `try-catch`. IE doesn't implement the API.
|
||||||
|
throw new Error();
|
||||||
|
}
|
||||||
|
|
||||||
push.apply( results,
|
push.apply( results,
|
||||||
newContext.querySelectorAll( newSelector )
|
newContext.querySelectorAll( newSelector )
|
||||||
);
|
);
|
||||||
|
@ -1174,6 +1195,31 @@ setDocument = Sizzle.setDocument = function( node ) {
|
||||||
!el.querySelectorAll( ":scope fieldset div" ).length;
|
!el.querySelectorAll( ":scope fieldset div" ).length;
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
// Support: Chrome 105+, Firefox 104+, Safari 15.4+
|
||||||
|
// Make sure forgiving mode is not used in `CSS.supports( "selector(...)" )`.
|
||||||
|
//
|
||||||
|
// `:is()` uses a forgiving selector list as an argument and is widely
|
||||||
|
// implemented, so it's a good one to test against.
|
||||||
|
support.cssSupportsSelector = assert( function() {
|
||||||
|
/* eslint-disable no-undef */
|
||||||
|
|
||||||
|
return CSS.supports( "selector(*)" ) &&
|
||||||
|
|
||||||
|
// Support: Firefox 78-81 only
|
||||||
|
// In old Firefox, `:is()` didn't use forgiving parsing. In that case,
|
||||||
|
// fail this test as there's no selector to test against that.
|
||||||
|
// `CSS.supports` uses unforgiving parsing
|
||||||
|
document.querySelectorAll( ":is(:jqfake)" ) &&
|
||||||
|
|
||||||
|
// `*` is needed as Safari & newer Chrome implemented something in between
|
||||||
|
// for `:has()` - it throws in `qSA` if it only contains an unsupported
|
||||||
|
// argument but multiple ones, one of which is supported, are fine.
|
||||||
|
// We want to play safe in case `:is()` gets the same treatment.
|
||||||
|
!CSS.supports( "selector(:is(*,:jqfake))" );
|
||||||
|
|
||||||
|
/* eslint-enable */
|
||||||
|
} );
|
||||||
|
|
||||||
/* Attributes
|
/* Attributes
|
||||||
---------------------------------------------------------------------- */
|
---------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
@ -1440,6 +1486,18 @@ setDocument = Sizzle.setDocument = function( node ) {
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( !support.cssSupportsSelector ) {
|
||||||
|
|
||||||
|
// Support: Chrome 105+, Safari 15.4+
|
||||||
|
// `:has()` uses a forgiving selector list as an argument so our regular
|
||||||
|
// `try-catch` mechanism fails to catch `:has()` with arguments not supported
|
||||||
|
// natively like `:has(:contains("Foo"))`. Where supported & spec-compliant,
|
||||||
|
// we now use `CSS.supports("selector(SELECTOR_TO_BE_TESTED)")` but outside
|
||||||
|
// that, let's mark `:has` as buggy to always use jQuery traversal for
|
||||||
|
// `:has()`.
|
||||||
|
rbuggyQSA.push( ":has" );
|
||||||
|
}
|
||||||
|
|
||||||
rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) );
|
rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) );
|
||||||
rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( "|" ) );
|
rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( "|" ) );
|
||||||
|
|
||||||
|
@ -1452,7 +1510,14 @@ setDocument = Sizzle.setDocument = function( node ) {
|
||||||
// As in, an element does not contain itself
|
// As in, an element does not contain itself
|
||||||
contains = hasCompare || rnative.test( docElem.contains ) ?
|
contains = hasCompare || rnative.test( docElem.contains ) ?
|
||||||
function( a, b ) {
|
function( a, b ) {
|
||||||
var adown = a.nodeType === 9 ? a.documentElement : a,
|
|
||||||
|
// Support: IE <9 only
|
||||||
|
// IE doesn't have `contains` on `document` so we need to check for
|
||||||
|
// `documentElement` presence.
|
||||||
|
// We need to fall back to `a` when `documentElement` is missing
|
||||||
|
// as `ownerDocument` of elements within `<template/>` may have
|
||||||
|
// a null one - a default behavior of all modern browsers.
|
||||||
|
var adown = a.nodeType === 9 && a.documentElement || a,
|
||||||
bup = b && b.parentNode;
|
bup = b && b.parentNode;
|
||||||
return a === bup || !!( bup && bup.nodeType === 1 && (
|
return a === bup || !!( bup && bup.nodeType === 1 && (
|
||||||
adown.contains ?
|
adown.contains ?
|
||||||
|
@ -2242,7 +2307,7 @@ Expr = Sizzle.selectors = {
|
||||||
return elem.nodeName.toLowerCase() === "input" &&
|
return elem.nodeName.toLowerCase() === "input" &&
|
||||||
elem.type === "text" &&
|
elem.type === "text" &&
|
||||||
|
|
||||||
// Support: IE<8
|
// Support: IE <10 only
|
||||||
// New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
|
// New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
|
||||||
( ( attr = elem.getAttribute( "type" ) ) == null ||
|
( ( attr = elem.getAttribute( "type" ) ) == null ||
|
||||||
attr.toLowerCase() === "text" );
|
attr.toLowerCase() === "text" );
|
||||||
|
@ -6608,17 +6673,37 @@ function curCSS( elem, name, computed ) {
|
||||||
// .css('filter') (IE 9 only, trac-12537)
|
// .css('filter') (IE 9 only, trac-12537)
|
||||||
// .css('--customProperty) (gh-3144)
|
// .css('--customProperty) (gh-3144)
|
||||||
if ( computed ) {
|
if ( computed ) {
|
||||||
|
|
||||||
|
// Support: IE <=9 - 11+
|
||||||
|
// IE only supports `"float"` in `getPropertyValue`; in computed styles
|
||||||
|
// it's only available as `"cssFloat"`. We no longer modify properties
|
||||||
|
// sent to `.css()` apart from camelCasing, so we need to check both.
|
||||||
|
// Normally, this would create difference in behavior: if
|
||||||
|
// `getPropertyValue` returns an empty string, the value returned
|
||||||
|
// by `.css()` would be `undefined`. This is usually the case for
|
||||||
|
// disconnected elements. However, in IE even disconnected elements
|
||||||
|
// with no styles return `"none"` for `getPropertyValue( "float" )`
|
||||||
ret = computed.getPropertyValue( name ) || computed[ name ];
|
ret = computed.getPropertyValue( name ) || computed[ name ];
|
||||||
|
|
||||||
// trim whitespace for custom property (issue gh-4926)
|
if ( isCustomProp && ret ) {
|
||||||
if ( isCustomProp ) {
|
|
||||||
|
|
||||||
// rtrim treats U+000D CARRIAGE RETURN and U+000C FORM FEED
|
// Support: Firefox 105+, Chrome <=105+
|
||||||
|
// Spec requires trimming whitespace for custom properties (gh-4926).
|
||||||
|
// Firefox only trims leading whitespace. Chrome just collapses
|
||||||
|
// both leading & trailing whitespace to a single space.
|
||||||
|
//
|
||||||
|
// Fall back to `undefined` if empty string returned.
|
||||||
|
// This collapses a missing definition with property defined
|
||||||
|
// and set to an empty string but there's no standard API
|
||||||
|
// allowing us to differentiate them without a performance penalty
|
||||||
|
// and returning `undefined` aligns with older jQuery.
|
||||||
|
//
|
||||||
|
// rtrimCSS treats U+000D CARRIAGE RETURN and U+000C FORM FEED
|
||||||
// as whitespace while CSS does not, but this is not a problem
|
// as whitespace while CSS does not, but this is not a problem
|
||||||
// because CSS preprocessing replaces them with U+000A LINE FEED
|
// because CSS preprocessing replaces them with U+000A LINE FEED
|
||||||
// (which *is* CSS whitespace)
|
// (which *is* CSS whitespace)
|
||||||
// https://www.w3.org/TR/css-syntax-3/#input-preprocessing
|
// https://www.w3.org/TR/css-syntax-3/#input-preprocessing
|
||||||
ret = ret.replace( rtrimCSS, "$1" );
|
ret = ret.replace( rtrimCSS, "$1" ) || undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ret === "" && !isAttached( elem ) ) {
|
if ( ret === "" && !isAttached( elem ) ) {
|
|
@ -28,7 +28,6 @@
|
||||||
border: var(--bs-alert-border);
|
border: var(--bs-alert-border);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<script src="{{urlpath}}/vw_static/jdenticon.js"></script>
|
|
||||||
<script>
|
<script>
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
@ -141,6 +140,7 @@
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
<script src="{{urlpath}}/vw_static/jdenticon.js"></script>
|
||||||
<script src="{{urlpath}}/vw_static/bootstrap-native.js"></script>
|
<script src="{{urlpath}}/vw_static/bootstrap-native.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
<small>Please provide it below:</small>
|
<small>Please provide it below:</small>
|
||||||
|
|
||||||
<form class="form-inline" method="post" action="{{urlpath}}/admin">
|
<form class="form-inline" method="post" action="{{urlpath}}/admin">
|
||||||
<input type="password" class="form-control w-50 mr-2" name="token" placeholder="Enter admin token" autofocus="autofocus">
|
<input type="password" autocomplete="password" class="form-control w-50 mr-2" name="token" placeholder="Enter admin token" autofocus="autofocus">
|
||||||
{{#if redirect}}
|
{{#if redirect}}
|
||||||
<input type="hidden" id="redirect" name="redirect" value="/{{redirect}}">
|
<input type="hidden" id="redirect" name="redirect" value="/{{redirect}}">
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
|
@ -49,7 +49,7 @@
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<link rel="stylesheet" href="{{urlpath}}/vw_static/datatables.css" />
|
<link rel="stylesheet" href="{{urlpath}}/vw_static/datatables.css" />
|
||||||
<script src="{{urlpath}}/vw_static/jquery-3.6.1.slim.js"></script>
|
<script src="{{urlpath}}/vw_static/jquery-3.6.2.slim.js"></script>
|
||||||
<script src="{{urlpath}}/vw_static/datatables.js"></script>
|
<script src="{{urlpath}}/vw_static/datatables.js"></script>
|
||||||
<script>
|
<script>
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
|
@ -136,7 +136,7 @@
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<link rel="stylesheet" href="{{urlpath}}/vw_static/datatables.css" />
|
<link rel="stylesheet" href="{{urlpath}}/vw_static/datatables.css" />
|
||||||
<script src="{{urlpath}}/vw_static/jquery-3.6.1.slim.js"></script>
|
<script src="{{urlpath}}/vw_static/jquery-3.6.2.slim.js"></script>
|
||||||
<script src="{{urlpath}}/vw_static/datatables.js"></script>
|
<script src="{{urlpath}}/vw_static/datatables.js"></script>
|
||||||
<script>
|
<script>
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
|
@ -63,6 +63,8 @@ impl Fairing for AppHeaders {
|
||||||
// app.simplelogin.io, app.anonaddy.com, api.fastmail.com, quack.duckduckgo.com
|
// app.simplelogin.io, app.anonaddy.com, api.fastmail.com, quack.duckduckgo.com
|
||||||
let csp = format!(
|
let csp = format!(
|
||||||
"default-src 'self'; \
|
"default-src 'self'; \
|
||||||
|
base-uri 'self'; \
|
||||||
|
form-action 'self'; \
|
||||||
object-src 'self' blob:; \
|
object-src 'self' blob:; \
|
||||||
script-src 'self'{script_src}; \
|
script-src 'self'{script_src}; \
|
||||||
style-src 'self' 'unsafe-inline'; \
|
style-src 'self' 'unsafe-inline'; \
|
||||||
|
@ -74,12 +76,12 @@ impl Fairing for AppHeaders {
|
||||||
moz-extension://* \
|
moz-extension://* \
|
||||||
{allowed_iframe_ancestors}; \
|
{allowed_iframe_ancestors}; \
|
||||||
img-src 'self' data: \
|
img-src 'self' data: \
|
||||||
https://haveibeenpwned.com/ \
|
https://haveibeenpwned.com \
|
||||||
https://www.gravatar.com \
|
https://www.gravatar.com \
|
||||||
{icon_service_csp}; \
|
{icon_service_csp}; \
|
||||||
connect-src 'self' \
|
connect-src 'self' \
|
||||||
https://api.pwnedpasswords.com/range/ \
|
https://api.pwnedpasswords.com \
|
||||||
https://2fa.directory/api/ \
|
https://2fa.directory \
|
||||||
https://app.simplelogin.io/api/ \
|
https://app.simplelogin.io/api/ \
|
||||||
https://app.anonaddy.com/api/ \
|
https://app.anonaddy.com/api/ \
|
||||||
https://api.fastmail.com/ \
|
https://api.fastmail.com/ \
|
||||||
|
|
Loading…
Reference in a new issue