diff --git a/src/app/provider/core.nim b/src/app/provider/core.nim index 8311a5fce7..7652f999db 100644 --- a/src/app/provider/core.nim +++ b/src/app/provider/core.nim @@ -22,4 +22,4 @@ proc delete*(self: Web3ProviderController) = delete self.view proc init*(self: Web3ProviderController) = - discard + self.view.init() diff --git a/src/app/provider/view.nim b/src/app/provider/view.nim index 7501099141..dc6717146b 100644 --- a/src/app/provider/view.nim +++ b/src/app/provider/view.nim @@ -6,6 +6,7 @@ import ../../status/libstatus/settings as status_settings import json, json_serialization, sets, strutils import chronicles import nbaser +import stew/byteutils from base32 import nil const AUTH_METHODS = toHashSet(["eth_accounts", "eth_coinbase", "eth_sendTransaction", "eth_sign", "keycard_signTypedData", "eth_signTypedData", "personal_sign", "personal_ecRecover"]) @@ -41,6 +42,7 @@ type messageId: JsonNode payload: Payload request: string + hostname: string APIRequest = ref object isAllowed: bool @@ -61,6 +63,7 @@ proc toWeb3SendAsyncReadOnly(message: string): Web3SendAsyncReadOnly = result = Web3SendAsyncReadOnly( messageId: data["messageId"], request: $data["payload"], + hostname: data{"hostname"}.getStr(), payload: Payload( id: data["payload"]["id"], rpcMethod: data["payload"]["method"].getStr() @@ -80,6 +83,7 @@ proc toAPIRequest(message: string): APIRequest = QtObject: type Web3ProviderView* = ref object of QObject status*: Status + dappsAddress*: string proc setup(self: Web3ProviderView) = self.QObject.setup @@ -91,10 +95,11 @@ QtObject: new(result, delete) result = Web3ProviderView() result.status = status + result.dappsAddress = "" result.setup - proc process(data: Web3SendAsyncReadOnly): string = - if AUTH_METHODS.contains(data.payload.rpcMethod): # TODO: && if the dapp does not have the "web3" permission: + proc process(data: Web3SendAsyncReadOnly, status: Status): string = + if AUTH_METHODS.contains(data.payload.rpcMethod) and not status.permissions.hasPermission(data.hostname, Permission.Web3): return $ %* { "type": ResponseTypes.Web3SendAsyncCallback, "messageId": data.messageId, @@ -158,7 +163,7 @@ QtObject: proc postMessage*(self: Web3ProviderView, message: string): string {.slot.} = case message.requestType(): - of RequestTypes.Web3SendAsyncReadOnly: message.toWeb3SendAsyncReadOnly().process() + of RequestTypes.Web3SendAsyncReadOnly: message.toWeb3SendAsyncReadOnly().process(self.status) of RequestTypes.HistoryStateChanged: """{"type":"TODO-IMPLEMENT-THIS"}""" ############# TODO: of RequestTypes.APIRequest: message.toAPIRequest().process(self.status) else: """{"type":"TODO-IMPLEMENT-THIS"}""" ##################### TODO: @@ -168,9 +173,23 @@ QtObject: QtProperty[int] networkId: read = getNetworkId - proc toString(bytes: openarray[byte]): string = - result = newString(bytes.len) - copyMem(result[0].addr, bytes[0].unsafeAddr, bytes.len) + proc dappsAddressChanged(self: Web3ProviderView, address: string) {.signal.} + + proc getDappsAddress(self: Web3ProviderView): string {.slot.} = + result = self.dappsAddress + + proc setDappsAddress(self: Web3ProviderView, address: string) {.slot.} = + self.dappsAddress = address + self.status.saveSetting(Setting.DappsAddress, address) + self.dappsAddressChanged(address) + + QtProperty[string] dappsAddress: + read = getDappsAddress + notify = dappsAddressChanged + write = setDappsAddress + + proc clearPermissions*(self: Web3ProviderView): string {.slot.} = + self.status.permissions.clearPermissions() proc ensResourceURL*(self: Web3ProviderView, ens: string, url: string): string {.slot.} = # TODO: add support for swarm: "swarm-gateways.net/bzz:/...." and ipns @@ -180,7 +199,7 @@ QtObject: return url_replaceHostAndAddPath(url, url_host(url), IPFS_SCHEME) let decodedContentHash = contentHash.decodeContentHash() - let base32Hash = base32.encode(base58.decode(decodedContentHash).toString()).toLowerAscii().replace("=", "") + let base32Hash = base32.encode(string.fromBytes(base58.decode(decodedContentHash))).toLowerAscii().replace("=", "") result = url_replaceHostAndAddPath(url, base32Hash & IPFS_GATEWAY, IPFS_SCHEME) proc replaceHostByENS*(self: Web3ProviderView, url: string, ens: string): string {.slot.} = @@ -188,3 +207,6 @@ QtObject: proc getHost*(self: Web3ProviderView, url: string): string {.slot.} = result = url_host(url) + + proc init*(self: Web3ProviderView) = + self.setDappsAddress(status_settings.getSetting[string](Setting.DappsAddress)) diff --git a/src/app/wallet/views/account_list.nim b/src/app/wallet/views/account_list.nim index 924ed6cecb..b6eb51b252 100644 --- a/src/app/wallet/views/account_list.nim +++ b/src/app/wallet/views/account_list.nim @@ -16,6 +16,7 @@ type FiatBalance = UserRole + 5 Assets = UserRole + 6 WalletType = UserRole + 7 + Wallet = UserRole + 8 QtObject: type AccountList* = ref object of QAbstractListModel @@ -94,6 +95,7 @@ QtObject: of AccountRoles.FiatBalance: result = newQVariant(fmt"{account.realFiatBalance:>.2f}") of AccountRoles.Assets: result = newQVariant(accountView.assets) of AccountRoles.WalletType: result = newQVariant(account.walletType) + of AccountRoles.Wallet: result = newQVariant(account.wallet) method roleNames(self: AccountList): Table[int, string] = { AccountRoles.Name.int:"name", @@ -102,6 +104,7 @@ QtObject: AccountRoles.Balance.int:"balance", AccountRoles.FiatBalance.int:"fiatBalance", AccountRoles.Assets.int:"assets", + AccountRoles.Wallet.int:"isWallet", AccountRoles.WalletType.int:"walletType" }.toTable proc addAccountToList*(self: AccountList, account: WalletAccount) = diff --git a/src/nim_status_client.nim b/src/nim_status_client.nim index 18d784b8f5..6b450dd049 100644 --- a/src/nim_status_client.nim +++ b/src/nim_status_client.nim @@ -97,6 +97,7 @@ proc mainProc() = status.startMessenger() profile.init(args.account) wallet.init() + provider.init() chat.init() utilsController.init() diff --git a/src/status/libstatus/wallet.nim b/src/status/libstatus/wallet.nim index 62c3ac6578..7612e308e4 100644 --- a/src/status/libstatus/wallet.nim +++ b/src/status/libstatus/wallet.nim @@ -22,8 +22,8 @@ proc getWalletAccounts*(): seq[WalletAccount] = publicKey: if (account.hasKey("public-key")): $account["public-key"].getStr else: "", name: $account["name"].getStr, iconColor: $account["color"].getStr, - wallet: $account["wallet"].getStr == "true", - chat: $account["chat"].getStr == "false", + wallet: account["wallet"].getBool, + chat: account["chat"].getBool, )) result = walletAccounts except: diff --git a/src/status/permissions.nim b/src/status/permissions.nim index d436e3da36..28fa50da4a 100644 --- a/src/status/permissions.nim +++ b/src/status/permissions.nim @@ -58,5 +58,10 @@ proc revokePermission*(self: PermissionsModel, dapp: string, permission: Permiss discard proc clearPermissions*(self: PermissionsModel, dapp: string) = - # TODO: implement - discard \ No newline at end of file + # TODO implement + discard + +proc clearPermissions*(self: PermissionsModel) = + let response = callPrivateRPC("permissions_getDappPermissions") + for dapps in response.parseJson["result"].getElems(): + discard callPrivateRPC("permissions_deleteDappPermissions", %*[dapps["dapp"].getStr()]) diff --git a/ui/app/AppLayouts/Browser/BrowserLayout.qml b/ui/app/AppLayouts/Browser/BrowserLayout.qml index f5dd8a8a3f..df94f254e8 100644 --- a/ui/app/AppLayouts/Browser/BrowserLayout.qml +++ b/ui/app/AppLayouts/Browser/BrowserLayout.qml @@ -412,6 +412,56 @@ Item { } } + Menu { + id: accountsMenu + Repeater { + model: walletModel.accounts + MenuItem { + visible: model.isWallet || model.walletType === "generated" + height: visible ? 40 : 0 + text: model.name + onTriggered: { + web3Provider.dappsAddress = model.address; + web3Provider.clearPermissions(); + for (let i = 0; i < tabs.count; ++i){ + tabs.getTab(i).item.reload(); + } + } + checked: { + if(web3Provider.dappsAddress == model.address){ + txtAccountBtn.text = model.name.substr(0, 1); + rectAccountBtn.color = model.iconColor + return true; + } + return false; + } + } + } + } + + ToolButton { + id: accountBtn + Rectangle { + id: rectAccountBtn + anchors.centerIn: parent + width: 20 + height: width + radius: width / 2 + color: "" + StyledText { + id: txtAccountBtn + text: "" + opacity: 0.7 + font.weight: Font.Bold + font.pixelSize: 14 + color: "white" + anchors.horizontalCenter: parent.horizontalCenter + anchors.verticalCenter: parent.verticalCenter + } + } + onClicked: accountsMenu.popup(accountBtn.x, accountBtn.y + accountBtn.height) + } + Menu { id: settingsMenu y: settingsMenuButton.height