Skip to content

Commit 2a408a1

Browse files
committed
fix: support KWallet for cookie key retrieval on Linux
1 parent 3a7df0e commit 2a408a1

File tree

1 file changed

+36
-0
lines changed

1 file changed

+36
-0
lines changed

src/browser/profile_porter.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,10 +448,45 @@ fn get_macos_key_provider(browser: BrowserId) -> Result<KeyProvider> {
448448
})
449449
}
450450

451+
/// KWallet keyring name for a browser, matching Chromium's convention.
452+
/// Ref: https://chromium.googlesource.com/chromium/src/+/refs/heads/main/components/os_crypt/sync/key_storage_kwallet.cc
453+
fn kwallet_keyring_name(browser: BrowserId) -> &'static str {
454+
match browser {
455+
BrowserId::Chrome => "Chrome",
456+
BrowserId::Brave => "Brave",
457+
BrowserId::Edge | BrowserId::Opera => "Chromium",
458+
BrowserId::Vivaldi => "Chrome",
459+
BrowserId::Arc => "Arc",
460+
}
461+
}
462+
463+
fn try_kwallet_password(browser: BrowserId) -> Option<String> {
464+
let name = kwallet_keyring_name(browser);
465+
let output = std::process::Command::new("kwallet-query")
466+
.args([
467+
"--read-password",
468+
&format!("{name} Safe Storage"),
469+
"--folder",
470+
&format!("{name} Keys"),
471+
"kdewallet",
472+
])
473+
.output()
474+
.ok()?;
475+
if !output.status.success() {
476+
return None;
477+
}
478+
let pw = String::from_utf8_lossy(&output.stdout).trim().to_string();
479+
if pw.is_empty() || pw.to_lowercase().starts_with("failed to read") {
480+
return None;
481+
}
482+
Some(pw)
483+
}
484+
451485
fn get_linux_key_provider(browser: BrowserId) -> Result<KeyProvider> {
452486
let desc = browser.descriptor();
453487
let app_name = desc.keychain_service_for_current_os();
454488

489+
// Try GNOME/freedesktop secret service first, then KWallet, then "peanuts" fallback.
455490
let passphrase = if let Some(app) = app_name {
456491
std::process::Command::new("secret-tool")
457492
.args(["lookup", "application", app])
@@ -460,6 +495,7 @@ fn get_linux_key_provider(browser: BrowserId) -> Result<KeyProvider> {
460495
.filter(|o| o.status.success())
461496
.map(|o| String::from_utf8_lossy(&o.stdout).trim().to_string())
462497
.filter(|s| !s.is_empty())
498+
.or_else(|| try_kwallet_password(browser))
463499
.unwrap_or_else(|| "peanuts".to_string())
464500
} else {
465501
"peanuts".to_string()

0 commit comments

Comments
 (0)