From 2e867841619efc67e8d221b7d15833520d56f3be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Commaille?= Date: Mon, 27 Nov 2023 13:10:22 +0100 Subject: [PATCH] secret: Serialize secret as JSON MessagePack creates issues with Secret Service providers that expect a valid string. We don't really care about saving a few bytes when storing secrets. --- src/secret.rs | 82 ++++++++++++++++++++++++--------------------------- 1 file changed, 39 insertions(+), 43 deletions(-) diff --git a/src/secret.rs b/src/secret.rs index 1c7a6759..88f757f5 100644 --- a/src/secret.rs +++ b/src/secret.rs @@ -13,14 +13,14 @@ use ruma::{DeviceId, OwnedDeviceId, OwnedUserId, UserId}; use serde::{Deserialize, Serialize}; use serde_json::error::Error as JsonError; use thiserror::Error; -use tracing::{debug, error, warn}; +use tracing::{debug, error, info}; use url::Url; use crate::{ application::AppProfile, gettext_f, prelude::*, spawn_tokio, utils::matrix, APP_ID, PROFILE, }; -pub const CURRENT_VERSION: u8 = 4; +pub const CURRENT_VERSION: u8 = 5; const SCHEMA_ATTRIBUTE: &str = "xdg:schema"; static DATA_PATH: Lazy = Lazy::new(|| { @@ -275,21 +275,21 @@ impl StoredSession { }; let secret = match item.secret().await { Ok(secret) => { - if version == 0 { - match Secret::from_utf8(&secret) { + if version <= 4 { + match rmp_serde::from_slice::(&secret) { Ok(secret) => secret, Err(error) => { - error!("Could not parse secret in stored session: {error:?}"); + error!("Could not parse secret in stored session: {error}"); return Err(SecretError::Invalid(gettext( "Malformed secret in stored session", ))); } } } else { - match rmp_serde::from_slice::(&secret) { + match serde_json::from_slice(&secret) { Ok(secret) => secret, Err(error) => { - error!("Could not parse secret in stored session: {error}"); + error!("Could not parse secret in stored session: {error:?}"); return Err(SecretError::Invalid(gettext( "Malformed secret in stored session", ))); @@ -407,7 +407,7 @@ impl StoredSession { let attrs = self.attributes(); let attributes = attrs.iter().map(|(k, v)| (*k, v.as_ref())).collect(); - let secret = rmp_serde::to_vec_named(&self.secret).unwrap(); + let secret = serde_json::to_string(&self.secret).unwrap(); keyring .create_item( @@ -478,34 +478,30 @@ impl StoredSession { Ok(()) } - /// Migrate this session to version 4. - /// - /// This implies moving the database under Fractal's directory. - pub async fn migrate_to_v4(&mut self, item: Item) { - warn!( - "Session {} with version {} found for user {}, migrating to version 4…", - self.id(), - self.version, - self.user_id, - ); + /// Migrate this session to the current version. + pub async fn apply_migrations(&mut self, item: Item) { + if self.version < 4 { + info!("Migrating to version 4…"); - let target_path = DATA_PATH.join(self.id()); + let target_path = DATA_PATH.join(self.id()); - if self.path != target_path { - debug!("Moving database to: {}", target_path.to_string_lossy()); + if self.path != target_path { + debug!("Moving database to: {}", target_path.to_string_lossy()); - if let Err(error) = fs::create_dir_all(&target_path) { - error!("Failed to create new directory: {error}"); + if let Err(error) = fs::create_dir_all(&target_path) { + error!("Failed to create new directory: {error}"); + } + + if let Err(error) = fs::rename(&self.path, &target_path) { + error!("Failed to move database: {error}"); + } + + self.path = target_path; } - - if let Err(error) = fs::rename(&self.path, &target_path) { - error!("Failed to move database: {error}"); - } - - self.path = target_path; } - self.version = 4; + info!("Migrating to version 5…"); + self.version = 5; let clone = self.clone(); spawn_tokio!(async move { @@ -548,14 +544,6 @@ pub struct Secret { pub passphrase: String, } -impl Secret { - /// Converts a vector of bytes to a `Secret`. - pub fn from_utf8(slice: &[u8]) -> Result { - let s = String::from_utf8(slice.to_owned())?; - Ok(serde_json::from_str(&s)?) - } -} - /// Retrieves all sessions stored to the `SecretService` pub async fn restore_sessions() -> Result, SecretError> { let keyring = Keyring::new().await?; @@ -575,15 +563,23 @@ pub async fn restore_sessions() -> Result, SecretError> { Ok(session) => sessions.push(session), Err(SecretError::OldVersion { item, mut session }) => { if session.version == 0 { - warn!( - "Found old session for {} with sled store, removing…", + info!( + "Found old session for user {} with sled store, removing…", session.user_id ); session.delete(Some(item), true).await; - } else if session.version < 4 { - session.migrate_to_v4(item).await; - sessions.push(session); + continue; } + + info!( + "Found session {} for user {} with old version {}, applying migrations…", + session.id(), + session.user_id, + session.version, + ); + session.apply_migrations(item).await; + + sessions.push(session); } Err(SecretError::WrongProfile) => {} Err(error) => {