-
Notifications
You must be signed in to change notification settings - Fork 732
Description
Bug
get_or_create_key() in src/credential_store.rs unconditionally writes the encryption key to ~/.config/gws/.encryption_key on first run, before attempting to store it in the OS keyring. The file is never cleaned up after a successful keyring store.
This means on a macOS machine with a fully functional Keychain, the encryption key exists in two places:
- macOS Keychain (protected by login credentials / biometrics)
~/.config/gws/.encryption_key(protected only by file permissions0600)
Impact
The file-based key makes credential files portable — copying the entire ~/.config/gws/ directory to another machine transfers both the encrypted credentials and the key needed to decrypt them, defeating the purpose of keyring-based key storage.
Root Cause
In credential_store.rs lines 64–120, the Err(keyring::Error::NoEntry) branch:
- Generates a random 256-bit key
- Writes it to
.encryption_key(lines 102–115) - Then does best-effort
entry.set_password()(line 118)
The file write happens unconditionally regardless of whether the keyring store succeeds.
Proposed Fix
Only write .encryption_key as a fallback when the keyring is unavailable:
// Generate key
let mut key = [0u8; 32];
rand::thread_rng().fill_bytes(&mut key);
let b64_key = STANDARD.encode(key);
// Try keyring first
if entry.set_password(&b64_key).is_err() {
// Keyring failed — persist to file as fallback
write_key_file(&key_file, &b64_key);
} else {
// Keyring succeeded — clean up any stale file
let _ = std::fs::remove_file(&key_file);
}Verification
ls -la ~/.config/gws/.encryption_key
# Should NOT exist on systems with a working keyring