diff --git a/Cargo.toml b/Cargo.toml index 3f9b5e8579e4a715a1896e60dadab75026b2c17f..f32095c5a152f8332be6ff4f528a7d5eab1be2ac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ serde = "^1.0.125" log = "^0.4.11" syslog = "^5.0.0" xdg = "^2.2.0" +serde_json = "^1.0.64" [profile.release] opt-level = 'z' diff --git a/src/cache.rs b/src/cache.rs index fa9cb0e124a62bc9fcb063e1e4feff196babeca5..23f286191386be82003138b8b5b301cef66353d2 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -26,14 +26,18 @@ use std::ffi::CString; use oauth2::basic::BasicTokenResponse; use std::env; -use std::fs::remove_file; +use std::fs; use std::io; use std::path::PathBuf; use xdg::{BaseDirectories,BaseDirectoriesError}; +use serde::{Deserialize, Serialize}; +use serde_json; + const TOKEN_DEFAULT_EXPIRES: u64 = 24 * 60 * 60; const USER_TOKEN_FILENAME: &str = "user_token.json"; +#[derive(Serialize, Deserialize)] struct UserToken { access_token: String, expires_at: u64, @@ -128,11 +132,47 @@ impl Cache { } pub fn load_user_token(&self, owner: String) -> Option<&UserToken> { - return self.user_tokens.get(&owner); + match self.user_tokens.get(&owner) { + Some(t) => { + if t.is_expired() { + // Try to load token from file + self.drop_privileges(owner).ok(); + let new_token = match self.place_user_cache_file(owner, USER_TOKEN_FILENAME) { + Ok(path) => match load_json(path) { + Ok(read_token) => { + self.user_tokens.insert(owner, read_token); + Some(&read_token) + }, + Err(e) => { + self.user_tokens.remove(&owner); + None + } + }, + Err(e) => { + self.user_tokens.remove(&owner); + None + } + }; + self.restore_privileges(); + new_token + } else { + Some(t) + } + }, + None => None + } } pub fn save_user_token(&self, owner: String, token: UserToken) { self.user_tokens.insert(owner, token); + + // Try to write user's token cache file + self.drop_privileges(owner).ok(); + match self.place_user_cache_file(owner, USER_TOKEN_FILENAME) { + Ok(path) => save_json(path, token), + Err(e) => Err(e) + }; + self.restore_privileges(); } pub fn delete_user_token(&self, owner: String) { @@ -141,7 +181,7 @@ impl Cache { // Try to remove user's token cache file self.drop_privileges(owner).ok(); match self.place_user_cache_file(owner, USER_TOKEN_FILENAME) { - Ok(path) => remove_file(path), + Ok(path) => fs::remove_file(path), Err(e) => Err(e) }; self.restore_privileges(); @@ -156,6 +196,23 @@ impl Cache { } } +fn load_json<'de, O: Deserialize<'de>>(path: PathBuf) -> Result<O, io::Error> { + let json = fs::read_to_string(path)?; + match serde_json::from_str(&json) { + Ok(o) => Ok(o), + Err(e) => return Err(io::Error::new(io::ErrorKind::InvalidData, e)) + } +} + +fn save_json<O: Serialize>(path: PathBuf, obj: O) -> Result<(), io::Error> { + let json = match serde_json::to_string(&obj) { + Ok(j) => j, + Err(e) => return Err(io::Error::new(io::ErrorKind::InvalidData, e)) + }; + + fs::write(path, json) +} + lazy_static! { pub static ref CACHE: Cache = Cache::new(); }