feat(@desktop/onboarding): `Lost Keycard` - start using account without keycard

This commit introduces:
- `Start using account without keycard` flow

Closes: #7642
This commit is contained in:
Sale Djenic 2023-01-26 12:52:01 +01:00 committed by Anthony Laibe
parent b00f0a80b5
commit 841a37e930
29 changed files with 334 additions and 86 deletions

View File

@ -373,8 +373,7 @@ proc convertSelectedKeyPairToKeycardAccount*(self: Controller, password: string)
return return
let acc = self.accountsService.createAccountFromMnemonic(self.getSeedPhrase(), includeEncryption = true) let acc = self.accountsService.createAccountFromMnemonic(self.getSeedPhrase(), includeEncryption = true)
singletonInstance.localAccountSettings.setStoreToKeychainValue(LS_VALUE_NOT_NOW) singletonInstance.localAccountSettings.setStoreToKeychainValue(LS_VALUE_NOT_NOW)
self.accountsService.convertToKeycardAccount(self.tmpSelectedKeyPairDto.keyUid, self.accountsService.convertToKeycardAccount(currentPassword = password,
currentPassword = password,
newPassword = acc.derivedAccounts.encryption.publicKey) newPassword = acc.derivedAccounts.encryption.publicKey)
proc getConvertingProfileSuccess*(self: Controller): bool = proc getConvertingProfileSuccess*(self: Controller): bool =

View File

