Skip to main content

tuitbot_server/auth/
token.rs

1//! File-based bearer token management.
2//!
3//! On first start, generates a random 256-bit token (hex-encoded) and writes it
4//! to `~/.tuitbot/api_token`. Tauri and CLI clients read this file directly.
5
6use std::path::Path;
7
8use rand::RngCore;
9
10/// Ensure the API token file exists, creating one if needed.
11///
12/// Returns the token string. The file is written with restrictive permissions
13/// so only the current user can read it.
14pub fn ensure_api_token(config_dir: &Path) -> anyhow::Result<String> {
15    let token_path = config_dir.join("api_token");
16
17    if token_path.exists() {
18        let token = std::fs::read_to_string(&token_path)?.trim().to_string();
19        if !token.is_empty() {
20            return Ok(token);
21        }
22    }
23
24    // Generate a random 256-bit (32-byte) token and hex-encode it.
25    let mut bytes = [0u8; 32];
26    rand::thread_rng().fill_bytes(&mut bytes);
27    let token = hex::encode(bytes);
28
29    // Ensure the directory exists.
30    std::fs::create_dir_all(config_dir)?;
31
32    std::fs::write(&token_path, &token)?;
33
34    // Set file permissions to 0600 (owner read/write only) on Unix.
35    #[cfg(unix)]
36    {
37        use std::os::unix::fs::PermissionsExt;
38        std::fs::set_permissions(&token_path, std::fs::Permissions::from_mode(0o600))?;
39    }
40
41    tracing::info!(path = %token_path.display(), "Generated new API token");
42
43    Ok(token)
44}