Git Product home page Git Product logo

keyring-rs's Introduction

Keyring-rs

build dependencies crates.io docs.rs

A cross-platform library to manage storage and retrieval of passwords (and other secrets) in the underlying platform secure store, with a fully-developed example that provides a command-line interface.

Usage

To use this library in your project add the following to your Cargo.toml file:

[dependencies]
keyring = "2"

This will give you access to the keyring crate in your code. Now you can use the Entry::new function to create a new keyring entry. The new function takes a service name and a user name which together identify the entry.

Passwords can be added to an entry using its set_password method. They can then be read back using the get_password method, and removed using the delete_password method.

use keyring::{Entry, Result};

fn main() -> Result<()> {
    let entry = Entry::new("my_service", "my_name")?;
    entry.set_password("topS3cr3tP4$$w0rd")?;
    let password = entry.get_password()?;
    println!("My password is '{}'", password);
    entry.delete_password()?;
    Ok(())
}

Errors

Creating and operating on entries can yield a keyring::Error which provides both a platform-independent code that classifies the error and, where relevant, underlying platform errors or more information about what went wrong.

Examples

The keychain-rs project contains a sample application (cli) and a sample library (ios).

The cli application is a command-line interface to the keyring. It can be used to explore how the library is used. It can also be used in debugging keyring-based applications to probe the contents of the credential store.

The ios library is a full exercise of all the iOS functionality; it's meant to be loaded into an iOS test harness such as the one found in this project. While the library can be compiled and linked to on macOS as well, doing so doesn't provide any advantages over the standard macOS tests.

Client Testing

This crate comes with a mock credential store that can be used by clients who want to test without accessing the native platform store. The mock store is cross-platform and allows mocking errors as well as successes.

Extensibility

This crate allows clients to "bring their own credential store" by providing traits that clients can implement. See the developer docs for details.

Platforms

This crate provides secure storage support for Linux (secret-service and kernel keyutils), iOS (keychain), macOS (keychain), and Windows (credential manager). It also builds on FreeBSD and OpenBSD (secret-service), and probably works there, but since neither the maintainers nor GitHub do testing on BSD variants, we rely on contributors to support these platforms. Thanks for your help!

The default features of this crate are set up to build all the available platform support. So, for example, if you build on macOS, then keychain support is enabled by loading other underlying crates that the keychain credential store requires.

On Linux, there are two supported platform credential stores: the secret-service and the kernel keyutils, and both are built by default. If you only want to use one or the other, then you must turn off default features in your dependency specification and explicitly specify the feature for the platform support you want. For example, you might use

keyring = { version = "2", default_features = false, features = ["linux-secret-service"] }

If you don't build any of the platform support features, then you will get the mock keystore as your default.

PLEASE NOTE: As of version 2.2, turning off the default feature set will turn off platform support on all platforms, not just on Linux (as was the case before). While this behavior is a breaking change on Mac, Windows, FreeBSD and OpenBSD, the behavior on those platforms before was unintended and undefined (suppressing default features did nothing), so this is considered a bug fix rather than a semver-breaking change that requires a major version bump.

ALSO NOTE: Although the TOML file for this crate specifies a minimum Rust version of 1.68, that version apples to the library builds only. The TOML has development dependencies that require Rust 1.70. We keep each major version of the library compiling on Rust versions that are at least as old as the initial release of that major version.

Upgrading from v1

The v2 release, although it adds a lot of functionality relative to v1, is fully compatible with respect to persisted entry data: it will both read and set passwords on entries that were originally written by v1, and entries written by v2 will be readable and updatable by v1.

From a client API point of view, the biggest difference between v2 and v1 is that entry creation using Entry::new and Entry::new_with_target can now fail, so v1 client code will need to add an unwrap or other error handling in order to work with v2.

There are also new Error variants in v2, and the enum has been declared non-exhaustive (to allow for variants to be added without breaking client code). This means that v1 client code that relies on exhaustive matching will need to be updated.

License

Licensed under either of

at your option.

Contributors