@ -338,7 +338,7 @@ proc importMnemonic*(self: Controller): bool =
self.delegate.importAccountSuccess() self.delegate.importAccountSuccess()
return true return true
else: else:
self.delegate.importAccountError(error) self.delegate.emitStartupError(error, StartupErrorType.ImportAccError)
return false return false
proc setupKeychain(self: Controller, store: bool) = proc setupKeychain(self: Controller, store: bool) =
@ -352,7 +352,7 @@ proc setupAccount(self: Controller, accountId: string, storeToKeychain: bool) =
self.delegate.moveToLoadingAppState() self.delegate.moveToLoadingAppState()
let error = self.accountsService.setupAccount(accountId, self.tmpPassword, self.tmpDisplayName) let error = self.accountsService.setupAccount(accountId, self.tmpPassword, self.tmpDisplayName)
if error != "": if error != "":
self.delegate.setupAccountError(error) self.delegate.emitStartupError(error, StartupErrorType.SetupAccError)
else: else:
self.setupKeychain(storeToKeychain) self.setupKeychain(storeToKeychain)
@ -388,7 +388,7 @@ proc setupKeycardAccount*(self: Controller, storeToKeychain: bool, newKeycard: b
else: else:
if self.tmpKeycardEvent.keyUid.len == 0 or if self.tmpKeycardEvent.keyUid.len == 0 or
self.accountsService.openedAccountsContainsKeyUid(self.tmpKeycardEvent.keyUid): self.accountsService.openedAccountsContainsKeyUid(self.tmpKeycardEvent.keyUid):
self.delegate.importAccountError(ACCOUNT_ALREADY_EXISTS_ERROR) self.delegate.emitStartupError(ACCOUNT_ALREADY_EXISTS_ERROR, StartupErrorType.ImportAccError)
return return
self.delegate.moveToLoadingAppState() self.delegate.moveToLoadingAppState()
if newKeycard: if newKeycard:
@ -441,19 +441,43 @@ proc login*(self: Controller) =
if(error.len > 0): if(error.len > 0):
self.delegate.emitAccountLoginError(error) self.delegate.emitAccountLoginError(error)
proc loginAccountKeycard*(self: Controller, storeToKeychain = false, syncWalletAfterLogin = false) = proc loginAccountKeycard*(self: Controller, storeToKeychainValue: string, syncWalletAfterLogin = false) =
if syncWalletAfterLogin: if syncWalletAfterLogin:
self.syncKeycardBasedOnAppWalletStateAfterLogin() self.syncKeycardBasedOnAppWalletStateAfterLogin()
singletonInstance.localAccountSettings.setStoreToKeychainValue(storeToKeychainValue)
self.delegate.moveToLoadingAppState()
let selAcc = self.getSelectedLoginAccount()
let error = self.accountsService.loginAccountKeycard(selAcc, self.tmpKeycardEvent)
if(error.len > 0):
self.delegate.emitAccountLoginError(error)
proc loginAccountKeycardUsingSeedPhrase*(self: Controller, storeToKeychain: bool) =
let acc = self.accountsService.createAccountFromMnemonic(self.getSeedPhrase(), includeEncryption = true, includeWhisper = true)
let selAcc = self.getSelectedLoginAccount()
var kcData = KeycardEvent(
keyUid: acc.keyUid,
masterKey: KeyDetails(address: acc.address),
whisperKey: KeyDetails(privateKey: acc.derivedAccounts.whisper.privateKey),
encryptionKey: KeyDetails(publicKey: acc.derivedAccounts.encryption.publicKey)
)
if acc.derivedAccounts.whisper.privateKey.startsWith("0x"):
kcData.whisperKey.privateKey = acc.derivedAccounts.whisper.privateKey[2..^1]
if storeToKeychain: if storeToKeychain:
## storing not now, user will be asked to store the pin once he is logged in ## storing not now, user will be asked to store the pin once he is logged in
singletonInstance.localAccountSettings.setStoreToKeychainValue(LS_VALUE_NOT_NOW) singletonInstance.localAccountSettings.setStoreToKeychainValue(LS_VALUE_NOT_NOW)
else: else:
singletonInstance.localAccountSettings.setStoreToKeychainValue(LS_VALUE_NEVER) singletonInstance.localAccountSettings.setStoreToKeychainValue(LS_VALUE_NEVER)
self.delegate.moveToLoadingAppState() self.delegate.moveToLoadingAppState()
let error = self.accountsService.loginAccountKeycard(self.tmpKeycardEvent) let error = self.accountsService.loginAccountKeycard(selAcc, kcData)
if(error.len > 0): if(error.len > 0):
self.delegate.emitAccountLoginError(error) self.delegate.emitAccountLoginError(error)
proc convertToRegularAccount*(self: Controller): string =
let acc = self.accountsService.createAccountFromMnemonic(self.getSeedPhrase(), includeEncryption = true)
return self.accountsService.convertToRegularAccount(self.getSeedPhrase(), acc.derivedAccounts.encryption.publicKey, self.getPassword())
proc getKeyUidForSeedPhrase*(self: Controller, seedPhrase: string): string = proc getKeyUidForSeedPhrase*(self: Controller, seedPhrase: string): string =
let acc = self.accountsService.createAccountFromMnemonic(seedPhrase) let acc = self.accountsService.createAccountFromMnemonic(seedPhrase)
return acc.keyUid return acc.keyUid

View File

@ -29,6 +29,8 @@ method executePrimaryCommand*(self: BiometricsState, controller: Controller) =
elif self.flowType == FlowType.LostKeycardReplacement: elif self.flowType == FlowType.LostKeycardReplacement:
self.storeToKeychain = storeToKeychain self.storeToKeychain = storeToKeychain
controller.startLoginFlowAutomatically(controller.getPin()) controller.startLoginFlowAutomatically(controller.getPin())
elif self.flowType == FlowType.LostKeycardConvertToRegularAccount:
controller.loginAccountKeycardUsingSeedPhrase(storeToKeychain)
method executeSecondaryCommand*(self: BiometricsState, controller: Controller) = method executeSecondaryCommand*(self: BiometricsState, controller: Controller) =
let storeToKeychain = false # false, cause we don't have keychain support for other than mac os let storeToKeychain = false # false, cause we don't have keychain support for other than mac os
@ -49,6 +51,8 @@ method executeSecondaryCommand*(self: BiometricsState, controller: Controller) =
elif self.flowType == FlowType.LostKeycardReplacement: elif self.flowType == FlowType.LostKeycardReplacement:
self.storeToKeychain = storeToKeychain self.storeToKeychain = storeToKeychain
controller.startLoginFlowAutomatically(controller.getPin()) controller.startLoginFlowAutomatically(controller.getPin())
elif self.flowType == FlowType.LostKeycardConvertToRegularAccount:
controller.loginAccountKeycardUsingSeedPhrase(storeToKeychain)
method resolveKeycardNextState*(self: BiometricsState, keycardFlowType: string, keycardEvent: KeycardEvent, method resolveKeycardNextState*(self: BiometricsState, keycardFlowType: string, keycardEvent: KeycardEvent,
controller: Controller): State = controller: Controller): State =
@ -56,4 +60,7 @@ method resolveKeycardNextState*(self: BiometricsState, keycardFlowType: string,
if keycardFlowType == ResponseTypeValueKeycardFlowResult and if keycardFlowType == ResponseTypeValueKeycardFlowResult and
keycardEvent.error.len == 0: keycardEvent.error.len == 0:
controller.setKeycardEvent(keycardEvent) controller.setKeycardEvent(keycardEvent)
controller.loginAccountKeycard(self.storeToKeychain, syncWalletAfterLogin = true) var storeToKeychainValue = LS_VALUE_NEVER
if self.storeToKeychain:
storeToKeychainValue = LS_VALUE_NOT_NOW
controller.loginAccountKeycard(storeToKeychainValue, syncWalletAfterLogin = true)

View File

@ -56,5 +56,6 @@ method resolveKeycardNextState*(self: KeycardEnterPukState, keycardFlowType: str
if keycardFlowType == ResponseTypeValueKeycardFlowResult: if keycardFlowType == ResponseTypeValueKeycardFlowResult:
controller.setKeycardEvent(keycardEvent) controller.setKeycardEvent(keycardEvent)
controller.setPukValid(true) controller.setPukValid(true)
controller.loginAccountKeycard() let storeToKeychainValue = singletonInstance.localAccountSettings.getStoreToKeychainValue()
controller.loginAccountKeycard(storeToKeychainValue)
return nil return nil

View File

@ -44,7 +44,8 @@ method executePrimaryCommand*(self: KeycardPinSetState, controller: Controller)
controller.startLoginFlowAutomatically(controller.getPin()) controller.startLoginFlowAutomatically(controller.getPin())
return return
if controller.getValidPuk(): if controller.getValidPuk():
controller.loginAccountKeycard() let storeToKeychainValue = singletonInstance.localAccountSettings.getStoreToKeychainValue()
controller.loginAccountKeycard(storeToKeychainValue)
if self.flowType == FlowType.LostKeycardReplacement: if self.flowType == FlowType.LostKeycardReplacement:
if main_constants.IS_MACOS: if main_constants.IS_MACOS:
return return
@ -56,10 +57,10 @@ method resolveKeycardNextState*(self: KeycardPinSetState, keycardFlowType: strin
if keycardFlowType == ResponseTypeValueKeycardFlowResult and if keycardFlowType == ResponseTypeValueKeycardFlowResult and
keycardEvent.error.len == 0: keycardEvent.error.len == 0:
controller.setKeycardEvent(keycardEvent) controller.setKeycardEvent(keycardEvent)
controller.loginAccountKeycard(storeToKeychain = true, syncWalletAfterLogin = true) controller.loginAccountKeycard(storeToKeychainValue = LS_VALUE_NOT_NOW, syncWalletAfterLogin = true)
if self.flowType == FlowType.AppLogin: if self.flowType == FlowType.AppLogin:
if keycardFlowType == ResponseTypeValueKeycardFlowResult and if keycardFlowType == ResponseTypeValueKeycardFlowResult and
keycardEvent.error.len == 0: keycardEvent.error.len == 0:
# we are here in case of recover account from the login flow using seed phrase # we are here in case of recover account from the login flow using seed phrase
controller.setKeycardEvent(keycardEvent) controller.setKeycardEvent(keycardEvent)
controller.loginAccountKeycard(storeToKeychain = false, syncWalletAfterLogin = false) controller.loginAccountKeycard(storeToKeychainValue = LS_VALUE_NEVER, syncWalletAfterLogin = false)

View File

@ -10,6 +10,5 @@ proc delete*(self: KeycardWrongKeycardState) =
method executeBackCommand*(self: KeycardWrongKeycardState, controller: Controller) = method executeBackCommand*(self: KeycardWrongKeycardState, controller: Controller) =
if self.flowType == FlowType.FirstRunOldUserKeycardImport or if self.flowType == FlowType.FirstRunOldUserKeycardImport or
self.flowType == FlowType.AppLogin or self.flowType == FlowType.AppLogin:
self.flowType == FlowType.LostKeycardReplacement:
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WrongSeedPhrase, add = false)) controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WrongSeedPhrase, add = false))

View File

