Skip to content

Commit

Permalink
Merge pull request #7 from Gamboster/feat/bchtestValidation
Browse files Browse the repository at this point in the history
Feat: validation for 'bchtest:' prefix and tests for this
  • Loading branch information
matiu authored May 30, 2018
2 parents 3e22db0 + 6d9026d commit 494b14c
Show file tree
Hide file tree
Showing 2 changed files with 189 additions and 17 deletions.
20 changes: 10 additions & 10 deletions lib/uri.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ var _ = require('lodash');
var URL = require('url');

var Address = require('./address');
var Networks = require('./networks');
var Unit = require('./unit');

/**
Expand Down Expand Up @@ -109,16 +110,15 @@ URI.isValid = function(arg, knownParams) {
*/
URI.parse = function(uri) {
var info = URL.parse(uri, true);

if (info.protocol !== 'bitcoincash:') {
throw new TypeError('Invalid bitcoin URI');
if (Networks.get( info.protocol.replace(':', '') ,'prefix')) {
// workaround to host insensitiveness
var group = /[^:]*:\/?\/?([^?]*)/.exec(uri);
info.query.address = group && group[1] || undefined;

return info.query;
} else {
throw new TypeError('Invalid bitcoin URI');
}

// workaround to host insensitiveness
var group = /[^:]*:\/?\/?([^?]*)/.exec(uri);
info.query.address = group && group[1] || undefined;

return info.query;
};

URI.Members = ['address', 'amount', 'message', 'label', 'r'];
Expand Down Expand Up @@ -205,7 +205,7 @@ URI.prototype.toString = function() {
_.extend(query, this.extras);

return URL.format({
protocol: 'bitcoincash:',
protocol: Networks.get(this.network ,'name').prefix + ':',
host: this.address.toString(true),
query: query
});
Expand Down
186 changes: 179 additions & 7 deletions test/uri.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,45 @@ describe('URI', function() {
uri['req-extra'].should.equal('param');
});

// TODO: Split this and explain tests
it('parses uri strings correctly for testnet network (test vector)', function() {
var uri;

URI.parse.bind(URI, 'badURI').should.throw(TypeError);

uri = URI.parse('bchtest:');
expect(uri.address).to.be.undefined();
expect(uri.amount).to.be.undefined();
expect(uri.otherParam).to.be.undefined();

uri = URI.parse('bchtest:qqkj609un9sl896yezxj0j5hxagk7h7pnyyzaz887x');
uri.address.should.equal('qqkj609un9sl896yezxj0j5hxagk7h7pnyyzaz887x');
expect(uri.amount).to.be.undefined();
expect(uri.otherParam).to.be.undefined();

uri = URI.parse('bchtest:qqkj609un9sl896yezxj0j5hxagk7h7pnyyzaz887x?amount=123.22');
uri.address.should.equal('qqkj609un9sl896yezxj0j5hxagk7h7pnyyzaz887x');
uri.amount.should.equal('123.22');
expect(uri.otherParam).to.be.undefined();

uri = URI.parse('bchtest:qqkj609un9sl896yezxj0j5hxagk7h7pnyyzaz887x?amount=123.22' +
'&other-param=something&req-extra=param');
uri.address.should.equal('qqkj609un9sl896yezxj0j5hxagk7h7pnyyzaz887x');
uri.amount.should.equal('123.22');
uri['other-param'].should.equal('something');
uri['req-extra'].should.equal('param');
});

it('Should return error if try to use an invalid bitcoin URI', function() {
var uri;

try {
uri = URI.parse('badprefix:qqkj609un9sl896yezxj0j5hxagk7h7pnyyzaz887x');
} catch (e) {
expect(e.message).to.equal('Invalid bitcoin URI');
}
});

describe('cashaddr', function() {
URI.parse.bind(URI, 'badURI').should.throw(TypeError);

Expand Down Expand Up @@ -105,7 +144,73 @@ describe('URI', function() {
// becase other-; req-* was not supplied to validator
URI.isValid(str).should.equal(true);
});
});

describe('cashaddr for testnet', function() {
URI.parse.bind(URI, 'badURI').should.throw(TypeError);

// cashaddr
it('address only', function() {
var uri;
var str = 'bchtest:qqkj609un9sl896yezxj0j5hxagk7h7pnyyzaz887x';
uri = URI.parse(str);
uri.address.should.equal('qqkj609un9sl896yezxj0j5hxagk7h7pnyyzaz887x');
expect(uri.amount).to.be.undefined();
expect(uri.otherParam).to.be.undefined();
URI.isValid(str).should.equal(true);
});

it('address +amount', function() {
var uri;
var str = 'bchtest:qqkj609un9sl896yezxj0j5hxagk7h7pnyyzaz887x?amount=123.22';
uri = URI.parse(str);
uri.address.should.equal('qqkj609un9sl896yezxj0j5hxagk7h7pnyyzaz887x');
uri.amount.should.equal('123.22');
expect(uri.otherParam).to.be.undefined();
URI.isValid(str).should.equal(true);
});


it('address +amount + opts', function() {
var uri;
var str = 'bchtest:qqkj609un9sl896yezxj0j5hxagk7h7pnyyzaz887x?amount=123.22' +
'&other-param=something&req-extra=param';
uri = URI.parse(str);
uri.address.should.equal('qqkj609un9sl896yezxj0j5hxagk7h7pnyyzaz887x');
uri.amount.should.equal('123.22');
uri['other-param'].should.equal('something');
uri['req-extra'].should.equal('param');

URI.isValid(str).should.equal(false);
});

it('address +amount + opts', function() {
var uri;
var str = 'bchtest:qqkj609un9sl896yezxj0j5hxagk7h7pnyyzaz887x?amount=123.22' +
'&other-param=something&req-extra=param';
uri = URI.parse(str);
uri.address.should.equal('qqkj609un9sl896yezxj0j5hxagk7h7pnyyzaz887x');
uri.amount.should.equal('123.22');
uri['other-param'].should.equal('something');
uri['req-extra'].should.equal('param');

// becase other-; req-* was not supplied to validator
URI.isValid(str).should.equal(false);
});

it('address +amount + opts', function() {
var uri;
var str = 'bchtest:qqkj609un9sl896yezxj0j5hxagk7h7pnyyzaz887x?amount=123.22' +
'&message=Donation%20for%20project%20xyz&label=myLabel';
uri = URI.parse(str);
uri.address.should.equal('qqkj609un9sl896yezxj0j5hxagk7h7pnyyzaz887x');
uri.amount.should.equal('123.22');
uri.label.should.equal('myLabel');
uri.message.should.equal('Donation for project xyz');

// becase other-; req-* was not supplied to validator
URI.isValid(str).should.equal(true);
});

});

Expand All @@ -114,7 +219,6 @@ describe('URI', function() {
// TODO: Split this and explain tests
it('URIs can be validated statically (test vector)', function() {
URI.isValid('bitcoincash:qzruaav37d2hwqfaqvsktwdqjly502s06qfra0qe9m').should.equal(true);
URI.isValid('bitcoincash:mkYY5NRvikVBY1EPtaq9fAFgquesdjqECw').should.equal(true);

URI.isValid('bitcoincash:qzruaav37d2hwqfaqvsktwdqjly502s06qfra0qe9m?amount=1.2')
.should.equal(true);
Expand All @@ -134,6 +238,28 @@ describe('URI', function() {
.should.equal(false);
});

// TODO: Split this and explain tests
it('URIs can be validated statically (test vector)', function() {
URI.isValid('bchtest:qqkj609un9sl896yezxj0j5hxagk7h7pnyyzaz887x').should.equal(true);

URI.isValid('bchtest:qqkj609un9sl896yezxj0j5hxagk7h7pnyyzaz887x?amount=1.2')
.should.equal(true);
URI.isValid('bchtest:qqkj609un9sl896yezxj0j5hxagk7h7pnyyzaz887x?amount=1.2&other=param')
.should.equal(true);
URI.isValid('bchtest:qqkj609un9sl896yezxj0j5hxagk7h7pnyyzaz887x?amount=1.2&req-other=param',
['req-other']).should.equal(true);
URI.isValid('bchtest:mmrqEBJxUCf42vdb3oozZtyz5mKr3Vb2Em?amount=0.1&' +
'r=https%3A%2F%2Ftest.bitpay.com%2Fi%2F6DKgf8cnJC388irbXk5hHu').should.equal(true);

URI.isValid('bchtest:').should.equal(false);
URI.isValid('bchtest:badUri').should.equal(false);
URI.isValid('bchtest:1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfk?amount=bad').should.equal(false);
URI.isValid('bchtest:1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfk?amount=1.2&req-other=param')
.should.equal(false);
URI.isValid('bchtest:?r=https%3A%2F%2Ftest.bitpay.com%2Fi%2F6DKgf8cnJC388irbXk5hHu')
.should.equal(false);
});

it('fails on creation with no params', function() {
(function(){
return new URI();
Expand All @@ -145,6 +271,11 @@ describe('URI', function() {
uri.should.be.instanceof(URI);
});

it('do not need new keyword for testnet', function() {
var uri = URI('bchtest:qqkj609un9sl896yezxj0j5hxagk7h7pnyyzaz887x');
uri.should.be.instanceof(URI);
});

describe('instantiation from bitcoin uri', function() {
/* jshint maxstatements: 25 */
var uri;
Expand All @@ -162,27 +293,61 @@ describe('URI', function() {
expect(uri.otherParam).to.be.undefined();
});

it('stores unknown parameters as "extras"', function() {
uri = new URI('bitcoincash:qzruaav37d2hwqfaqvsktwdqjly502s06qfra0qe9m?amount=1.2&other=param');
uri.address.should.be.instanceof(bitcore.Address);
expect(uri.other).to.be.undefined();
uri.extras.other.should.equal('param');
});

it('throws error when a required feature is not supported', function() {
(function() {
return new URI('bitcoincash:qzruaav37d2hwqfaqvsktwdqjly502s06qfra0qe9m?amount=1.2&other=param&req-required=param');
}).should.throw(Error);
});

it('has no false negative when checking supported features', function() {
uri = new URI('bitcoincash:qzruaav37d2hwqfaqvsktwdqjly502s06qfra0qe9m?amount=1.2&other=param&' +
'req-required=param', ['req-required']);
uri.address.should.be.instanceof(bitcore.Address);
uri.amount.should.equal(120000000);
uri.extras.other.should.equal('param');
uri.extras['req-required'].should.equal('param');
});
});

describe('instantiation from bitcoin uri for testnet', function() {
/* jshint maxstatements: 25 */
var uri;

it('parses a testnet address', function() {
uri = new URI('bitcoincash:mkYY5NRvikVBY1EPtaq9fAFgquesdjqECw');
uri = new URI('bchtest:qqkj609un9sl896yezxj0j5hxagk7h7pnyyzaz887x');
uri.address.should.be.instanceof(bitcore.Address);
uri.network.should.equal(Networks.testnet);
});

it('parses amount', function() {
uri = URI.fromString('bchtest:qqkj609un9sl896yezxj0j5hxagk7h7pnyyzaz887x?amount=123.22');
uri.address.toString().should.equal('bchtest:qqkj609un9sl896yezxj0j5hxagk7h7pnyyzaz887x');
uri.amount.should.equal(12322000000);
expect(uri.otherParam).to.be.undefined();
});

it('stores unknown parameters as "extras"', function() {
uri = new URI('bitcoincash:qzruaav37d2hwqfaqvsktwdqjly502s06qfra0qe9m?amount=1.2&other=param');
uri = new URI('bchtest:qqkj609un9sl896yezxj0j5hxagk7h7pnyyzaz887x?amount=1.2&other=param');
uri.address.should.be.instanceof(bitcore.Address);
expect(uri.other).to.be.undefined();
uri.extras.other.should.equal('param');
});

it('throws error when a required feature is not supported', function() {
(function() {
return new URI('bitcoincash:qzruaav37d2hwqfaqvsktwdqjly502s06qfra0qe9m?amount=1.2&other=param&req-required=param');
return new URI('bchtest:qqkj609un9sl896yezxj0j5hxagk7h7pnyyzaz887x?amount=1.2&other=param&req-required=param');
}).should.throw(Error);
});

it('has no false negative when checking supported features', function() {
uri = new URI('bitcoincash:qzruaav37d2hwqfaqvsktwdqjly502s06qfra0qe9m?amount=1.2&other=param&' +
uri = new URI('bchtest:qqkj609un9sl896yezxj0j5hxagk7h7pnyyzaz887x?amount=1.2&other=param&' +
'req-required=param', ['req-required']);
uri.address.should.be.instanceof(bitcore.Address);
uri.amount.should.equal(120000000);
Expand All @@ -203,7 +368,7 @@ describe('URI', function() {
uri.network.should.equal(Networks.livenet);

uri = new URI({
address: 'mkYY5NRvikVBY1EPtaq9fAFgquesdjqECw'
address: 'qqkj609un9sl896yezxj0j5hxagk7h7pnyyzaz887x'
});
uri.address.should.be.instanceof(bitcore.Address);
uri.network.should.equal(Networks.testnet);
Expand Down Expand Up @@ -240,12 +405,19 @@ describe('URI', function() {
it('should support double slash scheme', function() {
var uri = new URI('bitcoincash://qzruaav37d2hwqfaqvsktwdqjly502s06qfra0qe9m');
uri.address.toString().should.equal('bitcoincash:qzruaav37d2hwqfaqvsktwdqjly502s06qfra0qe9m');

uri = new URI('bchtest://qqkj609un9sl896yezxj0j5hxagk7h7pnyyzaz887x');
uri.address.toString().should.equal('bchtest:qqkj609un9sl896yezxj0j5hxagk7h7pnyyzaz887x');
});

it('should input/output String', function() {
var str = 'bitcoincash:qzruaav37d2hwqfaqvsktwdqjly502s06qfra0qe9m?' +
'message=Donation%20for%20project%20xyz&label=myLabel&other=xD';
URI.fromString(str).toString().should.equal(str);

str = 'bchtest:qqkj609un9sl896yezxj0j5hxagk7h7pnyyzaz887x?' +
'message=Donation%20for%20project%20xyz&label=myLabel&other=xD';
URI.fromString(str).toString().should.equal(str);
});

it('should input/output JSON', function() {
Expand Down Expand Up @@ -303,7 +475,7 @@ describe('URI', function() {
});

it('writes correctly the "r" parameter on string serialization', function() {
var originalString = 'bitcoincash:qpzextxrtp4ettwsfru86fggmwf565h3jshdfuz5vj?amount=0.1&' +
var originalString = 'bchtest:qpzextxrtp4ettwsfru86fggmwf565h3jshdfuz5vj?amount=0.1&' +
'r=https%3A%2F%2Ftest.bitpay.com%2Fi%2F6DKgf8cnJC388irbXk5hHu';
var uri = new URI(originalString);
uri.toString().should.equal(originalString);
Expand Down

0 comments on commit 494b14c

Please sign in to comment.