chore: paket: move common keyring code into module

This commit is contained in:
jane400 2024-09-21 21:01:24 +02:00 committed by jane400
parent a8d82bb7b7
commit d5c2997c62
3 changed files with 105 additions and 68 deletions

59
paket/src/keyring.rs Normal file
View file

@ -0,0 +1,59 @@
use std::sync::OnceLock;
pub static KEYRING: OnceLock<oo7::Keyring> = OnceLock::new();
fn get_keyring_base_attribute() -> (&'static str, &'static str) {
("app", crate::constants::APP_ID)
}
fn get_keyring_attributes_refresh_token() -> Vec<(&'static str, &'static str)> {
vec![get_keyring_base_attribute(), ("type", "refresh_token")]
}
fn get_keyring_attributes_packstation() -> Vec<(&'static str, &'static str)> {
vec![
get_keyring_base_attribute(),
("type", "packstation-gerät-secret"),
]
}
pub async fn keyring_delete_all_items() -> oo7::Result<()> {
get_keyring()
.delete(&vec![get_keyring_base_attribute()])
.await
}
fn get_keyring<'a>() -> &'a oo7::Keyring {
KEYRING.get().unwrap()
}
pub async fn keyring_get_refresh_token() -> oo7::Result<Option<String>> {
let items = get_keyring()
.search_items(&get_keyring_attributes_refresh_token())
.await?;
if let Some(item) = items.get(0) {
if item.is_locked().await? {
item.unlock().await?;
}
let data = item.secret().await.unwrap();
Ok(Some(String::from_utf8(data.to_vec()).unwrap()))
} else {
Ok(None)
}
}
pub async fn keyring_set_refresh_token(value: String) -> oo7::Result<()> {
get_keyring()
.create_item(
"Refresh Token",
&get_keyring_attributes_refresh_token(),
value,
true,
)
.await
}
pub fn keyring_is_available() -> bool {
KEYRING.get().is_some()
}

View file

@ -2,6 +2,7 @@ pub mod account;
pub mod advice; pub mod advice;
pub mod advices; pub mod advices;
pub mod constants; pub mod constants;
pub mod keyring;
pub mod login; pub mod login;
pub mod ready; pub mod ready;
pub mod tracking; pub mod tracking;

View file

