aboutsummaryrefslogtreecommitdiff
path: root/src/main.rs
diff options
context:
space:
mode:
authorBlackDex <[email protected]>2022-07-19 18:39:42 +0200
committerBlackDex <[email protected]>2022-07-20 13:29:39 +0200
commit9a787dd105edeea5fdb309a50f2b47155937c5ed (patch)
tree003aca0dbcca1e531ad1ee6fe7348047fa4ec7c9 /src/main.rs
parentf1a67663d19013271ebd49f7cd6056f59f6dc3f7 (diff)
downloadvaultwarden-9a787dd105edeea5fdb309a50f2b47155937c5ed.tar.gz
vaultwarden-9a787dd105edeea5fdb309a50f2b47155937c5ed.zip
Fix persistent folder check within containers
The previous persistent folder check worked by checking if a file exists. If you used a bind-mount, then this file is not there. But when using a docker/podman volume those files are copied, and caused the container to not start. This change checks the `/proc/self/mountinfo` for a specific patern to see if the data folder is persistent or not. Fixes #2622
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs48
1 files changed, 43 insertions, 5 deletions
diff --git a/src/main.rs b/src/main.rs
index 20f40bc5..ad47f3c5 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -61,6 +61,11 @@ use std::{
thread,
};
+use tokio::{
+ fs::File,
+ io::{AsyncBufReadExt, BufReader},
+};
+
#[macro_use]
mod error;
mod api;
@@ -89,7 +94,7 @@ async fn main() -> Result<(), Error> {
let extra_debug = matches!(level, LF::Trace | LF::Debug);
- check_data_folder();
+ check_data_folder().await;
check_rsa_keys().unwrap_or_else(|_| {
error!("Error creating keys, exiting...");
exit(1);
@@ -286,7 +291,7 @@ fn create_dir(path: &str, description: &str) {
create_dir_all(path).expect(&err_msg);
}
-fn check_data_folder() {
+async fn check_data_folder() {
let data_folder = &CONFIG.data_folder();
let path = Path::new(data_folder);
if !path.exists() {
@@ -299,9 +304,10 @@ fn check_data_folder() {
exit(1);
}
- let persistent_volume_check_file = format!("{data_folder}/vaultwarden_docker_persistent_volume_check");
- let check_file = Path::new(&persistent_volume_check_file);
- if check_file.exists() && std::env::var("I_REALLY_WANT_VOLATILE_STORAGE").is_err() {
+ if is_running_in_docker()
+ && std::env::var("I_REALLY_WANT_VOLATILE_STORAGE").is_err()
+ && !docker_data_folder_is_persistent(data_folder).await
+ {
error!(
"No persistent volume!\n\
########################################################################################\n\
@@ -314,6 +320,38 @@ fn check_data_folder() {
}
}
+/// Detect when using Docker or Podman the DATA_FOLDER is either a bind-mount or a volume created manually.
+/// If not created manually, then the data will not be persistent.
+/// A none persistent volume in either Docker or Podman is represented by a 64 alphanumerical string.
+/// If we detect this string, we will alert about not having a persistent self defined volume.
+/// This probably means that someone forgot to add `-v /path/to/vaultwarden_data/:/data`
+async fn docker_data_folder_is_persistent(data_folder: &str) -> bool {
+ if let Ok(mountinfo) = File::open("/proc/self/mountinfo").await {
+ // Since there can only be one mountpoint to the DATA_FOLDER
+ // We do a basic check for this mountpoint surrounded by a space.
+ let data_folder_match = if data_folder.starts_with('/') {
+ format!(" {data_folder} ")
+ } else {
+ format!(" /{data_folder} ")
+ };
+ let mut lines = BufReader::new(mountinfo).lines();
+ while let Some(line) = lines.next_line().await.unwrap_or_default() {
+ // Only execute a regex check if we find the base match
+ if line.contains(&data_folder_match) {
+ let re = regex::Regex::new(r"/volumes/[a-z0-9]{64}/_data /").unwrap();
+ if re.is_match(&line) {
+ return false;
+ }
+ // If we did found a match for the mountpoint, but not the regex, then still stop searching.
+ break;
+ }
+ }
+ }
+ // In all other cases, just assume a true.
+ // This is just an informative check to try and prevent data loss.
+ true
+}
+
fn check_rsa_keys() -> Result<(), crate::error::Error> {
// If the RSA keys don't exist, try to create them
let priv_path = CONFIG.private_rsa_key();