From 7f29d52bd207036fce807e6eb8649607ca6c9740 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20L=C3=BCtzner?= Date: Thu, 1 Aug 2024 12:21:36 +0200 Subject: [PATCH] prompt for password if none is given This shows a password prompt, if neither the `--password-file` or `--password-command` option is given **and** the `RESTIC_PASSWORD` env variable is unset. There's no way to hand over the password to restic as a CLI parameter, so we use the `RESTIC_PASSWORD` env variable under the hood to set it instead. The env variable is only valid for the restic process we call internally, so the next time redu is run, it'll prompt for the password again. --- Cargo.lock | 22 ++++++++++++++++++++++ Cargo.toml | 1 + src/args.rs | 21 +++++++++++++++------ 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 15d4c8e..a711fb6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -948,6 +948,7 @@ dependencies = [ "nix", "rand", "ratatui", + "rpassword", "rusqlite", "scopeguard", "serde", @@ -986,6 +987,27 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +[[package]] +name = "rpassword" +version = "7.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80472be3c897911d0137b2d2b9055faf6eeac5b14e324073d83bc17b191d7e3f" +dependencies = [ + "libc", + "rtoolbox", + "windows-sys 0.48.0", +] + +[[package]] +name = "rtoolbox" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c247d24e63230cdb56463ae328478bd5eac8b8faa8c69461a77e8e323afac90e" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "rusqlite" version = "0.32.1" diff --git a/Cargo.toml b/Cargo.toml index 5e42a4e..0a0680f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,7 @@ ratatui = { version = "0.27", features = [ "unstable-rendered-line-info", "unstable-widget-ref", ] } +rpassword = "7.3.1" rusqlite = { version = "0.32", features = ["bundled", "functions", "trace"] } scopeguard = "1" serde = { version = "1", features = ["derive"] } diff --git a/src/args.rs b/src/args.rs index 0815b73..23996cd 100644 --- a/src/args.rs +++ b/src/args.rs @@ -1,6 +1,9 @@ +use std::{env, io::Write}; + use clap::{ArgGroup, Parser}; use log::LevelFilter; use redu::restic::Repository; +use rpassword::read_password; use crate::restic::Password; @@ -33,7 +36,11 @@ impl Args { } else if let Some(str) = cli.restic_password { Password::Plain(str) } else { - unreachable!("Error in Config: neither password_command nor password_file found. Please open an issue if you see this.") + let pwd = Self::read_password_from_stdin(); + // There's no way to hand over the password to restic directly, so we use the env + // variable instead. + env::set_var("RESTIC_PASSWORD", &pwd); + Password::Plain(pwd) }, parallelism: cli.parallelism, log_level: match cli.verbose { @@ -44,6 +51,13 @@ impl Args { no_cache: cli.no_cache, } } + + fn read_password_from_stdin() -> String { + print!("enter password for repository: "); + // Console output is line buffered, so we need to flush to show the message. + _ = std::io::stdout().flush(); + read_password().unwrap() + } } /// This is like ncdu for a restic respository. @@ -83,11 +97,6 @@ impl Args { .required(true) .args(["repo", "repository_file"]), ))] -#[command(group( - ArgGroup::new("password") - .required(true) - .args(["password_command", "password_file", "restic_password"]), -))] struct Cli { #[arg(short = 'r', long, env = "RESTIC_REPOSITORY")] repo: Option,