googauth_lib/
config_file.rs1use dirs::home_dir;
2use serde::{Deserialize, Serialize};
3use std::fs;
4use std::fs::{create_dir_all, set_permissions, File, Permissions};
5use std::io::{BufReader, BufWriter};
6use std::os::unix::fs::PermissionsExt;
7use std::path::PathBuf;
8use crate::errors::LibError;
9
10#[derive(Serialize, Deserialize)]
14pub struct ConfigFile {
15 pub version: u32,
16 pub name: String,
17 pub client_id: String,
18 pub client_secret: String,
19 pub scopes: Vec<String>,
20 pub redirect_url: String,
21 pub refresh_token: Option<String>,
22 pub id_token: Option<Token>,
23 pub access_token: Option<Token>,
24}
25
26impl ConfigFile {
27 pub fn new(
28 name: &str,
29 client_id: &str,
30 client_secret: &str,
31 scopes: &[String],
32 redirect_url: &str,
33 ) -> ConfigFile {
34 ConfigFile {
35 version: 1,
36 name: name.to_string(),
37 client_id: client_id.to_string(),
38 client_secret: client_secret.to_string(),
39 scopes: scopes.iter().map(|s| s.to_string()).collect(),
40 redirect_url: redirect_url.to_string(),
41 refresh_token: None,
42 id_token: None,
43 access_token: None,
44 }
45 }
46}
47
48pub struct ConfigBasePath {
49 path: PathBuf,
50}
51
52impl ConfigBasePath {
53 pub fn default() -> Result<ConfigBasePath, LibError> {
54 let mut config_dir = match home_dir() {
55 None => {
56 return Err(LibError::HomeDirectoryNotFound);
57 }
58 Some(dir) => dir,
59 };
60 config_dir.push(".googauth");
61 Ok(ConfigBasePath { path: config_dir } )
62 }
63
64 pub fn from(path: PathBuf) -> ConfigBasePath {
65 ConfigBasePath { path }
66 }
67}
68
69#[derive(Clone, Serialize, Deserialize)]
70pub struct Token {
71 pub secret: String,
72 pub exp: u64,
73}
74
75impl Token {
76 pub fn new(secret: String, exp: u64) -> Token {
77 Token { secret, exp }
78 }
79}
80
81impl ConfigFile {
82 pub fn config_file(name: &str, config_base_path: &ConfigBasePath) -> Result<PathBuf, LibError> {
83 let mut config_dir = config_base_path.path.clone();
84 config_dir.push(name);
85 Ok(config_dir)
86 }
87
88 pub fn list_configs(config_base_path: &ConfigBasePath) -> Result<Vec<ConfigFile>, LibError> {
89 let config_dir = config_base_path.path.clone();
90
91 if config_dir.is_dir() {
92 let mut result = Vec::new();
93 let dirs = fs::read_dir(config_dir)?;
94 for entry in dirs {
95 let entry = entry?;
96 let path = entry.path();
97 if path.is_file() {
98 let file_name = path.file_name().ok_or(LibError::FilenameError)?.to_str().ok_or(LibError::FilenameError)?;
99 if let Ok(config_file) = ConfigFile::read_config(file_name, config_base_path) {
100 result.push(config_file);
101 }
102 }
103 }
104 return Ok(result);
105 }
106 Err(LibError::ConfigsDirectoryNotADirectory(config_dir))
107 }
108
109 pub fn read_config(name: &str, config_base_path: &ConfigBasePath) -> Result<ConfigFile, LibError> {
110 let config_dir = ConfigFile::config_file(name, config_base_path)?;
111
112 let config_file = File::open(config_dir.as_path())?;
113 let config_file_reader = BufReader::new(config_file);
114 let config = serde_json::from_reader(config_file_reader)?;
115 Ok(config)
116 }
117
118 pub fn save_config(&self, config_base_path: &ConfigBasePath) -> Result<(), LibError> {
119 let mut config_dir = config_base_path.path.clone();
120
121 create_dir_all(config_dir.as_path())?;
122 if cfg!(unix) {
123 set_permissions(config_dir.as_path(), Permissions::from_mode(0o700))?
124 }
125
126 config_dir.push(self.name.to_string());
127
128 let config_file = File::create(config_dir.as_path())?;
129
130 if cfg!(unix) {
131 set_permissions(config_dir.as_path(), Permissions::from_mode(0o600))?;
132 }
133
134 let config_file_writer = BufWriter::new(config_file);
135
136 serde_json::to_writer(config_file_writer, self)?;
137
138 Ok(())
139 }
140}