cryptsetup: allow 'mass' reuse

This commit is contained in:
Mikaël Cluseau
2025-11-20 09:11:12 +01:00
parent ac9d7e8d9d
commit 3597ba2968
7 changed files with 78 additions and 28 deletions

2
Cargo.lock generated
View File

@ -817,7 +817,7 @@ dependencies = [
[[package]] [[package]]
name = "init" name = "init"
version = "2.5.0" version = "2.5.1"
dependencies = [ dependencies = [
"base64", "base64",
"dkl", "dkl",

View File

@ -1,6 +1,6 @@
[package] [package]
name = "init" name = "init"
version = "2.5.0" version = "2.5.1"
edition = "2024" edition = "2024"
[profile.release] [profile.release]

View File

@ -1,5 +1,4 @@
pub mod bootstrap; pub mod bootstrap;
pub mod connect_boot;
pub mod init; pub mod init;
pub mod init_input; pub mod init_input;
pub mod version; pub mod version;

View File

@ -1 +0,0 @@

View File

@ -33,6 +33,7 @@ pub async fn bootstrap(cfg: Config) {
.await; .await;
} }
// prepare system
let boot_version = utils::param("version").unwrap_or("current"); let boot_version = utils::param("version").unwrap_or("current");
let base_dir = &format!("/bootstrap/{boot_version}"); let base_dir = &format!("/bootstrap/{boot_version}");

View File

@ -56,27 +56,72 @@ pub async fn setup(devs: &[CryptDev]) {
.await; .await;
} }
static PREV_PW: Mutex<String> = Mutex::const_new(String::new()); struct PrevPw {
pw: String,
reuse: bool,
}
impl PrevPw {
fn is_set(&self) -> bool {
!self.pw.is_empty()
}
fn can_reuse(&self) -> bool {
self.reuse && self.is_set()
}
fn invalidate(&mut self) {
self.pw = String::new();
self.reuse = false;
}
async fn input(&mut self, prompt: impl std::fmt::Display) -> String {
if self.can_reuse() {
info!("reusing password");
self.pw.clone()
} else if self.is_set() {
let pw =
input::read_password(format!("{prompt} (\"\" reuse, \"*\" auto-reuse)? ")).await;
match pw.as_str() {
"" => self.pw.clone(),
"*" => {
self.reuse = true;
self.pw.clone()
}
_ => {
self.pw = pw.clone();
pw
}
}
} else {
let pw = loop {
let pw = input::read_password(format!("{prompt}? ")).await;
if pw.is_empty() {
error!("empty password provided!");
continue;
}
break pw;
};
self.pw = pw.clone();
pw
}
}
}
static PREV_PW: Mutex<PrevPw> = Mutex::const_new(PrevPw {
pw: String::new(),
reuse: false,
});
async fn crypt_open(crypt_dev: &str, dev_path: &str) -> Result<()> { async fn crypt_open(crypt_dev: &str, dev_path: &str) -> Result<()> {
'open_loop: loop { 'open_loop: loop {
let mut prev_pw = PREV_PW.lock().await; let mut prev_pw = PREV_PW.lock().await;
let prompt = if prev_pw.is_empty() {
format!("crypt password for {crypt_dev}? ")
} else {
format!("crypt password for {crypt_dev} (enter = reuse previous)? ")
};
let mut pw = input::read_password(prompt).await; let pw = prev_pw
if pw.is_empty() { .input(format!("crypt password for {crypt_dev}"))
pw = prev_pw.clone(); .await;
}
if pw.is_empty() {
error!("empty password provided!");
continue;
}
*prev_pw = pw.clone();
if cryptsetup(&pw, ["open", dev_path, crypt_dev]).await? { if cryptsetup(&pw, ["open", dev_path, crypt_dev]).await? {
return Ok(()); return Ok(());
@ -107,15 +152,17 @@ async fn crypt_open(crypt_dev: &str, dev_path: &str) -> Result<()> {
} }
_ => unreachable!(), _ => unreachable!(),
} }
} else { }
// device looks initialized, don't allow format
warn!("{dev_path} looks initialized, formatting not allowed from init");
match input::read_choice(["[r]etry", "[i]gnore"]).await { // device looks initialized, don't allow format
'r' => continue 'open_loop, warn!("{dev_path} looks initialized, formatting not allowed from init");
'i' => return Ok(()),
_ => unreachable!(), prev_pw.invalidate();
}
match input::read_choice(["[r]etry", "[i]gnore"]).await {
'r' => continue 'open_loop,
'i' => return Ok(()),
_ => unreachable!(),
} }
} }
} }

View File

@ -2,6 +2,10 @@ use crate::input;
pub async fn run() { pub async fn run() {
tokio::spawn(async { tokio::spawn(async {
// give a bit of time for stdout
use tokio::time::{sleep, Duration};
sleep(Duration::from_millis(200)).await;
if let Err(e) = input::forward_requests_from_socket().await { if let Err(e) = input::forward_requests_from_socket().await {
eprintln!("failed to forwards requests from socket: {e}"); eprintln!("failed to forwards requests from socket: {e}");
std::process::exit(1); std::process::exit(1);