From 7feb82c242673f7995c5577da3a9cba8f5d0d1e8 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Wed, 11 Oct 2017 21:05:50 +0200 Subject: [PATCH] Display vouched overlay on dapps (#6710) * Remove .only * Add vouch overlays to dapps * Cleanup address * Only run where we have a contentHash * GitLab kickstart --- js/scripts/test.js | 2 +- js/src/contracts/abi/index.js | 1 + js/src/contracts/abi/vouchfor.json | 1 + js/src/ui/DappCard/dappCard.js | 2 + js/src/ui/DappVouchFor/dappVouchFor.css | 43 +++++++++++ js/src/ui/DappVouchFor/dappVouchFor.js | 57 ++++++++++++++ js/src/ui/DappVouchFor/index.js | 17 +++++ js/src/ui/DappVouchFor/store.js | 74 +++++++++++++++++++ js/src/ui/IdentityIcon/identityIcon.js | 4 +- .../SignRequest/signRequest.spec.js | 4 +- 10 files changed, 201 insertions(+), 4 deletions(-) create mode 100644 js/src/contracts/abi/vouchfor.json create mode 100644 js/src/ui/DappVouchFor/dappVouchFor.css create mode 100644 js/src/ui/DappVouchFor/dappVouchFor.js create mode 100644 js/src/ui/DappVouchFor/index.js create mode 100644 js/src/ui/DappVouchFor/store.js diff --git a/js/scripts/test.js b/js/scripts/test.js index e426642db..e60e3cb6c 100644 --- a/js/scripts/test.js +++ b/js/scripts/test.js @@ -1 +1 @@ -// test script 10 +// test script 11 diff --git a/js/src/contracts/abi/index.js b/js/src/contracts/abi/index.js index f475cce07..eac825820 100644 --- a/js/src/contracts/abi/index.js +++ b/js/src/contracts/abi/index.js @@ -29,3 +29,4 @@ export signaturereg from './signaturereg.json'; export smsverification from './sms-verification.json'; export tokenreg from './tokenreg.json'; export foundationWallet from './foundation-multisig-wallet.json'; +export vouchfor from './vouchfor.json'; diff --git a/js/src/contracts/abi/vouchfor.json b/js/src/contracts/abi/vouchfor.json new file mode 100644 index 000000000..362eb0c8b --- /dev/null +++ b/js/src/contracts/abi/vouchfor.json @@ -0,0 +1 @@ +[{"constant":true,"inputs":[],"name":"certifier","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_what","type":"bytes32"}],"name":"vouch","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_what","type":"bytes32"},{"name":"_index","type":"uint256"}],"name":"vouched","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_what","type":"bytes32"},{"name":"_index","type":"uint256"}],"name":"unvouch","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"bytes32"},{"name":"","type":"uint256"}],"name":"vouchers","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_certifier","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"who","type":"address"},{"indexed":false,"name":"what","type":"bytes32"}],"name":"Vouched","type":"event"}] diff --git a/js/src/ui/DappCard/dappCard.js b/js/src/ui/DappCard/dappCard.js index cc0faf47d..0e3f65fcc 100644 --- a/js/src/ui/DappCard/dappCard.js +++ b/js/src/ui/DappCard/dappCard.js @@ -19,6 +19,7 @@ import React, { Component, PropTypes } from 'react'; import Container, { Title as ContainerTitle } from '~/ui/Container'; import DappIcon from '~/ui/DappIcon'; import Tags from '~/ui/Tags'; +import DappVouchFor from '../DappVouchFor'; import styles from './dappCard.css'; @@ -61,6 +62,7 @@ export default class DappCard extends Component { app={ app } className={ styles.image } /> + . +*/ + +.tag { + color: inherit; + position: absolute; + top: 1em; + right: 1em; + + .image { + position: absolute; + right: 0; + top: 0; + width: 32px; + height: 32px; + } + + .bubble { + background: red; + border-radius: 0.25em; + color: white; + font-size: 0.75em; + padding: 0.1em 0.5em; + position: absolute; + right: 0; + top: 0; + z-index: 100; + } +} diff --git a/js/src/ui/DappVouchFor/dappVouchFor.js b/js/src/ui/DappVouchFor/dappVouchFor.js new file mode 100644 index 000000000..426c881cd --- /dev/null +++ b/js/src/ui/DappVouchFor/dappVouchFor.js @@ -0,0 +1,57 @@ +// 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 . + +import React, { Component, PropTypes } from 'react'; +import { observer } from 'mobx-react'; + +import IdentityIcon from '../IdentityIcon'; + +import Store from './store'; +import styles from './dappVouchFor.css'; + +@observer +export default class DappVouchFor extends Component { + static contextTypes = { + api: PropTypes.object.isRequired + }; + + static propTypes = { + app: PropTypes.object.isRequired + }; + + store = new Store(this.context.api, this.props.app); + + render () { + const count = this.store.vouchers.length; + + if (!count) { + return null; + } + + return ( +
+ +
+ { count } +
+
+ ); + } +} diff --git a/js/src/ui/DappVouchFor/index.js b/js/src/ui/DappVouchFor/index.js new file mode 100644 index 000000000..be61d5029 --- /dev/null +++ b/js/src/ui/DappVouchFor/index.js @@ -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 . + +export default from './dappVouchFor'; diff --git a/js/src/ui/DappVouchFor/store.js b/js/src/ui/DappVouchFor/store.js new file mode 100644 index 000000000..cee44749d --- /dev/null +++ b/js/src/ui/DappVouchFor/store.js @@ -0,0 +1,74 @@ +// 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 . + +import { action, observable } from 'mobx'; +import { uniq } from 'lodash'; + +import Contracts from '~/contracts'; +import { vouchfor as vouchForAbi } from '~/contracts/abi'; + +export default class Store { + @observable vouchers = []; + + constructor (api, app) { + this._api = api; + + const { contentHash } = app; + + if (contentHash) { + this.lookupVouchers(contentHash); + } + } + + lookupVouchers (contentHash) { + Contracts + .get().registry + .lookupAddress('vouchfor') + .then((address) => { + if (!address || /^0x0*$/.test(address)) { + return; + } + + return this._api.newContract(vouchForAbi, address); + }) + .then(async (contract) => { + if (!contract) { + return; + } + + let lastItem = false; + + for (let index = 0; !lastItem; index++) { + const voucher = await contract.instance.vouched.call({}, [`0x${contentHash}`, index]); + + if (/^0x0*$/.test(voucher)) { + lastItem = true; + } else { + this.addVoucher(voucher); + } + } + }) + .catch((error) => { + console.error('vouchFor', error); + + return; + }); + } + + @action addVoucher = (voucher) => { + this.vouchers = uniq([].concat(this.vouchers.peek(), [voucher])); + } +} diff --git a/js/src/ui/IdentityIcon/identityIcon.js b/js/src/ui/IdentityIcon/identityIcon.js index 3db1bc763..0d31b6bb5 100644 --- a/js/src/ui/IdentityIcon/identityIcon.js +++ b/js/src/ui/IdentityIcon/identityIcon.js @@ -30,6 +30,7 @@ class IdentityIcon extends Component { static propTypes = { address: PropTypes.string, + alt: PropTypes.string, button: PropTypes.bool, center: PropTypes.bool, className: PropTypes.string, @@ -84,7 +85,7 @@ class IdentityIcon extends Component { } render () { - const { address, button, className, center, disabled, inline, padded, tiny } = this.props; + const { address, alt, button, className, center, disabled, inline, padded, tiny } = this.props; const { iconsrc } = this.state; const classes = [ styles.icon, @@ -135,6 +136,7 @@ class IdentityIcon extends Component { return ( { { expect(component).to.be.ok; }); - describe.only('isMarkdown', () => { + describe('isMarkdown', () => { it('returns true for markdown', () => { const testMd = '# this is some\n\n*markdown*'; const encodedMd = asciiToHex(unescape(encodeURIComponent(testMd))); @@ -99,7 +99,7 @@ describe('views/Signer/components/SignRequest', () => { expect(isMarkdown(encodedMd)).to.be.true; }); - it('returns false for randow data', () => { + it('returns false for random data', () => { expect(isMarkdown('0x1234')).to.be.false; }); });