diff --git a/package.json b/package.json index 9d9d0c71..e45a07bd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "casperlabs-signer", - "version": "1.1.1", + "version": "1.2.0", "private": true, "dependencies": { "@babel/core": "^7.14.3", diff --git a/public/manifest.json b/public/manifest.json index 632f3425..459f201c 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -1,6 +1,6 @@ { "manifest_version": 2, - "version": "1.1.1", + "version": "1.2.0", "name": "CasperLabs Signer", "author": "https://casperlabs.io", "description": "CasperLabs Signer tool for signing transactions on the blockchain.", diff --git a/src/background/SignMessageManager.ts b/src/background/SignMessageManager.ts index e1b686a8..e0365dbd 100644 --- a/src/background/SignMessageManager.ts +++ b/src/background/SignMessageManager.ts @@ -1,8 +1,7 @@ import * as events from 'events'; import { AppState } from '../lib/MemStore'; import PopupManager from '../background/PopupManager'; -import { DeployUtil, encodeBase16 } from 'casper-client-sdk'; -import { toJS } from 'mobx'; +import { DeployUtil, encodeBase16, PublicKey } from 'casper-client-sdk'; export type deployStatus = 'unsigned' | 'signed' | 'failed'; export interface deployWithID { @@ -10,6 +9,7 @@ export interface deployWithID { status: deployStatus; deploy: DeployUtil.Deploy | undefined; signingKey: string; + targetKey: string; error?: Error; pushed?: boolean; } @@ -119,7 +119,11 @@ export default class SignMessageManager extends events.EventEmitter { * @param {JSON} deployJson * @returns {number} id for added deploy */ - public addUnsignedDeployToQueue(deployJson: any, publicKey: string): number { + public addUnsignedDeployToQueue( + deployJson: any, + sourcePublicKey: string, + targetPublicKey: string + ): number { const id: number = this.createId(); try { @@ -127,14 +131,16 @@ export default class SignMessageManager extends events.EventEmitter { id: id, status: 'unsigned', deploy: DeployUtil.deployFromJson(deployJson), - signingKey: publicKey + signingKey: sourcePublicKey, + targetKey: targetPublicKey }); } catch (err) { this.unsignedDeploys.push({ id: id, status: 'failed', deploy: undefined, - signingKey: publicKey, + signingKey: sourcePublicKey, + targetKey: targetPublicKey, error: err }); } @@ -151,7 +157,8 @@ export default class SignMessageManager extends events.EventEmitter { */ public signDeploy( deploy: any, - publicKey: string // hex-encoded PublicKey bytes with algo prefix + sourcePublicKeyHex: string, // hex-encoded PublicKey bytes with algo prefix + targetPublicKeyHex: string ): Promise { return new Promise((resolve, reject) => { // TODO: Need to abstract it to reusable method @@ -166,7 +173,11 @@ export default class SignMessageManager extends events.EventEmitter { } // Adding the deploy to the queue will update the extension state and UI - const deployId = this.addUnsignedDeployToQueue(deploy, publicKey); + const deployId = this.addUnsignedDeployToQueue( + deploy, + sourcePublicKeyHex, + targetPublicKeyHex + ); this.popupManager.openPopup('sign'); // Await outcome of user interaction with popup. this.once(`${deployId}:finished`, (processedDeploy: deployWithID) => { @@ -274,16 +285,30 @@ export default class SignMessageManager extends events.EventEmitter { let delegator; if (deploy.deploy.session.transfer) { - amount = deploy.deploy.session.transfer - ?.getArgByName('amount')! - .asBigNumber() - .toString(); + // First let's check if the provided targetPublicKey matches the one used in deploy + // We're doing it because its impossible to extract target in a form of PublicKey from Deploy + const providedTargetKeyHash = encodeBase16( + PublicKey.fromHex(deploy.targetKey).toAccountHash() + ); - target = encodeBase16( + const deployTargetKeyHash = encodeBase16( deploy.deploy.session.transfer ?.getArgByName('target')! .asBytesArray()! ); + + if (providedTargetKeyHash !== deployTargetKeyHash) { + throw new Error( + "Provided target public key doesn't match the one in deploy" + ); + } + + target = deploy.targetKey; + + amount = deploy.deploy.session.transfer + ?.getArgByName('amount')! + .asBigNumber() + .toString(); } if (deploy.deploy.session.storedContractByHash) { diff --git a/src/content/inpage.ts b/src/content/inpage.ts index 5078cda2..016c97f5 100644 --- a/src/content/inpage.ts +++ b/src/content/inpage.ts @@ -27,8 +27,8 @@ class CasperLabsPluginHelper { return this.call('removeSite'); } - async sign(deploy: JSON, publicKey: string) { - return this.call('sign', deploy, publicKey); + async sign(deploy: JSON, sourcePublicKey: string, targetPublicKey: string) { + return this.call('sign', deploy, sourcePublicKey, targetPublicKey); } async getActivePublicKey() { diff --git a/src/popup/components/SignMessagePage.tsx b/src/popup/components/SignMessagePage.tsx index 3396017a..d2d3df76 100644 --- a/src/popup/components/SignMessagePage.tsx +++ b/src/popup/components/SignMessagePage.tsx @@ -5,13 +5,15 @@ import SignMessageContainer from '../container/SignMessageContainer'; import Pages from './Pages'; import { browser } from 'webextension-polyfill-ts'; import AccountManager from '../container/AccountManager'; +import { withStyles } from '@material-ui/core/styles'; import { Button, Table, TableBody, TableCell, TableContainer, - TableRow + TableRow, + Tooltip } from '@material-ui/core'; import Typography from '@material-ui/core/Typography'; import Grid from '@material-ui/core/Grid'; @@ -22,9 +24,17 @@ import { deployWithID } from '../../background/SignMessageManager'; const numberWithSpaces = (num: number) => num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ' '); +const styles = () => ({ + tooltip: { + width: '260px', + margin: '10px 0 0 0' + } +}); + interface Props extends RouteComponentProps { signMessageContainer: SignMessageContainer; authContainer: AccountManager; + classes: Record, string>; } @observer @@ -52,8 +62,8 @@ class SignMessagePage extends React.Component< } } - createRow(key: string, value: any) { - return { key, value }; + createRow(key: string, value: any, title?: any) { + return { key, value, title }; } truncateString( @@ -75,10 +85,19 @@ class SignMessagePage extends React.Component< let baseRows = [ this.createRow( 'Signing Key', - this.truncateString(deployData.signingKey, 6, 6) + this.truncateString(deployData.signingKey, 6, 6), + deployData.signingKey + ), + this.createRow( + 'Account', + this.truncateString(deployData.account, 6, 6), + deployData.account + ), + this.createRow( + 'Hash', + this.truncateString(deployData.deployHash, 6, 6), + deployData.deployHash ), - this.createRow('Account', this.truncateString(deployData.account, 6, 6)), - this.createRow('Hash', this.truncateString(deployData.deployHash, 6, 6)), this.createRow('Timestamp', deployData.timestamp), this.createRow('Chain Name', deployData.chainName), this.createRow('Gas Price', deployData.gasPrice), @@ -89,7 +108,11 @@ class SignMessagePage extends React.Component< this.setState({ rows: [ ...baseRows, - this.createRow('To', this.truncateString(deployData.target!, 6, 6)), + this.createRow( + 'Target', + this.truncateString(deployData.target!, 6, 6), + deployData.target + ), this.createRow('Transfer ID', deployData.id) ] }); @@ -99,11 +122,13 @@ class SignMessagePage extends React.Component< ...baseRows, this.createRow( 'Validator', - this.truncateString(deployData.validator!, 6, 6) + this.truncateString(deployData.validator!, 6, 6), + deployData.validator ), this.createRow( 'Delegator', - this.truncateString(deployData.delegator!, 6, 6) + this.truncateString(deployData.delegator!, 6, 6), + deployData.delegator ) ] }); @@ -124,16 +149,23 @@ class SignMessagePage extends React.Component< {this.state.rows.map((row: any) => ( - - - {row.key} - - {row.value} - + + + + {row.key} + + {row.value} + + ))}
@@ -185,4 +217,4 @@ class SignMessagePage extends React.Component< } } -export default withRouter(SignMessagePage); +export default withStyles(styles)(withRouter(SignMessagePage));