From 11d7cb2ef43b57863d7f58e88c30a34613bd10f5 Mon Sep 17 00:00:00 2001 From: jane400 Date: Wed, 2 Oct 2024 17:43:38 +0200 Subject: [PATCH] feat: better keyring handling --- paket/src/keyring.rs | 122 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 111 insertions(+), 11 deletions(-) diff --git a/paket/src/keyring.rs b/paket/src/keyring.rs index b30a8a0..82747e9 100644 --- a/paket/src/keyring.rs +++ b/paket/src/keyring.rs @@ -1,4 +1,8 @@ -use std::sync::OnceLock; +use std::{str::FromStr as _, sync::OnceLock}; + +use gtk::glib; +use libpaket::{locker::crypto::CustomerKeySeed, login::RefreshToken, LibraryError}; +use secrecy::{zeroize::Zeroize, ExposeSecret, SecretBox}; pub static KEYRING: OnceLock = OnceLock::new(); @@ -7,13 +11,18 @@ fn get_keyring_base_attribute() -> (&'static str, &'static str) { } fn get_keyring_attributes_refresh_token() -> Vec<(&'static str, &'static str)> { - vec![get_keyring_base_attribute(), ("type", "refresh_token")] + vec![ + get_keyring_base_attribute(), + ("type", "refresh_token"), + ("version", "1"), + ] } fn get_keyring_attributes_packstation() -> Vec<(&'static str, &'static str)> { vec![ get_keyring_base_attribute(), ("type", "packstation-gerät-secret"), + ("version", "1"), ] } @@ -30,7 +39,7 @@ fn get_keyring<'a>() -> &'a oo7::Keyring { KEYRING.get().unwrap() } -pub async fn keyring_get_refresh_token() -> oo7::Result> { +pub async fn keyring_get_refresh_token() -> oo7::Result> { let items = get_keyring() .search_items(&get_keyring_attributes_refresh_token()) .await?; @@ -40,7 +49,9 @@ pub async fn keyring_get_refresh_token() -> oo7::Result> { item.unlock().await?; } let data = item.secret().await.unwrap(); - Ok(Some(String::from_utf8(data.to_vec()).unwrap())) + Ok(Some( + RefreshToken::new(String::from_utf8(data.to_vec()).unwrap()).unwrap(), + )) } else { Ok(None) } @@ -57,23 +68,112 @@ pub async fn keyring_set_refresh_token(value: String) -> oo7::Result<()> { .await } -pub async fn keyring_get_packstation() -> oo7::Result> { +#[derive(serde::Serialize, serde::Deserialize, Clone)] +struct PackstationSecrets { + postnumber: String, + seed: String, + uuid: String, + device_id: String, +} + +impl secrecy::SerializableSecret for PackstationSecrets {} + +impl Zeroize for PackstationSecrets { + fn zeroize(&mut self) { + self.device_id.zeroize(); + self.postnumber.zeroize(); + self.seed.zeroize(); + self.uuid.zeroize(); + } +} + +#[derive(Debug)] +pub enum KeyringError { + OO7(oo7::Error), + Libpaket(LibraryError), + SerdeJson(serde_json::Error), + Uuid(uuid::Error), +} + +type KeyringResult = Result; + +impl From for KeyringError { + fn from(value: oo7::Error) -> Self { + KeyringError::OO7(value) + } +} + +impl From for KeyringError { + fn from(value: LibraryError) -> Self { + KeyringError::Libpaket(value) + } +} + +impl From for KeyringError { + fn from(value: serde_json::Error) -> Self { + Self::SerdeJson(value) + } +} + +impl From for KeyringError { + fn from(value: uuid::Error) -> Self { + KeyringError::Uuid(value) + } +} + +pub async fn keyring_get_packstation() -> KeyringResult> { let items = get_keyring() .search_items(&get_keyring_attributes_packstation()) .await?; - todo!() + if let Some(item) = items.get(0) { + if item.is_locked().await? { + item.unlock().await?; + } + let data = item.secret().await.unwrap(); + let data = serde_json::from_slice::>(data.as_slice())?; + let data = data.expose_secret(); + + let uuid = uuid::Uuid::from_str(data.uuid.as_str())?; + let seed = glib::base64_decode(&data.seed); + Ok(Some(CustomerKeySeed::from( + &data.postnumber, + seed, + &uuid, + data.device_id.clone(), + ))) + } else { + Ok(None) + } } -pub async fn keyring_set_packstation(value: String) -> oo7::Result<()> { - get_keyring() +pub async fn keyring_set_packstation(data: &CustomerKeySeed) -> KeyringResult<()> { + if data.device_id.is_none() { + return Ok(()); + } + let seed = secrecy::SecretString::from(Into::::into(glib::base64_encode( + data.seed.expose_secret().as_bytes(), + ))); + let uuid = data.uuid.to_string(); + let device_id = data.device_id.as_ref().unwrap().to_string(); + + let secret = SecretBox::new(Box::new(PackstationSecrets { + postnumber: data.postnumber.clone(), + seed: seed.expose_secret().to_string(), + uuid, + device_id, + })); + + let string = secrecy::SecretString::from(serde_json::to_string_pretty(&secret)?); + + Ok(get_keyring() .create_item( "Paket: Device keys", - &get_keyring_attributes_refresh_token(), - value, + &get_keyring_attributes_packstation(), + string.expose_secret(), true, ) - .await + .await?) } pub fn keyring_is_available() -> bool {