@ -59,5 +59,6 @@ method resolveKeycardNextState*(self: KeycardWrongPukState, keycardFlowType: str
if keycardFlowType == ResponseTypeValueKeycardFlowResult: if keycardFlowType == ResponseTypeValueKeycardFlowResult:
controller.setKeycardEvent(keycardEvent) controller.setKeycardEvent(keycardEvent)
controller.setPukValid(true) controller.setPukValid(true)
controller.loginAccountKeycard() let storeToKeychainValue = singletonInstance.localAccountSettings.getStoreToKeychainValue()
controller.loginAccountKeycard(storeToKeychainValue)
return nil return nil

View File

@ -0,0 +1,14 @@
type
LoginKeycardConvertedToRegularAccountState* = ref object of State
proc newLoginKeycardConvertedToRegularAccountState*(flowType: FlowType, backState: State): LoginKeycardConvertedToRegularAccountState =
result = LoginKeycardConvertedToRegularAccountState()
result.setup(flowType, StateType.LoginKeycardConvertedToRegularAccount, backState)
proc delete*(self: LoginKeycardConvertedToRegularAccountState) =
self.State.delete
method executePrimaryCommand*(self: LoginKeycardConvertedToRegularAccountState, controller: Controller) =
if self.flowType == FlowType.LostKeycardConvertToRegularAccount:
info "restart the app because of successfully converted keycard account to regular account"
quit() # quit the app

View File

@ -10,4 +10,5 @@ proc delete*(self: LoginKeycardPinVerifiedState) =
method executePrimaryCommand*(self: LoginKeycardPinVerifiedState, controller: Controller) = method executePrimaryCommand*(self: LoginKeycardPinVerifiedState, controller: Controller) =
if self.flowType == FlowType.AppLogin: if self.flowType == FlowType.AppLogin:
controller.loginAccountKeycard() let storeToKeychainValue = singletonInstance.localAccountSettings.getStoreToKeychainValue()
controller.loginAccountKeycard(storeToKeychainValue)

View File

@ -19,8 +19,9 @@ method executePrimaryCommand*(self: LostKeycardOptionsState, controller: Control
self.setFlowType(FlowType.LostKeycardReplacement) self.setFlowType(FlowType.LostKeycardReplacement)
controller.runLoadAccountFlow() controller.runLoadAccountFlow()
method executeSecondaryCommand*(self: LostKeycardOptionsState, controller: Controller) = method getNextSecondaryState*(self: LostKeycardOptionsState, controller: Controller): State =
echo "TODO: start using account without keycard..." if controller.isSelectedAccountAKeycardAccount():
return createState(StateType.UserProfileEnterSeedPhrase, FlowType.LostKeycardConvertToRegularAccount, self)
method resolveKeycardNextState*(self: LostKeycardOptionsState, keycardFlowType: string, keycardEvent: KeycardEvent, method resolveKeycardNextState*(self: LostKeycardOptionsState, keycardFlowType: string, keycardEvent: KeycardEvent,
controller: Controller): State = controller: Controller): State =

View File

@ -14,6 +14,7 @@ type FlowType* {.pure.} = enum
FirstRunOldUserImportSeedPhrase = "FirstRunOldUserImportSeedPhrase" FirstRunOldUserImportSeedPhrase = "FirstRunOldUserImportSeedPhrase"
AppLogin = "AppLogin" AppLogin = "AppLogin"
LostKeycardReplacement = "LostKeycardReplacement" LostKeycardReplacement = "LostKeycardReplacement"
LostKeycardConvertToRegularAccount = "LostKeycardConvertToRegularAccount"
type StateType* {.pure.} = enum type StateType* {.pure.} = enum
NoState = "NoState" NoState = "NoState"
@ -29,6 +30,7 @@ type StateType* {.pure.} = enum
UserProfileConfirmPassword = "UserProfileConfirmPassword" UserProfileConfirmPassword = "UserProfileConfirmPassword"
UserProfileImportSeedPhrase = "UserProfileImportSeedPhrase" UserProfileImportSeedPhrase = "UserProfileImportSeedPhrase"
UserProfileEnterSeedPhrase = "UserProfileEnterSeedPhrase" UserProfileEnterSeedPhrase = "UserProfileEnterSeedPhrase"
UserProfileWrongSeedPhrase = "UserProfileWrongSeedPhrase"
Biometrics = "Biometrics" Biometrics = "Biometrics"
KeycardPluginReader = "KeycardPluginReader" KeycardPluginReader = "KeycardPluginReader"
KeycardInsertKeycard = "KeycardInsertKeycard" KeycardInsertKeycard = "KeycardInsertKeycard"
@ -69,6 +71,7 @@ type StateType* {.pure.} = enum
LoginKeycardMaxPairingSlotsReached = "LoginKeycardMaxPairingSlotsReached" LoginKeycardMaxPairingSlotsReached = "LoginKeycardMaxPairingSlotsReached"
LoginKeycardEmpty = "LoginKeycardEmpty" LoginKeycardEmpty = "LoginKeycardEmpty"
LoginNotKeycard = "LoginNotKeycard" LoginNotKeycard = "LoginNotKeycard"
LoginKeycardConvertedToRegularAccount = "LoginKeycardConvertedToRegularAccount"
ProfileFetching = "ProfileFetching" ProfileFetching = "ProfileFetching"
ProfileFetchingSuccess = "ProfileFetchingSuccess" ProfileFetchingSuccess = "ProfileFetchingSuccess"
ProfileFetchingTimeout = "ProfileFetchingTimeout" ProfileFetchingTimeout = "ProfileFetchingTimeout"

View File

@ -1,4 +1,5 @@
import sequtils, sugar, chronicles import sequtils, sugar, chronicles
import ../../../global/global_singleton
import ../../../../constants as main_constants import ../../../../constants as main_constants
import ../../../../app_service/service/keycard/constants import ../../../../app_service/service/keycard/constants
import ../controller import ../controller
@ -54,12 +55,14 @@ include user_profile_create_password_state
include user_profile_create_state include user_profile_create_state
include user_profile_create_same_chat_key_state include user_profile_create_same_chat_key_state
include user_profile_enter_seed_phrase_state include user_profile_enter_seed_phrase_state
include user_profile_wrong_seed_phrase_state
include user_profile_import_seed_phrase_state include user_profile_import_seed_phrase_state
include welcome_state_new_user include welcome_state_new_user
include welcome_state_old_user include welcome_state_old_user
include welcome_state include welcome_state
include login_state include login_state
include login_plugin_state include login_plugin_state
include login_keycard_converted_to_regular_account_state
include login_keycard_insert_keycard_state include login_keycard_insert_keycard_state
include login_keycard_inserted_keycard_state include login_keycard_inserted_keycard_state
include login_keycard_reading_keycard_state include login_keycard_reading_keycard_state

View File

@ -21,6 +21,8 @@ proc createState*(stateToBeCreated: StateType, flowType: FlowType, backState: St
return newUserProfileImportSeedPhraseState(flowType, backState) return newUserProfileImportSeedPhraseState(flowType, backState)
if stateToBeCreated == StateType.UserProfileEnterSeedPhrase: if stateToBeCreated == StateType.UserProfileEnterSeedPhrase:
return newUserProfileEnterSeedPhraseState(flowType, backState) return newUserProfileEnterSeedPhraseState(flowType, backState)
if stateToBeCreated == StateType.UserProfileWrongSeedPhrase:
return newUserProfileWrongSeedPhraseState(flowType, backState)
if stateToBeCreated == StateType.Biometrics: if stateToBeCreated == StateType.Biometrics:
return newBiometricsState(flowType, backState) return newBiometricsState(flowType, backState)
if stateToBeCreated == StateType.KeycardPluginReader: if stateToBeCreated == StateType.KeycardPluginReader:
@ -73,6 +75,8 @@ proc createState*(stateToBeCreated: StateType, flowType: FlowType, backState: St
return newLoginState(flowType, backState) return newLoginState(flowType, backState)
if stateToBeCreated == StateType.LoginPlugin: if stateToBeCreated == StateType.LoginPlugin:
return newLoginPluginState(flowType, backState) return newLoginPluginState(flowType, backState)
if stateToBeCreated == StateType.LoginKeycardConvertedToRegularAccount:
return newLoginKeycardConvertedToRegularAccountState(flowType, backState)
if stateToBeCreated == StateType.LoginKeycardInsertKeycard: if stateToBeCreated == StateType.LoginKeycardInsertKeycard:
return newLoginKeycardInsertKeycardState(flowType, backState) return newLoginKeycardInsertKeycardState(flowType, backState)
if stateToBeCreated == StateType.LoginKeycardInsertedKeycard: if stateToBeCreated == StateType.LoginKeycardInsertedKeycard:

View File

@ -24,6 +24,8 @@ method executePrimaryCommand*(self: UserProfileConfirmPasswordState, controller:
elif self.flowType == FlowType.FirstRunNewUserNewKeycardKeys: elif self.flowType == FlowType.FirstRunNewUserNewKeycardKeys:
controller.storeKeycardAccountAndLogin(storeToKeychain, newKeycard = true) controller.storeKeycardAccountAndLogin(storeToKeychain, newKeycard = true)
elif self.flowType == FlowType.FirstRunOldUserImportSeedPhrase: elif self.flowType == FlowType.FirstRunOldUserImportSeedPhrase:
controller.storeImportedAccountAndLogin(storeToKeychain = false) controller.storeImportedAccountAndLogin(storeToKeychain)
elif self.flowType == FlowType.LostKeycardConvertToRegularAccount:
controller.loginAccountKeycardUsingSeedPhrase(storeToKeychain)

View File

@ -32,6 +32,14 @@ method getNextPrimaryState*(self: UserProfileEnterSeedPhraseState, controller: C
if self.enteredMnemonicMatchTargetedKeyUid: if self.enteredMnemonicMatchTargetedKeyUid:
return createState(StateType.KeycardCreatePin, self.flowType, self) return createState(StateType.KeycardCreatePin, self.flowType, self)
return createState(StateType.KeycardWrongKeycard, self.flowType, self) return createState(StateType.KeycardWrongKeycard, self.flowType, self)
if self.flowType == FlowType.LostKeycardReplacement:
if self.enteredMnemonicMatchTargetedKeyUid:
return createState(StateType.KeycardCreatePin, self.flowType, self)
return createState(StateType.UserProfileWrongSeedPhrase, self.flowType, self)
if self.flowType == FlowType.LostKeycardConvertToRegularAccount:
if self.enteredMnemonicMatchTargetedKeyUid:
return createState(StateType.UserProfileCreatePassword, self.flowType, self)
return createState(StateType.UserProfileWrongSeedPhrase, self.flowType, self)
method executePrimaryCommand*(self: UserProfileEnterSeedPhraseState, controller: Controller) = method executePrimaryCommand*(self: UserProfileEnterSeedPhraseState, controller: Controller) =
if self.flowType == FlowType.FirstRunNewUserImportSeedPhrase or if self.flowType == FlowType.FirstRunNewUserImportSeedPhrase or
@ -59,6 +67,10 @@ method executePrimaryCommand*(self: UserProfileEnterSeedPhraseState, controller:
controller.storeSeedPhraseToKeycard(controller.getSeedPhraseLength(), controller.getSeedPhrase()) controller.storeSeedPhraseToKeycard(controller.getSeedPhraseLength(), controller.getSeedPhrase())
else: else:
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WrongSeedPhrase, add = true)) controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WrongSeedPhrase, add = true))
if self.flowType == FlowType.LostKeycardConvertToRegularAccount:
self.enteredMnemonicMatchTargetedKeyUid = controller.keyUidMatchSelectedLoginAccount(keyUid)
if not self.enteredMnemonicMatchTargetedKeyUid:
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WrongSeedPhrase, add = true))
method resolveKeycardNextState*(self: UserProfileEnterSeedPhraseState, keycardFlowType: string, keycardEvent: KeycardEvent, method resolveKeycardNextState*(self: UserProfileEnterSeedPhraseState, keycardFlowType: string, keycardEvent: KeycardEvent,
controller: Controller): State = controller: Controller): State =

View File

@ -0,0 +1,22 @@
type
UserProfileWrongSeedPhraseState* = ref object of State
proc newUserProfileWrongSeedPhraseState*(flowType: FlowType, backState: State): UserProfileWrongSeedPhraseState =
result = UserProfileWrongSeedPhraseState()
result.setup(flowType, StateType.UserProfileWrongSeedPhrase, backState)
proc delete*(self: UserProfileWrongSeedPhraseState) =
self.State.delete
method executeBackCommand*(self: UserProfileWrongSeedPhraseState, controller: Controller) =
if self.flowType == FlowType.LostKeycardReplacement or
self.flowType == FlowType.LostKeycardConvertToRegularAccount:
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WrongSeedPhrase, add = false))
method executePrimaryCommand*(self: UserProfileWrongSeedPhraseState, controller: Controller) =
self.executeBackCommand(controller)
method getNextPrimaryState*(self: UserProfileWrongSeedPhraseState, controller: Controller): State =
if self.flowType == FlowType.LostKeycardReplacement or
self.flowType == FlowType.LostKeycardConvertToRegularAccount:
return self.getBackState()

