From c613c4415c73bb7c712619c19a18fad2ccfd4bcb Mon Sep 17 00:00:00 2001 From: Fernando Boucquez Date: Tue, 29 Oct 2019 22:23:25 +0100 Subject: [PATCH 1/3] TS-81 Address.isValidAddress methods --- src/core/format/RawAddress.ts | 22 +----- src/model/account/Address.ts | 55 ++++++++++++-- test/core/format/RawAddress.spec.ts | 36 --------- test/model/account/Address.spec.ts | 113 +++++++++++++++++++++++++++- 4 files changed, 160 insertions(+), 66 deletions(-) diff --git a/src/core/format/RawAddress.ts b/src/core/format/RawAddress.ts index 63c0e2a219..4b6da1cb9c 100644 --- a/src/core/format/RawAddress.ts +++ b/src/core/format/RawAddress.ts @@ -69,7 +69,6 @@ export class RawAddress { if (RawAddress.constants.sizes.addressDecoded !== decoded.length) { throw Error(`${Convert.uint8ToHex(decoded)} does not represent a valid decoded address`); } - return Base32.Base32Encode(decoded); } @@ -111,6 +110,9 @@ export class RawAddress { * @returns {boolean} true if the decoded address is valid, false otherwise. */ public static isValidAddress = (decoded: Uint8Array, networkType: NetworkType): boolean => { + if (RawAddress.constants.sizes.addressDecoded !== decoded.length) { + return false; + } const signSchema = SHA3Hasher.resolveSignSchema(networkType); const hash = signSchema === SignSchema.SHA3 ? sha3_256.create() : keccak256.create(); const checksumBegin = RawAddress.constants.sizes.addressDecoded - RawAddress.constants.sizes.checksum; @@ -120,22 +122,4 @@ export class RawAddress { return RawArray.deepEqual(checksum, decoded.subarray(checksumBegin)); } - /** - * Determines the validity of an encoded address string. - * @param {string} encoded The encoded address string. - * @param {NetworkType} networkType The network identifier. - * @returns {boolean} true if the encoded address string is valid, false otherwise. - */ - public static isValidEncodedAddress = (encoded: string, networkType: NetworkType): boolean => { - if (RawAddress.constants.sizes.addressEncoded !== encoded.length) { - return false; - } - - try { - const decoded = RawAddress.stringToAddress(encoded); - return RawAddress.isValidAddress(decoded, networkType); - } catch (err) { - return false; - } - } } diff --git a/src/model/account/Address.ts b/src/model/account/Address.ts index a3624f255c..ab4428b4da 100644 --- a/src/model/account/Address.ts +++ b/src/model/account/Address.ts @@ -13,8 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { Convert, RawAddress } from '../../core/format'; -import {NetworkType} from '../blockchain/NetworkType'; +import { Convert, RawAddress, RawArray } from '../../core/format'; +import { NetworkType } from '../blockchain/NetworkType'; +import { SHA3Hasher, SignSchema } from "../../core/crypto"; +import { keccak256, sha3_256 } from "js-sha3"; /** * The address structure describes an address with its network @@ -30,7 +32,7 @@ export class Address { networkType: NetworkType): Address { const publicKeyUint8 = Convert.hexToUint8(publicKey); const address = RawAddress - .addressToString(RawAddress.publicKeyToAddress(publicKeyUint8, networkType)); + .addressToString(RawAddress.publicKeyToAddress(publicKeyUint8, networkType)); return new Address(address, networkType); } @@ -43,9 +45,9 @@ export class Address { public static createFromRawAddress(rawAddress: string): Address { let networkType: NetworkType; const addressTrimAndUpperCase: string = rawAddress - .trim() - .toUpperCase() - .replace(/-/g, ''); + .trim() + .toUpperCase() + .replace(/-/g, ''); if (addressTrimAndUpperCase.length !== 40) { throw new Error('Address ' + addressTrimAndUpperCase + ' has to be 40 characters long'); } @@ -65,12 +67,41 @@ export class Address { /** * Create an Address from a given encoded address. - * @param {string} encoded + * @param {string} encoded address. Expected format: 9085215E4620D383C2DF70235B9EF7607F6A28EF6D16FD7B9C. * @return {Address} */ public static createFromEncoded(encoded: string): Address { return Address.createFromRawAddress(RawAddress - .addressToString(Convert.hexToUint8(encoded))); + .addressToString(Convert.hexToUint8(encoded))); + } + + + /** + * Determines the validity of an raw address string. + * @param {string} rawAddress The raw address string. Expected format SCHCZBZ6QVJAHGJTKYVPW5FBSO2IXXJQBPV5XE6P + * @param {NetworkType} networkType The network identifier. + * @returns {boolean} true if the raw address string is valid, false otherwise. + */ + public static isValidRawAAddress = (rawAddress: string, networkType: NetworkType): boolean => { + try { + return RawAddress.isValidAddress(RawAddress.stringToAddress(rawAddress), networkType); + } catch (err) { + return false; + } + } + + /** + * Determines the validity of an encoded address string. + * @param {string} encoded The encoded address string. Expected format: 9085215E4620D383C2DF70235B9EF7607F6A28EF6D16FD7B9C + * @param {NetworkType} networkType The network identifier. + * @returns {boolean} true if the encoded address string is valid, false otherwise. + */ + public static isValidEncodedAddress = (encoded: string, networkType: NetworkType): boolean => { + try { + return RawAddress.isValidAddress(Convert.hexToUint8(encoded), networkType); + } catch (err) { + return false; + } } /** @@ -96,6 +127,14 @@ export class Address { return this.address; } + /** + * Get address in the encoded format ex: NAR3W7B4BCOZSZMFIZRYB3N5YGOUSWIYJCJ6HDFH. + * @returns {string} + */ + public encoded(): string { + return Convert.uint8ToHex(RawAddress.stringToAddress(this.address)); + } + /** * Get address in pretty format ex: SB3KUB-HATFCP-V7UZQL-WAQ2EU-R6SIHB-SBEOED-DDF3. * @returns {string} diff --git a/test/core/format/RawAddress.spec.ts b/test/core/format/RawAddress.spec.ts index da80fc96f5..e4a5e65798 100644 --- a/test/core/format/RawAddress.spec.ts +++ b/test/core/format/RawAddress.spec.ts @@ -192,42 +192,6 @@ describe('address', () => { }); }); - describe('isValidEncodedAddress', () => { - it('returns true for valid encoded address', () => { - // Arrange: - const encoded = 'NAR3W7B4BCOZSZMFIZRYB3N5YGOUSWIYJCJ6HDFG'; - - // Assert: - expect(address.isValidEncodedAddress(encoded, NetworkType.MIJIN_TEST)).to.equal(true); - }); - - it('returns false for invalid encoded address', () => { - // Arrange: changed last char - const encoded = 'NAR3W7B4BCOZSZMFIZRYB3N5YGOUSWIYJCJ6HDFH'; - - // Assert: - expect(address.isValidEncodedAddress(encoded, NetworkType.MIJIN_TEST)).to.equal(false); - }); - - it('returns false for encoded address with wrong length', () => { - // Arrange: added ABC - const encoded = 'NAR3W7B4BCOZSZMFIZRYB3N5YGOUSWIYJCJ6HDFGABC'; - - // Assert: - expect(address.isValidEncodedAddress(encoded, NetworkType.MIJIN_TEST)).to.equal(false); - }); - - it('adding leading or trailing white space invalidates encoded address', () => { - // Arrange: - const encoded = 'NAR3W7B4BCOZSZMFIZRYB3N5YGOUSWIYJCJ6HDFG'; - - // Assert: - expect(address.isValidEncodedAddress(` \t ${encoded}`, NetworkType.MIJIN_TEST)).to.equal(false); - expect(address.isValidEncodedAddress(`${encoded} \t `, NetworkType.MIJIN_TEST)).to.equal(false); - expect(address.isValidEncodedAddress(` \t ${encoded} \t `, NetworkType.MIJIN_TEST)).to.equal(false); - }); - }); - /** * @see https://raw.githubusercontent.com/nemtech/test-vectors/master/1.test-address-nis1.json */ diff --git a/test/model/account/Address.spec.ts b/test/model/account/Address.spec.ts index 08122676db..d8bc15f56c 100644 --- a/test/model/account/Address.spec.ts +++ b/test/model/account/Address.spec.ts @@ -14,9 +14,13 @@ * limitations under the License. */ -import {expect} from 'chai'; -import {Address} from '../../../src/model/account/Address'; -import {NetworkType} from '../../../src/model/blockchain/NetworkType'; +import { expect } from 'chai'; +import { Address } from '../../../src/model/account/Address'; +import { NetworkType } from '../../../src/model/blockchain/NetworkType'; +import { Convert as convert, RawAddress } from "../../../src/core/format"; +import { Account } from "../../../src/model/account/Account"; + +const Address_Decoded_Size = 25; describe('Address', () => { const publicKey = 'c2f93346e27ce6ad1a9f8f5e3066f8326593a406bdf357acb041e2f9ab402efe'.toUpperCase(); @@ -122,4 +126,107 @@ describe('Address', () => { const compareAddress = Address.createFromRawAddress('TCTMW23D2MN5VE4AQ4TZIDZENGNOZXPRPSDRSFRF'); expect(address.equals(compareAddress)).to.be.equal(false); }); + + it('It creates the address from an encoded value', () => { + let encoded = '917E7E29A01014C2F300000000000000000000000000000000'; + const address = Address.createFromEncoded(encoded); + expect(address.encoded()).to.be.equal(encoded); + }); + + describe('isValidRawAAddress', () => { + + + it('returns true for valid address when generated', () => { + // Assert: + expect(Address.isValidRawAAddress(Account.generateNewAccount(NetworkType.MIJIN_TEST).address.plain(), NetworkType.MIJIN_TEST)).to.equal(true); + expect(Address.isValidRawAAddress(Account.generateNewAccount(NetworkType.MAIN_NET).address.plain(), NetworkType.MAIN_NET)).to.equal(true); + expect(Address.isValidRawAAddress(Account.generateNewAccount(NetworkType.MIJIN).address.plain(), NetworkType.MIJIN)).to.equal(true); + expect(Address.isValidRawAAddress(Account.generateNewAccount(NetworkType.TEST_NET).address.plain(), NetworkType.TEST_NET)).to.equal(true); + }); + + it('returns true for valid address', () => { + // Arrange: + const rawAddress = 'SCHCZBZ6QVJAHGJTKYVPW5FBSO2IXXJQBPV5XE6P'; + + // Assert: + expect(Address.isValidRawAAddress(rawAddress, NetworkType.MIJIN_TEST)).to.equal(true); + }); + + it('returns false for address with invalid checksum', () => { + // Arrange: + const rawAddress = 'SCHCZBZ6QVJAHGJTKYAPW5FBSO2IXXJQBPV5XE6P'; + + // Assert: + expect(Address.isValidRawAAddress(rawAddress, NetworkType.MIJIN_TEST)).to.equal(false); + }); + + it('returns false for address with invalid hash', () => { + // Arrange: + const rawAddress = 'SCHCZBZ6QVJAHGJTKYVPW5FBSO2IXXJQBPV5XE7P'; + + // Assert: + expect(Address.isValidRawAAddress(rawAddress, NetworkType.MIJIN_TEST)).to.equal(false); + }); + + it('returns false for address with invalid prefix', () => { + // Arrange: + const rawAddress = 'ACHCZBZ6QVJAHGJTKYVPW5FBSO2IXXJQBPV5XE6P'; + + // Assert: + expect(Address.isValidRawAAddress(rawAddress, NetworkType.MIJIN_TEST)).to.equal(false); + }); + }); + + describe('isValidEncodedAddress', () => { + + it('returns true for valid address when generated', () => { + // Assert: + expect(Address.isValidEncodedAddress(Account.generateNewAccount(NetworkType.MIJIN_TEST).address.encoded(), NetworkType.MIJIN_TEST)).to.equal(true); + expect(Address.isValidEncodedAddress(Account.generateNewAccount(NetworkType.MAIN_NET).address.encoded(), NetworkType.MAIN_NET)).to.equal(true); + expect(Address.isValidEncodedAddress(Account.generateNewAccount(NetworkType.MIJIN).address.encoded(), NetworkType.MIJIN)).to.equal(true); + expect(Address.isValidEncodedAddress(Account.generateNewAccount(NetworkType.TEST_NET).address.encoded(), NetworkType.TEST_NET)).to.equal(true); + }); + + it('returns true for valid encoded address', () => { + // Arrange: + const encoded = '9085215E4620D383C2DF70235B9EF7507F6A28EF6D16FD7B9C'; + + // Assert: + expect(Address.isValidEncodedAddress(encoded, NetworkType.MIJIN_TEST)).to.equal(true); + }); + + it('returns false for invalid hex encoded address', () => { + // Arrange: + const encoded = 'Z085215E4620D383C2DF70235B9EF7507F6A28EF6D16FD7B9C'; + + // Assert: + expect(Address.isValidEncodedAddress(encoded, NetworkType.MIJIN_TEST)).to.equal(false); + }); + + it('returns false for invalid encoded address', () => { + // Arrange: changed last char + const encoded = '9085215E4620D383C2DF70235B9EF7507F6A28EF6D16FD7B9D'; + + // Assert: + expect(Address.isValidEncodedAddress(encoded, NetworkType.MIJIN_TEST)).to.equal(false); + }); + + it('returns false for encoded address with wrong length', () => { + // Arrange: added ABC + const encoded = '9085215E4620D383C2DF70235B9EF7607F6A28EF6D16FD7B9C'; + + // Assert: + expect(Address.isValidEncodedAddress(encoded, NetworkType.MIJIN_TEST)).to.equal(false); + }); + + it('adding leading or trailing white space invalidates encoded address', () => { + // Arrange: + const encoded = '9085215E4620D383C2DF70235B9EF7507F6A28EF6D16FD7B9C'; + + // Assert: + expect(Address.isValidEncodedAddress(` \t ${encoded}`, NetworkType.MIJIN_TEST)).to.equal(false); + expect(Address.isValidEncodedAddress(`${encoded} \t `, NetworkType.MIJIN_TEST)).to.equal(false); + expect(Address.isValidEncodedAddress(` \t ${encoded} \t `, NetworkType.MIJIN_TEST)).to.equal(false); + }); + }); }); From a1d6dec8769c87ec50f7fa0eabdb313a30dfd554 Mon Sep 17 00:00:00 2001 From: Fernando Boucquez Date: Wed, 30 Oct 2019 12:15:56 +0100 Subject: [PATCH 2/3] Added intellij iml files to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 780579cd2e..0496dbefe4 100644 --- a/.gitignore +++ b/.gitignore @@ -83,6 +83,7 @@ fabric.properties modules.xml .idea/ *.ipr +*.iml # End of https://www.gitignore.io/api/intellij+iml dist/ From 019e15af612e6b05a0c91d38f402dd9921cb3527 Mon Sep 17 00:00:00 2001 From: Fernando Boucquez Date: Wed, 30 Oct 2019 13:16:14 +0100 Subject: [PATCH 3/3] fixed typo --- src/model/account/Address.ts | 2 +- test/model/account/Address.spec.ts | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/model/account/Address.ts b/src/model/account/Address.ts index ab4428b4da..9dc7d7fd78 100644 --- a/src/model/account/Address.ts +++ b/src/model/account/Address.ts @@ -82,7 +82,7 @@ export class Address { * @param {NetworkType} networkType The network identifier. * @returns {boolean} true if the raw address string is valid, false otherwise. */ - public static isValidRawAAddress = (rawAddress: string, networkType: NetworkType): boolean => { + public static isValidRawAddress = (rawAddress: string, networkType: NetworkType): boolean => { try { return RawAddress.isValidAddress(RawAddress.stringToAddress(rawAddress), networkType); } catch (err) { diff --git a/test/model/account/Address.spec.ts b/test/model/account/Address.spec.ts index d8bc15f56c..fffe493f28 100644 --- a/test/model/account/Address.spec.ts +++ b/test/model/account/Address.spec.ts @@ -133,15 +133,15 @@ describe('Address', () => { expect(address.encoded()).to.be.equal(encoded); }); - describe('isValidRawAAddress', () => { + describe('isValidRawAddress', () => { it('returns true for valid address when generated', () => { // Assert: - expect(Address.isValidRawAAddress(Account.generateNewAccount(NetworkType.MIJIN_TEST).address.plain(), NetworkType.MIJIN_TEST)).to.equal(true); - expect(Address.isValidRawAAddress(Account.generateNewAccount(NetworkType.MAIN_NET).address.plain(), NetworkType.MAIN_NET)).to.equal(true); - expect(Address.isValidRawAAddress(Account.generateNewAccount(NetworkType.MIJIN).address.plain(), NetworkType.MIJIN)).to.equal(true); - expect(Address.isValidRawAAddress(Account.generateNewAccount(NetworkType.TEST_NET).address.plain(), NetworkType.TEST_NET)).to.equal(true); + expect(Address.isValidRawAddress(Account.generateNewAccount(NetworkType.MIJIN_TEST).address.plain(), NetworkType.MIJIN_TEST)).to.equal(true); + expect(Address.isValidRawAddress(Account.generateNewAccount(NetworkType.MAIN_NET).address.plain(), NetworkType.MAIN_NET)).to.equal(true); + expect(Address.isValidRawAddress(Account.generateNewAccount(NetworkType.MIJIN).address.plain(), NetworkType.MIJIN)).to.equal(true); + expect(Address.isValidRawAddress(Account.generateNewAccount(NetworkType.TEST_NET).address.plain(), NetworkType.TEST_NET)).to.equal(true); }); it('returns true for valid address', () => { @@ -149,7 +149,7 @@ describe('Address', () => { const rawAddress = 'SCHCZBZ6QVJAHGJTKYVPW5FBSO2IXXJQBPV5XE6P'; // Assert: - expect(Address.isValidRawAAddress(rawAddress, NetworkType.MIJIN_TEST)).to.equal(true); + expect(Address.isValidRawAddress(rawAddress, NetworkType.MIJIN_TEST)).to.equal(true); }); it('returns false for address with invalid checksum', () => { @@ -157,7 +157,7 @@ describe('Address', () => { const rawAddress = 'SCHCZBZ6QVJAHGJTKYAPW5FBSO2IXXJQBPV5XE6P'; // Assert: - expect(Address.isValidRawAAddress(rawAddress, NetworkType.MIJIN_TEST)).to.equal(false); + expect(Address.isValidRawAddress(rawAddress, NetworkType.MIJIN_TEST)).to.equal(false); }); it('returns false for address with invalid hash', () => { @@ -165,7 +165,7 @@ describe('Address', () => { const rawAddress = 'SCHCZBZ6QVJAHGJTKYVPW5FBSO2IXXJQBPV5XE7P'; // Assert: - expect(Address.isValidRawAAddress(rawAddress, NetworkType.MIJIN_TEST)).to.equal(false); + expect(Address.isValidRawAddress(rawAddress, NetworkType.MIJIN_TEST)).to.equal(false); }); it('returns false for address with invalid prefix', () => { @@ -173,7 +173,7 @@ describe('Address', () => { const rawAddress = 'ACHCZBZ6QVJAHGJTKYVPW5FBSO2IXXJQBPV5XE6P'; // Assert: - expect(Address.isValidRawAAddress(rawAddress, NetworkType.MIJIN_TEST)).to.equal(false); + expect(Address.isValidRawAddress(rawAddress, NetworkType.MIJIN_TEST)).to.equal(false); }); });