vw_small

Hardened fork of Vaultwarden (https://github.com/dani-garcia/vaultwarden) with fewer features.
git clone https://git.philomathiclife.com/repos/vw_small
Log | Files | Refs | README

commit 95fc88ae5bef5f4d1e9a8da4f5de7c955fb75a19
parent a82c04910f259fd0296085cc9aa9280df5881a87
Author: BlackDex <black.dex@gmail.com>
Date:   Mon,  5 Apr 2021 15:09:16 +0200

Some admin interface updates.

- Fixed bug when web-vault is disabled.
- Updated sql-server version check to be simpler thx to @weiznich ( https://github.com/dani-garcia/bitwarden_rs/pull/1548#discussion_r604767196 )
- Use `VACUUM INTO` to create a SQLite backup instead of using the external sqlite3 application.
  - This also removes the dependancy of having the sqlite3 packages installed on the final image unnecessary, and thus removed it.
- Updated backup filename to also have the current time.
- Add specific bitwarden_rs web-vault version check (to match letter patched versions)
  Will work when https://github.com/dani-garcia/bw_web_builds/pull/33 is build (But still works without it also).

Diffstat:
Mdocker/Dockerfile.j2 | 4----
Mdocker/amd64/Dockerfile | 1-
Mdocker/amd64/Dockerfile.alpine | 1-
Mdocker/arm64/Dockerfile | 1-
Mdocker/armv6/Dockerfile | 1-
Mdocker/armv7/Dockerfile | 1-
Mdocker/armv7/Dockerfile.alpine | 1-
Msrc/api/admin.rs | 27++++++++++++++++++---------
Msrc/db/mod.rs | 56++++++++++++++++++++------------------------------------
Msrc/static/templates/admin/diagnostics.hbs | 13++++++++++++-
10 files changed, 50 insertions(+), 56 deletions(-)

diff --git a/docker/Dockerfile.j2 b/docker/Dockerfile.j2 @@ -215,9 +215,6 @@ RUN apk add --no-cache \ openssl \ curl \ dumb-init \ -{% if "sqlite" in features %} - sqlite \ -{% endif %} {% if "mysql" in features %} mariadb-connector-c \ {% endif %} @@ -232,7 +229,6 @@ RUN apt-get update && apt-get install -y \ ca-certificates \ curl \ dumb-init \ - sqlite3 \ libmariadb-dev-compat \ libpq5 \ && rm -rf /var/lib/apt/lists/* diff --git a/docker/amd64/Dockerfile b/docker/amd64/Dockerfile @@ -86,7 +86,6 @@ RUN apt-get update && apt-get install -y \ ca-certificates \ curl \ dumb-init \ - sqlite3 \ libmariadb-dev-compat \ libpq5 \ && rm -rf /var/lib/apt/lists/* diff --git a/docker/amd64/Dockerfile.alpine b/docker/amd64/Dockerfile.alpine @@ -82,7 +82,6 @@ RUN apk add --no-cache \ openssl \ curl \ dumb-init \ - sqlite \ postgresql-libs \ ca-certificates diff --git a/docker/arm64/Dockerfile b/docker/arm64/Dockerfile @@ -129,7 +129,6 @@ RUN apt-get update && apt-get install -y \ ca-certificates \ curl \ dumb-init \ - sqlite3 \ libmariadb-dev-compat \ libpq5 \ && rm -rf /var/lib/apt/lists/* diff --git a/docker/armv6/Dockerfile b/docker/armv6/Dockerfile @@ -129,7 +129,6 @@ RUN apt-get update && apt-get install -y \ ca-certificates \ curl \ dumb-init \ - sqlite3 \ libmariadb-dev-compat \ libpq5 \ && rm -rf /var/lib/apt/lists/* diff --git a/docker/armv7/Dockerfile b/docker/armv7/Dockerfile @@ -129,7 +129,6 @@ RUN apt-get update && apt-get install -y \ ca-certificates \ curl \ dumb-init \ - sqlite3 \ libmariadb-dev-compat \ libpq5 \ && rm -rf /var/lib/apt/lists/* diff --git a/docker/armv7/Dockerfile.alpine b/docker/armv7/Dockerfile.alpine @@ -86,7 +86,6 @@ RUN apk add --no-cache \ openssl \ curl \ dumb-init \ - sqlite \ ca-certificates RUN mkdir /data diff --git a/src/api/admin.rs b/src/api/admin.rs @@ -1,7 +1,7 @@ use once_cell::sync::Lazy; use serde::de::DeserializeOwned; use serde_json::Value; -use std::{env, process::Command, time::Duration}; +use std::{env, time::Duration}; use reqwest::{blocking::Client, header::USER_AGENT}; use rocket::{ @@ -68,7 +68,6 @@ static CAN_BACKUP: Lazy<bool> = Lazy::new(|| { DbConnType::from_url(&CONFIG.database_url()) .map(|t| t == DbConnType::sqlite) .unwrap_or(false) - && Command::new("sqlite3").arg("-version").status().is_ok() }); #[get("/")] @@ -502,9 +501,17 @@ fn diagnostics(_token: AdminToken, ip_header: IpHeader, conn: DbConn) -> ApiResu use std::net::ToSocketAddrs; // Get current running versions - let vault_version_path = format!("{}/{}", CONFIG.web_vault_folder(), "version.json"); - let vault_version_str = read_file_string(&vault_version_path)?; - let web_vault_version: WebVaultVersion = serde_json::from_str(&vault_version_str)?; + let web_vault_version: WebVaultVersion = match read_file_string(&format!("{}/{}", CONFIG.web_vault_folder(), "bwrs-version.json")) { + Ok(s) => serde_json::from_str(&s)?, + _ => { + match read_file_string(&format!("{}/{}", CONFIG.web_vault_folder(), "version.json")) { + Ok(s) => serde_json::from_str(&s)?, + _ => { + WebVaultVersion{version: String::from("Version file missing")} + }, + } + }, + }; // Execute some environment checks let running_within_docker = is_running_in_docker(); @@ -557,9 +564,10 @@ fn diagnostics(_token: AdminToken, ip_header: IpHeader, conn: DbConn) -> ApiResu let diagnostics_json = json!({ "dns_resolved": dns_resolved, - "web_vault_version": web_vault_version.version, "latest_release": latest_release, "latest_commit": latest_commit, + "web_vault_enabled": &CONFIG.web_vault_enabled(), + "web_vault_version": web_vault_version.version, "latest_web_build": latest_web_build, "running_within_docker": running_within_docker, "has_http_access": has_http_access, @@ -571,6 +579,7 @@ fn diagnostics(_token: AdminToken, ip_header: IpHeader, conn: DbConn) -> ApiResu "db_type": *DB_TYPE, "db_version": get_sql_server_version(&conn), "admin_url": format!("{}/diagnostics", admin_url(Referer(None))), + "server_time_local": Local::now().format("%Y-%m-%d %H:%M:%S %Z").to_string(), "server_time": Utc::now().format("%Y-%m-%d %H:%M:%S UTC").to_string(), // Run the date/time check as the last item to minimize the difference }); @@ -596,11 +605,11 @@ fn delete_config(_token: AdminToken) -> EmptyResult { } #[post("/config/backup_db")] -fn backup_db(_token: AdminToken) -> EmptyResult { +fn backup_db(_token: AdminToken, conn: DbConn) -> EmptyResult { if *CAN_BACKUP { - backup_database() + backup_database(&conn) } else { - err!("Can't back up current DB (either it's not SQLite or the 'sqlite' binary is not present)"); + err!("Can't back up current DB (Only SQLite supports this feature)"); } } diff --git a/src/db/mod.rs b/src/db/mod.rs @@ -1,5 +1,3 @@ -use std::process::Command; - use chrono::prelude::*; use diesel::r2d2::{ConnectionManager, Pool, PooledConnection}; use rocket::{ @@ -144,6 +142,7 @@ macro_rules! db_run { // Different code for each db ( @raw $conn:ident: $( $($db:ident),+ $body:block )+ ) => { #[allow(unused)] use diesel::prelude::*; + #[allow(unused_variables)] match $conn { $($( #[cfg($db)] @@ -221,21 +220,21 @@ macro_rules! db_object { // Reexport the models, needs to be after the macros are defined so it can access them pub mod models; -/// Creates a back-up of the database using sqlite3 -pub fn backup_database() -> Result<(), Error> { - use std::path::Path; - let db_url = CONFIG.database_url(); - let db_path = Path::new(&db_url).parent().unwrap(); - - let now: DateTime<Utc> = Utc::now(); - let file_date = now.format("%Y%m%d").to_string(); - let backup_command: String = format!("{}{}{}", ".backup 'db_", file_date, ".sqlite3'"); - - Command::new("sqlite3") - .current_dir(db_path) - .args(&["db.sqlite3", &backup_command]) - .output() - .expect("Can't open database, sqlite3 is not available, make sure it's installed and available on the PATH"); +/// Creates a back-up of the sqlite database +/// MySQL/MariaDB and PostgreSQL are not supported. +pub fn backup_database(conn: &DbConn) -> Result<(), Error> { + db_run! {@raw conn: + postgresql, mysql { + err!("PostgreSQL and MySQL/MariaDB do not support this backup feature"); + } + sqlite { + use std::path::Path; + let db_url = CONFIG.database_url(); + let db_path = Path::new(&db_url).parent().unwrap().to_string_lossy(); + let file_date = Utc::now().format("%Y%m%d_%H%M%S").to_string(); + diesel::sql_query(format!("VACUUM INTO '{}/db_{}.sqlite3'", db_path, file_date)).execute(conn)?; + } + } Ok(()) } @@ -243,29 +242,14 @@ pub fn backup_database() -> Result<(), Error> { /// Get the SQL Server version pub fn get_sql_server_version(conn: &DbConn) -> String { - use diesel::sql_types::Text; - #[derive(QueryableByName)] - struct SqlVersion { - #[sql_type = "Text"] - version: String, - } - db_run! {@raw conn: postgresql, mysql { - match diesel::sql_query("SELECT version() AS version;").get_result::<SqlVersion>(conn).ok() { - Some(v) => { - v.version - }, - _ => "Unknown".to_string() - } + no_arg_sql_function!(version, diesel::sql_types::Text); + diesel::select(version).get_result::<String>(conn).unwrap_or_else(|_| "Unknown".to_string()) } sqlite { - match diesel::sql_query("SELECT sqlite_version() AS version;").get_result::<SqlVersion>(conn).ok() { - Some(v) => { - v.version - }, - _ => "Unknown".to_string() - } + no_arg_sql_function!(sqlite_version, diesel::sql_types::Text); + diesel::select(sqlite_version).get_result::<String>(conn).unwrap_or_else(|_| "Unknown".to_string()) } } } diff --git a/src/static/templates/admin/diagnostics.hbs b/src/static/templates/admin/diagnostics.hbs @@ -20,6 +20,7 @@ <dd class="col-sm-7"> <span id="server-latest">{{diagnostics.latest_release}}<span id="server-latest-commit" class="d-none">-{{diagnostics.latest_commit}}</span></span> </dd> + {{#if diagnostics.web_vault_enabled}} <dt class="col-sm-5">Web Installed <span class="badge badge-success d-none" id="web-success" title="Latest version is installed.">Ok</span> <span class="badge badge-warning d-none" id="web-warning" title="There seems to be an update available.">Update</span> @@ -35,6 +36,13 @@ <span id="web-latest">{{diagnostics.latest_web_build}}</span> </dd> {{/unless}} + {{/if}} + {{#unless diagnostics.web_vault_enabled}} + <dt class="col-sm-5">Web Installed</dt> + <dd class="col-sm-7"> + <span id="web-installed">Web Vault is disabled</span> + </dd> + {{/unless}} <dt class="col-sm-5">Database</dt> <dd class="col-sm-7"> <span><b>{{diagnostics.db_type}}:</b> {{diagnostics.db_version}}</span> @@ -118,7 +126,10 @@ <dd class="col-sm-7"> <span id="dns-resolved">{{diagnostics.dns_resolved}}</span> </dd> - + <dt class="col-sm-5">Date & Time (Local)</dt> + <dd class="col-sm-7"> + <span><b>Server:</b> {{diagnostics.server_time_local}}</span> + </dd> <dt class="col-sm-5">Date & Time (UTC) <span class="badge badge-success d-none" id="time-success" title="Time offsets seem to be correct.">Ok</span> <span class="badge badge-danger d-none" id="time-warning" title="Time offsets are too mouch at drift.">Error</span>