View File

@ -5,6 +5,13 @@ from ../../../app_service/service/keycard/service import KeycardEvent, KeyDetail
const UNIQUE_STARTUP_MODULE_IDENTIFIER* = "SartupModule" const UNIQUE_STARTUP_MODULE_IDENTIFIER* = "SartupModule"
type
StartupErrorType* {.pure.} = enum
UnknownType = 0
ImportAccError
SetupAccError
ConvertToRegularAccError
type type
AccessInterface* {.pure inheritable.} = ref object of RootObj AccessInterface* {.pure inheritable.} = ref object of RootObj
@ -92,15 +99,12 @@ method getPin*(self: AccessInterface): string {.base.} =
method getPasswordStrengthScore*(self: AccessInterface, password: string, userName: string): int {.base.} = method getPasswordStrengthScore*(self: AccessInterface, password: string, userName: string): int {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method setupAccountError*(self: AccessInterface, error: string) {.base.} = method emitStartupError*(self: AccessInterface, error: string, errType: StartupErrorType) {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method validMnemonic*(self: AccessInterface, mnemonic: string): bool {.base.} = method validMnemonic*(self: AccessInterface, mnemonic: string): bool {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method importAccountError*(self: AccessInterface, error: string) {.base.} =
raise newException(ValueError, "No implementation available")
method importAccountSuccess*(self: AccessInterface) {.base.} = method importAccountSuccess*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")

View File

@ -262,15 +262,12 @@ method getPin*[T](self: Module[T]): string =
method getPasswordStrengthScore*[T](self: Module[T], password, userName: string): int = method getPasswordStrengthScore*[T](self: Module[T], password, userName: string): int =
return self.controller.getPasswordStrengthScore(password, userName) return self.controller.getPasswordStrengthScore(password, userName)
method setupAccountError*[T](self: Module[T], error: string) = method emitStartupError*[T](self: Module[T], error: string, errType: StartupErrorType) =
self.view.setupAccountError(error) self.view.emitStartupError(error, errType)
method validMnemonic*[T](self: Module[T], mnemonic: string): bool = method validMnemonic*[T](self: Module[T], mnemonic: string): bool =
return self.controller.validMnemonic(mnemonic) return self.controller.validMnemonic(mnemonic)
method importAccountError*[T](self: Module[T], error: string) =
self.view.importAccountError(error)
method importAccountSuccess*[T](self: Module[T]) = method importAccountSuccess*[T](self: Module[T]) =
self.view.importAccountSuccess() self.view.importAccountSuccess()
@ -358,8 +355,15 @@ method startAppAfterDelay*[T](self: Module[T]) =
self.view.setCurrentStartupState(newProfileFetchingState(currStateObj.flowType(), nil)) self.view.setCurrentStartupState(newProfileFetchingState(currStateObj.flowType(), nil))
self.moveToStartupState() self.moveToStartupState()
proc logoutAndDisplayError[T](self: Module[T], error: string) = proc logoutAndDisplayError[T](self: Module[T], error: string, errType: StartupErrorType) =
self.delegate.logout() self.delegate.logout()
if self.controller.isSelectedLoginAccountKeycardAccount() and
errType == StartupErrorType.ConvertToRegularAccError:
self.view.setCurrentStartupState(newLoginState(FlowType.AppLogin, nil))
self.controller.runLoginFlow()
self.moveToStartupState()
self.emitStartupError(error, errType)
return
self.moveToStartupState() self.moveToStartupState()
self.emitAccountLoginError(error) self.emitAccountLoginError(error)
@ -377,12 +381,20 @@ method onNodeLogin*[T](self: Module[T], error: string) =
self.delayStartingApp() self.delayStartingApp()
let err = self.delegate.userLoggedIn() let err = self.delegate.userLoggedIn()
if err.len > 0: if err.len > 0:
self.logoutAndDisplayError(err) self.logoutAndDisplayError(err, StartupErrorType.UnknownType)
return return
elif currStateObj.flowType() == FlowType.LostKeycardConvertToRegularAccount:
let err = self.controller.convertToRegularAccount()
if err.len > 0:
self.logoutAndDisplayError(err, StartupErrorType.ConvertToRegularAccError)
return
self.delegate.logout()
self.view.setCurrentStartupState(newLoginKeycardConvertedToRegularAccountState(currStateObj.flowType(), nil))
self.moveToStartupState()
else: else:
let err = self.delegate.userLoggedIn() let err = self.delegate.userLoggedIn()
if err.len > 0: if err.len > 0:
self.logoutAndDisplayError(err) self.logoutAndDisplayError(err, StartupErrorType.UnknownType)
return return
self.delegate.finishAppLoading() self.delegate.finishAppLoading()
if currStateObj.flowType() != FlowType.AppLogin: if currStateObj.flowType() != FlowType.AppLogin:
@ -393,7 +405,7 @@ method onNodeLogin*[T](self: Module[T], error: string) =
if currStateObj.flowType() == FlowType.AppLogin: if currStateObj.flowType() == FlowType.AppLogin:
self.emitAccountLoginError(error) self.emitAccountLoginError(error)
else: else:
self.setupAccountError(error) self.emitStartupError(error, StartupErrorType.SetupAccError)
error "login error", methodName="onNodeLogin", errDesription =error error "login error", methodName="onNodeLogin", errDesription =error
method onKeycardResponse*[T](self: Module[T], keycardFlowType: string, keycardEvent: KeycardEvent) = method onKeycardResponse*[T](self: Module[T], keycardFlowType: string, keycardEvent: KeycardEvent) =

View File

@ -192,18 +192,13 @@ QtObject:
proc getPasswordStrengthScore*(self: View, password: string, userName: string): int {.slot.} = proc getPasswordStrengthScore*(self: View, password: string, userName: string): int {.slot.} =
return self.delegate.getPasswordStrengthScore(password, userName) return self.delegate.getPasswordStrengthScore(password, userName)
proc accountSetupError*(self: View, error: string) {.signal.} proc startupError*(self: View, error: string, errType: int) {.signal.}
proc setupAccountError*(self: View, error: string) = proc emitStartupError*(self: View, error: string, errType: StartupErrorType) =
self.accountSetupError(error) self.startupError(error, errType.int)
proc validMnemonic*(self: View, mnemonic: string): bool {.slot.} = proc validMnemonic*(self: View, mnemonic: string): bool {.slot.} =
return self.delegate.validMnemonic(mnemonic) return self.delegate.validMnemonic(mnemonic)
proc accountImportError*(self: View, error: string) {.signal.}
proc importAccountError*(self: View, error: string) =
# In QML we can connect to this signal and notify user, before refactoring we didn't have this signal
self.accountImportError(error)
proc accountImportSuccess*(self: View) {.signal.} proc accountImportSuccess*(self: View) {.signal.}
proc importAccountSuccess*(self: View) = proc importAccountSuccess*(self: View) =
self.importedAccountChanged() self.importedAccountChanged()

View File

@ -8,12 +8,11 @@ type
settingsJson: JsonNode settingsJson: JsonNode
hashedCurrentPassword: string hashedCurrentPassword: string
newPassword: string newPassword: string
keyStoreDir: string
const convertToKeycardAccountTask*: Task = proc(argEncoded: string) {.gcsafe, nimcall.} = const convertToKeycardAccountTask*: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
let arg = decode[ConvertToKeycardAccountTaskArg](argEncoded) let arg = decode[ConvertToKeycardAccountTaskArg](argEncoded)
try: try:
let response = status_account.convertToKeycardAccount(arg.keyStoreDir, arg.accountDataJson, arg.settingsJson, let response = status_account.convertToKeycardAccount(arg.accountDataJson, arg.settingsJson,
arg.hashedCurrentPassword, arg.newPassword) arg.hashedCurrentPassword, arg.newPassword)
arg.finish(response) arg.finish(response)
except Exception as e: except Exception as e:

View File

@ -462,7 +462,7 @@ QtObject:
"public-key": whisperPublicKey, "public-key": whisperPublicKey,
"name": alias, "name": alias,
"display-name": displayName, "display-name": displayName,
"address": whisperAddress, "address": address,
"eip1581-address": eip1581Address, "eip1581-address": eip1581Address,
"dapps-address": walletAddress, "dapps-address": walletAddress,
"wallet-root-address": walletRootAddress, "wallet-root-address": walletRootAddress,
@ -631,21 +631,15 @@ QtObject:
error "error: ", procName="login", errName = e.name, errDesription = e.msg error "error: ", procName="login", errName = e.name, errDesription = e.msg
return e.msg return e.msg
proc loginAccountKeycard*(self: Service, keycardData: KeycardEvent): string = proc loginAccountKeycard*(self: Service, accToBeLoggedIn: AccountDto, keycardData: KeycardEvent): string =
try: try:
self.setKeyStoreDir(keycardData.keyUid) self.setKeyStoreDir(keycardData.keyUid)
let openedAccounts = self.openedAccounts()
var accToBeLoggedIn: AccountDto
for acc in openedAccounts:
if acc.keyUid == keycardData.keyUid:
accToBeLoggedIn = acc
break
var accountDataJson = %* { var accountDataJson = %* {
"name": accToBeLoggedIn.name, "name": accToBeLoggedIn.name,
"address": keycardData.masterKey.address, "address": keycardData.masterKey.address,
"key-uid": keycardData.keyUid "key-uid": keycardData.keyUid,
"kdfIterations": KDF_ITERATIONS,
} }
var settingsJson: JsonNode var settingsJson: JsonNode
self.addKeycardDetails(settingsJson, accountDataJson) self.addKeycardDetails(settingsJson, accountDataJson)
@ -681,14 +675,12 @@ QtObject:
error "error: ", procName="verifyAccountPassword", errName = e.name, errDesription = e.msg error "error: ", procName="verifyAccountPassword", errName = e.name, errDesription = e.msg
proc convertToKeycardAccount*(self: Service, keyUid: string, currentPassword: string, newPassword: string) = proc convertToKeycardAccount*(self: Service, currentPassword: string, newPassword: string) =
var accountDataJson = %* { var accountDataJson = %* {
"name": self.getLoggedInAccount().name, "key-uid": self.getLoggedInAccount().keyUid,
"key-uid": keyUid "kdfIterations": KDF_ITERATIONS
}
var settingsJson = %* {
"display-name": self.getLoggedInAccount().name
} }
var settingsJson = %* { }
self.addKeycardDetails(settingsJson, accountDataJson) self.addKeycardDetails(settingsJson, accountDataJson)
@ -704,7 +696,6 @@ QtObject:
slot: "onConvertToKeycardAccount", slot: "onConvertToKeycardAccount",
accountDataJson: accountDataJson, accountDataJson: accountDataJson,
settingsJson: settingsJson, settingsJson: settingsJson,
keyStoreDir: self.keyStoreDir,
hashedCurrentPassword: hashedCurrentPassword, hashedCurrentPassword: hashedCurrentPassword,
newPassword: newPassword newPassword: newPassword
) )
@ -726,6 +717,20 @@ QtObject:
error "error handilng migrated keypair response", errDesription=e.msg error "error handilng migrated keypair response", errDesription=e.msg
self.events.emit(SIGNAL_CONVERTING_PROFILE_KEYPAIR, ResultArgs(success: result)) self.events.emit(SIGNAL_CONVERTING_PROFILE_KEYPAIR, ResultArgs(success: result))
proc convertToRegularAccount*(self: Service, mnemonic: string, currentPassword: string, newPassword: string): string =
let hashedPassword = hashString(newPassword)
try:
let response = status_account.convertToRegularAccount(mnemonic, currentPassword, hashedPassword)
var errMsg = ""
if(response.result.contains("error")):
errMsg = response.result["error"].getStr
if errMsg.len > 0:
error "error: ", procName="convertToRegularAccount", errDesription = errMsg
return errMsg
except Exception as e:
error "error converting to regular account: ", message = e.msg
return e.msg
proc verifyPassword*(self: Service, password: string): bool = proc verifyPassword*(self: Service, password: string): bool =
try: try:
let hashedPassword = hashString(password) let hashedPassword = hashString(password)

View File

@ -243,16 +243,25 @@ proc saveAccountAndLoginWithKeycard*(chatKey, password: string, account, subacco
error "error doing rpc request", methodName = "saveAccountAndLogin", exception=e.msg error "error doing rpc request", methodName = "saveAccountAndLogin", exception=e.msg
raise newException(RpcException, e.msg) raise newException(RpcException, e.msg)
proc convertToKeycardAccount*(keyStoreDir: string, account: JsonNode, settings: JsonNode, password: string, newPassword: string): proc convertToKeycardAccount*(account: JsonNode, settings: JsonNode, password: string, newPassword: string):
RpcResponse[JsonNode] {.raises: [Exception].} = RpcResponse[JsonNode] {.raises: [Exception].} =
try: try:
let response = status_go.convertToKeycardAccount(keyStoreDir, $account, $settings, password, newPassword) let response = status_go.convertToKeycardAccount($account, $settings, password, newPassword)
result.result = Json.decode(response, JsonNode) result.result = Json.decode(response, JsonNode)
except RpcException as e: except RpcException as e:
error "error doing rpc request", methodName = "convertToKeycardAccount", exception=e.msg error "error doing rpc request", methodName = "convertToKeycardAccount", exception=e.msg
raise newException(RpcException, e.msg) raise newException(RpcException, e.msg)
proc convertToRegularAccount*(mnemonic: string, currPassword: string, newPassword: string):
RpcResponse[JsonNode] {.raises: [Exception].} =
try:
let response = status_go.convertToRegularAccount(mnemonic, currPassword, newPassword)
result.result = Json.decode(response, JsonNode)
except RpcException as e:
error "error doing rpc request", methodName = "convertToRegularAccount", exception=e.msg
raise newException(RpcException, e.msg)
proc login*(name, keyUid: string, kdfIterations: int, hashedPassword, thumbnail, large: string, nodeCfgObj: string): proc login*(name, keyUid: string, kdfIterations: int, hashedPassword, thumbnail, large: string, nodeCfgObj: string):
RpcResponse[JsonNode] RpcResponse[JsonNode]
{.raises: [Exception].} = {.raises: [Exception].} =

View File

@ -2,6 +2,10 @@ import QtQuick 2.14
import QtQuick.Controls 2.14 import QtQuick.Controls 2.14
import QtQuick.Dialogs 1.3 import QtQuick.Dialogs 1.3
import StatusQ.Core 0.1
import StatusQ.Popups.Dialog 0.1
import StatusQ.Core.Theme 0.1
import utils 1.0 import utils 1.0
import shared.popups.keycard 1.0 import shared.popups.keycard 1.0
@ -77,6 +81,7 @@ OnboardingBasePage {
case Constants.startupState.loginKeycardMaxPairingSlotsReached: case Constants.startupState.loginKeycardMaxPairingSlotsReached:
case Constants.startupState.loginKeycardEmpty: case Constants.startupState.loginKeycardEmpty:
case Constants.startupState.loginNotKeycard: case Constants.startupState.loginNotKeycard:
case Constants.startupState.loginKeycardConvertedToRegularAccount:
return loginViewComponent return loginViewComponent
case Constants.startupState.keycardPluginReader: case Constants.startupState.keycardPluginReader:
@ -108,6 +113,7 @@ OnboardingBasePage {
case Constants.startupState.keycardMaxPairingSlotsReached: case Constants.startupState.keycardMaxPairingSlotsReached:
case Constants.startupState.keycardMaxPinRetriesReached: case Constants.startupState.keycardMaxPinRetriesReached:
case Constants.startupState.keycardMaxPukRetriesReached: case Constants.startupState.keycardMaxPukRetriesReached:
case Constants.startupState.userProfileWrongSeedPhrase:
return keycardStateViewComponent return keycardStateViewComponent
case Constants.startupState.keycardEnterPuk: case Constants.startupState.keycardEnterPuk:
@ -132,18 +138,19 @@ OnboardingBasePage {
Connections { Connections {
target: root.startupStore.startupModuleInst target: root.startupStore.startupModuleInst
onAccountSetupError: { onStartupError: {
msgDialog.errType = errType
if (errType === Constants.startupErrorType.setupAccError) {
if (error === Constants.existingAccountError) { if (error === Constants.existingAccountError) {
msgDialog.title = qsTr("Keys for this account already exist") msgDialog.title = qsTr("Keys for this account already exist")
msgDialog.text = qsTr("Keys for this account already exist and can't be added again. If you've lost your password, passcode or Keycard, uninstall the app, reinstall and access your keys by entering your seed phrase") msgDialog.text = qsTr("Keys for this account already exist and can't be added again. If you've lost\
your password, passcode or Keycard, uninstall the app, reinstall and access your keys by entering your seed phrase.")
} else { } else {
msgDialog.title = qsTr("Login failed") msgDialog.title = qsTr("Login failed")
msgDialog.text = qsTr("Login failed. Please re-enter your password and try again.") msgDialog.text = qsTr("Login failed. Please re-enter your password and try again.")
} }
msgDialog.open()
} }
else if (errType === Constants.startupErrorType.importAccError) {
onAccountImportError: {
if (error === Constants.existingAccountError) { if (error === Constants.existingAccountError) {
msgDialog.title = qsTr("Keys for this account already exist") msgDialog.title = qsTr("Keys for this account already exist")
msgDialog.text = qsTr("Keys for this account already exist and can't be added again. If you've lost\ msgDialog.text = qsTr("Keys for this account already exist and can't be added again. If you've lost\
@ -153,8 +160,18 @@ case of Keycard try recovering using PUK or reinstall the app and try login with
msgDialog.title = qsTr("Error importing seed") msgDialog.title = qsTr("Error importing seed")
msgDialog.text = error msgDialog.text = error
} }
}
else if (errType === Constants.startupErrorType.convertToRegularAccError) {
msgDialog.title = qsTr("Converting account")
msgDialog.text = qsTr("Really sorry about this inconvenience.\n\
Most likely that your account is damaged while converting to a regular Status account.\n\
First try to login after app restart, if that doesn't work, you can alway recover your accout\n\
following the \"Add existing Status user\" flow, using your seed phrase.")
}
msgDialog.open() msgDialog.open()
} }
onDisplayKeycardSharedModuleFlow: { onDisplayKeycardSharedModuleFlow: {
keycardPopup.active = true keycardPopup.active = true
} }
@ -163,13 +180,26 @@ case of Keycard try recovering using PUK or reinstall the app and try login with
} }
} }
MessageDialog { StatusDialog {
id: msgDialog id: msgDialog
title: qsTr("Login failed") title: qsTr("Login failed")
text: qsTr("Login failed. Please re-enter your password and try again.")
icon: StandardIcon.Critical property int errType: Constants.startupErrorType.unknownType
standardButtons: StandardButton.Ok property string text: qsTr("Login failed. Please re-enter your password and try again.")
StatusBaseText {
anchors.fill: parent
font.pixelSize: 15
color: Theme.palette.directColor1
text: msgDialog.text
wrapMode: Text.WordWrap
}
standardButtons: Dialog.Ok
onAccepted: { onAccepted: {
if (msgDialog.errType == Constants.startupErrorType.convertToRegularAccError) {
Qt.quit();
}
console.log("TODO: restart flow...") console.log("TODO: restart flow...")
} }
} }

View File

@ -365,6 +365,44 @@ Item {
color: Theme.palette.baseColor1 color: Theme.palette.baseColor1
font.pixelSize: Constants.keycard.general.fontSize3 font.pixelSize: Constants.keycard.general.fontSize3
} }
},
State {
name: Constants.startupState.userProfileWrongSeedPhrase
when: root.startupStore.currentStartupState.stateType === Constants.startupState.userProfileWrongSeedPhrase
PropertyChanges {
target: image
pattern: Constants.keycardAnimations.strongError.pattern
source: ""
startImgIndexForTheFirstLoop: Constants.keycardAnimations.strongError.startImgIndexForTheFirstLoop
startImgIndexForOtherLoops: Constants.keycardAnimations.strongError.startImgIndexForOtherLoops
endImgIndex: Constants.keycardAnimations.strongError.endImgIndex
duration: Constants.keycardAnimations.strongError.duration
loops: Constants.keycardAnimations.strongError.loops
}
PropertyChanges {
target: title
text: qsTr("Seed phrase doesnt match any user")
color: Theme.palette.directColor1
font.pixelSize: Constants.keycard.general.fontSize1
}
PropertyChanges {
target: info
text: qsTr("The seed phrase you enter needs to match the seed phrase of an existing user on this device")
color: Theme.palette.directColor1
font.pixelSize: Constants.keycard.general.fontSize2
}
PropertyChanges {
target: button
text: qsTr("Try entering seed phrase again")
}
PropertyChanges {
target: link
text: ""
}
PropertyChanges {
target: message
text: ""
}
} }
] ]
} }

