1
- import NimQml , chronicles, json
1
+ import NimQml , chronicles, json, strutils
2
2
import logging
3
3
4
4
import io_interface
@@ -14,12 +14,14 @@ from app_service/service/settings/dto/settings import SettingsDto
14
14
from app_service/ service/ accounts/ dto/ accounts import AccountDto
15
15
from app_service/ service/ keycardV2/ dto import KeycardEventDto , KeycardExportedKeysDto , KeycardState
16
16
17
+ import ../ startup/ models/ login_account_item as login_acc_item
18
+
17
19
export io_interface
18
20
19
21
logScope:
20
22
topics = " onboarding-module"
21
23
22
- type SecondaryFlow * {.pure } = enum
24
+ type OnboardingFlow * {.pure } = enum
23
25
Unknown = 0 ,
24
26
CreateProfileWithPassword ,
25
27
CreateProfileWithSeedphrase ,
@@ -28,13 +30,17 @@ type SecondaryFlow* {.pure} = enum
28
30
LoginWithSeedphrase ,
29
31
LoginWithSyncing ,
30
32
LoginWithKeycard ,
31
- ActualLogin , # TODO get the real name and value for this when it's implemented on the front-end
33
+
34
+ type LoginMethod * {.pure } = enum
35
+ Unknown = 0 ,
36
+ Password ,
37
+ Keycard ,
32
38
33
39
type ProgressState * {.pure .} = enum
34
40
Idle ,
35
41
InProgress ,
36
42
Success ,
37
- Failed
43
+ Failed ,
38
44
39
45
type
40
46
Module * [T: io_interface.DelegateInterface ] = ref object of io_interface.AccessInterface
43
49
viewVariant: QVariant
44
50
controller: Controller
45
51
localPairingStatus: LocalPairingStatus
46
- currentFlow: SecondaryFlow
52
+ loginFlow: LoginMethod
53
+ onboardingFlow: OnboardingFlow
47
54
exportedKeys: KeycardExportedKeysDto
48
55
49
56
proc newModule * [T](
@@ -58,6 +65,8 @@ proc newModule*[T](
58
65
result .delegate = delegate
59
66
result .view = view.newView (result )
60
67
result .viewVariant = newQVariant (result .view)
68
+ result .onboardingFlow = OnboardingFlow .Unknown
69
+ result .loginFlow = LoginMethod .Unknown
61
70
result .controller = controller.newController (
62
71
result ,
63
72
events,
@@ -87,6 +96,20 @@ method onAppLoaded*[T](self: Module[T]) =
87
96
method load * [T](self: Module [T]) =
88
97
singletonInstance.engine.setRootContextProperty (" onboardingModule" , self.viewVariant)
89
98
self.controller.init ()
99
+
100
+ let openedAccounts = self.controller.getOpenedAccounts ()
101
+ if openedAccounts.len > 0 :
102
+ var items: seq [login_acc_item.Item ]
103
+ for i in 0 ..< openedAccounts.len:
104
+ let acc = openedAccounts[i]
105
+ var thumbnailImage: string
106
+ var largeImage: string
107
+ acc.extractImages (thumbnailImage, largeImage)
108
+ items.add (login_acc_item.initItem (order = i, acc.name, icon = " " , thumbnailImage, largeImage, acc.keyUid, acc.colorHash,
109
+ acc.colorId, acc.keycardPairing))
110
+
111
+ self.view.setLoginAccountsModelItems (items)
112
+
90
113
self.delegate.onboardingDidLoad ()
91
114
92
115
method initialize * [T](self: Module [T], pin: string ) =
@@ -118,26 +141,26 @@ method loadMnemonic*[T](self: Module[T], mnemonic: string) =
118
141
119
142
method finishOnboardingFlow * [T](self: Module [T], flowInt: int , dataJson: string ): string =
120
143
try :
121
- self.currentFlow = SecondaryFlow (flowInt)
144
+ self.onboardingFlow = OnboardingFlow (flowInt)
122
145
123
146
let data = parseJson (dataJson)
124
147
let password = data[" password" ].str
125
148
let seedPhrase = data[" seedphrase" ].str
126
149
127
150
var err = " "
128
151
129
- case self.currentFlow :
152
+ case self.onboardingFlow :
130
153
# CREATE PROFILE FLOWS
131
- of SecondaryFlow .CreateProfileWithPassword :
154
+ of OnboardingFlow .CreateProfileWithPassword :
132
155
err = self.controller.createAccountAndLogin (password)
133
- of SecondaryFlow .CreateProfileWithSeedphrase :
156
+ of OnboardingFlow .CreateProfileWithSeedphrase :
134
157
err = self.controller.restoreAccountAndLogin (
135
158
password,
136
159
seedPhrase,
137
160
recoverAccount = false ,
138
161
keycardInstanceUID = " " ,
139
162
)
140
- of SecondaryFlow .CreateProfileWithKeycardNewSeedphrase :
163
+ of OnboardingFlow .CreateProfileWithKeycardNewSeedphrase :
141
164
# New user with a seedphrase we showed them
142
165
let keycardEvent = self.view.getKeycardEvent ()
143
166
err = self.controller.restoreAccountAndLogin (
@@ -146,7 +169,7 @@ method finishOnboardingFlow*[T](self: Module[T], flowInt: int, dataJson: string)
146
169
recoverAccount = false ,
147
170
keycardInstanceUID = keycardEvent.keycardInfo.instanceUID,
148
171
)
149
- of SecondaryFlow .CreateProfileWithKeycardExistingSeedphrase :
172
+ of OnboardingFlow .CreateProfileWithKeycardExistingSeedphrase :
150
173
# New user who entered their own seed phrase
151
174
let keycardEvent = self.view.getKeycardEvent ()
152
175
err = self.controller.restoreAccountAndLogin (
@@ -157,53 +180,78 @@ method finishOnboardingFlow*[T](self: Module[T], flowInt: int, dataJson: string)
157
180
)
158
181
159
182
# LOGIN FLOWS
160
- of SecondaryFlow .LoginWithSeedphrase :
183
+ of OnboardingFlow .LoginWithSeedphrase :
161
184
err = self.controller.restoreAccountAndLogin (
162
185
password,
163
186
seedPhrase,
164
187
recoverAccount = true ,
165
188
keycardInstanceUID = " " ,
166
189
)
167
- of SecondaryFlow .LoginWithSyncing :
190
+ of OnboardingFlow .LoginWithSyncing :
168
191
# The pairing was already done directly through inputConnectionStringForBootstrapping, we can login
169
192
self.controller.loginLocalPairingAccount (
170
193
self.localPairingStatus.account,
171
194
self.localPairingStatus.password,
172
195
self.localPairingStatus.chatKey,
173
196
)
174
- of SecondaryFlow .LoginWithKeycard :
197
+ of OnboardingFlow .LoginWithKeycard :
175
198
err = self.controller.restoreKeycardAccountAndLogin (
176
199
self.view.getKeycardEvent ().keycardInfo.keyUID,
177
200
self.view.getKeycardEvent ().keycardInfo.instanceUID,
178
201
self.exportedKeys,
179
202
recoverAccount = true
180
203
)
181
204
else :
182
- raise newException (ValueError , " Unknown flow: " & $ self.currentFlow )
205
+ raise newException (ValueError , " Unknown flow: " & $ self.onboardingFlow )
183
206
184
207
return err
185
208
except Exception as e:
186
209
error " Error finishing Onboarding Flow" , msg = e.msg
187
210
return e.msg
188
211
212
+ method loginRequested * [T](self: Module [T], keyUid: string , loginFlow: int , dataJson: string ) =
213
+ try :
214
+ self.loginFlow = LoginMethod (loginFlow)
215
+
216
+ let data = parseJson (dataJson)
217
+ let account = self.controller.getAccountByKeyUid (keyUid)
218
+
219
+ case self.loginFlow:
220
+ of LoginMethod .Password :
221
+ self.controller.login (account, data[" password" ].str)
222
+ of LoginMethod .Keycard :
223
+ self.authorize (data[" pin" ].str)
224
+ # We will continue the flow when the card is authorized in onKeycardStateUpdated
225
+ else :
226
+ raise newException (ValueError , " Unknown flow: " & $ self.onboardingFlow)
227
+
228
+ except Exception as e:
229
+ error " Error finishing Login Flow" , msg = e.msg
230
+ self.view.accountLoginError (e.msg, wrongPassword = false )
231
+
189
232
proc finishAppLoading2 [T](self: Module [T]) =
190
233
self.delegate.appReady ()
191
234
192
- # TODO get the flow to send the right metric
193
235
var eventType = " user-logged-in"
194
- if self.currentFlow != SecondaryFlow . ActualLogin :
236
+ if self.loginFlow == LoginMethod . Unknown :
195
237
eventType = " onboarding-completed"
196
238
singletonInstance.globalEvents.addCentralizedMetricIfEnabled (eventType,
197
- $ (%* {" flowType" : repr (self.currentFlow )}))
239
+ $ (%* {" flowType" : repr (self.onboardingFlow )}))
198
240
199
241
self.controller.stopKeycardService ()
200
242
201
243
self.delegate.finishAppLoading ()
202
-
244
+
245
+ method onAccountLoginError * [T](self: Module [T], error: string ) =
246
+ # SQLITE_NOTADB: "file is not a database"
247
+ var wrongPassword = false
248
+ if error.contains (" file is not a database" ):
249
+ wrongPassword = true
250
+ self.view.accountLoginError (error, wrongPassword)
251
+
203
252
method onNodeLogin * [T](self: Module [T], error: string , account: AccountDto , settings: SettingsDto ) =
204
253
if error.len != 0 :
205
- # TODO : Handle error
206
- echo " ERROR from onNodeLogin: " , error
254
+ self.onAccountLoginError (error)
207
255
return
208
256
209
257
self.controller.setLoggedInAccount (account)
@@ -221,6 +269,11 @@ method onLocalPairingStatusUpdate*[T](self: Module[T], status: LocalPairingStatu
221
269
method onKeycardStateUpdated * [T](self: Module [T], keycardEvent: KeycardEventDto ) =
222
270
self.view.setKeycardEvent (keycardEvent)
223
271
272
+ if keycardEvent.state == KeycardState .Authorized and self.loginFlow == LoginMethod .Keycard :
273
+ # After authorizing, we export the keys
274
+ self.controller.exportLoginKeysFromKeycard ()
275
+ # We will login once we have the keys in onKeycardExportLoginKeysSuccess
276
+
224
277
if keycardEvent.state == KeycardState .NotEmpty and self.view.getPinSettingState () == ProgressState .InProgress .int :
225
278
# We just finished setting the pin
226
279
self.view.setPinSettingState (ProgressState .Success .int )
@@ -235,19 +288,39 @@ method onKeycardSetPinFailure*[T](self: Module[T], error: string) =
235
288
method onKeycardAuthorizeFailure * [T](self: Module [T], error: string ) =
236
289
self.view.setAuthorizationState (ProgressState .Failed .int )
237
290
291
+ if self.loginFlow == LoginMethod .Keycard :
292
+ # We were trying to login and the authorization failed
293
+ var wrongPassword = false
294
+ if error.contains (" wrong pin" ):
295
+ wrongPassword = true
296
+ self.view.accountLoginError (error, wrongPassword)
297
+
238
298
method onKeycardLoadMnemonicFailure * [T](self: Module [T], error: string ) =
239
299
self.view.setAddKeyPairState (ProgressState .Failed .int )
240
300
241
301
method onKeycardLoadMnemonicSuccess * [T](self: Module [T], keyUID: string ) =
242
302
self.view.setAddKeyPairState (ProgressState .Success .int )
243
303
244
- method onKeycardExportKeysFailure * [T](self: Module [T], error: string ) =
304
+ method onKeycardExportRestoreKeysFailure * [T](self: Module [T], error: string ) =
245
305
self.view.setRestoreKeysExportState (ProgressState .Failed .int )
246
306
247
- method onKeycardExportKeysSuccess * [T](self: Module [T], exportedKeys: KeycardExportedKeysDto ) =
307
+ method onKeycardExportRestoreKeysSuccess * [T](self: Module [T], exportedKeys: KeycardExportedKeysDto ) =
248
308
self.exportedKeys = exportedKeys
249
309
self.view.setRestoreKeysExportState (ProgressState .Success .int )
250
310
311
+ method onKeycardExportLoginKeysFailure * [T](self: Module [T], error: string ) =
312
+ self.view.accountLoginError (error, wrongPassword = false )
313
+
314
+ method onKeycardExportLoginKeysSuccess * [T](self: Module [T], exportedKeys: KeycardExportedKeysDto ) =
315
+ # We got the keys, now we can login. If everything goes well, we will finish the app loading
316
+ self.controller.login (
317
+ self.controller.getAccountByKeyUid (self.view.getKeycardEvent.keycardInfo.keyUID),
318
+ password = " " ,
319
+ keycard = true ,
320
+ publicEncryptionKey = exportedKeys.encryptionKey.publicKey,
321
+ privateWhisperKey = exportedKeys.whisperKey.privateKey,
322
+ )
323
+
251
324
method exportRecoverKeys * [T](self: Module [T]) =
252
325
self.view.setRestoreKeysExportState (ProgressState .InProgress .int )
253
326
self.controller.exportRecoverKeysFromKeycard ()
0 commit comments