chore(deps): migrate keyring from 3 to 4

keyring v4 is no longer a library crate; the API moved to keyring-core
plus per-platform credential store crates. Replace the keyring dependency
with keyring-core and the native store crates, and register the default
store at runtime (lazily, once) since v4 no longer selects it at compile
time via Cargo features.
This commit is contained in:
Christian Visintin
2026-06-08 19:15:11 +02:00
parent bca261b7b2
commit b1601fb17e
4 changed files with 131 additions and 19 deletions

94
Cargo.lock generated
View File

@@ -110,6 +110,17 @@ version = "1.0.102"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
[[package]]
name = "apple-native-keyring-store"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7be2f067ccd8d4b4d4a66ddafe0f32a5dff31732f32dbff85fefc40929b1f72"
dependencies = [
"keyring-core",
"log",
"security-framework 3.7.0",
]
[[package]]
name = "approx"
version = "0.5.1"
@@ -1417,11 +1428,29 @@ version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "708b509edf7889e53d7efb0ffadd994cc6c2345ccb62f55cfd6b0682165e4fa6"
dependencies = [
"aes 0.8.4",
"block-padding 0.3.3",
"cbc 0.1.2",
"dbus",
"fastrand",
"hkdf 0.12.4",
"num",
"once_cell",
"openssl",
"sha2 0.10.9",
"zeroize",
]
[[package]]
name = "dbus-secret-service-keyring-store"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21d8f54da401bb5eb2a4d873ac4b359f4a599df2ca8634bb5b8c045e5ee78757"
dependencies = [
"dbus-secret-service",
"keyring-core",
]
[[package]]
name = "delegate"
version = "0.13.5"
@@ -2973,19 +3002,12 @@ dependencies = [
]
[[package]]
name = "keyring"
version = "3.6.3"
name = "keyring-core"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eebcc3aff044e5944a8fbaf69eb277d11986064cba30c468730e8b9909fb551c"
checksum = "fb1e621458ca9c51aa110bd0339d4751a056b9576bf1253aee1aa560dda0fc9d"
dependencies = [
"byteorder",
"dbus-secret-service",
"log",
"openssl",
"security-framework 2.11.1",
"security-framework 3.7.0",
"windows-sys 0.60.2",
"zeroize",
]
[[package]]
@@ -3463,6 +3485,20 @@ dependencies = [
"unicode-segmentation",
]
[[package]]
name = "num"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23"
dependencies = [
"num-bigint",
"num-complex",
"num-integer",
"num-iter",
"num-rational",
"num-traits",
]
[[package]]
name = "num-bigint"
version = "0.4.6"
@@ -3489,6 +3525,15 @@ dependencies = [
"zeroize",
]
[[package]]
name = "num-complex"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
dependencies = [
"num-traits",
]
[[package]]
name = "num-conv"
version = "0.2.2"
@@ -3515,6 +3560,17 @@ dependencies = [
"num-traits",
]
[[package]]
name = "num-rational"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
dependencies = [
"num-bigint",
"num-integer",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.19"
@@ -6164,6 +6220,7 @@ version = "1.0.0"
dependencies = [
"aes 0.9.1",
"aes-gcm 0.10.3",
"apple-native-keyring-store",
"argh",
"base64 0.22.1",
"bitflags 2.13.0",
@@ -6172,10 +6229,11 @@ dependencies = [
"cfg_aliases",
"chrono",
"content_inspector",
"dbus-secret-service-keyring-store",
"dirs",
"edit",
"filetime",
"keyring",
"keyring-core",
"lazy-regex",
"log",
"md-5 0.11.0",
@@ -6213,6 +6271,7 @@ dependencies = [
"vergen-git2",
"whoami",
"wildmatch",
"windows-native-keyring-store",
]
[[package]]
@@ -7275,6 +7334,19 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
name = "windows-native-keyring-store"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "063426e76fdec7438d56bb777f67e318a84a25c707b07e575cb8b78e10c028f8"
dependencies = [
"byteorder",
"keyring-core",
"regex",
"windows-sys 0.61.2",
"zeroize",
]
[[package]]
name = "windows-numerics"
version = "0.2.0"

View File

@@ -48,12 +48,7 @@ content_inspector = "0.2"
dirs = "6"
edit = "0.1"
filetime = "0.2"
keyring = { version = "3", features = [
"apple-native",
"sync-secret-service",
"vendored",
"windows-native",
] }
keyring-core = "1"
lazy-regex = "3"
log = "0.4"
md-5 = "0.11"
@@ -95,6 +90,12 @@ unicode-width = "0.2"
whoami = "2"
wildmatch = "2"
[target."cfg(any(target_os = \"linux\", target_os = \"freebsd\"))".dependencies]
dbus-secret-service-keyring-store = { version = "1", features = [
"crypto-rust",
"vendored",
] }
[target."cfg(target_family = \"unix\")".dependencies]
remotefs-ftp = { version = "0.4", features = [
"native-tls",
@@ -105,6 +106,12 @@ uzers = "0.12"
[target."cfg(target_family = \"windows\")".dependencies]
remotefs-ftp = { version = "0.4", features = ["native-tls"] }
[target."cfg(target_os = \"macos\")".dependencies]
apple-native-keyring-store = { version = "1", features = ["keychain"] }
[target."cfg(target_os = \"windows\")".dependencies]
windows-native-keyring-store = "1"
[dev-dependencies]
pretty_assertions = "1"
serial_test = "3"

View File

@@ -6,7 +6,7 @@
pub mod filestorage;
pub mod keyringstorage;
// ext
use keyring::Error as KeyringError;
use keyring_core::Error as KeyringError;
use thiserror::Error;
/// defines the error type for the `KeyStorage`

View File

@@ -4,10 +4,40 @@
// Local
// Ext
use keyring::{Entry as Keyring, Error as KeyringError};
use std::sync::Once;
use keyring_core::{Entry as Keyring, Error as KeyringError};
use super::{KeyStorage, KeyStorageError};
/// Guards the one-time registration of the process-wide default credential store.
static INIT_STORE: Once = Once::new();
/// Registers the native credential store as `keyring-core`'s process-wide default.
///
/// Unlike `keyring` 3.x, which selected the credential store at compile time via
/// Cargo features, `keyring-core` 4.x requires the application to register a store
/// at runtime *before* creating any [`Keyring`] entry. We do this lazily and
/// exactly once, choosing the native store for the current platform. On platforms
/// with no supported store nothing is registered, so [`Keyring`] operations fail
/// and the caller transparently falls back to file-based storage.
fn ensure_default_store() {
INIT_STORE.call_once(|| {
#[cfg(target_os = "macos")]
if let Ok(store) = apple_native_keyring_store::keychain::Store::new() {
keyring_core::set_default_store(store);
}
#[cfg(target_os = "windows")]
if let Ok(store) = windows_native_keyring_store::Store::new() {
keyring_core::set_default_store(store);
}
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
if let Ok(store) = dbus_secret_service_keyring_store::Store::new() {
keyring_core::set_default_store(store);
}
});
}
/// provides a `KeyStorage` implementation using the keyring crate
pub struct KeyringStorage {
username: String,
@@ -27,6 +57,7 @@ impl KeyStorage for KeyringStorage {
/// The key might be acccess through an identifier, which identifies
/// the key in the storage
fn get_key(&self, storage_id: &str) -> Result<String, KeyStorageError> {
ensure_default_store();
let storage: Keyring = Keyring::new(storage_id, self.username.as_str())?;
match storage.get_password() {
Ok(s) => Ok(s),
@@ -46,6 +77,7 @@ impl KeyStorage for KeyringStorage {
/// Set the key into the key storage
fn set_key(&self, storage_id: &str, key: &str) -> Result<(), KeyStorageError> {
ensure_default_store();
let storage: Keyring = Keyring::new(storage_id, self.username.as_str())?;
match storage.set_password(key) {
Ok(_) => Ok(()),
@@ -57,6 +89,7 @@ impl KeyStorage for KeyringStorage {
///
/// Returns whether the key storage is supported on the host system
fn is_supported(&self) -> bool {
ensure_default_store();
let dummy: String = String::from("dummy-service");
let storage: Keyring = match Keyring::new(dummy.as_str(), self.username.as_str()) {
Ok(s) => s,