View File

@ -1265,6 +1265,56 @@ Item {
text: "" text: ""
visible: false visible: false
} }
},
State {
name: Constants.startupState.loginKeycardConvertedToRegularAccount
when: root.startupStore.currentStartupState.stateType === Constants.startupState.loginKeycardConvertedToRegularAccount
PropertyChanges {
target: image
pattern: Constants.keycardAnimations.strongSuccess.pattern
source: ""
startImgIndexForTheFirstLoop: Constants.keycardAnimations.strongSuccess.startImgIndexForTheFirstLoop
startImgIndexForOtherLoops: Constants.keycardAnimations.strongSuccess.startImgIndexForOtherLoops
endImgIndex: Constants.keycardAnimations.strongSuccess.endImgIndex
duration: Constants.keycardAnimations.strongSuccess.duration
loops: Constants.keycardAnimations.strongSuccess.loops
}
PropertyChanges {
target: userInfo
visible: false
}
PropertyChanges {
target: title
text: qsTr("Your account has been successfully converted to a non Keycard account")
visible: true
}
PropertyChanges {
target: passwordSection
visible: false
}
PropertyChanges {
target: pinSection
visible: false
}
PropertyChanges {
target: info
visible: false
}
PropertyChanges {
target: message
text: qsTr("To complete the process close Status and log in with your password")
visible: true
}
PropertyChanges {
target: button
text: qsTr("Restart app & sign in using your password")
visible: true
}
PropertyChanges {
target: link
text: ""
visible: false
}
} }
] ]
} }

