Merge branch 'master' into isValidOrderHash
This commit is contained in:
commit
dc1ca23e30
@ -33,6 +33,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/bignumber.js": "^4.0.2",
|
"@types/bignumber.js": "^4.0.2",
|
||||||
"@types/chai": "^3.5.2",
|
"@types/chai": "^3.5.2",
|
||||||
|
"@types/jsonschema": "^1.1.1",
|
||||||
"@types/mocha": "^2.2.41",
|
"@types/mocha": "^2.2.41",
|
||||||
"@types/node": "^7.0.22",
|
"@types/node": "^7.0.22",
|
||||||
"awesome-typescript-loader": "^3.1.3",
|
"awesome-typescript-loader": "^3.1.3",
|
||||||
@ -54,6 +55,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bignumber.js": "^4.0.2",
|
"bignumber.js": "^4.0.2",
|
||||||
"ethereumjs-util": "^5.1.1",
|
"ethereumjs-util": "^5.1.1",
|
||||||
|
"jsonschema": "^1.1.1",
|
||||||
"lodash": "^4.17.4",
|
"lodash": "^4.17.4",
|
||||||
"web3": "^0.19.0"
|
"web3": "^0.19.0"
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import * as BigNumber from 'bignumber.js';
|
import * as BigNumber from 'bignumber.js';
|
||||||
import * as ethUtil from 'ethereumjs-util';
|
import * as ethUtil from 'ethereumjs-util';
|
||||||
import {assert} from './utils/assert';
|
import {assert} from './utils/assert';
|
||||||
|
import {ECSignatureSchema} from './schemas/ec_signature_schema';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Elliptic Curve signature
|
* Elliptic Curve signature
|
||||||
@ -21,7 +22,7 @@ export class ZeroEx {
|
|||||||
*/
|
*/
|
||||||
public static isValidSignature(dataHex: string, signature: ECSignature, signer: ETHAddressHex): boolean {
|
public static isValidSignature(dataHex: string, signature: ECSignature, signer: ETHAddressHex): boolean {
|
||||||
assert.isHexString('dataHex', dataHex);
|
assert.isHexString('dataHex', dataHex);
|
||||||
assert.isObject('signature', signature);
|
assert.doesConformToSchema('signature', signature, ECSignatureSchema);
|
||||||
assert.isETHAddressHex('signer', signer);
|
assert.isETHAddressHex('signer', signer);
|
||||||
|
|
||||||
const dataBuff = ethUtil.toBuffer(dataHex);
|
const dataBuff = ethUtil.toBuffer(dataHex);
|
||||||
|
4
src/ts/globals.d.ts
vendored
4
src/ts/globals.d.ts
vendored
@ -2,6 +2,10 @@ declare type ETHPublicKey = string;
|
|||||||
declare type ETHAddressHex = string;
|
declare type ETHAddressHex = string;
|
||||||
declare type ETHAddressBuff = Buffer;
|
declare type ETHAddressBuff = Buffer;
|
||||||
|
|
||||||
|
declare interface Schema {
|
||||||
|
id: string;
|
||||||
|
}
|
||||||
|
|
||||||
declare module 'ethereumjs-util' {
|
declare module 'ethereumjs-util' {
|
||||||
const toBuffer: (dataHex: string) => Buffer;
|
const toBuffer: (dataHex: string) => Buffer;
|
||||||
const hashPersonalMessage: (msg: Buffer) => Buffer;
|
const hashPersonalMessage: (msg: Buffer) => Buffer;
|
||||||
|
20
src/ts/schemas/ec_signature_schema.ts
Normal file
20
src/ts/schemas/ec_signature_schema.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
export const ECSignatureParameter = {
|
||||||
|
id: '/ECSignatureParameter',
|
||||||
|
type: 'string',
|
||||||
|
pattern: '^0[xX][0-9A-Fa-f]{64}$',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ECSignatureSchema = {
|
||||||
|
id: '/ECSignature',
|
||||||
|
properties: {
|
||||||
|
v: {
|
||||||
|
type: 'number',
|
||||||
|
minimum: 27,
|
||||||
|
maximum: 28,
|
||||||
|
},
|
||||||
|
r: {$ref: '/ECSignatureParameter'},
|
||||||
|
s: {$ref: '/ECSignatureParameter'},
|
||||||
|
},
|
||||||
|
required: ['v', 'r', 's'],
|
||||||
|
type: 'object',
|
||||||
|
};
|
@ -1,6 +1,7 @@
|
|||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import * as BigNumber from 'bignumber.js';
|
import * as BigNumber from 'bignumber.js';
|
||||||
import Web3 = require('web3');
|
import Web3 = require('web3');
|
||||||
|
import {SchemaValidator} from './schema_validator';
|
||||||
|
|
||||||
const HEX_REGEX = /^0x([0-9A-F]{2})*$/i;
|
const HEX_REGEX = /^0x([0-9A-F]{2})*$/i;
|
||||||
|
|
||||||
@ -20,12 +21,18 @@ export const assert = {
|
|||||||
const web3 = new Web3();
|
const web3 = new Web3();
|
||||||
this.assert(web3.isAddress(value), this.typeAssertionMessage(variableName, 'ETHAddressHex', value));
|
this.assert(web3.isAddress(value), this.typeAssertionMessage(variableName, 'ETHAddressHex', value));
|
||||||
},
|
},
|
||||||
isObject(variableName: string, value: object) {
|
|
||||||
this.assert(_.isObject(value), this.typeAssertionMessage(variableName, 'object', value));
|
|
||||||
},
|
|
||||||
isNumber(variableName: string, value: number) {
|
isNumber(variableName: string, value: number) {
|
||||||
this.assert(_.isFinite(value), this.typeAssertionMessage(variableName, 'number', value));
|
this.assert(_.isFinite(value), this.typeAssertionMessage(variableName, 'number', value));
|
||||||
},
|
},
|
||||||
|
doesConformToSchema(variableName: string, value: object, schema: Schema) {
|
||||||
|
const schemaValidator = new SchemaValidator();
|
||||||
|
const validationResult = schemaValidator.validate(value, schema);
|
||||||
|
const hasValidationErrors = validationResult.errors.length > 0;
|
||||||
|
const msg = `Expected ${variableName} to conform to schema ${schema.id}
|
||||||
|
Encountered: ${JSON.stringify(value, null, '\t')}
|
||||||
|
Validation errors: ${validationResult.errors.join(', ')}`;
|
||||||
|
this.assert(!hasValidationErrors, msg);
|
||||||
|
},
|
||||||
assert(condition: boolean, message: string) {
|
assert(condition: boolean, message: string) {
|
||||||
if (!condition) {
|
if (!condition) {
|
||||||
throw new Error(message);
|
throw new Error(message);
|
||||||
|
14
src/ts/utils/schema_validator.ts
Normal file
14
src/ts/utils/schema_validator.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import {Validator, ValidatorResult} from 'jsonschema';
|
||||||
|
import {ECSignatureSchema, ECSignatureParameter} from '../schemas/ec_signature_schema';
|
||||||
|
|
||||||
|
export class SchemaValidator {
|
||||||
|
private validator: Validator;
|
||||||
|
constructor() {
|
||||||
|
this.validator = new Validator();
|
||||||
|
this.validator.addSchema(ECSignatureParameter, ECSignatureParameter.id);
|
||||||
|
this.validator.addSchema(ECSignatureSchema, ECSignatureSchema.id);
|
||||||
|
}
|
||||||
|
public validate(instance: object, schema: Schema): ValidatorResult {
|
||||||
|
return this.validator.validate(instance, schema);
|
||||||
|
}
|
||||||
|
}
|
@ -14,15 +14,14 @@ describe('ZeroEx library', () => {
|
|||||||
s: '0x2d887fd3b17bfdce3481f10bea41f45ba9f709d39ce8325427b57afcfc994cee',
|
s: '0x2d887fd3b17bfdce3481f10bea41f45ba9f709d39ce8325427b57afcfc994cee',
|
||||||
};
|
};
|
||||||
const address = '0x9b2055d370f73ec7d8a03e965129118dc8f5bf83';
|
const address = '0x9b2055d370f73ec7d8a03e965129118dc8f5bf83';
|
||||||
describe('should return false for malformed signature', () => {
|
describe('should throw if passed a malformed signature', () => {
|
||||||
it('malformed v', () => {
|
it('malformed v', () => {
|
||||||
const malformedSignature = {
|
const malformedSignature = {
|
||||||
v: 34,
|
v: 34,
|
||||||
r: signature.r,
|
r: signature.r,
|
||||||
s: signature.s,
|
s: signature.s,
|
||||||
};
|
};
|
||||||
const isValid = ZeroEx.isValidSignature(data, malformedSignature, address);
|
expect(() => ZeroEx.isValidSignature(data, malformedSignature, address)).to.throw();
|
||||||
expect(isValid).to.be.false;
|
|
||||||
});
|
});
|
||||||
it('r lacks 0x prefix', () => {
|
it('r lacks 0x prefix', () => {
|
||||||
const malformedR = signature.r.replace('0x', '');
|
const malformedR = signature.r.replace('0x', '');
|
||||||
@ -31,18 +30,16 @@ describe('ZeroEx library', () => {
|
|||||||
r: malformedR,
|
r: malformedR,
|
||||||
s: signature.s,
|
s: signature.s,
|
||||||
};
|
};
|
||||||
const isValid = ZeroEx.isValidSignature(data, malformedSignature, address);
|
expect(() => ZeroEx.isValidSignature(data, malformedSignature, address)).to.throw();
|
||||||
expect(isValid).to.be.false;
|
|
||||||
});
|
});
|
||||||
it('r is too short', () => {
|
it('r is too short', () => {
|
||||||
const malformedR = signature.r.substr(10);
|
const malformedR = signature.r.substr(10);
|
||||||
const malformedSignature = {
|
const malformedSignature = {
|
||||||
v: signature.v,
|
v: signature.v,
|
||||||
r: malformedR,
|
r: malformedR,
|
||||||
s: signature.s,
|
s: signature.s.replace('0', 'z'),
|
||||||
};
|
};
|
||||||
const isValid = ZeroEx.isValidSignature(data, malformedSignature, address);
|
expect(() => ZeroEx.isValidSignature(data, malformedSignature, address)).to.throw();
|
||||||
expect(isValid).to.be.false;
|
|
||||||
});
|
});
|
||||||
it('s is not hex', () => {
|
it('s is not hex', () => {
|
||||||
const malformedS = signature.s.replace('0', 'z');
|
const malformedS = signature.s.replace('0', 'z');
|
||||||
@ -51,8 +48,7 @@ describe('ZeroEx library', () => {
|
|||||||
r: signature.r,
|
r: signature.r,
|
||||||
s: malformedS,
|
s: malformedS,
|
||||||
};
|
};
|
||||||
const isValid = ZeroEx.isValidSignature(data, malformedSignature, address);
|
expect(() => ZeroEx.isValidSignature(data, malformedSignature, address)).to.throw();
|
||||||
expect(isValid).to.be.false;
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('should return false if the data doesn\'t pertain to the signature & address', () => {
|
it('should return false if the data doesn\'t pertain to the signature & address', () => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user