Service: set-password maintenance command for forgotten passwords

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Richard ZinkandClaude Opus 5.5 committed 2026-11-03 13:44:15 +01:00
1 parent 359000afa3
commit f13ab1a629
2 files changed
+26

No files matched your search

+24
View File
@@ -470,9 +470,33 @@ async fn delete_save(State(st): State<AppState>, headers: HeaderMap, Path(id): P
StatusCode::NO_CONTENT.into_response()
}
// Maintenance: "dungeoncraft-saves set-password <name> <password>" sets a user's password
// (stop the service first or restart it afterwards; the user's sessions end).
fn set_password_cli(dir: &std::path::Path, name: &str, password: &str) {
let path = dir.join("users.json");
let mut users: Vec<User> = std::fs::read(&path).ok().and_then(|b| serde_json::from_slice(&b).ok()).unwrap_or_default();
let Some(u) = users.iter_mut().find(|u| u.name == name) else {
eprintln!("no user {}", name);
std::process::exit(1);
};
u.salt = random_hex(16);
u.hash = hash_password(password, &u.salt);
std::fs::write(&path, serde_json::to_vec_pretty(&users).unwrap_or_default()).expect("write users.json");
let spath = dir.join("sessions.json");
let mut sessions: HashMap<String, String> = std::fs::read(&spath).ok().and_then(|b| serde_json::from_slice(&b).ok()).unwrap_or_default();
sessions.retain(|_, n| n != name);
let _ = std::fs::write(&spath, serde_json::to_vec(&sessions).unwrap_or_default());
println!("password of {} set", name);
}
#[tokio::main]
async fn main() {
let dir = PathBuf::from(std::env::var("SAVE_DIR").unwrap_or_else(|_| "/data".into()));
let args: Vec<String> = std::env::args().collect();
if args.get(1).map(|s| s.as_str()) == Some("set-password") && args.len() == 4 {
set_password_cli(&dir, &args[2], &args[3]);
return;
}
tokio::fs::create_dir_all(dir.join("users")).await.expect("data directory");
let users: Vec<User> = tokio::fs::read(dir.join("users.json")).await.ok().and_then(|b| serde_json::from_slice(&b).ok()).unwrap_or_default();
let sessions: HashMap<String, String> = tokio::fs::read(dir.join("sessions.json")).await.ok().and_then(|b| serde_json::from_slice(&b).ok()).unwrap_or_default();