feat(@settings): new dapp permissions view

This commit is contained in:
Anthony Laibe 2022-03-04 10:09:58 +01:00 committed by Anthony Laibe
parent 6e0471c943
commit 0908b13ad5
37 changed files with 480 additions and 529 deletions

View File

@ -0,0 +1,87 @@
import NimQml, Tables, strutils, strformat
import ../../../../../app_service/service/wallet_account/service as wallet_account_service
type
ModelRole {.pure.} = enum
Name = UserRole + 1
Address
Color
QtObject:
type
AccountsModel* = ref object of QAbstractListModel
items: seq[WalletAccountDto]
proc delete(self: AccountsModel) =
self.items = @[]
self.QAbstractListModel.delete
proc setup(self: AccountsModel) =
self.QAbstractListModel.setup
proc newAccountsModel*(): AccountsModel =
new(result, delete)
result.setup
proc `$`*(self: AccountsModel): string =
for i in 0 ..< self.items.len:
result &= fmt"""
[{i}]:({$self.items[i].name})
"""
proc modelChanged(self: AccountsModel) {.signal.}
proc countChanged(self: AccountsModel) {.signal.}
proc getCount(self: AccountsModel): int {.slot.} =
self.items.len
QtProperty[int] count:
read = getCount
notify = countChanged
method rowCount(self: AccountsModel, index: QModelIndex = nil): int =
return self.items.len
method roleNames(self: AccountsModel): Table[int, string] =
{
ModelRole.Name.int:"name",
ModelRole.Address.int:"address",
ModelRole.Color.int:"color",
}.toTable
method data(self: AccountsModel, 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.Name:
result = newQVariant(item.name)
of ModelRole.Address:
result = newQVariant(item.address)
of ModelRole.Color:
result = newQVariant(item.color)
proc addItem*(self: AccountsModel, item: WalletAccountDto) =
let parentModelIndex = newQModelIndex()
defer: parentModelIndex.delete
for i in self.items:
if i == item:
return
self.beginInsertRows(parentModelIndex, self.items.len, self.items.len)
self.items.add(item)
self.endInsertRows()
self.modelChanged()
self.countChanged()
proc clear*(self: AccountsModel) {.slot.} =
self.beginResetModel()
self.items = @[]
self.endResetModel()
self.countChanged()

View File

@ -4,20 +4,25 @@ import controller_interface
import io_interface
import options
import ../../../../../app_service/service/dapp_permissions/service as dapp_permissions_service
import ../../../../../app_service/service/wallet_account/service as wallet_account_service
export controller_interface
type
Controller* = ref object of controller_interface.AccessInterface
delegate: io_interface.AccessInterface
dappPermissionsService: dapp_permissions_service.ServiceInterface
dappPermissionsService: dapp_permissions_service.Service
walletAccountService: wallet_account_service.Service
proc newController*(delegate: io_interface.AccessInterface,
dappPermissionsService: dapp_permissions_service.ServiceInterface):
Controller =
proc newController*(
delegate: io_interface.AccessInterface,
dappPermissionsService: dapp_permissions_service.Service,
walletAccountService: wallet_account_service.Service,
): Controller =
result = Controller()
result.delegate = delegate
result.dappPermissionsService = dappPermissionsService
result.walletAccountService = walletAccountService
method delete*(self: Controller) =
discard
@ -28,20 +33,23 @@ method init*(self: Controller) =
method getDapps*(self: Controller): seq[dapp_permissions_service.Dapp] =
return self.dappPermissionsService.getDapps()
method getDapp*(self: Controller, dapp:string): Option[dapp_permissions_service.Dapp] =
return self.dappPermissionsService.getDapp(dapp)
method getDapp*(self: Controller, dapp:string, address: string): Option[dapp_permissions_service.Dapp] =
return self.dappPermissionsService.getDapp(dapp, address)
method hasPermission*(self: Controller, dapp: string, permission: dapp_permissions_service.Permission):bool =
return self.dappPermissionsService.hasPermission(dapp, permission)
method hasPermission*(self: Controller, dapp: string, address: string, permission: dapp_permissions_service.Permission):bool =
return self.dappPermissionsService.hasPermission(dapp, address, permission)
method addPermission*(self: Controller, dapp: string, permission: dapp_permissions_service.Permission) =
discard self.dappPermissionsService.addPermission(dapp, permission)
method addPermission*(self: Controller, dapp: string, address: string, permission: dapp_permissions_service.Permission) =
discard self.dappPermissionsService.addPermission(dapp, address, permission)
method clearPermissions*(self: Controller, dapp: string) =
discard self.dappPermissionsService.clearPermissions(dapp)
method disconnectAddress*(self: Controller, dappName: string, address: string) =
discard self.dappPermissionsService.disconnectAddress(dappName, address)
method revokeAllPermisions*(self: Controller) =
discard self.dappPermissionsService.revokeAllPermisions()
method disconnect*(self: Controller, dappName: string) =
discard self.dappPermissionsService.disconnect(dappName)
method revokePermission*(self: Controller, dapp: string, permission: string) =
discard self.dappPermissionsService.revoke(dapp, permission.toPermission())
method removePermission*(self: Controller, dappName: string, address: string, permission: dapp_permissions_service.Permission) =
discard self.dappPermissionsService.removePermission(dappName, address, permission)
method getAccountForAddress*(self: Controller, address: string): WalletAccountDto =
return self.walletAccountService.getAccountByAddress(address)

View File

@ -1,4 +1,6 @@
import ../../../../../app_service/service/dapp_permissions/service_interface as dapp_permissions_service
import ../../../../../app_service/service/dapp_permissions/service as dapp_permissions_service
import ../../../../../app_service/service/wallet_account/service as wallet_account_service
import options
type
@ -14,20 +16,23 @@ method init*(self: AccessInterface) {.base.} =
method getDapps*(self: AccessInterface): seq[dapp_permissions_service.Dapp] {.base.} =
raise newException(ValueError, "No implementation available")
method getDapp*(self: AccessInterface, dapp: string): Option[dapp_permissions_service.Dapp] {.base.} =
method getDapp*(self: AccessInterface, dapp: string, address: string): Option[dapp_permissions_service.Dapp] {.base.} =
raise newException(ValueError, "No implementation available")
method addPermission*(self: AccessInterface, dapp: string, permission: dapp_permissions_service.Permission) {.base.} =
method addPermission*(self: AccessInterface, dapp: string, address: string, permission: dapp_permissions_service.Permission) {.base.} =
raise newException(ValueError, "No implementation available")
method hasPermission*(self: AccessInterface, dapp: string, permission: dapp_permissions_service.Permission):bool {.base.} =
method hasPermission*(self: AccessInterface, dapp: string, address: string, permission: dapp_permissions_service.Permission):bool {.base.} =
raise newException(ValueError, "No implementation available")
method clearPermissions*(self: AccessInterface, dapp: string) {.base.} =
method disconnectAddress*(self: AccessInterface, dapp: string, address: string) {.base.} =
raise newException(ValueError, "No implementation available")
method revokePermission*(self: AccessInterface, dapp: string, name: string) {.base.} =
method disconnect*(self: AccessInterface, dapp: string) {.base.} =
raise newException(ValueError, "No implementation available")
method revokeAllPermisions*(self: AccessInterface) {.base.} =
method removePermission*(self: AccessInterface, dapp: string, address: string, permission: dapp_permissions_service.Permission) {.base.} =
raise newException(ValueError, "No implementation available")
method getAccountForAddress*(self: AccessInterface, address: string): WalletAccountDto {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -1,13 +1,15 @@
import NimQml, Tables, strutils, strformat
import NimQml, Tables, strutils, strformat, json
import ./item
type
ModelRole {.pure.} = enum
Name = UserRole + 1
Accounts
QtObject:
type
DappsModel* = ref object of QAbstractListModel
items: seq[string]
items: seq[Item]
proc delete(self: DappsModel) =
self.items = @[]
@ -28,6 +30,8 @@ QtObject:
proc modelChanged(self: DappsModel) {.signal.}
proc countChanged(self: DappsModel) {.signal.}
proc getCount(self: DappsModel): int {.slot.} =
self.items.len
@ -40,7 +44,8 @@ QtObject:
method roleNames(self: DappsModel): Table[int, string] =
{
ModelRole.Name.int:"name"
ModelRole.Name.int:"name",
ModelRole.Accounts.int:"accounts"
}.toTable
method data(self: DappsModel, index: QModelIndex, role: int): QVariant =
@ -50,9 +55,22 @@ QtObject:
if (index.row < 0 or index.row >= self.items.len):
return
result = newQVariant(self.items[index.row])
let item = self.items[index.row]
let enumRole = role.ModelRole
case enumRole:
of ModelRole.Name:
result = newQVariant(item.name)
of ModelRole.Accounts:
result = newQVariant(item.accounts)
proc addItem*(self: DappsModel, item: string) =
proc rowData*(self: DappsModel, index: int, column: string): string {.slot.} =
if (index > self.items.len - 1):
return
let item = self.items[index]
case column:
of "name": result = item.name
proc addItem*(self: DappsModel, item: Item) =
let parentModelIndex = newQModelIndex()
defer: parentModelIndex.delete
@ -64,8 +82,10 @@ QtObject:
self.items.add(item)
self.endInsertRows()
self.modelChanged()
self.countChanged()
proc clear*(self: DappsModel) =
self.beginResetModel()
self.items = @[]
self.endResetModel()
self.countChanged()

View File

@ -1,4 +1,4 @@
import ../../../../../app_service/service/dapp_permissions/service_interface as dapp_permissions_service
import ../../../../../app_service/service/dapp_permissions/service as dapp_permissions_service
# Defines how parent module accesses this module
include ./private_interfaces/module_base_interface

View File

@ -0,0 +1,28 @@
import strformat
import ./permissions
import ./accounts
import ../../../../../app_service/service/wallet_account/service as wallet_account_service
type
Item* = object
name*: string
accounts*: AccountsModel
permissions*: PermissionsModel
proc initItem*(
name: string,
permissions: seq[string]
): Item =
result.name = name
result.accounts = newAccountsModel()
result.permissions = newPermissionsModel()
for p in permissions:
result.permissions.addItem(p)
proc `$`*(self: Item): string =
result = fmt"""Dapps(
name: {self.name}
]"""
proc addAccount*(self: Item, account: WalletAccountDto): void =
self.accounts.addItem(account)

View File

@ -1,11 +1,14 @@
import NimQml
import io_interface
import sequtils
import ../io_interface as delegate_interface
import view
import ./item
import sets
import controller
import ../../../../global/global_singleton
import ../../../../../app_service/service/dapp_permissions/service as dapp_permissions_service
import ../../../../../app_service/service/wallet_account/service as wallet_account_service
import options
export io_interface
@ -17,13 +20,17 @@ type
moduleLoaded: bool
controller: controller.AccessInterface
proc newModule*(delegate: delegate_interface.AccessInterface, dappPermissionsService: dapp_permissions_service.ServiceInterface): Module =
proc newModule*(
delegate: delegate_interface.AccessInterface,
dappPermissionsService: dapp_permissions_service.Service,
walletAccountServive: wallet_account_service.Service,
): Module =
result = Module()
result.delegate = delegate
result.view = view.newView(result)
result.viewVariant = newQVariant(result.view)
result.moduleLoaded = false
result.controller = controller.newController(result, dappPermissionsService)
result.controller = controller.newController(result, dappPermissionsService, walletAccountServive)
method delete*(self: Module) =
self.view.delete
@ -33,15 +40,27 @@ method delete*(self: Module) =
method fetchDapps*(self: Module) =
self.view.clearDapps()
let dapps = self.controller.getDapps()
for d in dapps:
self.view.addDapp(d.name)
var items: seq[Item] = @[]
method fetchPermissions(self: Module, dapp: string) =
self.view.clearPermissions()
let dapp = self.controller.getDapp(dapp)
if dapp.isSome:
for p in dapp.get().permissions.items:
self.view.addPermission($p)
for dapp in dapps:
var found = false
for item in items:
if item.name == dapp.name:
let account = self.controller.getAccountForAddress(dapp.address)
item.addAccount(account)
found = true
break
if not found:
let item = initItem(
dapp.name, dapp.permissions.mapIt($it)
)
items.add(item)
let account = self.controller.getAccountForAddress(dapp.address)
item.addAccount(account)
for item in items:
self.view.addDapp(item)
method load*(self: Module) =
singletonInstance.engine.setRootContextProperty("dappPermissionsModule", self.viewVariant)
@ -55,17 +74,21 @@ method viewDidLoad*(self: Module) =
self.moduleLoaded = true
self.delegate.dappsDidLoad()
method hasPermission*(self: Module, hostname: string, permission: string): bool =
self.controller.hasPermission(hostname, permission.toPermission())
method hasPermission*(self: Module, hostname: string, address: string, permission: string): bool =
self.controller.hasPermission(hostname, address, permission.toPermission())
method addPermission*(self: Module, hostname: string, permission: string) =
self.controller.addPermission(hostname, permission.toPermission())
method addPermission*(self: Module, hostname: string, address: string, permission: string) =
self.controller.addPermission(hostname, address, permission.toPermission())
self.fetchDapps()
method clearPermissions*(self: Module, dapp: string) =
self.controller.clearPermissions(dapp)
method removePermission*(self: Module, dapp: string, address: string, permission: string) =
self.controller.removePermission(dapp, address, permission.toPermission())
self.fetchDapps()
method revokeAllPermissions*(self: Module) =
self.controller.revokeAllPermisions()
method disconnectAddress*(self: Module, dapp: string, address: string) =
self.controller.disconnectAddress(dapp, address)
self.fetchDapps()
method revokePermission*(self: Module, dapp: string, name: string) =
self.controller.revokePermission(dapp, name)
method disconnect*(self: Module, dapp: string) =
self.controller.disconnect(dapp)
self.fetchDapps()

View File

@ -1,17 +1,17 @@
method hasPermission*(self: AccessInterface, hostname: string, permission: string): bool =
method hasPermission*(self: AccessInterface, hostname: string, address: string, permission: string): bool =
raise newException(ValueError, "No implementation available")
method clearPermissions*(self: AccessInterface, dapp: string) =
method disconnectAddress*(self: AccessInterface, dapp: string, address: string) {.base.} =
raise newException(ValueError, "No implementation available")
method revokePermission*(self: AccessInterface, dapp: string, name: string) =
method removePermission*(self: AccessInterface, dapp: string, address: string, permission: string) {.base.} =
raise newException(ValueError, "No implementation available")
method revokeAllPermissions*(self: AccessInterface) =
method disconnect*(self: AccessInterface, dapp: string) {.base.} =
raise newException(ValueError, "No implementation available")
method fetchDapps*(self: AccessInterface) =
raise newException(ValueError, "No implementation available")
method fetchPermissions*(self: AccessInterface, dapp: string) =
method fetchPermissions*(self: AccessInterface, dapp: string, address: string) =
raise newException(ValueError, "No implementation available")

View File

@ -1,5 +1,5 @@
method viewDidLoad*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method addPermission*(self: AccessInterface, hostname: string, permission: string) =
method addPermission*(self: AccessInterface, hostname: string, address: string, permission: string) =
raise newException(ValueError, "No implementation available")

View File

@ -1,84 +1,62 @@
import NimQml
import io_interface
import dapps
import permissions
import ./dapps
import ./item
QtObject:
type
View* = ref object of QObject
delegate: io_interface.AccessInterface
dappsModel: DappsModel
permissionsModel: PermissionsModel
dappsModelVariant: QVariant
permissionsModelVariant: QVariant
proc setup(self: View) =
self.QObject.setup
proc delete*(self: View) =
self.dappsModel.delete
self.permissionsModel.delete
self.dappsModelVariant.delete
self.permissionsModelVariant.delete
self.QObject.delete
proc newView*(delegate: io_interface.AccessInterface): View =
new(result, delete)
result.delegate = delegate
result.dappsModel = newDappsModel()
result.permissionsModel = newPermissionsModel()
result.dappsModelVariant = newQVariant(result.dappsModel)
result.permissionsModelVariant = newQVariant(result.permissionsModel)
result.setup()
proc load*(self: View) =
self.delegate.viewDidLoad()
proc addDapp*(self: View, item: string) =
proc addDapp*(self: View, item: Item) =
self.dappsModel.addItem(item)
proc addPermission*(self: View, item: string) =
self.permissionsModel.addItem(item)
proc modelChanged*(self: View) {.signal.}
proc getPermissionsModel(self: View): QVariant {.slot.} =
return self.permissionsModelVariant
proc getDappsModel(self: View): QVariant {.slot.} =
return self.dappsModelVariant
QtProperty[QVariant] permissions:
read = getPermissionsModel
notify = modelChanged
QtProperty[QVariant] dapps:
read = getDappsModel
notify = modelChanged
proc hasPermission(self: View, hostname: string, permission: string): bool {.slot.} =
return self.delegate.hasPermission(hostname, permission)
proc hasPermission(self: View, hostname: string, address: string, permission: string): bool {.slot.} =
return self.delegate.hasPermission(hostname, address, permission)
proc addPermission(self: View, hostname: string, permission: string) {.slot.} =
self.delegate.addPermission(hostname, permission)
proc addPermission(self: View, hostname: string, address: string, permission: string) {.slot.} =
self.delegate.addPermission(hostname, address, permission)
proc clearPermissions(self: View, dapp: string): string {.slot.} =
self.delegate.clearPermissions(dapp)
proc removePermission(self: View, dapp: string, address: string, permission: string): string {.slot.} =
self.delegate.removePermission(dapp, address, permission)
proc revokePermission(self: View, dapp: string, name: string) {.slot.} =
self.delegate.revokePermission(dapp, name)
proc disconnectAddress(self: View, dapp: string, address: string): string {.slot.} =
self.delegate.disconnectAddress(dapp, address)
proc revokeAllPermissions(self: View) {.slot.} =
self.delegate.revokeAllPermissions()
proc disconnect(self: View, dapp: string) {.slot.} =
self.delegate.disconnect(dapp)
proc clearDapps*(self: View) =
self.dappsModel.clear()
proc clearPermissions*(self: View) =
self.permissionsModel.clear()
proc fetchDapps(self: View) {.slot.} =
self.delegate.fetchDapps()
proc fetchPermissions(self: View, dapp: string) {.slot.} =
self.delegate.fetchPermissions(dapp)
self.delegate.fetchDapps()

View File

@ -10,6 +10,8 @@ import ../../../../app_service/service/bookmarks/service as bookmark_service
import ../../../../app_service/service/settings/service as settings_service
import ../../../../app_service/service/dapp_permissions/service as dapp_permissions_service
import ../../../../app_service/service/provider/service as provider_service
import ../../../../app_service/service/wallet_account/service as wallet_account_service
export io_interface
type
@ -25,16 +27,17 @@ type
proc newModule*(delegate: delegate_interface.AccessInterface,
bookmarkService: bookmark_service.ServiceInterface,
settingsService: settings_service.ServiceInterface,
dappPermissionsService: dapp_permissions_service.ServiceInterface,
providerService: provider_service.ServiceInterface): Module =
dappPermissionsService: dapp_permissions_service.Service,
providerService: provider_service.ServiceInterface,
walletAccountService: wallet_account_service.Service): Module =
result = Module()
result.delegate = delegate
result.view = view.newView(result)
result.viewVariant = newQVariant(result.view)
result.moduleLoaded = false
result.providerModule = provider_module.newModule(result, settingsService, dappPermissionsService, providerService)
result.providerModule = provider_module.newModule(result, settingsService, providerService)
result.bookmarkModule = bookmark_module.newModule(result, bookmarkService)
result.dappsModule = dapps_module.newModule(result, dappPermissionsService)
result.dappsModule = dapps_module.newModule(result, dappPermissionsService, walletAccountService)
method delete*(self: Module) =
self.view.delete

View File

@ -3,7 +3,6 @@ import controller_interface
import io_interface
import ../../../../../app_service/service/settings/service_interface as settings_service
import ../../../../../app_service/service/dapp_permissions/service as dapp_permissions_service
import ../../../../../app_service/service/provider/service_interface as provider_service
export controller_interface
@ -11,18 +10,15 @@ type
Controller* = ref object of controller_interface.AccessInterface
delegate: io_interface.AccessInterface
settingsService: settings_service.ServiceInterface
dappPermissionsService: dapp_permissions_service.ServiceInterface
providerService: provider_service.ServiceInterface
proc newController*(delegate: io_interface.AccessInterface,
settingsService: settings_service.ServiceInterface,
dappPermissionsService: dapp_permissions_service.ServiceInterface,
providerService: provider_service.ServiceInterface):
Controller =
result = Controller()
result.delegate = delegate
result.settingsService = settingsService
result.dappPermissionsService = dappPermissionsService
result.providerService = providerService
method delete*(self: Controller) =
@ -41,14 +37,8 @@ method setDappsAddress*(self: Controller, address: string) =
method getCurrentNetworkId*(self: Controller): int =
return self.settingsService.getCurrentNetworkId()
method disconnect*(self: Controller) =
discard self.dappPermissionsService.revoke("web3".toPermission())
method postMessage*(self: Controller, requestType: string, message: string): string =
return self.providerService.postMessage(requestType, message)
method hasPermission*(self: Controller, hostname: string, permission: string): bool =
return self.dappPermissionsService.hasPermission(hostname, permission.toPermission())
method ensResourceURL*(self: Controller, ens: string, url: string): (string, string, string, string, bool) =
return self.providerService.ensResourceURL(ens, url)

View File

@ -17,14 +17,8 @@ method setDappsAddress*(self: AccessInterface, address: string) {.base.} =
method getCurrentNetworkId*(self: AccessInterface): int {.base.} =
raise newException(ValueError, "No implementation available")
method disconnect*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method postMessage*(self: AccessInterface, requestType: string, message: string): string {.base.} =
raise newException(ValueError, "No implementation available")
method hasPermission*(self: AccessInterface, hostname: string, permission: string): bool {.base.} =
raise newException(ValueError, "No implementation available")
method ensResourceURL*(self: AccessInterface, ens: string, url: string): (string, string, string, string, bool) =
raise newException(ValueError, "No implementation available")

View File

@ -4,7 +4,6 @@ import view
import controller
import ../io_interface as delegate_interface
import ../../../../../app_service/service/settings/service_interface as settings_service
import ../../../../../app_service/service/dapp_permissions/service as dapp_permissions_service
import ../../../../../app_service/service/provider/service_interface as provider_service
import ../../../../global/global_singleton
export io_interface
@ -19,14 +18,13 @@ type
proc newModule*(delegate: delegate_interface.AccessInterface,
settingsService: settings_service.ServiceInterface,
dappPermissionsService: dapp_permissions_service.ServiceInterface,
providerService: provider_service.ServiceInterface): Module =
result = Module()
result.delegate = delegate
result.view = newView(result)
result.viewVariant = newQVariant(result.view)
result.moduleLoaded = false
result.controller = controller.newController(result, settingsService, dappPermissionsService, providerService)
result.controller = controller.newController(result, settingsService, providerService)
method delete*(self: Module) =
self.controller.delete
@ -52,14 +50,8 @@ method viewDidLoad*(self: Module) =
self.moduleLoaded = true
self.delegate.providerDidLoad()
method disconnect*(self: Module) =
self.controller.disconnect()
method postMessage*(self: Module, requestType: string, message: string): string =
return self.controller.postMessage(requestType, message)
method hasPermission*(self: Module, hostname: string, permission: string): bool =
return self.controller.hasPermission(hostname, permission)
method ensResourceURL*(self: Module, ens: string, url: string): (string, string, string, string, bool) =
return self.controller.ensResourceURL(ens, url)

View File

@ -4,14 +4,11 @@ method setDappsAddress*(self: AccessInterface, newDappAddress: string) {.base.}
method onDappAddressChanged*(self: AccessInterface, newDappAddress: string) {.base.} =
raise newException(ValueError, "No implementation available")
method disconnect*(self: AccessInterface) {.base.} =
method disconnect*(self: AccessInterface, dappName: string, address: string) {.base.} =
raise newException(ValueError, "No implementation available")
method postMessage*(self: AccessInterface, requestType: string, message: string): string {.base.} =
raise newException(ValueError, "No implementation available")
method hasPermission*(self: AccessInterface, hostname: string, permission: string): bool {.base.} =
raise newException(ValueError, "No implementation available")
method ensResourceURL*(self: AccessInterface, ens: string, url: string): (string, string, string, string, bool) =
raise newException(ValueError, "No implementation available")

View File

@ -56,15 +56,9 @@ QtObject:
proc getHost*(self: View, url: string): string {.slot.} =
result = url_host(url)
proc disconnect*(self: View) {.slot.} =
self.delegate.disconnect()
proc postMessage*(self: View, requestType: string, message: string): string {.slot.} =
return self.delegate.postMessage(requestType, message)
proc hasPermission(self: View, hostname: string, permission: string): bool {.slot.} =
return self.delegate.hasPermission(hostname, permission)
proc ensResourceURL*(self: View, ens: string, url: string): string {.slot.} =
let (url, base, http_scheme, path_prefix, hasContentHash) = self.delegate.ensResourceURL(ens, url)
result = url_replaceHostAndAddPath(url, (if hasContentHash: base else: url_host(base)), http_scheme, path_prefix)

View File

@ -94,7 +94,7 @@ proc newModule*[T](
settingsService: settings_service.ServiceInterface,
contactsService: contacts_service.Service,
aboutService: about_service.Service,
dappPermissionsService: dapp_permissions_service.ServiceInterface,
dappPermissionsService: dapp_permissions_service.Service,
languageService: language_service.ServiceInterface,
privacyService: privacy_service.Service,
providerService: provider_service.ServiceInterface,
@ -140,7 +140,7 @@ proc newModule*[T](
settingsService, savedAddressService, networkService,
)
result.browserSectionModule = browser_section_module.newModule(result, bookmarkService, settingsService,
dappPermissionsService, providerService)
dappPermissionsService, providerService, walletAccountService)
result.profileSectionModule = profile_section_module.newModule(
result, events, accountsService, settingsService, stickersService,
profileService, contactsService, aboutService, languageService, privacyService, nodeConfigurationService,

View File

@ -5,11 +5,13 @@ include ../../../common/json_utils
type Dapp* = object
name*: string
address*: string
permissions*: HashSet[Permission]
proc toDapp*(jsonObj: JsonNode): Dapp =
result = Dapp()
result.permissions = initHashSet[Permission]()
discard jsonObj.getProp("dapp", result.name)
discard jsonObj.getProp("address", result.address)
for permission in jsonObj["permissions"].getElems():
result.permissions.incl(permission.getStr().toPermission())

View File

@ -3,17 +3,18 @@ import sets
import result
import options
include ../../common/json_utils
import service_interface
import ../../../backend/permissions as status_go
import dto/dapp
import dto/permission
export service_interface
export dapp
export permission
logScope:
topics = "dapp-permissions-service"
type
Service* = ref object of ServiceInterface
Service* = ref object
dapps: Table[string, Dapp]
type R = Result[Dapp, string]
@ -29,7 +30,10 @@ method init*(self: Service) =
try:
let response = status_go.getDappPermissions()
for dapp in response.result.getElems().mapIt(it.toDapp()):
self.dapps[dapp.name] = dapp
if dapp.address == "":
continue
self.dapps[dapp.name & dapp.address] = dapp
except Exception as e:
let errDescription = e.msg
error "error: ", errDescription
@ -37,84 +41,85 @@ method init*(self: Service) =
method getDapps*(self: Service): seq[Dapp] =
return toSeq(self.dapps.values)
method getDapp*(self: Service, dapp: string): Option[Dapp] =
if self.dapps.hasKey(dapp):
return some(self.dapps[dapp])
method getDapp*(self: Service, name: string, address: string): Option[Dapp] =
let key = name & address
if self.dapps.hasKey(key):
return some(self.dapps[key])
return none(Dapp)
method clearPermissions*(self: Service, dapp: string): bool =
try:
if not self.dapps.hasKey(dapp):
return
discard status_go.deleteDappPermissions(dapp)
self.dapps.del(dapp)
return true
except Exception as e:
let errDescription = e.msg
error "error: ", errDescription
method addPermission*(self: Service, name: string, address: string, permission: Permission): R =
let key = name & address
method revoke*(self: Service, permission: Permission): bool =
try:
var dappsToDelete: seq[string] = @[]
for dapp in self.dapps.mvalues:
if dapp.permissions.contains(permission):
dapp.permissions.excl(permission)
if dapp.permissions.len > 0:
discard status_go.addDappPermissions(dapp.name, dapp.permissions.toSeq().mapIt($it))
else:
discard status_go.deleteDappPermissions(dapp.name)
dappsToDelete.add(dapp.name)
for dappName in dappsToDelete:
self.dapps.del(dappName)
return true
except Exception as e:
let errDescription = e.msg
error "error: ", errDescription
method revoke*(self: Service, dapp: string, permission: Permission): bool =
try:
if not self.dapps.hasKey(dapp):
return
if self.dapps[dapp].permissions.contains(permission):
self.dapps[dapp].permissions.excl(permission)
if self.dapps[dapp].permissions.len > 0:
discard status_go.addDappPermissions(dapp, self.dapps[dapp].permissions.toSeq().mapIt($it))
else:
discard status_go.deleteDappPermissions(dapp)
self.dapps.del(dapp)
return true
except Exception as e:
let errDescription = e.msg
error "error: ", errDescription
method addPermission*(self: Service, dapp: string, permission: Permission): R =
try:
if not self.dapps.hasKey(dapp):
self.dapps[dapp] = Dapp(
name: dapp,
if not self.dapps.hasKey(key):
self.dapps[key] = Dapp(
name: name,
address: address,
permissions: initHashSet[Permission]()
)
self.dapps[dapp].permissions.incl(permission)
discard status_go.addDappPermissions(dapp, self.dapps[dapp].permissions.toSeq().mapIt($it))
result.ok self.dapps[dapp]
self.dapps[key].permissions.incl(permission)
let permissions = self.dapps[key].permissions.toSeq().mapIt($it)
discard status_go.addDappPermissions(name, address, permissions)
result.ok self.dapps[key]
except Exception as e:
let errDescription = e.msg
error "error: ", errDescription
result.err errDescription
method revokeAllPermisions*(self: Service): bool =
method hasPermission*(self: Service, dapp: string, address: string, permission: Permission): bool =
let key = dapp & address
if not self.dapps.hasKey(key):
return false
return self.dapps[key].permissions.contains(permission)
method disconnect*(self: Service, dappName: string): bool =
try:
for d in self.dapps.values:
discard status_go.deleteDappPermissions(d.name)
self.dapps.clear()
var addresses: seq[string] = @[]
for dapp in self.dapps.values:
if dapp.name != dappName:
continue
discard status_go.deleteDappPermissions(dapp.name, dapp.address)
addresses.add(dapp.address)
for address in addresses:
self.dapps.del(dappName & address)
return true
except Exception as e:
let errDescription = e.msg
error "error: ", errDescription
method disconnectAddress*(self: Service, dappName: string, address: string): bool =
let key = dappName & address
if not self.dapps.hasKey(key):
return
try:
discard status_go.deleteDappPermissions(dappName, address)
self.dapps.del(key)
return true
except Exception as e:
let errDescription = e.msg
error "error: ", errDescription
method hasPermission*(self: Service, dapp: string, permission: Permission): bool =
if not self.dapps.hasKey(dapp):
return false
return self.dapps[dapp].permissions.contains(permission)
method removePermission*(self: Service, name: string, address: string, permission: Permission): bool =
let key = name & address
if not self.dapps.hasKey(key):
return
try:
if self.dapps[key].permissions.contains(permission):
self.dapps[key].permissions.excl(permission)
if self.dapps[key].permissions.len > 0:
discard status_go.addDappPermissions(name, address, self.dapps[key].permissions.toSeq().mapIt($it))
else:
discard status_go.deleteDappPermissions(name, address)
self.dapps.del(key)
return true
except Exception as e:
let errDescription = e.msg
error "error: ", errDescription

View File

@ -1,43 +0,0 @@
import dto/dapp
import dto/permission
import results
import options
export dapp
export permission
type R = Result[Dapp, string]
type
ServiceInterface* {.pure inheritable.} = ref object of RootObj
## Abstract class for this service access.
method delete*(self: ServiceInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method init*(self: ServiceInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method getDapps*(self: ServiceInterface): seq[Dapp] {.base.} =
raise newException(ValueError, "No implementation available")
method getDapp*(self: ServiceInterface, dapp: string): Option[Dapp] {.base.} =
raise newException(ValueError, "No implementation available")
method hasPermission*(self: ServiceInterface, dapp: string, permission: Permission): bool {.base.} =
raise newException(ValueError, "No implementation available")
method clearPermissions*(self: ServiceInterface, dapp: string): bool {.base.} =
raise newException(ValueError, "No implementation available")
method revoke*(self: ServiceInterface, permission: Permission): bool {.base.} =
raise newException(ValueError, "No implementation available")
method revoke*(self: ServiceInterface, dapp: string, permission: Permission): bool {.base.} =
raise newException(ValueError, "No implementation available")
method revokeAllPermisions*(self: ServiceInterface): bool {.base.} =
raise newException(ValueError, "No implementation available")
method addPermission*(self: ServiceInterface, dapp: string, permission: Permission): R {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -8,13 +8,14 @@ proc getDappPermissions*(): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* []
result = callPrivateRPC("permissions_getDappPermissions", payload)
proc addDappPermissions*(dapp: string, permissions: seq[string]): RpcResponse[JsonNode] {.raises: [Exception].} =
proc addDappPermissions*(dapp: string, address: string, permissions: seq[string]): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %*[{
"dapp": dapp,
"address": address,
"permissions": permissions
}]
result = callPrivateRPC("permissions_addDappPermissions", payload)
proc deleteDappPermissions*(dapp: string): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [dapp]
result = callPrivateRPC("permissions_deleteDappPermissions", payload)
proc deleteDappPermissions*(dapp: string, address: string): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [dapp, address]
result = callPrivateRPC("permissions_deleteDappPermissionsByNameAndAddress", payload)

View File

@ -17,7 +17,7 @@ StatusModal {
id: browserConnectionModal
property var currentTab
property var request: ({"hostname": "", "title": "", "permission": ""})
property var request: ({"hostname": "", "address": "", "title": "", "permission": ""})
property string currentAddress: ""
property bool interactedWith: false
property var web3Response: function(){}
@ -30,10 +30,11 @@ StatusModal {
bottomPadding: 0
function postMessage(isAllowed){
console.log(isAllowed)
interactedWith = true
RootStore.currentTabConnected = isAllowed
if(isAllowed){
Web3ProviderStore.addPermission(request.hostname, request.permission)
Web3ProviderStore.addPermission(request.hostname, request.address, request.permission)
}
browserConnectionModal.web3Response(Web3ProviderStore.web3ProviderInst.postMessage(Constants.api_request, JSON.stringify(request)))
}
@ -127,7 +128,6 @@ StatusModal {
browserConnectionModal.currentAddress = selectedAccount.address
Web3ProviderStore.web3ProviderInst.dappsAddress = selectedAccount.address;
Web3ProviderStore.revokeAllPermissions()
if (selectedAccount.address) {
Web3ProviderStore.web3ProviderInst.dappsAddress = selectedAccount.address;

View File

@ -133,7 +133,6 @@ Popup {
accountSelectorRow.currentAddress = selectedAccount.address
Web3ProviderStore.web3ProviderInst.dappsAddress = selectedAccount.address;
WalletStore.setDappBrowserAddress()
Web3ProviderStore.revokeAllPermissions()
reload()
}
}

View File

@ -10,12 +10,16 @@ QtObject {
property int networkId: providerModule.networkId
function revokeAllPermissions(){
dappPermissionsModule.revokeAllPermissions()
function disconnectAddress(dappName, address){
dappPermissionsModule.disconnectAddress(address)
}
function addPermission(permission, hostName ){
dappPermissionsModule.addPermission(permission, hostName)
function addPermission(hostname, address, permission){
dappPermissionsModule.addPermission(hostname, address, permission)
}
function hasPermission(hostname, address, permission){
return dappPermissionsModule.hasPermission(hostname, address, permission)
}
function determineRealURL(text){

View File

@ -35,6 +35,7 @@ QtObject {
console.error("Error parsing the message data", e)
return;
}
request.address = WalletStore.dappBrowserAccount.address
var ensAddr = Web3ProviderStore.urlENSDictionary[request.hostname];
if (ensAddr) {
@ -45,7 +46,7 @@ QtObject {
RootStore.currentTabConnected = true
web3Response(JSON.stringify({type: Constants.web3DisconnectAccount}));
} else if (requestType === Constants.api_request) {
if (!Web3ProviderStore.web3ProviderInst.hasPermission(request.hostname, request.permission)) {
if (!Web3ProviderStore.hasPermission(request.hostname, request.address, request.permission)) {
RootStore.currentTabConnected = false
var dialog = createAccessDialogComponent()
dialog.request = request;

View File

@ -1,5 +1,6 @@
import StatusQ.Components 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
StatusListItem {
@ -16,5 +17,4 @@ StatusListItem {
color: Theme.palette.baseColor1
}
]
}

View File

@ -1,62 +0,0 @@
import QtQuick 2.3
import QtQuick.Controls 2.3
import QtQuick.Layouts 1.3
import Qt.labs.platform 1.1
import StatusQ.Core 0.1
import utils 1.0
import shared 1.0
import shared.panels 1.0
Item {
property string name: "Status.im"
height: 50
anchors.right: parent.right
anchors.left: parent.left
signal dappClicked(string dapp)
SVGImage {
id: image
height: 40
width: 40
anchors.top: parent.top
anchors.topMargin: 4
anchors.left: parent.left
fillMode: Image.PreserveAspectFit
source: Style.svg("generalDappIcon")
}
StatusBaseText {
id: dappText
text: name
elide: Text.ElideRight
anchors.right: parent.right
anchors.rightMargin: Style.current.padding
font.pixelSize: 17
anchors.top: parent.top
anchors.topMargin: 10
anchors.left: image.right
anchors.leftMargin: Style.current.padding
}
SVGImage {
id: arrow
height: 24
width: 24
anchors.top: parent.top
anchors.topMargin: 10
anchors.right: parent.right
anchors.rightMargin: Style.current.padding
fillMode: Image.PreserveAspectFit
source: Style.svg("list-next")
}
MouseArea {
cursorShape: Qt.PointingHandCursor
anchors.fill: parent
onClicked: dappClicked(name)
}
}

View File

@ -1,51 +0,0 @@
import QtQuick 2.3
import QtQuick.Controls 2.3
import QtQuick.Layouts 1.3
import Qt.labs.platform 1.1
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import utils 1.0
import shared 1.0
Item {
property string name: "permission-name-here"
height: 50
anchors.right: parent.right
anchors.left: parent.left
signal removeBtnClicked(string permission)
StatusBaseText {
id: dappText
text: name
elide: Text.ElideRight
anchors.right: parent.right
anchors.rightMargin: Style.current.padding
font.pixelSize: 17
anchors.top: parent.top
anchors.topMargin: Style.current.smallPadding
anchors.left: parent.left
anchors.leftMargin: Style.current.padding
}
StatusBaseText {
//% "Revoke access"
text: qsTrId("revoke-access")
color: Theme.palette.dangerColor1
anchors.top: parent.top
anchors.topMargin: Style.current.smallPadding
anchors.right: parent.right
anchors.rightMargin: Style.current.padding
MouseArea {
cursorShape: Qt.PointingHandCursor
anchors.fill: parent
onClicked: removeBtnClicked(name)
}
}
}

View File

@ -1,52 +0,0 @@
import QtQuick 2.13
import QtQuick.Controls 2.13
import QtQuick.Layouts 1.13
import utils 1.0
import shared 1.0
import shared.popups 1.0
import "./"
import "../panels"
// TODO: replace with StatusModal
ModalPopup {
id: root
//% "Dapp permissions"
title: qsTrId("dapp-permissions")
property var store
Component.onCompleted: store.initDappList()
property Component permissionListPopup: PermissionList {
onClosed: destroy()
store: root.store
onAccessRevoked: store.initDappList()
}
Item {
anchors.fill: parent
ScrollView {
anchors.fill: parent
Layout.fillWidth: true
Layout.fillHeight: true
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
ScrollBar.vertical.policy: dappListView.contentHeight > dappListView.height ? ScrollBar.AlwaysOn : ScrollBar.AlwaysOff
ListView {
anchors.fill: parent
spacing: 0
clip: true
id: dappListView
model: root.store.dappList
delegate: Dapp {
name: model.name
onDappClicked: Global.openPopup(permissionListPopup, {dapp: dapp})
}
}
}
}
}

View File

@ -1,72 +0,0 @@
import QtQuick 2.13
import QtQuick.Controls 2.13
import QtQuick.Layouts 1.13
import StatusQ.Controls 0.1
import shared.popups 1.0
import utils 1.0
import "../panels"
// TODO: replace with StatusModal
ModalPopup {
property string dapp: ""
id: root
title: dapp
width: 400
height: 400
property var store
Component.onCompleted: store.initPermissionList(dapp)
signal accessRevoked(string dapp)
Item {
anchors.fill: parent
ScrollView {
anchors.fill: parent
Layout.fillWidth: true
Layout.fillHeight: true
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
ScrollBar.vertical.policy: permissionListView.contentHeight > permissionListView.height ? ScrollBar.AlwaysOn : ScrollBar.AlwaysOff
ListView {
anchors.fill: parent
spacing: 0
clip: true
id: permissionListView
model: root.store.permissionList
delegate: Permission {
name: model.name
onRemoveBtnClicked: {
root.store.revokePermission(dapp, model.name);
if(permissionListView.count === 1){
accessRevoked(dapp);
close();
}
root.store.initPermissionList(dapp)
}
}
}
}
}
footer: StatusButton {
anchors.horizontalCenter: parent.horizontalCenter
type: StatusBaseButton.Type.Danger
//% "Revoke all access"
text: qsTrId("revoke-all-access")
onClicked: {
root.store.clearPermissions(dapp)
accessRevoked(dapp);
close();
}
}
}

View File

@ -50,8 +50,6 @@ QtObject {
property WalletStore walletStore: WalletStore {
}
property var dappList: dappPermissionsModule.dapps
property var permissionList: dappPermissionsModule.permissions
property bool browserMenuItemEnabled: localAccountSensitiveSettings.isBrowserEnabled
property bool appsMenuItemsEnabled: localAccountSensitiveSettings.isWalletEnabled
@ -124,22 +122,6 @@ QtObject {
}
}
function initPermissionList(name) {
dappPermissionsModule.fetchPermissions(name)
}
function revokePermission(dapp, name) {
dappPermissionsModule.revokePermission(dapp, name)
}
function clearPermissions(dapp) {
dappPermissionsModule.clearPermissions(dapp)
}
function initDappList() {
dappPermissionsModule.fetchDapps()
}
function getCurrentVersion() {
return aboutModuleInst.getCurrentVersion()
}

View File

@ -39,4 +39,18 @@ QtObject {
function deleteAccount(address) {
return walletSectionAccounts.deleteAccount(address)
}
property var dappList: dappPermissionsModule.dapps
function disconnect(dappName) {
dappPermissionsModule.disconnect(dappName)
}
function accountsForDapp(dappName) {
return dappPermissionsModule.accountsForDapp(dappName)
}
function disconnectAddress(dappName, address) {
return dappPermissionsModule.disconnectAddress(dappName, address)
}
}

View File

@ -22,10 +22,6 @@ Item {
property var store
property int profileContentWidth
property Component dappListPopup: DappList {
store: root.store
onClosed: destroy()
}
property Component homePagePopup: HomepageModal {}
property Component searchEngineModal: SearchEngineModal {}
property Component ethereumExplorerModal: EthereumExplorerModal {}
@ -127,16 +123,6 @@ Item {
topPadding: Style.current.bigPadding
bottomPadding: Style.current.padding
}
// TODO: Replace with StatusQ StatusListItem component
StatusSettingsLineButton {
//% "Set DApp access permissions"
text: qsTrId("set-dapp-access-permissions")
isSwitch: false
onClicked: {
dappListPopup.createObject(root).open()
}
}
}
}
}

View File

@ -52,6 +52,10 @@ ScrollView {
root.walletStore.switchAccountByAddress(address)
stackContainer.currentIndex = 2
}
onGoToDappPermissionsView: {
stackContainer.currentIndex = 3
}
}
NetworksView {
@ -63,7 +67,14 @@ ScrollView {
}
AccountView {
id: accountView
walletStore: root.walletStore
anchors.fill: parent
onGoBack: {
stackContainer.currentIndex = 0
}
}
DappPermissionsView {
walletStore: root.walletStore
anchors.fill: parent
onGoBack: {

View File

@ -0,0 +1,103 @@
import QtQuick 2.13
import shared.status 1.0
import StatusQ.Controls 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Components 0.1
import utils 1.0
import "../../stores"
import "../../controls"
Item {
id: root
signal goBack
property WalletStore walletStore
StatusFlatButton {
id: backButton
anchors.top: parent.top
anchors.topMargin: Style.current.bigPadding
anchors.left: parent.left
anchors.leftMargin: Style.current.bigPadding
icon.name: "arrow-left"
icon.height: 13.5
icon.width: 17.5
text: qsTr("Wallet")
onClicked: {
root.goBack()
}
}
Column {
id: column
anchors.topMargin: Style.current.xlPadding
anchors.top: backButton.bottom
anchors.leftMargin: Style.current.xlPadding * 2
anchors.left: root.left
width: 560
StatusBaseText {
id: titleText
text: qsTr("DApp Permissions")
font.weight: Font.Bold
font.pixelSize: 28
color: Theme.palette.directColor1
}
Item {
height: Style.current.bigPadding
width: parent.width
}
Repeater {
id: permissionsList
model: walletStore.dappList
delegate: Item {
width: parent.width
height: listItem.height + spacer.height
StatusListItem {
id: listItem
title: model.name
icon.isLetterIdenticon: true
width: parent.width
highlighted: true
sensor.enabled: false
components: [
StatusButton {
text: model.accounts.count > 1 ? qsTr("Disconnect All") : qsTr("Disconnect")
size: StatusBaseButton.Size.Small
type: StatusBaseButton.Type.Danger
onClicked: {
walletStore.disconnect(model.name)
}
}
]
bottomModel: model.accounts
bottomDelegate: StatusListItemTag {
property int outerIndex: listItem.index
title: model.name
icon.isLetterIdenticon: true
icon.color: model.color
onClicked: {
const dappName = walletStore.dappList.rowData(outerIndex, 'name')
walletStore.disconnectAddress(dappName, model.address)
}
}
}
Item {
id: spacer
height: Style.current.bigPadding
width: parent.width
}
}
}
}
}

View File

@ -17,6 +17,7 @@ Column {
signal goToNetworksView()
signal goToAccountView(address: string)
signal goToDappPermissionsView()
StatusBaseText {
id: titleText
@ -57,9 +58,12 @@ Column {
}
StatusSettingsLineButton {
text: qsTr("DApp Permission")
text: qsTr("DApp Permissions")
currentValue: {
return qsTr("%1 DApps connected").arg(root.walletStore.dappList.count)
}
height: 64
onClicked: goToNetworksView()
onClicked: goToDappPermissionsView()
}
Separator {

2
vendor/status-go vendored

@ -1 +1 @@
Subproject commit 442d24a79f410170f816228269357e35819d775f
Subproject commit 9c16cedb1e415a1d7f715634d3dd0a18c6f739e5