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 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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue