11use std:: cell:: RefCell ;
22use std:: collections:: HashMap ;
33use std:: rc:: Rc ;
4+ use std:: sync:: { Arc , RwLock } ;
5+
6+ use async_trait:: async_trait;
7+
8+ #[ derive( Clone ) ]
9+ pub struct KeyringItem {
10+ attributes : HashMap < String , String > ,
11+ // we could zero-out this region of memory
12+ secret : Vec < u8 > ,
13+ }
14+
15+ impl KeyringItem {
16+ async fn attributes ( & self ) -> HashMap < String , String > {
17+ self . attributes . clone ( )
18+ }
19+ async fn secret ( & self ) -> & [ u8 ] {
20+ & self . secret [ ..]
21+ }
22+ }
23+
24+ #[ async_trait]
25+ trait LightKeyring {
26+ async fn search_items (
27+ & self ,
28+ attributes : HashMap < & str , & str > ,
29+ ) -> anyhow:: Result < Vec < KeyringItem > > ;
30+ async fn create_item (
31+ & self ,
32+ label : & str ,
33+ attributes : HashMap < & str , & str > ,
34+ secret : & str ,
35+ replace : bool ,
36+ ) -> anyhow:: Result < ( ) > ;
37+ async fn delete ( & self , attributes : HashMap < & str , & str > ) -> anyhow:: Result < ( ) > ;
38+ }
39+
40+ struct RealKeyring {
41+ keyring : oo7:: Keyring ,
42+ }
43+
44+ #[ async_trait]
45+ impl LightKeyring for RealKeyring {
46+ async fn search_items (
47+ & self ,
48+ attributes : HashMap < & str , & str > ,
49+ ) -> anyhow:: Result < Vec < KeyringItem > > {
50+ let items = self . keyring . search_items ( attributes) . await ?;
51+
52+ let mut out_items = vec ! [ ] ;
53+ for item in items {
54+ out_items. push ( KeyringItem {
55+ attributes : item. attributes ( ) . await ?,
56+ secret : item. secret ( ) . await ?. to_vec ( ) ,
57+ } ) ;
58+ }
59+ Ok ( out_items)
60+ }
61+
62+ async fn create_item (
63+ & self ,
64+ label : & str ,
65+ attributes : HashMap < & str , & str > ,
66+ secret : & str ,
67+ replace : bool ,
68+ ) -> anyhow:: Result < ( ) > {
69+ self . keyring
70+ . create_item ( label, attributes, secret, replace)
71+ . await ?;
72+ Ok ( ( ) )
73+ }
74+
75+ async fn delete ( & self , attributes : HashMap < & str , & str > ) -> anyhow:: Result < ( ) > {
76+ self . keyring . delete ( attributes) . await ?;
77+ Ok ( ( ) )
78+ }
79+ }
80+
81+ struct NullableKeyring {
82+ search_response : Vec < KeyringItem > ,
83+ }
84+
85+ impl NullableKeyring {
86+ pub fn new ( search_response : Vec < KeyringItem > ) -> Self {
87+ Self { search_response }
88+ }
89+ }
90+
91+ #[ async_trait]
92+ impl LightKeyring for NullableKeyring {
93+ async fn search_items (
94+ & self ,
95+ _attributes : HashMap < & str , & str > ,
96+ ) -> anyhow:: Result < Vec < KeyringItem > > {
97+ Ok ( self . search_response . clone ( ) )
98+ }
99+
100+ async fn create_item (
101+ & self ,
102+ _label : & str ,
103+ _attributes : HashMap < & str , & str > ,
104+ _secret : & str ,
105+ _replace : bool ,
106+ ) -> anyhow:: Result < ( ) > {
107+ Ok ( ( ) )
108+ }
109+
110+ async fn delete ( & self , _attributes : HashMap < & str , & str > ) -> anyhow:: Result < ( ) > {
111+ Ok ( ( ) )
112+ }
113+ }
114+ impl NullableKeyring {
115+ pub fn with_credentials ( credentials : Vec < Credential > ) -> Self {
116+ let mut search_response = vec ! [ ] ;
117+
118+ for cred in credentials {
119+ let attributes = HashMap :: from ( [
120+ ( "type" . to_string ( ) , "password" . to_string ( ) ) ,
121+ ( "username" . to_string ( ) , cred. username . clone ( ) ) ,
122+ ( "server" . to_string ( ) , cred. password . clone ( ) ) ,
123+ ] ) ;
124+ search_response. push ( KeyringItem {
125+ attributes,
126+ secret : cred. password . into_bytes ( ) ,
127+ } ) ;
128+ }
129+
130+ Self { search_response }
131+ }
132+ }
4133
5134#[ derive( Debug , Clone ) ]
6135pub struct Credential {
7136 pub username : String ,
8137 pub password : String ,
9138}
10139
11- #[ derive( Debug , Clone ) ]
140+ #[ derive( Clone ) ]
12141pub struct Credentials {
13- keyring : Rc < oo7 :: Keyring > ,
14- creds : Rc < RefCell < HashMap < String , Credential > > > ,
142+ keyring : Arc < dyn LightKeyring + Send + Sync > ,
143+ creds : Arc < RwLock < HashMap < String , Credential > > > ,
15144}
16145
17146impl Credentials {
18147 pub async fn new ( ) -> anyhow:: Result < Self > {
19148 let mut this = Self {
20- keyring : Rc :: new (
21- oo7:: Keyring :: new ( )
149+ keyring : Arc :: new ( RealKeyring {
150+ keyring : oo7:: Keyring :: new ( )
22151 . await
23152 . expect ( "Failed to start Secret Service" ) ,
24- ) ,
153+ } ) ,
154+ creds : Default :: default ( ) ,
155+ } ;
156+ this. load ( ) . await ?;
157+ Ok ( this)
158+ }
159+ pub async fn new_nullable ( credentials : Vec < Credential > ) -> anyhow:: Result < Self > {
160+ let mut this = Self {
161+ keyring : Arc :: new ( NullableKeyring :: with_credentials ( credentials) ) ,
25162 creds : Default :: default ( ) ,
26163 } ;
27164 this. load ( ) . await ?;
28165 Ok ( this)
29166 }
30167 pub async fn load ( & mut self ) -> anyhow:: Result < ( ) > {
31168 let attrs = HashMap :: from ( [ ( "type" , "password" ) ] ) ;
32- let values = self
33- . keyring
34- . search_items ( attrs)
35- . await
36- . map_err ( |e| capnp:: Error :: failed ( e. to_string ( ) ) ) ?;
169+ let values = self . keyring . search_items ( attrs) . await ?;
37170
38- self . creds . borrow_mut ( ) . clear ( ) ;
171+ let mut lock = self . creds . write ( ) . unwrap ( ) ;
172+ lock. clear ( ) ;
39173 for item in values {
40- let attrs = item
41- . attributes ( )
42- . await
43- . map_err ( |e| capnp:: Error :: failed ( e. to_string ( ) ) ) ?;
44- self . creds . borrow_mut ( ) . insert (
174+ let attrs = item. attributes ( ) . await ;
175+ lock. insert (
45176 attrs[ "server" ] . to_string ( ) ,
46177 Credential {
47178 username : attrs[ "username" ] . to_string ( ) ,
48- password : std:: str:: from_utf8 ( & item. secret ( ) . await ? ) ?. to_string ( ) ,
179+ password : std:: str:: from_utf8 ( & item. secret ( ) . await ) ?. to_string ( ) ,
49180 } ,
50181 ) ;
51182 }
52183 Ok ( ( ) )
53184 }
54185 pub fn get ( & self , server : & str ) -> Option < Credential > {
55- self . creds . borrow ( ) . get ( server) . cloned ( )
186+ self . creds . read ( ) . unwrap ( ) . get ( server) . cloned ( )
56187 }
57188 pub fn list_all ( & self ) -> HashMap < String , Credential > {
58- self . creds . borrow ( ) . clone ( )
189+ self . creds . read ( ) . unwrap ( ) . clone ( )
59190 }
60191 pub async fn insert ( & self , server : & str , username : & str , password : & str ) -> anyhow:: Result < ( ) > {
61192 {
62- if let Some ( cred) = self . creds . borrow ( ) . get ( server) {
193+ if let Some ( cred) = self . creds . read ( ) . unwrap ( ) . get ( server) {
63194 if cred. username != username {
64195 anyhow:: bail!( "You can add only one account per server" ) ;
65196 }
@@ -72,10 +203,9 @@ impl Credentials {
72203 ] ) ;
73204 self . keyring
74205 . create_item ( "Password" , attrs, password, true )
75- . await
76- . map_err ( |e| capnp:: Error :: failed ( e. to_string ( ) ) ) ?;
206+ . await ?;
77207
78- self . creds . borrow_mut ( ) . insert (
208+ self . creds . write ( ) . unwrap ( ) . insert (
79209 server. to_string ( ) ,
80210 Credential {
81211 username : username. to_string ( ) ,
@@ -87,7 +217,8 @@ impl Credentials {
87217 pub async fn delete ( & self , server : & str ) -> anyhow:: Result < ( ) > {
88218 let creds = {
89219 self . creds
90- . borrow ( )
220+ . read ( )
221+ . unwrap ( )
91222 . get ( server)
92223 . ok_or ( anyhow:: anyhow!( "server creds not found" ) ) ?
93224 . clone ( )
@@ -97,12 +228,10 @@ impl Credentials {
97228 ( "username" , & creds. username ) ,
98229 ( "server" , server) ,
99230 ] ) ;
100- self . keyring
101- . delete ( attrs)
102- . await
103- . map_err ( |e| capnp:: Error :: failed ( e. to_string ( ) ) ) ?;
231+ self . keyring . delete ( attrs) . await ?;
104232 self . creds
105- . borrow_mut ( )
233+ . write ( )
234+ . unwrap ( )
106235 . remove ( server)
107236 . ok_or ( anyhow:: anyhow!( "server creds not found" ) ) ?;
108237 Ok ( ( ) )
0 commit comments