From 92bd3e4999e7c18b3fa3215805754728cdc41912 Mon Sep 17 00:00:00 2001 From: Igor Sirotin Date: Wed, 31 May 2023 16:06:23 +0300 Subject: [PATCH] feat: Ability to login directly with hashed password (#10811) --- src/app/modules/startup/controller.nim | 4 ++-- src/app_service/common/utils.nim | 5 ++++- src/app_service/service/accounts/service.nim | 18 +++++++--------- src/backend/core.nim | 5 ++--- src/backend/privacy.nim | 22 +++++++------------- 5 files changed, 22 insertions(+), 32 deletions(-) diff --git a/src/app/modules/startup/controller.nim b/src/app/modules/startup/controller.nim index 0b839870cc..f68645ba97 100644 --- a/src/app/modules/startup/controller.nim +++ b/src/app/modules/startup/controller.nim @@ -12,7 +12,7 @@ import ../../../app_service/service/keychain/service as keychain_service import ../../../app_service/service/profile/service as profile_service import ../../../app_service/service/keycard/service as keycard_service import ../../../app_service/service/devices/service as devices_service -import ../../../app_service/common/account_constants +import ../../../app_service/common/[account_constants, utils] import ../shared_modules/keycard_popup/io_interface as keycard_shared_module @@ -445,7 +445,7 @@ proc isSelectedAccountAKeycardAccount*(self: Controller): bool = proc login*(self: Controller) = self.delegate.moveToLoadingAppState() let selectedAccount = self.getSelectedLoginAccount() - self.accountsService.login(selectedAccount, self.tmpPassword) + self.accountsService.login(selectedAccount, hashPassword(self.tmpPassword)) proc loginAccountKeycard*(self: Controller, storeToKeychainValue: string, syncWalletAfterLogin = false) = if syncWalletAfterLogin: diff --git a/src/app_service/common/utils.nim b/src/app_service/common/utils.nim index fd7c3755ba..7e46e4b1dd 100644 --- a/src/app_service/common/utils.nim +++ b/src/app_service/common/utils.nim @@ -18,6 +18,9 @@ proc hashPassword*(password: string, lower: bool = true): string = return hashed +proc hashedPasswordToUpperCase*(hashedPassword: string): string = + return "0x" & hashedPassword[2 .. ^1].toUpperAscii() + proc prefix*(methodName: string, isExt:bool = true): string = result = "waku" result = result & (if isExt: "ext_" else: "_") @@ -83,4 +86,4 @@ proc isPathOutOfTheDefaultStatusDerivationTree*(path: string): bool = return false proc contractUniqueKey*(chainId: int, contractAddress: string): string = - return $chainId & "_" & contractAddress \ No newline at end of file + return $chainId & "_" & contractAddress diff --git a/src/app_service/service/accounts/service.nim b/src/app_service/service/accounts/service.nim index c3f7b18c09..aa537d3235 100644 --- a/src/app_service/service/accounts/service.nim +++ b/src/app_service/service/accounts/service.nim @@ -66,7 +66,6 @@ QtObject: keyStoreDir: string defaultWalletEmoji: string tmpAccount: AccountDto - tmpPassword: string tmpHashedPassword: string tmpThumbnailImage: string tmpLargeImage: string @@ -618,9 +617,8 @@ QtObject: self.loggedInAccount = account self.setLocalAccountSettingsFile() - proc login*(self: Service, account: AccountDto, password: string) = + proc login*(self: Service, account: AccountDto, hashedPassword: string) = try: - let hashedPassword = hashPassword(password) var thumbnailImage: string var largeImage: string for img in account.images: @@ -634,7 +632,7 @@ QtObject: os.createDir(keyStoreDir) status_core.migrateKeyStoreDir($ %* { "key-uid": account.keyUid - }, password, main_constants.ROOTKEYSTOREDIR, keyStoreDir) + }, hashedPassword, main_constants.ROOTKEYSTOREDIR, keyStoreDir) self.setKeyStoreDir(account.keyUid) # This is moved from `status-lib` here @@ -691,15 +689,14 @@ QtObject: "RendezvousNodes": @[], "DiscV5BootstrapNodes": @[] } - - let isOldHashPassword = self.verifyDatabasePassword(account.keyUid, hashPassword(password, lower=false)) + + let isOldHashPassword = self.verifyDatabasePassword(account.keyUid, hashedPasswordToUpperCase(hashedPassword)) if isOldHashPassword: # Start loading screen with warning self.events.emit(SIGNAL_REENCRYPTION_PROCESS_STARTED, Args()) # Save tmp properties so that we can login after the timer self.tmpAccount = account - self.tmpPassword = password self.tmpHashedPassword = hashedPassword self.tmpThumbnailImage = thumbnailImage self.tmpLargeImage = largeImage @@ -722,9 +719,8 @@ QtObject: proc onWaitForReencryptionTimeout(self: Service, response: string) {.slot.} = # Reencryption (can freeze and take up to 30 minutes) - let pwd = self.tmpPassword - self.tmpPassword = "" # Clear the password from memory as fast as possible - discard status_privacy.lowerDatabasePassword(self.tmpAccount.keyUid, pwd) + let oldHashedPassword = hashedPasswordToUpperCase(self.tmpHashedPassword) + discard status_privacy.changeDatabaseHashedPassword(self.tmpAccount.keyUid, oldHashedPassword, self.tmpHashedPassword) # Normal login after reencryption self.doLogin(self.tmpAccount, self.tmpHashedPassword, self.tmpThumbnailImage, self.tmpLargeImage, self.tmpNodeCfg) @@ -833,4 +829,4 @@ QtObject: return false proc getKdfIterations*(self: Service): int = - return KDF_ITERATIONS \ No newline at end of file + return KDF_ITERATIONS diff --git a/src/backend/core.nim b/src/backend/core.nim index c73c5dc785..c16820001c 100644 --- a/src/backend/core.nim +++ b/src/backend/core.nim @@ -78,11 +78,10 @@ proc sendTransaction*(chainId: int, inputJSON: string, password: string): RpcRes raise newException(RpcException, e.msg) -proc migrateKeyStoreDir*(account: string, password: string, oldKeystoreDir: string, multiaccountKeystoreDir: string) +proc migrateKeyStoreDir*(account: string, hashedPassword: string, oldKeystoreDir: string, multiaccountKeystoreDir: string) {.raises: [RpcException, ValueError, Defect, SerializationError].} = try: - var hashed_password = "0x" & $keccak_256.digest(password) - discard status_go.migrateKeyStoreDir(account, hashed_password, oldKeystoreDir, multiaccountKeystoreDir) + discard status_go.migrateKeyStoreDir(account, hashedPassword, oldKeystoreDir, multiaccountKeystoreDir) except Exception as e: error "error migrating keystore dir", account, exception=e.msg raise newException(RpcException, e.msg) diff --git a/src/backend/privacy.nim b/src/backend/privacy.nim index 7f11c1dece..e243b0051f 100644 --- a/src/backend/privacy.nim +++ b/src/backend/privacy.nim @@ -9,29 +9,21 @@ export response_type logScope: topics = "rpc-privacy" -proc changeDatabasePassword*(keyUID: string, password: string, newPassword: string): RpcResponse[JsonNode] +proc changeDatabaseHashedPassword*(keyUID: string, oldHashedPassword: string, newHashedPassword: string): RpcResponse[JsonNode] {.raises: [Exception].} = try: - let hashedPassword = hashPassword(password) - let hashedNewPassword = hashPassword(newPassword) - let response = status_go.changeDatabasePassword(keyUID, hashedPassword, hashedNewPassword) + let response = status_go.changeDatabasePassword(keyUID, oldHashedPassword, newHashedPassword) result.result = Json.decode(response, JsonNode) except RpcException as e: error "error", methodName = "changeDatabasePassword", exception=e.msg raise newException(RpcException, e.msg) -proc lowerDatabasePassword*(keyUID: string, password: string): RpcResponse[JsonNode] +proc changeDatabasePassword*(keyUID: string, password: string, newPassword: string): RpcResponse[JsonNode] {.raises: [Exception].} = - try: - let hashedPassword = hashPassword(password, lower=false) - let hashedNewPassword = hashPassword(password) - let response = status_go.changeDatabasePassword(keyUID, hashedPassword, hashedNewPassword) - result.result = Json.decode(response, JsonNode) - except RpcException as e: - error "error", methodName = "lowerDatabasePassword", exception=e.msg - raise newException(RpcException, e.msg) - + let hashedPassword = hashPassword(password) + let hashedNewPassword = hashPassword(newPassword) + return changeDatabaseHashedPassword(keyUID, hashedPassword, hashedNewPassword) proc getLinkPreviewWhitelist*(): RpcResponse[JsonNode] {.raises: [Exception].} = let payload = %* [] - result = callPrivateRPC("getLinkPreviewWhitelist".prefix, payload) \ No newline at end of file + result = callPrivateRPC("getLinkPreviewWhitelist".prefix, payload)