dls: add password hash function

This commit is contained in:
Mikaël Cluseau
2026-03-16 11:06:19 +01:00
parent 4b1edb2a55
commit 4619899e65
6 changed files with 216 additions and 647 deletions

804
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -28,10 +28,12 @@ hex = "0.4.3"
human-units = "0.5.3"
log = "0.4.27"
lz4 = "1.28.1"
nix = { version = "0.30.1", features = ["user"] }
nix = { version = "0.31.2", features = ["user"] }
openssl = "0.10.73"
page_size = "0.6.0"
reqwest = { version = "0.13.1", features = ["json", "stream", "native-tls", "socks"] }
reqwest = { version = "0.13.1", features = ["json", "stream", "native-tls", "socks"], default-features = false }
rpassword = "7.4.0"
rust-argon2 = "3.0.0"
serde = { version = "1.0.219", features = ["derive"] }
serde_json = "1.0.140"
serde_yaml = "0.9.34"

View File

@@ -36,6 +36,10 @@ enum Command {
},
#[command(subcommand)]
DlSet(DlSet),
/// hash a password
Hash {
salt: String,
},
}
#[derive(Subcommand)]
@@ -103,14 +107,16 @@ async fn main() -> eyre::Result<()> {
.parse_default_env()
.init();
let token = std::env::var("DLS_TOKEN").map_err(|_| format_err!("DLS_TOKEN should be set"))?;
let dls = dls::Client::new(cli.dls, token);
let dls = || {
let token = std::env::var("DLS_TOKEN").expect("DLS_TOKEN should be set");
dls::Client::new(cli.dls, token)
};
use Command as C;
match cli.command {
C::Clusters => write_json(&dls.clusters().await?),
C::Clusters => write_json(&dls().clusters().await?),
C::Cluster { cluster, command } => {
let dls = dls();
let cluster = dls.cluster(cluster);
use ClusterCommand as CC;
@@ -155,8 +161,9 @@ async fn main() -> eyre::Result<()> {
}
}
}
C::Hosts => write_json(&dls.hosts().await?),
C::Hosts => write_json(&dls().hosts().await?),
C::Host { out, host, asset } => {
let dls = dls();
let host_name = host.clone();
let host = dls.host(host);
match asset {
@@ -171,7 +178,7 @@ async fn main() -> eyre::Result<()> {
C::DlSet(set) => match set {
DlSet::Sign { expiry, items } => {
let req = dls::DownloadSetReq { expiry, items };
let signed = dls.sign_dl_set(&req).await?;
let signed = dls().sign_dl_set(&req).await?;
println!("{signed}");
}
DlSet::Show { signed_set } => {
@@ -211,11 +218,19 @@ async fn main() -> eyre::Result<()> {
name,
asset,
} => {
let dls = dls();
let stream = dls.fetch_dl_set(&signed_set, &kind, &name, &asset).await?;
let mut out = create_asset_file(out, &kind, &name, &asset).await?;
copy_stream(stream, &mut out).await?;
}
},
C::Hash { salt } => {
let salt = dkl::base64_decode(&salt)?;
let passphrase = rpassword::prompt_password("password to hash: ")?;
let hash = dls::store::hash_password(&salt, &passphrase)?;
println!("hash (hex): {}", hex::encode(&hash));
println!("hash (base64): {}", dkl::base64_encode(&hash));
}
};
Ok(())

View File

@@ -6,6 +6,8 @@ use std::collections::BTreeMap as Map;
use std::fmt::Display;
use std::net::IpAddr;
pub mod store;
pub struct Client {
base_url: String,
token: String,

17
src/dls/store.rs Normal file
View File

@@ -0,0 +1,17 @@
pub fn hash_password(salt: &[u8], passphrase: &str) -> argon2::Result<[u8; 32]> {
let hash = argon2::hash_raw(
passphrase.as_bytes(),
salt,
&argon2::Config {
variant: argon2::Variant::Argon2id,
hash_length: 32,
time_cost: 1,
mem_cost: 65536,
thread_mode: argon2::ThreadMode::Parallel,
lanes: 4,
..Default::default()
},
)?;
unsafe { Ok(hash.try_into().unwrap_unchecked()) }
}

View File

@@ -83,6 +83,11 @@ impl Config {
}
pub fn base64_decode(s: &str) -> Result<Vec<u8>, base64::DecodeError> {
use base64::{Engine, prelude::BASE64_STANDARD_NO_PAD as B64};
use base64::{prelude::BASE64_STANDARD_NO_PAD as B64, Engine as _};
B64.decode(s.trim_end_matches('='))
}
pub fn base64_encode(b: &[u8]) -> String {
use base64::{prelude::BASE64_STANDARD as B64, Engine as _};
B64.encode(b)
}