1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
use crate::vault::secret::SecretId;
use keyring::{Entry, Result};
use once_cell::sync::Lazy;
use secrecy::{ExposeSecret, SecretString};
use std::sync::Arc;
use tokio::sync::Mutex;
use url::Url;
#[allow(dead_code)]
const SERVICE_NAME: &str = "https://saveoursecrets.com";
#[allow(dead_code)]
const URN_PREFIX: &str = "urn:sos";
static KEYRING: Lazy<Arc<Mutex<NativeKeyring>>> =
Lazy::new(|| Arc::new(Mutex::new(Default::default())));
/// Get the native keyring mirror.
pub fn get_native_keyring() -> Arc<Mutex<NativeKeyring>> {
Arc::clone(&KEYRING)
}
/// Native keyring provides access to the system keychain.
#[derive(Default)]
pub struct NativeKeyring {
enabled: bool,
}
impl NativeKeyring {
/// Determine if this native keyring mirror is enabled.
pub fn enabled(&self) -> bool {
self.enabled
}
/// Set if this native keyring mirror is enabled.
pub fn set_enabled(&mut self, enabled: bool) {
self.enabled = enabled;
}
fn service_name(
&self,
secret_id: &SecretId,
website: Option<&Url>,
) -> String {
let service = if let Some(url) = website {
url.to_string()
} else {
SERVICE_NAME.to_owned()
};
format!("{}:{}:{}", URN_PREFIX, secret_id, service)
}
fn entry_name(&self, secret_name: &str, username: &str) -> String {
format!("{} ({})", secret_name, username)
}
/// Create a password in the native keyring.
#[allow(dead_code)]
pub(crate) fn create_entry(
&self,
secret_id: &SecretId,
secret_name: &str,
username: &str,
password: &SecretString,
website: Option<&Url>,
) -> Result<()> {
if self.enabled {
let service = self.service_name(secret_id, website);
let entry_name = self.entry_name(secret_name, username);
let entry = Entry::new(&service, &entry_name)?;
entry.set_password(password.expose_secret())?;
}
Ok(())
}
/*
/// Get a password in the native keyring.
#[allow(dead_code)]
pub(crate) fn get_entry(
&self,
secret_id: &SecretId,
secret_name: &str,
username: &str,
website: Option<&Url>,
) -> Result<Option<SecretString>> {
if self.enabled {
let service = self.service_name(secret_id, website);
let entry_name = self.entry_name(secret_name, username);
let entry = Entry::new(&service, &entry_name)?;
match entry.get_password() {
Ok(password) => Ok(Some(SecretString::new(password))),
Err(e) => match e {
Error::NoEntry => Ok(None),
_ => Err(e),
}
}
} else {
Ok(None)
}
}
*/
/// Delete a password in the native keyring.
#[allow(dead_code)]
pub(crate) fn delete_entry(
&self,
secret_id: &SecretId,
secret_name: &str,
username: &str,
website: Option<&Url>,
) -> Result<()> {
if self.enabled {
let service = self.service_name(secret_id, website);
let entry_name = self.entry_name(secret_name, username);
let entry = Entry::new(&service, &entry_name)?;
entry.delete_password()?;
}
Ok(())
}
}