Skip to content

Commit

Permalink
Implement signRaw
Browse files Browse the repository at this point in the history
  • Loading branch information
c410-f3r committed Nov 25, 2019
1 parent 04d044e commit 301079f
Show file tree
Hide file tree
Showing 10 changed files with 211 additions and 72 deletions.
59 changes: 59 additions & 0 deletions packages/extension-ui/src/Popup/Signing/Bytes.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright 2019 @polkadot/extension-ui authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.

import styled from 'styled-components';
import React from 'react';

interface Props {
className?: string;
bytes: string;
url: string;
}

function Bytes ({ bytes, className, url }: Props): React.ReactElement<Props> {
return (
<table className={className}>
<tbody>
<tr>
<td className='label'>from</td>
<td className='data'>{url}</td>
</tr>
<tr>
<td className='label'>bytes</td>
<td className='data'>{bytes}</td>
</tr>
</tbody>
</table>
);
}

export default styled(Bytes)`
border: 0;
display: block;
font-size: 0.75rem;
margin-top: 0.75rem;
td.data {
max-width: 0;
overflow: hidden;
text-align: left;
text-overflow: ellipsis;
vertical-align: middle;
width: 100%;
pre {
font-family: inherit;
font-size: 0.75rem;
margin: 0;
}
}
td.label {
opacity: 0.5;
padding: 0 0.5rem;
text-align: right;
vertical-align: middle;
white-space: nowrap;
}
`;
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ function mortalityAsString (era: ExtrinsicEra, hexBlockNumber: string): string {
return `mortal, valid from #${formatNumber(mortal.birth(blockNumber))} to #${formatNumber(mortal.death(blockNumber))}`;
}

