Skip to content

Commit

Permalink
Merge pull request #215 from brotskydotcom/issue-214
Browse files Browse the repository at this point in the history
Allow use of both linux-native and secret-service keystores. Make secret-service be the default in this case.
  • Loading branch information
brotskydotcom authored Oct 12, 2024
2 parents 27a7b35 + 88c2ae5 commit 900fd68
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 39 deletions.
12 changes: 7 additions & 5 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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"
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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).
Expand Down
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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/"]
Expand All @@ -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 }
Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -136,6 +136,7 @@ Thanks to the following for helping make this library better, whether through co
- @ryanavella
- @samuela
- @ShaunSHamilton
- @soywod
- @stankec
- @steveatinfincia
- @Sytten
Expand Down
66 changes: 36 additions & 30 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;

Expand All @@ -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;

Expand Down

0 comments on commit 900fd68

Please sign in to comment.