Skip to main content

things3_cloud/
auth.rs

1use std::fs;
2
3use anyhow::{Context, Result, anyhow};
4use serde::{Deserialize, Serialize};
5
6use crate::dirs::auth_file_path;
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
9struct AuthPayload {
10    email: String,
11    password: String,
12}
13
14fn validate_auth(email: &str, password: &str) -> Result<(String, String)> {
15    let email = email.trim().to_string();
16    let password = password.to_string();
17
18    if email.is_empty() {
19        return Err(anyhow!("Missing auth email."));
20    }
21    if password.is_empty() {
22        return Err(anyhow!("Missing auth password."));
23    }
24
25    Ok((email, password))
26}
27
28pub fn load_auth() -> Result<(String, String)> {
29    let path = auth_file_path();
30    if !path.exists() {
31        return Err(anyhow!(
32            "Auth not configured. Run `things3 set-auth` to create {}.",
33            path.display()
34        ));
35    }
36
37    let raw = fs::read_to_string(&path)
38        .with_context(|| format!("Failed reading auth config at {}", path.display()))?;
39    let payload: AuthPayload = serde_json::from_str(&raw)
40        .with_context(|| format!("Failed reading auth config at {}", path.display()))?;
41
42    validate_auth(&payload.email, &payload.password)
43}
44
45pub fn write_auth(email: &str, password: &str) -> Result<std::path::PathBuf> {
46    let (email, password) = validate_auth(email, password)?;
47    let path = auth_file_path();
48    let parent = path
49        .parent()
50        .ok_or_else(|| anyhow!("Invalid auth file path"))?
51        .to_path_buf();
52    fs::create_dir_all(&parent).with_context(|| format!("Failed creating {}", parent.display()))?;
53
54    let payload = AuthPayload { email, password };
55    let serialized = serde_json::to_string(&payload)?;
56    let tmp_path = path.with_extension("tmp");
57    fs::write(&tmp_path, serialized)
58        .with_context(|| format!("Failed writing {}", tmp_path.display()))?;
59    fs::rename(&tmp_path, &path)
60        .with_context(|| format!("Failed finalizing {}", path.display()))?;
61
62    #[cfg(unix)]
63    {
64        use std::os::unix::fs::PermissionsExt;
65        let mut perms = fs::metadata(&path)?.permissions();
66        perms.set_mode(0o600);
67        fs::set_permissions(&path, perms)?;
68    }
69
70    Ok(path)
71}