mirror of
https://github.com/status-im/status-desktop.git
synced 2025-01-12 07:14:37 +00:00
fix: checksum validation (#15915)
* feat: checksum validation added to adding saved addresses Fixes: #15772 * feat: checksum validation added to adding watch only address Fixes: #15779
This commit is contained in:
parent
63076e6ecc
commit
7dc08731f4
@ -71,3 +71,6 @@ proc hasPairedDevices*(self: Controller): bool =
|
|||||||
|
|
||||||
proc reloadAccountTokens*(self: Controller) =
|
proc reloadAccountTokens*(self: Controller) =
|
||||||
self.walletAccountService.reloadAccountTokens()
|
self.walletAccountService.reloadAccountTokens()
|
||||||
|
|
||||||
|
proc isChecksumValidForAddress*(self: Controller, address: string): bool =
|
||||||
|
return self.walletAccountService.isChecksumValidForAddress(address)
|
@ -123,3 +123,6 @@ method canProfileProveOwnershipOfProvidedAddresses*(self: AccessInterface, addre
|
|||||||
|
|
||||||
method reloadAccountTokens*(self: AccessInterface) {.base.} =
|
method reloadAccountTokens*(self: AccessInterface) {.base.} =
|
||||||
raise newException(ValueError, "No implementation available")
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
|
method isChecksumValidForAddress*(self: AccessInterface, address: string): bool {.base.} =
|
||||||
|
raise newException(ValueError, "No implementation available")
|
||||||
|
@ -539,3 +539,6 @@ method canProfileProveOwnershipOfProvidedAddresses*(self: Module, addresses: str
|
|||||||
method reloadAccountTokens*(self: Module) =
|
method reloadAccountTokens*(self: Module) =
|
||||||
self.view.setIsAccountTokensReloading(true)
|
self.view.setIsAccountTokensReloading(true)
|
||||||
self.controller.reloadAccountTokens()
|
self.controller.reloadAccountTokens()
|
||||||
|
|
||||||
|
method isChecksumValidForAddress*(self: Module, address: string): bool =
|
||||||
|
return self.controller.isChecksumValidForAddress(address)
|
@ -316,3 +316,5 @@ QtObject:
|
|||||||
read = getIsAccountTokensReloading
|
read = getIsAccountTokensReloading
|
||||||
notify = isAccountTokensReloadingChanged
|
notify = isAccountTokensReloadingChanged
|
||||||
|
|
||||||
|
proc isChecksumValidForAddress*(self: View, address: string): bool {.slot.} =
|
||||||
|
return self.delegate.isChecksumValidForAddress(address)
|
@ -252,6 +252,9 @@ proc getNumOfAddressesToGenerateForKeypair*(self: Controller, keyUid: string): i
|
|||||||
proc resolveSuggestedPathForKeypair*(self: Controller, keyUid: string): string =
|
proc resolveSuggestedPathForKeypair*(self: Controller, keyUid: string): string =
|
||||||
return self.walletAccountService.resolveSuggestedPathForKeypair(keyUid)
|
return self.walletAccountService.resolveSuggestedPathForKeypair(keyUid)
|
||||||
|
|
||||||
|
proc isChecksumValidForAddress*(self: Controller, address: string): bool =
|
||||||
|
return self.walletAccountService.isChecksumValidForAddress(address)
|
||||||
|
|
||||||
proc remainingAccountCapacity*(self: Controller): int =
|
proc remainingAccountCapacity*(self: Controller): int =
|
||||||
return self.walletAccountService.remainingAccountCapacity()
|
return self.walletAccountService.remainingAccountCapacity()
|
||||||
|
|
||||||
|
@ -107,6 +107,9 @@ method removingSavedAddressConfirmed*(self: AccessInterface, address: string) {.
|
|||||||
method savedAddressDeleted*(self: AccessInterface, address: string, errorMsg: string) {.base.} =
|
method savedAddressDeleted*(self: AccessInterface, address: string, errorMsg: string) {.base.} =
|
||||||
raise newException(ValueError, "No implementation available")
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
|
method isChecksumValidForAddress*(self: AccessInterface, address: string): bool {.base.} =
|
||||||
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
method remainingAccountCapacity*(self: AccessInterface): int {.base.} =
|
method remainingAccountCapacity*(self: AccessInterface): int {.base.} =
|
||||||
raise newException(ValueError, "No implementation available")
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
|
@ -736,6 +736,9 @@ method buildNewSeedPhraseKeypairAndAddItToOrigin*[T](self: Module[T]) =
|
|||||||
derivedFrom = genAcc.address)
|
derivedFrom = genAcc.address)
|
||||||
self.setItemForSelectedOrigin(item)
|
self.setItemForSelectedOrigin(item)
|
||||||
|
|
||||||
|
method isChecksumValidForAddress*[T](self: Module[T], address: string): bool =
|
||||||
|
return self.controller.isChecksumValidForAddress(address)
|
||||||
|
|
||||||
method remainingAccountCapacity*[T](self: Module[T]): int =
|
method remainingAccountCapacity*[T](self: Module[T]): int =
|
||||||
return self.controller.remainingAccountCapacity()
|
return self.controller.remainingAccountCapacity()
|
||||||
|
|
||||||
|
@ -364,6 +364,9 @@ QtObject:
|
|||||||
proc removingSavedAddressRejected*(self: View) {.slot.} =
|
proc removingSavedAddressRejected*(self: View) {.slot.} =
|
||||||
self.setDisablePopup(false)
|
self.setDisablePopup(false)
|
||||||
|
|
||||||
|
proc isChecksumValidForAddress*(self: View, address: string): bool {.slot.} =
|
||||||
|
return self.delegate.isChecksumValidForAddress(address)
|
||||||
|
|
||||||
proc remainingAccountCapacity*(self: View): int {.slot.} =
|
proc remainingAccountCapacity*(self: View): int {.slot.} =
|
||||||
return self.delegate.remainingAccountCapacity()
|
return self.delegate.remainingAccountCapacity()
|
||||||
|
|
||||||
|
@ -92,6 +92,17 @@ QtObject:
|
|||||||
result.networkService = networkService
|
result.networkService = networkService
|
||||||
result.currencyService = currencyService
|
result.currencyService = currencyService
|
||||||
|
|
||||||
|
proc isChecksumValidForAddress*(self: Service, address: string): bool =
|
||||||
|
var updated = false
|
||||||
|
try:
|
||||||
|
let response = backend.isChecksumValidForAddress(address)
|
||||||
|
if not response.error.isNil:
|
||||||
|
error "status-go error", procName="isChecksumValidForAddress", errCode=response.error.code, errDesription=response.error.message
|
||||||
|
return response.result.getBool
|
||||||
|
except Exception as e:
|
||||||
|
error "error: ", procName="isChecksumValidForAddress", errName=e.name, errDesription=e.msg
|
||||||
|
|
||||||
|
|
||||||
include service_account
|
include service_account
|
||||||
include service_token
|
include service_token
|
||||||
include service_keycard
|
include service_keycard
|
||||||
|
@ -332,3 +332,6 @@ rpc(getBalancesByChain, "wallet"):
|
|||||||
|
|
||||||
rpc(restartWalletReloadTimer, "wallet"):
|
rpc(restartWalletReloadTimer, "wallet"):
|
||||||
discard
|
discard
|
||||||
|
|
||||||
|
rpc(isChecksumValidForAddress, "wallet"):
|
||||||
|
address: string
|
||||||
|
22
ui/StatusQ/src/StatusQ/Core/StatusIconWithTooltip.qml
Normal file
22
ui/StatusQ/src/StatusQ/Core/StatusIconWithTooltip.qml
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import QtQuick 2.13
|
||||||
|
import QtQuick.Controls 2.15
|
||||||
|
|
||||||
|
import StatusQ.Controls 0.1
|
||||||
|
|
||||||
|
StatusIcon {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property string tooltipText
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: tooltipSensor
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusToolTip {
|
||||||
|
visible: tooltipSensor.containsMouse && !!text
|
||||||
|
text: root.tooltipText
|
||||||
|
}
|
||||||
|
}
|
@ -7,6 +7,7 @@ StatusCenteredFlow 0.1 StatusCenteredFlow.qml
|
|||||||
StatusFontSettings 0.1 StatusFontSettings.qml
|
StatusFontSettings 0.1 StatusFontSettings.qml
|
||||||
StatusGridView 0.1 StatusGridView.qml
|
StatusGridView 0.1 StatusGridView.qml
|
||||||
StatusIcon 0.1 StatusIcon.qml
|
StatusIcon 0.1 StatusIcon.qml
|
||||||
|
StatusIconWithTooltip 0.1 StatusIconWithTooltip.qml
|
||||||
StatusIdenticonRingSettings 0.1 StatusIdenticonRingSettings.qml
|
StatusIdenticonRingSettings 0.1 StatusIdenticonRingSettings.qml
|
||||||
StatusListView 0.1 StatusListView.qml
|
StatusListView 0.1 StatusListView.qml
|
||||||
StatusModalHeaderSettings 0.1 StatusModalHeaderSettings.qml
|
StatusModalHeaderSettings 0.1 StatusModalHeaderSettings.qml
|
||||||
|
@ -176,6 +176,7 @@
|
|||||||
<file>StatusQ/Core/StatusFontSettings.qml</file>
|
<file>StatusQ/Core/StatusFontSettings.qml</file>
|
||||||
<file>StatusQ/Core/StatusGridView.qml</file>
|
<file>StatusQ/Core/StatusGridView.qml</file>
|
||||||
<file>StatusQ/Core/StatusIcon.qml</file>
|
<file>StatusQ/Core/StatusIcon.qml</file>
|
||||||
|
<file>StatusQ/Core/StatusIconWithTooltip.qml</file>
|
||||||
<file>StatusQ/Core/StatusIdenticonRingSettings.qml</file>
|
<file>StatusQ/Core/StatusIdenticonRingSettings.qml</file>
|
||||||
<file>StatusQ/Core/StatusListView.qml</file>
|
<file>StatusQ/Core/StatusListView.qml</file>
|
||||||
<file>StatusQ/Core/StatusModalHeaderSettings.qml</file>
|
<file>StatusQ/Core/StatusModalHeaderSettings.qml</file>
|
||||||
|
@ -119,6 +119,8 @@ StatusModal {
|
|||||||
|| chainShortNamesDirty && (!d.editMode || d.storedChainShortNames !== d.chainShortNames)
|
|| chainShortNamesDirty && (!d.editMode || d.storedChainShortNames !== d.chainShortNames)
|
||||||
|| d.colorId.toUpperCase() !== d.storedColorId.toUpperCase()
|
|| d.colorId.toUpperCase() !== d.storedColorId.toUpperCase()
|
||||||
|
|
||||||
|
property bool incorrectChecksum: false
|
||||||
|
|
||||||
|
|
||||||
readonly property var chainPrefixRegexPattern: /[^:]+\:?|:/g
|
readonly property var chainPrefixRegexPattern: /[^:]+\:?|:/g
|
||||||
readonly property bool addressInputIsENS: !!d.ens &&
|
readonly property bool addressInputIsENS: !!d.ens &&
|
||||||
@ -231,6 +233,13 @@ StatusModal {
|
|||||||
addressInput.errorMessageCmp.visible = true
|
addressInput.errorMessageCmp.visible = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function checkIfAddressChecksumIsValid() {
|
||||||
|
d.incorrectChecksum = false
|
||||||
|
if (d.addressInputIsAddress) {
|
||||||
|
d.incorrectChecksum = !root.store.isChecksumValidForAddress(d.address)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function checkForAddressInputErrorsWarnings() {
|
function checkForAddressInputErrorsWarnings() {
|
||||||
addressInput.errorMessageCmp.visible = false
|
addressInput.errorMessageCmp.visible = false
|
||||||
addressInput.errorMessageCmp.color = Theme.palette.dangerColor1
|
addressInput.errorMessageCmp.color = Theme.palette.dangerColor1
|
||||||
@ -261,6 +270,7 @@ StatusModal {
|
|||||||
networkSelector.state = ""
|
networkSelector.state = ""
|
||||||
if (d.addressInputIsAddress) {
|
if (d.addressInputIsAddress) {
|
||||||
d.checkForAddressInputOwningErrorsWarnings()
|
d.checkForAddressInputOwningErrorsWarnings()
|
||||||
|
d.checkIfAddressChecksumIsValid()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -453,7 +463,7 @@ StatusModal {
|
|||||||
enabled: !(d.editMode || d.addAddress)
|
enabled: !(d.editMode || d.addAddress)
|
||||||
input.edit.textFormat: TextEdit.RichText
|
input.edit.textFormat: TextEdit.RichText
|
||||||
input.rightComponent: (d.resolvingEnsNameInProgress || d.checkingContactsAddressInProgress) ?
|
input.rightComponent: (d.resolvingEnsNameInProgress || d.checkingContactsAddressInProgress) ?
|
||||||
loadingIndicator : null
|
loadingIndicator : d.incorrectChecksum? incorrectChecksumComponent : null
|
||||||
input.asset.name: d.addressInputValid && !d.editMode ? "checkbox" : ""
|
input.asset.name: d.addressInputValid && !d.editMode ? "checkbox" : ""
|
||||||
input.asset.color: enabled ? Theme.palette.primaryColor1 : Theme.palette.baseColor1
|
input.asset.color: enabled ? Theme.palette.primaryColor1 : Theme.palette.baseColor1
|
||||||
input.asset.width: 17
|
input.asset.width: 17
|
||||||
@ -472,6 +482,18 @@ StatusModal {
|
|||||||
StatusLoadingIndicator {}
|
StatusLoadingIndicator {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: incorrectChecksumComponent
|
||||||
|
|
||||||
|
StatusIconWithTooltip {
|
||||||
|
icon: "warning"
|
||||||
|
width: 20
|
||||||
|
height: 20
|
||||||
|
color: Theme.palette.warningColor1
|
||||||
|
tooltipText: qsTr("Checksum of the entered address is incorrect")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onTextChanged: {
|
onTextChanged: {
|
||||||
if (skipTextUpdate || !d.initialized)
|
if (skipTextUpdate || !d.initialized)
|
||||||
return
|
return
|
||||||
|
@ -304,6 +304,10 @@ QtObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isChecksumValidForAddress(address) {
|
||||||
|
return root.walletSectionInst.isChecksumValidForAddress(address)
|
||||||
|
}
|
||||||
|
|
||||||
function getNameForAddress(address) {
|
function getNameForAddress(address) {
|
||||||
var name = getNameForWalletAddress(address)
|
var name = getNameForWalletAddress(address)
|
||||||
if (name.length === 0) {
|
if (name.length === 0) {
|
||||||
|
@ -20,6 +20,16 @@ Column {
|
|||||||
addressInput.reset()
|
addressInput.reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: d
|
||||||
|
|
||||||
|
property bool incorrectChecksum: false
|
||||||
|
|
||||||
|
function checkIfAddressChecksumIsValid(address) {
|
||||||
|
d.incorrectChecksum = !root.store.isChecksumValidForAddress(address)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
StatusInput {
|
StatusInput {
|
||||||
id: addressInput
|
id: addressInput
|
||||||
objectName: "AddAccountPopup-WatchOnlyAddress"
|
objectName: "AddAccountPopup-WatchOnlyAddress"
|
||||||
@ -29,14 +39,27 @@ Column {
|
|||||||
label: qsTr("Ethereum address or ENS name")
|
label: qsTr("Ethereum address or ENS name")
|
||||||
placeholderText: qsTr("Type or paste ETH address")
|
placeholderText: qsTr("Type or paste ETH address")
|
||||||
input.multiline: true
|
input.multiline: true
|
||||||
input.rightComponent: StatusButton {
|
input.rightComponent: Row {
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
spacing: 8
|
||||||
borderColor: Theme.palette.primaryColor1
|
|
||||||
size: StatusBaseButton.Size.Tiny
|
StatusIconWithTooltip {
|
||||||
text: qsTr("Paste")
|
visible: d.incorrectChecksum
|
||||||
onClicked: {
|
icon: "warning"
|
||||||
addressInput.text = ""
|
width: 20
|
||||||
addressInput.input.edit.paste()
|
height: 20
|
||||||
|
color: Theme.palette.warningColor1
|
||||||
|
tooltipText: qsTr("Checksum of the entered address is incorrect")
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusButton {
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
borderColor: Theme.palette.primaryColor1
|
||||||
|
size: StatusBaseButton.Size.Tiny
|
||||||
|
text: qsTr("Paste")
|
||||||
|
onClicked: {
|
||||||
|
addressInput.text = ""
|
||||||
|
addressInput.input.edit.paste()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
validators: [
|
validators: [
|
||||||
@ -46,8 +69,11 @@ Column {
|
|||||||
]
|
]
|
||||||
|
|
||||||
onTextChanged: {
|
onTextChanged: {
|
||||||
|
d.incorrectChecksum = false
|
||||||
if (addressInput.valid) {
|
if (addressInput.valid) {
|
||||||
root.store.changeWatchOnlyAccountAddressPostponed(text.trim())
|
const trimmedText = text.trim()
|
||||||
|
root.store.changeWatchOnlyAccountAddressPostponed(trimmedText)
|
||||||
|
d.checkIfAddressChecksumIsValid(trimmedText)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
root.store.cleanWatchOnlyAccountAddress()
|
root.store.cleanWatchOnlyAccountAddress()
|
||||||
|
@ -167,6 +167,10 @@ BasePopupStore {
|
|||||||
root.addAccountModule.startScanningForActivity()
|
root.addAccountModule.startScanningForActivity()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isChecksumValidForAddress(address) {
|
||||||
|
return root.addAccountModule.isChecksumValidForAddress(address)
|
||||||
|
}
|
||||||
|
|
||||||
function remainingAccountCapacity() {
|
function remainingAccountCapacity() {
|
||||||
return root.addAccountModule.remainingAccountCapacity()
|
return root.addAccountModule.remainingAccountCapacity()
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user