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-client.workspace = true
|
||||||
wayland-protocols.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]
|
[target.'cfg(target_os = "android")'.dependencies]
|
||||||
android-native-keyring-store.workspace = true
|
android-native-keyring-store.workspace = true
|
||||||
keyring-core.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
|
/// 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.
|
/// 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";
|
const SERVICE: &str = "DarkRoom";
|
||||||
|
|
||||||
/// Secret Service implementation (GNOME Keyring, KWallet via ksecretd).
|
/// The `keyring`-backed store: Secret Service on Linux (GNOME Keyring,
|
||||||
#[cfg(all(unix, not(target_os = "android")))]
|
/// 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;
|
pub struct PlatformSecretStore;
|
||||||
|
|
||||||
#[cfg(all(unix, not(target_os = "android")))]
|
#[cfg(any(all(unix, not(target_os = "android")), windows))]
|
||||||
impl PlatformSecretStore {
|
impl PlatformSecretStore {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
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 {
|
impl Default for PlatformSecretStore {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new()
|
Self::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(unix, not(target_os = "android")))]
|
#[cfg(any(all(unix, not(target_os = "android")), windows))]
|
||||||
impl SecretStore for PlatformSecretStore {
|
impl SecretStore for PlatformSecretStore {
|
||||||
fn store(&self, secret_ref: &SecretRef, secret: &str) -> Result<(), SecretError> {
|
fn store(&self, secret_ref: &SecretRef, secret: &str) -> Result<(), SecretError> {
|
||||||
Self::entry(secret_ref)?
|
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 {
|
fn map_err(e: keyring::Error) -> SecretError {
|
||||||
match e {
|
match e {
|
||||||
keyring::Error::NoEntry => SecretError::NotFound,
|
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
|
/// Failing loudly is deliberate: a silent no-op store would look like it
|
||||||
/// worked and then lose the credential.
|
/// 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;
|
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 {
|
impl PlatformSecretStore {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
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 {
|
impl Default for PlatformSecretStore {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new()
|
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 {
|
impl SecretStore for PlatformSecretStore {
|
||||||
fn store(&self, _r: &SecretRef, _s: &str) -> Result<(), SecretError> {
|
fn store(&self, _r: &SecretRef, _s: &str) -> Result<(), SecretError> {
|
||||||
Err(SecretError::Unavailable(
|
Err(SecretError::Unavailable(
|
||||||
|
|||||||
Reference in New Issue
Block a user