diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index c351613..7419f3d 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -3,11 +3,11 @@ name: CI on: [ workflow_dispatch, push, pull_request ] jobs: - ci_native: + ci_non_nix: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ ubuntu-latest, macos-latest, windows-latest ] + os: [ macos-latest, windows-latest ] steps: - name: Fetch head @@ -35,17 +35,19 @@ jobs: run: cargo clippy -- -D warnings - name: Build and Test - run: cargo test --features=apple-native,windows-native,linux-native --verbose + run: cargo test --features=apple-native,windows-native --verbose - name: Build the CLI release - run: cargo build --release --features=apple-native,windows-native,linux-native --example keyring-cli + run: cargo build --release --features=apple-native,windows-native --example keyring-cli - ci_secret_service: + ci_nix: runs-on: ubuntu-latest strategy: matrix: features: + - "linux-native" - "sync-secret-service" + - "linux-native,sync-secret-service" - "sync-secret-service,crypto-rust" - "sync-secret-service,crypto-openssl" - "async-secret-service,tokio,crypto-rust" diff --git a/CHANGELOG.md b/CHANGELOG.md index c8cb30a..9779049 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## Version 3.4.0 +- Allow use of both secret-service and keyutils. + ## Version 3.3.0 - Add support for credential-store attributes other than those used by this crate. This allows the creation of credentials that are more compatible with 3rd-party clients, such as the OS-provided GUIs over credentials. - Make the textual descriptions of entries consistently follow the form `user@service` (or `user@service:target` if a target was specified). diff --git a/Cargo.toml b/Cargo.toml index 388629a..1dc7919 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ keywords = ["password", "credential", "keychain", "keyring", "cross-platform"] license = "MIT OR Apache-2.0" name = "keyring" repository = "https://github.com/hwchen/keyring-rs.git" -version = "3.3.0" +version = "3.4.0" rust-version = "1.75" edition = "2021" exclude = [".github/"] @@ -29,7 +29,7 @@ vendored = ["dbus-secret-service?/vendored", "openssl?/vendored"] openssl = { version = "0.10.55", optional = true } [target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies] # see issue #190 -security-framework = { version = "2", optional = true } +security-framework = { version = "3", optional = true } [target.'cfg(target_os = "linux")'.dependencies] secret-service = { version = "4", optional = true } diff --git a/README.md b/README.md index f41c36b..ff0ec5b 100644 --- a/README.md +++ b/README.md @@ -61,9 +61,9 @@ This crate provides built-in implementations of the following platform-specific * _macOS_, _iOS_: The local keychain. * _Windows_: The Windows Credential Manager. -To enable the stores you want, you use features: there is one feature for each possibly-included credential store. If you specify a feature (e.g., `dbus-secret-service`) _and_ your target platform (e.g., `freebsd`) supports that credential store, it will be included as the default credential store in that build. That way you can have a build command that specifies a single credential store for each of your target platforms, and use that same build command for all targets. (You cannot enable more than one keystore for a given platform, except when producing docs.) +To enable the stores you want, you use features: there is one feature for each possibly-included credential store. If you specify a feature (e.g., `dbus-secret-service`) _and_ your target platform (e.g., `freebsd`) supports that credential store, it will be included as the default credential store in that build. That way you can have a build command that specifies a single credential store for each of your target platforms, and use that same build command for all targets. -If you don't enable any credential stores that are supported on a specific target, the _mock_ keystore will be the default on that target. If you enable multiple credential stores for a specific target, you will get a compile error. See the [developer docs](https://docs.rs/keyring/) for details of which features control the inclusion of which credential stores (and which platforms each credential store targets). +If you don't enable any credential stores that are supported on a given platform, or you enable multiple credential stores for some platform, the _mock_ keystore will be the default on that platform. See the [developer docs](https://docs.rs/keyring/) for details of which features control the inclusion of which credential stores (and which platforms each credential store targets). ### Platform-specific issues @@ -136,6 +136,7 @@ Thanks to the following for helping make this library better, whether through co - @ryanavella - @samuela - @ShaunSHamilton +- @soywod - @stankec - @steveatinfincia - @Sytten diff --git a/src/lib.rs b/src/lib.rs index 24447db..3677623 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -64,9 +64,9 @@ example, the macOS Keychain credential store is only included if the `"apple-nat feature is specified (and the crate is built with a macOS target). If no specified credential store features apply to a given platform, +or multiple credential store features apply to a given platform, this crate will use the (platform-independent) _mock_ credential store (see below) -on that platform. Specifying multiple credential store features for a given -platform is not supported, and will cause compile-time errors. There are no +on that platform. There are no default features in this crate: you must specify explicitly which platform-specific credential stores you intend to use. @@ -99,6 +99,18 @@ Here are the available credential store features: installed on the user's machine, specify the `vendored` feature to statically link them with the built crate. +You cannot specify both the `sync-secret-service` and `async-secret-service` features; +this will produce a compile error. You must pick one or the other if you want to use +the secret service for credential storage. + +The Linux platform is the only one for which this crate supplies multiple keystores: +secret-service and keyutils. The secret-service is the more widely used store, because +it provides persistence of credentials beyond reboot (which keyutils does not). However, +because secret-service relies on system UI for unlocking credentials, it often isn't +available on headless Linux installations, so keyutils is provided for those situations. +If you enable both the secret-service store and the keyutils store, the secret-service +store will be used as the default. + ## Client-provided Credential Stores In addition to the platform stores implemented by this crate, clients @@ -168,31 +180,22 @@ use std::collections::HashMap; pub mod mock; // -// no duplicate keystores on any platform +// can't use both sync and async secret service // -#[cfg(all( - not(doc), - any( - all(feature = "linux-native", feature = "sync-secret-service"), - all(feature = "linux-native", feature = "async-secret-service"), - all(feature = "sync-secret-service", feature = "async-secret-service") - ) -))] -compile_error!("You can enable at most one keystore per target architecture"); +#[cfg(all(feature = "sync-secret-service", feature = "async-secret-service"))] +compile_error!("This crate cannot use the secret-service both synchronously and asynchronously"); // -// Pick the *nix keystore +// pick the *nix keystore // #[cfg(all(target_os = "linux", feature = "linux-native"))] pub mod keyutils; +// use keyutils as default if secret-service is not available #[cfg(all( target_os = "linux", feature = "linux-native", - not(all( - doc, - any(feature = "sync-secret-service", feature = "async-secret-service") - )) + not(any(feature = "sync-secret-service", feature = "async-secret-service")) ))] pub use keyutils as default; @@ -201,24 +204,27 @@ pub use keyutils as default; any(feature = "sync-secret-service", feature = "async-secret-service") ))] pub mod secret_service; +// use secret-service as default if it's available #[cfg(all( any(target_os = "linux", target_os = "freebsd", target_os = "openbsd"), - any(feature = "sync-secret-service", feature = "async-secret-service") + any(feature = "sync-secret-service", feature = "async-secret-service"), ))] pub use secret_service as default; -#[cfg(all( - target_os = "linux", - not(any( - feature = "linux-native", - feature = "sync-secret-service", - feature = "async-secret-service" - )) -))] -pub use mock as default; -#[cfg(all( - any(target_os = "freebsd", target_os = "openbsd"), - not(any(feature = "sync-secret-service", feature = "async-secret-service")) +// fallback to mock if neither keyutils nor secret service is available +#[cfg(any( + all( + target_os = "linux", + not(any( + feature = "linux-native", + feature = "sync-secret-service", + feature = "async-secret-service" + )) + ), + all( + any(target_os = "freebsd", target_os = "openbsd"), + not(any(feature = "sync-secret-service", feature = "async-secret-service")) + ) ))] pub use mock as default;