Keep secrets in Credential Manager on Windows
The Secret Service store was keyring::Entry all the way down, and keyring 4's v1 feature set — the one the workspace already asks for — includes the Windows Credential Manager backend. So the Windows store is the same implementation with its cfg widened, and the crate as a target dependency. The one behavioural difference is that the availability probe always succeeds there, which is correct: Credential Manager is always present, so FR-NC-2's degraded mode does not arise. Until now a Windows build compiled, started, and failed at sign-in with the placeholder store's "no secret store is implemented".
This commit is contained in:
@@ -24,6 +24,11 @@ x11rb.workspace = true
|
||||
wayland-client.workspace = true
|
||||
wayland-protocols.workspace = true
|
||||
|
||||
# The same crate on Windows: its `v1` features include the Credential Manager
|
||||
# backend, and `secrets.rs` is one implementation over both.
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
keyring.workspace = true
|
||||
|
||||
[target.'cfg(target_os = "android")'.dependencies]
|
||||
android-native-keyring-store.workspace = true
|
||||
keyring-core.workspace = true
|
||||
|
||||
@@ -100,14 +100,22 @@ pub trait SecretStore: Send + Sync {
|
||||
///
|
||||
/// Used by the two stores that have somewhere to file them; the placeholder
|
||||
/// below has nothing to name, and a Windows build otherwise warns here.
|
||||
#[cfg(any(all(unix, not(target_os = "android")), target_os = "android"))]
|
||||
#[cfg(any(all(unix, not(target_os = "android")), windows, target_os = "android"))]
|
||||
const SERVICE: &str = "DarkRoom";
|
||||
|
||||
/// Secret Service implementation (GNOME Keyring, KWallet via ksecretd).
|
||||
#[cfg(all(unix, not(target_os = "android")))]
|
||||
/// The `keyring`-backed store: Secret Service on Linux (GNOME Keyring,
|
||||
/// KWallet via ksecretd), Credential Manager on Windows.
|
||||
///
|
||||
/// One implementation for both because `keyring::Entry` is the same API over
|
||||
/// either, and its `v1` feature set already includes the Windows backend. The
|
||||
/// difference is in what "unavailable" means: a Linux desktop may have no
|
||||
/// secrets daemon, which FR-NC-2 treats as a stated degraded mode, while
|
||||
/// Credential Manager is always present — so on Windows `is_available` is a
|
||||
/// probe that always succeeds, and that is correct rather than optimistic.
|
||||
#[cfg(any(all(unix, not(target_os = "android")), windows))]
|
||||
pub struct PlatformSecretStore;
|
||||
|
||||
#[cfg(all(unix, not(target_os = "android")))]
|
||||
#[cfg(any(all(unix, not(target_os = "android")), windows))]
|
||||
impl PlatformSecretStore {
|
||||
pub fn new() -> Self {
|
||||
Self
|
||||
@@ -118,14 +126,14 @@ impl PlatformSecretStore {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(unix, not(target_os = "android")))]
|
||||
#[cfg(any(all(unix, not(target_os = "android")), windows))]
|
||||
impl Default for PlatformSecretStore {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(unix, not(target_os = "android")))]
|
||||
#[cfg(any(all(unix, not(target_os = "android")), windows))]
|
||||
impl SecretStore for PlatformSecretStore {
|
||||
fn store(&self, secret_ref: &SecretRef, secret: &str) -> Result<(), SecretError> {
|
||||
Self::entry(secret_ref)?
|
||||
@@ -160,7 +168,7 @@ impl SecretStore for PlatformSecretStore {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(unix, not(target_os = "android")))]
|
||||
#[cfg(any(all(unix, not(target_os = "android")), windows))]
|
||||
fn map_err(e: keyring::Error) -> SecretError {
|
||||
match e {
|
||||
keyring::Error::NoEntry => SecretError::NotFound,
|
||||
@@ -265,24 +273,24 @@ fn map_err(e: keyring_core::Error) -> SecretError {
|
||||
///
|
||||
/// Failing loudly is deliberate: a silent no-op store would look like it
|
||||
/// worked and then lose the credential.
|
||||
#[cfg(not(any(all(unix, not(target_os = "android")), target_os = "android")))]
|
||||
#[cfg(not(any(all(unix, not(target_os = "android")), windows, target_os = "android")))]
|
||||
pub struct PlatformSecretStore;
|
||||
|
||||
#[cfg(not(any(all(unix, not(target_os = "android")), target_os = "android")))]
|
||||
#[cfg(not(any(all(unix, not(target_os = "android")), windows, target_os = "android")))]
|
||||
impl PlatformSecretStore {
|
||||
pub fn new() -> Self {
|
||||
Self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(any(all(unix, not(target_os = "android")), target_os = "android")))]
|
||||
#[cfg(not(any(all(unix, not(target_os = "android")), windows, target_os = "android")))]
|
||||
impl Default for PlatformSecretStore {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(any(all(unix, not(target_os = "android")), target_os = "android")))]
|
||||
#[cfg(not(any(all(unix, not(target_os = "android")), windows, target_os = "android")))]
|
||||
impl SecretStore for PlatformSecretStore {
|
||||
fn store(&self, _r: &SecretRef, _s: &str) -> Result<(), SecretError> {
|
||||
Err(SecretError::Unavailable(
|
||||
|
||||
Reference in New Issue
Block a user