1use anyhow::{Context, Result};
2use serde::Deserialize;
3use std::{collections::HashMap, fs, path::PathBuf};
4
5#[derive(Deserialize, Clone, Debug)]
6pub struct AppConfig {
7 pub client_id: String,
8 pub client_secret: Option<String>,
9 pub tenant_id: String,
10 pub scope: String,
11}
12
13pub type ConfigMap = HashMap<String, AppConfig>;
14
15pub fn config_path() -> Result<PathBuf> {
16 Ok(dirs::config_dir()
17 .context("Could not determine config directory")?
18 .join("msoauth/config.toml"))
19}
20
21pub fn load_profile(profile: &str) -> Result<AppConfig> {
22 let path = config_path()?;
23
24 if !path.exists() {
25 anyhow::bail!(
26 "Config file not found at {}\n\n\
27 Please create it with the following format:\n\n\
28 [default]\n\
29 client_id = \"...\"\n\
30 client_secret = \"...\"\n\
31 tenant_id = \"...\"\n\
32 scope = \"https://graph.microsoft.com/.default\"",
33 path.display()
34 );
35 }
36
37 let config_data = fs::read_to_string(&path)?;
38 let profiles: ConfigMap = toml::from_str(&config_data)
39 .with_context(|| format!("Failed to parse config from {}", path.display()))?;
40
41 profiles
42 .get(profile)
43 .cloned()
44 .with_context(|| format!("Auth profile `{profile}` not found in config"))
45}