haste_health/cli/
secrets.rs1use haste_fhir_model::r4::generated::terminology::IssueType;
8use haste_fhir_operation_error::OperationOutcomeError;
9use serde::{Deserialize, Serialize};
10use std::{collections::HashMap, path::PathBuf};
11
12#[derive(Serialize, Deserialize, Debug, Clone)]
15pub(crate) struct StoredTokens {
16 pub(crate) access_token: String,
17 pub(crate) refresh_token: Option<String>,
18 pub(crate) id_token: Option<String>,
19 pub(crate) expires_at: i64,
21}
22
23#[derive(Serialize, Deserialize, Debug, Clone, Default)]
25pub(crate) struct ProfileSecrets {
26 #[serde(default)]
28 pub(crate) client_secret: Option<String>,
29 #[serde(default)]
31 pub(crate) tokens: Option<StoredTokens>,
32}
33
34#[derive(Serialize, Deserialize, Debug, Default)]
36pub(crate) struct CliSecrets {
37 #[serde(default)]
38 pub(crate) profiles: HashMap<String, ProfileSecrets>,
39}
40
41impl CliSecrets {
42 pub(crate) fn profile(&self, name: &str) -> Option<&ProfileSecrets> {
43 self.profiles.get(name)
44 }
45
46 pub(crate) fn profile_mut(&mut self, name: &str) -> &mut ProfileSecrets {
47 self.profiles.entry(name.to_string()).or_default()
48 }
49
50 pub(crate) fn remove_profile(&mut self, name: &str) {
51 self.profiles.remove(name);
52 }
53}
54
55fn read_existing_secrets(location: &PathBuf) -> Result<CliSecrets, OperationOutcomeError> {
56 let secrets_str = std::fs::read_to_string(location).map_err(|_| {
57 OperationOutcomeError::error(
58 IssueType::exception(),
59 format!(
60 "Failed to read secrets file at location '{}'",
61 location.to_string_lossy()
62 ),
63 )
64 })?;
65
66 toml::from_str::<CliSecrets>(&secrets_str).map_err(|_| {
67 OperationOutcomeError::error(
68 IssueType::exception(),
69 format!(
70 "Failed to parse secrets file at location '{}'",
71 location.to_string_lossy()
72 ),
73 )
74 })
75}
76
77pub(crate) fn load_secrets(location: &PathBuf) -> CliSecrets {
79 if let Ok(secrets) = read_existing_secrets(location) {
80 return secrets;
81 }
82
83 let secrets = CliSecrets::default();
84 write_secrets(location, &secrets).expect("Failed to write default secrets file");
85 secrets
86}
87
88pub(crate) fn write_secrets(
89 location: &PathBuf,
90 secrets: &CliSecrets,
91) -> Result<(), OperationOutcomeError> {
92 std::fs::write(location, toml::to_string(secrets).unwrap()).map_err(|_| {
93 OperationOutcomeError::error(
94 IssueType::exception(),
95 format!(
96 "Failed to write secrets file at location '{}'",
97 location.to_string_lossy()
98 ),
99 )
100 })
101}