steamguard-cli/src/accountmanager.rs
2021-08-13 19:04:03 -04:00

149 lines
4.4 KiB
Rust

use log::*;
use serde::{Deserialize, Serialize};
use std::io::{BufReader, Write};
use std::path::Path;
use std::sync::{Arc, Mutex};
use std::{cell::Cell, fs::File};
use steamguard::SteamGuardAccount;
#[derive(Debug, Serialize, Deserialize)]
pub struct Manifest {
pub encrypted: bool,
pub entries: Vec<ManifestEntry>,
/// Not implemented, kept for compatibility with SDA.
pub first_run: bool,
/// Not implemented, kept for compatibility with SDA.
pub periodic_checking: bool,
/// Not implemented, kept for compatibility with SDA.
pub periodic_checking_interval: i32,
/// Not implemented, kept for compatibility with SDA.
pub periodic_checking_checkall: bool,
/// Not implemented, kept for compatibility with SDA.
pub auto_confirm_market_transactions: bool,
/// Not implemented, kept for compatibility with SDA.
pub auto_confirm_trades: bool,
#[serde(skip)]
pub accounts: Vec<Arc<Mutex<SteamGuardAccount>>>,
#[serde(skip)]
folder: String, // I wanted to use a Path here, but it was too hard to make it work...
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ManifestEntry {
pub encryption_iv: Option<String>,
pub encryption_salt: Option<String>,
pub filename: String,
#[serde(rename = "steamid")]
pub steam_id: u64,
}
impl Default for Manifest {
fn default() -> Self {
Manifest {
encrypted: false,
entries: vec![],
first_run: false,
periodic_checking: false,
periodic_checking_interval: 0,
periodic_checking_checkall: false,
auto_confirm_market_transactions: false,
auto_confirm_trades: false,
accounts: vec![],
folder: "".into(),
}
}
}
impl Manifest {
/// `path` should be the path to manifest.json
pub fn new(path: &Path) -> Self {
Manifest {
folder: String::from(path.parent().unwrap().to_str().unwrap()),
..Default::default()
}
}
pub fn load(path: &Path) -> anyhow::Result<Self> {
debug!("loading manifest: {:?}", &path);
let file = File::open(path)?;
let reader = BufReader::new(file);
let mut manifest: Manifest = serde_json::from_reader(reader)?;
manifest.folder = String::from(path.parent().unwrap().to_str().unwrap());
return Ok(manifest);
}
pub fn load_accounts(&mut self) -> anyhow::Result<()> {
for entry in &self.entries {
let path = Path::new(&self.folder).join(&entry.filename);
debug!("loading account: {:?}", path);
let file = File::open(path)?;
let reader = BufReader::new(file);
let account: SteamGuardAccount = serde_json::from_reader(reader)?;
self.accounts.push(Arc::new(Mutex::new(account)));
}
Ok(())
}
pub fn add_account(&mut self, account: SteamGuardAccount) {
debug!("adding account to manifest: {}", account.account_name);
let steamid = account.session.clone().unwrap().steam_id;
self.entries.push(ManifestEntry {
filename: format!("{}.maFile", &account.account_name),
steam_id: steamid,
encryption_iv: None,
encryption_salt: None,
});
self.accounts.push(Arc::new(Mutex::new(account)));
}
pub fn import_account(&mut self, import_path: String) -> anyhow::Result<()> {
let path = Path::new(&import_path);
ensure!(path.exists(), "{} does not exist.", import_path);
ensure!(path.is_file(), "{} is not a file.", import_path);
let file = File::open(path)?;
let reader = BufReader::new(file);
let account: SteamGuardAccount = serde_json::from_reader(reader)?;
self.add_account(account);
return Ok(());
}
pub fn remove_account(&mut self, account_name: String) {
let index = self
.accounts
.iter()
.position(|a| a.lock().unwrap().account_name == account_name)
.unwrap();
self.accounts.remove(index);
self.entries.remove(index);
}
pub fn save(&self) -> anyhow::Result<()> {
ensure!(
self.entries.len() == self.accounts.len(),
"Manifest entries don't match accounts."
);
for (entry, account) in self.entries.iter().zip(&self.accounts) {
debug!("saving {}", entry.filename);
let serialized = serde_json::to_string(account.as_ref())?;
ensure!(
serialized.len() > 2,
"Something extra weird happened and the account was serialized into nothing."
);
let path = Path::new(&self.folder).join(&entry.filename);
let mut file = File::create(path)?;
file.write_all(serialized.as_bytes())?;
file.sync_data()?;
}
debug!("saving manifest");
let manifest_serialized = serde_json::to_string(&self)?;
let path = Path::new(&self.folder).join("manifest.json");
let mut file = File::create(path)?;
file.write_all(manifest_serialized.as_bytes())?;
file.sync_data()?;
Ok(())
}
}