Skip to main content

things3_cloud/
auth.rs

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