@@ -7,32 +7,39 @@ mod vault;
77
88#[ tauri:: command]
99fn resolve_twofactor ( password : & str , uid : & str ) -> Value {
10- let mut container = driver:: read ( password) ;
11-
12- let credentials = container. as_array_mut ( ) . unwrap ( ) ;
13-
14- let credential = credentials. iter_mut ( ) . find ( |credential| {
15- let credential = credential. as_object ( ) . unwrap ( ) ;
16- let id = credential. get ( "uid" ) . unwrap ( ) . as_str ( ) . unwrap ( ) ;
17-
18- id == uid
19- } ) ;
20-
21- let credential_obj = credential. unwrap ( ) . as_object_mut ( ) . unwrap ( ) ;
22-
23- let credentials = credential_obj
24- . get_mut ( "credential" )
25- . unwrap ( )
26- . as_object_mut ( )
27- . unwrap ( ) ;
28-
29- let secret = credentials. get ( "twoFactor" ) . unwrap ( ) . as_str ( ) . unwrap ( ) ;
30- let totp = TOTPBuilder :: new ( ) . base32_key ( secret) . finalize ( ) . unwrap ( ) ;
31-
32- let code = totp. generate ( ) ;
33- let response: Value = json ! ( { "success" : true , "code" : code } ) ;
10+ let container = driver:: read ( password) ;
3411
35- response
12+ let credentials = match container. as_array ( ) {
13+ Some ( arr) => arr,
14+ None => return json ! ( { "success" : false , "message" : "Failed to read vault" } ) ,
15+ } ;
16+
17+ let credential = match credentials. iter ( ) . find ( |c| {
18+ c. as_object ( )
19+ . and_then ( |obj| obj. get ( "uid" ) )
20+ . and_then ( |id| id. as_str ( ) )
21+ . map ( |id| id == uid)
22+ . unwrap_or ( false )
23+ } ) {
24+ Some ( c) => c,
25+ None => return json ! ( { "success" : false , "message" : "Credential not found" } ) ,
26+ } ;
27+
28+ let secret = match credential
29+ . get ( "credential" )
30+ . and_then ( |c| c. get ( "twoFactor" ) )
31+ . and_then ( |t| t. as_str ( ) )
32+ {
33+ Some ( s) => s,
34+ None => return json ! ( { "success" : false , "message" : "No 2FA secret found" } ) ,
35+ } ;
36+
37+ let totp = match TOTPBuilder :: new ( ) . base32_key ( secret) . finalize ( ) {
38+ Ok ( t) => t,
39+ Err ( _) => return json ! ( { "success" : false , "message" : "Invalid 2FA secret" } ) ,
40+ } ;
41+
42+ json ! ( { "success" : true , "code" : totp. generate( ) } )
3643}
3744
3845#[ tauri:: command]
@@ -52,50 +59,60 @@ fn export_credentials(password: &str) -> Value {
5259 return json ! ( { "success" : false , "message" : "Authentication failed. Invalid password." } ) ;
5360 }
5461
55- let response: Value = json ! ( { "success" : true , "data" : data } ) ;
56-
57- response
62+ json ! ( { "success" : true , "data" : data } )
5863}
5964
6065#[ tauri:: command]
6166fn remove_credentials ( password : & str , uid : & str ) -> Value {
6267 let mut container = driver:: read ( password) ;
63- let credentials = container. as_array_mut ( ) . unwrap ( ) ;
6468
65- credentials. retain ( |credential| {
66- let credential = credential. as_object ( ) . unwrap ( ) ;
67- let id = credential. get ( "uid" ) . unwrap ( ) . as_str ( ) . unwrap ( ) ;
69+ let credentials = match container. as_array_mut ( ) {
70+ Some ( arr) => arr,
71+ None => return json ! ( { "success" : false , "message" : "Failed to read vault" } ) ,
72+ } ;
6873
69- id != uid
74+ credentials. retain ( |credential| {
75+ credential
76+ . as_object ( )
77+ . and_then ( |obj| obj. get ( "uid" ) )
78+ . and_then ( |id| id. as_str ( ) )
79+ . map ( |id| id != uid)
80+ . unwrap_or ( true )
7081 } ) ;
7182
7283 driver:: write ( password, json ! ( credentials) ) ;
7384
74- let response: Value = json ! ( { "success" : true } ) ;
75-
76- response
85+ json ! ( { "success" : true } )
7786}
7887
7988#[ tauri:: command]
8089fn update_credential ( password : & str , uid : & str , credential_type : & str , credential : Value ) -> Value {
8190 let mut container = driver:: read ( password) ;
82- let credentials = container. as_array_mut ( ) . unwrap ( ) ;
8391
84- for item in credentials. iter_mut ( ) {
85- let credential_obj = item. as_object_mut ( ) . unwrap ( ) ;
86- let id = credential_obj. get ( "uid" ) . unwrap ( ) . as_str ( ) . unwrap ( ) ;
92+ let credentials = match container. as_array_mut ( ) {
93+ Some ( arr) => arr,
94+ None => return json ! ( { "success" : false , "message" : "Failed to read vault" } ) ,
95+ } ;
8796
88- if id == uid {
89- credential_obj. insert ( "type" . to_string ( ) , json ! ( credential_type) ) ;
90- credential_obj. insert ( "credential" . to_string ( ) , credential. clone ( ) ) ;
91- break ;
97+ for item in credentials. iter_mut ( ) {
98+ if let Some ( obj) = item. as_object_mut ( ) {
99+ let matches = obj
100+ . get ( "uid" )
101+ . and_then ( |id| id. as_str ( ) )
102+ . map ( |id| id == uid)
103+ . unwrap_or ( false ) ;
104+
105+ if matches {
106+ obj. insert ( "type" . to_string ( ) , json ! ( credential_type) ) ;
107+ obj. insert ( "credential" . to_string ( ) , credential. clone ( ) ) ;
108+ break ;
109+ }
92110 }
93111 }
94112
95113 driver:: write ( password, json ! ( credentials) ) ;
96114
97- let response: Value = json ! ( { "success" : true } ) ;
98- response
115+ json ! ( { "success" : true } )
99116}
100117
101118#[ tauri:: command]
@@ -104,7 +121,11 @@ fn add_credential(password: &str, credential_type: &str, credential: Value) -> V
104121
105122 let uid = Uuid :: new_v4 ( ) . to_string ( ) ;
106123
107- let credentials = container. as_array_mut ( ) . unwrap ( ) ;
124+ let credentials = match container. as_array_mut ( ) {
125+ Some ( arr) => arr,
126+ None => return json ! ( { "success" : false , "message" : "Failed to read vault" } ) ,
127+ } ;
128+
108129 credentials. push ( json ! ( {
109130 "uid" : uid,
110131 "type" : credential_type,
@@ -113,9 +134,7 @@ fn add_credential(password: &str, credential_type: &str, credential: Value) -> V
113134
114135 driver:: write ( password, json ! ( credentials) ) ;
115136
116- let response: Value = json ! ( { "success" : true } ) ;
117-
118- response
137+ json ! ( { "success" : true } )
119138}
120139
121140#[ tauri:: command]
@@ -125,30 +144,23 @@ fn get_credentials(password: &str) -> Result<Vec<Value>, String> {
125144 return Err ( "Authentication failed. Invalid password." . to_string ( ) ) ;
126145 }
127146
128- let response : Vec < Value > = data
147+ let credentials = data
129148 . as_array ( )
130- . unwrap ( )
149+ . ok_or ( "Invalid vault format" ) ?;
150+
151+ let response: Vec < Value > = credentials
131152 . iter ( )
132153 . map ( |credential| {
133154 let mut credential = credential. clone ( ) ;
134- let credential_obj = credential. as_object_mut ( ) . unwrap ( ) ;
135-
136- let credentials = credential_obj
137- . get_mut ( "credential" )
138- . unwrap ( )
139- . as_object_mut ( )
140- . unwrap ( ) ;
141-
142- let twofactor = credentials
143- . entry ( "twoFactor" )
144- . or_insert ( serde_json:: Value :: Bool ( false ) ) ;
145-
146- if twofactor. is_boolean ( ) {
147- * twofactor = serde_json:: Value :: Bool ( false ) ;
148- } else {
149- * twofactor = serde_json:: Value :: Bool ( true ) ;
155+ if let Some ( obj) = credential. as_object_mut ( ) {
156+ if let Some ( creds) = obj. get_mut ( "credential" ) . and_then ( |c| c. as_object_mut ( ) ) {
157+ let has_twofactor = creds
158+ . get ( "twoFactor" )
159+ . map ( |t| t. is_string ( ) )
160+ . unwrap_or ( false ) ;
161+ creds. insert ( "twoFactor" . to_string ( ) , Value :: Bool ( has_twofactor) ) ;
162+ }
150163 }
151-
152164 credential
153165 } )
154166 . collect ( ) ;
@@ -162,20 +174,32 @@ fn register(password: &str) -> Value {
162174
163175 driver:: write ( password, json ! ( [ ] ) ) ;
164176
165- let response: Value = json ! ( { "success" : true } ) ;
166-
167- response
177+ json ! ( { "success" : true } )
168178}
169179
170180#[ tauri:: command]
171181fn login ( password : & str ) -> bool {
172- let container = driver:: read ( password) ;
173-
174- if container. is_array ( ) {
175- return true ;
182+ let container_path = vault:: get_container_path ( ) ;
183+ let encrypted_data = match std:: fs:: read ( & container_path) {
184+ Ok ( data) => data,
185+ Err ( _) => return false ,
186+ } ;
187+
188+ // Try legacy format first (fast, no KDF)
189+ if let Ok ( plaintext) = vault:: decrypt_legacy_public ( password, & encrypted_data) {
190+ if let Ok ( container) = serde_json:: from_str :: < serde_json:: Value > ( & plaintext) {
191+ if container. is_array ( ) {
192+ // Re-encrypt with Argon2id
193+ driver:: write ( password, container) ;
194+ return true ;
195+ }
196+ }
197+ return false ;
176198 }
177199
178- false
200+ // Try new Argon2id format
201+ let container = driver:: read ( password) ;
202+ container. is_array ( )
179203}
180204
181205#[ tauri:: command]
0 commit comments