Watch
1
0
Fork
You've already forked vaultwarden
0
mirror of https://github.com/dani-garcia/vaultwarden.git synced 2026-11-09 23:59:17 -05:00

Compare commits

..
Author SHA1 Message Date
Daniel García
f312e00dfa
Test dylint 2024-11-09 17:31:22 +01:00
272 changed files with 38493 additions and 45171 deletions

View file

@ -1,11 +1,10 @@
# Ignore everything // Ignore everything
* *
# Allow what is needed // Allow what is needed
!.git !.git
!docker/healthcheck.sh !docker/healthcheck.sh
!docker/start.sh !docker/start.sh
!macros
!migrations !migrations
!src !src

View file

@ -15,14 +15,6 @@
#################### ####################
## Main data folder ## Main data folder
## This can be a path to local folder or a path to an external location
## depending on features enabled at build time. Possible external locations:
##
## - AWS S3 Bucket (via `s3` feature): s3://bucket-name/path/to/folder
##
## When using an external location, make sure to set TMP_FOLDER,
## TEMPLATES_FOLDER, and DATABASE_URL to local paths and/or a remote database
## location.
# DATA_FOLDER=data # DATA_FOLDER=data
## Individual folders, these override %DATA_FOLDER% ## Individual folders, these override %DATA_FOLDER%
@ -30,13 +22,10 @@
# ICON_CACHE_FOLDER=data/icon_cache # ICON_CACHE_FOLDER=data/icon_cache
# ATTACHMENTS_FOLDER=data/attachments # ATTACHMENTS_FOLDER=data/attachments
# SENDS_FOLDER=data/sends # SENDS_FOLDER=data/sends
## Temporary folder used for storing temporary file uploads
## Must be a local path.
# TMP_FOLDER=data/tmp # TMP_FOLDER=data/tmp
## HTML template overrides data folder ## Templates data folder, by default uses embedded templates
## Must be a local path. ## Check source code to see the format
# TEMPLATES_FOLDER=data/templates # TEMPLATES_FOLDER=data/templates
## Automatically reload the templates for every request, slow, use only for development ## Automatically reload the templates for every request, slow, use only for development
# RELOAD_TEMPLATES=false # RELOAD_TEMPLATES=false
@ -50,11 +39,8 @@
######################### #########################
## Database URL ## Database URL
## When using SQLite, this should use the sqlite:// scheme followed by the path ## When using SQLite, this is the path to the DB file, default to %DATA_FOLDER%/db.sqlite3
## to the DB file. It defaults to sqlite://%DATA_FOLDER%/db.sqlite3. # DATABASE_URL=data/db.sqlite3
## Bare paths without the sqlite:// scheme are supported for backwards compatibility,
## but only if the database file already exists.
# DATABASE_URL=sqlite://data/db.sqlite3
## When using MySQL, specify an appropriate connection URI. ## When using MySQL, specify an appropriate connection URI.
## Details: https://docs.diesel.rs/2.1.x/diesel/mysql/struct.MysqlConnection.html ## Details: https://docs.diesel.rs/2.1.x/diesel/mysql/struct.MysqlConnection.html
# DATABASE_URL=mysql://user:password@host[:port]/database_name # DATABASE_URL=mysql://user:password@host[:port]/database_name
@ -78,19 +64,11 @@
# DB_CONNECTION_RETRIES=15 # DB_CONNECTION_RETRIES=15
## Database timeout ## Database timeout
## Timeout in seconds when acquiring database connection ## Timeout when acquiring database connection
# DATABASE_TIMEOUT=30 # DATABASE_TIMEOUT=30
## Database idle timeout
## Timeout in seconds before idle connections to the database are closed.
# DATABASE_IDLE_TIMEOUT=600
## Database min connections
## Define the minimum size of the connection pool used for connecting to the database.
# DATABASE_MIN_CONNS=2
## Database max connections ## Database max connections
## Define the maximum size of the connection pool used for connecting to the database. ## Define the size of the connection pool used for connecting to the database.
# DATABASE_MAX_CONNS=10 # DATABASE_MAX_CONNS=10
## Database connection initialization ## Database connection initialization
@ -139,7 +117,7 @@
## and are always in terms of UTC time (regardless of your local time zone settings). ## and are always in terms of UTC time (regardless of your local time zone settings).
## ##
## The schedule format is a bit different from crontab as crontab does not contains seconds. ## The schedule format is a bit different from crontab as crontab does not contains seconds.
## You can test the format here: https://crontab.guru, but remove the first digit! ## You can test the the format here: https://crontab.guru, but remove the first digit!
## SEC MIN HOUR DAY OF MONTH MONTH DAY OF WEEK ## SEC MIN HOUR DAY OF MONTH MONTH DAY OF WEEK
## "0 30 9,12,15 1,15 May-Aug Mon,Wed,Fri" ## "0 30 9,12,15 1,15 May-Aug Mon,Wed,Fri"
## "0 30 * * * * " ## "0 30 * * * * "
@ -173,20 +151,16 @@
## Defaults to daily. Set blank to disable this job. Also without EVENTS_DAYS_RETAIN set, this job will not start. ## Defaults to daily. Set blank to disable this job. Also without EVENTS_DAYS_RETAIN set, this job will not start.
# EVENT_CLEANUP_SCHEDULE="0 10 0 * * *" # EVENT_CLEANUP_SCHEDULE="0 10 0 * * *"
## Number of days to retain events stored in the database. ## Number of days to retain events stored in the database.
## If unset (the default) or 0, 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=
## ##
## Cron schedule of the job that cleans old auth requests from the auth request. ## Cron schedule of the job that cleans old auth requests from the auth request.
## Defaults to every minute. Set blank to disable this job. ## Defaults to every minute. Set blank to disable this job.
# AUTH_REQUEST_PURGE_SCHEDULE="30 * * * * *" # AUTH_REQUEST_PURGE_SCHEDULE="30 * * * * *"
## ##
## Cron schedule of the job that cleans expired Duo contexts from the database. Does nothing if Duo MFA is disabled. ## Cron schedule of the job that cleans expired Duo contexts from the database. Does nothing if Duo MFA is disabled or set to use the legacy iframe prompt.
## Defaults to every minute. Set blank to disable this job. ## Defaults to every minute. Set blank to disable this job.
# DUO_CONTEXT_PURGE_SCHEDULE="30 * * * * *" # DUO_CONTEXT_PURGE_SCHEDULE="30 * * * * *"
#
## Cron schedule of the job that cleans sso auth from incomplete flow
## Defaults to daily (20 minutes after midnight). Set blank to disable this job.
# PURGE_INCOMPLETE_SSO_AUTH="0 20 0 * * *"
######################## ########################
### General settings ### ### General settings ###
@ -233,7 +207,7 @@
# USER_SEND_LIMIT= # USER_SEND_LIMIT=
## Number of days to wait before auto-deleting a trashed item. ## Number of days to wait before auto-deleting a trashed item.
## If unset (the default) or 0, trashed items are not auto-deleted. ## If unset (the default), trashed items are not auto-deleted.
## This setting applies globally, so make sure to inform all users of any changes to this setting. ## This setting applies globally, so make sure to inform all users of any changes to this setting.
# TRASH_AUTO_DELETE_DAYS= # TRASH_AUTO_DELETE_DAYS=
@ -255,8 +229,7 @@
# SIGNUPS_ALLOWED=true # SIGNUPS_ALLOWED=true
## Controls if new users need to verify their email address upon registration ## Controls if new users need to verify their email address upon registration
## On new client versions, this will require the user to verify their email at signup time. ## Note that setting this option to true prevents logins until the email address has been verified!
## On older clients, it will require the user to verify their email before they can log in.
## The welcome email will include a verification link, and login attempts will periodically ## The welcome email will include a verification link, and login attempts will periodically
## trigger another verification email to be sent. ## trigger another verification email to be sent.
# SIGNUPS_VERIFY=false # SIGNUPS_VERIFY=false
@ -286,7 +259,7 @@
## A comma-separated list means only those users can create orgs: ## A comma-separated list means only those users can create orgs:
# ORG_CREATION_USERS=admin1@example.com,admin2@example.com # ORG_CREATION_USERS=admin1@example.com,admin2@example.com
## Allows org admins to invite users, even when signups are disabled ## Invitations org admins to invite users, even when signups are disabled
# INVITATIONS_ALLOWED=true # INVITATIONS_ALLOWED=true
## Name shown in the invitation emails that don't come from a specific organization ## Name shown in the invitation emails that don't come from a specific organization
# INVITATION_ORG_NAME=Vaultwarden # INVITATION_ORG_NAME=Vaultwarden
@ -307,23 +280,14 @@
## The default for new users. If changed, it will be updated during login for existing users. ## The default for new users. If changed, it will be updated during login for existing users.
# PASSWORD_ITERATIONS=600000 # PASSWORD_ITERATIONS=600000
## Controls whether users can set or show password hints. This setting applies globally to all users. ## Controls whether users can set password hints. This setting applies globally to all users.
# PASSWORD_HINTS_ALLOWED=true # PASSWORD_HINTS_ALLOWED=true
## Controls whether a password hint should be shown directly in the web page if ## Controls whether a password hint should be shown directly in the web page if
## SMTP service is not configured and password hints are allowed. ## SMTP service is not configured. Not recommended for publicly-accessible instances
## Not recommended for publicly-accessible instances because this provides ## as this provides unauthenticated access to potentially sensitive data.
## unauthenticated access to potentially sensitive data.
# SHOW_PASSWORD_HINT=false # SHOW_PASSWORD_HINT=false
#########################
### Client settings ###
#########################
## Control whether clients onboarding interstitials are suppressed
## (post-login welcome dialogs, extension install prompts, setup extension redirects, and premium upsell modals)
# CLIENT_SUPPRESS_ONBOARDING=false
######################### #########################
### Advanced settings ### ### Advanced settings ###
######################### #########################
@ -332,16 +296,6 @@
## Set to the string "none" (without quotes), to disable any headers and just use the remote IP ## Set to the string "none" (without quotes), to disable any headers and just use the remote IP
# IP_HEADER=X-Real-IP # IP_HEADER=X-Real-IP
## Which addresses the header above is accepted from, defaults to "local".
## Anyone able to reach Vaultwarden can set the header, and the client IP is used for the login and
## admin rate limits, so it is only trusted when the request comes from a proxy listed here.
## "local" accepts it from any non global address, which covers a reverse proxy running on the same
## host or container network. Use "all" to accept it from anywhere, or list the addresses of your
## proxy as IPs and CIDR ranges if it connects from a public address.
## For a list header like X-Forwarded-For, the client IP is the rightmost address that isn't one of
## these proxies, so with several proxies in a row (a CDN in front of nginx, for example) list all of them.
# IP_HEADER_TRUSTED_PROXIES=local
## Icon service ## Icon service
## The predefined icon services are: internal, bitwarden, duckduckgo, google. ## The predefined icon services are: internal, bitwarden, duckduckgo, google.
## To specify a custom icon service, set a URL template with exactly one instance of `{}`, ## To specify a custom icon service, set a URL template with exactly one instance of `{}`,
@ -367,51 +321,35 @@
## Default: 2592000 (30 days) ## Default: 2592000 (30 days)
# ICON_CACHE_TTL=2592000 # ICON_CACHE_TTL=2592000
## Cache time-to-live for icons which weren't available, in seconds (0 is "forever") ## Cache time-to-live for icons which weren't available, in seconds (0 is "forever")
## Default: 259200 (3 days) ## Default: 2592000 (3 days)
# ICON_CACHE_NEGTTL=259200 # ICON_CACHE_NEGTTL=259200
## Icon download timeout ## Icon download timeout
## Configure the timeout value when downloading the favicons. ## Configure the timeout value when downloading the favicons.
## The default is 10 seconds, but this could be too low on slower network connections ## The default is 10 seconds, but this could be to low on slower network connections
# ICON_DOWNLOAD_TIMEOUT=10 # ICON_DOWNLOAD_TIMEOUT=10
## Block HTTP domains/IPs by Regex ## Block HTTP domains/IPs by Regex
## Any domains or IPs that match this regex won't be fetched by the internal HTTP client. ## Any domains or IPs that match this regex won't be fetched by the internal HTTP client.
## Useful to hide other servers in the local network. Check the WIKI for more details ## Useful to hide other servers in the local network. Check the WIKI for more details
## NOTE: Always enclose this regex within single quotes! ## NOTE: Always enclose this regex withing single quotes!
# HTTP_REQUEST_BLOCK_REGEX='^(192\.168\.0\.[0-9]+|192\.168\.1\.[0-9]+)$' # HTTP_REQUEST_BLOCK_REGEX='^(192\.168\.0\.[0-9]+|192\.168\.1\.[0-9]+)$'
## Enabling this will cause the internal HTTP client to refuse to connect to any non-global IP address. ## Enabling this will cause the internal HTTP client to refuse to connect to any non global IP address.
## Useful to secure your internal environment: See https://en.wikipedia.org/wiki/Reserved_IP_addresses for a list of IPs which it will block ## Useful to secure your internal environment: See https://en.wikipedia.org/wiki/Reserved_IP_addresses for a list of IPs which it will block
# HTTP_REQUEST_BLOCK_NON_GLOBAL_IPS=true # HTTP_REQUEST_BLOCK_NON_GLOBAL_IPS=true
## Client Settings ## Client Settings
## Server-wide Fill Assist rules feed base directory URL, not a JSON file.
## Defaults to https://fillassist.bitwarden.com.
## Must be a valid HTTPS URL without credentials, query parameters, fragments, or surrounding whitespace.
# FILL_ASSIST_RULES_URL=https://fillassist.bitwarden.com
## Enable experimental feature flags for clients. ## Enable experimental feature flags for clients.
## This is a comma-separated list of flags, e.g. "flag1,flag2,flag3". ## This is a comma-separated list of flags, e.g. "flag1,flag2,flag3".
## Note that clients cache the /api/config endpoint for about 1 hour and it could take some time before they are enabled or disabled!
## ##
## The following flags are available: ## The following flags are available:
## - "fill-assist-targeting-rules": Enable Fill Assist targeting rules in the browser extension. (Browser >= 2026.6.0) ## - "autofill-overlay": Add an overlay menu to form fields for quick access to credentials.
## - "pm-5594-safari-account-switching": Enable account switching in Safari. (Safari >= 2026.2.0) ## - "autofill-v2": Use the new autofill implementation.
## - "pm-32413-multi-client-password-management": Enable changing the master password directly in the client. (Desktop/Extension >= 2026.4.0) ## - "browser-fileless-import": Directly import credentials from other providers without a file.
## - "ssh-agent-v2": Enable newer SSH agent support. (Desktop >= 2026.2.1) ## - "extension-refresh": Temporarily enable the new extension design until general availability (should be used with the beta Chrome extension)
## - "windows-desktop-autotype": Enable the autotype feature preview on Windows. (Desktop >= 2025.8.0) ## - "fido2-vault-credentials": Enable the use of FIDO2 security keys as second factor.
## - "windows-desktop-autotype-ga": Enable the new, still in development, autotype implementation on Windows. (Desktop >= 2026.9.1) # EXPERIMENTAL_CLIENT_FEATURE_FLAGS=fido2-vault-credentials
## Only enable one of the two autotype flags, the clients disable autotype completely when both are enabled.
## - "pm-30529-webauthn-related-origins": Allow passkeys stored in the vault to be used on related origins listed in a site's /.well-known/webauthn file (Browser >= 2026.2.0)
## - "pm-32009-new-item-types": Enable new item types: Bank Account, Driver's License, and Passport (Clients >= 2026.4.0)
## - "pm-34171-card-scanner": Enable the new card scanner feature on mobile (Android >= 2026.4.1, iOS >= 2026.4.1)
## - "enable-basic-auth-response": Enable HTTP Basic Auth autofill in the browser extension (Browser >= 2026.9.0)
## - "undetermined-cipher-scenario-logic": Enable the rewritten add/update login notification triggering logic in the browser extension (Browser >= 2026.2.0)
## - "biometrics-sdk-ipc": Enable biometric unlock over the SDK IPC framework (Desktop >= 2026.9.0, Browser >= 2026.9.0)
## - "windows-native-credential-sync": Register the desktop app as a passkey provider in Windows, so passkeys in the vault can be used by other apps and browsers.
## Requires the Microsoft Store (appx) build of the desktop app. Stable releases up to and including 2026.9.1 lack the required plugin registration, so it has no effect there yet.
# EXPERIMENTAL_CLIENT_FEATURE_FLAGS=
## Require new device emails. When a user logs in an email is required to be sent. ## Require new device emails. When a user logs in an email is required to be sent.
## If sending the email fails the login attempt will fail!! ## If sending the email fails the login attempt will fail!!
@ -469,27 +407,12 @@
## Multiple values must be separated with a whitespace. ## Multiple values must be separated with a whitespace.
# ALLOWED_IFRAME_ANCESTORS= # ALLOWED_IFRAME_ANCESTORS=
## Allowed connect-src (Know the risks!)
## https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/connect-src
## Allows other domains for URLs which can be loaded using script interfaces like the Forwarded email alias feature
## This adds the configured value to the 'Content-Security-Policy' headers 'connect-src' value.
## Multiple values must be separated with a whitespace. And only HTTPS values are allowed.
## Example: "https://my-addy-io.domain.tld https://my-simplelogin.domain.tld"
# ALLOWED_CONNECT_SRC=""
## Number of seconds, on average, between login requests from the same IP address before rate limiting kicks in. ## Number of seconds, on average, between login requests from the same IP address before rate limiting kicks in.
# LOGIN_RATELIMIT_SECONDS=60 # LOGIN_RATELIMIT_SECONDS=60
## Allow a burst of requests of up to this size, while maintaining the average indicated by `LOGIN_RATELIMIT_SECONDS`. ## Allow a burst of requests of up to this size, while maintaining the average indicated by `LOGIN_RATELIMIT_SECONDS`.
## Note that this applies to both the login and the 2FA, so it's recommended to allow a burst size of at least 2. ## Note that this applies to both the login and the 2FA, so it's recommended to allow a burst size of at least 2.
# LOGIN_RATELIMIT_MAX_BURST=10 # LOGIN_RATELIMIT_MAX_BURST=10
## Number of seconds, on average, between requests from the same IP address to one of the rate limited
## unauthenticated endpoints, like the password hint, the account recovery mails or accessing a Send.
# UNAUTHENTICATED_RATELIMIT_SECONDS=60
## Allow a burst of requests of up to this size, while maintaining the average indicated by `UNAUTHENTICATED_RATELIMIT_SECONDS`.
## This budget is shared between all of those endpoints, so it is more lenient than the login one.
# UNAUTHENTICATED_RATELIMIT_MAX_BURST=50
## BETA FEATURE: Groups ## BETA FEATURE: Groups
## Controls whether group support is enabled for organizations ## Controls whether group support is enabled for organizations
## This setting applies to organizations. ## This setting applies to organizations.
@ -497,15 +420,6 @@
## KNOW WHAT YOU ARE DOING! ## KNOW WHAT YOU ARE DOING!
# ORG_GROUPS_ENABLED=false # ORG_GROUPS_ENABLED=false
## EXPERIMENTAL FEATURE: Custom roles
## Enables the Custom member role with granular permissions for organizations.
## This is still being developed: only the permissions this version enforces can be granted.
## This is enforced by the server and is unrelated to EXPERIMENTAL_CLIENT_FEATURE_FLAGS.
## Disabling it again keeps the stored Custom roles and permissions, but they grant nothing until it is re-enabled.
## Disabled by default because this is an experimental feature!
## KNOW WHAT YOU ARE DOING!
# EXPERIMENTAL_CUSTOM_ROLES=false
## Increase secure note size limit (Know the risks!) ## Increase secure note size limit (Know the risks!)
## Sets the secure note size limit to 100_000 instead of the default 10_000. ## Sets the secure note size limit to 100_000 instead of the default 10_000.
## WARNING: This could cause issues with clients. Also exports will not work on Bitwarden servers! ## WARNING: This could cause issues with clients. Also exports will not work on Bitwarden servers!
@ -518,63 +432,6 @@
## Setting this to true will enforce the Single Org Policy to be enabled before you can enable the Reset Password policy. ## Setting this to true will enforce the Single Org Policy to be enabled before you can enable the Reset Password policy.
# ENFORCE_SINGLE_ORG_WITH_RESET_PW_POLICY=false # ENFORCE_SINGLE_ORG_WITH_RESET_PW_POLICY=false
## Prefer IPv6 (AAAA) resolving
## This settings configures the DNS resolver to resolve IPv6 first, and if not available try IPv4
## This could be useful in IPv6 only environments.
# DNS_PREFER_IPV6=false
#####################################
### SSO settings (OpenID Connect) ###
#####################################
## Controls whether users can login using an OpenID Connect identity provider
# SSO_ENABLED=false
## Prevent users from logging in directly without going through SSO
# SSO_ONLY=false
## Allow SSO flow to create account. You probably want to disable it when using a public provider.
# SSO_SIGNUPS_ALLOWED=true
## On SSO Signup if a user with a matching email already exists make the association
# SSO_SIGNUPS_MATCH_EMAIL=true
## Allow unknown email verification status. Allowing this with `SSO_SIGNUPS_MATCH_EMAIL=true` open potential account takeover.
# SSO_ALLOW_UNKNOWN_EMAIL_VERIFICATION=false
## Base URL of the OIDC server (auto-discovery is used)
## - Should not include the `/.well-known/openid-configuration` part and no trailing `/`
## - ${SSO_AUTHORITY}/.well-known/openid-configuration should return a json document: https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationResponse
# SSO_AUTHORITY=https://auth.example.com
## Authorization request scopes. Optional SSO scopes, override if email and profile are not enough (`openid` is implicit).
# SSO_SCOPES="email profile"
## Additional authorization url parameters (ex: to obtain a `refresh_token` with Google Auth).
# SSO_AUTHORIZE_EXTRA_PARAMS="access_type=offline&prompt=consent"
## Activate PKCE for the Auth Code flow.
# SSO_PKCE=true
## Regex for additional trusted Id token audience (by default only the client_id is trusted).
# SSO_AUDIENCE_TRUSTED='^$'
## Set your Client ID and Client Key
# SSO_CLIENT_ID=11111
# SSO_CLIENT_SECRET=AAAAAAAAAAAAAAAAAAAAAAAA
## Optional Master password policy (minComplexity=[0-4]), `enforceOnLogin` is not supported at the moment.
# SSO_MASTER_PASSWORD_POLICY='{"enforceOnLogin":false,"minComplexity":3,"minLength":12,"requireLower":false,"requireNumbers":false,"requireSpecial":false,"requireUpper":false}'
## Use sso only for authentication not the session lifecycle
# SSO_AUTH_ONLY_NOT_SESSION=false
## Client cache for discovery endpoint. Duration in seconds (0 to disable).
# SSO_CLIENT_CACHE_EXPIRATION=0
## Log all the tokens, LOG_LEVEL=debug is required
# SSO_DEBUG_TOKENS=false
######################## ########################
### MFA/2FA settings ### ### MFA/2FA settings ###
######################## ########################
@ -598,6 +455,11 @@
# DUO_HOST=<API Hostname> # DUO_HOST=<API Hostname>
## After that, you should be able to follow the rest of the guide linked above, ## After that, you should be able to follow the rest of the guide linked above,
## ignoring the fields that ask for the values that you already configured beforehand. ## ignoring the fields that ask for the values that you already configured beforehand.
##
## If you want to attempt to use Duo's 'Traditional Prompt' (deprecated, iframe based) set DUO_USE_IFRAME to 'true'.
## Duo no longer supports this, but it still works for some integrations.
## If you aren't sure, leave this alone.
# DUO_USE_IFRAME=false
## Email 2FA settings ## Email 2FA settings
## Email token size ## Email token size
@ -612,7 +474,7 @@
## Maximum attempts before an email token is reset and a new email will need to be sent. ## Maximum attempts before an email token is reset and a new email will need to be sent.
# EMAIL_ATTEMPTS_LIMIT=3 # EMAIL_ATTEMPTS_LIMIT=3
## ##
## Setup email 2FA on registration regardless of any organization policy ## Setup email 2FA regardless of any organization policy
# EMAIL_2FA_ENFORCE_ON_VERIFIED_INVITE=false # EMAIL_2FA_ENFORCE_ON_VERIFIED_INVITE=false
## Automatically setup email 2FA as fallback provider when needed ## Automatically setup email 2FA as fallback provider when needed
# EMAIL_2FA_AUTO_FALLBACK=false # EMAIL_2FA_AUTO_FALLBACK=false
@ -623,18 +485,15 @@
## Note that the checkbox would still be present, but ignored. ## Note that the checkbox would still be present, but ignored.
# DISABLE_2FA_REMEMBER=false # DISABLE_2FA_REMEMBER=false
## ##
## Number of days before a remembered 2FA login expires (min: 1, max: 90).
# TWO_FACTOR_REMEMBER_DAYS=30
##
## Authenticator Settings ## Authenticator Settings
## Disable authenticator time drifted codes to be valid. ## Disable authenticator time drifted codes to be valid.
## TOTP codes of the previous and next 30 seconds will be invalid ## TOTP codes of the previous and next 30 seconds will be invalid
## ##
## According to the RFC6238 (https://tools.ietf.org/html/rfc6238), ## According to the RFC6238 (https://tools.ietf.org/html/rfc6238),
## we allow by default the TOTP code which was valid one step back and one in the future. ## we allow by default the TOTP code which was valid one step back and one in the future.
## This can however allow attackers to be a bit more lucky with their attempts because there are 3 valid codes. ## This can however allow attackers to be a bit more lucky with there attempts because there are 3 valid codes.
## You can disable this, so that only the current TOTP Code is allowed. ## You can disable this, so that only the current TOTP Code is allowed.
## Keep in mind that when a server drifts out of time, valid codes could be marked as invalid. ## Keep in mind that when a sever drifts out of time, valid codes could be marked as invalid.
## In any case, if a code has been used it can not be used again, also codes which predates it will be invalid. ## In any case, if a code has been used it can not be used again, also codes which predates it will be invalid.
# AUTHENTICATOR_DISABLE_TIME_DRIFT=false # AUTHENTICATOR_DISABLE_TIME_DRIFT=false
@ -672,7 +531,7 @@
# SMTP_AUTH_MECHANISM= # SMTP_AUTH_MECHANISM=
## Server name sent during the SMTP HELO ## Server name sent during the SMTP HELO
## By default this value should be the machine's hostname, ## By default this value should be is on the machine's hostname,
## but might need to be changed in case it trips some anti-spam filters ## but might need to be changed in case it trips some anti-spam filters
# HELO_NAME= # HELO_NAME=

