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:
Jaco
2021-06-10 21:13:46 +02:00
committed by GitHub
parent fd0b7afd0d
commit e4ce268b1c
12 changed files with 172 additions and 7 deletions
+11
View File
@@ -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:
+1
View File
@@ -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 -1
View File
@@ -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';
+3
View File
@@ -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('');
});
});
+31
View File
@@ -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);
}
+1
View File
@@ -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;
}
+1
View File
@@ -14,6 +14,7 @@ const packages = [
'extension',
'extension-base',
'extension-chains',
'extension-dapp',
'extension-inject',
'extension-ui'
];
+3 -1
View File
@@ -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