Merge pull request #161 from rustic-rs/password-options

Add global options --password and --password-command
This commit is contained in:
aawsome 2022-08-30 14:22:17 +02:00 committed by GitHub
commit 093d6d2fd4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 66 additions and 19 deletions

View File

@ -1,7 +1,7 @@
use std::fmt::Write;
use std::fs::File;
use std::io::BufReader;
use std::path::PathBuf;
use std::path::Path;
use std::process::Command;
use std::time::Duration;
@ -25,25 +25,43 @@ pub fn bytes(b: u64) -> String {
ByteSize(b).to_string_as(true)
}
pub async fn get_key(be: &impl ReadBackend, password_file: Option<PathBuf>) -> Result<Key> {
match password_file {
None => {
for _i in 0..MAX_PASSWORD_RETRIES {
let pass = prompt_password("enter repository password: ")?;
if let Ok(key) = find_key_in_backend(be, &pass, None).await {
ve1!("password is correct");
pub async fn get_key(
be: &impl ReadBackend,
password: Option<&str>,
password_file: Option<&Path>,
password_command: Option<&str>,
) -> Result<Key> {
let password = match (password, password_file, password_command) {
(Some(pwd), _, _) => Some(pwd.to_string()),
(_, Some(file), _) => {
let mut file = BufReader::new(File::open(file)?);
Some(read_password_from_bufread(&mut file)?)
}
(_, _, Some(command)) => {
let mut commands: Vec<_> = command.split(' ').collect();
let output = Command::new(commands[0])
.args(&mut commands[1..])
.output()?;
let mut pwd = BufReader::new(&*output.stdout);
Some(read_password_from_bufread(&mut pwd)?)
}
(None, None, None) => None,
};
for _ in 0..MAX_PASSWORD_RETRIES {
match &password {
// if password is given, directly return the result of find_key_in_backend and don't retry
Some(pass) => return find_key_in_backend(be, pass, None).await,
None => {
// TODO: Differentiate between wrong password and other error!
if let Ok(key) =
find_key_in_backend(be, &prompt_password("enter repository password: ")?, None)
.await
{
return Ok(key);
}
}
bail!("tried too often...aborting!");
}
Some(file) => {
let mut file = BufReader::new(File::open(file)?);
let pass = read_password_from_bufread(&mut file)?;
if let Ok(key) = find_key_in_backend(be, &pass, None).await {
ve1!("password is correct");
return Ok(key);
}
}
}
bail!("incorrect password!");

View File

@ -52,6 +52,15 @@ struct Opts {
)]
repo_hot: Option<String>,
/// Password of the repository - WARNING: Using --password can reveal the password in the process list!
#[clap(
long,
global = true,
env = "RUSTIC_PASSWORD",
help_heading = "GLOBAL OPTIONS"
)]
password: Option<String>,
/// File to read the password from
#[clap(
short,
@ -59,10 +68,21 @@ struct Opts {
global = true,
parse(from_os_str),
env = "RUSTIC_PASSWORD_FILE",
help_heading = "GLOBAL OPTIONS"
help_heading = "GLOBAL OPTIONS",
conflicts_with = "password"
)]
password_file: Option<PathBuf>,
/// Command to read the password from
#[clap(
long,
global = true,
env = "RUSTIC_PASSWORD_COMMAND",
help_heading = "GLOBAL OPTIONS",
conflicts_with_all = &["password", "password-file"],
)]
password_command: Option<String>,
/// Increase verbosity (can be used multiple times)
#[clap(
long,
@ -202,7 +222,16 @@ pub async fn execute() -> Result<()> {
bail!("keys from repo and repo-hot do not match. Aborting.");
}
}
let key = get_key(&be, args.password_file).await?;
let key = get_key(
&be,
args.password.as_deref(),
args.password_file.as_deref(),
args.password_command.as_deref(),
)
.await?;
ve1!("password is correct.");
let dbe = DecryptBackend::new(&be, key.clone());
let config: ConfigFile = dbe.get_file(&config_ids[0]).await?;
match (config.is_hot == Some(true), be_hot.is_some()) {