View File

@ -316,7 +316,8 @@ Item {
return qsTr("Recover Keycard") return qsTr("Recover Keycard")
} }
else if (root.startupStore.currentStartupState.flowType === Constants.startupFlow.firstRunNewUserImportSeedPhraseIntoKeycard || else if (root.startupStore.currentStartupState.flowType === Constants.startupFlow.firstRunNewUserImportSeedPhraseIntoKeycard ||
root.startupStore.currentStartupState.flowType === Constants.startupFlow.lostKeycardReplacement) { root.startupStore.currentStartupState.flowType === Constants.startupFlow.lostKeycardReplacement ||
root.startupStore.currentStartupState.flowType === Constants.startupFlow.lostKeycardConvertToRegularAccount) {
return qsTr("Next") return qsTr("Next")
} }
return "" return ""

View File

@ -6,6 +6,7 @@ import QtQml.Models 2.14
import StatusQ.Core 0.1 import StatusQ.Core 0.1
import StatusQ.Controls 0.1 import StatusQ.Controls 0.1
import StatusQ.Popups.Dialog 0.1 import StatusQ.Popups.Dialog 0.1
import StatusQ.Core.Theme 0.1
import utils 1.0 import utils 1.0
import shared.popups.keycard 1.0 import shared.popups.keycard 1.0

