Service: set-password maintenance command for forgotten passwords
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
359000afa3
commit
f13ab1a629
2 files changed
+26
No files matched your search
@@ -115,6 +115,8 @@ A small Rust service (axum) in `server/` keeps the user accounts (Argon2 passwor
|
||||
| `GET /api/saves/{id}` | savegame JSON |
|
||||
| `DELETE /api/saves/{id}` | delete a savegame |
|
||||
|
||||
A forgotten password is set again on the server with `docker compose stop saves && docker compose run --rm --no-deps saves dungeoncraft-saves set-password <name> '<password>' && docker compose up -d saves` (ends the user's sessions). To start over with no accounts at all, delete `users.json` and `sessions.json` in the `savegames` volume.
|
||||
|
||||
All requests except health and login need `Authorization: Bearer <token>`. Limits: 1 MB per savegame, 500 MB in total, 30 write requests and 20 login attempts per minute. Settings: `SAVE_DIR` (default `/data`), `LISTEN` (default `0.0.0.0:8080`).
|
||||
|
||||
## Adding a language
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in new issue
Block a user