Thanks to the following for helping make this library better, whether through contributing code, discussion, or bug reports!

  • @Alexei-Barnes
  • @benwr
  • @bhkaminski
  • @brotskydotcom
  • @complexspaces
  • @connor4312
  • @dario23
  • @dten
  • @gondolyr
  • @hwchen
  • @jankatins
  • @jasikpark
  • @jkhsjdhjs
  • @jonathanmorley
  • @jyuch
  • @klemensn
  • @landhb
  • @lexxvir
  • @MaikKlein
  • @Phrohdoh
  • @phlip9
  • @ReactorScram
  • @Rukenshia
  • @russellbanks
  • @ryanavella
  • @samuela
  • @stankec
  • @steveatinfincia
  • @Sytten
  • @VorpalBlade
  • @thewh1teagle

If you should be on this list, but don't find yourself, please contact @brotskydotcom.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

keyring-rs's People

Contributors

adobedan avatar alexei-barnes avatar brotskydotcom avatar dependabot[bot] avatar hwchen avatar jasikpark avatar jonathanmorley avatar jyuch avatar klemensn avatar landhb avatar lexxvir avatar maikklein avatar monorkin avatar nagasunilt avatar phlip9 avatar russellbanks avatar spazmotic avatar steveatinfincia avatar uniphil avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

keyring-rs's Issues

Mobile Support

I may be way out in left field here, but would it every make sense to add support for android and iOS to keyring-rs? It seems like a unified keyring interface could be powerful as Rust continues to make inroads into the mobile space.

Use `zeroize`

Hi, when I came across this crate, zeroize came to mind, would this crate potentially benefit from zeroing out credentials when dropped?

Limited storage for credentials on Windows when using UTF8

I've got a use case for this library (Storing JWTs) which requires storing passwords of length ~1,500 bytes. This (encoded with UTF8) should fit fine in the max storage size of a Windows credential, of 5*512 (2,560) bytes.

However, because this library only offers using the CredWriteW method of storing credentials, it only stores them as UTF16. This effectively halves the available storage for ASCII encoded data such as a JWT to 1,280 bytes.

I suggest that we introduce a new pair of features, windows-utf16 and windows-utf8 (with windows-utf16 as a default feature) that switch between UTF16 with CredWriteW, and UTF8 with CredWriteA. If this is a suggestion that you like, I'm happy to create a PR for that approach. Otherwise I'm open to hearing better approaches to solving my problem.

Unreliable behavior of delete_password() across operating systems

After your comment I've created a short POC which (reproducably) succeeds on Linux, but fails on macOS and Windows:

extern crate keyring;

use keyring::{Keyring, KeyringError};

fn main() -> Result<(), KeyringError> {
    let service = "ce06501c7f791b4d653effb50f234cd6fa451c734054acb9936c14e965abf37d";
    let username = "username";

    let keyring = Keyring::new(service, username);
    match keyring.delete_password() {
        Err(KeyringError::NoPasswordFound) => Ok(()),
        Err(e) => Err(e),
        _ => Ok(()),
    }
}

On Linux this just reaches the Ok(()) of the NoPasswordFound arm, on Windows it produces a WindowsVaultError, on macOS it returns a general KeyringError with the message Mac Os Keychain Error: The specified item could not be found in the keychain..

I would love for the function to return a predictable result, ideally 🙂

(And have a test case for it!)

Numeric pins break everything

On OSX, I have a numeric pin stored that I want to retrieve.

I'm assuming that the code here: https://github.com/hwchen/keyring-rs/blob/master/src/macos.rs#L98-L104 is meant to deal with binary objects (although I can't find any code for trying to serialize as hex), in the case of my ascii numeric pin it's trying to decode it as hex and then turn that into UTF 8 which fails, and as a result I can't fetch my entry.

Maybe this should be a different method? I can open a PR for that if you'd prefer.

KeyringError::NoPasswordFound is not used on MacOS

On MacOS, if I try to get a nonexistent password, instead of getting an instance of KeyringError::NoPasswordFound I get Mac Os Keychain Error: The specified item could not be found in the keychain..

The macos.rs file shows no uses of NoPasswordFound.

Can't tell if a secret exists on Windows

It looks to me like there's no way to get a NoPasswordFound from the Windows implementation which makes it hard to figure out if the library is failing or there's just no password set.

Long term maybe the API should be changed to return an Option<T> instead of returning an Err when there's no value?

Version 2: plug-in credential providers, and mocking

OK, it's time for a v2 that addresses the issues raised in #94 and #95 (and provides the ability for clients to address the issues in #76 and #84). Here are the enhancements needed:

  1. The ability for 3rd parties to provide new credential storage mechanisms, and for clients to choose those as their default mechanism.
  2. Support for a "mock" credential store that allows controlling both return and error values. Preferably the mock store should also be an example of how you plug in a new storage mechanism.

