summaryrefslogtreecommitdiff
path: root/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs106
1 files changed, 89 insertions, 17 deletions
diff --git a/src/main.rs b/src/main.rs
index cd17a2f5..dbf527f7 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -118,14 +118,22 @@ async fn main() -> Result<(), Error> {
}
const HELP: &str = "\
- Alternative implementation of the Bitwarden server API written in Rust
+Alternative implementation of the Bitwarden server API written in Rust
- USAGE:
- vaultwarden
+USAGE:
+ vaultwarden [FLAGS|COMMAND]
+
+FLAGS:
+ -h, --help Prints help information
+ -v, --version Prints the app version
+
+COMMAND:
+ hash [--preset {bitwarden|owasp}] Generate an Argon2id PHC ADMIN_TOKEN
+
+PRESETS: m= t= p=
+ bitwarden (default) 64MiB, 3 Iterations, 4 Threads
+ owasp 19MiB, 2 Iterations, 1 Thread
- FLAGS:
- -h, --help Prints help information
- -v, --version Prints the app version
";
pub const VERSION: Option<&str> = option_env!("VW_VERSION");
@@ -142,24 +150,88 @@ fn parse_args() {
println!("vaultwarden {version}");
exit(0);
}
-}
+ if let Some(command) = pargs.subcommand().unwrap_or_default() {
+ if command == "hash" {
+ use argon2::{
+ password_hash::SaltString, Algorithm::Argon2id, Argon2, ParamsBuilder, PasswordHasher, Version::V0x13,
+ };
+
+ let mut argon2_params = ParamsBuilder::new();
+ let preset: Option<String> = pargs.opt_value_from_str(["-p", "--preset"]).unwrap_or_default();
+ let selected_preset;
+ match preset.as_deref() {
+ Some("owasp") => {
+ selected_preset = "owasp";
+ argon2_params.m_cost(19456);
+ argon2_params.t_cost(2);
+ argon2_params.p_cost(1);
+ }
+ _ => {
+ // Bitwarden preset is the default
+ selected_preset = "bitwarden";
+ argon2_params.m_cost(65540);
+ argon2_params.t_cost(3);
+ argon2_params.p_cost(4);
+ }
+ }
+
+ println!("Generate an Argon2id PHC string using the '{selected_preset}' preset:\n");
+
+ let password = rpassword::prompt_password("Password: ").unwrap();
+ if password.len() < 8 {
+ println!("\nPassword must contain at least 8 characters");
+ exit(1);
+ }
+
+ let password_verify = rpassword::prompt_password("Confirm Password: ").unwrap();
+ if password != password_verify {
+ println!("\nPasswords do not match");
+ exit(1);
+ }
+
+ let argon2 = Argon2::new(Argon2id, V0x13, argon2_params.build().unwrap());
+ let salt = SaltString::b64_encode(&crate::crypto::get_random_bytes::<32>()).unwrap();
+
+ let argon2_timer = tokio::time::Instant::now();
+ if let Ok(password_hash) = argon2.hash_password(password.as_bytes(), &salt) {
+ println!(
+ "\n\
+ ADMIN_TOKEN='{password_hash}'\n\n\
+ Generation of the Argon2id PHC string took: {:?}",
+ argon2_timer.elapsed()
+ );
+ } else {
+ error!("Unable to generate Argon2id PHC hash.");
+ exit(1);
+ }
+ }
+ exit(0);
+ }
+}
fn launch_info() {
- println!("/--------------------------------------------------------------------\\");
- println!("| Starting Vaultwarden |");
+ println!(
+ "\
+ /--------------------------------------------------------------------\\\n\
+ | Starting Vaultwarden |"
+ );
if let Some(version) = VERSION {
println!("|{:^68}|", format!("Version {version}"));
}
- println!("|--------------------------------------------------------------------|");
- println!("| This is an *unofficial* Bitwarden implementation, DO NOT use the |");
- println!("| official channels to report bugs/features, regardless of client. |");
- println!("| Send usage/configuration questions or feature requests to: |");
- println!("| https://vaultwarden.discourse.group/ |");
- println!("| Report suspected bugs/issues in the software itself at: |");
- println!("| https://github.com/dani-garcia/vaultwarden/issues/new |");
- println!("\\--------------------------------------------------------------------/\n");
+ println!(
+ "\
+ |--------------------------------------------------------------------|\n\
+ | This is an *unofficial* Bitwarden implementation, DO NOT use the |\n\
+ | official channels to report bugs/features, regardless of client. |\n\
+ | Send usage/configuration questions or feature requests to: |\n\
+ | https://github.com/dani-garcia/vaultwarden/discussions or |\n\
+ | https://vaultwarden.discourse.group/ |\n\
+ | Report suspected bugs/issues in the software itself at: |\n\
+ | https://github.com/dani-garcia/vaultwarden/issues/new |\n\
+ \\--------------------------------------------------------------------/\n"
+ );
}
fn init_logging(level: log::LevelFilter) -> Result<(), fern::InitError> {