From 76c8907a4cac4ef1eb04acd343bf156356aa2aa3 Mon Sep 17 00:00:00 2001 From: Dennis Eriksen Date: Fri, 15 Nov 2019 22:39:07 +0100 Subject: bitwarden_rs now builds. Hopefully just need to configure it now. --- .env.template | 174 --------------------- bitwarden_rs.env | 174 +++++++++++++++++++++ mkosi.build | 57 ++++--- mkosi.default | 6 +- mkosi.extra/etc/apt/apt.conf.d/20auto-upgrades | 9 ++ .../etc/apt/apt.conf.d/50unattended-upgrades | 34 ++++ .../etc/systemd/system/bitwarden_rs.service | 29 ++++ mkosi.nspawn | 3 - mkosi.postinst | 12 +- 9 files changed, 282 insertions(+), 216 deletions(-) delete mode 100644 .env.template create mode 100644 bitwarden_rs.env create mode 100644 mkosi.extra/etc/apt/apt.conf.d/20auto-upgrades create mode 100644 mkosi.extra/etc/apt/apt.conf.d/50unattended-upgrades create mode 100644 mkosi.extra/etc/systemd/system/bitwarden_rs.service diff --git a/.env.template b/.env.template deleted file mode 100644 index 79b93f4..0000000 --- a/.env.template +++ /dev/null @@ -1,174 +0,0 @@ -## Bitwarden_RS Configuration File -## Uncomment any of the following lines to change the defaults - -## Main data folder -# DATA_FOLDER=data - -## Database URL -## When using SQLite, this is the path to the DB file, default to %DATA_FOLDER%/db.sqlite3 -## When using MySQL, this it is the URL to the DB, including username and password: -## Format: mysql://[user[:password]@]host/database_name -# DATABASE_URL=data/db.sqlite3 - -## Individual folders, these override %DATA_FOLDER% -# RSA_KEY_FILENAME=data/rsa_key -# ICON_CACHE_FOLDER=data/icon_cache -# ATTACHMENTS_FOLDER=data/attachments - -## Templates data folder, by default uses embedded templates -## Check source code to see the format -# TEMPLATES_FOLDER=/path/to/templates -## Automatically reload the templates for every request, slow, use only for development -# RELOAD_TEMPLATES=false - -## Cache time-to-live for successfully obtained icons, in seconds (0 is "forever") -# ICON_CACHE_TTL=2592000 -## Cache time-to-live for icons which weren't available, in seconds (0 is "forever") -# ICON_CACHE_NEGTTL=259200 - -## Web vault settings -# WEB_VAULT_FOLDER=web-vault/ -# WEB_VAULT_ENABLED=true - -## Enables websocket notifications -# WEBSOCKET_ENABLED=false - -## Controls the WebSocket server address and port -# WEBSOCKET_ADDRESS=0.0.0.0 -# WEBSOCKET_PORT=3012 - -## Enable extended logging -## This shows timestamps and allows logging to file and to syslog -### To enable logging to file, use the LOG_FILE env variable -### To enable syslog, use the USE_SYSLOG env variable -# EXTENDED_LOGGING=true - -## Logging to file -## This requires extended logging -## It's recommended to also set 'ROCKET_CLI_COLORS=off' -# LOG_FILE=/path/to/log - -## Logging to Syslog -## This requires extended logging -## It's recommended to also set 'ROCKET_CLI_COLORS=off' -# USE_SYSLOG=false - -## Log level -## Change the verbosity of the log output -## Valid values are "trace", "debug", "info", "warn", "error" and "off" -## This requires extended logging -# LOG_LEVEL=Info - -## Enable WAL for the DB -## Set to false to avoid enabling WAL during startup. -## Note that if the DB already has WAL enabled, you will also need to disable WAL in the DB, -## this setting only prevents bitwarden_rs from automatically enabling it on start. -## Please read project wiki page about this setting first before changing the value as it can -## cause performance degradation or might render the service unable to start. -# ENABLE_DB_WAL=true - -## Disable icon downloading -## Set to true to disable icon downloading, this would still serve icons from $ICON_CACHE_FOLDER, -## but it won't produce any external network request. Needs to set $ICON_CACHE_TTL to 0, -## otherwise it will delete them and they won't be downloaded again. -# DISABLE_ICON_DOWNLOAD=false - -## Icon download timeout -## Configure the timeout value when downloading the favicons. -## The default is 10 seconds, but this could be to low on slower network connections -# ICON_DOWNLOAD_TIMEOUT=10 - -## Icon blacklist Regex -## Any domains or IPs that match this regex won't be fetched by the icon service. -## Useful to hide other servers in the local network. Check the WIKI for more details -# ICON_BLACKLIST_REGEX=192\.168\.1\.[0-9].*^ - -## Any IP which is not defined as a global IP will be blacklisted. -## Usefull to secure your internal environment: See https://en.wikipedia.org/wiki/Reserved_IP_addresses for a list of IPs which it will block -# ICON_BLACKLIST_NON_GLOBAL_IPS=true - -## Disable 2FA remember -## Enabling this would force the users to use a second factor to login every time. -## Note that the checkbox would still be present, but ignored. -# DISABLE_2FA_REMEMBER=false - -## Controls if new users can register -# SIGNUPS_ALLOWED=true - -## Token for the admin interface, preferably use a long random string -## One option is to use 'openssl rand -base64 48' -## If not set, the admin panel is disabled -# ADMIN_TOKEN=Vy2VyYTTsKPv8W5aEOWUbB/Bt3DEKePbHmI4m9VcemUMS2rEviDowNAFqYi1xjmp - -## Enable this to bypass the admin panel security. This option is only -## meant to be used with the use of a separate auth layer in front -# DISABLE_ADMIN_TOKEN=false - -## Invitations org admins to invite users, even when signups are disabled -# INVITATIONS_ALLOWED=true - -## Controls the PBBKDF password iterations to apply on the server -## The change only applies when the password is changed -# PASSWORD_ITERATIONS=100000 - -## Whether password hint should be sent into the error response when the client request it -# SHOW_PASSWORD_HINT=true - -## Domain settings -## The domain must match the address from where you access the server -## It's recommended to configure this value, otherwise certain functionality might not work, -## like attachment downloads, email links and U2F. -## For U2F to work, the server must use HTTPS, you can use Let's Encrypt for free certs -# DOMAIN=https://bw.domain.tld:8443 - -## Yubico (Yubikey) Settings -## Set your Client ID and Secret Key for Yubikey OTP -## You can generate it here: https://upgrade.yubico.com/getapikey/ -## You can optionally specify a custom OTP server -# YUBICO_CLIENT_ID=11111 -# YUBICO_SECRET_KEY=AAAAAAAAAAAAAAAAAAAAAAAA -# YUBICO_SERVER=http://yourdomain.com/wsapi/2.0/verify - -## Duo Settings -## You need to configure all options to enable global Duo support, otherwise users would need to configure it themselves -## Create an account and protect an application as mentioned in this link (only the first step, not the rest): -## https://help.bitwarden.com/article/setup-two-step-login-duo/#create-a-duo-security-account -## Then set the following options, based on the values obtained from the last step: -# DUO_IKEY= -# DUO_SKEY= -# DUO_HOST= -## 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. - -## Authenticator Settings -## Disable authenticator time drifted codes to be valid. -## TOTP codes of the previous and next 30 seconds will be invalid -## -## 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. -## 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. -## 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. -# AUTHENTICATOR_DISABLE_TIME_DRIFT = false - -## Rocket specific settings, check Rocket documentation to learn more -# ROCKET_ENV=staging -# ROCKET_ADDRESS=0.0.0.0 # Enable this to test mobile app -# ROCKET_PORT=8000 -# ROCKET_TLS={certs="/path/to/certs.pem",key="/path/to/key.pem"} - -## Mail specific settings, set SMTP_HOST and SMTP_FROM to enable the mail service. -## To make sure the email links are pointing to the correct host, set the DOMAIN variable. -## Note: if SMTP_USERNAME is specified, SMTP_PASSWORD is mandatory -# SMTP_HOST=smtp.domain.tld -# SMTP_FROM=bitwarden-rs@domain.tld -# SMTP_FROM_NAME=Bitwarden_RS -# SMTP_PORT=587 -# SMTP_SSL=true -# SMTP_USERNAME=username -# SMTP_PASSWORD=password -# SMTP_AUTH_MECHANISM="Plain" -# SMTP_TIMEOUT=15 - -# vim: syntax=ini diff --git a/bitwarden_rs.env b/bitwarden_rs.env new file mode 100644 index 0000000..79b93f4 --- /dev/null +++ b/bitwarden_rs.env @@ -0,0 +1,174 @@ +## Bitwarden_RS Configuration File +## Uncomment any of the following lines to change the defaults + +## Main data folder +# DATA_FOLDER=data + +## Database URL +## When using SQLite, this is the path to the DB file, default to %DATA_FOLDER%/db.sqlite3 +## When using MySQL, this it is the URL to the DB, including username and password: +## Format: mysql://[user[:password]@]host/database_name +# DATABASE_URL=data/db.sqlite3 + +## Individual folders, these override %DATA_FOLDER% +# RSA_KEY_FILENAME=data/rsa_key +# ICON_CACHE_FOLDER=data/icon_cache +# ATTACHMENTS_FOLDER=data/attachments + +## Templates data folder, by default uses embedded templates +## Check source code to see the format +# TEMPLATES_FOLDER=/path/to/templates +## Automatically reload the templates for every request, slow, use only for development +# RELOAD_TEMPLATES=false + +## Cache time-to-live for successfully obtained icons, in seconds (0 is "forever") +# ICON_CACHE_TTL=2592000 +## Cache time-to-live for icons which weren't available, in seconds (0 is "forever") +# ICON_CACHE_NEGTTL=259200 + +## Web vault settings +# WEB_VAULT_FOLDER=web-vault/ +# WEB_VAULT_ENABLED=true + +## Enables websocket notifications +# WEBSOCKET_ENABLED=false + +## Controls the WebSocket server address and port +# WEBSOCKET_ADDRESS=0.0.0.0 +# WEBSOCKET_PORT=3012 + +## Enable extended logging +## This shows timestamps and allows logging to file and to syslog +### To enable logging to file, use the LOG_FILE env variable +### To enable syslog, use the USE_SYSLOG env variable +# EXTENDED_LOGGING=true + +## Logging to file +## This requires extended logging +## It's recommended to also set 'ROCKET_CLI_COLORS=off' +# LOG_FILE=/path/to/log + +## Logging to Syslog +## This requires extended logging +## It's recommended to also set 'ROCKET_CLI_COLORS=off' +# USE_SYSLOG=false + +## Log level +## Change the verbosity of the log output +## Valid values are "trace", "debug", "info", "warn", "error" and "off" +## This requires extended logging +# LOG_LEVEL=Info + +## Enable WAL for the DB +## Set to false to avoid enabling WAL during startup. +## Note that if the DB already has WAL enabled, you will also need to disable WAL in the DB, +## this setting only prevents bitwarden_rs from automatically enabling it on start. +## Please read project wiki page about this setting first before changing the value as it can +## cause performance degradation or might render the service unable to start. +# ENABLE_DB_WAL=true + +## Disable icon downloading +## Set to true to disable icon downloading, this would still serve icons from $ICON_CACHE_FOLDER, +## but it won't produce any external network request. Needs to set $ICON_CACHE_TTL to 0, +## otherwise it will delete them and they won't be downloaded again. +# DISABLE_ICON_DOWNLOAD=false + +## Icon download timeout +## Configure the timeout value when downloading the favicons. +## The default is 10 seconds, but this could be to low on slower network connections +# ICON_DOWNLOAD_TIMEOUT=10 + +## Icon blacklist Regex +## Any domains or IPs that match this regex won't be fetched by the icon service. +## Useful to hide other servers in the local network. Check the WIKI for more details +# ICON_BLACKLIST_REGEX=192\.168\.1\.[0-9].*^ + +## Any IP which is not defined as a global IP will be blacklisted. +## Usefull to secure your internal environment: See https://en.wikipedia.org/wiki/Reserved_IP_addresses for a list of IPs which it will block +# ICON_BLACKLIST_NON_GLOBAL_IPS=true + +## Disable 2FA remember +## Enabling this would force the users to use a second factor to login every time. +## Note that the checkbox would still be present, but ignored. +# DISABLE_2FA_REMEMBER=false + +## Controls if new users can register +# SIGNUPS_ALLOWED=true + +## Token for the admin interface, preferably use a long random string +## One option is to use 'openssl rand -base64 48' +## If not set, the admin panel is disabled +# ADMIN_TOKEN=Vy2VyYTTsKPv8W5aEOWUbB/Bt3DEKePbHmI4m9VcemUMS2rEviDowNAFqYi1xjmp + +## Enable this to bypass the admin panel security. This option is only +## meant to be used with the use of a separate auth layer in front +# DISABLE_ADMIN_TOKEN=false + +## Invitations org admins to invite users, even when signups are disabled +# INVITATIONS_ALLOWED=true + +## Controls the PBBKDF password iterations to apply on the server +## The change only applies when the password is changed +# PASSWORD_ITERATIONS=100000 + +## Whether password hint should be sent into the error response when the client request it +# SHOW_PASSWORD_HINT=true + +## Domain settings +## The domain must match the address from where you access the server +## It's recommended to configure this value, otherwise certain functionality might not work, +## like attachment downloads, email links and U2F. +## For U2F to work, the server must use HTTPS, you can use Let's Encrypt for free certs +# DOMAIN=https://bw.domain.tld:8443 + +## Yubico (Yubikey) Settings +## Set your Client ID and Secret Key for Yubikey OTP +## You can generate it here: https://upgrade.yubico.com/getapikey/ +## You can optionally specify a custom OTP server +# YUBICO_CLIENT_ID=11111 +# YUBICO_SECRET_KEY=AAAAAAAAAAAAAAAAAAAAAAAA +# YUBICO_SERVER=http://yourdomain.com/wsapi/2.0/verify + +## Duo Settings +## You need to configure all options to enable global Duo support, otherwise users would need to configure it themselves +## Create an account and protect an application as mentioned in this link (only the first step, not the rest): +## https://help.bitwarden.com/article/setup-two-step-login-duo/#create-a-duo-security-account +## Then set the following options, based on the values obtained from the last step: +# DUO_IKEY= +# DUO_SKEY= +# DUO_HOST= +## 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. + +## Authenticator Settings +## Disable authenticator time drifted codes to be valid. +## TOTP codes of the previous and next 30 seconds will be invalid +## +## 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. +## 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. +## 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. +# AUTHENTICATOR_DISABLE_TIME_DRIFT = false + +## Rocket specific settings, check Rocket documentation to learn more +# ROCKET_ENV=staging +# ROCKET_ADDRESS=0.0.0.0 # Enable this to test mobile app +# ROCKET_PORT=8000 +# ROCKET_TLS={certs="/path/to/certs.pem",key="/path/to/key.pem"} + +## Mail specific settings, set SMTP_HOST and SMTP_FROM to enable the mail service. +## To make sure the email links are pointing to the correct host, set the DOMAIN variable. +## Note: if SMTP_USERNAME is specified, SMTP_PASSWORD is mandatory +# SMTP_HOST=smtp.domain.tld +# SMTP_FROM=bitwarden-rs@domain.tld +# SMTP_FROM_NAME=Bitwarden_RS +# SMTP_PORT=587 +# SMTP_SSL=true +# SMTP_USERNAME=username +# SMTP_PASSWORD=password +# SMTP_AUTH_MECHANISM="Plain" +# SMTP_TIMEOUT=15 + +# vim: syntax=ini diff --git a/mkosi.build b/mkosi.build index fce9cb7..347966e 100755 --- a/mkosi.build +++ b/mkosi.build @@ -1,46 +1,43 @@ #!/bin/sh -export RUSTUP_HOME=/usr/local/rustup \ - CARGO_HOME=/usr/local/cargo \ - PATH=/usr/local/cargo/bin:$PATH \ - RUST_VERSION=1.39.0 - DB=sqlite +export RUSTUP_HOME=/root/.rustup \ + CARGO_HOME=/root/.cargo \ + PATH=/root/.cargo/bin:$PATH \ + RUST_VERSION=1.39.0 \ + DB=postgresql \ VAULT_VERSION=v2.12.0 + +mkdir /root/src && cd /root/src git clone https://github.com/dani-garcia/bitwarden_rs.git -## build vault ## + + +## get vault ## mkdir /root/src/bitwarden_rs/web-vault cd /root/src/bitwarden_rs/web-vault curl -L https://github.com/dani-garcia/bw_web_builds/releases/download/$VAULT_VERSION/bw_web_$VAULT_VERSION.tar.gz | tar xz -ls cd /root/src/bitwarden_rs + + ## Setting up rust for build ## -url="https://static.rust-lang.org/rustup/archive/1.20.2/x86_64-unknown-linux-gnu/rustup-init"; \ -wget "$url"; \ -echo "e68f193542c68ce83c449809d2cad262cc2bbb99640eb47c58fc1dc58cc30add *rustup-init" | sha256sum -c -; \ -chmod +x rustup-init; \ -./rustup-init -y --no-modify-path --profile minimal --default-toolchain $RUST_VERSION; \ -rm rustup-init; \ -chmod -R a+w $RUSTUP_HOME $CARGO_HOME; \ -rustup --version; \ -cargo --version; \ -rustc --version; \ -## building bitwarden_rs ## +wget "https://static.rust-lang.org/rustup/archive/1.20.2/x86_64-unknown-linux-gnu/rustup-init" +echo "e68f193542c68ce83c449809d2cad262cc2bbb99640eb47c58fc1dc58cc30add *rustup-init" | sha256sum -c - +chmod +x rustup-init +./rustup-init -y --no-modify-path --profile minimal --default-toolchain $RUST_VERSION +rm rustup-init +chmod -R a+w $RUSTUP_HOME $CARGO_HOME +rustup --version +cargo --version +rustc --version -cargo new --bin app -cd app -cp -r /root/src/bitwarden_rs/Cargo.* /root/src/bitwarden_rs/rust-toolchain /root/src/bitwarden_rs/build.rs . -cargo build --features $DB --release -#find . -not -path "./target*" -delete -touch src/main.rs -#cargo build --features $DB --release +## building bitwarden_rs ## + +cargo build --features postgresql --release -mkdir /root/src/bitwarden_built -cp /root/src/bitwarden_rs/Rocket.toml /root/src/bitwarden_built/. -cp -r /root/src/bitwarden_rs/web-vault /root/src/bitwarden_built/. -cp -r /root/src/bitwarden_rs/app /root/src/bitwarden_built/. -rm -rf /root/src/bitwarden_rs +## move stuff ## +mv web-vault ${DESTDIR}/ +mv target/release ${DESTDIR}/bitwarden_rs diff --git a/mkosi.default b/mkosi.default index 1c3d422..52c3dfd 100644 --- a/mkosi.default +++ b/mkosi.default @@ -14,8 +14,7 @@ Packages= unattended-upgrades curl locales - openssl - sqlite3 + libpq-dev BuildPackages= git @@ -25,4 +24,5 @@ BuildPackages= wget libssl-dev pkg-config - + libpq-dev + curl diff --git a/mkosi.extra/etc/apt/apt.conf.d/20auto-upgrades b/mkosi.extra/etc/apt/apt.conf.d/20auto-upgrades new file mode 100644 index 0000000..4c725ab --- /dev/null +++ b/mkosi.extra/etc/apt/apt.conf.d/20auto-upgrades @@ -0,0 +1,9 @@ +APT::Periodic::Unattended-Upgrade "1"; + +APT::Periodic::Update-Package-Lists "1"; + + +APT::Periodic::AutocleanInterval "7"; + + + diff --git a/mkosi.extra/etc/apt/apt.conf.d/50unattended-upgrades b/mkosi.extra/etc/apt/apt.conf.d/50unattended-upgrades new file mode 100644 index 0000000..768347b --- /dev/null +++ b/mkosi.extra/etc/apt/apt.conf.d/50unattended-upgrades @@ -0,0 +1,34 @@ +// Unattended-Upgrade::Origins-Pattern controls which packages are +// upgraded. +Unattended-Upgrade::Origins-Pattern { + "origin=Ubuntu,archive=${distro_codename}-security"; + "o=Ubuntu,a=${distro_codename}"; + "o=Ubuntu,a=${distro_codename}-updates"; + "o=Ubuntu,a=${distro_codename}-proposed-updates"; + "o=Ubuntu,n=${distro_codename}-backports"; + }; + +// List of packages to not update (regexp are supported) +Unattended-Upgrade::Package-Blacklist { +}; + + +// Split the upgrade into the smallest possible chunks so that +// they can be interrupted with SIGUSR1. This makes the upgrade +// a bit slower but it has the benefit that shutdown while a upgrade +// is running is possible (with a small delay) +Unattended-Upgrade::MinimalSteps "true"; + + +// Do automatic removal of new unused dependencies after the upgrade +// (equivalent to apt-get autoremove) +Unattended-Upgrade::Remove-Unused-Dependencies "true"; + + +// Do upgrade application even if it requires restart after upgrade +// I.e. "XB-Upgrade-Requires: app-restart" is set in the debian/control file +Unattended-Upgrade::IgnoreAppsRequireRestart "true"; + +// Automatically run "dpkg --force-confold --configure -a". +Unattended-Upgrade::AutoFixInterruptedDpkg "true"; + diff --git a/mkosi.extra/etc/systemd/system/bitwarden_rs.service b/mkosi.extra/etc/systemd/system/bitwarden_rs.service new file mode 100644 index 0000000..54327c2 --- /dev/null +++ b/mkosi.extra/etc/systemd/system/bitwarden_rs.service @@ -0,0 +1,29 @@ +[Unit] +Description=Bitwarden Server (Rust Edition) +Documentation=https://github.com/dani-garcia/bitwarden_rs +After=network.target + +[Service] +# The user/group bitwarden_rs is run under. the working directory (see below) should allow write and read access to this user/group +User=bitwarden_rs +Group=bitwarden_rs +# The location of the .env file for configuration +EnvironmentFile=/etc/bitwarden_rs.env +# The location of the compiled binary +ExecStart=/usr/local/bin/bitwarden_rs +# Set reasonable connection and process limits +LimitNOFILE=1048576 +LimitNPROC=64 +# Isolate bitwarden_rs from the rest of the system +PrivateTmp=true +PrivateDevices=true +ProtectHome=true +ProtectSystem=strict +# Only allow writes to the following directory and set it to the working directory (user and password data are stored here) +WorkingDirectory=/var/lib/bitwarden_rs +ReadWriteDirectories=/var/lib/bitwarden_rs +# Allow bitwarden_rs to bind ports in the range of 0-1024 +AmbientCapabilities=CAP_NET_BIND_SERVICE + +[Install] +WantedBy=multi-user.target diff --git a/mkosi.nspawn b/mkosi.nspawn index 6c9cfa1..d5d3a36 100644 --- a/mkosi.nspawn +++ b/mkosi.nspawn @@ -7,9 +7,6 @@ PrivateUsers=pick [Files] PrivateUsersChown=true -Bind=/root/src/bitwarden_built:/root -Bind=/var/lib/bitwarden:/data - [Network] VirtualEthernet=no diff --git a/mkosi.postinst b/mkosi.postinst index 4fcdfc3..6cd5334 100755 --- a/mkosi.postinst +++ b/mkosi.postinst @@ -1,9 +1,9 @@ #!/bin/sh +mv /bitwarden_rs/bitwarden_rs /usr/local/bin/ -export ROCKET_ENV=staging \ - ROCKET_PORT=8080 \ - ROCKET_WORKERS=10 +mkdir /var/lib/bitwarden_rs +useradd -d /var/lib/bitwarden_rs --system bitwarden_rs +chown -R bitwarden_rs: /var/lib/bitwarden_rs + +systemctl enable bitwarden_rs -mkdir /web-vault -cp -r /root/web-vault/* /web-vault/. || echo "build" -/root/app/target/release/bitwarden_rs || echo "build" -- cgit v1.2.3