Lines
84.21 %
Functions
80 %
Branches
100 %
//! Keyring migration support for legacy formats
use std::path::PathBuf;
use oo7::{Secret, file::UnlockedKeyring};
use crate::error::Error;
/// Pending keyring migration
#[derive(Clone)]
pub enum PendingMigration {
/// Legacy v0 keyring format
V0 {
name: String,
path: PathBuf,
label: String,
alias: String,
},
/// KWallet keyring format
#[cfg(feature = "kwallet_migration")]
KWallet {
}
impl PendingMigration {
/// Attempt to migrate this keyring with the provided secret
pub async fn migrate(
&self,
data_dir: &PathBuf,
secret: &Secret,
) -> Result<UnlockedKeyring, Error> {
match self {
Self::V0 { path, name, .. } => {
tracing::debug!("Migrating v0 keyring: {}", name);
let unlocked = UnlockedKeyring::open_at(data_dir, name, secret.clone()).await?;
// Write migrated keyring
unlocked.write().await?;
tracing::info!("Wrote migrated keyring '{}' to disk", name);
// Cleanup old file
if let Err(e) = tokio::fs::remove_file(path).await {
tracing::warn!("Failed to remove v0 keyring at {:?}: {}", path, e);
} else {
tracing::info!("Removed v0 keyring file at {:?}", path);
tracing::info!("Successfully migrated v0 keyring '{}'", name);
Ok(unlocked)
Self::KWallet { path, name, .. } => {
tracing::debug!("Migrating KWallet keyring: {}", name);
// Parse KWallet file in blocking task
let path_clone = path.clone();
let password = secret.to_vec();
let wallet = tokio::task::spawn_blocking(move || {
kwallet_parser::KWalletFile::open(&path_clone, &password)
})
.await
.map_err(|e| {
Error::IO(std::io::Error::other(format!("Task join error: {}", e)))
})??;
tracing::info!("Parsed KWallet file '{}'", name);
// Create new oo7 keyring
// Convert KWallet entries to oo7 items
let mut items = Vec::new();
for (folder_name, folder) in wallet.wallet() {
for (entry_key, entry) in folder {
match kwallet_parser::convert_entry(folder_name, entry_key, entry) {
Ok(ss_entry) => {
items.push((
ss_entry.label().to_owned(),
ss_entry.attributes().to_owned(),
Secret::blob(ss_entry.secret()),
true,
));
Err(e) => {
tracing::warn!(
"Skipping entry {}/{}: {}",
folder_name,
entry_key,
e
);
unlocked.create_items(items).await?;
tracing::info!("Migrated KWallet entries to oo7 format for '{}'", name);
// Cleanup old files
tracing::warn!("Failed to remove KWallet file at {:?}: {}", path, e);
tracing::info!("Removed KWallet file at {:?}", path);
// Try to remove salt file if it exists
let salt_path = path.with_extension("salt");
if salt_path.exists() {
if let Err(e) = tokio::fs::remove_file(&salt_path).await {
"Failed to remove KWallet salt file at {:?}: {}",
salt_path,
tracing::info!("Removed KWallet salt file at {:?}", salt_path);
tracing::info!("Successfully migrated KWallet keyring '{}'", name);
pub fn name(&self) -> &str {
Self::V0 { name, .. } => name,
Self::KWallet { name, .. } => name,
pub fn label(&self) -> &str {
Self::V0 { label, .. } => label,
Self::KWallet { label, .. } => label,
pub fn alias(&self) -> &str {
Self::V0 { alias, .. } => alias,
Self::KWallet { alias, .. } => alias,
pub fn path(&self) -> &PathBuf {
Self::V0 { path, .. } => path,
Self::KWallet { path, .. } => path,