chore: paket: move common keyring code into module
This commit is contained in:
parent
a8d82bb7b7
commit
d5c2997c62
3 changed files with 105 additions and 68 deletions
59
paket/src/keyring.rs
Normal file
59
paket/src/keyring.rs
Normal 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()
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue