Wrap all raw signed bytes inside <Bytes> (#743)
* Wrap all raw signed bytes inside <RawBytes>
* Use u8aToU8a
* Update packages/extension-base/src/background/RequestBytesSign.ts
* Also wrap Qr signing
* Update packages/extension-base/src/utils/wrapRawBytes.ts
* Update packages/extension-base/src/utils/wrapRawBytes.ts
* empty wrap test
* Additional tests
* Update CHANGELOG
* Expose {wrap, unwrap}Bytes utils in extension-dapp
* Update yarn.lock
* Fix build alias
This commit is contained in:
@@ -1,5 +1,16 @@
|
||||
# CHANGELOG
|
||||
|
||||
## master
|
||||
|
||||
Contributed:
|
||||
|
||||
- Support signing of raw data via Qr (Thanks to https://github.com/Tbaut)
|
||||
|
||||
Changes:
|
||||
|
||||
- Raw signing interfaces will now always place a `<Bytes>...</Bytes>` wrapper around signed data
|
||||
|
||||
|
||||
## 0.38.3 May 31, 2021
|
||||
|
||||
Contributed:
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.14.0",
|
||||
"@polkadot/api": "^4.12.2-6",
|
||||
"@polkadot/extension-dapp": "^0.38.4-18",
|
||||
"@polkadot/extension-inject": "^0.38.4-18",
|
||||
"@polkadot/keyring": "^6.6.1",
|
||||
"@polkadot/phishing": "^0.6.171",
|
||||
|
||||
@@ -5,8 +5,9 @@ import type { KeyringPair } from '@polkadot/keyring/types';
|
||||
import type { SignerPayloadRaw } from '@polkadot/types/types';
|
||||
import type { RequestSign } from './types';
|
||||
|
||||
import { wrapBytes } from '@polkadot/extension-dapp/wrapBytes';
|
||||
import { TypeRegistry } from '@polkadot/types';
|
||||
import { hexToU8a, u8aToHex } from '@polkadot/util';
|
||||
import { u8aToHex } from '@polkadot/util';
|
||||
|
||||
export default class RequestBytesSign implements RequestSign {
|
||||
public readonly payload: SignerPayloadRaw;
|
||||
@@ -19,7 +20,7 @@ export default class RequestBytesSign implements RequestSign {
|
||||
return {
|
||||
signature: u8aToHex(
|
||||
pair.sign(
|
||||
hexToU8a(this.payload.data)
|
||||
wrapBytes(this.payload.data)
|
||||
)
|
||||
)
|
||||
};
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
|
||||
import type { KeypairType } from '@polkadot/util-crypto/types';
|
||||
|
||||
export default function canDerive (type?: KeypairType): boolean {
|
||||
export function canDerive (type?: KeypairType): boolean {
|
||||
return !!type && ['ed25519', 'sr25519', 'ecdsa'].includes(type);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2019-2021 @polkadot/extension authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
export { default as canDerive } from './canDerive';
|
||||
export { canDerive } from './canDerive';
|
||||
|
||||
@@ -8,6 +8,9 @@ import { decodeAddress, encodeAddress } from '@polkadot/util-crypto';
|
||||
|
||||
import { documentReadyPromise } from './util';
|
||||
|
||||
// expose utility functions
|
||||
export { unwrapBytes, wrapBytes } from './wrapBytes';
|
||||
|
||||
// just a helper (otherwise we cast all-over, so shorter and more readable)
|
||||
const win = window as Window & InjectedWindow;
|
||||
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
// Copyright 2019-2021 @polkadot/extension authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import { u8aConcat, u8aEq, u8aToString } from '@polkadot/util';
|
||||
|
||||
import { POSTFIX, PREFIX, unwrapBytes, wrapBytes } from './wrapBytes';
|
||||
|
||||
const TEST_DATA = 'this is just some random message that we expect to be wrapped along the way';
|
||||
const TEST_WRAP_EMPTY = `${u8aToString(PREFIX)}${u8aToString(POSTFIX)}`;
|
||||
const TEST_WRAP_FULL = `${u8aToString(PREFIX)}${TEST_DATA}${u8aToString(POSTFIX)}`;
|
||||
const TEST_WARP_HALF_PRE = `${u8aToString(PREFIX)}${TEST_DATA}`;
|
||||
const TEST_WRAP_HALF_POST = `${TEST_DATA}${u8aToString(POSTFIX)}`;
|
||||
|
||||
describe('wrapBytes', (): void => {
|
||||
it('wraps empty bytes', (): void => {
|
||||
expect(
|
||||
u8aEq(
|
||||
wrapBytes(new Uint8Array()),
|
||||
u8aConcat(PREFIX, POSTFIX)
|
||||
)
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('wraps when no wrapping is detected', (): void => {
|
||||
expect(
|
||||
u8aToString(
|
||||
wrapBytes(TEST_DATA)
|
||||
)
|
||||
).toEqual(TEST_WRAP_FULL);
|
||||
});
|
||||
|
||||
it('wraps when only start wrap is detected', (): void => {
|
||||
expect(
|
||||
u8aToString(
|
||||
wrapBytes(TEST_WARP_HALF_PRE)
|
||||
)
|
||||
).toEqual(`${u8aToString(PREFIX)}${TEST_WARP_HALF_PRE}${u8aToString(POSTFIX)}`);
|
||||
});
|
||||
|
||||
it('wraps when only end wrap is detected', (): void => {
|
||||
expect(
|
||||
u8aToString(
|
||||
wrapBytes(TEST_WRAP_HALF_POST)
|
||||
)
|
||||
).toEqual(`${u8aToString(PREFIX)}${TEST_WRAP_HALF_POST}${u8aToString(POSTFIX)}`);
|
||||
});
|
||||
|
||||
it('does not re-wrap when a wrap is already present', (): void => {
|
||||
expect(
|
||||
u8aToString(
|
||||
wrapBytes(TEST_WRAP_FULL)
|
||||
)
|
||||
).toEqual(TEST_WRAP_FULL);
|
||||
});
|
||||
|
||||
it('does not re-wrap when a wrap (empty data) is already present', (): void => {
|
||||
expect(
|
||||
u8aToString(
|
||||
wrapBytes(TEST_WRAP_EMPTY)
|
||||
)
|
||||
).toEqual(TEST_WRAP_EMPTY);
|
||||
});
|
||||
});
|
||||
|
||||
describe('unwrapBytes', (): void => {
|
||||
it('unwraps empty bytes', (): void => {
|
||||
expect(
|
||||
u8aEq(
|
||||
unwrapBytes(new Uint8Array()),
|
||||
new Uint8Array()
|
||||
)
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('unwraps when no wrapping is detected', (): void => {
|
||||
expect(
|
||||
u8aToString(
|
||||
unwrapBytes(TEST_DATA)
|
||||
)
|
||||
).toEqual(TEST_DATA);
|
||||
});
|
||||
|
||||
it('unwraps when no wrapping is detected (only start)', (): void => {
|
||||
expect(
|
||||
u8aToString(
|
||||
unwrapBytes(TEST_WARP_HALF_PRE)
|
||||
)
|
||||
).toEqual(TEST_WARP_HALF_PRE);
|
||||
});
|
||||
|
||||
it('unwraps when no wrapping is detected (only end)', (): void => {
|
||||
expect(
|
||||
u8aToString(
|
||||
unwrapBytes(TEST_WRAP_HALF_POST)
|
||||
)
|
||||
).toEqual(TEST_WRAP_HALF_POST);
|
||||
});
|
||||
|
||||
it('unwraps when a wrap is present', (): void => {
|
||||
expect(
|
||||
u8aToString(
|
||||
unwrapBytes(TEST_WRAP_FULL)
|
||||
)
|
||||
).toEqual(TEST_DATA);
|
||||
});
|
||||
|
||||
it('unwraps when a an empty wrap is present', (): void => {
|
||||
expect(
|
||||
u8aToString(
|
||||
unwrapBytes(TEST_WRAP_EMPTY)
|
||||
)
|
||||
).toEqual('');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright 2019-2021 @polkadot/extension authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import { u8aConcat, u8aEq, u8aToU8a } from '@polkadot/util';
|
||||
|
||||
export const PREFIX = u8aToU8a('<Bytes>');
|
||||
export const POSTFIX = u8aToU8a('</Bytes>');
|
||||
|
||||
const WRAP_LEN = PREFIX.length + POSTFIX.length;
|
||||
|
||||
function isWrapped (u8a: Uint8Array): boolean {
|
||||
return u8a.length >= WRAP_LEN &&
|
||||
u8aEq(u8a.subarray(0, PREFIX.length), PREFIX) &&
|
||||
u8aEq(u8a.slice(-POSTFIX.length), POSTFIX);
|
||||
}
|
||||
|
||||
export function unwrapBytes (bytes: string | Uint8Array): Uint8Array {
|
||||
const u8a = u8aToU8a(bytes);
|
||||
|
||||
return isWrapped(u8a)
|
||||
? u8a.subarray(PREFIX.length, u8a.length - POSTFIX.length)
|
||||
: u8a;
|
||||
}
|
||||
|
||||
export function wrapBytes (bytes: string | Uint8Array): Uint8Array {
|
||||
const u8a = u8aToU8a(bytes);
|
||||
|
||||
return isWrapped(u8a)
|
||||
? u8a
|
||||
: u8aConcat(PREFIX, u8a, POSTFIX);
|
||||
}
|
||||
@@ -13,6 +13,7 @@
|
||||
"@fortawesome/free-solid-svg-icons": "^5.15.3",
|
||||
"@fortawesome/react-fontawesome": "^0.1.14",
|
||||
"@polkadot/extension-base": "^0.38.4-18",
|
||||
"@polkadot/extension-dapp": "^0.38.4-18",
|
||||
"@polkadot/extension-inject": "^0.38.4-18",
|
||||
"@polkadot/hw-ledger": "^6.6.1",
|
||||
"@polkadot/keyring": "^6.6.1",
|
||||
|
||||
@@ -6,8 +6,8 @@ import type { ExtrinsicPayload } from '@polkadot/types/interfaces';
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { wrapBytes } from '@polkadot/extension-dapp/wrapBytes';
|
||||
import { QrDisplayPayload, QrScanSignature } from '@polkadot/react-qr';
|
||||
import { hexToU8a } from '@polkadot/util';
|
||||
|
||||
import { Button } from '../../components';
|
||||
import useTranslation from '../../hooks/useTranslation';
|
||||
@@ -34,7 +34,7 @@ function Qr ({ address, className, cmd, genesisHash, onSignature, payload }: Pro
|
||||
case CMD_MORTAL:
|
||||
return (payload as ExtrinsicPayload).toU8a();
|
||||
case CMD_SIGN_MESSAGE:
|
||||
return hexToU8a(payload as string);
|
||||
return wrapBytes(payload as string);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ const packages = [
|
||||
'extension',
|
||||
'extension-base',
|
||||
'extension-chains',
|
||||
'extension-dapp',
|
||||
'extension-inject',
|
||||
'extension-ui'
|
||||
];
|
||||
|
||||
@@ -2143,6 +2143,7 @@ __metadata:
|
||||
dependencies:
|
||||
"@babel/runtime": ^7.14.0
|
||||
"@polkadot/api": ^4.12.2-6
|
||||
"@polkadot/extension-dapp": ^0.38.4-18
|
||||
"@polkadot/extension-inject": ^0.38.4-18
|
||||
"@polkadot/keyring": ^6.6.1
|
||||
"@polkadot/phishing": ^0.6.171
|
||||
@@ -2161,7 +2162,7 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@polkadot/extension-dapp@workspace:packages/extension-dapp":
|
||||
"@polkadot/extension-dapp@^0.38.4-18, @polkadot/extension-dapp@workspace:packages/extension-dapp":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@polkadot/extension-dapp@workspace:packages/extension-dapp"
|
||||
dependencies:
|
||||
@@ -2199,6 +2200,7 @@ __metadata:
|
||||
"@fortawesome/free-solid-svg-icons": ^5.15.3
|
||||
"@fortawesome/react-fontawesome": ^0.1.14
|
||||
"@polkadot/extension-base": ^0.38.4-18
|
||||
"@polkadot/extension-dapp": ^0.38.4-18
|
||||
"@polkadot/extension-inject": ^0.38.4-18
|
||||
"@polkadot/hw-ledger": ^6.6.1
|
||||
"@polkadot/keyring": ^6.6.1
|
||||
|
||||
Reference in New Issue
Block a user