@@ -28,19 +28,26 @@ This provides better compatibility with 3rd party clients that may already
28
28
have created items that match the entry, and reduces the chance
29
29
of ambiguity in later searches.
30
30
31
- ## Async runtime required
32
-
33
- While this crate uses the secret-service via its blocking API,
34
- the secret-service crate is built on zbus which always talks to the dbus via async calls.
35
- Thus, using the secret-service implies using an async runtime under the covers.
36
- If you are already using an async runtime,
37
- you can use keyring features to make sure that secret-service
38
- uses a compatible runtime. But be careful: if you make keyring calls
39
- on the main thread in this situation, you will likely crash because
40
- you will block the main thread (see\
31
+ ## keyring v1 incompatibility
32
+
33
+ In order to fix
34
+ [this bug](https://github.com/hwchen/keyring-rs/issues/204)
35
+ efficiently, this implementation can no longer access
36
+ credentials that have no `target` attribute. Since keyring v1
37
+ didn't set this attribute, any old credentials left from v1
38
+ will have to be upgraded to a v3-compatible format
39
+ using platform-specific code. You can use the new secret-service-specific
40
+ entry creation call [new_with_no_target] to
41
+ create an [Entry] that will retrieve a v1 password and/or delete it.
42
+
43
+ ## Tokio runtime caution
44
+
45
+ If you are using the `async-secret-service` with this crate,
46
+ and specifying `tokio` as your runtime, be careful:
47
+ if you make keyring calls on the main thread, you will likely deadlock (see\
41
48
[this issue on GitHub](https://github.com/hwchen/keyring-rs/issues/132)
42
- for details). You will need to spawn a separate thread on which
43
- you make your keyring calls so the main thread doesn't block .
49
+ for details). You need to spawn a separate thread on which
50
+ you make your keyring calls to avoid this .
44
51
45
52
## Headless usage
46
53
@@ -233,6 +240,26 @@ impl SsCredential {
233
240
} )
234
241
}
235
242
243
+ /// Create a credential that has *no* target and the given service and user.
244
+ ///
245
+ /// This emulates what keyring v1 did, and can be very handy when you need to
246
+ /// access an old v1 credential that's in your secret service default collection.
247
+ pub fn new_with_no_target ( service : & str , user : & str ) -> Result < Self > {
248
+ let attributes = HashMap :: from ( [
249
+ ( "service" . to_string ( ) , service. to_string ( ) ) ,
250
+ ( "username" . to_string ( ) , user. to_string ( ) ) ,
251
+ ( "application" . to_string ( ) , "rust-keyring" . to_string ( ) ) ,
252
+ ] ) ;
253
+ Ok ( Self {
254
+ attributes,
255
+ label : format ! (
256
+ "keyring-rs v{} for no target, service '{service}', user '{user}'" ,
257
+ env!( "CARGO_PKG_VERSION" ) ,
258
+ ) ,
259
+ target : None ,
260
+ } )
261
+ }
262
+
236
263
/// Create a credential from an underlying item.
237
264
///
238
265
/// The created credential will have all the attributes and label
@@ -293,27 +320,24 @@ impl SsCredential {
293
320
let ss = SecretService :: connect ( session_type) . map_err ( platform_failure) ?;
294
321
let attributes: HashMap < & str , & str > = self . search_attributes ( ) . into_iter ( ) . collect ( ) ;
295
322
let search = ss. search_items ( attributes) . map_err ( decode_error) ?;
296
- let target = self . target . as_ref ( ) . ok_or_else ( empty_target) ?;
297
- let unlocked = matching_target_items ( & search. unlocked , target) ?;
298
- let locked = matching_target_items ( & search. locked , target) ?;
299
323
if require_unique {
300
- let count = locked. len ( ) + unlocked. len ( ) ;
324
+ let count = search . locked . len ( ) + search . unlocked . len ( ) ;
301
325
if count == 0 {
302
326
return Err ( ErrorCode :: NoEntry ) ;
303
327
} else if count > 1 {
304
328
let mut creds: Vec < Box < Credential > > = vec ! [ ] ;
305
- for item in locked. into_iter ( ) . chain ( unlocked. into_iter ( ) ) {
329
+ for item in search . locked . iter ( ) . chain ( search . unlocked . iter ( ) ) {
306
330
let cred = Self :: new_from_item ( item) ?;
307
331
creds. push ( Box :: new ( cred) )
308
332
}
309
333
return Err ( ErrorCode :: Ambiguous ( creds) ) ;
310
334
}
311
335
}
312
336
let mut results: Vec < T > = vec ! [ ] ;
313
- for item in unlocked. into_iter ( ) {
337
+ for item in search . unlocked . iter ( ) {
314
338
results. push ( f ( item) ?) ;
315
339
}
316
- for item in locked. into_iter ( ) {
340
+ for item in search . locked . iter ( ) {
317
341
item. unlock ( ) . map_err ( decode_error) ?;
318
342
results. push ( f ( item) ?) ;
319
343
}
@@ -335,6 +359,9 @@ impl SsCredential {
335
359
/// but this just selects the ones we search on
336
360
fn search_attributes ( & self ) -> HashMap < & str , & str > {
337
361
let mut result: HashMap < & str , & str > = HashMap :: new ( ) ;
362
+ if self . target . is_some ( ) {
363
+ result. insert ( "target" , self . attributes [ "target" ] . as_str ( ) ) ;
364
+ }
338
365
result. insert ( "service" , self . attributes [ "service" ] . as_str ( ) ) ;
339
366
result. insert ( "username" , self . attributes [ "username" ] . as_str ( ) ) ;
340
367
result
@@ -429,25 +456,6 @@ pub fn delete_item(item: &Item) -> Result<()> {
429
456
item. delete ( ) . map_err ( decode_error)
430
457
}
431
458
432
- /// Given a slice of items, filter out the ones that have an explicit target
433
- /// attribute that doesn't match the given target.
434
- ///
435
- /// References to the matching items are returned in a new vector.
436
- pub fn matching_target_items < ' a > (
437
- source : & ' a [ Item < ' a > ] ,
438
- target : & str ,
439
- ) -> Result < Vec < & ' a Item < ' a > > > {
440
- let mut result: Vec < & ' a Item < ' a > > = vec ! [ ] ;
441
- for i in source. iter ( ) {
442
- match i. get_attributes ( ) . map_err ( decode_error) ?. get ( "target" ) {
443
- None => result. push ( i) ,
444
- Some ( item_target) if target. eq ( item_target) => result. push ( i) ,
445
- _ => { }
446
- }
447
- }
448
- Ok ( result)
449
- }
450
-
451
459
//
452
460
// Error utilities
453
461
//
0 commit comments