Skip to content

Commit

Permalink
QR Code Scanner Fixes (#332)
Browse files Browse the repository at this point in the history
* fix: create enable scanner state

* fix: add warnnings when address detected

* fix: remove unhandled promise rejection warning

* fix: remove useless code

* fix: changes according to review
  • Loading branch information
hanwencheng authored and Tbaut committed Aug 27, 2019
1 parent bfb5bc0 commit cbfbd32
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 40 deletions.
53 changes: 38 additions & 15 deletions src/screens/QrScanner.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,35 @@ import { RNCamera } from 'react-native-camera';
import { Subscribe } from 'unstated';

import colors from '../colors';
import fonts from "../fonts";
import fonts from '../fonts';
import AccountsStore from '../stores/AccountsStore';
import ScannerStore from '../stores/ScannerStore';
import { isJsonString, rawDataToU8A } from '../util/decoders';
import {isAddressString, isJsonString, rawDataToU8A} from '../util/decoders';

export default class Scanner extends React.PureComponent {
static navigationOptions = {
title: 'Transaction Details',
headerBackTitle: 'Scanner'
};

constructor(props) {
super(props);
this.state = { enableScan: true };
}

showErrorMessage(scannerStore, title, message) {
this.setState({ enableScan: false });
Alert.alert(title, message, [
{
text: 'Try again',
onPress: () => {
scannerStore.cleanup();
this.setState({ enableScan: true });
}
}
]);
}

render() {
return (
<Subscribe to={[ScannerStore, AccountsStore]}>
Expand All @@ -43,27 +61,26 @@ export default class Scanner extends React.PureComponent {
navigation={this.props.navigation}
scannerStore={scannerStore}
onBarCodeRead={async txRequestData => {
if (scannerStore.isBusy()) {
if (scannerStore.isBusy() || !this.state.enableScan) {
return;
}

if (isJsonString(txRequestData.data)) { // Ethereum Legacy
if(isAddressString(txRequestData.data)){
return this.showErrorMessage(scannerStore, text.ADDRESS_ERROR_TITLE, text.ADDRESS_ERROR_MESSAGE);
} else if (isJsonString(txRequestData.data)) {
// Ethereum Legacy
await scannerStore.setUnsigned(txRequestData.data);
} else {
try {
const strippedData = rawDataToU8A(txRequestData.rawData);
await scannerStore.setParsedData(strippedData, accountsStore);
await scannerStore.setParsedData(
strippedData,
accountsStore
);
} catch (e) {
Alert.alert('Unable to parse transaction', e.message, [
{
text: 'Try again',
onPress: () => {
scannerStore.cleanup();
}
}
]);
return this.showErrorMessage(scannerStore, text.PARSE_ERROR_TITLE, e.message);
}
}
}

if (await scannerStore.setData(accountsStore)) {
if (scannerStore.getType() === 'transaction') {
Expand Down Expand Up @@ -143,6 +160,12 @@ export class QrScannerView extends React.PureComponent {
}
}

const text = {
ADDRESS_ERROR_TITLE: 'Address detected',
ADDRESS_ERROR_MESSAGE: 'Please create a transaction using a software such as MyCrypto or Fether so that Parity Signer can sign it.',
PARSE_ERROR_TITLE: 'Unable to parse transaction'
};

const styles = StyleSheet.create({
inactive: {
backgroundColor: colors.bg,
Expand Down Expand Up @@ -207,6 +230,6 @@ const styles = StyleSheet.create({
color: colors.bg_text,
fontSize: 14,
fontFamily: fonts.bold,
paddingBottom: 20,
paddingBottom: 20
}
});
8 changes: 4 additions & 4 deletions src/stores/ScannerStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export default class ScannerStore extends Container<ScannerState> {

async setParsedData(strippedData, accountsStore) {
const parsedData = await constructDataFromBytes(strippedData);

if (parsedData.isMultipart) {
this.setPartData(parseData.frame, parsedData.frameCount, parseData.partData, accountsStore);
return;
Expand All @@ -100,7 +100,7 @@ export default class ScannerStore extends Container<ScannerState> {
// we havne't filled all the frames yet
if (Object.keys(this.state.multipartData.length) < frameCount) {
const nextDataState = this.state.multipartData;

nextDataState[frame] = partData;

this.setState({
Expand Down Expand Up @@ -268,7 +268,7 @@ export default class ScannerStore extends Container<ScannerState> {
cleanup() {
this.setState(defaultState);
}

getIsOversized() {
return this.state.isOversized;
}
Expand Down Expand Up @@ -308,4 +308,4 @@ export default class ScannerStore extends Container<ScannerState> {
getErrorMsg() {
return this.state.scanErrorMsg;
}
}
}
64 changes: 43 additions & 21 deletions src/util/decoders.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@
// @flow

import { GenericExtrinsicPayload } from '@polkadot/types';
import { hexStripPrefix, hexToU8a, u8aToHex, u8aToString } from '@polkadot/util';
import {
hexStripPrefix,
hexToU8a,
u8aToHex,
u8aToString
} from '@polkadot/util';
import { encodeAddress } from '@polkadot/util-crypto';

import { blake2s, keccak } from './native';
Expand Down Expand Up @@ -88,7 +93,7 @@ export function rawDataToU8A(rawData) {

export async function constructDataFromBytes(bytes) {
const frameInfo = hexStripPrefix(u8aToHex(bytes.slice(0, 5)));
const isMultipart = !!(parseInt(frameInfo.substr(0, 2), 16));
const isMultipart = !!parseInt(frameInfo.substr(0, 2), 16);
const frameCount = parseInt(frameInfo.substr(2, 4), 16);
const currentFrame = parseInt(frameInfo.substr(6, 4), 16);
const uosAfterFrames = hexStripPrefix(u8aToHex(bytes.slice(5)));
Expand Down Expand Up @@ -116,7 +121,12 @@ export async function constructDataFromBytes(bytes) {
// decode payload appropriately via UOS
switch (zerothByte) {
case '45': // Ethereum UOS payload
action = firstByte === '00' || firstByte === '01' ? 'signData' : firstByte === '01' ? 'signTransaction' : null;
action =
firstByte === '00' || firstByte === '01'
? 'signData'
: firstByte === '01'
? 'signTransaction'
: null;
address = uosAfterFrames.substr(4, 44);

data['action'] = action;
Expand All @@ -142,12 +152,14 @@ export async function constructDataFromBytes(bytes) {
data['data']['crypto'] = crypto;
data['data']['account'] = ss58Encoded;

switch(secondByte) {
switch (secondByte) {
case '00':
data['action'] = 'signTransaction';
data['oversized'] = isOversized;
data['isHash'] = isOversized;
data['data']['data'] = isOversized ? await blake2s(u8aToHex(rawPayload)) : new GenericExtrinsicPayload(rawPayload, { version: 3 });
data['data']['data'] = isOversized
? await blake2s(u8aToHex(rawPayload))
: new GenericExtrinsicPayload(rawPayload, { version: 3 });
break;
case '01':
data['action'] = 'signTransaction';
Expand All @@ -159,13 +171,17 @@ export async function constructDataFromBytes(bytes) {
data['action'] = 'signTransaction';
data['oversized'] = isOversized;
data['isHash'] = isOversized;
data['data']['data'] = isOversized ? await blake2s(u8aToHex(rawPayload)) : new GenericExtrinsicPayload(rawPayload, { version: 3 });
data['data']['data'] = isOversized
? await blake2s(u8aToHex(rawPayload))
: new GenericExtrinsicPayload(rawPayload, { version: 3 });
break;
case '03': // Cold Signer should attempt to decode message to utf8
data['action'] = 'signData';
data['oversized'] = isOversized;
data['isHash'] = isOversized;
data['data']['data'] = isOversized ? await blake2s(u8aToHex(rawPayload)) : u8aToString(rawPayload);
data['data']['data'] = isOversized
? await blake2s(u8aToHex(rawPayload))
: u8aToString(rawPayload);
break;
default:
break;
Expand All @@ -188,29 +204,35 @@ export function decodeToString(message: Uint8Array): string {
}

export function asciiToHex(message: string): string {
var result = [];
for (let i = 0; i < message.length; i++) {
var hex = Number(message.charCodeAt(i)).toString(16);
result.push(hex);
let result = [];
for (let i = 0; i < message.length; i++) {
const hex = Number(message.charCodeAt(i)).toString(16);
result.push(hex);
}
return result.join('');
return result.join('');
}

export function hexToAscii(hexBytes: Uint8Array): string {
var hex = hexBytes.toString();
var str = '';
for (var n = 0; n < hex.length; n += 2) {
str += String.fromCharCode(parseInt(hex.substr(n, 2), 16));
}
const hex = hexBytes.toString();
let str = '';
for (let n = 0; n < hex.length; n += 2) {
str += String.fromCharCode(parseInt(hex.substr(n, 2), 16));
}

return str;
return str;
}

export function isJsonString(str) {
try {
JSON.parse(str);
JSON.parse(str);
} catch (e) {
return false;
return false;
}
return true;
}
}

export function isAddressString(str) {
return str.substr(0, 2) === '0x' ||
str.substr(0, 9) === 'ethereum:' ||
str.substr(0, 10) === 'substrate:'
}

0 comments on commit cbfbd32

Please sign in to comment.