mirror of
https://github.com/status-im/status-desktop.git
synced 2025-02-17 00:56:39 +00:00
feat: dapps permissions
This commit is contained in:
parent
1ec6dee429
commit
37e213e89b
@ -1,5 +1,5 @@
|
||||
import NimQml, sequtils, strutils, sugar, os
|
||||
import views/[mailservers_list, ens_manager, contact_list, profile_info, device_list]
|
||||
import views/[mailservers_list, ens_manager, contact_list, profile_info, device_list, dapp_list]
|
||||
import ../../status/profile/[mailserver, profile, devices]
|
||||
import ../../status/profile as status_profile
|
||||
import ../../status/contacts as status_contacts
|
||||
@ -22,6 +22,7 @@ QtObject:
|
||||
addedContacts*: ContactList
|
||||
blockedContacts*: ContactList
|
||||
deviceList*: DeviceList
|
||||
dappList*: DappList
|
||||
network: string
|
||||
status*: Status
|
||||
isDeviceSetup: bool
|
||||
@ -40,6 +41,7 @@ QtObject:
|
||||
if not self.deviceList.isNil: self.deviceList.delete
|
||||
if not self.ens.isNil: self.ens.delete
|
||||
if not self.profile.isNil: self.profile.delete
|
||||
if not self.dappList.isNil: self.dappList.delete
|
||||
self.QObject.delete
|
||||
|
||||
proc newProfileView*(status: Status, changeLanguage: proc(locale: string)): ProfileView =
|
||||
@ -51,6 +53,7 @@ QtObject:
|
||||
result.addedContacts = newContactList()
|
||||
result.blockedContacts = newContactList()
|
||||
result.deviceList = newDeviceList()
|
||||
result.dappList = newDappList(status)
|
||||
result.ens = newEnsManager(status)
|
||||
result.network = ""
|
||||
result.status = status
|
||||
@ -241,6 +244,12 @@ QtObject:
|
||||
QtProperty[QVariant] deviceList:
|
||||
read = getDeviceList
|
||||
|
||||
proc getDappList(self: ProfileView): QVariant {.slot.} =
|
||||
return newQVariant(self.dappList)
|
||||
|
||||
QtProperty[QVariant] dappList:
|
||||
read = getDappList
|
||||
|
||||
proc getEnsManager(self: ProfileView): QVariant {.slot.} =
|
||||
return newQVariant(self.ens)
|
||||
|
||||
|
63
src/app/profile/views/dapp_list.nim
Normal file
63
src/app/profile/views/dapp_list.nim
Normal file
@ -0,0 +1,63 @@
|
||||
import NimQml
|
||||
import Tables
|
||||
import ../../../status/status
|
||||
import permission_list
|
||||
|
||||
type
|
||||
DappsRoles {.pure.} = enum
|
||||
Name = UserRole + 1,
|
||||
|
||||
QtObject:
|
||||
type DappList* = ref object of QAbstractListModel
|
||||
status: Status
|
||||
dapps: seq[Dapp]
|
||||
permissionList: PermissionList
|
||||
|
||||
proc setup(self: DappList) = self.QAbstractListModel.setup
|
||||
|
||||
proc delete(self: DappList) =
|
||||
self.dapps = @[]
|
||||
self.permissionList.delete
|
||||
self.QAbstractListModel.delete
|
||||
|
||||
proc newDappList*(status: Status): DappList =
|
||||
new(result, delete)
|
||||
result.status = status
|
||||
result.permissionList = newPermissionList(status)
|
||||
result.dapps = @[]
|
||||
result.setup
|
||||
|
||||
proc init*(self: DappList) {.slot.} =
|
||||
self.beginResetModel()
|
||||
self.dapps = self.status.permissions.getDapps()
|
||||
self.endResetModel()
|
||||
|
||||
method rowCount(self: DappList, index: QModelIndex = nil): int =
|
||||
return self.dapps.len
|
||||
|
||||
method data(self: DappList, index: QModelIndex, role: int): QVariant =
|
||||
if not index.isValid:
|
||||
return
|
||||
if index.row < 0 or index.row >= self.dapps.len:
|
||||
return
|
||||
result = newQVariant(self.dapps[index.row].name)
|
||||
|
||||
method roleNames(self: DappList): Table[int, string] =
|
||||
{
|
||||
DappsRoles.Name.int:"name",
|
||||
}.toTable
|
||||
|
||||
proc clearData(self: DappList) {.slot.} =
|
||||
self.beginResetModel()
|
||||
self.dapps = @[]
|
||||
self.endResetModel()
|
||||
|
||||
proc revokeAllPermissions(self: DappList) {.slot.} =
|
||||
self.status.permissions.clearPermissions()
|
||||
self.clearData()
|
||||
|
||||
proc getPermissionList(self: DappList): QVariant {.slot.} =
|
||||
return newQVariant(self.permissionList)
|
||||
|
||||
QtProperty[QVariant] permissionList:
|
||||
read = getPermissionList
|
70
src/app/profile/views/permission_list.nim
Normal file
70
src/app/profile/views/permission_list.nim
Normal file
@ -0,0 +1,70 @@
|
||||
import NimQml
|
||||
import Tables
|
||||
import ../../../status/status
|
||||
import sets
|
||||
import sequtils
|
||||
|
||||
type
|
||||
PermissionRoles {.pure.} = enum
|
||||
Name = UserRole + 1,
|
||||
|
||||
QtObject:
|
||||
type PermissionList* = ref object of QAbstractListModel
|
||||
status: Status
|
||||
dapp: string
|
||||
permissions: HashSet[Permission]
|
||||
|
||||
proc setup(self: PermissionList) = self.QAbstractListModel.setup
|
||||
|
||||
proc delete(self: PermissionList) =
|
||||
self.dapp = ""
|
||||
self.permissions = initHashSet[Permission]()
|
||||
self.QAbstractListModel.delete
|
||||
|
||||
proc newPermissionList*(status: Status): PermissionList =
|
||||
new(result, delete)
|
||||
result.status = status
|
||||
result.dapp = ""
|
||||
result.permissions = initHashSet[Permission]()
|
||||
result.setup
|
||||
|
||||
proc init*(self: PermissionList, dapp: string) {.slot.} =
|
||||
self.beginResetModel()
|
||||
self.dapp = dapp
|
||||
self.permissions = self.status.permissions.getPermissions(dapp)
|
||||
self.endResetModel()
|
||||
|
||||
proc getDapp(self: PermissionList): string {.slot.} = self.dapp
|
||||
|
||||
QtProperty[QVariant] dapp:
|
||||
read = getDapp
|
||||
|
||||
proc revokePermission(self: PermissionList, permission: string) {.slot.} =
|
||||
self.status.permissions.revokePermission(self.dapp, permission.toPermission())
|
||||
|
||||
proc revokeAccess(self: PermissionList) {.slot.} =
|
||||
self.status.permissions.clearPermissions(self.dapp)
|
||||
|
||||
method rowCount(self: PermissionList, index: QModelIndex = nil): int = self.permissions.len
|
||||
|
||||
method data(self: PermissionList, index: QModelIndex, role: int): QVariant =
|
||||
if not index.isValid:
|
||||
return
|
||||
if index.row < 0 or index.row >= self.permissions.len:
|
||||
return
|
||||
result = newQVariant($self.permissions.toSeq[index.row])
|
||||
|
||||
method roleNames(self: PermissionList): Table[int, string] =
|
||||
{
|
||||
PermissionRoles.Name.int:"name",
|
||||
}.toTable
|
||||
|
||||
proc clearData(self: PermissionList) {.slot.} =
|
||||
self.beginResetModel()
|
||||
self.dapp = ""
|
||||
self.permissions = initHashSet[Permission]()
|
||||
self.endResetModel()
|
||||
|
||||
proc revokeAllPermissions(self: PermissionList) {.slot.} =
|
||||
self.status.permissions.clearPermissions(self.dapp)
|
||||
self.clearData()
|
@ -34,11 +34,29 @@ proc newPermissionsModel*(events: EventEmitter): PermissionsModel =
|
||||
proc init*(self: PermissionsModel) =
|
||||
discard
|
||||
|
||||
|
||||
type Dapp* = object
|
||||
name*: string
|
||||
permissions*: HashSet[Permission]
|
||||
|
||||
proc getDapps*(self: PermissionsModel): seq[Dapp] =
|
||||
let response = callPrivateRPC("permissions_getDappPermissions")
|
||||
result = @[]
|
||||
for dapps in response.parseJson["result"].getElems():
|
||||
var dapp = Dapp(
|
||||
name: dapps["dapp"].getStr(),
|
||||
permissions: initHashSet[Permission]()
|
||||
)
|
||||
for permission in dapps["permissions"].getElems():
|
||||
dapp.permissions.incl(permission.getStr().toPermission())
|
||||
result.add(dapp)
|
||||
|
||||
proc getPermissions*(self: PermissionsModel, dapp: string): HashSet[Permission] =
|
||||
let response = callPrivateRPC("permissions_getDappPermissions")
|
||||
result = initHashSet[Permission]()
|
||||
for dappPermission in response.parseJson["result"].getElems():
|
||||
if dappPermission["dapp"].getStr() == dapp:
|
||||
if not dappPermission.hasKey("permissions"): return
|
||||
for permission in dappPermission["permissions"].getElems():
|
||||
result.incl(permission.getStr().toPermission())
|
||||
|
||||
@ -54,12 +72,19 @@ proc addPermission*(self: PermissionsModel, dapp: string, permission: Permission
|
||||
}])
|
||||
|
||||
proc revokePermission*(self: PermissionsModel, dapp: string, permission: Permission) =
|
||||
# TODO: implement
|
||||
discard
|
||||
var permissions = self.getPermissions(dapp)
|
||||
permissions.excl(permission)
|
||||
|
||||
if permissions.len == 0:
|
||||
discard callPrivateRPC("permissions_deleteDappPermissions", %*[dapp])
|
||||
else:
|
||||
discard callPrivateRPC("permissions_addDappPermissions", %*[{
|
||||
"dapp": dapp,
|
||||
"permissions": permissions.toSeq()
|
||||
}])
|
||||
|
||||
proc clearPermissions*(self: PermissionsModel, dapp: string) =
|
||||
# TODO implement
|
||||
discard
|
||||
discard callPrivateRPC("permissions_deleteDappPermissions", %*[dapp])
|
||||
|
||||
proc clearPermissions*(self: PermissionsModel) =
|
||||
let response = callPrivateRPC("permissions_getDappPermissions")
|
||||
|
@ -26,11 +26,6 @@ Rectangle {
|
||||
onClosing: destroy()
|
||||
}
|
||||
|
||||
property Item currentWebView: tabs.currentIndex < tabs.count ? tabs.getTab(tabs.currentIndex).item : null
|
||||
|
||||
property Component browserDialogComponent: BrowserDialog {
|
||||
onClosing: destroy()
|
||||
}
|
||||
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
|
@ -5,12 +5,17 @@ import QtGraphicalEffects 1.13
|
||||
import "../../../../imports"
|
||||
import "../../../../shared"
|
||||
import "../../../../shared/status"
|
||||
import "Privileges/"
|
||||
|
||||
Item {
|
||||
id: privacyContainer
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
|
||||
property Component dappListPopup: DappList {
|
||||
onClosed: destroy()
|
||||
}
|
||||
|
||||
Item {
|
||||
id: profileImgNameContainer
|
||||
anchors.top: parent.top
|
||||
@ -74,6 +79,51 @@ Item {
|
||||
anchors.top: backupSeedPhrase.bottom
|
||||
anchors.topMargin: Style.current.bigPadding
|
||||
}
|
||||
|
||||
Item {
|
||||
id: dappPermissions
|
||||
anchors.top: backupSeedPhrase.bottom
|
||||
anchors.topMargin: Style.current.padding
|
||||
height: dappPermissionsText.height
|
||||
width: parent.width
|
||||
|
||||
StyledText {
|
||||
id: dappPermissionsText
|
||||
text: qsTr("Set DApp access permissions")
|
||||
font.pixelSize: 15
|
||||
}
|
||||
|
||||
SVGImage {
|
||||
id: caret2
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 0
|
||||
anchors.verticalCenter: dappPermissionsText.verticalCenter
|
||||
source: "../../../img/caret.svg"
|
||||
width: 13
|
||||
height: 7
|
||||
rotation: -90
|
||||
}
|
||||
|
||||
ColorOverlay {
|
||||
anchors.fill: caret2
|
||||
source: caret
|
||||
color: Style.current.darkGrey
|
||||
rotation: -90
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: dappListPopup.createObject(privacyContainer).open()
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
}
|
||||
}
|
||||
|
||||
Separator {
|
||||
id: separator2
|
||||
anchors.top: dappPermissions.bottom
|
||||
anchors.topMargin: Style.current.bigPadding
|
||||
}
|
||||
|
||||
StatusSectionHeadline {
|
||||
id: labelPrivacy
|
||||
//% "Privacy"
|
||||
|
58
ui/app/AppLayouts/Profile/Sections/Privileges/Dapp.qml
Normal file
58
ui/app/AppLayouts/Profile/Sections/Privileges/Dapp.qml
Normal file
@ -0,0 +1,58 @@
|
||||
import QtQuick 2.3
|
||||
import QtQuick.Controls 2.3
|
||||
import QtQuick.Layouts 1.3
|
||||
import Qt.labs.platform 1.1
|
||||
import "../../../../../imports"
|
||||
import "../../../../../shared"
|
||||
|
||||
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: "../../../../img/generalDappIcon.svg"
|
||||
}
|
||||
|
||||
StyledText {
|
||||
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: "../../../../img/list-next.svg"
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
anchors.fill: parent
|
||||
onClicked: dappClicked(name)
|
||||
}
|
||||
}
|
50
ui/app/AppLayouts/Profile/Sections/Privileges/DappList.qml
Normal file
50
ui/app/AppLayouts/Profile/Sections/Privileges/DappList.qml
Normal file
@ -0,0 +1,50 @@
|
||||
import QtQuick 2.13
|
||||
import QtQuick.Controls 2.13
|
||||
import QtQuick.Layouts 1.13
|
||||
import "../../../../../imports"
|
||||
import "../../../../../shared"
|
||||
import "./"
|
||||
|
||||
ModalPopup {
|
||||
id: popup
|
||||
title: qsTr("Dapp permissions")
|
||||
|
||||
Component.onCompleted: profileModel.dappList.init()
|
||||
Component.onDestruction: profileModel.dappList.clearData()
|
||||
|
||||
property Component permissionListPopup: PermissionList {
|
||||
onClosed: destroy()
|
||||
onAccessRevoked: profileModel.dappList.init()
|
||||
}
|
||||
|
||||
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: profileModel.dappList
|
||||
delegate: Dapp {
|
||||
name: model.name
|
||||
onDappClicked: permissionListPopup.createObject(privacyContainer, {dapp: dapp}).open()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*##^##
|
||||
Designer {
|
||||
D{i:0;height:300;width:300}
|
||||
}
|
||||
##^##*/
|
46
ui/app/AppLayouts/Profile/Sections/Privileges/Permission.qml
Normal file
46
ui/app/AppLayouts/Profile/Sections/Privileges/Permission.qml
Normal file
@ -0,0 +1,46 @@
|
||||
import QtQuick 2.3
|
||||
import QtQuick.Controls 2.3
|
||||
import QtQuick.Layouts 1.3
|
||||
import Qt.labs.platform 1.1
|
||||
import "../../../../../imports"
|
||||
import "../../../../../shared"
|
||||
|
||||
Item {
|
||||
property string name: "permission-name-here"
|
||||
|
||||
height: 50
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
|
||||
signal removeBtnClicked(string permission)
|
||||
|
||||
StyledText {
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Revoke access")
|
||||
color: Style.current.red
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
import QtQuick 2.13
|
||||
import QtQuick.Controls 2.13
|
||||
import QtQuick.Layouts 1.13
|
||||
import "../../../../../imports"
|
||||
import "../../../../../shared"
|
||||
import "./"
|
||||
|
||||
ModalPopup {
|
||||
property string dapp: ""
|
||||
|
||||
id: popup
|
||||
title: dapp
|
||||
|
||||
width: 400
|
||||
height: 400
|
||||
|
||||
Component.onCompleted: profileModel.dappList.permissionList.init(dapp)
|
||||
Component.onDestruction: profileModel.dappList.permissionList.clearData()
|
||||
|
||||
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: profileModel.dappList.permissionList
|
||||
delegate: Permission {
|
||||
name: model.name
|
||||
onRemoveBtnClicked: {
|
||||
profileModel.dappList.permissionList.revokePermission(model.name);
|
||||
if(permissionListView.count === 1){
|
||||
accessRevoked(dapp);
|
||||
close();
|
||||
}
|
||||
profileModel.dappList.permissionList.init(dapp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
footer: StyledButton {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
btnColor: Style.current.lightRed
|
||||
btnBorderWidth: 1
|
||||
btnBorderColor: Style.current.border
|
||||
textColor: Style.current.red
|
||||
label: qsTr("Revoke all access")
|
||||
onClicked: {
|
||||
profileModel.dappList.permissionList.revokeAccess();
|
||||
accessRevoked(dapp);
|
||||
close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*##^##
|
||||
Designer {
|
||||
D{i:0;height:300;width:300}
|
||||
}
|
||||
##^##*/
|
5
ui/app/img/generalDappIcon.svg
Normal file
5
ui/app/img/generalDappIcon.svg
Normal file
@ -0,0 +1,5 @@
|
||||
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="40" height="40" rx="20" fill="#EEF2F5"/>
|
||||
<path d="M19 12.5H15.6923C14.9828 12.5 14.8299 12.5062 14.7296 12.5246C14.1166 12.6369 13.6369 13.1166 13.5246 13.7296C13.5062 13.8299 13.5 13.9828 13.5 14.6923V16.25C13.5 16.6642 13.1642 17 12.75 17C12.3358 17 12 16.6642 12 16.25V14.6923C12 14.049 12 13.7274 12.0491 13.4592C12.2738 12.2332 13.2332 11.2738 14.4592 11.0491C14.7274 11 15.049 11 15.6923 11H19C23.9706 11 28 15.0294 28 20C28 24.9706 23.9706 29 19 29H15.6923C15.049 29 14.7274 29 14.4592 28.9509C13.2332 28.7262 12.2738 27.7668 12.0491 26.5408C12 26.2726 12 25.951 12 25.3077V23.75C12 23.3358 12.3358 23 12.75 23C13.1642 23 13.5 23.3358 13.5 23.75V25.3077C13.5 26.0172 13.5062 26.1701 13.5246 26.2704C13.6369 26.8834 14.1166 27.3631 14.7296 27.4754C14.8299 27.4938 14.9828 27.5 15.6923 27.5H19C23.1421 27.5 26.5 24.1421 26.5 20C26.5 15.8579 23.1421 12.5 19 12.5Z" fill="#939BA1"/>
|
||||
<path d="M11 19.25C10.5858 19.25 10.25 19.5858 10.25 20C10.25 20.4142 10.5858 20.75 11 20.75H19C19.4142 20.75 19.75 20.4142 19.75 20C19.75 19.5858 19.4142 19.25 19 19.25H11Z" fill="#939BA1"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
Loading…
x
Reference in New Issue
Block a user