Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ fabric.properties
modules.xml
.idea/
*.ipr
*.iml

# End of https://www.gitignore.io/api/intellij+iml
dist/
Expand Down
22 changes: 3 additions & 19 deletions src/core/format/RawAddress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,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);
}

Expand Down Expand Up @@ -112,6 +111,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;
Expand All @@ -120,22 +122,4 @@ export class RawAddress {
RawArray.copy(checksum, RawArray.uint8View(hash.arrayBuffer()), RawAddress.constants.sizes.checksum);
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;
}
}
}
55 changes: 47 additions & 8 deletions src/model/account/Address.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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);
}

Expand All @@ -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');
}
Expand All @@ -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 isValidRawAddress = (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;
}
}

/**
Expand All @@ -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}
Expand Down
36 changes: 0 additions & 36 deletions test/core/format/RawAddress.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down
113 changes: 110 additions & 3 deletions test/model/account/Address.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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('isValidRawAddress', () => {


it('returns true for valid address when generated', () => {
// Assert:
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', () => {
// Arrange:
const rawAddress = 'SCHCZBZ6QVJAHGJTKYVPW5FBSO2IXXJQBPV5XE6P';

// Assert:
expect(Address.isValidRawAddress(rawAddress, NetworkType.MIJIN_TEST)).to.equal(true);
});

it('returns false for address with invalid checksum', () => {
// Arrange:
const rawAddress = 'SCHCZBZ6QVJAHGJTKYAPW5FBSO2IXXJQBPV5XE6P';

// Assert:
expect(Address.isValidRawAddress(rawAddress, NetworkType.MIJIN_TEST)).to.equal(false);
});

it('returns false for address with invalid hash', () => {
// Arrange:
const rawAddress = 'SCHCZBZ6QVJAHGJTKYVPW5FBSO2IXXJQBPV5XE7P';

// Assert:
expect(Address.isValidRawAddress(rawAddress, NetworkType.MIJIN_TEST)).to.equal(false);
});

it('returns false for address with invalid prefix', () => {
// Arrange:
const rawAddress = 'ACHCZBZ6QVJAHGJTKYVPW5FBSO2IXXJQBPV5XE6P';

// Assert:
expect(Address.isValidRawAddress(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);
});
});
});