mirror of
https://github.com/nimbold/Firelink.git
synced 2026-08-07 09:53:17 +00:00
fix(security): redact secrets from plaintext persistence
- Strip password, cookies, and headers from download_queue before writing to store.bin; secrets remain in-memory for the active session only. - Move extension pairing token from PersistedSettings to the OS keychain, rotating it on upgrade from versions that persisted it as plaintext. - Add ignores_legacy_extension_pairing_token_field test to confirm serde silently drops the old field so existing installs migrate cleanly. - Document intentional retention of URLs (signed params are the download source and cannot be redacted without breaking resume/retry).
This commit is contained in:
@@ -237,7 +237,10 @@ pub struct PersistedSettings {
|
||||
pub media_cookie_source: MediaCookieSource,
|
||||
pub download_directories: HashMap<String, String>,
|
||||
pub site_logins: Vec<SiteLogin>,
|
||||
pub extension_pairing_token: String,
|
||||
// Note: `extension_pairing_token` is intentionally NOT persisted here. It
|
||||
// is an HMAC shared secret and is stored in the OS keychain by the
|
||||
// frontend. The field is kept on legacy persisted JSON only; serde ignores
|
||||
// unknown fields when decoding, so existing installs migrate cleanly.
|
||||
pub auto_check_updates: bool,
|
||||
}
|
||||
|
||||
|
||||
@@ -168,7 +168,6 @@ fn default_settings() -> PersistedSettings {
|
||||
media_cookie_source: MediaCookieSource::None,
|
||||
download_directories,
|
||||
site_logins: Vec::new(),
|
||||
extension_pairing_token: String::new(),
|
||||
auto_check_updates: true,
|
||||
}
|
||||
}
|
||||
@@ -229,4 +228,24 @@ mod tests {
|
||||
|
||||
assert_eq!(settings.max_concurrent_downloads, 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ignores_legacy_extension_pairing_token_field() {
|
||||
// Older versions persisted `extensionPairingToken` as plaintext inside
|
||||
// the settings document. It now lives in the OS keychain and is no
|
||||
// longer part of PersistedSettings. serde ignores the unknown field so
|
||||
// existing installs decode without error; the plaintext value is
|
||||
// simply dropped and a fresh token is minted by the frontend.
|
||||
let stored = json!({
|
||||
"state": {
|
||||
"extensionPairingToken": "plaintext-leaked-secret",
|
||||
"maxConcurrentDownloads": 5
|
||||
},
|
||||
"version": 0
|
||||
});
|
||||
|
||||
let settings = decode_stored_settings(&Value::String(stored.to_string())).unwrap();
|
||||
|
||||
assert_eq!(settings.max_concurrent_downloads, 5);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user