diff --git a/src/app/boot/app_controller.nim b/src/app/boot/app_controller.nim index 1ce4289008..2aea6e8c96 100644 --- a/src/app/boot/app_controller.nim +++ b/src/app/boot/app_controller.nim @@ -50,7 +50,6 @@ logScope: type AppController* = ref object of RootObj - storeDefaultKeyPair: bool syncKeycardBasedOnAppWalletState: bool applyKeycardReplacement: bool changedKeycardUids: seq[tuple[oldKcUid: string, newKcUid: string]] # used in case user unlocked keycard during onboarding using seed phrase @@ -120,7 +119,6 @@ proc userLoggedIn*(self: AppController): string proc appReady*(self: AppController) proc logout*(self: AppController) proc finishAppLoading*(self: AppController) -proc storeDefaultKeyPairForNewKeycardUser*(self: AppController) proc syncKeycardBasedOnAppWalletStateAfterLogin*(self: AppController) proc applyKeycardReplacementAfterLogin*(self: AppController) proc addToKeycardUidPairsToCheckForAChangeAfterLogin*(self: AppController, oldKeycardUid: string, newKeycardUid: string) @@ -146,7 +144,6 @@ proc connect(self: AppController) = proc newAppController*(statusFoundation: StatusFoundation): AppController = result = AppController() - result.storeDefaultKeyPair = false result.syncKeycardBasedOnAppWalletState = false result.applyKeycardReplacement = false result.statusFoundation = statusFoundation @@ -593,9 +590,6 @@ proc applyNecessaryActionsAfterLoggingIn(self: AppController) = discard self.walletAccountService.updateKeycardUid(oldUid, newUid) discard self.walletAccountService.setKeycardUnlocked(singletonInstance.userProfile.getKeyUid(), newUid) -proc storeDefaultKeyPairForNewKeycardUser*(self: AppController) = - self.storeDefaultKeyPair = true - proc syncKeycardBasedOnAppWalletStateAfterLogin*(self: AppController) = self.syncKeycardBasedOnAppWalletState = true diff --git a/src/app/global/utils.nim b/src/app/global/utils.nim index d80400358a..7b281145c1 100644 --- a/src/app/global/utils.nim +++ b/src/app/global/utils.nim @@ -75,9 +75,6 @@ QtObject: return "0" return $stint.fromHex(StUint[256], value) - proc generateAlias*(self: Utils, pk: string): string {.slot.} = - return generateAliasFromPk(pk) - proc readTextFile*(self: Utils, filepath: string): string {.slot.} = try: return readFile(filepath) diff --git a/src/app/modules/shared_modules/keycard_popup/internal/repeat_pin_state.nim b/src/app/modules/shared_modules/keycard_popup/internal/repeat_pin_state.nim index 505f1730d2..67a4ab5833 100644 --- a/src/app/modules/shared_modules/keycard_popup/internal/repeat_pin_state.nim +++ b/src/app/modules/shared_modules/keycard_popup/internal/repeat_pin_state.nim @@ -80,4 +80,4 @@ method resolveKeycardNextState*(self: RepeatPinState, keycardFlowType: string, k return createState(StateType.MaxPukRetriesReached, self.flowType, nil) if keycardFlowType == ResponseTypeValueKeycardFlowResult: controller.setPukValid(true) - return createState(StateType.PinSet, self.flowType, nil) \ No newline at end of file + return createState(StateType.PinSet, self.flowType, nil) diff --git a/src/app/modules/startup/controller.nim b/src/app/modules/startup/controller.nim index d6f1332834..c9b4a71ba1 100644 --- a/src/app/modules/startup/controller.nim +++ b/src/app/modules/startup/controller.nim @@ -22,7 +22,7 @@ logScope: type ProfileImageDetails = object url*: string - croppedImage*: string # TODO: Remove after https://github.com/status-im/status-go/issues/4977 + croppedImage*: string cropRectangle*: ImageCropRectangle type @@ -189,7 +189,9 @@ proc init*(self: Controller) = proc shouldStartWithOnboardingScreen*(self: Controller): bool = return self.accountsService.openedAccounts().len == 0 -# This is used when fetching backup failed and we create a new displayName and profileImage. +# This is used in 2 flows, in case fetching backup failed and we create a new displayName and profileImage: +# 1. FirstRunOldUserImportSeedPhrase +# 2. FirstRunOldUserKeycardImport # At this point the account is already created in the database. All that's left is to set the displayName and profileImage. proc storeProfileDataAndProceedWithAppLoading*(self: Controller) = self.delegate.removeAllKeycardUidPairsForCheckingForAChangeAfterLogin() # reason for this is in the table in AppController.nim file @@ -201,12 +203,6 @@ proc storeProfileDataAndProceedWithAppLoading*(self: Controller) = proc checkFetchingStatusAndProceed*(self: Controller) = self.delegate.checkFetchingStatusAndProceed() -proc getGeneratedAccounts*(self: Controller): seq[GeneratedAccountDto] = - return self.accountsService.generatedAccounts() - -proc getImportedAccount*(self: Controller): GeneratedAccountDto = - return self.accountsService.getImportedAccount() - proc getPasswordStrengthScore*(self: Controller, password, userName: string): int = return self.generalService.getPasswordStrengthScore(password, userName) @@ -348,7 +344,6 @@ proc tryToObtainDataFromKeychain*(self: Controller) = let selectedAccount = self.getSelectedLoginAccount() self.keychainService.tryToObtainData(selectedAccount.keyUid) -# TODO: Remove when implemented https://github.com/status-im/status-go/issues/4977 proc storeIdentityImage*(self: Controller): seq[Image] = if self.tmpProfileImageDetails.url.len == 0: return @@ -375,6 +370,7 @@ proc validMnemonic*(self: Controller, mnemonic: string): bool = # validateMnemonicForImport checks if mnemonic is valid and not yet saved in local database proc validateMnemonicForImport*(self: Controller, mnemonic: string): bool = + let (keyUID, err) = self.accountsService.validateMnemonic(mnemonic) if err.len != 0: self.delegate.emitStartupError(err, StartupErrorType.ImportAccError) @@ -387,16 +383,6 @@ proc validateMnemonicForImport*(self: Controller, mnemonic: string): bool = self.setSeedPhrase(mnemonic) return true -# TODO: Remove after https://github.com/status-im/status-go/issues/4977 -proc importMnemonic*(self: Controller): bool = - let error = self.accountsService.importMnemonic(self.tmpSeedPhrase) - if(error.len == 0): - self.delegate.importAccountSuccess() - return true - else: - self.delegate.emitStartupError(error, StartupErrorType.ImportAccError) - return false - proc setupKeychain(self: Controller, store: bool) = if store: singletonInstance.localAccountSettings.setStoreToKeychainValue(LS_VALUE_NOT_NOW) @@ -425,6 +411,7 @@ proc importAccountAndLogin*(self: Controller, storeToKeychain: bool, recoverAcco self.connectToFetchingFromWakuEvents() else: self.delegate.moveToLoadingAppState() + let error = self.accountsService.importAccountAndLogin( self.tmpSeedPhrase, self.tmpPassword, @@ -433,56 +420,48 @@ proc importAccountAndLogin*(self: Controller, storeToKeychain: bool, recoverAcco self.tmpProfileImageDetails.url, self.tmpProfileImageDetails.cropRectangle, ) + self.processCreateAccountResult(error, storeToKeychain) -proc storeKeycardAccountAndLogin*(self: Controller, storeToKeychain: bool, newKeycard: bool) = - if self.importMnemonic(): - self.delegate.moveToLoadingAppState() - if newKeycard: - self.delegate.storeDefaultKeyPairForNewKeycardUser() - self.storeMetadataForNewKeycardUser() - else: - self.syncKeycardBasedOnAppWalletStateAfterLogin() - let (_, flowEvent) = self.keycardService.getLastReceivedKeycardData() # we need this to get the correct instanceUID - self.accountsService.setupAccountKeycard(flowEvent, self.tmpDisplayName, useImportedAcc = true) - self.setupKeychain(storeToKeychain) - else: - error "an error ocurred while importing mnemonic" +# NOTE: Called during FirstRunNewUserNewKeycardKeys and FirstRunNewUserImportSeedPhraseIntoKeycard +# WARNING: Reuse `importAccountAndLogin` with custom parameters +proc storeKeycardAccountAndLogin*(self: Controller, storeToKeychain: bool, newKeycard: bool = true) = + self.delegate.moveToLoadingAppState() + self.storeMetadataForNewKeycardUser() + let (_, flowEvent) = self.keycardService.getLastReceivedKeycardData() + let error = self.accountsService.importAccountAndLogin( + self.tmpSeedPhrase, + password = "", # For keycard it will be substituted with`encryption.publicKey` in status-go + false, + self.tmpDisplayName, + self.tmpProfileImageDetails.url, + self.tmpProfileImageDetails.cropRectangle, + keycardInstanceUID = flowEvent.instanceUID, + ) + self.processCreateAccountResult(error, storeToKeychain) +# NOTE: Called during FirstRunOldUserKeycardImport proc setupKeycardAccount*(self: Controller, storeToKeychain: bool, recoverAccount: bool = false) = if self.tmpKeycardEvent.keyUid.len == 0 or self.accountsService.openedAccountsContainsKeyUid(self.tmpKeycardEvent.keyUid): self.delegate.emitStartupError(ACCOUNT_ALREADY_EXISTS_ERROR, StartupErrorType.ImportAccError) return + if recoverAccount: self.delegate.prepareAndInitFetchingData() self.connectToFetchingFromWakuEvents() - if self.tmpSeedPhrase.len > 0: - # if `tmpSeedPhrase` is not empty means user has recovered keycard via seed phrase - let accFromSeedPhrase = self.accountsService.createAccountFromMnemonic(self.tmpSeedPhrase, includeEncryption = true, - includeWhisper = true, includeRoot = true, includeDefaultWallet = true, includeEip1581 = true) - self.tmpKeycardEvent.masterKey.privateKey = accFromSeedPhrase.privateKey - self.tmpKeycardEvent.masterKey.publicKey = accFromSeedPhrase.publicKey - self.tmpKeycardEvent.masterKey.address = accFromSeedPhrase.address - self.tmpKeycardEvent.whisperKey.privateKey = accFromSeedPhrase.derivedAccounts.whisper.privateKey - self.tmpKeycardEvent.whisperKey.publicKey = accFromSeedPhrase.derivedAccounts.whisper.publicKey - self.tmpKeycardEvent.whisperKey.address = accFromSeedPhrase.derivedAccounts.whisper.address - self.tmpKeycardEvent.walletKey.privateKey = accFromSeedPhrase.derivedAccounts.defaultWallet.privateKey - self.tmpKeycardEvent.walletKey.publicKey = accFromSeedPhrase.derivedAccounts.defaultWallet.publicKey - self.tmpKeycardEvent.walletKey.address = accFromSeedPhrase.derivedAccounts.defaultWallet.address - self.tmpKeycardEvent.walletRootKey.privateKey = accFromSeedPhrase.derivedAccounts.walletRoot.privateKey - self.tmpKeycardEvent.walletRootKey.publicKey = accFromSeedPhrase.derivedAccounts.walletRoot.publicKey - self.tmpKeycardEvent.walletRootKey.address = accFromSeedPhrase.derivedAccounts.walletRoot.address - self.tmpKeycardEvent.eip1581Key.privateKey = accFromSeedPhrase.derivedAccounts.eip1581.privateKey - self.tmpKeycardEvent.eip1581Key.publicKey = accFromSeedPhrase.derivedAccounts.eip1581.publicKey - self.tmpKeycardEvent.eip1581Key.address = accFromSeedPhrase.derivedAccounts.eip1581.address - self.tmpKeycardEvent.encryptionKey.privateKey = accFromSeedPhrase.derivedAccounts.encryption.privateKey - self.tmpKeycardEvent.encryptionKey.publicKey = accFromSeedPhrase.derivedAccounts.encryption.publicKey - self.tmpKeycardEvent.encryptionKey.address = accFromSeedPhrase.derivedAccounts.encryption.address self.syncKeycardBasedOnAppWalletStateAfterLogin() - self.accountsService.setupAccountKeycard(self.tmpKeycardEvent, self.tmpDisplayName, useImportedAcc = false, recoverAccount) - self.setupKeychain(storeToKeychain) + + let error = self.accountsService.restoreKeycardAccountAndLogin( + self.tmpKeycardEvent, + recoverAccount, + self.tmpDisplayName, + self.tmpProfileImageDetails.url, + self.tmpProfileImageDetails.cropRectangle, + ) + + self.processCreateAccountResult(error, storeToKeychain) proc getOpenedAccounts*(self: Controller): seq[AccountDto] = return self.accountsService.openedAccounts() @@ -509,51 +488,41 @@ proc isSelectedAccountAKeycardAccount*(self: Controller): bool = let selectedAccount = self.getSelectedLoginAccount() return selectedAccount.keycardPairing.len > 0 -proc login*(self: Controller) = +proc login*(self: Controller, keycard: bool = false, keycardReplacement: bool = false) = self.delegate.moveToLoadingAppState() - let selectedAccount = self.getSelectedLoginAccount() - self.accountsService.login(selectedAccount, hashPassword(self.tmpPassword)) + + var passwordHash, chatPrivateKey, mnemonic = "" + + if not keycard: + passwordHash = hashPassword(self.tmpPassword) + else: + passwordHash = self.tmpKeycardEvent.encryptionKey.publicKey + chatPrivateKey = self.tmpKeycardEvent.whisperKey.privateKey + mnemonic = self.tmpSeedPhrase + + if keycard and keycardReplacement: + self.delegate.applyKeycardReplacementAfterLogin() + + self.accountsService.login( + self.getSelectedLoginAccount(), + passwordHash, + chatPrivateKey, + mnemonic, + ) proc loginLocalPairingAccount*(self: Controller) = self.delegate.moveToLoadingAppState() - if self.localPairingStatus.chatKey.len == 0: - self.accountsService.login(self.localPairingStatus.account, self.localPairingStatus.password) - else: - var kcEvent = KeycardEvent() - kcEvent.keyUid = self.localPairingStatus.account.keyUid - kcEvent.whisperKey.privateKey = self.localPairingStatus.chatKey - kcEvent.encryptionKey.publicKey = self.localPairingStatus.password - discard self.accountsService.loginAccountKeycard(self.localPairingStatus.account, kcEvent) - -proc loginAccountKeycard*(self: Controller, storeToKeychainValue: string, keycardReplacement = false) = - if keycardReplacement: - self.delegate.applyKeycardReplacementAfterLogin() - 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) + self.accountsService.login( + self.localPairingStatus.account, + self.localPairingStatus.password, + chatPrivateKey = self.localPairingStatus.chatKey ) - if acc.derivedAccounts.whisper.privateKey.startsWith("0x"): - kcData.whisperKey.privateKey = acc.derivedAccounts.whisper.privateKey[2..^1] - self.setupKeychain(storeToKeychain) - - self.delegate.moveToLoadingAppState() - let error = self.accountsService.loginAccountKeycard(selAcc, kcData) - if(error.len > 0): - self.delegate.emitAccountLoginError(error) +# FIXME: Why do we even have storeToKeychain during login? Makes no sense +# https://github.com/status-im/status-desktop/issues/15167 +proc loginAccountKeycard*(self: Controller, storeToKeychain: bool, keycardReplacement = false) = + # singletonInstance.localAccountSettings.setStoreToKeychainValue(storeToKeychainValue) + self.login(keycard = true, keycardReplacement = keycardReplacement) proc convertKeycardProfileKeypairToRegular*(self: Controller) = let acc = self.accountsService.createAccountFromMnemonic(self.getSeedPhrase(), includeEncryption = true) @@ -633,8 +602,8 @@ proc buildSeedPhrasesFromIndexes*(self: Controller, seedPhraseIndexes: seq[int]) proc generateRandomPUK*(self: Controller): string = return self.keycardService.generateRandomPUK() +# Stores metadata, default Status account only, to the keycard for a newly created keycard user. proc storeMetadataForNewKeycardUser(self: Controller) = - ## Stores metadata, default Status account only, to the keycard for a newly created keycard user. let paths = @[account_constants.PATH_DEFAULT_WALLET] self.runStoreMetadataFlow(self.getDisplayName(), self.getPin(), paths) diff --git a/src/app/modules/startup/internal/biometrics_state.nim b/src/app/modules/startup/internal/biometrics_state.nim index 1932623990..d485b68d6d 100644 --- a/src/app/modules/startup/internal/biometrics_state.nim +++ b/src/app/modules/startup/internal/biometrics_state.nim @@ -29,16 +29,16 @@ proc command(self: BiometricsState, controller: Controller, storeToKeychain: boo ## but since current implementation is like that and this is not a bug fixing issue, left as it is. controller.importAccountAndLogin(storeToKeychain, recoverAccount = true) elif self.flowType == FlowType.FirstRunNewUserNewKeycardKeys: - controller.storeKeycardAccountAndLogin(storeToKeychain, newKeycard = true) + controller.storeKeycardAccountAndLogin(storeToKeychain) elif self.flowType == FlowType.FirstRunNewUserImportSeedPhraseIntoKeycard: - controller.storeKeycardAccountAndLogin(storeToKeychain, newKeycard = true) + controller.storeKeycardAccountAndLogin(storeToKeychain) elif self.flowType == FlowType.FirstRunOldUserKeycardImport: controller.setupKeycardAccount(storeToKeychain, recoverAccount = true) elif self.flowType == FlowType.LostKeycardReplacement: self.storeToKeychain = storeToKeychain controller.startLoginFlowAutomatically(controller.getPin()) elif self.flowType == FlowType.LostKeycardConvertToRegularAccount: - controller.loginAccountKeycardUsingSeedPhrase(storeToKeychain) + controller.loginAccountKeycard(storeToKeychain, keycardReplacement = false) method executePrimaryCommand*(self: BiometricsState, controller: Controller) = self.command(controller, true) @@ -49,10 +49,6 @@ method executeSecondaryCommand*(self: BiometricsState, controller: Controller) = method resolveKeycardNextState*(self: BiometricsState, keycardFlowType: string, keycardEvent: KeycardEvent, controller: Controller): State = if self.flowType == FlowType.LostKeycardReplacement: - if keycardFlowType == ResponseTypeValueKeycardFlowResult and - keycardEvent.error.len == 0: + if keycardFlowType == ResponseTypeValueKeycardFlowResult and keycardEvent.error.len == 0: controller.setKeycardEvent(keycardEvent) - var storeToKeychainValue = LS_VALUE_NEVER - if self.storeToKeychain: - storeToKeychainValue = LS_VALUE_NOT_NOW - controller.loginAccountKeycard(storeToKeychainValue, keycardReplacement = true) + controller.loginAccountKeycard(self.storeToKeychain, keycardReplacement = true) diff --git a/src/app/modules/startup/internal/keycard_enter_pin_state.nim b/src/app/modules/startup/internal/keycard_enter_pin_state.nim index f22a5adae2..74df062e79 100644 --- a/src/app/modules/startup/internal/keycard_enter_pin_state.nim +++ b/src/app/modules/startup/internal/keycard_enter_pin_state.nim @@ -32,31 +32,34 @@ method resolveKeycardNextState*(self: KeycardEnterPinState, keycardFlowType: str let state = ensureReaderAndCardPresenceOnboarding(self, keycardFlowType, keycardEvent, controller) if not state.isNil: return state - if self.flowType == FlowType.FirstRunOldUserKeycardImport: - if keycardFlowType == ResponseTypeValueEnterPIN and - keycardEvent.error.len > 0 and - keycardEvent.error == RequestParamPIN: - controller.setRemainingAttempts(keycardEvent.pinRetries) - if keycardEvent.pinRetries > 0: - return createState(StateType.KeycardWrongPin, self.flowType, self.getBackState) + + if self.flowType != FlowType.FirstRunOldUserKeycardImport: + return + + if keycardFlowType == ResponseTypeValueEnterPIN and + keycardEvent.error.len > 0 and + keycardEvent.error == RequestParamPIN: + controller.setRemainingAttempts(keycardEvent.pinRetries) + if keycardEvent.pinRetries > 0: + return createState(StateType.KeycardWrongPin, self.flowType, self.getBackState) + return createState(StateType.KeycardMaxPinRetriesReached, self.flowType, self.getBackState) + if keycardFlowType == ResponseTypeValueEnterPUK and + keycardEvent.error.len == 0: + if keycardEvent.pinRetries == 0 and keycardEvent.pukRetries > 0: return createState(StateType.KeycardMaxPinRetriesReached, self.flowType, self.getBackState) - if keycardFlowType == ResponseTypeValueEnterPUK and - keycardEvent.error.len == 0: - if keycardEvent.pinRetries == 0 and keycardEvent.pukRetries > 0: - return createState(StateType.KeycardMaxPinRetriesReached, self.flowType, self.getBackState) - if keycardFlowType == ResponseTypeValueSwapCard and - keycardEvent.error.len > 0 and - keycardEvent.error == RequestParamPUKRetries: - controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.MaxPUKReached, add = true)) - return createState(StateType.KeycardMaxPukRetriesReached, self.flowType, self.getBackState) - if keycardFlowType == ResponseTypeValueSwapCard and - keycardEvent.error.len > 0 and - keycardEvent.error == RequestParamFreeSlots: - return createState(StateType.KeycardMaxPairingSlotsReached, self.flowType, self.getBackState) - if keycardFlowType == ResponseTypeValueKeycardFlowResult: - controller.setKeycardEvent(keycardEvent) - if not main_constants.IS_MACOS: - controller.setupKeycardAccount(storeToKeychain = false, recoverAccount = true) - return createState(StateType.ProfileFetching, self.flowType, nil) + if keycardFlowType == ResponseTypeValueSwapCard and + keycardEvent.error.len > 0 and + keycardEvent.error == RequestParamPUKRetries: + controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.MaxPUKReached, add = true)) + return createState(StateType.KeycardMaxPukRetriesReached, self.flowType, self.getBackState) + if keycardFlowType == ResponseTypeValueSwapCard and + keycardEvent.error.len > 0 and + keycardEvent.error == RequestParamFreeSlots: + return createState(StateType.KeycardMaxPairingSlotsReached, self.flowType, self.getBackState) + if keycardFlowType == ResponseTypeValueKeycardFlowResult: + controller.setKeycardEvent(keycardEvent) + if main_constants.SUPPORTS_FINGERPRINT: let backState = findBackStateWithTargetedStateType(self, StateType.RecoverOldUser) - return createState(StateType.Biometrics, self.flowType, backState) \ No newline at end of file + return createState(StateType.Biometrics, self.flowType, backState) + controller.setupKeycardAccount(storeToKeychain = false, recoverAccount = true) + return createState(StateType.ProfileFetching, self.flowType, nil) diff --git a/src/app/modules/startup/internal/keycard_enter_puk_state.nim b/src/app/modules/startup/internal/keycard_enter_puk_state.nim index 8eac6e2e1c..c8ea609849 100644 --- a/src/app/modules/startup/internal/keycard_enter_puk_state.nim +++ b/src/app/modules/startup/internal/keycard_enter_puk_state.nim @@ -36,11 +36,11 @@ method resolveKeycardNextState*(self: KeycardEnterPukState, keycardFlowType: str if keycardFlowType == ResponseTypeValueKeycardFlowResult: controller.setKeycardEvent(keycardEvent) controller.setPukValid(true) - if not main_constants.IS_MACOS: - controller.setupKeycardAccount(storeToKeychain = false) - return nil - let backState = findBackStateWithTargetedStateType(self, StateType.RecoverOldUser) - return createState(StateType.Biometrics, self.flowType, backState) + if main_constants.SUPPORTS_FINGERPRINT: + let backState = findBackStateWithTargetedStateType(self, StateType.RecoverOldUser) + return createState(StateType.Biometrics, self.flowType, backState) + controller.setupKeycardAccount(storeToKeychain = false) + return nil if self.flowType == FlowType.AppLogin: if keycardFlowType == ResponseTypeValueEnterNewPIN and keycardEvent.error.len > 0 and @@ -57,5 +57,7 @@ method resolveKeycardNextState*(self: KeycardEnterPukState, keycardFlowType: str controller.setKeycardEvent(keycardEvent) controller.setPukValid(true) let storeToKeychainValue = singletonInstance.localAccountSettings.getStoreToKeychainValue() - controller.loginAccountKeycard(storeToKeychainValue) - return nil \ No newline at end of file + # FIXME: Make sure storeToKeychain is correct here. The idea is not to pass it at all + # https://github.com/status-im/status-desktop/issues/15167 + controller.loginAccountKeycard(storeToKeychain = false) + return nil diff --git a/src/app/modules/startup/internal/keycard_pin_set_state.nim b/src/app/modules/startup/internal/keycard_pin_set_state.nim index cb64854004..972669eac4 100644 --- a/src/app/modules/startup/internal/keycard_pin_set_state.nim +++ b/src/app/modules/startup/internal/keycard_pin_set_state.nim @@ -19,9 +19,9 @@ method getNextPrimaryState*(self: KeycardPinSetState, controller: Controller): S return createState(StateType.UserProfileCreate, self.flowType, self.getBackState) if self.flowType == FlowType.FirstRunOldUserKeycardImport: if controller.getValidPuk(): - if not main_constants.IS_MACOS: - return createState(StateType.ProfileFetching, self.flowType, nil) - return createState(StateType.Biometrics, self.flowType, self.getBackState) + if main_constants.SUPPORTS_FINGERPRINT: + return createState(StateType.Biometrics, self.flowType, self.getBackState) + return createState(StateType.ProfileFetching, self.flowType, nil) return createState(StateType.KeycardWrongPuk, self.flowType, self.getBackState) if self.flowType == FlowType.AppLogin: if controller.getRecoverKeycardUsingSeedPhraseWhileLoggingIn(): @@ -35,7 +35,7 @@ method getNextPrimaryState*(self: KeycardPinSetState, controller: Controller): S method executePrimaryCommand*(self: KeycardPinSetState, controller: Controller) = if self.flowType == FlowType.FirstRunOldUserKeycardImport: - if main_constants.IS_MACOS: + if main_constants.SUPPORTS_FINGERPRINT: return if controller.getValidPuk(): controller.setupKeycardAccount(storeToKeychain = false, recoverAccount = true) @@ -44,24 +44,28 @@ method executePrimaryCommand*(self: KeycardPinSetState, controller: Controller) controller.startLoginFlowAutomatically(controller.getPin()) return if controller.getValidPuk(): - let storeToKeychainValue = singletonInstance.localAccountSettings.getStoreToKeychainValue() - controller.loginAccountKeycard(storeToKeychainValue) + # FIXME: Make sure storeToKeychain is correct here. The idea is not to pass it at all + # https://github.com/status-im/status-desktop/issues/15167 + # let storeToKeychainValue = singletonInstance.localAccountSettings.getStoreToKeychainValue() + controller.loginAccountKeycard(storeToKeychain = false) if self.flowType == FlowType.LostKeycardReplacement: controller.startLoginFlowAutomatically(controller.getPin()) method resolveKeycardNextState*(self: KeycardPinSetState, keycardFlowType: string, keycardEvent: KeycardEvent, controller: Controller): State = - var storeToKeychainValue = LS_VALUE_NEVER - if self.flowType == FlowType.LostKeycardReplacement: - if keycardFlowType == ResponseTypeValueKeycardFlowResult and - keycardEvent.error.len == 0: - if main_constants.IS_MACOS: - storeToKeychainValue = LS_VALUE_NOT_NOW - controller.setKeycardEvent(keycardEvent) - controller.loginAccountKeycard(storeToKeychainValue, keycardReplacement = true) - if self.flowType == FlowType.AppLogin: - if keycardFlowType == ResponseTypeValueKeycardFlowResult and - keycardEvent.error.len == 0: - # we are here in case of recover account from the login flow using seed phrase - controller.setKeycardEvent(keycardEvent) - controller.loginAccountKeycard(storeToKeychainValue, keycardReplacement = false) \ No newline at end of file + + if keycardFlowType != ResponseTypeValueKeycardFlowResult: + return + + if keycardEvent.error.len != 0: + return + + let keycardReplacement = self.flowType == FlowType.LostKeycardReplacement + if not keycardReplacement and self.flowType != FlowType.AppLogin: + return + + let storeToKeychain = keycardReplacement and main_constants.SUPPORTS_FINGERPRINT + + controller.setKeycardEvent(keycardEvent) + controller.loginAccountKeycard(storeToKeychain, keycardReplacement) + diff --git a/src/app/modules/startup/internal/keycard_wrong_pin_state.nim b/src/app/modules/startup/internal/keycard_wrong_pin_state.nim index 064107a024..2d46184e73 100644 --- a/src/app/modules/startup/internal/keycard_wrong_pin_state.nim +++ b/src/app/modules/startup/internal/keycard_wrong_pin_state.nim @@ -23,32 +23,34 @@ method resolveKeycardNextState*(self: KeycardWrongPinState, keycardFlowType: str let state = ensureReaderAndCardPresenceOnboarding(self, keycardFlowType, keycardEvent, controller) if not state.isNil: return state - if self.flowType == FlowType.FirstRunOldUserKeycardImport: - if keycardFlowType == ResponseTypeValueEnterPIN and - keycardEvent.error.len > 0 and - keycardEvent.error == RequestParamPIN: - controller.setRemainingAttempts(keycardEvent.pinRetries) - if keycardEvent.pinRetries > 0: - return self + if self.flowType != FlowType.FirstRunOldUserKeycardImport: + return + + if keycardFlowType == ResponseTypeValueEnterPIN and + keycardEvent.error.len > 0 and + keycardEvent.error == RequestParamPIN: + controller.setRemainingAttempts(keycardEvent.pinRetries) + if keycardEvent.pinRetries > 0: + return self + return createState(StateType.KeycardMaxPinRetriesReached, self.flowType, self.getBackState) + if keycardFlowType == ResponseTypeValueEnterPUK and + keycardEvent.error.len == 0: + if keycardEvent.pinRetries == 0 and keycardEvent.pukRetries > 0: return createState(StateType.KeycardMaxPinRetriesReached, self.flowType, self.getBackState) - if keycardFlowType == ResponseTypeValueEnterPUK and - keycardEvent.error.len == 0: - if keycardEvent.pinRetries == 0 and keycardEvent.pukRetries > 0: - return createState(StateType.KeycardMaxPinRetriesReached, self.flowType, self.getBackState) - return nil - if keycardFlowType == ResponseTypeValueSwapCard and - keycardEvent.error.len > 0 and - keycardEvent.error == RequestParamPUKRetries: - controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.MaxPUKReached, add = true)) - return createState(StateType.KeycardMaxPukRetriesReached, self.flowType, self.getBackState) - if keycardFlowType == ResponseTypeValueSwapCard and - keycardEvent.error.len > 0 and - keycardEvent.error == RequestParamFreeSlots: - return createState(StateType.KeycardMaxPairingSlotsReached, self.flowType, self.getBackState) - if keycardFlowType == ResponseTypeValueKeycardFlowResult: - controller.setKeycardEvent(keycardEvent) - if not main_constants.IS_MACOS: - controller.setupKeycardAccount(storeToKeychain = false) - return nil + return nil + if keycardFlowType == ResponseTypeValueSwapCard and + keycardEvent.error.len > 0 and + keycardEvent.error == RequestParamPUKRetries: + controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.MaxPUKReached, add = true)) + return createState(StateType.KeycardMaxPukRetriesReached, self.flowType, self.getBackState) + if keycardFlowType == ResponseTypeValueSwapCard and + keycardEvent.error.len > 0 and + keycardEvent.error == RequestParamFreeSlots: + return createState(StateType.KeycardMaxPairingSlotsReached, self.flowType, self.getBackState) + if keycardFlowType == ResponseTypeValueKeycardFlowResult: + controller.setKeycardEvent(keycardEvent) + if main_constants.SUPPORTS_FINGERPRINT: let backState = findBackStateWithTargetedStateType(self, StateType.RecoverOldUser) - return createState(StateType.Biometrics, self.flowType, backState) \ No newline at end of file + return createState(StateType.Biometrics, self.flowType, backState) + controller.setupKeycardAccount(storeToKeychain = false) + return nil diff --git a/src/app/modules/startup/internal/keycard_wrong_puk_state.nim b/src/app/modules/startup/internal/keycard_wrong_puk_state.nim index fe8a8b89c4..9424b7ba0b 100644 --- a/src/app/modules/startup/internal/keycard_wrong_puk_state.nim +++ b/src/app/modules/startup/internal/keycard_wrong_puk_state.nim @@ -38,11 +38,11 @@ method resolveKeycardNextState*(self: KeycardWrongPukState, keycardFlowType: str if keycardFlowType == ResponseTypeValueKeycardFlowResult: controller.setKeycardEvent(keycardEvent) controller.setPukValid(true) - if not main_constants.IS_MACOS: - controller.setupKeycardAccount(storeToKeychain = false, recoverAccount = true) - return createState(StateType.ProfileFetching, self.flowType, nil) - let backState = findBackStateWithTargetedStateType(self, StateType.RecoverOldUser) - return createState(StateType.Biometrics, self.flowType, backState) + if main_constants.SUPPORTS_FINGERPRINT: + let backState = findBackStateWithTargetedStateType(self, StateType.RecoverOldUser) + return createState(StateType.Biometrics, self.flowType, backState) + controller.setupKeycardAccount(storeToKeychain = false, recoverAccount = true) + return createState(StateType.ProfileFetching, self.flowType, nil) if self.flowType == FlowType.AppLogin: if keycardFlowType == ResponseTypeValueEnterPUK and keycardEvent.error.len > 0 and @@ -60,5 +60,7 @@ method resolveKeycardNextState*(self: KeycardWrongPukState, keycardFlowType: str controller.setKeycardEvent(keycardEvent) controller.setPukValid(true) let storeToKeychainValue = singletonInstance.localAccountSettings.getStoreToKeychainValue() - controller.loginAccountKeycard(storeToKeychainValue) - return nil \ No newline at end of file + # FIXME: Make sure storeToKeychain is correct here. The idea is not to pass it at all + # https://github.com/status-im/status-desktop/issues/15167 + controller.loginAccountKeycard(false) + return nil diff --git a/src/app/modules/startup/internal/login_keycard_pin_verified_state.nim b/src/app/modules/startup/internal/login_keycard_pin_verified_state.nim index 6d11299199..87cc40fb34 100644 --- a/src/app/modules/startup/internal/login_keycard_pin_verified_state.nim +++ b/src/app/modules/startup/internal/login_keycard_pin_verified_state.nim @@ -11,4 +11,6 @@ proc delete*(self: LoginKeycardPinVerifiedState) = method executePrimaryCommand*(self: LoginKeycardPinVerifiedState, controller: Controller) = if self.flowType == FlowType.AppLogin: let storeToKeychainValue = singletonInstance.localAccountSettings.getStoreToKeychainValue() - controller.loginAccountKeycard(storeToKeychainValue) \ No newline at end of file + # FIXME: Make sure storeToKeychain is correct here. The idea is not to pass it at all + # https://github.com/status-im/status-desktop/issues/15167 + controller.loginAccountKeycard(false) diff --git a/src/app/modules/startup/internal/user_profile_confirm_password_state.nim b/src/app/modules/startup/internal/user_profile_confirm_password_state.nim index e5273f0c0c..beb395205a 100644 --- a/src/app/modules/startup/internal/user_profile_confirm_password_state.nim +++ b/src/app/modules/startup/internal/user_profile_confirm_password_state.nim @@ -25,8 +25,8 @@ method executePrimaryCommand*(self: UserProfileConfirmPasswordState, controller: elif self.flowType == FlowType.FirstRunNewUserImportSeedPhrase: controller.importAccountAndLogin(storeToKeychain) elif self.flowType == FlowType.FirstRunNewUserNewKeycardKeys: - controller.storeKeycardAccountAndLogin(storeToKeychain, newKeycard = true) + controller.storeKeycardAccountAndLogin(storeToKeychain) elif self.flowType == FlowType.FirstRunOldUserImportSeedPhrase: controller.importAccountAndLogin(storeToKeychain, recoverAccount = true) elif self.flowType == FlowType.LostKeycardConvertToRegularAccount: - controller.loginAccountKeycardUsingSeedPhrase(storeToKeychain) + controller.loginAccountKeycard(storeToKeychain, keycardReplacement = true) diff --git a/src/app/modules/startup/io_interface.nim b/src/app/modules/startup/io_interface.nim index 4079bda7c1..877786970a 100644 --- a/src/app/modules/startup/io_interface.nim +++ b/src/app/modules/startup/io_interface.nim @@ -68,9 +68,6 @@ method startUpUIRaised*(self: AccessInterface) {.base.} = method emitLogOut*(self: AccessInterface) {.base.} = raise newException(ValueError, "No implementation available") -method getImportedAccount*(self: AccessInterface): GeneratedAccountDto {.base.} = - raise newException(ValueError, "No implementation available") - method generateImage*(self: AccessInterface, imageUrl: string, aX: int, aY: int, bX: int, bY: int): string {.base.} = raise newException(ValueError, "No implementation available") @@ -110,9 +107,6 @@ method emitStartupError*(self: AccessInterface, error: string, errType: StartupE method validMnemonic*(self: AccessInterface, mnemonic: string): bool {.base.} = raise newException(ValueError, "No implementation available") -method importAccountSuccess*(self: AccessInterface) {.base.} = - raise newException(ValueError, "No implementation available") - method setSelectedLoginAccount*(self: AccessInterface, item: login_acc_item.Item) {.base.} = raise newException(ValueError, "No implementation available") @@ -152,9 +146,6 @@ method setRemainingAttempts*(self: AccessInterface, value: int) {.base.} = method runFactoryResetPopup*(self: AccessInterface) {.base.} = raise newException(ValueError, "No implementation available") -method storeDefaultKeyPairForNewKeycardUser*(self: AccessInterface) {.base.} = - raise newException(ValueError, "No implementation available") - method syncKeycardBasedOnAppWalletStateAfterLogin*(self: AccessInterface) {.base.} = raise newException(ValueError, "No implementation available") @@ -238,7 +229,6 @@ type c.userLoggedIn() c.finishAppLoading() c.appReady() - c.storeDefaultKeyPairForNewKeycardUser() c.syncKeycardBasedOnAppWalletStateAfterLogin() c.applyKeycardReplacementAfterLogin() c.addToKeycardUidPairsToCheckForAChangeAfterLogin(string, string) diff --git a/src/app/modules/startup/models/generated_account_item.nim b/src/app/modules/startup/models/generated_account_item.nim deleted file mode 100644 index 70a71c0aec..0000000000 --- a/src/app/modules/startup/models/generated_account_item.nim +++ /dev/null @@ -1,29 +0,0 @@ -type - Item* = object - id: string - alias: string - address: string - pubKey: string - keyUid: string - -proc initItem*(id, alias, address, pubKey, keyUid: string): Item = - result.id = id - result.alias = alias - result.address = address - result.pubKey = pubKey - result.keyUid = keyUid - -proc getId*(self: Item): string = - return self.id - -proc getAlias*(self: Item): string = - return self.alias - -proc getAddress*(self: Item): string = - return self.address - -proc getPubKey*(self: Item): string = - return self.pubKey - -proc getKeyUid*(self: Item): string = - return self.keyUid diff --git a/src/app/modules/startup/models/generated_account_model.nim b/src/app/modules/startup/models/generated_account_model.nim deleted file mode 100644 index a93b122188..0000000000 --- a/src/app/modules/startup/models/generated_account_model.nim +++ /dev/null @@ -1,66 +0,0 @@ -import NimQml, Tables, strutils - -import generated_account_item - -type - ModelRole {.pure.} = enum - Id = UserRole + 1 - Alias - Address - PubKey - KeyUid - -QtObject: - type - Model* = ref object of QAbstractListModel - items: seq[Item] - - proc delete(self: Model) = - self.items = @[] - self.QAbstractListModel.delete - - proc setup(self: Model) = - self.QAbstractListModel.setup - - proc newModel*(): Model = - new(result, delete) - result.setup - - method rowCount(self: Model, index: QModelIndex = nil): int = - return self.items.len - - method roleNames(self: Model): Table[int, string] = - { - ModelRole.Id.int:"accountId", - ModelRole.Alias.int:"username", - ModelRole.Address.int:"address", - ModelRole.PubKey.int:"pubKey", - ModelRole.KeyUid.int:"keyUid" - }.toTable - - method data(self: Model, index: QModelIndex, role: int): QVariant = - if (not index.isValid): - return - - if (index.row < 0 or index.row >= self.items.len): - return - - let item = self.items[index.row] - let enumRole = role.ModelRole - - case enumRole: - of ModelRole.Id: - result = newQVariant(item.getId()) - of ModelRole.Alias: - result = newQVariant(item.getAlias()) - of ModelRole.Address: - result = newQVariant(item.getAddress()) - of ModelRole.PubKey: - result = newQVariant(item.getPubKey()) - of ModelRole.KeyUid: - result = newQVariant(item.getKeyUid()) - - proc setItems*(self: Model, items: seq[Item]) = - self.beginResetModel() - self.items = items - self.endResetModel() diff --git a/src/app/modules/startup/module.nim b/src/app/modules/startup/module.nim index cd1811e7a4..3689b0d697 100644 --- a/src/app/modules/startup/module.nim +++ b/src/app/modules/startup/module.nim @@ -3,7 +3,6 @@ import NimQml, chronicles import io_interface import view, controller import internal/[state, state_factory] -import models/generated_account_item as gen_acc_item import models/login_account_item as login_acc_item import models/fetching_data_model as fetch_model import app/global/global_singleton @@ -119,12 +118,6 @@ method load*[T](self: Module[T]) = singletonInstance.engine.setRootContextProperty("startupModule", self.viewVariant) self.controller.init() - let generatedAccounts = self.controller.getGeneratedAccounts() - var accounts: seq[gen_acc_item.Item] - for acc in generatedAccounts: - accounts.add(gen_acc_item.initItem(acc.id, acc.alias, acc.address, acc.derivedAccounts.whisper.publicKey, acc.keyUid)) - self.view.setGeneratedAccountList(accounts) - if self.controller.shouldStartWithOnboardingScreen(): self.view.setCurrentStartupState(newWelcomeState(state.FlowType.General, nil)) else: @@ -262,9 +255,6 @@ method onQuinaryActionClicked*[T](self: Module[T]) = self.view.setCurrentStartupState(nextState) debug "quinary_action - set state", setCurrFlow=nextState.flowType(), setCurrState=nextState.stateType() -method getImportedAccount*[T](self: Module[T]): GeneratedAccountDto = - return self.controller.getImportedAccount() - method generateImage*[T](self: Module[T], imageUrl: string, aX: int, aY: int, bX: int, bY: int): string = return self.controller.generateImage(imageUrl, aX, aY, bX, bY) @@ -304,9 +294,6 @@ method emitStartupError*[T](self: Module[T], error: string, errType: StartupErro method validMnemonic*[T](self: Module[T], mnemonic: string): bool = return self.controller.validMnemonic(mnemonic) -method importAccountSuccess*[T](self: Module[T]) = - self.view.importAccountSuccess() - method setSelectedLoginAccount*[T](self: Module[T], item: login_acc_item.Item) = self.controller.cancelCurrentFlow() if item.getKeyUid().len == 0: @@ -535,9 +522,6 @@ method onSharedKeycarModuleFlowTerminated*[T](self: Module[T], lastStepInTheCurr self.view.setCurrentStartupState(newState) debug "new state for onboarding/login flow continuation after shared flow is terminated", setCurrFlow=newState.flowType(), newCurrState=newState.stateType() -method storeDefaultKeyPairForNewKeycardUser*[T](self: Module[T]) = - self.delegate.storeDefaultKeyPairForNewKeycardUser() - method syncKeycardBasedOnAppWalletStateAfterLogin*[T](self: Module[T]) = self.delegate.syncKeycardBasedOnAppWalletStateAfterLogin() diff --git a/src/app/modules/startup/view.nim b/src/app/modules/startup/view.nim index 051c063821..60d0c60bae 100644 --- a/src/app/modules/startup/view.nim +++ b/src/app/modules/startup/view.nim @@ -2,8 +2,6 @@ import NimQml, chronicles import io_interface import selected_login_account import internal/[state, state_wrapper] -import models/generated_account_model as gen_acc_model -import models/generated_account_item as gen_acc_item import models/login_account_model as login_acc_model import models/login_account_item as login_acc_item import models/fetching_data_model as fetch_model @@ -25,8 +23,6 @@ QtObject: showBeforeGetStartedPopup: bool currentStartupState: StateWrapper currentStartupStateVariant: QVariant - generatedAccountsModel: gen_acc_model.Model - generatedAccountsModelVariant: QVariant selectedLoginAccount: SelectedLoginAccount selectedLoginAccountVariant: QVariant loginAccountsModel: login_acc_model.Model @@ -41,8 +37,6 @@ QtObject: proc delete*(self: View) = self.currentStartupStateVariant.delete self.currentStartupState.delete - self.generatedAccountsModel.delete - self.generatedAccountsModelVariant.delete self.selectedLoginAccount.delete self.selectedLoginAccountVariant.delete self.loginAccountsModel.delete @@ -62,8 +56,6 @@ QtObject: result.appState = AppState.StartupState result.currentStartupState = newStateWrapper() result.currentStartupStateVariant = newQVariant(result.currentStartupState) - result.generatedAccountsModel = gen_acc_model.newModel() - result.generatedAccountsModelVariant = newQVariant(result.generatedAccountsModel) result.selectedLoginAccount = newSelectedLoginAccount() result.selectedLoginAccountVariant = newQVariant(result.selectedLoginAccount) result.loginAccountsModel = login_acc_model.newModel() @@ -138,35 +130,6 @@ QtObject: proc emitLogOut*(self: View) = self.logOut() - proc generatedAccountsModelChanged*(self: View) {.signal.} - proc getGeneratedAccountsModel(self: View): QVariant {.slot.} = - return self.generatedAccountsModelVariant - proc setGeneratedAccountList*(self: View, accounts: seq[gen_acc_item.Item]) = - self.generatedAccountsModel.setItems(accounts) - self.generatedAccountsModelChanged() - QtProperty[QVariant] generatedAccountsModel: - read = getGeneratedAccountsModel - notify = generatedAccountsModelChanged - - proc importedAccountChanged*(self: View) {.signal.} - proc getImportedAccountAlias*(self: View): string {.slot.} = - return self.delegate.getImportedAccount().alias - QtProperty[string] importedAccountAlias: - read = getImportedAccountAlias - notify = importedAccountChanged - - proc getImportedAccountAddress*(self: View): string {.slot.} = - return self.delegate.getImportedAccount().address - QtProperty[string] importedAccountAddress: - read = getImportedAccountAddress - notify = importedAccountChanged - - proc getImportedAccountPubKey*(self: View): string {.slot.} = - return self.delegate.getImportedAccount().derivedAccounts.whisper.publicKey - QtProperty[string] importedAccountPubKey: - read = getImportedAccountPubKey - notify = importedAccountChanged - proc generateImage*(self: View, imageUrl: string, aX: int, aY: int, bX: int, bY: int): string {.slot.} = return self.delegate.generateImage(imageUrl, aX, aY, bX, bY) @@ -207,9 +170,6 @@ QtObject: proc validMnemonic*(self: View, mnemonic: string): bool {.slot.} = return self.delegate.validMnemonic(mnemonic) - proc importAccountSuccess*(self: View) = - self.importedAccountChanged() - proc selectedLoginAccountChanged*(self: View) {.signal.} proc getSelectedLoginAccount(self: View): QVariant {.slot.} = return self.selectedLoginAccountVariant diff --git a/src/app_service/common/utils.nim b/src/app_service/common/utils.nim index da1461a412..42caa91207 100644 --- a/src/app_service/common/utils.nim +++ b/src/app_service/common/utils.nim @@ -1,6 +1,6 @@ -import json, random, times, strutils, sugar, os, re, chronicles +import json, times, strutils, sugar, os, re, chronicles import nimcrypto -import signing_phrases, account_constants +import account_constants import ../../constants as main_constants @@ -26,16 +26,6 @@ proc prefix*(methodName: string, isExt:bool = true): string = result = result & (if isExt: "ext_" else: "_") result = result & methodName -proc generateSigningPhrase*(count: int): string = - let now = getTime() - var rng = initRand(now.toUnix * 1000000000 + now.nanosecond) - var phrases: seq[string] = @[] - - for i in 1..count: - phrases.add(rng.sample(signing_phrases.phrases)) - - result = phrases.join(" ") - proc first*(jArray: JsonNode, fieldName, id: string): JsonNode = if jArray == nil: return nil @@ -91,4 +81,4 @@ proc contractUniqueKey*(chainId: int, contractAddress: string): string = proc intersectSeqs*[T](seq1, seq2: seq[T]): seq[T] = for item in seq1: if item in seq2: - result.add(item) \ No newline at end of file + result.add(item) diff --git a/src/app_service/service/accounts/dto/create_account_request.nim b/src/app_service/service/accounts/dto/create_account_request.nim index 995d031c72..1f81b8d9a7 100644 --- a/src/app_service/service/accounts/dto/create_account_request.nim +++ b/src/app_service/service/accounts/dto/create_account_request.nim @@ -7,7 +7,7 @@ export image_crop_rectangle type CreateAccountRequest* = object - backupDisabledDataDir*: string + rootDataDir*: string kdfIterations*: int deviceName*: string displayName*: string @@ -38,9 +38,12 @@ type torrentConfigEnabled*: Option[bool] torrentConfigPort*: Option[int] + keycardInstanceUID*: string + keycardPairingDataFile*: string + proc toJson*(self: CreateAccountRequest): JsonNode = result = %*{ - "backupDisabledDataDir": self.backupDisabledDataDir, + "rootDataDir": self.rootDataDir, "kdfIterations": self.kdfIterations, "deviceName": self.deviceName, "displayName": self.displayName, @@ -54,6 +57,8 @@ proc toJson*(self: CreateAccountRequest): JsonNode = "logEnabled": self.logEnabled, "previewPrivacy": self.previewPrivacy, "upstreamConfig": self.upstreamConfig, + "keycardInstanceUID": self.keycardInstanceUID, + "keycardPairingDataFile": self.keycardPairingDataFile, } if self.logLevel.isSome(): diff --git a/src/app_service/service/accounts/dto/keycard_data.nim b/src/app_service/service/accounts/dto/keycard_data.nim new file mode 100644 index 0000000000..b4c77c0a94 --- /dev/null +++ b/src/app_service/service/accounts/dto/keycard_data.nim @@ -0,0 +1,28 @@ +import json + +type + KeycardData* = ref object + keyUID*: string + address*: string + whisperPrivateKey*: string + whisperPublicKey*: string + whisperAddress*: string + walletPublicKey*: string + walletAddress*: string + walletRootAddress*: string + eip1581Address*: string + encryptionPublicKey*: string + +proc toJson*(self: KeycardData): JsonNode = + result = %*{ + "keyUID": self.keyUID, + "address": self.address, + "whisperPrivateKey": self.whisperPrivateKey, + "whisperPublicKey": self.whisperPublicKey, + "whisperAddress": self.whisperAddress, + "walletPublicKey": self.walletPublicKey, + "walletAddress": self.walletAddress, + "walletRootAddress": self.walletRootAddress, + "eip1581Address": self.eip1581Address, + "encryptionPublicKey": self.encryptionPublicKey + } diff --git a/src/app_service/service/accounts/dto/login_request.nim b/src/app_service/service/accounts/dto/login_request.nim index a7978f1be5..2b91c38da2 100644 --- a/src/app_service/service/accounts/dto/login_request.nim +++ b/src/app_service/service/accounts/dto/login_request.nim @@ -1,5 +1,7 @@ import json -import ./wallet_secretes_config +import wallet_secretes_config + +export wallet_secretes_config type LoginAccountRequest* = object @@ -9,6 +11,8 @@ type runtimeLogLevel*: string wakuV2Nameserver*: string bandwidthStatsEnabled*: bool + keycardWhisperPrivateKey*: string + mnemonic*: string walletSecretsConfig*: WalletSecretsConfig proc toJson*(self: LoginAccountRequest): JsonNode = @@ -19,6 +23,8 @@ proc toJson*(self: LoginAccountRequest): JsonNode = "runtimeLogLevel": self.runtimeLogLevel, "wakuV2Nameserver": self.wakuV2Nameserver, "bandwidthStatsEnabled": self.bandwidthStatsEnabled, + "keycardWhisperPrivateKey": self.keycardWhisperPrivateKey, + "mnemonic": self.mnemonic, } for key, value in self.walletSecretsConfig.toJson().pairs(): result[key] = value diff --git a/src/app_service/service/accounts/dto/restore_account_request.nim b/src/app_service/service/accounts/dto/restore_account_request.nim index 2cccd836c3..37ed356430 100644 --- a/src/app_service/service/accounts/dto/restore_account_request.nim +++ b/src/app_service/service/accounts/dto/restore_account_request.nim @@ -1,18 +1,25 @@ import json -import create_account_request +import create_account_request, keycard_data + +export create_account_request, keycard_data type RestoreAccountRequest* = object mnemonic*: string + keycard*: KeycardData fetchBackup*: bool createAccountRequest*: CreateAccountRequest proc toJson*(self: RestoreAccountRequest): JsonNode = + result = %*{ "mnemonic": self.mnemonic, - "fetchBackup": self.fetchBackup + "fetchBackup": self.fetchBackup, } + if self.keycard != nil: + result["keycard"] = self.keycard.toJson() + for key, value in self.createAccountRequest.toJson().pairs(): result[key] = value diff --git a/src/app_service/service/accounts/service.nim b/src/app_service/service/accounts/service.nim index 5e04f84aef..d792203934 100644 --- a/src/app_service/service/accounts/service.nim +++ b/src/app_service/service/accounts/service.nim @@ -1,11 +1,10 @@ -import NimQml, Tables, os, json, stew/shims/strformat, sequtils, strutils, uuids, times, std/options +import NimQml, Tables, os, json, stew/shims/strformat, sequtils, strutils, times, std/options import json_serialization, chronicles import ../../../app/global/global_singleton import ./dto/accounts as dto_accounts import ./dto/generated_accounts as dto_generated_accounts import ./dto/login_request -import ./dto/create_account_request import ./dto/restore_account_request from ../keycard/service import KeycardEvent, KeyDetails @@ -20,8 +19,6 @@ import ../../../app/core/fleets/fleet_configuration import ../../common/[account_constants, network_constants, utils] import ../../../constants as main_constants -import ../settings/dto/settings as settings - export dto_accounts export dto_generated_accounts @@ -29,8 +26,6 @@ export dto_generated_accounts logScope: topics = "accounts-service" -const DEFAULT_WALLET_ACCOUNT_NAME = "Account 1" -const PATHS = @[PATH_WALLET_ROOT, PATH_EIP_1581, PATH_WHISPER, PATH_DEFAULT_WALLET, PATH_ENCRYPTION] const ACCOUNT_ALREADY_EXISTS_ERROR* = "account already exists" const KDF_ITERATIONS* {.intdefine.} = 256_000 const DEFAULT_CUSTOMIZATION_COLOR = "primary" # to match `CustomizationColor` on the go side @@ -62,15 +57,15 @@ QtObject: events: EventEmitter threadpool: ThreadPool fleetConfiguration: FleetConfiguration - generatedAccounts: seq[GeneratedAccountDto] accounts: seq[AccountDto] loggedInAccount: AccountDto - importedAccount: GeneratedAccountDto keyStoreDir: string defaultWalletEmoji: string tmpAccount: AccountDto tmpHashedPassword: string + proc restoreAccountAndLogin(self: Service, request: RestoreAccountRequest): string + proc delete*(self: Service) = self.QObject.delete @@ -83,6 +78,8 @@ QtObject: result.keyStoreDir = main_constants.ROOTKEYSTOREDIR result.defaultWalletEmoji = "" + proc scheduleReencrpytion(self: Service, account: AccountDto, hashedPassword: string, timeout: int = 1000) + proc setLocalAccountSettingsFile(self: Service) = if self.loggedInAccount.isValid(): singletonInstance.localAccountSettings.setFileName(self.loggedInAccount.name) @@ -99,9 +96,6 @@ QtObject: self.loggedInAccount.images = images singletonInstance.localAccountSettings.setFileName(displayName) - proc getImportedAccount*(self: Service): GeneratedAccountDto = - return self.importedAccount - proc setKeyStoreDir(self: Service, key: string) = self.keyStoreDir = joinPath(main_constants.ROOTKEYSTOREDIR, key) & main_constants.sep discard status_general.initKeystore(self.keyStoreDir) @@ -118,22 +112,10 @@ QtObject: self.updateLoggedInAccount(receivedData.backedUpProfile.displayName, receivedData.backedUpProfile.images) proc init*(self: Service) = - try: - let response = status_account.generateAddresses(PATHS) - - self.generatedAccounts = map(response.result.getElems(), - proc(x: JsonNode): GeneratedAccountDto = toGeneratedAccountDto(x)) - - for account in self.generatedAccounts.mitems: - account.alias = generateAliasFromPk(account.derivedAccounts.whisper.publicKey) - - except Exception as e: - error "error: ", procName="init", errName = e.name, errDesription = e.msg + discard proc clear*(self: Service) = - self.generatedAccounts = @[] self.loggedInAccount = AccountDto() - self.importedAccount = GeneratedAccountDto() proc validateMnemonic*(self: Service, mnemonic: string): (string, string) = try: @@ -144,13 +126,6 @@ QtObject: except Exception as e: error "error: ", procName="validateMnemonic", errName = e.name, errDesription = e.msg - proc generatedAccounts*(self: Service): seq[GeneratedAccountDto] = - if(self.generatedAccounts.len == 0): - error "There was some issue initiating account service" - return - - result = self.generatedAccounts - proc openedAccounts*(self: Service): seq[AccountDto] = try: let response = status_account.openedAccounts(main_constants.STATUSGODIR) @@ -165,106 +140,12 @@ QtObject: proc openedAccountsContainsKeyUid*(self: Service, keyUid: string): bool = return (keyUID in self.openedAccounts().mapIt(it.keyUid)) - proc saveKeycardAccountAndLogin(self: Service, chatKey, password: string, account, subaccounts, settings, - config: JsonNode): AccountDto = - try: - let response = status_account.saveAccountAndLoginWithKeycard(chatKey, password, account, subaccounts, settings, config) - - var error = "response doesn't contain \"error\"" - if(response.result.contains("error")): - error = response.result["error"].getStr - if error == "": - debug "Account saved succesfully" - result = toAccountDto(account) - return - - let err = "Error saving account and logging in via keycard : " & error - error "error: ", procName="saveKeycardAccountAndLogin", errDesription = err - - except Exception as e: - error "error: ", procName="saveKeycardAccountAndLogin", errName = e.name, errDesription = e.msg - - proc prepareSubaccountJsonObject(self: Service, account: GeneratedAccountDto, displayName: string): - JsonNode = - result = %* [ - { - "public-key": account.derivedAccounts.defaultWallet.publicKey, - "address": account.derivedAccounts.defaultWallet.address, - "colorId": DEFAULT_CUSTOMIZATION_COLOR, - "wallet": true, - "path": PATH_DEFAULT_WALLET, - "name": DEFAULT_WALLET_ACCOUNT_NAME, - "derived-from": account.address, - "emoji": self.defaultWalletEmoji - }, - { - "public-key": account.derivedAccounts.whisper.publicKey, - "address": account.derivedAccounts.whisper.address, - "name": if displayName == "": account.alias else: displayName, - "path": PATH_WHISPER, - "chat": true, - "derived-from": "" - } - ] - - proc getSubaccountDataForAccountId(self: Service, accountId: string, displayName: string): JsonNode = - for acc in self.generatedAccounts: - if(acc.id == accountId): - return self.prepareSubaccountJsonObject(acc, displayName) - - if(self.importedAccount.isValid()): - if(self.importedAccount.id == accountId): - return self.prepareSubaccountJsonObject(self.importedAccount, displayName) - proc toStatusGoSupportedLogLevel*(logLevel: string): string = if logLevel == "TRACE": return "DEBUG" return logLevel - proc prepareAccountSettingsJsonObject(self: Service, account: GeneratedAccountDto, - installationId: string, displayName: string, withoutMnemonic: bool): JsonNode = - result = %* { - "key-uid": account.keyUid, - "mnemonic": if withoutMnemonic: "" else: account.mnemonic, - "public-key": account.derivedAccounts.whisper.publicKey, - "name": account.alias, - "display-name": displayName, - "address": account.address, - "eip1581-address": account.derivedAccounts.eip1581.address, - "dapps-address": account.derivedAccounts.defaultWallet.address, - "wallet-root-address": account.derivedAccounts.walletRoot.address, - "preview-privacy?": true, - "signing-phrase": generateSigningPhrase(3), - "log-level": main_constants.LOG_LEVEL, - "latest-derived-path": 0, - "currency": "usd", - "networks/networks": @[], - "networks/current-network": "", - "wallet/visible-tokens": {}, - "waku-enabled": true, - "appearance": 0, - "installation-id": installationId, - "current-user-status": %* { - "publicKey": account.derivedAccounts.whisper.publicKey, - "statusType": 1, - "clock": 0, - "text": "" - }, - "profile-pictures-show-to": settings.PROFILE_PICTURES_SHOW_TO_EVERYONE, - "profile-pictures-visibility": settings.PROFILE_PICTURES_VISIBILITY_EVERYONE, - "url-unfurling-mode": int(settings.UrlUnfurlingMode.AlwaysAsk), - } - - proc getAccountSettings(self: Service, accountId: string, installationId: string, displayName: string, withoutMnemonic: bool): JsonNode = - for acc in self.generatedAccounts: - if(acc.id == accountId): - return self.prepareAccountSettingsJsonObject(acc, installationId, displayName, withoutMnemonic) - - if(self.importedAccount.isValid()): - if(self.importedAccount.id == accountId): - return self.prepareAccountSettingsJsonObject(self.importedAccount, installationId, displayName, withoutMnemonic) - - # TODO: Remove after https://github.com/status-im/status-go/issues/4977 + # TODO: Remove after https://github.com/status-im/status-desktop/issues/11435 proc getDefaultNodeConfig*(self: Service, installationId: string, recoverAccount: bool): JsonNode = let fleet = Fleet.ShardsTest let dnsDiscoveryURL = "enrtree://AMOJVZX4V6EXP7NTJPMAYJYST2QP6AJXYW76IU6VGJS7UVSNDYZG4@boot.test.shards.nodes.status.im" @@ -305,49 +186,8 @@ QtObject: result["KeycardPairingDataFile"] = newJString(main_constants.KEYCARDPAIRINGDATAFILE) result["ProcessBackedupMessages"] = newJBool(recoverAccount) - # TODO: Remove after https://github.com/status-im/status-go/issues/4977 - proc getLoginNodeConfig(self: Service): JsonNode = - # To create appropriate NodeConfig for Login we set only params that maybe be set via env variables or cli flags - result = %*{} - - # mandatory params - result["NetworkId"] = NETWORKS[0]{"chainId"} - result["DataDir"] = %* "./ethereum/mainnet" - result["KeyStoreDir"] = %* self.keyStoreDir.replace(main_constants.STATUSGODIR, "") - result["KeycardPairingDataFile"] = %* main_constants.KEYCARDPAIRINGDATAFILE - - # other params - result["Networks"] = NETWORKS - - result["UpstreamConfig"] = %* { - "URL": NETWORKS[0]{"rpcUrl"}, - "Enabled": true, - } - - result["ShhextConfig"] = %* { - "VerifyENSURL": NETWORKS[0]{"fallbackUrl"}, - "VerifyTransactionURL": NETWORKS[0]{"fallbackUrl"} - } - - result["WakuV2Config"] = %* { - "Port": WAKU_V2_PORT, - "UDPPort": WAKU_V2_PORT - } - - result["WalletConfig"] = NODE_CONFIG["WalletConfig"] - - result["TorrentConfig"] = %* { - "Port": TORRENT_CONFIG_PORT, - "DataDir": DEFAULT_TORRENT_CONFIG_DATADIR, - "TorrentDir": DEFAULT_TORRENT_CONFIG_TORRENTDIR - } - - if main_constants.runtimeLogLevelSet(): - result["RuntimeLogLevel"] = newJString(toStatusGoSupportedLogLevel(main_constants.LOG_LEVEL)) - - if STATUS_PORT != 0: - result["ListenAddr"] = newJString("0.0.0.0:" & $main_constants.STATUS_PORT) - + # FIXME: remove this method, settings should be processed in status-go + # https://github.com/status-im/status-go/issues/5359 proc addKeycardDetails(self: Service, kcInstance: string, settingsJson: var JsonNode, accountData: var JsonNode) = let keycardPairingJsonString = readFile(main_constants.KEYCARDPAIRINGDATAFILE) let keycardPairingJsonObj = keycardPairingJsonString.parseJSON @@ -383,7 +223,7 @@ QtObject: proc buildCreateAccountRequest(self: Service, password: string, displayName: string, imagePath: string, imageCropRectangle: ImageCropRectangle): CreateAccountRequest = return CreateAccountRequest( - backupDisabledDataDir: main_constants.STATUSGODIR, + rootDataDir: main_constants.STATUSGODIR, kdfIterations: KDF_ITERATIONS, password: hashPassword(password), displayName: displayName, @@ -396,6 +236,7 @@ QtObject: previewPrivacy: true, torrentConfigEnabled: some(false), torrentConfigPort: some(TORRENT_CONFIG_PORT), + keycardPairingDataFile: main_constants.KEYCARDPAIRINGDATAFILE, walletSecretsConfig: self.buildWalletSecrets(), ) @@ -420,13 +261,57 @@ QtObject: error "failed to create account or login", procName="createAccountAndLogin", errName = e.name, errDesription = e.msg return e.msg - proc importAccountAndLogin*(self: Service, mnemonic: string, password: string, recoverAccount: bool, displayName: string, imagePath: string, imageCropRectangle: ImageCropRectangle): string = + proc importAccountAndLogin*(self: Service, + mnemonic: string, + password: string, + recoverAccount: bool, + displayName: string, + imagePath: string, + imageCropRectangle: ImageCropRectangle, + keycardInstanceUID: string = "", + ): string = + + var request = RestoreAccountRequest( + mnemonic: mnemonic, + fetchBackup: recoverAccount, + createAccountRequest: self.buildCreateAccountRequest(password, displayName, imagePath, imageCropRectangle), + ) + request.createAccountRequest.keycardInstanceUID = keycardInstanceUID + + self.restoreAccountAndLogin(request) + + proc restoreKeycardAccountAndLogin*(self: Service, + keycardData: KeycardEvent, + recoverAccount: bool, + displayName: string, + imagePath: string, + imageCropRectangle: ImageCropRectangle, + ): string = + + let keycard = KeycardData( + keyUid: keycardData.keyUid, + address: keycardData.masterKey.address, + whisperPrivateKey: keycardData.whisperKey.privateKey, + whisperPublicKey: keycardData.whisperKey.publicKey, + whisperAddress: keycardData.whisperKey.address, + walletPublicKey: keycardData.walletKey.publicKey, + walletAddress: keycardData.walletKey.address, + walletRootAddress: keycardData.walletRootKey.address, + eip1581Address: keycardData.eip1581Key.address, + encryptionPublicKey: keycardData.encryptionKey.publicKey, + ) + + var request = RestoreAccountRequest( + keycard: keycard, + fetchBackup: recoverAccount, + createAccountRequest: self.buildCreateAccountRequest("", displayName, imagePath, imageCropRectangle), + ) + request.createAccountRequest.keycardInstanceUID = keycardData.instanceUid + + return self.restoreAccountAndLogin(request) + + proc restoreAccountAndLogin(self: Service, request: RestoreAccountRequest): string = try: - let request = RestoreAccountRequest( - mnemonic: mnemonic, - fetchBackup: recoverAccount, - createAccountRequest: self.buildCreateAccountRequest(password, displayName, imagePath, imageCropRectangle), - ) let response = status_account.restoreAccountAndLogin(request) if not response.result.contains("error"): @@ -438,120 +323,11 @@ QtObject: debug "Account saved succesfully" return "" - error "importAccountAndLogin status-go error: ", error - return "importAccountAndLogin failed: " & error + error "restoreAccountAndLogin status-go error: ", error + return "restoreAccountAndLogin failed: " & error except Exception as e: - error "failed to import account or login", procName="importAccountAndLogin", errName = e.name, errDesription = e.msg - return e.msg - - proc setupAccountKeycard*(self: Service, keycardData: KeycardEvent, displayName: string, useImportedAcc: bool, - recoverAccount: bool = false) = - try: - var keyUid = keycardData.keyUid - var address = keycardData.masterKey.address - var whisperPrivateKey = keycardData.whisperKey.privateKey - var whisperPublicKey = keycardData.whisperKey.publicKey - var whisperAddress = keycardData.whisperKey.address - var walletPublicKey = keycardData.walletKey.publicKey - var walletAddress = keycardData.walletKey.address - var walletRootAddress = keycardData.walletRootKey.address - var eip1581Address = keycardData.eip1581Key.address - var encryptionPublicKey = keycardData.encryptionKey.publicKey - if useImportedAcc: - keyUid = self.importedAccount.keyUid - address = self.importedAccount.address - whisperPublicKey = self.importedAccount.derivedAccounts.whisper.publicKey - whisperAddress = self.importedAccount.derivedAccounts.whisper.address - walletPublicKey = self.importedAccount.derivedAccounts.defaultWallet.publicKey - walletAddress = self.importedAccount.derivedAccounts.defaultWallet.address - walletRootAddress = self.importedAccount.derivedAccounts.walletRoot.address - eip1581Address = self.importedAccount.derivedAccounts.eip1581.address - encryptionPublicKey = self.importedAccount.derivedAccounts.encryption.publicKey - whisperPrivateKey = self.importedAccount.derivedAccounts.whisper.privateKey - - if whisperPrivateKey.startsWith("0x"): - whisperPrivateKey = whisperPrivateKey[2 .. ^1] - - let installationId = $genUUID() - let alias = generateAliasFromPk(whisperPublicKey) - - var accountDataJson = %* { - "name": if displayName == "": alias else: displayName, - "display-name": displayName, - "address": address, - "key-uid": keyUid, - "kdfIterations": KDF_ITERATIONS, - } - - self.setKeyStoreDir(keyUid) - let nodeConfigJson = self.getDefaultNodeConfig(installationId, recoverAccount) - let subaccountDataJson = %* [ - { - "public-key": walletPublicKey, - "address": walletAddress, - "colorId": DEFAULT_CUSTOMIZATION_COLOR, - "wallet": true, - "path": PATH_DEFAULT_WALLET, - "name": DEFAULT_WALLET_ACCOUNT_NAME, - "derived-from": address, - "emoji": self.defaultWalletEmoji, - }, - { - "public-key": whisperPublicKey, - "address": whisperAddress, - "name": if displayName == "": alias else: displayName, - "path": PATH_WHISPER, - "chat": true, - "derived-from": "" - } - ] - - var settingsJson = %* { - "key-uid": keyUid, - "public-key": whisperPublicKey, - "name": alias, - "display-name": displayName, - "address": address, - "eip1581-address": eip1581Address, - "dapps-address": walletAddress, - "wallet-root-address": walletRootAddress, - "preview-privacy?": true, - "signing-phrase": generateSigningPhrase(3), - "log-level": main_constants.LOG_LEVEL, - "latest-derived-path": 0, - "currency": "usd", - "networks/networks": @[], - "networks/current-network": "", - "wallet/visible-tokens": {}, - "waku-enabled": true, - "appearance": 0, - "installation-id": installationId, - "current-user-status": { - "publicKey": whisperPublicKey, - "statusType": 1, - "clock": 0, - "text": "" - } - } - - self.addKeycardDetails(keycardData.instanceUID, settingsJson, accountDataJson) - - if(accountDataJson.isNil or subaccountDataJson.isNil or settingsJson.isNil or - nodeConfigJson.isNil): - let description = "at least one json object is not prepared well" - error "error: ", procName="setupAccountKeycard", errDesription = description - return - - self.loggedInAccount = self.saveKeycardAccountAndLogin(chatKey = whisperPrivateKey, - password = encryptionPublicKey, - accountDataJson, - subaccountDataJson, - settingsJson, - nodeConfigJson) - self.setLocalAccountSettingsFile() - except Exception as e: - error "error: ", procName="setupAccount", errName = e.name, errDesription = e.msg + error "restore account failed", procName="restoreAccountAndLogin", errName = e.name, errDesription = e.msg proc createAccountFromPrivateKey*(self: Service, privateKey: string): GeneratedAccountDto = if privateKey.len == 0: @@ -610,27 +386,6 @@ QtObject: data.error = e.msg self.events.emit(SIGNAL_DERIVED_ADDRESSES_FROM_NOT_IMPORTED_MNEMONIC_FETCHED, data) - proc importMnemonic*(self: Service, mnemonic: string): string = - if mnemonic.len == 0: - return "empty mnemonic" - try: - let response = status_account.multiAccountImportMnemonic(mnemonic) - self.importedAccount = toGeneratedAccountDto(response.result) - - if (self.accounts.contains(self.importedAccount.keyUid)): - return ACCOUNT_ALREADY_EXISTS_ERROR - - let responseDerived = status_account.deriveAccounts(self.importedAccount.id, PATHS) - self.importedAccount.derivedAccounts = toDerivedAccounts(responseDerived.result) - - self.importedAccount.alias= generateAliasFromPk(self.importedAccount.derivedAccounts.whisper.publicKey) - - if (not self.importedAccount.isValid()): - return "imported account is not valid" - except Exception as e: - error "error: ", procName="importMnemonic", errName = e.name, errDesription = e.msg - return e.msg - proc verifyAccountPassword*(self: Service, account: string, password: string): bool = try: let response = status_account.verifyAccountPassword(account, utils.hashPassword(password), self.keyStoreDir) @@ -657,11 +412,13 @@ QtObject: except Exception as e: error "error: ", procName="verifyDatabasePassword", errName = e.name, errDesription = e.msg - proc doLogin(self: Service, account: AccountDto, passwordHash: string) = + proc doLogin(self: Service, account: AccountDto, passwordHash: string, chatPrivateKey: string = "", mnemonic: string = "") = var request = LoginAccountRequest( keyUid: account.keyUid, kdfIterations: account.kdfIterations, passwordHash: passwordHash, + keycardWhisperPrivateKey: chatPrivateKey, + mnemonic: mnemonic, walletSecretsConfig: self.buildWalletSecrets(), bandwidthStatsEnabled: true, ) @@ -678,8 +435,9 @@ QtObject: debug "account logged in" self.setLocalAccountSettingsFile() - proc login*(self: Service, account: AccountDto, hashedPassword: string) = + proc login*(self: Service, account: AccountDto, hashedPassword: string, chatPrivateKey: string = "", mnemonic: string = "") = try: + # WARNING: Is this keystore migration still needed? let keyStoreDir = joinPath(main_constants.ROOTKEYSTOREDIR, account.keyUid) & main_constants.sep if not dirExists(keyStoreDir): os.createDir(keyStoreDir) @@ -689,30 +447,33 @@ QtObject: self.setKeyStoreDir(account.keyUid) - let isOldHashPassword = self.verifyDatabasePassword(account.keyUid, hashedPasswordToUpperCase(hashedPassword)) - if isOldHashPassword: - debug "database reencryption scheduled" + if mnemonic == "": + let oldHashedPassword = hashedPasswordToUpperCase(hashedPassword) + if self.verifyDatabasePassword(account.keyUid, oldHashedPassword): + self.scheduleReencrpytion(account, hashedPassword, timeout = 1000) + return - # Save tmp properties so that we can login after the timer - self.tmpAccount = account - self.tmpHashedPassword = hashedPassword - - # Start a 1 second timer for the loading screen to appear - let arg = TimerTaskArg( - tptr: timerTask, - vptr: cast[ByteAddress](self.vptr), - slot: "onWaitForReencryptionTimeout", - timeoutInMilliseconds: 1000 - ) - self.threadpool.start(arg) - return - - self.doLogin(account, hashedPassword) + self.doLogin(account, hashedPassword, chatPrivateKey, mnemonic) except Exception as e: error "login failed", errName = e.name, errDesription = e.msg self.events.emit(SIGNAL_LOGIN_ERROR, LoginErrorArgs(error: e.msg)) + proc scheduleReencrpytion(self: Service, account: AccountDto, hashedPassword: string, timeout: int = 1000) = + debug "database reencryption scheduled" + + # Save tmp properties so that we can login after the timer + self.tmpAccount = account + self.tmpHashedPassword = hashedPassword + + let arg = TimerTaskArg( + tptr: timerTask, + vptr: cast[ByteAddress](self.vptr), + slot: "onWaitForReencryptionTimeout", + timeoutInMilliseconds: timeout + ) + self.threadpool.start(arg) + proc onWaitForReencryptionTimeout(self: Service, response: string) {.slot.} = debug "starting database reencryption" @@ -727,34 +488,6 @@ QtObject: self.tmpAccount = AccountDto() self.tmpHashedPassword = "" - proc loginAccountKeycard*(self: Service, accToBeLoggedIn: AccountDto, keycardData: KeycardEvent): string = - try: - self.setKeyStoreDir(keycardData.keyUid) - - var accountDataJson = %* { - "key-uid": accToBeLoggedIn.keyUid, - } - - let nodeConfigJson = self.getLoginNodeConfig() - - let response = status_account.loginWithKeycard(keycardData.whisperKey.privateKey, - keycardData.encryptionKey.publicKey, - accountDataJson, - nodeConfigJson) - - var error = "response doesn't contain \"error\"" - if(response.result.contains("error")): - error = response.result["error"].getStr - if error == "": - debug "Account logged in succesfully" - # this should be fetched later from waku - self.loggedInAccount = accToBeLoggedIn - self.setLocalAccountSettingsFile() - return - except Exception as e: - error "keycard login failed", procName="loginAccountKeycard", errName = e.name, errDesription = e.msg - return e.msg - proc convertRegularProfileKeypairToKeycard*(self: Service, keycardUid, currentPassword: string, newPassword: string) = var accountDataJson = %* { "key-uid": self.getLoggedInAccount().keyUid, @@ -816,7 +549,7 @@ QtObject: if(errMsg.len == 0): result = true else: - error "error: ", procName="onConvertKeycardProfileKeypairToRegular", errDesription = errMsg + error "failed to convert keycard account", procName="onConvertKeycardProfileKeypairToRegular", errDesription = errMsg except Exception as e: error "error handilng migrated keypair response", procName="onConvertKeycardProfileKeypairToRegular", errDesription=e.msg self.events.emit(SIGNAL_CONVERTING_PROFILE_KEYPAIR, ResultArgs(success: result)) diff --git a/src/app_service/service/accounts/utils.nim b/src/app_service/service/accounts/utils.nim index bf429c0c82..3a7e19c0ba 100644 --- a/src/app_service/service/accounts/utils.nim +++ b/src/app_service/service/accounts/utils.nim @@ -1,4 +1,3 @@ -import json import ../../../backend/accounts as status_account import ../../common/conversion @@ -42,9 +41,6 @@ proc compressCommunityKey*(publicKey: string): string = except Exception as e: echo "error: `compressCommunityKey` " & $e.name & " msg: " & $e.msg -proc generateAliasFromPk*(publicKey: string): string = - return status_account.generateAlias(publicKey).result.getStr - proc isAlias*(value: string): bool = return status_account.isAlias(value) @@ -57,4 +53,4 @@ proc changeCommunityKeyCompression*(publicKey: string): string = else: # is 33-bytes let uncompressedKey = decompressCommunityKey(publicKey) - return compressPk(uncompressedKey) \ No newline at end of file + return compressPk(uncompressedKey) diff --git a/src/backend/accounts.nim b/src/backend/accounts.nim index 8ec27a8d5b..ef291ec343 100644 --- a/src/backend/accounts.nim +++ b/src/backend/accounts.nim @@ -13,8 +13,6 @@ export response_type logScope: topics = "rpc-accounts" -const NUMBER_OF_ADDRESSES_TO_GENERATE = 1 -const MNEMONIC_PHRASE_LENGTH = 12 const PK_LENGTH_0X_INCLUDED = 132 const GENERATED* = "generated" @@ -132,22 +130,6 @@ proc updateAccount*(name, address, path: string, publicKey, keyUid, accountType, ] return core.callPrivateRPC("accounts_saveAccount", payload) -proc generateAddresses*(paths: seq[string]): RpcResponse[JsonNode] = - let payload = %* { - "n": NUMBER_OF_ADDRESSES_TO_GENERATE, - "mnemonicPhraseLength": MNEMONIC_PHRASE_LENGTH, - "bip39Passphrase": "", - "paths": paths - } - - try: - let response = status_go.multiAccountGenerateAndDeriveAddresses($payload) - result.result = Json.decode(response, JsonNode) - - except RpcException as e: - error "error doing rpc request", methodName = "generateAddresses", exception=e.msg - raise newException(RpcException, e.msg) - proc decompressPk*(publicKey: string): RpcResponse[string] = discard if publicKey.startsWith("0x04") and publicKey.len == PK_LENGTH_0X_INCLUDED: @@ -221,20 +203,6 @@ proc getRandomMnemonic*(): RpcResponse[JsonNode] = let payload = %* [] return core.callPrivateRPC("accounts_getRandomMnemonic", payload) -proc multiAccountImportMnemonic*(mnemonic: string): RpcResponse[JsonNode] = - let payload = %* { - "mnemonicPhrase": mnemonic, - "Bip39Passphrase": "" - } - - try: - let response = status_go.multiAccountImportMnemonic($payload) - result.result = Json.decode(response, JsonNode) - - except RpcException as e: - error "error doing rpc request", methodName = "multiAccountImportMnemonic", exception=e.msg - raise newException(RpcException, e.msg) - ## Imports a new mnemonic and creates local keystore file. proc importMnemonic*(mnemonic, password: string): RpcResponse[JsonNode] = @@ -290,20 +258,6 @@ proc createAccountFromPrivateKey*(privateKey: string): RpcResponse[JsonNode] = error "error doing rpc request", methodName = "createAccountFromPrivateKey", exception=e.msg raise newException(RpcException, e.msg) -proc deriveAccounts*(accountId: string, paths: seq[string]): RpcResponse[JsonNode] = - let payload = %* { - "accountID": accountId, - "paths": paths - } - - try: - let response = status_go.multiAccountDeriveAddresses($payload) - result.result = Json.decode(response, JsonNode) - - except RpcException as e: - error "error doing rpc request", methodName = "deriveAccounts", exception=e.msg - raise newException(RpcException, e.msg) - proc openedAccounts*(path: string): RpcResponse[JsonNode] = try: let response = status_go.openAccounts(path) @@ -342,16 +296,6 @@ proc restoreAccountAndLogin*(request: RestoreAccountRequest): RpcResponse[JsonNo error "error doing rpc request", methodName = "restoreAccountAndLogin", exception=e.msg raise newException(RpcException, e.msg) -proc saveAccountAndLoginWithKeycard*(chatKey, password: string, account, subaccounts, settings, config: JsonNode): - RpcResponse[JsonNode] = - try: - let response = status_go.saveAccountAndLoginWithKeycard($account, password, $settings, $config, $subaccounts, chatKey) - result.result = Json.decode(response, JsonNode) - - except RpcException as e: - error "error doing rpc request", methodName = "saveAccountAndLogin", exception=e.msg - raise newException(RpcException, e.msg) - proc convertRegularProfileKeypairToKeycard*(account: JsonNode, settings: JsonNode, keycardUid: string, password: string, newPassword: string): RpcResponse[JsonNode] = try: @@ -380,14 +324,6 @@ proc loginAccount*(request: LoginAccountRequest): RpcResponse[JsonNode] = error "loginAccount failed", exception=e.msg raise newException(RpcException, e.msg) -proc loginWithKeycard*(chatKey, password: string, account, confNode: JsonNode): RpcResponse[JsonNode] = - try: - let response = status_go.loginWithKeycard($account, password, chatKey, $confNode) - result.result = Json.decode(response, JsonNode) - except RpcException as e: - error "error doing rpc request", methodName = "loginWithKeycard", exception=e.msg - raise newException(RpcException, e.msg) - proc verifyAccountPassword*(address: string, hashedPassword: string, keystoreDir: string): RpcResponse[JsonNode] = try: diff --git a/vendor/nim-status-go b/vendor/nim-status-go index d38b1147f8..0fdd7d8def 160000 --- a/vendor/nim-status-go +++ b/vendor/nim-status-go @@ -1 +1 @@ -Subproject commit d38b1147f8b4d0c4abdb1dbf353aff36454e02ed +Subproject commit 0fdd7d8def22e64018fe2a47b9c0d98da387c6bc diff --git a/vendor/status-go b/vendor/status-go index ee2330fe5d..49eaabaca5 160000 --- a/vendor/status-go +++ b/vendor/status-go @@ -1 +1 @@ -Subproject commit ee2330fe5d4233a7d8b105420c2b93284ad161f3 +Subproject commit 49eaabaca5100368c5b39fb8c107aad2535371e5