feat(cli): add an option to specify the encrypt password in a file

This commit is contained in:
Lukas Krejci
2025-12-17 18:03:00 +01:00
parent c05a8944ef
commit 9b83d5617e
4 changed files with 41 additions and 8 deletions
+22 -4
View File
@@ -19,7 +19,7 @@
use clap::{builder::ValueParser, Parser, ValueEnum};
use std::{collections::HashSet, env, fmt, path::PathBuf, sync::LazyLock};
pub static SETTINGS: LazyLock<Settings> = LazyLock::new(Settings::parse);
pub static SETTINGS: LazyLock<Settings> = LazyLock::new(Settings::init);
#[derive(Debug, Parser)]
#[clap(
@@ -132,11 +132,17 @@ pub struct Settings {
/// bichon encryption password
#[clap(
long,
default_value = "change-this-default-password-now",
env,
help = "Set the encryption password for bichon. ⚠️ Change this default in production!"
help = "Set the encryption password for bichon. Alternatively, you can use --bichon-encrypt-password-file. If both are set, this parameter takes precedence over the file."
)]
pub bichon_encrypt_password: String,
pub bichon_encrypt_password: Option<String>,
#[clap(
long,
env,
help = "The file containing the encryption password. An alternative to --bichon-encrypt-password."
)]
pub bichon_encrypt_password_file: Option<String>,
#[clap(
long,
@@ -217,6 +223,18 @@ pub struct Settings {
pub bichon_sync_concurrency: Option<u16>,
}
impl Settings {
pub fn init() -> Self {
let s = Self::parse();
if s.bichon_encrypt_password.is_none() && s.bichon_encrypt_password_file.is_none() {
panic!(
"One of --bichon_encrypt_password or --bichon_encrypt_password_file has to be set"
);
}
s
}
}
#[derive(Clone, Copy, Debug, PartialEq, ValueEnum)]
pub enum CompressionAlgorithm {
#[clap(name = "none")]
+15 -3
View File
@@ -16,18 +16,30 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
use base64::{engine::general_purpose, Engine as _};
use ring::aead::{Aad, BoundKey, Nonce, NonceSequence, OpeningKey, SealingKey, AES_256_GCM};
use ring::pbkdf2::{self, derive};
use ring::rand::{SecureRandom, SystemRandom};
use std::fs;
use std::num::NonZeroU32;
use std::sync::LazyLock;
use crate::modules::error::code::ErrorCode;
use crate::modules::error::BichonResult;
use crate::modules::settings::cli::SETTINGS;
use crate::raise_error;
static ENCRYPT_PASSWORD: LazyLock<String> =
LazyLock::new(|| match &SETTINGS.bichon_encrypt_password {
Some(p) => p.clone(),
None => {
// unwrap() is safe here, because SETTINGS validates that at least one of the encrypt_password
// fields is set.
fs::read_to_string(SETTINGS.bichon_encrypt_password_file.as_ref().unwrap())
.expect("failed to read the file with the encrypt password")
}
});
struct SingleNonceSequence([u8; 12]);
impl SingleNonceSequence {
@@ -43,12 +55,12 @@ impl NonceSequence for SingleNonceSequence {
}
pub fn encrypt_string(plaintext: &str) -> BichonResult<String> {
internal_encrypt_string(&SETTINGS.bichon_encrypt_password, plaintext)
internal_encrypt_string(&ENCRYPT_PASSWORD, plaintext)
.map_err(|_| raise_error!("Failed to encrypt string.".into(), ErrorCode::InternalError))
}
pub fn decrypt_string(data: &str) -> BichonResult<String> {
internal_decrypt_string(&SETTINGS.bichon_encrypt_password, data).map_err(|_| {
internal_decrypt_string(&ENCRYPT_PASSWORD, data).map_err(|_| {
raise_error!(
"Decryption failed, likely due to incorrect encryption key or corrupted data".into(),
ErrorCode::InternalError