Fix/Update method permissions (#7233)
* Use hex everywhere as appId * Extract requestGroup sub item from clarity * Change size of icon in SignerPending
This commit is contained in:
parent
3cb4d81eb1
commit
f6f7a87dc6
30
js/package-lock.json
generated
30
js/package-lock.json
generated
@ -53,7 +53,7 @@
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@parity/api": "2.1.5",
|
||||
"@parity/shared": "2.2.8",
|
||||
"@parity/shared": "2.2.9",
|
||||
"@parity/ui": "2.2.15",
|
||||
"lodash": "4.17.4",
|
||||
"mobx": "3.3.2",
|
||||
@ -76,7 +76,7 @@
|
||||
"requires": {
|
||||
"@parity/api": "2.1.5",
|
||||
"@parity/etherscan": "2.1.3",
|
||||
"@parity/shared": "2.2.8",
|
||||
"@parity/shared": "2.2.9",
|
||||
"bignumber.js": "3.0.1",
|
||||
"brace": "0.9.0",
|
||||
"date-difference": "1.0.0",
|
||||
@ -578,7 +578,7 @@
|
||||
"requires": {
|
||||
"@parity/api": "2.1.5",
|
||||
"@parity/etherscan": "2.1.3",
|
||||
"@parity/shared": "2.2.8",
|
||||
"@parity/shared": "2.2.9",
|
||||
"bignumber.js": "3.0.1",
|
||||
"brace": "0.9.0",
|
||||
"date-difference": "1.0.0",
|
||||
@ -1151,9 +1151,9 @@
|
||||
"version": "github:paritytech/plugin-signer-qr#c16423de5b8a8f68ebd5f1e78e084fa959329a9f"
|
||||
},
|
||||
"@parity/shared": {
|
||||
"version": "2.2.8",
|
||||
"resolved": "https://registry.npmjs.org/@parity/shared/-/shared-2.2.8.tgz",
|
||||
"integrity": "sha512-gSF4rX2dsjEHAlWvCSNRPeWRSGBKLxev6ke6othzmO4AluTK71A4ZM3N18fw5NTybCiiELbdNUPkxzCtvs92Ew==",
|
||||
"version": "2.2.9",
|
||||
"resolved": "https://registry.npmjs.org/@parity/shared/-/shared-2.2.9.tgz",
|
||||
"integrity": "sha512-bbzfcFNt0XsO9oJj3ySPfMgFAcPtFJElHbEXTm4xU4xntADoSIYuWtvonq2uULxA1LQ1O+1hGpyagQ8OZ+YoqQ==",
|
||||
"requires": {
|
||||
"@parity/ledger": "2.1.2",
|
||||
"eventemitter3": "2.0.3",
|
||||
@ -1215,7 +1215,7 @@
|
||||
"requires": {
|
||||
"@parity/api": "2.1.5",
|
||||
"@parity/etherscan": "2.1.3",
|
||||
"@parity/shared": "2.2.8",
|
||||
"@parity/shared": "2.2.9",
|
||||
"babel-runtime": "6.26.0",
|
||||
"bignumber.js": "4.1.0",
|
||||
"brace": "0.11.0",
|
||||
@ -2371,7 +2371,6 @@
|
||||
"version": "6.24.1",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.24.1.tgz",
|
||||
"integrity": "sha1-0+MQtA72ZKNmIiAAl8bUQCmPK/4=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"babel-plugin-transform-strict-mode": "6.24.1",
|
||||
"babel-runtime": "6.26.0",
|
||||
@ -2709,7 +2708,7 @@
|
||||
"babel-plugin-transform-es2015-function-name": "6.24.1",
|
||||
"babel-plugin-transform-es2015-literals": "6.22.0",
|
||||
"babel-plugin-transform-es2015-modules-amd": "6.24.1",
|
||||
"babel-plugin-transform-es2015-modules-commonjs": "6.26.0",
|
||||
"babel-plugin-transform-es2015-modules-commonjs": "6.24.1",
|
||||
"babel-plugin-transform-es2015-modules-systemjs": "6.24.1",
|
||||
"babel-plugin-transform-es2015-modules-umd": "6.24.1",
|
||||
"babel-plugin-transform-es2015-object-super": "6.24.1",
|
||||
@ -2721,19 +2720,6 @@
|
||||
"babel-plugin-transform-es2015-typeof-symbol": "6.23.0",
|
||||
"babel-plugin-transform-es2015-unicode-regex": "6.24.1",
|
||||
"babel-plugin-transform-regenerator": "6.26.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"babel-plugin-transform-es2015-modules-commonjs": {
|
||||
"version": "6.26.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.0.tgz",
|
||||
"integrity": "sha1-DYOUApt9xqvhqX7xgeAHWN0uXYo=",
|
||||
"requires": {
|
||||
"babel-plugin-transform-strict-mode": "6.24.1",
|
||||
"babel-runtime": "6.26.0",
|
||||
"babel-template": "6.26.0",
|
||||
"babel-types": "6.26.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"babel-preset-flow": {
|
||||
|
@ -147,7 +147,7 @@
|
||||
"@parity/plugin-signer-default": "paritytech/plugin-signer-default",
|
||||
"@parity/plugin-signer-hardware": "paritytech/plugin-signer-hardware",
|
||||
"@parity/plugin-signer-qr": "paritytech/plugin-signer-qr",
|
||||
"@parity/shared": "^2.2.8",
|
||||
"@parity/shared": "^2.2.9",
|
||||
"@parity/ui": "^3.0.14",
|
||||
"keythereum": "1.0.2",
|
||||
"lodash.flatten": "4.4.0",
|
||||
|
@ -6,4 +6,16 @@ To be clear with the terminology used in the code here:
|
||||
- a *methodGroup* is the grouping of similar methods (see `methodGroups.js`)
|
||||
- a *permission* is a boolean which tells if an app is allowed to call a method or not
|
||||
- a *request* is when an app prompts the shell to call a method
|
||||
- a *requestGroup* is an array of *requests* whose methods are in the same *methodGroup*
|
||||
- a *requestGroup* is a map of the following form
|
||||
```javascript
|
||||
{
|
||||
appId1: {
|
||||
methodGroup1: [request1, request2] // This is a requestGroup sub-item
|
||||
},
|
||||
appId2: {
|
||||
methodGroup1: [request1]
|
||||
methodGroup2: [request3]
|
||||
},
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
@ -0,0 +1,24 @@
|
||||
/* Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
/* This file is part of Parity.
|
||||
/*
|
||||
/* Parity is free software: you can redistribute it and/or modify
|
||||
/* it under the terms of the GNU General Public License as published by
|
||||
/* the Free Software Foundation, either version 3 of the License, or
|
||||
/* (at your option) any later version.
|
||||
/*
|
||||
/* Parity is distributed in the hope that it will be useful,
|
||||
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
/* GNU General Public License for more details.
|
||||
/*
|
||||
/* You should have received a copy of the GNU General Public License
|
||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
.requestGroupSubItem {
|
||||
margin-top: 2px;
|
||||
|
||||
.requestGroupSubItemTitle {
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { PureComponent } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import Popup from 'semantic-ui-react/dist/commonjs/modules/Popup';
|
||||
import Button from '@parity/ui/lib/Button';
|
||||
|
||||
import methodGroups from '../../methodGroups';
|
||||
import styles from './RequestGroupSubItem.css';
|
||||
|
||||
export default class RequestGroupSubItem extends PureComponent {
|
||||
handleApprove = () => this.props.onApprove(this.props.requests, this.props.groupId)
|
||||
|
||||
handleReject = () => this.props.onReject(this.props.requests)
|
||||
|
||||
render () {
|
||||
const { groupId } = this.props;
|
||||
|
||||
return (
|
||||
<div className={ styles.requestGroupSubItem }>
|
||||
<span className={ styles.requestGroupSubItemTitle }>
|
||||
Permission for{' '}
|
||||
<Popup
|
||||
trigger={ <span>{groupId}</span> }
|
||||
content={ `Requested methods: ${methodGroups[groupId].methods.join(', ')}` }
|
||||
/>
|
||||
</span>
|
||||
<Button
|
||||
size='mini'
|
||||
label={
|
||||
<FormattedMessage
|
||||
id='dappRequests.request.buttons.approve'
|
||||
defaultMessage='Approve'
|
||||
/>
|
||||
}
|
||||
onClick={ this.handleApprove }
|
||||
/>
|
||||
<Button
|
||||
size='mini'
|
||||
label={
|
||||
<FormattedMessage
|
||||
id='dappRequests.request.buttons.reject'
|
||||
defaultMessage='Reject'
|
||||
/>
|
||||
}
|
||||
onClick={ this.handleReject }
|
||||
/>
|
||||
</div>
|
||||
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
RequestGroupSubItem.propTypes = {
|
||||
className: PropTypes.string,
|
||||
groupId: PropTypes.string,
|
||||
onApprove: PropTypes.func.isRequired,
|
||||
onReject: PropTypes.func.isRequired,
|
||||
requests: PropTypes.array.isRequired
|
||||
};
|
@ -0,0 +1,17 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
export default from './RequestGroupSubItem';
|
@ -28,12 +28,4 @@ $backgroundTwo: #e57a00;
|
||||
> span {
|
||||
margin-right: 30px;
|
||||
}
|
||||
|
||||
.requestGroup {
|
||||
margin-top: 2px;
|
||||
|
||||
.requestGroupTitle {
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,49 +14,25 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { PureComponent } from 'react';
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import Popup from 'semantic-ui-react/dist/commonjs/modules/Popup';
|
||||
import Button from '@parity/ui/lib/Button';
|
||||
|
||||
import DappsStore from '@parity/shared/lib/mobx/dappsStore';
|
||||
|
||||
import RequestGroupSubItem from './RequestGroupSubItem';
|
||||
import styles from './RequestGroups.css';
|
||||
|
||||
export default class RequestGroups extends PureComponent {
|
||||
state = {
|
||||
opened: false
|
||||
};
|
||||
|
||||
handleApproveRequestGroup = groupId => {
|
||||
const { requestGroups, onApproveRequestGroup } = this.props;
|
||||
|
||||
onApproveRequestGroup(Object.values(requestGroups[groupId].map(({ requestId }) => requestId)));
|
||||
}
|
||||
|
||||
handleRejectRequestGroup = groupId => {
|
||||
const { requestGroups, onRejectRequestGroup } = this.props;
|
||||
|
||||
onRejectRequestGroup(Object.values(requestGroups[groupId].map(({ requestId }) => requestId)));
|
||||
}
|
||||
|
||||
renderPopupContent = groupId => {
|
||||
const { requestGroups } = this.props;
|
||||
// Get unique list of methods in that request group
|
||||
const requestedMethods = [...new Set(
|
||||
Object.values(requestGroups[groupId])
|
||||
.map(request => request.data.method || request.data.params[0])
|
||||
)];
|
||||
|
||||
return `Requested methods: ${requestedMethods.join(', ')}`;
|
||||
export default class RequestGroups extends Component {
|
||||
handleApproveRequestGroup = (requests, groupId) => {
|
||||
this.props.onApproveRequestGroup(requests, groupId, this.props.appId);
|
||||
}
|
||||
|
||||
render () {
|
||||
const {
|
||||
appId,
|
||||
requestGroups
|
||||
requestGroups,
|
||||
onRejectRequestGroup
|
||||
} = this.props;
|
||||
|
||||
const app = DappsStore.get().getAppById(appId);
|
||||
@ -72,35 +48,13 @@ export default class RequestGroups extends PureComponent {
|
||||
} }
|
||||
/>
|
||||
{Object.keys(requestGroups).map(groupId => (
|
||||
<div key={ `${appId}-${groupId}` } className={ styles.requestGroup }>
|
||||
<span className={ styles.requestGroupTitle }>
|
||||
Permission for{' '}
|
||||
<Popup
|
||||
trigger={ <span>{groupId}</span> }
|
||||
content={ this.renderPopupContent(groupId) }
|
||||
/>
|
||||
</span>
|
||||
<Button
|
||||
size='mini'
|
||||
label={
|
||||
<FormattedMessage
|
||||
id='dappRequests.request.buttons.approve'
|
||||
defaultMessage='Approve'
|
||||
/>
|
||||
}
|
||||
onClick={ () => this.handleApproveRequestGroup(groupId) }
|
||||
/>
|
||||
<Button
|
||||
size='mini'
|
||||
label={
|
||||
<FormattedMessage
|
||||
id='dappRequests.request.buttons.reject'
|
||||
defaultMessage='Reject'
|
||||
/>
|
||||
}
|
||||
onClick={ () => this.handleRejectRequestGroup(groupId) }
|
||||
/>
|
||||
</div>
|
||||
<RequestGroupSubItem
|
||||
key={ `${appId}-${groupId}` }
|
||||
groupId={ groupId }
|
||||
requests={ requestGroups[groupId] }
|
||||
onApprove={ this.handleApproveRequestGroup }
|
||||
onReject={ onRejectRequestGroup }
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
@ -17,6 +17,7 @@
|
||||
import { observer } from 'mobx-react';
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import methodGroups from './methodGroups';
|
||||
import RequestGroups from './RequestGroups';
|
||||
import Store from './store';
|
||||
import styles from './dappRequests.css';
|
||||
@ -24,12 +25,16 @@ import styles from './dappRequests.css';
|
||||
class DappRequests extends Component {
|
||||
store = Store.get();
|
||||
|
||||
handleApproveRequestGroup = requestIds => {
|
||||
requestIds.forEach(this.store.approveRequest);
|
||||
// When we approve a requestGroup, when approve all the requests, and add permissions
|
||||
// to all the other methods in the same methodGroup
|
||||
handleApproveRequestGroup = (requests, groupId, appId) => {
|
||||
requests.map(({ requestId }) => requestId).forEach(this.store.approveRequest);
|
||||
methodGroups[groupId].methods.forEach(method => this.store.addAppPermission(method, appId));
|
||||
}
|
||||
|
||||
handleRejectRequestGroup = requestIds => {
|
||||
requestIds.forEach(this.store.rejectRequest);
|
||||
// When we reject a requestGroup, we reject the requests in that group
|
||||
handleRejectRequestGroup = requests => {
|
||||
requests.map(({ requestId }) => requestId).forEach(this.store.rejectRequest);
|
||||
}
|
||||
|
||||
render () {
|
||||
|
@ -18,6 +18,7 @@ import { action, computed, observable } from 'mobx';
|
||||
import store from 'store';
|
||||
|
||||
import { sha3 } from '@parity/api/lib/util/sha3';
|
||||
import { isHex } from '@parity/api/lib/util/types';
|
||||
|
||||
import { methodGroupFromMethod } from './methodGroups';
|
||||
|
||||
@ -52,7 +53,7 @@ export default class Store {
|
||||
|
||||
accumulator[appId] = accumulator[appId] || {};
|
||||
accumulator[appId][methodGroup] = accumulator[appId][methodGroup] || [];
|
||||
accumulator[appId][methodGroup].push({ data, requestId }); // Append the requestId field in the request object
|
||||
accumulator[appId][methodGroup].push({ data, requestId }); // Push request & append the requestId field in the request object
|
||||
|
||||
return accumulator;
|
||||
}, {});
|
||||
@ -99,7 +100,7 @@ export default class Store {
|
||||
this.requests = { ...this.requests };
|
||||
};
|
||||
|
||||
getPermissionId = (method, appId) => `${method}:${appId}` // Create an id to identify permissions based on method and appId
|
||||
getPermissionId = (method, appId) => `${method}:${isHex(appId) ? appId : sha3(appId)}`; // Create an id to identify permissions based on method and appId
|
||||
|
||||
getMethodFromRequest = requestId => {
|
||||
const { data: { method, params } } = this.requests[requestId];
|
||||
@ -131,13 +132,10 @@ export default class Store {
|
||||
};
|
||||
|
||||
setPermissions = _permissions => {
|
||||
const permissions = {};
|
||||
|
||||
Object.keys(_permissions).forEach(id => {
|
||||
permissions[id] = !!_permissions[id];
|
||||
});
|
||||
|
||||
this.permissions = permissions;
|
||||
this.permissions = {
|
||||
...this.permissions,
|
||||
..._permissions
|
||||
};
|
||||
this.savePermissions();
|
||||
|
||||
return true;
|
||||
|
@ -19,7 +19,6 @@
|
||||
background: rgba(40, 40, 40, 0.85);
|
||||
color: white;
|
||||
line-height: 1.5em;
|
||||
text-align: left;
|
||||
padding: 4em 2em;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
|
@ -19,6 +19,11 @@
|
||||
display: flex !important;
|
||||
}
|
||||
|
||||
.fromAvatar {
|
||||
width: 28px !important;
|
||||
height: 28px !important;
|
||||
}
|
||||
|
||||
.toAvatar {
|
||||
margin-left: 3px;
|
||||
}
|
||||
|
@ -168,6 +168,7 @@ class RequestItem extends Component {
|
||||
<List.Item onClick={ onClick }>
|
||||
<Image avatar size='mini' verticalAlign='middle'>
|
||||
<IdentityIcon
|
||||
className={ styles.fromAvatar }
|
||||
address={ transaction.from }
|
||||
/>
|
||||
</Image>
|
||||
|
Loading…
Reference in New Issue
Block a user