You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
223 lines
5.5 KiB
223 lines
5.5 KiB
'use strict';
|
|
|
|
var _ = require('lodash');
|
|
var URL = require('url');
|
|
|
|
var Address = require('./address');
|
|
var Unit = require('./unit');
|
|
|
|
/**
|
|
* Bitcore URI
|
|
*
|
|
* Instantiate an URI from a bitcoin URI String or an Object. An URI instance
|
|
* can be created with a bitcoin uri string or an object. All instances of
|
|
* URI are valid, the static method isValid allows checking before instantiation.
|
|
*
|
|
* All standard parameters can be found as members of the class, the address
|
|
* is represented using an {Address} instance and the amount is represented in
|
|
* satoshis. Any other non-standard parameters can be found under the extra member.
|
|
*
|
|
* @example
|
|
* ```javascript
|
|
*
|
|
* var uri = new URI('bitcoin:12A1MyfXbW6RhdRAZEqofac5jCQQjwEPBu?amount=1.2');
|
|
* console.log(uri.address, uri.amount);
|
|
* ```
|
|
*
|
|
* @param {string|Object} data - A bitcoin URI string or an Object
|
|
* @param {Array.<string>=} knownParams - Required non-standard params
|
|
* @throws {TypeError} Invalid bitcoin address
|
|
* @throws {TypeError} Invalid amount
|
|
* @throws {Error} Unknown required argument
|
|
* @returns {URI} A new valid and frozen instance of URI
|
|
* @constructor
|
|
*/
|
|
var URI = function(data, knownParams) {
|
|
if (!(this instanceof URI)) {
|
|
return new URI(data, knownParams);
|
|
}
|
|
|
|
this.extras = {};
|
|
this.knownParams = knownParams || [];
|
|
this.address = this.network = this.amount = this.message = null;
|
|
|
|
if (typeof(data) === 'string') {
|
|
var params = URI.parse(data);
|
|
if (params.amount) {
|
|
params.amount = this._parseAmount(params.amount);
|
|
}
|
|
this._fromObject(params);
|
|
} else if (typeof(data) === 'object') {
|
|
this._fromObject(data);
|
|
} else {
|
|
throw new TypeError('Unrecognized data format.');
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Instantiate a URI from a String
|
|
*
|
|
* @param {string} str - JSON string or object of the URI
|
|
* @returns {URI} A new instance of a URI
|
|
*/
|
|
URI.fromString = function fromString(str) {
|
|
if (typeof(str) !== 'string') {
|
|
throw new TypeError('Expected a string');
|
|
}
|
|
return new URI(str);
|
|
};
|
|
|
|
/**
|
|
* Instantiate a URI from an Object
|
|
*
|
|
* @param {Object} data - object of the URI
|
|
* @returns {URI} A new instance of a URI
|
|
*/
|
|
URI.fromObject = function fromObject(json) {
|
|
return new URI(json);
|
|
};
|
|
|
|
/**
|
|
* Check if an bitcoin URI string is valid
|
|
*
|
|
* @example
|
|
* ```javascript
|
|
*
|
|
* var valid = URI.isValid('bitcoin:12A1MyfXbW6RhdRAZEqofac5jCQQjwEPBu');
|
|
* // true
|
|
* ```
|
|
*
|
|
* @param {string|Object} data - A bitcoin URI string or an Object
|
|
* @param {Array.<string>=} knownParams - Required non-standard params
|
|
* @returns {boolean} Result of uri validation
|
|
*/
|
|
URI.isValid = function(arg, knownParams) {
|
|
try {
|
|
new URI(arg, knownParams);
|
|
} catch (err) {
|
|
return false;
|
|
}
|
|
return true;
|
|
};
|
|
|
|
/**
|
|
* Convert a bitcoin URI string into a simple object.
|
|
*
|
|
* @param {string} uri - A bitcoin URI string
|
|
* @throws {TypeError} Invalid bitcoin URI
|
|
* @returns {Object} An object with the parsed params
|
|
*/
|
|
URI.parse = function(uri) {
|
|
var info = URL.parse(uri, true);
|
|
|
|
if (info.protocol !== 'bitcoin:') {
|
|
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'];
|
|
|
|
/**
|
|
* Internal function to load the URI instance with an object.
|
|
*
|
|
* @param {Object} obj - Object with the information
|
|
* @throws {TypeError} Invalid bitcoin address
|
|
* @throws {TypeError} Invalid amount
|
|
* @throws {Error} Unknown required argument
|
|
*/
|
|
URI.prototype._fromObject = function(obj) {
|
|
/* jshint maxcomplexity: 10 */
|
|
|
|
if (!Address.isValid(obj.address)) {
|
|
throw new TypeError('Invalid bitcoin address');
|
|
}
|
|
|
|
this.address = new Address(obj.address);
|
|
this.network = this.address.network;
|
|
this.amount = obj.amount;
|
|
|
|
for (var key in obj) {
|
|
if (key === 'address' || key === 'amount') {
|
|
continue;
|
|
}
|
|
|
|
if (/^req-/.exec(key) && this.knownParams.indexOf(key) === -1) {
|
|
throw Error('Unknown required argument ' + key);
|
|
}
|
|
|
|
var destination = URI.Members.indexOf(key) > -1 ? this : this.extras;
|
|
destination[key] = obj[key];
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Internal function to transform a BTC string amount into satoshis
|
|
*
|
|
* @param {string} amount - Amount BTC string
|
|
* @throws {TypeError} Invalid amount
|
|
* @returns {Object} Amount represented in satoshis
|
|
*/
|
|
URI.prototype._parseAmount = function(amount) {
|
|
amount = Number(amount);
|
|
if (isNaN(amount)) {
|
|
throw new TypeError('Invalid amount');
|
|
}
|
|
return Unit.fromBTC(amount).toSatoshis();
|
|
};
|
|
|
|
URI.prototype.toObject = URI.prototype.toJSON = function toObject() {
|
|
var json = {};
|
|
for (var i = 0; i < URI.Members.length; i++) {
|
|
var m = URI.Members[i];
|
|
if (this.hasOwnProperty(m) && typeof(this[m]) !== 'undefined') {
|
|
json[m] = this[m].toString();
|
|
}
|
|
}
|
|
_.extend(json, this.extras);
|
|
return json;
|
|
};
|
|
|
|
/**
|
|
* Will return a the string representation of the URI
|
|
*
|
|
* @returns {string} Bitcoin URI string
|
|
*/
|
|
URI.prototype.toString = function() {
|
|
var query = {};
|
|
if (this.amount) {
|
|
query.amount = Unit.fromSatoshis(this.amount).toBTC();
|
|
}
|
|
if (this.message) {
|
|
query.message = this.message;
|
|
}
|
|
if (this.label) {
|
|
query.label = this.label;
|
|
}
|
|
if (this.r) {
|
|
query.r = this.r;
|
|
}
|
|
_.extend(query, this.extras);
|
|
|
|
return URL.format({
|
|
protocol: 'bitcoin:',
|
|
host: this.address,
|
|
query: query
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Will return a string formatted for the console
|
|
*
|
|
* @returns {string} Bitcoin URI
|
|
*/
|
|
URI.prototype.inspect = function() {
|
|
return '<URI: ' + this.toString() + '>';
|
|
};
|
|
|
|
module.exports = URI;
|
|
|