function Details ({ className, isDecoded, payload: { era, nonce, tip }, request: { blockNumber, genesisHash, method, specVersion: hexSpec }, url }: Props): React.ReactElement<Props> {
function Extrinsic ({ className, isDecoded, payload: { era, nonce, tip }, request: { blockNumber, genesisHash, method, specVersion: hexSpec }, url }: Props): React.ReactElement<Props> {
const chain = useRef(findChain(genesisHash)).current;
const specVersion = useRef(bnToBn(hexSpec)).current;
const [decoded, setDecoded] = useState<Decoded>({ json: null, method: null });
Expand Down Expand Up @@ -139,7 +139,7 @@ function Details ({ className, isDecoded, payload: { era, nonce, tip }, request:
);
}

export default styled(Details)`
export default styled(Extrinsic)`
border: 0;
display: block;
font-size: 0.75rem;
Expand Down
92 changes: 56 additions & 36 deletions packages/extension-ui/src/Popup/Signing/Request.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,42 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.

import { AccountJson, RequestSign } from '@polkadot/extension/background/types';
import { ExtrinsicPayload } from '@polkadot/types/interfaces';
import { AccountJson, RequestExtrinsicSign } from '@polkadot/extension/background/types';
import { SignerPayloadJSON, SignerPayloadRaw } from '@polkadot/types/types';
import { createType } from '@polkadot/types';

import React, { useContext, useState, useEffect } from 'react';
import { createType } from '@polkadot/types';

import { ActionBar, ActionContext, Address, Link } from '../../components';
import { approveSignPassword, approveSignSignature, cancelSignRequest } from '../../messaging';
import Details from './Details';
import Bytes from './Bytes';
import Extrinsic from './Extrinsic';
import Qr from './Qr';
import Unlock from './Unlock';

interface Props {
account: AccountJson;
isFirst: boolean;
request: RequestExtrinsicSign;
request: RequestSign;
signId: string;
url: string;
}

export default function Request ({ account: { isExternal }, isFirst, request, signId, url }: Props): React.ReactElement<Props> | null {
const onAction = useContext(ActionContext);
const [payload, setPayload] = useState<ExtrinsicPayload | null>(null);
const [hexBytes, setHexBytes] = useState<string | null>(null);
const [extrinsic, setExtrinsic] = useState<ExtrinsicPayload | null>(null);

useEffect((): void => {
setPayload(createType('ExtrinsicPayload', request, { version: request.version }));
const inner = request.inner;
if ((inner as SignerPayloadRaw).data) {
setHexBytes((inner as SignerPayloadRaw).data);
} else {
setExtrinsic(createType('ExtrinsicPayload', request, { version: (inner as SignerPayloadJSON).version }));
}
}, [request]);

if (!payload) {
return null;
}

const _onCancel = (): Promise<void> =>
cancelSignRequest(signId)
.then((): void => onAction())
Expand All @@ -46,30 +50,46 @@ export default function Request ({ account: { isExternal }, isFirst, request, si
approveSignSignature(signId, signature)
.then((): void => onAction())
.catch((error: Error) => console.error(error));

return (
<Address
address={request.address}
genesisHash={request.genesisHash}
>
{isExternal && isFirst
? <Qr
payload={payload}
request={request}
onSignature={_onSignature}
/>
: <Details
isDecoded={isFirst}
payload={payload}
request={request}
url={url}
/>
}
{isFirst && !isExternal && <Unlock onSign={_onSign} />}
<ActionBar>
<div />
<Link isDanger onClick={_onCancel}>Cancel</Link>
</ActionBar>
</Address>
);
if (extrinsic !== null) {
const payload = request.inner as SignerPayloadJSON;
return (
<Address
address={payload.address}
genesisHash={payload.genesisHash}
>
{isExternal && isFirst
? <Qr
payload={extrinsic}
request={payload}
onSignature={_onSignature}
/>
: <Extrinsic
isDecoded={isFirst}
payload={extrinsic}
request={payload}
url={url}
/>
}
{isFirst && !isExternal && <Unlock onSign={_onSign} />}
<ActionBar>
<div />
<Link isDanger onClick={_onCancel}>Cancel</Link>
</ActionBar>
</Address>
);
} else if (hexBytes !== null) {
const payload = request.inner as SignerPayloadRaw;
return (
<Address address={payload.address}>
<Bytes bytes={payload.data} url={url} />
{isFirst && !isExternal && <Unlock onSign={_onSign} />}
<ActionBar>
<div />
<Link isDanger onClick={_onCancel}>Cancel</Link>
</ActionBar>
</Address>
);
} else {
return null;
}
}
22 changes: 22 additions & 0 deletions packages/extension/src/background/RequestBytesSign.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2019 @polkadot/extension authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.

import { KeyringPair } from '@polkadot/keyring/types';
import { RequestSign } from './types';
import { SignerPayloadJSON, SignerPayloadRaw } from '@polkadot/types/types';
import { u8aToHex, stringToU8a } from '@polkadot/util';

export default class RequestBytesSign implements RequestSign {
inner: SignerPayloadJSON | SignerPayloadRaw;

constructor (inner: SignerPayloadRaw) {
this.inner = inner;
}

sign (pair: KeyringPair): { signature: string } {
const inner = this.inner as SignerPayloadRaw;
const signedBytes = pair.sign(stringToU8a(inner.data));
return { signature: u8aToHex(signedBytes) };
}
}
22 changes: 22 additions & 0 deletions packages/extension/src/background/RequestExtrinsicSign.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2019 @polkadot/extension authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.

import { createType } from '@polkadot/types';
import { KeyringPair } from '@polkadot/keyring/types';
import { RequestSign } from './types';
import { SignerPayloadJSON, SignerPayloadRaw } from '@polkadot/types/types';

export default class RequestExtrinsicSign implements RequestSign {
inner: SignerPayloadJSON | SignerPayloadRaw;

constructor (inner: SignerPayloadJSON) {
this.inner = inner;
}

sign (pair: KeyringPair): { signature: string } {
const inner = this.inner as SignerPayloadJSON;
const extrinsic = createType('ExtrinsicPayload', this.inner, { version: inner.version });
return extrinsic.sign(pair);
}
}
8 changes: 2 additions & 6 deletions packages/extension/src/background/handlers/Extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { AccountJson, AuthorizeRequest, MessageTypes, RequestAccountCreateExtern
import extension from 'extensionizer';
import keyring from '@polkadot/ui-keyring';
import accountsObservable from '@polkadot/ui-keyring/observable/accounts';
import { createType } from '@polkadot/types';
import { assert, isHex } from '@polkadot/util';
import { keyExtractSuri, mnemonicGenerate, mnemonicValidate } from '@polkadot/util-crypto';

Expand Down Expand Up @@ -150,7 +149,7 @@ export default class Extension {
assert(queued, 'Unable to find request');

const { request, resolve, reject } = queued;
const pair = keyring.getPair(request.address);
const pair = keyring.getPair(request.inner.address);

if (!pair) {
reject(new Error('Unable to find pair'));
Expand All @@ -159,10 +158,7 @@ export default class Extension {
}

pair.decodePkcs8(password);

const payload = createType('ExtrinsicPayload', request, { version: request.version });
const result = payload.sign(pair);

const result = request.sign(pair);
pair.lock();

resolve({
Expand Down
12 changes: 6 additions & 6 deletions packages/extension/src/background/handlers/State.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.

import { AccountJson, AuthorizeRequest, RequestAuthorizeTab, RequestExtrinsicSign, ResponseExtrinsicSign, SigningRequest } from '../types';
import { AccountJson, AuthorizeRequest, RequestAuthorizeTab, RequestSign, ResponseSigning, SigningRequest } from '../types';

import extension from 'extensionizer';
import { BehaviorSubject } from 'rxjs';
Expand All @@ -28,8 +28,8 @@ type AuthUrls = Record<string, {
interface SignRequest {
account: AccountJson;
id: string;
request: RequestExtrinsicSign;
resolve: (result: ResponseExtrinsicSign) => void;
request: RequestSign;
resolve: (result: ResponseSigning) => void;
reject: (error: Error) => void;
url: string;
}
Expand Down Expand Up @@ -125,8 +125,8 @@ export default class State {
};
}

private signComplete = (id: string, fn: Function): (result: ResponseExtrinsicSign | Error) => void => {
return (result: ResponseExtrinsicSign | Error): void => {
private signComplete = (id: string, fn: Function): (result: ResponseSigning | Error) => void => {
return (result: ResponseSigning | Error): void => {
delete this._signRequests[id];
this.updateIconSign(true);

Expand Down Expand Up @@ -211,7 +211,7 @@ export default class State {
return this._signRequests[id];
}

public signQueue (url: string, request: RequestExtrinsicSign, account: AccountJson): Promise<ResponseExtrinsicSign> {
public sign (url: string, request: RequestSign, account: AccountJson): Promise<ResponseSigning> {
const id = getId();

return new Promise((resolve, reject): void => {
Expand Down
28 changes: 22 additions & 6 deletions packages/extension/src/background/handlers/Tabs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@
// of the Apache-2.0 license. See the LICENSE file for details.

import { InjectedAccount } from '@polkadot/extension-inject/types';
import { KeyringPair } from '@polkadot/keyring/types';
import { RequestAuthorizeTab, ResponseSigning, RequestTypes, ResponseTypes, MessageTypes } from '../types';
import { SignerPayloadJSON, SignerPayloadRaw } from '@polkadot/types/types';
import { SubjectInfo } from '@polkadot/ui-keyring/observable/types';
import { RequestAuthorizeTab, RequestExtrinsicSign, ResponseExtrinsicSign, RequestTypes, ResponseTypes, MessageTypes } from '../types';

import keyring from '@polkadot/ui-keyring';
import accountsObservable from '@polkadot/ui-keyring/observable/accounts';
import { assert } from '@polkadot/util';
import RequestBytesSign from '../RequestBytesSign';
import RequestExtrinsicSign from '../RequestExtrinsicSign';

import State from './State';
import { createSubscription, unsubscribe } from './subscriptions';
Expand Down Expand Up @@ -50,13 +54,22 @@ export default class Tabs {
return true;
}

private extrinsicSign (url: string, request: RequestExtrinsicSign): Promise<ResponseExtrinsicSign> {
const { address } = request;
private getSigningPair (address: string): KeyringPair {
const pair = keyring.getPair(address);

assert(pair, 'Unable to find keypair');
return pair;
}

return this.state.signQueue(url, request, { address, ...pair.meta });
private bytesSign (url: string, request: SignerPayloadRaw): Promise<ResponseSigning> {
const address = request.address;
const pair = this.getSigningPair(address);
return this.state.sign(url, new RequestBytesSign(request), { address, ...pair.meta });
}

private extrinsicSign (url: string, request: SignerPayloadJSON): Promise<ResponseSigning> {
const address = request.address;
const pair = this.getSigningPair(address);
return this.state.sign(url, new RequestExtrinsicSign(request), { address, ...pair.meta });
}

public async handle<TMessageType extends MessageTypes> (id: string, type: TMessageType, request: RequestTypes[TMessageType], url: string, port: chrome.runtime.Port): Promise<ResponseTypes[keyof ResponseTypes]> {
Expand All @@ -74,8 +87,11 @@ export default class Tabs {
case 'pub(accounts.subscribe)':
return this.accountsSubscribe(url, id, port);

case 'pub(bytes.sign)':
return this.bytesSign(url, request as SignerPayloadRaw);

case 'pub(extrinsic.sign)':
return this.extrinsicSign(url, request as RequestExtrinsicSign);
return this.extrinsicSign(url, request as SignerPayloadJSON);

default:
throw new Error(`Unable to handle message of type ${type}`);
Expand Down
Loading

0 comments on commit 301079f

Please sign in to comment.