1
.gitattributes vendored
View file

@ -1,2 +1,3 @@
# Ignore vendored scripts in GitHub stats # Ignore vendored scripts in GitHub stats
src/static/scripts/* linguist-vendored src/static/scripts/* linguist-vendored

3
.github/CODEOWNERS vendored
View file

@ -1,6 +1,3 @@
/.github @dani-garcia @BlackDex /.github @dani-garcia @BlackDex
/.github/** @dani-garcia @BlackDex
/.github/CODEOWNERS @dani-garcia @BlackDex /.github/CODEOWNERS @dani-garcia @BlackDex
/.github/ISSUE_TEMPLATE/** @dani-garcia @BlackDex
/.github/workflows/** @dani-garcia @BlackDex /.github/workflows/** @dani-garcia @BlackDex
/SECURITY.md @dani-garcia @BlackDex

View file

@ -8,30 +8,15 @@ body:
value: | value: |
Thanks for taking the time to fill out this bug report! Thanks for taking the time to fill out this bug report!
Please **do not** submit feature requests or ask for help on how to configure Vaultwarden here! Please *do not* submit feature requests or ask for help on how to configure Vaultwarden here.
The [GitHub Discussions](https://github.com/dani-garcia/vaultwarden/discussions/) has sections for Questions and Ideas. The [GitHub Discussions](https://github.com/dani-garcia/vaultwarden/discussions/) has sections for Questions and Ideas.
Our [Wiki](https://github.com/dani-garcia/vaultwarden/wiki/) has topics on how to configure Vaultwarden.
Also, make sure you are running [![GitHub Release](https://img.shields.io/github/release/dani-garcia/vaultwarden.svg)](https://github.com/dani-garcia/vaultwarden/releases/latest) of Vaultwarden! Also, make sure you are running [![GitHub Release](https://img.shields.io/github/release/dani-garcia/vaultwarden.svg)](https://github.com/dani-garcia/vaultwarden/releases/latest) of Vaultwarden!
And search for existing open or closed issues or discussions regarding your topic before posting.
Be sure to check and validate the Vaultwarden Admin Diagnostics (`/admin/diagnostics`) page for any errors! Be sure to check and validate the Vaultwarden Admin Diagnostics (`/admin/diagnostics`) page for any errors!
See here [how to enable the admin page](https://github.com/dani-garcia/vaultwarden/wiki/Enabling-admin-page). See here [how to enable the admin page](https://github.com/dani-garcia/vaultwarden/wiki/Enabling-admin-page).
> [!IMPORTANT]
> ## :bangbang: Search for existing **Closed _AND_ Open** [Issues](https://github.com/dani-garcia/vaultwarden/issues?q=is%3Aissue%20) **_AND_** [Discussions](https://github.com/dani-garcia/vaultwarden/discussions?discussions_q=) regarding your topic before posting! :bangbang:
#
- type: checkboxes
id: checklist
attributes:
label: Prerequisites
description: Please confirm you have completed the following before submitting an issue!
options:
- label: I have searched the existing **Closed _AND_ Open** [Issues](https://github.com/dani-garcia/vaultwarden/issues?q=is%3Aissue%20) **_AND_** [Discussions](https://github.com/dani-garcia/vaultwarden/discussions?discussions_q=)
required: true
- label: I have searched and read the [documentation](https://github.com/dani-garcia/vaultwarden/wiki/)
required: true
# #
- id: support-string - id: support-string
type: textarea type: textarea
@ -51,7 +36,7 @@ body:
attributes: attributes:
label: Vaultwarden Build Version label: Vaultwarden Build Version
description: What version of Vaultwarden are you running? description: What version of Vaultwarden are you running?
placeholder: ex. v1.34.0 or v1.34.1-53f58b14 placeholder: ex. v1.31.0 or v1.32.0-3466a804
validations: validations:
required: true required: true
# #
@ -82,7 +67,7 @@ body:
attributes: attributes:
label: Reverse Proxy label: Reverse Proxy
description: Are you using a reverse proxy, if so which and what version? description: Are you using a reverse proxy, if so which and what version?
placeholder: ex. nginx 1.29.0, caddy 2.10.0, traefik 3.4.4, haproxy 3.2 placeholder: ex. nginx 1.26.2, caddy 2.8.4, traefik 3.1.2, haproxy 3.0
validations: validations:
required: true required: true
# #
@ -130,7 +115,7 @@ body:
attributes: attributes:
label: Client Version label: Client Version
description: What version(s) of the client(s) are you seeing the problem on? description: What version(s) of the client(s) are you seeing the problem on?
placeholder: ex. CLI v2025.7.0, Firefox 140 - v2025.6.1 placeholder: ex. CLI v2024.7.2, Firefox 130 - v2024.7.0
# #
- id: reproduce - id: reproduce
type: textarea type: textarea

View file

@ -1,9 +1,4 @@
name: Build name: Build
permissions: {}
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
on: on:
push: push:
@ -18,8 +13,6 @@ on:
- "diesel.toml" - "diesel.toml"
- "docker/Dockerfile.j2" - "docker/Dockerfile.j2"
- "docker/DockerSettings.yaml" - "docker/DockerSettings.yaml"
- "macros/**"
pull_request: pull_request:
paths: paths:
- ".github/workflows/build.yml" - ".github/workflows/build.yml"
@ -32,21 +25,16 @@ on:
- "diesel.toml" - "diesel.toml"
- "docker/Dockerfile.j2" - "docker/Dockerfile.j2"
- "docker/DockerSettings.yaml" - "docker/DockerSettings.yaml"
- "macros/**"
defaults:
run:
shell: bash
jobs: jobs:
build: build:
name: Build and Test ${{ matrix.channel }} # We use Ubuntu 22.04 here because this matches the library versions used within the Debian docker containers
runs-on: ubuntu-24.04 runs-on: ubuntu-22.04
timeout-minutes: 120 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:
RUSTFLAGS: "-Dwarnings" RUSTFLAGS: "-D warnings"
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@ -54,55 +42,62 @@ jobs:
- "rust-toolchain" # The version defined in rust-toolchain - "rust-toolchain" # The version defined in rust-toolchain
- "msrv" # The supported MSRV - "msrv" # The supported MSRV
name: Build and Test ${{ matrix.channel }}
steps: steps:
# Checkout the repo
- name: "Checkout"
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 #v4.2.1
# End Checkout the repo
# Install dependencies # Install dependencies
- name: "Install dependencies Ubuntu" - name: "Install dependencies Ubuntu"
run: sudo apt-get update && sudo apt-get install -y --no-install-recommends openssl build-essential libmariadb-dev-compat libpq-dev libssl-dev pkg-config run: sudo apt-get update && sudo apt-get install -y --no-install-recommends openssl build-essential libmariadb-dev-compat libpq-dev libssl-dev pkg-config
# End Install dependencies # End Install dependencies
# Checkout the repo
- name: "Checkout"
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
fetch-depth: 0
# End Checkout the repo
# Determine rust-toolchain version # Determine rust-toolchain version
- name: Init Variables - name: Init Variables
id: toolchain id: toolchain
env: shell: bash
CHANNEL: ${{ matrix.channel }}
run: | run: |
if [[ "${CHANNEL}" == 'rust-toolchain' ]]; then if [[ "${{ matrix.channel }}" == 'rust-toolchain' ]]; then
RUST_TOOLCHAIN="$(grep -m1 -oP 'channel.*"(\K.*?)(?=")' rust-toolchain.toml)" RUST_TOOLCHAIN="$(grep -oP 'channel.*"(\K.*?)(?=")' rust-toolchain.toml)"
elif [[ "${CHANNEL}" == 'msrv' ]]; then elif [[ "${{ matrix.channel }}" == 'msrv' ]]; then
RUST_TOOLCHAIN="$(grep -m1 -oP 'rust-version\s.*"(\K.*?)(?=")' Cargo.toml)" RUST_TOOLCHAIN="$(grep -oP 'rust-version.*"(\K.*?)(?=")' Cargo.toml)"
else else
RUST_TOOLCHAIN="${CHANNEL}" RUST_TOOLCHAIN="${{ matrix.channel }}"
fi fi
echo "RUST_TOOLCHAIN=${RUST_TOOLCHAIN}" | tee -a "${GITHUB_OUTPUT}" echo "RUST_TOOLCHAIN=${RUST_TOOLCHAIN}" | tee -a "${GITHUB_OUTPUT}"
# End Determine rust-toolchain version # End Determine rust-toolchain version
- name: "Install toolchain ${{steps.toolchain.outputs.RUST_TOOLCHAIN}} as default" # Only install the clippy and rustfmt components on the default rust-toolchain
env: - name: "Install rust-toolchain version"
CHANNEL: ${{ matrix.channel }} uses: dtolnay/rust-toolchain@7b1c307e0dcbda6122208f10795a713336a9b35a # master @ Aug 8, 2024, 7:36 PM GMT+2
RUST_TOOLCHAIN: ${{steps.toolchain.outputs.RUST_TOOLCHAIN}} if: ${{ matrix.channel == 'rust-toolchain' }}
with:
toolchain: "${{steps.toolchain.outputs.RUST_TOOLCHAIN}}"
components: clippy, rustfmt
# End Uses the rust-toolchain file to determine version
# Install the any other channel to be used for which we do not execute clippy and rustfmt
- name: "Install MSRV version"
uses: dtolnay/rust-toolchain@7b1c307e0dcbda6122208f10795a713336a9b35a # master @ Aug 8, 2024, 7:36 PM GMT+2
if: ${{ matrix.channel != 'rust-toolchain' }}
with:
toolchain: "${{steps.toolchain.outputs.RUST_TOOLCHAIN}}"
# End Install the MSRV channel to be used
# Set the current matrix toolchain version as default
- name: "Set toolchain ${{steps.toolchain.outputs.RUST_TOOLCHAIN}} as default"
run: | run: |
# Remove the rust-toolchain.toml # Remove the rust-toolchain.toml
rm rust-toolchain.toml rm rust-toolchain.toml
# Set the default
# Install the correct toolchain version rustup default ${{steps.toolchain.outputs.RUST_TOOLCHAIN}}
rustup toolchain install "${RUST_TOOLCHAIN}" --profile minimal --no-self-update
# If this matrix is the `rust-toolchain` flow, also install rustfmt and clippy
if [[ "${CHANNEL}" == 'rust-toolchain' ]]; then
rustup component add --toolchain "${RUST_TOOLCHAIN}" rustfmt clippy
fi
# Set as the default toolchain
rustup default "${RUST_TOOLCHAIN}"
# Show environment # Show environment
- name: "Show environment" - name: "Show environment"
@ -112,68 +107,61 @@ jobs:
# End Show environment # End Show environment
# Enable Rust Caching # Enable Rust Caching
- name: Rust Caching - uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3
uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2.9.3
with: with:
# Use a custom prefix-key to force a fresh start. This is sometimes needed with bigger changes. # Use a custom prefix-key to force a fresh start. This is sometimes needed with bigger changes.
# Like changing the build host from Ubuntu 20.04 to 22.04 for example. # Like changing the build host from Ubuntu 20.04 to 22.04 for example.
# Only update when really needed! Use a <year>.<month>[.<inc>] format. # Only update when really needed! Use a <year>.<month>[.<inc>] format.
prefix-key: "v2025.09-rust" prefix-key: "v2023.07-rust"
# End Enable Rust Caching # End Enable Rust Caching
# Run cargo tests # Run cargo tests
# First test all features together, afterwards test them separately. # First test all features together, afterwards test them separately.
- name: "test features: sqlite,mysql,postgresql,enable_mimalloc,s3"
id: test_sqlite_mysql_postgresql_mimalloc_s3
if: ${{ !cancelled() }}
run: |
cargo test --profile ci --features sqlite,mysql,postgresql,enable_mimalloc,s3
- name: "test features: sqlite,mysql,postgresql,enable_mimalloc" - name: "test features: sqlite,mysql,postgresql,enable_mimalloc"
id: test_sqlite_mysql_postgresql_mimalloc id: test_sqlite_mysql_postgresql_mimalloc
if: ${{ !cancelled() }} if: $${{ always() }}
run: | run: |
cargo test --profile ci --features sqlite,mysql,postgresql,enable_mimalloc cargo test --features sqlite,mysql,postgresql,enable_mimalloc
- name: "test features: sqlite,mysql,postgresql" - name: "test features: sqlite,mysql,postgresql"
id: test_sqlite_mysql_postgresql id: test_sqlite_mysql_postgresql
if: ${{ !cancelled() }} if: $${{ always() }}
run: | run: |
cargo test --profile ci --features sqlite,mysql,postgresql cargo test --features sqlite,mysql,postgresql
- name: "test features: sqlite" - name: "test features: sqlite"
id: test_sqlite id: test_sqlite
if: ${{ !cancelled() }} if: $${{ always() }}
run: | run: |
cargo test --profile ci --features sqlite cargo test --features sqlite
- name: "test features: mysql" - name: "test features: mysql"
id: test_mysql id: test_mysql
if: ${{ !cancelled() }} if: $${{ always() }}
run: | run: |
cargo test --profile ci --features mysql cargo test --features mysql
- name: "test features: postgresql" - name: "test features: postgresql"
id: test_postgresql id: test_postgresql
if: ${{ !cancelled() }} if: $${{ always() }}
run: | run: |
cargo test --profile ci --features postgresql cargo test --features postgresql
# End Run cargo tests # End Run cargo tests
# Run cargo clippy, and fail on warnings # Run cargo clippy, and fail on warnings
- name: "clippy features: sqlite,mysql,postgresql,enable_mimalloc,s3" - name: "clippy features: sqlite,mysql,postgresql,enable_mimalloc"
id: clippy id: clippy
if: ${{ !cancelled() && matrix.channel == 'rust-toolchain' }} if: ${{ always() && matrix.channel == 'rust-toolchain' }}
run: | run: |
cargo clippy --profile ci --features sqlite,mysql,postgresql,enable_mimalloc,s3 cargo clippy --features sqlite,mysql,postgresql,enable_mimalloc -- -D warnings
# End Run cargo clippy # End Run cargo clippy
# Run cargo fmt (Only run on rust-toolchain defined version) # Run cargo fmt (Only run on rust-toolchain defined version)
- name: "check formatting" - name: "check formatting"
id: formatting id: formatting
if: ${{ !cancelled() && matrix.channel == 'rust-toolchain' }} if: ${{ always() && matrix.channel == 'rust-toolchain' }}
run: | run: |
cargo fmt --all -- --check cargo fmt --all -- --check
# End Run cargo fmt # End Run cargo fmt
@ -183,31 +171,21 @@ jobs:
# This is useful so all test/clippy/fmt actions are done, and they can all be addressed # This is useful so all test/clippy/fmt actions are done, and they can all be addressed
- name: "Some checks failed" - name: "Some checks failed"
if: ${{ failure() }} if: ${{ failure() }}
env:
TEST_DB_M_S3: ${{ steps.test_sqlite_mysql_postgresql_mimalloc_s3.outcome }}
TEST_DB_M: ${{ steps.test_sqlite_mysql_postgresql_mimalloc.outcome }}
TEST_DB: ${{ steps.test_sqlite_mysql_postgresql.outcome }}
TEST_SQLITE: ${{ steps.test_sqlite.outcome }}
TEST_MYSQL: ${{ steps.test_mysql.outcome }}
TEST_POSTGRESQL: ${{ steps.test_postgresql.outcome }}
CLIPPY: ${{ steps.clippy.outcome }}
FMT: ${{ steps.formatting.outcome }}
run: | run: |
echo "### :x: Checks Failed!" >> "${GITHUB_STEP_SUMMARY}" echo "### :x: Checks Failed!" >> $GITHUB_STEP_SUMMARY
echo "" >> "${GITHUB_STEP_SUMMARY}" echo "" >> $GITHUB_STEP_SUMMARY
echo "|Job|Status|" >> "${GITHUB_STEP_SUMMARY}" echo "|Job|Status|" >> $GITHUB_STEP_SUMMARY
echo "|---|------|" >> "${GITHUB_STEP_SUMMARY}" echo "|---|------|" >> $GITHUB_STEP_SUMMARY
echo "|test (sqlite,mysql,postgresql,enable_mimalloc,s3)|${TEST_DB_M_S3}|" >> "${GITHUB_STEP_SUMMARY}" echo "|test (sqlite,mysql,postgresql,enable_mimalloc)|${{ steps.test_sqlite_mysql_postgresql_mimalloc.outcome }}|" >> $GITHUB_STEP_SUMMARY
echo "|test (sqlite,mysql,postgresql,enable_mimalloc)|${TEST_DB_M}|" >> "${GITHUB_STEP_SUMMARY}" echo "|test (sqlite,mysql,postgresql)|${{ steps.test_sqlite_mysql_postgresql.outcome }}|" >> $GITHUB_STEP_SUMMARY
echo "|test (sqlite,mysql,postgresql)|${TEST_DB}|" >> "${GITHUB_STEP_SUMMARY}" echo "|test (sqlite)|${{ steps.test_sqlite.outcome }}|" >> $GITHUB_STEP_SUMMARY
echo "|test (sqlite)|${TEST_SQLITE}|" >> "${GITHUB_STEP_SUMMARY}" echo "|test (mysql)|${{ steps.test_mysql.outcome }}|" >> $GITHUB_STEP_SUMMARY
echo "|test (mysql)|${TEST_MYSQL}|" >> "${GITHUB_STEP_SUMMARY}" echo "|test (postgresql)|${{ steps.test_postgresql.outcome }}|" >> $GITHUB_STEP_SUMMARY
echo "|test (postgresql)|${TEST_POSTGRESQL}|" >> "${GITHUB_STEP_SUMMARY}" echo "|clippy (sqlite,mysql,postgresql,enable_mimalloc)|${{ steps.clippy.outcome }}|" >> $GITHUB_STEP_SUMMARY
echo "|clippy (sqlite,mysql,postgresql,enable_mimalloc,s3)|${CLIPPY}|" >> "${GITHUB_STEP_SUMMARY}" echo "|fmt|${{ steps.formatting.outcome }}|" >> $GITHUB_STEP_SUMMARY
echo "|fmt|${FMT}|" >> "${GITHUB_STEP_SUMMARY}" echo "" >> $GITHUB_STEP_SUMMARY
echo "" >> "${GITHUB_STEP_SUMMARY}" echo "Please check the failed jobs and fix where needed." >> $GITHUB_STEP_SUMMARY
echo "Please check the failed jobs and fix where needed." >> "${GITHUB_STEP_SUMMARY}" echo "" >> $GITHUB_STEP_SUMMARY
echo "" >> "${GITHUB_STEP_SUMMARY}"
exit 1 exit 1
@ -216,5 +194,5 @@ jobs:
- name: "All checks passed" - name: "All checks passed"
if: ${{ success() }} if: ${{ success() }}
run: | run: |
echo "### :tada: Checks Passed!" >> "${GITHUB_STEP_SUMMARY}" echo "### :tada: Checks Passed!" >> $GITHUB_STEP_SUMMARY
echo "" >> "${GITHUB_STEP_SUMMARY}" echo "" >> $GITHUB_STEP_SUMMARY

View file

@ -1,35 +0,0 @@
name: Check templates
permissions: {}
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
on: [ push, pull_request ]
defaults:
run:
shell: bash
jobs:
docker-templates:
name: Validate docker templates
runs-on: ubuntu-24.04
timeout-minutes: 30
steps:
# Checkout the repo
- name: "Checkout"
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
# End Checkout the repo
- name: Run make to rebuild templates
working-directory: docker
run: make
- name: Check for unstaged changes
working-directory: docker
run: git diff --exit-code
continue-on-error: false

View file

@ -1,26 +1,24 @@
name: Hadolint name: Hadolint
permissions: {}
concurrency: on: [
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} push,
cancel-in-progress: true pull_request
]
on: [ push, pull_request ]
defaults:
run:
shell: bash
jobs: jobs:
hadolint: hadolint:
name: Validate Dockerfile syntax name: Validate Dockerfile syntax
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
timeout-minutes: 30 timeout-minutes: 30
steps: steps:
# Checkout the repo
- name: Checkout
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 #v4.2.1
# End Checkout the repo
# Start Docker Buildx # Start Docker Buildx
- name: Setup Docker Buildx - name: Setup Docker Buildx
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1 uses: docker/setup-buildx-action@c47758b77c9736f4b2ef4073d4d51994fabfe349 # v3.7.1
# https://github.com/moby/buildkit/issues/3969 # https://github.com/moby/buildkit/issues/3969
# Also set max parallelism to 2, the default of 4 breaks GitHub Actions and causes OOMKills # Also set max parallelism to 2, the default of 4 breaks GitHub Actions and causes OOMKills
with: with:
@ -30,29 +28,25 @@ jobs:
driver-opts: | driver-opts: |
network=host network=host
# Checkout the repo # Download hadolint - https://github.com/hadolint/hadolint/releases
- name: Checkout - name: Download hadolint
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 shell: bash
with: run: |
persist-credentials: false sudo curl -L https://github.com/hadolint/hadolint/releases/download/v${HADOLINT_VERSION}/hadolint-$(uname -s)-$(uname -m) -o /usr/local/bin/hadolint && \
# End Checkout the repo sudo chmod +x /usr/local/bin/hadolint
env:
HADOLINT_VERSION: 2.12.0
# End Download hadolint
# Test Dockerfiles with hadolint # Test Dockerfiles with hadolint
# Uses the Docker-based action (hadolint pre-bundled in ghcr.io/hadolint/hadolint:v2.14.0-debian) - name: Run hadolint
# so no binary is downloaded at runtime. Pinned by commit SHA for supply-chain safety. shell: bash
- name: Run hadolint on Dockerfile.debian run: hadolint docker/Dockerfile.{debian,alpine}
uses: hadolint/hadolint-action@06be81baf89a55ffd0e24b8f04a4185738dd3387 # v3.5.0
with:
dockerfile: docker/Dockerfile.debian
- name: Run hadolint on Dockerfile.alpine
uses: hadolint/hadolint-action@06be81baf89a55ffd0e24b8f04a4185738dd3387 # v3.5.0
with:
dockerfile: docker/Dockerfile.alpine
# End Test Dockerfiles with hadolint # End Test Dockerfiles with hadolint
# Test Dockerfiles with docker build checks # Test Dockerfiles with docker build checks
- name: Run docker build check - name: Run docker build check
shell: bash
run: | run: |
echo "Checking docker/Dockerfile.debian" echo "Checking docker/Dockerfile.debian"
docker build --check . -f docker/Dockerfile.debian docker build --check . -f docker/Dockerfile.debian

View file

@ -1,11 +1,4 @@
name: Release name: Release
permissions: {}
concurrency:
# Apply concurrency control only on the upstream repo
group: ${{ github.repository == 'dani-garcia/vaultwarden' && format('{0}-{1}', github.workflow, github.ref) || github.run_id }}
# Don't cancel other runs when creating a tag
cancel-in-progress: ${{ github.ref_type == 'branch' }}
on: on:
push: push:
@ -13,88 +6,90 @@ on:
- main - main
tags: tags:
# https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#filter-pattern-cheat-sheet - '*'
- '[1-2].[0-9]+.[0-9]+'
defaults:
run:
shell: bash
# A "release" environment must be created in the repository settings
# (Settings > Environments > New environment) with the following
# variables and secrets configured as needed.
#
# Variables (only set the ones for registries you want to push to):
# DOCKERHUB_REPO: 'index.docker.io/<user>/<repo>'
# QUAY_REPO: 'quay.io/<user>/<repo>'
# GHCR_REPO: 'ghcr.io/<user>/<repo>'
#
# Secrets (only required when the corresponding *_REPO variable is set):
# DOCKERHUB_REPO => DOCKERHUB_USERNAME, DOCKERHUB_TOKEN
# QUAY_REPO => QUAY_USERNAME, QUAY_TOKEN
# GITHUB_TOKEN is provided automatically
jobs: jobs:
docker-build: # https://github.com/marketplace/actions/skip-duplicate-actions
name: Build Vaultwarden containers # Some checks to determine if we need to continue with building a new docker.
# We will skip this check if we are creating a tag, because that has the same hash as a previous run already.
skip_check:
runs-on: ubuntu-24.04
if: ${{ github.repository == 'dani-garcia/vaultwarden' }} if: ${{ github.repository == 'dani-garcia/vaultwarden' }}
environment: outputs:
name: release should_skip: ${{ steps.skip_check.outputs.should_skip }}
deployment: false steps:
permissions: - name: Skip Duplicates Actions
packages: write # Needed to upload packages and artifacts id: skip_check
contents: read uses: fkirc/skip-duplicate-actions@f75f66ce1886f00957d99748a42c724f4330bdcf # v5.3.1
attestations: write # Needed to generate an artifact attestation for a build with:
id-token: write # Needed to mint the OIDC token necessary to request a Sigstore signing certificate cancel_others: 'true'
runs-on: ${{ contains(matrix.arch, 'arm') && 'ubuntu-24.04-arm' || 'ubuntu-24.04' }} # Only run this when not creating a tag
if: ${{ github.ref_type == 'branch' }}
docker-build:
runs-on: ubuntu-24.04
timeout-minutes: 120 timeout-minutes: 120
needs: skip_check
if: ${{ needs.skip_check.outputs.should_skip != 'true' && github.repository == 'dani-garcia/vaultwarden' }}
# Start a local docker registry to extract the final Alpine static build binaries
services:
registry:
image: registry:2
ports:
- 5000:5000
env: env:
SOURCE_COMMIT: ${{ github.sha }} SOURCE_COMMIT: ${{ github.sha }}
SOURCE_REPOSITORY_URL: "https://github.com/${{ github.repository }}" SOURCE_REPOSITORY_URL: "https://github.com/${{ github.repository }}"
# The *_REPO variables need to be configured as repository variables
# Append `/settings/variables/actions` to your repo url
# DOCKERHUB_REPO needs to be 'index.docker.io/<user>/<repo>'
# Check for Docker hub credentials in secrets
HAVE_DOCKERHUB_LOGIN: ${{ vars.DOCKERHUB_REPO != '' && secrets.DOCKERHUB_USERNAME != '' && secrets.DOCKERHUB_TOKEN != '' }}
# GHCR_REPO needs to be 'ghcr.io/<user>/<repo>'
# Check for Github credentials in secrets
HAVE_GHCR_LOGIN: ${{ vars.GHCR_REPO != '' && github.repository_owner != '' && secrets.GITHUB_TOKEN != '' }}
# QUAY_REPO needs to be 'quay.io/<user>/<repo>'
# Check for Quay.io credentials in secrets
HAVE_QUAY_LOGIN: ${{ vars.QUAY_REPO != '' && secrets.QUAY_USERNAME != '' && secrets.QUAY_TOKEN != '' }}
strategy: strategy:
matrix: matrix:
arch: ["amd64", "arm64", "arm/v7", "arm/v6"]
base_image: ["debian","alpine"] base_image: ["debian","alpine"]
steps: steps:
# Checkout the repo
- name: Checkout
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 #v4.2.1
with:
fetch-depth: 0
- name: Initialize QEMU binfmt support - name: Initialize QEMU binfmt support
uses: docker/setup-qemu-action@99012661954931238ded8c8b007157a8430204e1 # v4.4.0 uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # v3.2.0
with: with:
platforms: "arm64,arm" platforms: "arm64,arm"
# Start Docker Buildx # Start Docker Buildx
- name: Setup Docker Buildx - name: Setup Docker Buildx
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1 uses: docker/setup-buildx-action@c47758b77c9736f4b2ef4073d4d51994fabfe349 # v3.7.1
# https://github.com/moby/buildkit/issues/3969 # https://github.com/moby/buildkit/issues/3969
# Also set max parallelism to 2, the default of 4 breaks GitHub Actions and causes OOMKills # Also set max parallelism to 2, the default of 4 breaks GitHub Actions and causes OOMKills
with: with:
cache-binary: false
buildkitd-config-inline: | buildkitd-config-inline: |
[worker.oci] [worker.oci]
max-parallelism = 2 max-parallelism = 2
driver-opts: | driver-opts: |
network=host network=host
# Checkout the repo # Determine Base Tags and Source Version
- name: Checkout - name: Determine Base Tags and Source Version
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 shell: bash
# We need fetch-depth of 0 so we also get all the tag metadata
with:
persist-credentials: false
fetch-depth: 0
# Normalize the architecture string for use in paths and cache keys
- name: Normalize architecture string
env:
MATRIX_ARCH: ${{ matrix.arch }}
run: | run: |
# Replace slashes with nothing to create a safe string for paths/cache keys # Check which main tag we are going to build determined by github.ref_type
NORMALIZED_ARCH="${MATRIX_ARCH//\/}" if [[ "${{ github.ref_type }}" == "tag" ]]; then
echo "NORMALIZED_ARCH=${NORMALIZED_ARCH}" | tee -a "${GITHUB_ENV}" echo "BASE_TAGS=latest,${GITHUB_REF#refs/*/}" | tee -a "${GITHUB_ENV}"
elif [[ "${{ github.ref_type }}" == "branch" ]]; then
echo "BASE_TAGS=testing" | tee -a "${GITHUB_ENV}"
fi
# Determine Source Version
- name: Determine Source Version
run: |
# Get the Source Version for this release # Get the Source Version for this release
GIT_EXACT_TAG="$(git describe --tags --abbrev=0 --exact-match 2>/dev/null || true)" GIT_EXACT_TAG="$(git describe --tags --abbrev=0 --exact-match 2>/dev/null || true)"
if [[ -n "${GIT_EXACT_TAG}" ]]; then if [[ -n "${GIT_EXACT_TAG}" ]]; then
@ -103,286 +98,155 @@ jobs:
GIT_LAST_TAG="$(git describe --tags --abbrev=0)" GIT_LAST_TAG="$(git describe --tags --abbrev=0)"
echo "SOURCE_VERSION=${GIT_LAST_TAG}-${SOURCE_COMMIT:0:8}" | tee -a "${GITHUB_ENV}" echo "SOURCE_VERSION=${GIT_LAST_TAG}-${SOURCE_COMMIT:0:8}" | tee -a "${GITHUB_ENV}"
fi fi
# End Determine Base Tags
# Login to Docker Hub # Login to Docker Hub
- name: Login to Docker Hub - name: Login to Docker Hub
uses: docker/login-action@81c6f93d4bc991e510b342a00b419b3bb4efc5c6 # v4.7.0 uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
with: with:
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}
if: ${{ vars.DOCKERHUB_REPO != '' }} if: ${{ env.HAVE_DOCKERHUB_LOGIN == 'true' }}
- name: Add registry for DockerHub - name: Add registry for DockerHub
if: ${{ vars.DOCKERHUB_REPO != '' }} if: ${{ env.HAVE_DOCKERHUB_LOGIN == 'true' }}
env: shell: bash
DOCKERHUB_REPO: ${{ vars.DOCKERHUB_REPO }}
run: | run: |
echo "CONTAINER_REGISTRIES=${DOCKERHUB_REPO}" | tee -a "${GITHUB_ENV}" echo "CONTAINER_REGISTRIES=${{ vars.DOCKERHUB_REPO }}" | tee -a "${GITHUB_ENV}"
# Login to GitHub Container Registry # Login to GitHub Container Registry
- name: Login to GitHub Container Registry - name: Login to GitHub Container Registry
uses: docker/login-action@81c6f93d4bc991e510b342a00b419b3bb4efc5c6 # v4.7.0 uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.repository_owner }} username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
if: ${{ vars.GHCR_REPO != '' }} if: ${{ env.HAVE_GHCR_LOGIN == 'true' }}
- name: Add registry for ghcr.io - name: Add registry for ghcr.io
if: ${{ vars.GHCR_REPO != '' }} if: ${{ env.HAVE_GHCR_LOGIN == 'true' }}
env: shell: bash
GHCR_REPO: ${{ vars.GHCR_REPO }}
run: | run: |
echo "CONTAINER_REGISTRIES=${CONTAINER_REGISTRIES:+${CONTAINER_REGISTRIES},}${GHCR_REPO}" | tee -a "${GITHUB_ENV}" echo "CONTAINER_REGISTRIES=${CONTAINER_REGISTRIES:+${CONTAINER_REGISTRIES},}${{ vars.GHCR_REPO }}" | tee -a "${GITHUB_ENV}"
# Login to Quay.io # Login to Quay.io
- name: Login to Quay.io - name: Login to Quay.io
uses: docker/login-action@81c6f93d4bc991e510b342a00b419b3bb4efc5c6 # v4.7.0 uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
with: with:
registry: quay.io registry: quay.io
username: ${{ secrets.QUAY_USERNAME }} username: ${{ secrets.QUAY_USERNAME }}
password: ${{ secrets.QUAY_TOKEN }} password: ${{ secrets.QUAY_TOKEN }}
if: ${{ vars.QUAY_REPO != '' }} if: ${{ env.HAVE_QUAY_LOGIN == 'true' }}
- name: Add registry for Quay.io - name: Add registry for Quay.io
if: ${{ vars.QUAY_REPO != '' }} if: ${{ env.HAVE_QUAY_LOGIN == 'true' }}
env: shell: bash
QUAY_REPO: ${{ vars.QUAY_REPO }}
run: | run: |
echo "CONTAINER_REGISTRIES=${CONTAINER_REGISTRIES:+${CONTAINER_REGISTRIES},}${QUAY_REPO}" | tee -a "${GITHUB_ENV}" echo "CONTAINER_REGISTRIES=${CONTAINER_REGISTRIES:+${CONTAINER_REGISTRIES},}${{ vars.QUAY_REPO }}" | tee -a "${GITHUB_ENV}"
- name: Configure build cache from/to - name: Configure build cache from/to
env: shell: bash
GHCR_REPO: ${{ vars.GHCR_REPO }}
BASE_IMAGE: ${{ matrix.base_image }}
NORMALIZED_ARCH: ${{ env.NORMALIZED_ARCH }}
run: | run: |
# #
# Check if there is a GitHub Container Registry Login and use it for caching # Check if there is a GitHub Container Registry Login and use it for caching
if [[ -n "${GHCR_REPO}" ]]; then if [[ -n "${HAVE_GHCR_LOGIN}" ]]; then
echo "BAKE_CACHE_FROM=type=registry,ref=${GHCR_REPO}-buildcache:${BASE_IMAGE}-${NORMALIZED_ARCH}" | tee -a "${GITHUB_ENV}" echo "BAKE_CACHE_FROM=type=registry,ref=${{ vars.GHCR_REPO }}-buildcache:${{ matrix.base_image }}" | tee -a "${GITHUB_ENV}"
echo "BAKE_CACHE_TO=type=registry,ref=${GHCR_REPO}-buildcache:${BASE_IMAGE}-${NORMALIZED_ARCH},compression=zstd,mode=max" | tee -a "${GITHUB_ENV}" echo "BAKE_CACHE_TO=type=registry,ref=${{ vars.GHCR_REPO }}-buildcache:${{ matrix.base_image }},compression=zstd,mode=max" | tee -a "${GITHUB_ENV}"
else else
echo "BAKE_CACHE_FROM=" echo "BAKE_CACHE_FROM="
echo "BAKE_CACHE_TO=" echo "BAKE_CACHE_TO="
fi fi
# #
- name: Generate tags - name: Add localhost registry
id: tags if: ${{ matrix.base_image == 'alpine' }}
env: shell: bash
CONTAINER_REGISTRIES: "${{ env.CONTAINER_REGISTRIES }}"
run: | run: |
# Convert comma-separated list to newline-separated set commands echo "CONTAINER_REGISTRIES=${CONTAINER_REGISTRIES:+${CONTAINER_REGISTRIES},}localhost:5000/vaultwarden/server" | tee -a "${GITHUB_ENV}"
TAGS=$(echo "${CONTAINER_REGISTRIES}" | tr ',' '\n' | sed "s|.*|*.tags=&|")
# Output for use in next step
{
echo "TAGS<<EOF"
echo "$TAGS"
echo "EOF"
} >> "$GITHUB_ENV"
- name: Bake ${{ matrix.base_image }} containers - name: Bake ${{ matrix.base_image }} containers
id: bake_vw uses: docker/bake-action@2e3d19baedb14545e5d41222653874f25d5b4dfb # v5.10.0
uses: docker/bake-action@59cb1203cd42bcefd40a1b6d73b589e48c86040e # v7.5.0
env: env:
BASE_TAGS: "${{ steps.determine-version.outputs.BASE_TAGS }}" BASE_TAGS: "${{ env.BASE_TAGS }}"
SOURCE_COMMIT: "${{ env.SOURCE_COMMIT }}" SOURCE_COMMIT: "${{ env.SOURCE_COMMIT }}"
SOURCE_VERSION: "${{ env.SOURCE_VERSION }}" SOURCE_VERSION: "${{ env.SOURCE_VERSION }}"
SOURCE_REPOSITORY_URL: "${{ env.SOURCE_REPOSITORY_URL }}" SOURCE_REPOSITORY_URL: "${{ env.SOURCE_REPOSITORY_URL }}"
CONTAINER_REGISTRIES: "${{ env.CONTAINER_REGISTRIES }}"
with: with:
pull: true pull: true
source: . push: true
files: docker/docker-bake.hcl files: docker/docker-bake.hcl
targets: "${{ matrix.base_image }}-multi" targets: "${{ matrix.base_image }}-multi"
set: | set: |
*.cache-from=${{ env.BAKE_CACHE_FROM }} *.cache-from=${{ env.BAKE_CACHE_FROM }}
*.cache-to=${{ env.BAKE_CACHE_TO }} *.cache-to=${{ env.BAKE_CACHE_TO }}
*.platform=linux/${{ matrix.arch }}
${{ env.TAGS }}
*.output=type=local,dest=./output
*.output=type=image,push-by-digest=true,name-canonical=true,push=true
- name: Extract digest SHA
env: # Extract the Alpine binaries from the containers
BAKE_METADATA: ${{ steps.bake_vw.outputs.metadata }} - name: Extract binaries
BASE_IMAGE: ${{ matrix.base_image }} if: ${{ matrix.base_image == 'alpine' }}
shell: bash
run: | run: |
GET_DIGEST_SHA="$(jq -r --arg base "$BASE_IMAGE" '.[$base + "-multi"]."containerimage.digest"' <<< "${BAKE_METADATA}")" # Check which main tag we are going to build determined by github.ref_type
echo "DIGEST_SHA=${GET_DIGEST_SHA}" | tee -a "${GITHUB_ENV}" if [[ "${{ github.ref_type }}" == "tag" ]]; then
EXTRACT_TAG="latest"
- name: Export digest elif [[ "${{ github.ref_type }}" == "branch" ]]; then
env: EXTRACT_TAG="testing"
DIGEST_SHA: ${{ env.DIGEST_SHA }}
RUNNER_TEMP: ${{ runner.temp }}
run: |
mkdir -p "${RUNNER_TEMP}"/digests
digest="${DIGEST_SHA}"
touch "${RUNNER_TEMP}/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: digests-${{ env.NORMALIZED_ARCH }}-${{ matrix.base_image }}
path: ${{ runner.temp }}/digests/*
if-no-files-found: error
retention-days: 1
- name: Rename binaries to match target platform
env:
NORMALIZED_ARCH: ${{ env.NORMALIZED_ARCH }}
run: |
mv ./output/vaultwarden vaultwarden-"${NORMALIZED_ARCH}"
# Upload artifacts to Github Actions and Attest the binaries
- name: Attest binaries
uses: actions/attest@1e69f48acb82d1966a394da916b4c1698aa569d6 # v4.2.2
with:
subject-path: vaultwarden-${{ env.NORMALIZED_ARCH }}
- name: Upload binaries as artifacts
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: vaultwarden-${{ env.SOURCE_VERSION }}-linux-${{ env.NORMALIZED_ARCH }}-${{ matrix.base_image }}
path: vaultwarden-${{ env.NORMALIZED_ARCH }}
merge-manifests:
name: Merge manifests
runs-on: ubuntu-24.04
needs: docker-build
environment:
name: release
deployment: false
permissions:
packages: write # Needed to upload packages and artifacts
attestations: write # Needed to generate an artifact attestation for a build
id-token: write # Needed to mint the OIDC token necessary to request a Sigstore signing certificate
strategy:
matrix:
base_image: ["debian","alpine"]
steps:
- name: Download digests
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
path: ${{ runner.temp }}/digests
pattern: digests-*-${{ matrix.base_image }}
merge-multiple: true
# Login to Docker Hub
- name: Login to Docker Hub
uses: docker/login-action@81c6f93d4bc991e510b342a00b419b3bb4efc5c6 # v4.7.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
if: ${{ vars.DOCKERHUB_REPO != '' }}
- name: Add registry for DockerHub
if: ${{ vars.DOCKERHUB_REPO != '' }}
env:
DOCKERHUB_REPO: ${{ vars.DOCKERHUB_REPO }}
run: |
echo "CONTAINER_REGISTRIES=${DOCKERHUB_REPO}" | tee -a "${GITHUB_ENV}"
# Login to GitHub Container Registry
- name: Login to GitHub Container Registry
uses: docker/login-action@81c6f93d4bc991e510b342a00b419b3bb4efc5c6 # v4.7.0
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
if: ${{ vars.GHCR_REPO != '' }}
- name: Add registry for ghcr.io
if: ${{ vars.GHCR_REPO != '' }}
env:
GHCR_REPO: ${{ vars.GHCR_REPO }}
run: |
echo "CONTAINER_REGISTRIES=${CONTAINER_REGISTRIES:+${CONTAINER_REGISTRIES},}${GHCR_REPO}" | tee -a "${GITHUB_ENV}"
# Login to Quay.io
- name: Login to Quay.io
uses: docker/login-action@81c6f93d4bc991e510b342a00b419b3bb4efc5c6 # v4.7.0
with:
registry: quay.io
username: ${{ secrets.QUAY_USERNAME }}
password: ${{ secrets.QUAY_TOKEN }}
if: ${{ vars.QUAY_REPO != '' }}
- name: Add registry for Quay.io
if: ${{ vars.QUAY_REPO != '' }}
env:
QUAY_REPO: ${{ vars.QUAY_REPO }}
run: |
echo "CONTAINER_REGISTRIES=${CONTAINER_REGISTRIES:+${CONTAINER_REGISTRIES},}${QUAY_REPO}" | tee -a "${GITHUB_ENV}"
# Determine Base Tags
- name: Determine Base Tags
env:
BASE_IMAGE_TAG: "${{ matrix.base_image != 'debian' && format('-{0}', matrix.base_image) || '' }}"
REF_TYPE: ${{ github.ref_type }}
run: |
# Check which main tag we are going to build determined by ref_type
if [[ "${REF_TYPE}" == "tag" ]]; then
echo "BASE_TAGS=latest${BASE_IMAGE_TAG},${GITHUB_REF#refs/*/}${BASE_IMAGE_TAG}${BASE_IMAGE_TAG//-/,}" | tee -a "${GITHUB_ENV}"
elif [[ "${REF_TYPE}" == "branch" ]]; then
echo "BASE_TAGS=testing${BASE_IMAGE_TAG}" | tee -a "${GITHUB_ENV}"
fi fi
- name: Create manifest list, push it and extract digest SHA # After each extraction the image is removed.
working-directory: ${{ runner.temp }}/digests # This is needed because using different platforms doesn't trigger a new pull/download
env:
BASE_TAGS: "${{ env.BASE_TAGS }}"
CONTAINER_REGISTRIES: "${{ env.CONTAINER_REGISTRIES }}"
run: |
IFS=',' read -ra IMAGES <<< "${CONTAINER_REGISTRIES}"
IFS=',' read -ra TAGS <<< "${BASE_TAGS}"
TAG_ARGS=() # Extract amd64 binary
for img in "${IMAGES[@]}"; do docker create --name amd64 --platform=linux/amd64 "localhost:5000/vaultwarden/server:${EXTRACT_TAG}-alpine"
for tag in "${TAGS[@]}"; do docker cp amd64:/vaultwarden vaultwarden-amd64
TAG_ARGS+=("-t" "${img}:${tag}") docker rm --force amd64
done docker rmi --force "localhost:5000/vaultwarden/server:${EXTRACT_TAG}-alpine"
done
echo "Creating manifest" # Extract arm64 binary
if ! OUTPUT=$(docker buildx imagetools create \ docker create --name arm64 --platform=linux/arm64 "localhost:5000/vaultwarden/server:${EXTRACT_TAG}-alpine"
"${TAG_ARGS[@]}" \ docker cp arm64:/vaultwarden vaultwarden-arm64
$(printf "${IMAGES[0]}@sha256:%s " *) 2>&1); then docker rm --force arm64
echo "Manifest creation failed" docker rmi --force "localhost:5000/vaultwarden/server:${EXTRACT_TAG}-alpine"
echo "${OUTPUT}"
exit 1
fi
echo "Manifest created successfully" # Extract armv7 binary
echo "${OUTPUT}" docker create --name armv7 --platform=linux/arm/v7 "localhost:5000/vaultwarden/server:${EXTRACT_TAG}-alpine"
docker cp armv7:/vaultwarden vaultwarden-armv7
docker rm --force armv7
docker rmi --force "localhost:5000/vaultwarden/server:${EXTRACT_TAG}-alpine"
# Extract digest SHA for subsequent steps # Extract armv6 binary
GET_DIGEST_SHA="$(echo "${OUTPUT}" | grep -oE 'sha256:[a-f0-9]{64}' | tail -1)" docker create --name armv6 --platform=linux/arm/v6 "localhost:5000/vaultwarden/server:${EXTRACT_TAG}-alpine"
echo "DIGEST_SHA=${GET_DIGEST_SHA}" | tee -a "${GITHUB_ENV}" docker cp armv6:/vaultwarden vaultwarden-armv6
docker rm --force armv6
docker rmi --force "localhost:5000/vaultwarden/server:${EXTRACT_TAG}-alpine"
# Attest container images # Upload artifacts to Github Actions
- name: Attest - docker.io - ${{ matrix.base_image }} - name: "Upload amd64 artifact"
if: ${{ vars.DOCKERHUB_REPO != '' && env.DIGEST_SHA != ''}} uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
uses: actions/attest@1e69f48acb82d1966a394da916b4c1698aa569d6 # v4.2.2 if: ${{ matrix.base_image == 'alpine' }}
with: with:
subject-name: ${{ vars.DOCKERHUB_REPO }} name: vaultwarden-${{ env.SOURCE_VERSION }}-linux-amd64
subject-digest: ${{ env.DIGEST_SHA }} path: vaultwarden-amd64
push-to-registry: true
- name: Attest - ghcr.io - ${{ matrix.base_image }} - name: "Upload arm64 artifact"
if: ${{ vars.GHCR_REPO != '' && env.DIGEST_SHA != ''}} uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
uses: actions/attest@1e69f48acb82d1966a394da916b4c1698aa569d6 # v4.2.2 if: ${{ matrix.base_image == 'alpine' }}
with: with:
subject-name: ${{ vars.GHCR_REPO }} name: vaultwarden-${{ env.SOURCE_VERSION }}-linux-arm64
subject-digest: ${{ env.DIGEST_SHA }} path: vaultwarden-arm64
push-to-registry: true
- name: Attest - quay.io - ${{ matrix.base_image }} - name: "Upload armv7 artifact"
if: ${{ vars.QUAY_REPO != '' && env.DIGEST_SHA != ''}} uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
uses: actions/attest@1e69f48acb82d1966a394da916b4c1698aa569d6 # v4.2.2 if: ${{ matrix.base_image == 'alpine' }}
with: with:
subject-name: ${{ vars.QUAY_REPO }} name: vaultwarden-${{ env.SOURCE_VERSION }}-linux-armv7
subject-digest: ${{ env.DIGEST_SHA }} path: vaultwarden-armv7
push-to-registry: true
- name: "Upload armv6 artifact"
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
if: ${{ matrix.base_image == 'alpine' }}
with:
name: vaultwarden-${{ env.SOURCE_VERSION }}-linux-armv6
path: vaultwarden-armv6
# End Upload artifacts to Github Actions

View file

@ -1,10 +1,3 @@
name: Cleanup
permissions: {}
concurrency:
group: ${{ github.workflow }}
cancel-in-progress: false
on: on:
workflow_dispatch: workflow_dispatch:
inputs: inputs:
@ -16,11 +9,10 @@ on:
schedule: schedule:
- cron: '0 1 * * FRI' - cron: '0 1 * * FRI'
name: Cleanup
jobs: jobs:
releasecache-cleanup: releasecache-cleanup:
name: Releasecache Cleanup name: Releasecache Cleanup
permissions:
packages: write # To be able to cleanup old caches
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
continue-on-error: true continue-on-error: true
timeout-minutes: 30 timeout-minutes: 30

View file

@ -1,47 +1,37 @@
name: Trivy name: trivy
permissions: {}
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
on: on:
push: push:
branches: branches:
- main - main
tags: tags:
- '*' - '*'
pull_request: pull_request:
branches: branches: [ "main" ]
- main
schedule: schedule:
- cron: '08 11 * * *' - cron: '08 11 * * *'
permissions:
contents: read
jobs: jobs:
trivy-scan: trivy-scan:
# Only run this in the upstream repo and not on forks # Only run this in the master repo and not on forks
# When all forks run this at the same time, it is causing `Too Many Requests` issues # When all forks run this at the same time, it is causing `Too Many Requests` issues
if: ${{ github.repository == 'dani-garcia/vaultwarden' }} if: ${{ github.repository == 'dani-garcia/vaultwarden' }}
name: Trivy Scan name: Check
permissions:
security-events: write # To write the security report
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
timeout-minutes: 30 timeout-minutes: 30
permissions:
contents: read
security-events: write
actions: read
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 #v4.2.1
with:
persist-credentials: false
- name: Run Trivy vulnerability scanner - name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0 uses: aquasecurity/trivy-action@5681af892cd0f4997658e2bacc62bd0a894cf564 # v0.27.0
env:
TRIVY_DB_REPOSITORY: docker.io/aquasec/trivy-db:2,public.ecr.aws/aquasecurity/trivy-db:2,ghcr.io/aquasecurity/trivy-db:2
TRIVY_JAVA_DB_REPOSITORY: docker.io/aquasec/trivy-java-db:1,public.ecr.aws/aquasecurity/trivy-java-db:1,ghcr.io/aquasecurity/trivy-java-db:1
with: with:
scan-type: repo scan-type: repo
ignore-unfixed: true ignore-unfixed: true
@ -50,6 +40,6 @@ jobs:
severity: CRITICAL,HIGH severity: CRITICAL,HIGH
- name: Upload Trivy scan results to GitHub Security tab - name: Upload Trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@9b3254085494b55a0f7c4c2b3d2d52cc712ce370 # v4.39.1 uses: github/codeql-action/upload-sarif@2bbafcdd7fbf96243689e764c2f15d9735164f33 # v3.26.6
with: with:
sarif_file: 'trivy-results.sarif' sarif_file: 'trivy-results.sarif'

View file

@ -1,26 +0,0 @@
name: Code Spell Checking
permissions: {}
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
on: [ push, pull_request ]
jobs:
typos:
name: Run typos spell checking
runs-on: ubuntu-24.04
timeout-minutes: 30
steps:
# Checkout the repo
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
# End Checkout the repo
# When this version is updated, do not forget to update this in `.pre-commit-config.yaml` too
- name: Spell Check Repo
uses: crate-ci/typos@7f9d0819ca1c008ade73f4b41fa9d258d48f605b # v1.51.1

View file

@ -1,31 +0,0 @@
name: Security Analysis with zizmor
permissions: {}
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
on:
push:
branches: ["main"]
pull_request:
branches: ["**"]
jobs:
zizmor:
name: Run zizmor
runs-on: ubuntu-24.04
permissions:
security-events: write # To write the security report
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Run zizmor
uses: zizmorcore/zizmor-action@53290badfa369cb0bf7ad16342cb62c2fa47ac7b # v0.8.0
with:
# intentionally not scanning the entire repository,
# since it contains integration tests.
inputs: ./.github/

View file

@ -1,59 +1,44 @@
--- ---
repos: repos:
- repo: https://github.com/pre-commit/pre-commit-hooks - repo: https://github.com/pre-commit/pre-commit-hooks
rev: 3e8a8703264a2f4a69428a0aa4dcb512790b2c8c # v6.0.0 rev: v4.6.0
hooks: hooks:
- id: check-yaml - id: check-yaml
- id: check-json - id: check-json
- id: check-toml - id: check-toml
- id: mixed-line-ending - id: mixed-line-ending
args: [ "--fix=no" ] args: ["--fix=no"]
- id: end-of-file-fixer - id: end-of-file-fixer
exclude: "(.*js$|.*css$)" exclude: "(.*js$|.*css$)"
- id: check-case-conflict - id: check-case-conflict
- id: check-merge-conflict - id: check-merge-conflict
- id: detect-private-key - id: detect-private-key
- id: check-symlinks - id: check-symlinks
- id: forbid-submodules - id: forbid-submodules
- repo: local
# When this version is updated, do not forget to update this in `.github/workflows/typos.yaml` too
- repo: https://github.com/crate-ci/typos
rev: 7f9d0819ca1c008ade73f4b41fa9d258d48f605b # v1.51.1
hooks: hooks:
- id: typos - id: fmt
always_run: true name: fmt
description: Format files with cargo fmt.
- repo: local entry: cargo fmt
hooks: language: system
- id: fmt types: [rust]
name: fmt args: ["--", "--check"]
description: Format files with cargo fmt. - id: cargo-test
entry: cargo fmt name: cargo test
language: system description: Test the package for errors.
always_run: true entry: cargo test
pass_filenames: false language: system
args: [ "--", "--check" ] args: ["--features", "sqlite,mysql,postgresql,enable_mimalloc", "--"]
- id: cargo-test types_or: [rust, file]
name: cargo test files: (Cargo.toml|Cargo.lock|rust-toolchain|.*\.rs$)
description: Test the package for errors. pass_filenames: false
entry: cargo test - id: cargo-clippy
language: system name: cargo clippy
args: [ "--features", "sqlite,mysql,postgresql", "--" ] description: Lint Rust sources
types_or: [ rust, toml ] # Cargo.lock matches toml type which is intended entry: cargo clippy
pass_filenames: false language: system
- id: cargo-clippy args: ["--features", "sqlite,mysql,postgresql,enable_mimalloc", "--", "-D", "warnings"]
name: cargo clippy types_or: [rust, file]
description: Lint Rust sources files: (Cargo.toml|Cargo.lock|rust-toolchain|clippy.toml|.*\.rs$)
entry: cargo clippy pass_filenames: false
language: system
args: [ "--features", "sqlite,mysql,postgresql", "--", "-D", "warnings" ]
types_or: [ rust, toml ] # Cargo.lock matches toml type which is intended
pass_filenames: false
- id: check-docker-templates
name: check docker templates
description: Check if the Docker templates are updated
language: system
entry: sh
args:
- "-c"
- "cd docker && make"

View file

@ -1,28 +0,0 @@
[files]
extend-exclude = [
".git/",
"playwright/",
"*.js", # Ignore all JavaScript files
"!admin*.js", # Except our own JavaScript files
]
ignore-hidden = false
[default]
extend-ignore-re = [
# We use this in place of the reserved type identifier at some places
"typ",
# In SMTP it's called HELO, so ignore it
"(?i)helo_name",
"Server name sent during.+HELO",
# COSE Is short for CBOR Object Signing and Encryption, ignore these specific items
"COSEKey",
"COSEAlgorithm",
# Ignore this specific string as it's valid
"Ensure they are valid OTPs",
# This word is misspelled upstream
# https://github.com/bitwarden/server/blob/dff9f1cf538198819911cf2c20f8cda3307701c5/src/Notifications/HubHelpers.cs#L86
# https://github.com/bitwarden/clients/blob/9612a4ac45063e372a6fbe87eb253c7cb3c588fb/libs/common/src/auth/services/anonymous-hub.service.ts#L45
"AuthRequestResponseRecieved",
# Ignore Punycode/IDN tests
"xn--.+"
]

5196
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,292 +1,192 @@
[workspace.package]
edition = "2024"
rust-version = "1.97.1"
license = "AGPL-3.0-only"
repository = "https://github.com/dani-garcia/vaultwarden"
publish = false
[workspace]
members = ["macros"]
[package] [package]
name = "vaultwarden" name = "vaultwarden"
version = "1.0.0" version = "1.0.0"
authors = ["Daniel García <dani-garcia@users.noreply.github.com>"] authors = ["Daniel García <dani-garcia@users.noreply.github.com>"]
edition = "2021"
rust-version = "1.80.0"
resolver = "2"
repository = "https://github.com/dani-garcia/vaultwarden"
readme = "README.md"
license = "AGPL-3.0-only"
publish = false
build = "build.rs" build = "build.rs"
repository.workspace = true
edition.workspace = true
rust-version.workspace = true
license.workspace = true
publish.workspace = true
[features] [features]
default = [ # default = ["sqlite"]
# "sqlite",
# "sqlite_system",
# "mysql",
# "postgresql",
]
# Empty to keep compatibility, prefer to set USE_SYSLOG=true # Empty to keep compatibility, prefer to set USE_SYSLOG=true
enable_syslog = [] enable_syslog = []
# Please enable at least one of these DB backends.
mysql = ["diesel/mysql", "diesel_migrations/mysql"] mysql = ["diesel/mysql", "diesel_migrations/mysql"]
postgresql = ["diesel/postgres", "diesel_migrations/postgres"] postgresql = ["diesel/postgres", "diesel_migrations/postgres"]
sqlite_system = ["diesel/sqlite", "diesel_migrations/sqlite"] # Dynamically link SQLite sqlite = ["diesel/sqlite", "diesel_migrations/sqlite", "dep:libsqlite3-sys"]
sqlite = ["sqlite_system", "libsqlite3-sys/bundled"] # Statically link SQLite into the binary instead of dynamically.
# Enable to use a vendored and statically linked openssl # Enable to use a vendored and statically linked openssl
vendored_openssl = ["openssl/vendored"] vendored_openssl = ["openssl/vendored"]
# Enable MiMalloc memory allocator to replace the default malloc # Enable MiMalloc memory allocator to replace the default malloc
# This can improve performance for Alpine builds # This can improve performance for Alpine builds
enable_mimalloc = ["dep:mimalloc"] enable_mimalloc = ["dep:mimalloc"]
s3 = [ # This is a development dependency, and should only be used during development!
"opendal/services-s3", # It enables the usage of the diesel_logger crate, which is able to output the generated queries.
"dep:opendal-http-transport-reqwest", # You also need to set an env variable `QUERY_LOGGER=1` to fully activate this so you do not have to re-compile
"dep:aws-config", # if you want to turn off the logging for a specific run.
"dep:aws-credential-types", query_logger = ["dep:diesel_logger"]
"dep:aws-smithy-runtime-api",
"dep:http",
"dep:reqsign-aws-v4",
"dep:reqsign-core",
]
# OIDC specific features
oidc-accept-rfc3339-timestamps = ["openidconnect/accept-rfc3339-timestamps"]
oidc-accept-string-booleans = ["openidconnect/accept-string-booleans"]
# Enable unstable features, requires nightly # Enable unstable features, requires nightly
# Currently only used to enable rusts official ip support # Currently only used to enable rusts official ip support
unstable = [] unstable = []
[target."cfg(unix)".dependencies] [target."cfg(unix)".dependencies]
nix = { version = "0.31.3", features = ["fs"] }
# Logging # Logging
syslog = "7.0.0" syslog = "6.1.1"
[dependencies] [dependencies]
macros = { path = "./macros" }
# Logging # Logging
log = "0.4.35" log = "0.4.22"
fern = { version = "0.7.1", features = ["syslog-7", "reopen-1"] } fern = { version = "0.7.0", features = ["syslog-6", "reopen-1"] }
# We need the `log` feature for `tracing` to enable logging for several crates to work, like lettre or webauthn-rs tracing = { version = "0.1.40", features = ["log"] } # Needed to have lettre and webauthn-rs trace logging to work
tracing = { version = "0.1.44", features = ["log"] }
# A `dotenv` implementation for Rust # A `dotenv` implementation for Rust
dotenvy = { version = "0.15.7", default-features = false } dotenvy = { version = "0.15.7", default-features = false }
# Lazy initialization
once_cell = "1.20.2"
# Numerical libraries # Numerical libraries
num-traits = "0.2.19" num-traits = "0.2.19"
num-derive = "0.5.1" num-derive = "0.4.2"
bigdecimal = "0.4.11" bigdecimal = "0.4.5"
# Web framework # Web framework
rocket = { version = "0.5.2", default-features = false, features = ["json", "tls"] } rocket = { version = "0.5.1", features = ["tls", "json"], default-features = false }
rocket_ws = { version = "0.1.1" } rocket_ws = { version ="0.1.1" }
# WebSockets libraries # WebSockets libraries
rmpv = "1.3.1" # MessagePack library rmpv = "1.3.0" # MessagePack library
# Concurrent HashMap used for WebSocket messaging and favicons # Concurrent HashMap used for WebSocket messaging and favicons
dashmap = "6.2.1" dashmap = "6.1.0"
# Async futures # Async futures
futures = "0.3.34" futures = "0.3.31"
tokio = { version = "1.54.1", features = [ tokio = { version = "1.41.0", features = ["rt-multi-thread", "fs", "io-util", "parking_lot", "time", "signal", "net"] }
"fs",
"io-util",
"net",
"parking_lot",
"rt-multi-thread",
"signal",
"time",
] }
tokio-util = { version = "0.7.20", features = ["compat"] }
# A generic serialization/deserialization framework # A generic serialization/deserialization framework
serde = { version = "1.0.229", features = ["derive"] } serde = { version = "1.0.213", features = ["derive"] }
serde_json = "1.0.154" serde_json = "1.0.132"
# A safe, extensible ORM and Query builder # A safe, extensible ORM and Query builder
diesel = { version = "2.3.14", features = ["chrono", "r2d2", "numeric"] } diesel = { version = "2.2.4", features = ["chrono", "r2d2", "numeric"] }
diesel_migrations = "2.3.2" diesel_migrations = "2.2.0"
diesel_logger = { version = "0.3.0", optional = true }
derive_more = { version = "2.1.1", features = [ # Bundled/Static SQLite
"as_ref", libsqlite3-sys = { version = "0.30.1", features = ["bundled"], optional = true }
"deref",
"display",
"from",
"into",
] }
diesel-derive-newtype = "2.1.3"
# SQLite, statically bundled unless the `sqlite_system` feature is enabled
libsqlite3-sys = { version = "0.38.2", optional = true }
# Crypto-related libraries # Crypto-related libraries
rand = "0.10.3" rand = { version = "0.8.5", features = ["small_rng"] }
ring = "0.17.14" ring = "0.17.8"
rustls = { version = "0.23.46", features = ["ring", "std"], default-features = false }
subtle = "2.6.1"
# UUID generation # UUID generation
uuid = { version = "1.29.0", features = ["v4"] } uuid = { version = "1.11.0", features = ["v4"] }
# Date and time libraries # Date and time libraries
chrono = { version = "0.4.45", default-features = false, features = ["clock", "serde"] } chrono = { version = "0.4.38", features = ["clock", "serde"], default-features = false }
chrono-tz = "0.10.4" chrono-tz = "0.10.0"
time = "0.3.55" time = "0.3.36"
# Job scheduler # Job scheduler
job_scheduler_ng = "2.5.0" job_scheduler_ng = "2.0.5"
# Data encoding library Hex/Base32/Base64 # Data encoding library Hex/Base32/Base64
data-encoding = "2.11.1" data-encoding = "2.6.0"
# JWT library # JWT library
jsonwebtoken = { version = "11.1.0", default-features = false, features = ["rust_crypto", "use_pem"] } jsonwebtoken = "9.3.0"
# TOTP library # TOTP library
totp-lite = "2.0.1" totp-lite = "2.0.1"
# Yubico Library # Yubico Library
yubico_ng = { version = "1.0.0", default-features = false } yubico = { version = "0.11.0", features = ["online-tokio"], default-features = false }
# WebAuthn libraries # WebAuthn libraries
# danger-allow-state-serialisation is needed to save the state in the db webauthn-rs = "0.3.2"
# danger-credential-internals is needed to support U2F to Webauthn migration
webauthn-rs = { version = "0.5.5", features = ["danger-allow-state-serialisation", "danger-credential-internals"] }
webauthn-rs-proto = "0.5.5"
webauthn-rs-core = "0.5.5"
# Handling of URL's for WebAuthn and favicons # Handling of URL's for WebAuthn and favicons
url = "2.5.8" url = "2.5.2"
# Email libraries # Email libraries
lettre = { version = "0.11.23", default-features = false, features = [ lettre = { version = "0.11.10", features = ["smtp-transport", "sendmail-transport", "builder", "serde", "tokio1-native-tls", "hostname", "tracing", "tokio1"], default-features = false }
# Misc percent-encoding = "2.3.1" # URL encoding library used for URL's in the emails
"tracing",
"serde",
"builder",
"hostname",
# TLS/Security
"ring",
"rustls-native-certs",
"tokio1-rustls",
# Transport
"smtp-transport",
"sendmail-transport",
] }
percent-encoding = "2.3.2" # URL encoding library used for URL's in the emails
email_address = "0.2.9" email_address = "0.2.9"
# HTML Template library # HTML Template library
handlebars = { version = "6.4.4", features = ["dir_source"] } handlebars = { version = "6.1.0", features = ["dir_source"] }
# HTTP client (Used for favicons, version check, DUO and HIBP API) # HTTP client (Used for favicons, version check, DUO and HIBP API)
reqwest = { version = "0.13.5", default-features = false, features = [ reqwest = { version = "0.12.8", features = ["native-tls-alpn", "stream", "json", "gzip", "brotli", "socks", "cookies"] }
# Misc hickory-resolver = "0.24.1"
"charset",
"cookies",
"http2",
"json",
"form",
"rustls-no-provider",
"stream",
# Compression
"brotli",
"deflate",
"gzip",
"zstd",
# Proxy
"socks",
"system-proxy",
] }
hickory-resolver = "0.26.3"
# Favicon extraction libraries # Favicon extraction libraries
html5gum = "0.9.0" html5gum = "0.5.7"
regex = { version = "1.13.1", default-features = false, features = [ regex = { version = "1.11.0", features = ["std", "perf", "unicode-perl"], default-features = false }
"perf", data-url = "0.3.1"
"std", bytes = "1.8.0"
"unicode-perl",
] }
data-url = "0.3.2"
bytes = "1.12.1"
svg-hush = "0.9.7"
# Cache function results (Used for version check and favicon fetching) # Cache function results (Used for version check and favicon fetching)
cached = { version = "4.1.0", features = ["async"] } cached = { version = "0.53.1", features = ["async"] }
# Used for custom short lived cookie jar during favicon extraction # Used for custom short lived cookie jar during favicon extraction
cookie = "0.18.2" cookie = "0.18.1"
cookie_store = "0.22.1" cookie_store = "0.21.0"
# Used by U2F, JWT and PostgreSQL # Used by U2F, JWT and PostgreSQL
openssl = "0.10.81" openssl = "0.10.68"
# CLI argument parsing # CLI argument parsing
pico-args = "0.5.0" pico-args = "0.5.0"
# Macro ident concatenation # Macro ident concatenation
pastey = "0.2.3" paste = "1.0.15"
governor = "0.10.4" governor = "0.7.0"
# CIDR parsing for the trusted proxies of the client IP header
ipnet = "2.12.2"
# OIDC for SSO
openidconnect = { version = "4.1.0", default-features = false }
moka = { version = "0.12.16", features = ["future"] }
# Check client versions for specific features. # Check client versions for specific features.
semver = "1.0.28" semver = "1.0.23"
# Allow overriding the default memory allocator # Allow overriding the default memory allocator
# Mainly used for the musl builds, since the default musl malloc is very slow # Mainly used for the musl builds, since the default musl malloc is very slow
mimalloc = { version = "0.1.52", optional = true, default-features = false, features = ["secure"] } mimalloc = { version = "0.1.43", features = ["secure"], default-features = false, optional = true }
which = "6.0.3"
which = "8.0.6"
# Argon2 library with support for the PHC format # Argon2 library with support for the PHC format
argon2 = "0.6.0" argon2 = "0.5.3"
# Reading a password from the cli for generating the Argon2id ADMIN_TOKEN # Reading a password from the cli for generating the Argon2id ADMIN_TOKEN
rpassword = "7.5.4" rpassword = "7.3.1"
# Loading a dynamic CSS Stylesheet
grass_compiler = { version = "0.13.4", default-features = false }
# File are accessed through Apache OpenDAL
opendal = { version = "0.59.5", default-features = false, features = ["services-fs"] }
opendal-http-transport-reqwest = { version = "0.59.5", default-features = false, features = ["rustls-no-provider"], optional = true }
# For retrieving AWS credentials, including temporary SSO credentials
aws-config = { version = "1.13.0", optional = true, default-features = false, features = [
"behavior-version-latest",
"credentials-process",
"rt-tokio",
"sso",
] }
aws-credential-types = { version = "1.3.1", optional = true }
aws-smithy-runtime-api = { version = "1.19.2", optional = true }
http = { version = "1.5.0", optional = true }
reqsign-aws-v4 = { version = "3.3.1", optional = true }
reqsign-core = { version = "3.3.2", optional = true }
# Strip debuginfo from the release builds # Strip debuginfo from the release builds
# The debug symbols are to provide better panic traces # The symbols are the provide better panic traces
# Also enable fat LTO and use 1 codegen unit for optimizations # Also enable fat LTO and use 1 codegen unit for optimizations
[profile.release] [profile.release]
strip = "debuginfo" strip = "debuginfo"
lto = "fat" lto = "fat"
codegen-units = 1 codegen-units = 1
debug = false
# A little bit of a speedup
[profile.dev]
split-debuginfo = "unpacked"
# Always build argon2 using opt-level 3
# This is a huge speed improvement during testing
[profile.dev.package.argon2]
opt-level = 3
# Optimize for size # Optimize for size
[profile.release-micro] [profile.release-micro]
inherits = "release" inherits = "release"
strip = "symbols"
opt-level = "z" opt-level = "z"
strip = "symbols"
lto = "fat"
codegen-units = 1
panic = "abort" panic = "abort"
# Profile for systems with low resources # Profile for systems with low resources
@ -297,108 +197,68 @@ strip = "symbols"
lto = "thin" lto = "thin"
codegen-units = 16 codegen-units = 16
# Used for profiling and debugging like valgrind or heaptrack
# Inherits release to be sure all optimizations have been done
[profile.dbg]
inherits = "release"
strip = "none"
split-debuginfo = "off"
debug = "full"
# A little bit of a speedup for generic building
[profile.dev]
split-debuginfo = "unpacked"
debug = "line-tables-only"
# Used for CI builds to improve compile time
[profile.ci]
inherits = "dev"
debug = false
debug-assertions = false
strip = "symbols"
panic = "abort"
# Always build argon2 using opt-level 3
# This is a huge speed improvement during testing
[profile.dev.package.argon2]
opt-level = 3
# Linting config # Linting config
# https://doc.rust-lang.org/rustc/lints/groups.html # https://doc.rust-lang.org/rustc/lints/groups.html
[workspace.lints.rust] [lints.rust]
# Forbid # Forbid
unsafe_code = "forbid" unsafe_code = "forbid"
non_ascii_idents = "forbid" non_ascii_idents = "forbid"
# Deny # Deny
warnings = "deny" # Explicitly deny all warnings since we deny all warnings in the end deprecated_in_future = "deny"
# Deny lint groups
deprecated_safe = { level = "deny", priority = -1 }
future_incompatible = { level = "deny", priority = -1 } future_incompatible = { level = "deny", priority = -1 }
keyword_idents = { level = "deny", priority = -1 } keyword_idents = { level = "deny", priority = -1 }
let_underscore = { level = "deny", priority = -1 } let_underscore = { level = "deny", priority = -1 }
nonstandard_style = { level = "deny", priority = -1 } noop_method_call = "deny"
refining_impl_trait = { level = "deny", priority = -1 } refining_impl_trait = { level = "deny", priority = -1 }
rust_2018_idioms = { level = "deny", priority = -1 } rust_2018_idioms = { level = "deny", priority = -1 }
rust_2021_compatibility = { level = "deny", priority = -1 } rust_2021_compatibility = { level = "deny", priority = -1 }
rust_2024_compatibility = { level = "deny", priority = -1 } # rust_2024_compatibility = { level = "deny", priority = -1 } # Enable once we are at MSRV 1.81.0
unused = { level = "deny", priority = -1 }
# Deny individual lints
closure_returning_async_block = "deny"
deprecated_in_future = "deny"
single_use_lifetimes = "deny" single_use_lifetimes = "deny"
trivial_casts = "deny" trivial_casts = "deny"
trivial_numeric_casts = "deny" trivial_numeric_casts = "deny"
unused = { level = "deny", priority = -1 }
unused_import_braces = "deny" unused_import_braces = "deny"
unused_lifetimes = "deny" unused_lifetimes = "deny"
unused_qualifications = "deny" unused_qualifications = "deny"
variant_size_differences = "deny" variant_size_differences = "deny"
# The lints below are part of the rust_2024_compatibility group
static-mut-refs = "deny"
unsafe-op-in-unsafe-fn = "deny"
# https://rust-lang.github.io/rust-clippy/stable/index.html # https://rust-lang.github.io/rust-clippy/stable/index.html
[workspace.lints.clippy] [lints.clippy]
# Warn only so you can still use these during development, but not in the final code # Warn
dbg_macro = "warn" dbg_macro = "warn"
todo = "warn" todo = "warn"
# Ignore/Allow # Deny
result_large_err = "allow" case_sensitive_file_extension_comparisons = "deny"
cast_lossless = "deny"
# Warn on these lint group (Some might be warn by default already though)
# Will be denied during CI!
complexity = { level = "warn", priority = -1 }
pedantic = { level = "warn", priority = -1 }
perf = { level = "warn", priority = -1 }
style = { level = "warn", priority = -1 }
suspicious = { level = "warn", priority = -1 }
# Deny individual lints
branches_sharing_code = "deny"
clone_on_ref_ptr = "deny" clone_on_ref_ptr = "deny"
equatable_if_let = "deny" equatable_if_let = "deny"
filter_map_next = "deny"
float_cmp_const = "deny" float_cmp_const = "deny"
inefficient_to_string = "deny"
iter_on_empty_collections = "deny" iter_on_empty_collections = "deny"
iter_on_single_items = "deny" iter_on_single_items = "deny"
linkedlist = "deny"
macro_use_imports = "deny"
manual_assert = "deny"
manual_instant_elapsed = "deny"
manual_string_new = "deny"
match_on_vec_items = "deny"
match_wildcard_for_single_variants = "deny"
mem_forget = "deny" mem_forget = "deny"
needless_collect = "deny" needless_continue = "deny"
redundant_clone = "deny" needless_lifetimes = "deny"
option_option = "deny"
string_add_assign = "deny"
string_to_string = "deny"
unnecessary_join = "deny"
unnecessary_self_imports = "deny" unnecessary_self_imports = "deny"
useless_let_if_seq = "deny" unnested_or_patterns = "deny"
unused_async = "deny"
unused_self = "deny"
verbose_file_reads = "deny" verbose_file_reads = "deny"
str_to_string = "deny" zero_sized_map_values = "deny"
# Pedantic Opt-Outs
inline_always = "allow" # We use this sparsely
struct_field_names = "allow" # Noisy and some items are Bitwarden controlled
large_futures = "allow" # Causes a fail in some Rocket macro's, since we experience no issues, allow it
too_many_lines = "allow" # For now, allow this, good to enable in the future and see if we can refactor
unnecessary_wraps = "allow" # Too much false positives because of Rocket integrations
# We do not use these doc items
doc_link_with_quotes = "allow"
doc_markdown = "allow"
missing_errors_doc = "allow"
missing_panics_doc = "allow"
[lints]
workspace = true

View file

@ -59,22 +59,19 @@ A nearly complete implementation of the Bitwarden Client API is provided, includ
## Usage ## Usage
> [!IMPORTANT] > [!IMPORTANT]
> The web-vault requires the use of HTTPS and a secure context for the [Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API). <br> > Most modern web browsers disallow the use of Web Crypto APIs in insecure contexts. In this case, you might get an error like `Cannot read property 'importKey'`. To solve this problem, you need to access the web vault via HTTPS or localhost.
> That means it will only work if you [enable HTTPS](https://github.com/dani-garcia/vaultwarden/wiki/Enabling-HTTPS). <br> >
> We also suggest to use a [reverse proxy](https://github.com/dani-garcia/vaultwarden/wiki/Proxy-examples). >This can be configured in [Vaultwarden directly](https://github.com/dani-garcia/vaultwarden/wiki/Enabling-HTTPS) or using a third-party reverse proxy ([some examples](https://github.com/dani-garcia/vaultwarden/wiki/Proxy-examples)).
>
The recommended way to install and use Vaultwarden is via our container images which are published to [ghcr.io](https://github.com/dani-garcia/vaultwarden/pkgs/container/vaultwarden), [docker.io](https://hub.docker.com/r/vaultwarden/server) and [quay.io](https://quay.io/repository/vaultwarden/server). >If you have an available domain name, you can get HTTPS certificates with [Let's Encrypt](https://letsencrypt.org/), or you can generate self-signed certificates with utilities like [mkcert](https://github.com/FiloSottile/mkcert). Some proxies automatically do this step, like Caddy or Traefik (see examples linked above).
See [which container image to use](https://github.com/dani-garcia/vaultwarden/wiki/Which-container-image-to-use) for an explanation of the provided tags.
There are also [community driven packages](https://github.com/dani-garcia/vaultwarden/wiki/Third-party-packages) which can be used, but those might be lagging behind the latest version or might deviate in the way Vaultwarden is configured, as described in our [Wiki](https://github.com/dani-garcia/vaultwarden/wiki).
Alternatively, you can also [build Vaultwarden](https://github.com/dani-garcia/vaultwarden/wiki/Building-binary) yourself.
While Vaultwarden is based upon the [Rocket web framework](https://rocket.rs) which has built-in support for TLS our recommendation would be that you setup a reverse proxy (see [proxy examples](https://github.com/dani-garcia/vaultwarden/wiki/Proxy-examples)).
> [!TIP] > [!TIP]
>**For more detailed examples on how to install, use and configure Vaultwarden you can check our [Wiki](https://github.com/dani-garcia/vaultwarden/wiki).** >**For more detailed examples on how to install, use and configure Vaultwarden you can check our [Wiki](https://github.com/dani-garcia/vaultwarden/wiki).**
The main way to use Vaultwarden is via our container images which are published to [ghcr.io](https://github.com/dani-garcia/vaultwarden/pkgs/container/vaultwarden), [docker.io](https://hub.docker.com/r/vaultwarden/server) and [quay.io](https://quay.io/repository/vaultwarden/server).
There are also [community driven packages](https://github.com/dani-garcia/vaultwarden/wiki/Third-party-packages) which can be used, but those might be lagging behind the latest version or might deviate in the way Vaultwarden is configured, as described in our [Wiki](https://github.com/dani-garcia/vaultwarden/wiki).
### Docker/Podman CLI ### Docker/Podman CLI
Pull the container image and mount a volume from the host for persistent storage.<br> Pull the container image and mount a volume from the host for persistent storage.<br>
@ -86,7 +83,7 @@ docker run --detach --name vaultwarden \
--env DOMAIN="https://vw.domain.tld" \ --env DOMAIN="https://vw.domain.tld" \
--volume /vw-data/:/data/ \ --volume /vw-data/:/data/ \
--restart unless-stopped \ --restart unless-stopped \
--publish 127.0.0.1:8000:80 \ --publish 80:80 \
vaultwarden/server:latest vaultwarden/server:latest
``` ```
@ -107,7 +104,7 @@ services:
volumes: volumes:
- ./vw-data/:/data/ - ./vw-data/:/data/
ports: ports:
- 127.0.0.1:8000:80 - 80:80
``` ```
<br> <br>

View file

@ -21,7 +21,7 @@ notify us. We welcome working with you to resolve the issue promptly. Thanks in
The following bug classes are out-of scope: The following bug classes are out-of scope:
- Bugs that are already reported on Vaultwarden's issue tracker (https://github.com/dani-garcia/vaultwarden/issues) - Bugs that are already reported on Vaultwarden's issue tracker (https://github.com/dani-garcia/vaultwarden/issues)
- Bugs that are not part of Vaultwarden, like on the web-vault or mobile and desktop clients. These issues need to be reported in the respective project issue tracker at https://github.com/bitwarden to which we are not associated - Bugs that are not part of Vaultwarden, like on the the web-vault or mobile and desktop clients. These issues need to be reported in the respective project issue tracker at https://github.com/bitwarden to which we are not associated
- Issues in an upstream software dependency (ex: Rust, or External Libraries) which are already reported to the upstream maintainer - Issues in an upstream software dependency (ex: Rust, or External Libraries) which are already reported to the upstream maintainer
- Attacks requiring physical access to a user's device - Attacks requiring physical access to a user's device
- Issues related to software or protocols not under Vaultwarden's control - Issues related to software or protocols not under Vaultwarden's control

View file

@ -1,27 +1,28 @@
use std::{env, io::Error, process::Command}; use std::env;
use std::process::Command;
fn main() { fn main() {
// These allow using e.g. #[cfg(mysql)] instead of #[cfg(feature = "mysql")], which helps when trying to add them through macros // This allow using #[cfg(sqlite)] instead of #[cfg(feature = "sqlite")], which helps when trying to add them through macros
#[cfg(feature = "sqlite_system")] // The `sqlite` feature implies this one. #[cfg(feature = "sqlite")]
println!("cargo:rustc-cfg=sqlite"); println!("cargo:rustc-cfg=sqlite");
#[cfg(feature = "mysql")] #[cfg(feature = "mysql")]
println!("cargo:rustc-cfg=mysql"); println!("cargo:rustc-cfg=mysql");
#[cfg(feature = "postgresql")] #[cfg(feature = "postgresql")]
println!("cargo:rustc-cfg=postgresql"); println!("cargo:rustc-cfg=postgresql");
#[cfg(not(any(feature = "sqlite_system", feature = "mysql", feature = "postgresql")))] #[cfg(feature = "query_logger")]
println!("cargo:rustc-cfg=query_logger");
#[cfg(not(any(feature = "sqlite", feature = "mysql", feature = "postgresql")))]
compile_error!( compile_error!(
"You need to enable one DB backend. To build with previous defaults do: cargo build --features sqlite" "You need to enable one DB backend. To build with previous defaults do: cargo build --features sqlite"
); );
#[cfg(feature = "s3")]
println!("cargo:rustc-cfg=s3");
// Use check-cfg to let cargo know which cfg's we define, // Use check-cfg to let cargo know which cfg's we define,
// and avoid warnings when they are used in the code. // and avoid warnings when they are used in the code.
println!("cargo::rustc-check-cfg=cfg(sqlite)"); println!("cargo::rustc-check-cfg=cfg(sqlite)");
println!("cargo::rustc-check-cfg=cfg(mysql)"); println!("cargo::rustc-check-cfg=cfg(mysql)");
println!("cargo::rustc-check-cfg=cfg(postgresql)"); println!("cargo::rustc-check-cfg=cfg(postgresql)");
println!("cargo::rustc-check-cfg=cfg(s3)"); println!("cargo::rustc-check-cfg=cfg(query_logger)");
// Rerun when these paths are changed. // Rerun when these paths are changed.
// Someone could have checked-out a tag or specific commit, but no other files changed. // Someone could have checked-out a tag or specific commit, but no other files changed.
@ -30,6 +31,9 @@ fn main() {
println!("cargo:rerun-if-changed=.git/index"); println!("cargo:rerun-if-changed=.git/index");
println!("cargo:rerun-if-changed=.git/refs/tags"); println!("cargo:rerun-if-changed=.git/refs/tags");
#[cfg(all(not(debug_assertions), feature = "query_logger"))]
compile_error!("Query Logging is only allowed during development, it is not intended for production usage!");
// Support $BWRS_VERSION for legacy compatibility, but default to $VW_VERSION. // Support $BWRS_VERSION for legacy compatibility, but default to $VW_VERSION.
// If neither exist, read from git. // If neither exist, read from git.
let maybe_vaultwarden_version = let maybe_vaultwarden_version =
@ -41,12 +45,13 @@ fn main() {
} }
} }
fn run(args: &[&str]) -> Result<String, Error> { fn run(args: &[&str]) -> Result<String, std::io::Error> {
let out = Command::new(args[0]).args(&args[1..]).output()?; let out = Command::new(args[0]).args(&args[1..]).output()?;
if !out.status.success() { if !out.status.success() {
return Err(Error::other("Command not successful")); use std::io::{Error, ErrorKind};
return Err(Error::new(ErrorKind::Other, "Command not successful"));
} }
Ok(String::from_utf8(out.stdout).unwrap().trim().to_owned()) Ok(String::from_utf8(out.stdout).unwrap().trim().to_string())
} }
/// This method reads info from Git, namely tags, branch, and revision /// This method reads info from Git, namely tags, branch, and revision
@ -56,7 +61,7 @@ fn run(args: &[&str]) -> Result<String, Error> {
/// - `env!("GIT_BRANCH")` /// - `env!("GIT_BRANCH")`
/// - `env!("GIT_REV")` /// - `env!("GIT_REV")`
/// - `env!("VW_VERSION")` /// - `env!("VW_VERSION")`
fn version_from_git_info() -> Result<String, Error> { fn version_from_git_info() -> Result<String, std::io::Error> {
// The exact tag for the current commit, can be empty when // The exact tag for the current commit, can be empty when
// the current commit doesn't have an associated tag // the current commit doesn't have an associated tag
let exact_tag = run(&["git", "describe", "--abbrev=0", "--tags", "--exact-match"]).ok(); let exact_tag = run(&["git", "describe", "--abbrev=0", "--tags", "--exact-match"]).ok();

Some files were not shown because too many files have changed in this diff Show more