libwally/
auth.rs

1//! Defines storage of authentication information when interacting with
2//! registries.
3
4use std::collections::HashMap;
5use std::io;
6use std::path::{Path, PathBuf};
7
8use anyhow::Context;
9use serde::{Deserialize, Serialize};
10use toml_edit::{table, value, Document, Item};
11
12const DEFAULT_AUTH_TOML: &str = r#"
13# This is where Wally stores details for authenticating with registries.
14# It can be updated using `wally login` and `wally logout`.
15
16[tokens]
17
18"#;
19
20#[derive(Serialize, Deserialize)]
21pub struct AuthStore {
22    pub tokens: HashMap<String, String>,
23}
24
25impl AuthStore {
26    pub fn load() -> anyhow::Result<Self> {
27        let path = file_path()?;
28        let contents = Self::contents(&path)?;
29
30        let auth = toml::from_str(&contents).with_context(|| {
31            format!(
32                "Malformed Wally auth config file. Try deleting {}",
33                path.display()
34            )
35        })?;
36
37        Ok(auth)
38    }
39
40    pub fn set_token(key: &str, token: Option<&str>) -> anyhow::Result<()> {
41        let path = file_path()?;
42        let contents = Self::contents(&path)?;
43
44        let mut auth: Document = contents.parse().unwrap();
45
46        if !auth.as_table_mut().contains_table("tokens") {
47            auth["tokens"] = table();
48        }
49
50        let tokens = auth.as_table_mut().entry("tokens");
51
52        if let Some(token) = token {
53            tokens[key] = value(token);
54        } else {
55            tokens[key] = Item::None;
56        }
57
58        fs_err::create_dir_all(path.parent().unwrap())?;
59        fs_err::write(&path, auth.to_string())?;
60
61        Ok(())
62    }
63
64    fn contents(path: &Path) -> anyhow::Result<String> {
65        match fs_err::read_to_string(&path) {
66            Ok(contents) => Ok(contents),
67            Err(err) => {
68                if err.kind() == io::ErrorKind::NotFound {
69                    Ok(DEFAULT_AUTH_TOML.to_owned())
70                } else {
71                    return Err(err.into());
72                }
73            }
74        }
75    }
76}
77
78fn file_path() -> anyhow::Result<PathBuf> {
79    let mut path = dirs::home_dir().context("Failed to find home directory")?;
80    path.push(".wally");
81    path.push("auth.toml");
82    Ok(path)
83}