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.
This commit is contained in:
Kévin Commaille 2023-11-27 13:10:22 +01:00 committed by Kévin Commaille
parent d534071ad2
commit 2e86784161

View file

@ -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<PathBuf> = 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>(&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>(&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<Self, FromUtf8SecretError> {
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<Vec<StoredSession>, SecretError> {
let keyring = Keyring::new().await?;
@ -575,15 +563,23 @@ pub async fn restore_sessions() -> Result<Vec<StoredSession>, 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) => {