summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--mullvad-daemon/src/account_history.rs106
-rw-r--r--mullvad-daemon/src/main.rs9
-rw-r--r--mullvad-daemon/src/settings.rs10
3 files changed, 116 insertions, 9 deletions
diff --git a/mullvad-daemon/src/account_history.rs b/mullvad-daemon/src/account_history.rs
new file mode 100644
index 0000000000..16834854cd
--- /dev/null
+++ b/mullvad-daemon/src/account_history.rs
@@ -0,0 +1,106 @@
+extern crate serde_json;
+
+use app_dirs::{self, AppDataType};
+use std::fs::File;
+use std::io;
+use std::path::PathBuf;
+
+use mullvad_types::account::AccountToken;
+
+error_chain! {
+ errors {
+ DirectoryError {
+ description("Unable to create account history directory for program")
+ }
+ ReadError(path: PathBuf) {
+ description("Unable to read account history file")
+ display("Unable to read account history from {}", path.to_string_lossy())
+ }
+ WriteError(path: PathBuf) {
+ description("Unable to write account history file")
+ display("Unable to write account history to {}", path.to_string_lossy())
+ }
+ ParseError {
+ description("Malformed account history")
+ }
+ }
+}
+
+static ACCOUNT_HISTORY_FILE: &str = "account-history.json";
+static ACCOUNT_HISTORY_LIMIT: usize = 3;
+
+#[derive(Debug, Clone, Deserialize, Serialize, Default)]
+#[serde(default)]
+pub struct AccountHistory {
+ accounts: Vec<AccountToken>,
+}
+
+impl AccountHistory {
+ /// Loads account history from file. If no file is present it returns the defaults.
+ pub fn load() -> Result<AccountHistory> {
+ let history_path = Self::get_path()?;
+ match File::open(&history_path) {
+ Ok(mut file) => {
+ info!(
+ "Loading account history from {}",
+ history_path.to_string_lossy()
+ );
+ Self::parse(&mut file)
+ }
+ Err(ref e) if e.kind() == io::ErrorKind::NotFound => {
+ info!(
+ "No account history file at {}, using defaults",
+ history_path.to_string_lossy()
+ );
+ Ok(AccountHistory::default())
+ }
+ Err(e) => Err(e).chain_err(|| ErrorKind::ReadError(history_path)),
+ }
+ }
+
+ pub fn get_accounts(&self) -> Vec<AccountToken> {
+ self.accounts.clone()
+ }
+
+ /// Add account token to the account history removing duplicate entries
+ pub fn add_account_token(&mut self, account_token: AccountToken) -> Result<()> {
+ self.accounts
+ .retain(|existing_token| existing_token != &account_token);
+ self.accounts.push(account_token);
+
+ let num_accounts = self.accounts.len();
+ if num_accounts > ACCOUNT_HISTORY_LIMIT {
+ self.accounts = self.accounts
+ .split_off(num_accounts - ACCOUNT_HISTORY_LIMIT);
+ }
+
+ self.save()
+ }
+
+ /// Remove account token from the account history
+ pub fn remove_account_token(&mut self, account_token: AccountToken) -> Result<()> {
+ self.accounts
+ .retain(|existing_token| existing_token != &account_token);
+ self.save()
+ }
+
+ /// Serializes the account history and saves it to the file it was loaded from.
+ fn save(&self) -> Result<()> {
+ let path = Self::get_path()?;
+
+ debug!("Writing account history to {}", path.to_string_lossy());
+ let file = File::create(&path).chain_err(|| ErrorKind::WriteError(path.clone()))?;
+
+ serde_json::to_writer_pretty(file, self).chain_err(|| ErrorKind::WriteError(path))
+ }
+
+ fn parse(file: &mut File) -> Result<AccountHistory> {
+ serde_json::from_reader(file).chain_err(|| ErrorKind::ParseError)
+ }
+
+ fn get_path() -> Result<PathBuf> {
+ let dir = app_dirs::app_root(AppDataType::UserCache, &::APP_INFO)
+ .chain_err(|| ErrorKind::DirectoryError)?;
+ Ok(dir.join(ACCOUNT_HISTORY_FILE))
+ }
+}
diff --git a/mullvad-daemon/src/main.rs b/mullvad-daemon/src/main.rs
index 1619205669..b5ec71b2a3 100644
--- a/mullvad-daemon/src/main.rs
+++ b/mullvad-daemon/src/main.rs
@@ -6,6 +6,7 @@
//! GNU General Public License as published by the Free Software Foundation, either version 3 of
//! the License, or (at your option) any later version.
+extern crate app_dirs;
extern crate chrono;
#[macro_use]
extern crate clap;
@@ -41,8 +42,9 @@ mod management_interface;
mod rpc_info;
mod settings;
mod shutdown;
+mod account_history;
-
+use app_dirs::AppInfo;
use error_chain::ChainedError;
use futures::Future;
use jsonrpc_core::futures::sync::oneshot::Sender as OneshotSender;
@@ -69,6 +71,11 @@ use talpid_core::tunnel::{self, TunnelEvent, TunnelMetadata, TunnelMonitor};
use talpid_types::net::{Endpoint, OpenVpnParameters, TransportProtocol, TunnelEndpoint,
TunnelParameters};
+pub static APP_INFO: AppInfo = AppInfo {
+ name: ::CRATE_NAME,
+ author: "Mullvad",
+};
+
error_chain!{
errors {
/// The client is in the wrong state for the requested operation. Optimally the code should
diff --git a/mullvad-daemon/src/settings.rs b/mullvad-daemon/src/settings.rs
index cb9c0daabb..4053c36c19 100644
--- a/mullvad-daemon/src/settings.rs
+++ b/mullvad-daemon/src/settings.rs
@@ -1,7 +1,6 @@
-extern crate app_dirs;
extern crate serde_json;
-use self::app_dirs::{AppDataType, AppInfo};
+use app_dirs::{self, AppDataType};
use mullvad_types::relay_constraints::{Constraint, OpenVpnConstraints, RelayConstraints,
RelayConstraintsUpdate, TunnelConstraints};
@@ -28,11 +27,6 @@ error_chain! {
}
}
-static APP_INFO: AppInfo = AppInfo {
- name: ::CRATE_NAME,
- author: "Mullvad",
-};
-
static SETTINGS_FILE: &str = "settings.json";
#[derive(Debug, Clone, Deserialize, Serialize)]
@@ -90,7 +84,7 @@ impl Settings {
}
fn get_settings_path() -> Result<PathBuf> {
- let dir = app_dirs::app_root(AppDataType::UserConfig, &APP_INFO)
+ let dir = app_dirs::app_root(AppDataType::UserConfig, &::APP_INFO)
.chain_err(|| ErrorKind::DirectoryError)?;
Ok(dir.join(SETTINGS_FILE))
}