These enhancements should not complicate the existing (very simple) Entry model, so that existing clients don't have to revise their code.

While we're at it, we should clean up the API so that creating entries can fail. This will be a breaking change, but one that existing clients can adapt to simply by adding expect calls to their existing entry creations.

Async interface

Hello!

Down in secret-service there are discussions to either replace the current sync interface or provide one alongside it (hwchen/secret-service-rs#42). Since this will impact this crate I thought it would be a good idea to also start the discussion here.

Thanks

Add ability to access named keychains in macOS.

Current macOS implementation uses the default keychain by default and does not support opening specific keychain. This limits our ability to open system keychain since default keychain is almost always login keychain on macOS. What is the best possible to add this support to current implementation? I made this PR but open to any better implementation if there is one.

Ideally looking for functionality similar to https://developer.apple.com/documentation/security/1396431-seckeychainopen and https://github.com/kornelski/rust-security-framework/blob/master/security-framework/src/os/macos/keychain.rs#L36

Panic on ubuntu-server / wsl

If i try use this on ubuntu-server or windows subsystem for linux (wsl) / bash on windows I get the following error

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: SecretServiceError(Dbus(D-Bus error: Unable to autolaunch a dbus-daemon without a $DISPLAY for X11 (org.freedesktop.DBus.Error.NotSupported)))', /checkout/src/libcore/result.rs:916:4

is X11 really needed to access the keyring?

MacOsKeychainError is not documented as far as I can tell

When the user denies keychain access on macOS, keyring returns a MacOsKeychainError error, which would be fine except that it's not really clear how this works since it's not documented anywhere here: https://docs.rs/keyring/0.6.1/keyring/struct.Keyring.html. I tried searching the docs for the string "MacOsKeychainError" but there weren't any results: https://docs.rs/keyring/0.6.1/keyring/struct.Keyring.html?search=MacOsKeychainError.

Also, how can one tell the difference between the user denying access vs other types of keychain errors in this case?

Version 0.4.0 Yanked

I see that version 0.4.0 has recently been yanked from crates.io, but I don't see anything stating why. Was there a security vulnerability? 0.3.0 hasn't been yanked; is it still safe to use?

How do you write unit tests involving keyring-rs?

I was pondering on this question since before the 1.1.x releases and the refactored Platform and PlatformCredential data model.

Is it possible right now to write unit tests using the established mappers? Platform has not trait implementation, PlatformCredential also doesn't. On top of that, the implementation is "dynamically" chosen, depending on the operating system, which would mean I'd have to write three tests for every single function I'd want to see passing.

Is there any way to write tests involving keyring-rs right now (and if so, how?)? Or would this need some refactoring to allow for a more dynamic association of resources (e.g. provide your own Platform implementation, or PlatformCredential implementation.

Force user verification prior to accessing the keystore

Hello,

Thanks for your work on this package, it's great!

It might be a naive question, but is it possible to force a user verification when getting / setting a password?

For instance a use case would be that the user is asked for its fingerprint (or keystore main password) prior to accessing the password.

I understand it is not implemented here, just wondering if the most common keystore support this.

v1.0 checklist - for real this time

I think enough people have used this library to go ahead and plan to release 1.0 soon.

The main points I need to address:

  • release v1.0 of secret-service dependency (part of the is removing some dependencies)

For the future:

  • move cli binary to its own library, which would remove the binary's dependencies. I'm going to hold off on this, and maybe release 2.0, because I'm thinking of working on rust-lang/cargo#1982. If anybody has feedback, please leave it here: #20

Iterate usernames?

Not sure if this is possible on all platforms, but I'm hoping there's a way to iterate usernames within the service. As an example, I'm creating a CLI where I'd like to support logging into to multiple accounts, but I'd currently need to record the usernames externally to support an autocomplete friendly list of accounts.

Something like this might work:

for username in keychain::Keychain::usernames("service_name") {
  println!("{:?}", username);
}

macOS requests password twice for each `get_password`

Hi there and apologies for the possibly-confusing issue title!

This is my first programatic use of Keychain Access on macOS so what I'm running into may be normal/expected.

I am doing the following:

let access_key = keyring::Keyring::new("foo", "access_key").get_password().expect("Unable to get foo:access_key from system keychain");

And the system prompts me twice for an administrator password.

How can I get these creds from the keychain without prompting the user for a password?

What I'm building is an internal tool but ideally we'd not run it as root.

Any input would be greatly appreciated!

*BSD support

What is required to support keyring on a given unix system? FreeBSD presumably has something like gnome keyring in ports that could be used for this, or is it possible to point to a system like hashicorp vault as a generic secrets store?

Basic Travis CI testing?

Would it be helpful to add Travis CI to run RUST_TEST_THREADS=1 cargo test on all PRs on all platforms? I feel like it would be.

How does it work on raspbian ?

The tone of my question may appear rude, and if so, please forgive my poor english level.

So, I maintain a project where a GitHub angel has contributed this PR Riduidel/rrss2imap#46 using your excellent crate to securely store passwords. This is SERIOUSLY cool.
Unfortunatly, there is one thing that prevent me from merging it now: I deploy that executbale on my raspberry running raspbian. And I don't understand how to have your wonderful crate running on Raspbian. Have you got any tutorial for Raspbian users ?

Thanks a lot

1.0 plans

Next plans for this lib:

  • figure out cross-compilation details (making sure unneeded dependencies are not compiled?) (v0.3.0)
  • windows backend (v0.3.0)
  • design: should osx keychain be unlocked from cli (only required from ssh)?
  • traits-based design?
  • tests and CI.
  • docs
  • osx backend with https://crates.io/crates/security-framework (which I think should work)

Edit (9/27/2018):

I think this library has been used enough that I'm going to go ahead and plan for 1.0 without major changes to this library. I only need to clean up the secret-service library a bit, move that to 1.0, and then I'll be able to release 1.0 here.

See new issue: #21

[feature request] gracefully handle Secret Service absence

There are a number of scenarios in which there's either no Secret Service running on the machine or it's not available, eg. running in a Docker image. When trying to run an executable that depends on keyring-rs, the shell will respond with simply "No such file or directory". Debugging a bit shows us that the binary can't be run without gmp and dbus-1 available on the host system:

$ ldd nuvemfs-cli
	linux-vdso.so.1 (0x00007ffd69df9000)
	libgmp.so.10 => /usr/lib/x86_64-linux-gnu/libgmp.so.10 (0x00007f734d206000)
	libdbus-1.so.3 => not found
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f734ce15000)
	/lib/ld64.so.1 => /lib64/ld-linux-x86-64.so.2 (0x00007f734d487000)

It would be nice to be able to actually run the executable but return an error at runtime when the program attempts to access the keyring.

Oversight in examples, default and/or insert.

It's not clear, or rather ugly, how to perform on-boarding... That is the first time the application is run using a default value appears clunky. I guess there are three use cases:

  1. Ask the user for secret, the most difficult option. Perhaps this is the only supported method currently.
  2. Substitute a default value, use or_else and if matches!(... seems clunky.
  3. Insert a default value, same trick as with 2 but now you call into the handle.

Catching the NoEntry Error is natural enough to have specific helpers for that case. Variants of get_password that take a function argument. There is also the view that this is not an error, a get_password that returns a Result<Option<String>... would be another solution.

Weird bug with hex conversions on macOS

I have a weird bug where certain strings cause keyring-rs to throw an error on macOS. I haven’t worked out exactly what’s causing it, but it looks like my keychain entries are being interpreted as hex, and that’s throwing it off.

If I create a keychain entry ("testing", "password", "aa"), put the following in main.rs and then call cargo run:

// main.rs
extern crate keyring;

fn main() {
    println!("{:?}", keyring::Keyring::new("testing", "username").get_password());
}

I get the following error:

thread 'main' panicked at 'error converting hex to utf8: FromUtf8Error { bytes: [170], error: Utf8Error { valid_up_to: 0 } }', ../src/libcore/result.rs:788
note: Run with `RUST_BACKTRACE=1` for a backtrace.
error: Process didn't exit successfully: `target/debug/testing` (exit code: 101)

Other strings that produce the error: bb, c1, 99, 90, 80.

I get the correct result with 7f.

If I try hex strings below 7f (e.g. 6a, 00, 0a), the program exits correctly but the item it retrieves from the keychain is incorrect. e.g. if the keychain entry is 6a, it prints Ok("j").

Versions:

$ rustc --version
rustc 1.12.1 (d4f39402a 2016-10-19)

$ cat Cargo.toml
[package]
name = "testing"
version = "0.1.0"
authors = ["Alex Chan <[email protected]>"]

[dependencies]
keyring = "0.1.1"

$ sw_vers
ProductName:	Mac OS X
ProductVersion:	10.12.2
BuildVersion:	16C67

keyring failing weirdly on a remote vm

I've built a package that utilizes 0.1.x and it works fine on WSL linux.
I upgraded to 1.1.2, and it returns

[2022-02-22T10:46:09Z ERROR terra_rust] Platform secure storage failure: zbus error: I/O error: No such file or directory (os error 2)
[2022-02-22T10:46:09Z ERROR terra_rust] because: zbus error: I/O error: No such file or directory (os error 2)
[2022-02-22T10:46:09Z ERROR terra_rust] because: I/O error: No such file or directory (os error 2)
[2022-02-22T10:46:09Z ERROR terra_rust] because: No such file or directory (os error 2)

also.. when using either on a remote linux vm, both fail.
I'm assuming it is a configuration issue on my end. but I have no idea where to start looking.

TIA

MacOS: error reading hex output: OddLength

Hi,

I am using keyring-rs in my tool but some of my mac users have problems with retrieving passwords:

Call to keyring:
Keyring::new("saml2aws-auto", username).get_password()

How it's saved:
Keyring::new("saml2aws-auto", username).set_password(password)

Error:

stack backtrace:
0: std::sys::unix::backtrace::tracing:👿:unwind_backtrace
1: std::panicking::default_hook::{{closure}}
2: std::panicking::rust_panic_with_hook
3: std::panicking::begin_panic_fmt
4: core::panicking::panic_fmt
5: core::result::unwrap_failed
6: keyring::macos::Keyring::get_password
7: saml2aws_auto::config::interactive_create
8: saml2aws_auto::main
9: std::rt::lang_start::{{closure}}
10: main```

Error code 1783 on Windows

When trying to add a keyring entry on Windows, I get Error code 1783 which seems to correlate to RPC_X_BAD_STUB_DATA in winapi.

Incompatible with 3rd party (native) credential writers who use their own Target and User Name conventions

At lines 97 and 98 of windows.rs (release 0.10.1), the TargetName is set to be .-join of user name and service name. But this is an arbitrary convention of this rust project; there is no such requirement on TargetName when used by 3rd-party credential writers. This makes it impossible to read 3rd-party credentials written by apps that don't use a '.' somewhere in their target name.

On the other hand, I notice that the username field on the Rust side is, in fact, placed in the UserName field of the credential that is written. So it's not clear to me why the .-join convention is used at all for the target name on the Windows side, especially since I notice that the service argument is used for the target name without modification in the Mac implementation.

Handling of empty string passwords (and other empty input)

secret service (linux vault) does not create an item for an empty secret.

Not sure if osx is the same (will check later today), but am thinking whether it makes sense to check for empty input.

If this were a single-system library, I'd probably let the system vault since the library should just be a pass-through interface (and in case the system behavior changes).

But it might be good to make sure that behavior is standard for handling empty passwords across all systems?

I'm going to let the system vault handle this validation until convinced otherwise (which may not take much, haven't thought too hard about this).

Compile error on Windows due to unresolved winapi

Environment

  • Windows 10 21H2 (OS Build 19044.1466)
  • target stable-x86_64-pc-windows-msvc
  • rustc 1.58.1 (db9d1b20b 2022-01-20)
  • cargo 1.58.0 (f01b232bc 2022-01-19)

Procedure for reproducing

Create new cargo package.

cargo new --edition 2018 hoge

Edit Cargo.toml.

[package]
name = "hoge"
version = "0.1.0"
edition = "2018"

[dependencies]
keyring = "1"

Edit src/main.rs.

extern crate keyring;

fn main() {
    println!("Hello, world!");
}

Build package and it produce following message.

cargo build
   Compiling winapi v0.3.9
   Compiling byteorder v1.4.3
   Compiling keyring v1.0.0
error[E0432]: unresolved import `winapi::um::errhandlingapi`
  --> C:\Users\***\.cargo\registry\src\github.com-1ecc6299db9ec823\keyring-1.0.0\src\windows.rs:11:17
   |
11 | use winapi::um::errhandlingapi::GetLastError;
   |                 ^^^^^^^^^^^^^^ could not find `errhandlingapi` in `um`

For more information about this error, try `rustc --explain E0432`.
error: could not compile `keyring` due to previous error

Supporting pass as a fallback on linux

Many headless linux don't have a great way to work with secret-service. This is detailed in the documentation already, though I had to also launch the dbus daemon with export $(dbus-launch) which I found here.
I think a good fallback would be to use pass as this is what docker does too to store credentials (searching for cannot autolaunch d-bus without x11 $display yields a bunch of response going in that direction).

GitHub search results for this repository

This package looks really useful, but it's surprisingly hard to find relative to how many stars it has. Here are some example searches that don't turn up this package:

keyring rust
keyring linux and filtering Rust repositories
keyring macos and doing an advanced search for Rust
keyring windows
windows credentials rust, which does turn up my own package that I wrote under the impression that no others existed
windows credential manager and doing an advanced search for Rust
crossplatform keyring

I only found this package by searching code for keyring macos rust.

In fairness, just searching keyring and doing an advanced search for Rust specifically does turn up this package at the top, but it's odd that none of the other searches show this anywhere in the results.

I think this problem would be solved by just adding some tags to the repository using some of the keywords I tried.

Seeking maintainers

Hi all,

I'm already unable to spend much, if any, energy on keyring-rs and secret-service-rs. In the near future, I'll have more family obligations and so will have even less energy.

So, I'm looking for some help. At the moment, I'm especially looking for people to help review/merge PRs. In the future, I may hand off publishing duties also, but I'm going to reserve that to myself for now.

I'd especially like maintainers from places that use keyring in production, as they'll have the most skin in the game. If you're interested in helping out, please mention your use-case in this issue.

v2: should get_password/get_credential use collection-level search?

I'm using spotifyd while storing my credentials in my KeePassXC database, which has a SecretService implementation. KeePassXC has been updated recently and now supports prompting the user to confirm access of an application to a stored secret. This prompting doesn't seem to supported by keyring-rs, as the call of keyring-rs to GetSecret now fails with an error:

method call time=1648045650.307442 sender=:1.248 -> destination=org.freedesktop.secrets serial=5 path=/org/freedesktop/secrets/collection/KeyDB; interface=org.freedesktop.Secret.Collection; member=SearchItems
   array [
      dict entry(
         string "service"
         string "spotifyd"
      )
      dict entry(
         string "username"
         string "***"
      )
   ]
method return time=1648045650.307636 sender=:1.65 -> destination=:1.248 serial=1674 reply_serial=5
   array [
      object path "/org/freedesktop/secrets/collection/KeyDB/2bf27c5b9dc54eb78fcc8c97485425b6"
   ]
method call time=1648045650.307687 sender=:1.248 -> destination=org.freedesktop.secrets serial=6 path=/org/freedesktop/secrets/collection/KeyDB/2bf27c5b9dc54eb78fcc8c97485425b6; interface=org.freedesktop.Secret.Item; member=GetSecret
   object path "/org/freedesktop/secrets/session/7668f5ed92944dba9d4c9626a6e0f8ec"
error time=1648045650.307750 sender=:1.65 -> destination=:1.248 error_name=org.freedesktop.Secret.Error.IsLocked reply_serial=6

Here's an excerpt of a similar (but successful) message exchange by the Minecraft Launcher, which supports unlocking and prompting:

method call time=1648044309.545926 sender=:1.226 -> destination=:1.65 serial=9 path=/org/freedesktop/secrets; interface=org.freedesktop.Secret
.Service; member=SearchItems
   array [
      dict entry(
         string "tokenkey"
         string "mojangClientToken"
      )
      dict entry(
         string "xdg:schema"
         string "com.mojang.tokenstore"
      )
   ]
method return time=1648044309.546214 sender=:1.65 -> destination=:1.226 serial=1414 reply_serial=9
   array [
   ]
   array [
      object path "/org/freedesktop/secrets/collection/KeyDB/c6d5c87eec6b467788481f4cd2ae8b2b"
   ]
method call time=1648044309.546400 sender=:1.226 -> destination=:1.65 serial=10 path=/org/freedesktop/secrets; interface=org.freedesktop.Secret.Service; member=Unlock
   array [
      object path "/org/freedesktop/secrets/collection/KeyDB/c6d5c87eec6b467788481f4cd2ae8b2b"
   ]
method return time=1648044309.546534 sender=:1.65 -> destination=:1.226 serial=1415 reply_serial=10
   array [
   ]
   object path "/org/freedesktop/secrets/prompt/d9076c8584c34394aa60a72ab99ba1c2"
method call time=1648044309.547451 sender=:1.226 -> destination=:1.65 serial=17 path=/org/freedesktop/secrets/prompt/d9076c8584c34394aa60a72ab99ba1c2; interface=org.freedesktop.Secret.Prompt; member=Prompt
   string ""
method return time=1648044309.547541 sender=:1.65 -> destination=:1.226 serial=1416 reply_serial=17
signal time=1648044310.578814 sender=:1.65 -> destination=(null destination) serial=1417 path=/org/freedesktop/secrets/prompt/d9076c8584c34394aa60a72ab99ba1c2; interface=org.freedesktop.Secret.Prompt; member=Completed
   boolean false
   variant       array [
         object path "/org/freedesktop/secrets/collection/KeyDB/c6d5c87eec6b467788481f4cd2ae8b2b"
      ]
method call time=1648044310.579309 sender=:1.226 -> destination=:1.65 serial=20 path=/org/freedesktop/secrets; interface=org.freedesktop.Secret.Service; member=GetSecrets
   array [
      object path "/org/freedesktop/secrets/collection/KeyDB/c6d5c87eec6b467788481f4cd2ae8b2b"
   ]
   object path "/org/freedesktop/secrets/session/c3a1ac6acba843b492fa157419b38f71"

It can be observed, that the Minecraft Launcher first calls Unlock on the objects returned in SearchItems. Then Prompt is called on the object returned by Unlock. Only after this GetSecrets is called.
keyring-rs on the other hand calls GetSecret immediately without calling Unlock and Prompt first, which is the reason for the failure.

I assume a call to unlock() and prompt() is missing here, before get_secret():

let bytes = item.get_secret().map_err(decode_error)?;

Also it seems like prompt() isn't implemented for Item in secret-service-rs yet.

Relevant SecretService spec: https://specifications.freedesktop.org/secret-service/latest/ch08.html

"MacOsKeychainError" when unprivileged

Hey,

I've had another user report problems with my tool, and this time it seems to be related to the user not unlocking their Keychain (or not having adminsitrative rights to do so). I'm not entirely sure how to reproduce this but it would be nice if I could get another error type for this, telling me that their Keychain just isn't accessible so that I can print a nice error message.

Surprising feature on MacOS: empty service/account strings are wildcards

The underlying Security Framework functions take optional arguments for the service and account strings, but this bubbles up to keyring as plain &strs. Passing an empty string is then treated as a non-provided optional argument rather than an explicit empty value. So, for example:

    #[test]
    fn secret_wildcard() {
        let name = "test";
        let entry = keyring::Entry::new("my_service", name);
        entry.set_password("abc").unwrap();

        let entry = keyring::Entry::new("my_service", name);
        let pass = entry.get_password().unwrap();
        assert_eq!("abc", pass);

        // Can also access via empty string(s)!
        let entry = keyring::Entry::new("my_service", "");
        let pass = entry.get_password().unwrap();
        assert_eq!("abc", pass);

        // And can use the empty-string entry to overwrite the original!
        entry.set_password("def").unwrap();

        let entry = keyring::Entry::new("my_service", name);
        let pass = entry.get_password().unwrap();
        assert_eq!("def", pass);

        entry.delete_password().unwrap();
    }

I've only tested this on MacOS but I suspect the behavior is the same on iOS.

This makes some sense as a reflection of the underlying API, but just reading the docs for keyring, I think it's a very surprising behavior. I think this should either a) get clear documentation somewhere, b) be forbidden (just fail on empty values somewhere) or c) be reflected in the API by making the service/account params Options.

Fix macos feature test, tests

I just published a version of keyring with a macos feature that allows specifying the keychain. The test is a bit mucked up, I'm planning on creating a new keychain file in a temp directory but it's not quite working.

In the meantime, I just switched to github actions. I don't think I lost the ability to test linux (readme notes that it was just building and not testing, since I couldn't get the dbus under x11 mock working).

Move cli to separate package to remove bin dependencies?

Just wanted to see what the demand is for removing the bin dependencies. This hasn't come up yet, so I don't see it as a big issue. However, I do want to do some cleanup here, so curious if I should do this sooner than later.

If sooner, I'll have to break the cli out into a separate crate. I'd prefer not to do this, just because it's extra maintenance overhead.

If later, I can work on rust-lang/cargo#1982, which would allow binary-specific dependencies in cargo.

Feedback welcome.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.