@ -1,9 +1,4 @@
use std::{ use std::{cell::RefCell, collections::HashMap, sync::Arc, time::Duration};
cell::RefCell,
collections::HashMap,
sync::{Arc, OnceLock},
time::Duration,
};
use adw::prelude::*; use adw::prelude::*;
use libpaket::{ use libpaket::{
@ -17,7 +12,7 @@ use relm4::{
}; };
use webkit::{prelude::WebViewExt, URIRequest, WebContext, WebView}; use webkit::{prelude::WebViewExt, URIRequest, WebContext, WebView};
static KEYRING: OnceLock<oo7::Keyring> = OnceLock::new(); use crate::keyring::{keyring_get_refresh_token, keyring_is_available, keyring_set_refresh_token};
#[derive(Debug)] #[derive(Debug)]
pub enum LoginInput { pub enum LoginInput {
@ -79,8 +74,19 @@ pub enum LoginCommand {
NeedsRefresh, NeedsRefresh,
} }
const KEYRING_ATTRIBUTES: [(&str, &str); 2] = macro_rules! keyring_result_get {
[("app", crate::constants::APP_ID), ("type", "refresh_token")]; ($sender: ident, $caller: expr, $code: expr) => {{
let res = $caller;
match res {
Ok(value) => Ok($code(value)),
Err(err) => {
$sender.output(LoginOutput::KeyringError(err)).unwrap();
Err(())
}
}
}};
}
#[relm4::component(async, pub)] #[relm4::component(async, pub)]
impl AsyncComponent for Login { impl AsyncComponent for Login {
@ -175,47 +181,27 @@ impl AsyncComponent for Login {
tracker: 0, tracker: 0,
}; };
let result = oo7::Keyring::new().await; let _ = keyring_result_get!(sender, oo7::Keyring::new().await, |keyring| {
match result { crate::keyring::KEYRING.set(keyring).unwrap();
Ok(keyring) => { });
KEYRING.set(keyring).unwrap();
if let Err(err) = KEYRING.get().unwrap().unlock().await { if keyring_is_available() {
sender
.output(LoginOutput::KeyringError(err))
.expect("sender not worky");
} else {
let keyring = KEYRING.get().unwrap();
match keyring
.search_items(&HashMap::from(KEYRING_ATTRIBUTES))
.await
{
Ok(res) => {
if res.len() > 0 {
let item = &res[0];
let refresh_token = item.secret().await.unwrap();
let refresh_token = let refresh_token =
std::str::from_utf8(refresh_token.as_slice()).unwrap(); keyring_result_get!(sender, keyring_get_refresh_token().await, move |value| {
model.refresh_token = return value;
Some(RefreshToken::new(refresh_token.to_string()).unwrap()); });
if let Ok(value) = refresh_token {
match value {
Some(value) => {
model.refresh_token = Some(RefreshToken::new(value).unwrap());
sender.input(LoginInput::NeedsRefresh); sender.input(LoginInput::NeedsRefresh);
} else { }
None => {
sender.input(LoginInput::NeedsLogin); sender.input(LoginInput::NeedsLogin);
} }
}
Err(err) => {
sender
.output(LoginOutput::KeyringError(err))
.expect("sender not worky");
}
}; };
} }
} }
Err(err) => {
sender
.output(LoginOutput::KeyringError(err))
.expect("sender not worky");
}
};
let webcontext = WebContext::builder().build(); let webcontext = WebContext::builder().build();
{ {
@ -273,7 +259,7 @@ impl AsyncComponent for Login {
*token.write() = None; *token.write() = None;
} }
if let Some(refresh_token) = self.refresh_token.clone() { if let Some(refresh_token) = self.refresh_token.clone() {
sender.command(|out, shutdown| { sender.command(|_, shutdown| {
shutdown shutdown
.register(async move { .register(async move {
let client = OpenIdClient::new(); let client = OpenIdClient::new();
@ -283,10 +269,7 @@ impl AsyncComponent for Login {
}); });
} }
self.refresh_token = None; self.refresh_token = None;
let keyring = KEYRING.get().unwrap(); let _ = crate::keyring::keyring_delete_all_items().await;
let _ = keyring
.delete(&HashMap::from([("app", crate::constants::APP_ID)]))
.await;
} }
LoginInput::NeedsRefresh => { LoginInput::NeedsRefresh => {
let refresh_token = self.refresh_token.as_ref().unwrap().clone(); let refresh_token = self.refresh_token.as_ref().unwrap().clone();
@ -388,27 +371,21 @@ impl Login {
.drop_on_shutdown() .drop_on_shutdown()
}); });
} }
let future = async {
self.refresh_token = Some(res.refresh_token); self.refresh_token = Some(res.refresh_token);
let keyring = KEYRING.get().unwrap();
keyring
.create_item(
"Refresh Token",
&HashMap::from(KEYRING_ATTRIBUTES),
self.refresh_token.as_ref().unwrap().to_string(),
true,
)
.await
.unwrap();
};
if !res.id_token.is_expired() { if !res.id_token.is_expired() {
let _ = keyring_result_get!(
sender,
keyring_set_refresh_token(self.refresh_token.as_ref().unwrap().to_string())
.await,
|_| {}
);
let credentials_model = self.shared_id_token.lock().await; let credentials_model = self.shared_id_token.lock().await;
let mut credentials_model = credentials_model.write(); let mut credentials_model = credentials_model.write();
*credentials_model = Some(res.id_token); *credentials_model = Some(res.id_token);
} }
future.await;
} }
Err(res) => { Err(res) => {
// We disarm the webkit flow/aka breaking the application. We want to reduce invalid requests // We disarm the webkit flow/aka breaking the application. We want to reduce invalid requests