use anyhow::Result;
use crate::{
models::{keyring, Account, Algorithm, Method, ProvidersModel},
utils::spawn_tokio_blocking,
};
pub enum Operation {
Backup,
Restore,
}
pub trait Restorable: Sized {
const ENCRYPTABLE: bool = false;
const SCANNABLE: bool = false;
const IDENTIFIER: &'static str;
type Item: RestorableItem;
fn title() -> String;
fn subtitle() -> String;
fn restore_from_data(from: &[u8], key: Option<&str>) -> Result<Vec<Self::Item>>;
}
pub trait RestorableItem {
fn account(&self) -> String;
fn issuer(&self) -> String;
fn secret(&self) -> String;
fn period(&self) -> Option<u32>;
fn method(&self) -> Method;
fn algorithm(&self) -> Algorithm;
fn digits(&self) -> Option<u32>;
fn counter(&self) -> Option<u32>;
fn restore(&self, provider: &ProvidersModel) -> Result<()> {
let owned_token = self.secret();
let token_exists =
spawn_tokio_blocking(async move { keyring::token_exists(&owned_token).await })?;
if !token_exists {
let provider = provider.find_or_create(
&self.issuer(),
self.period(),
self.method(),
None,
self.algorithm(),
self.digits(),
self.counter(),
None,
None,
)?;
let account =
Account::create(&self.account(), &self.secret(), self.counter(), &provider)?;
provider.add_account(&account);
} else {
tracing::info!(
"Account {}/{} already exists",
self.issuer(),
self.account()
);
}
Ok(())
}
}
pub trait Backupable: Sized {
const ENCRYPTABLE: bool = false;
const IDENTIFIER: &'static str;
fn title() -> String;
fn subtitle() -> String;
fn backup(provider: &ProvidersModel, key: Option<&str>) -> Result<Vec<u8>>;
}
mod aegis;
mod andotp;
mod bitwarden;
mod freeotp;
mod freeotp_json;
mod google;
mod legacy;
mod raivootp;
pub use self::{
aegis::Aegis, andotp::AndOTP, bitwarden::Bitwarden, freeotp::FreeOTP,
freeotp_json::FreeOTPJSON, google::Google, legacy::LegacyAuthenticator, raivootp::RaivoOTP,
};