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 advices;
pub mod constants;
pub mod keyring;
pub mod login;
pub mod ready;
pub mod tracking;

View file

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