View File

@ -24,6 +24,7 @@ QtObject {
readonly property string firstRunOldUserImportSeedPhrase: "FirstRunOldUserImportSeedPhrase" readonly property string firstRunOldUserImportSeedPhrase: "FirstRunOldUserImportSeedPhrase"
readonly property string appLogin: "AppLogin" readonly property string appLogin: "AppLogin"
readonly property string lostKeycardReplacement: "LostKeycardReplacement" readonly property string lostKeycardReplacement: "LostKeycardReplacement"
readonly property string lostKeycardConvertToRegularAccount: "LostKeycardConvertToRegularAccount"
} }
readonly property QtObject startupState: QtObject { readonly property QtObject startupState: QtObject {
@ -40,6 +41,7 @@ QtObject {
readonly property string userProfileConfirmPassword: "UserProfileConfirmPassword" readonly property string userProfileConfirmPassword: "UserProfileConfirmPassword"
readonly property string userProfileImportSeedPhrase: "UserProfileImportSeedPhrase" readonly property string userProfileImportSeedPhrase: "UserProfileImportSeedPhrase"
readonly property string userProfileEnterSeedPhrase: "UserProfileEnterSeedPhrase" readonly property string userProfileEnterSeedPhrase: "UserProfileEnterSeedPhrase"
readonly property string userProfileWrongSeedPhrase: "UserProfileWrongSeedPhrase"
readonly property string biometrics: "Biometrics" readonly property string biometrics: "Biometrics"
readonly property string keycardPluginReader: "KeycardPluginReader" readonly property string keycardPluginReader: "KeycardPluginReader"
readonly property string keycardInsertKeycard: "KeycardInsertKeycard" readonly property string keycardInsertKeycard: "KeycardInsertKeycard"
@ -80,6 +82,7 @@ QtObject {
readonly property string loginKeycardMaxPairingSlotsReached: "LoginKeycardMaxPairingSlotsReached" readonly property string loginKeycardMaxPairingSlotsReached: "LoginKeycardMaxPairingSlotsReached"
readonly property string loginKeycardEmpty: "LoginKeycardEmpty" readonly property string loginKeycardEmpty: "LoginKeycardEmpty"
readonly property string loginNotKeycard: "LoginNotKeycard" readonly property string loginNotKeycard: "LoginNotKeycard"
readonly property string loginKeycardConvertedToRegularAccount: "LoginKeycardConvertedToRegularAccount"
readonly property string profileFetching: "ProfileFetching" readonly property string profileFetching: "ProfileFetching"
readonly property string profileFetchingSuccess: "ProfileFetchingSuccess" readonly property string profileFetchingSuccess: "ProfileFetchingSuccess"
readonly property string profileFetchingTimeout: "ProfileFetchingTimeout" readonly property string profileFetchingTimeout: "ProfileFetchingTimeout"
@ -731,6 +734,13 @@ QtObject {
readonly property bool isCppApp: typeof cppApp !== "undefined" ? cppApp : false readonly property bool isCppApp: typeof cppApp !== "undefined" ? cppApp : false
readonly property QtObject startupErrorType: QtObject {
readonly property int unknownType: 0
readonly property int importAccError: 1
readonly property int setupAccError: 2
readonly property int convertToRegularAccError: 3
}
readonly property string existingAccountError: "account already exists" readonly property string existingAccountError: "account already exists"
readonly property string wrongDerivationPathError: "error parsing derivation path" readonly property string wrongDerivationPathError: "error parsing derivation path"

@ -1 +1 @@
Subproject commit 1d8c32e8557a55c86c35e5d6eaccb321995851a3 Subproject commit 8fed87fe272c4b49008cd7cc5950a96cd0751966