1 | 'use strict';
|
2 |
|
3 | var _ = require('lodash');
|
4 | var URL = require('url');
|
5 |
|
6 | var Address = require('./address');
|
7 | var Unit = require('./unit');
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 | var URI = function(data, knownParams) {
|
36 | if (!(this instanceof URI)) {
|
37 | return new URI(data, knownParams);
|
38 | }
|
39 |
|
40 | this.extras = {};
|
41 | this.knownParams = knownParams || [];
|
42 | this.address = this.network = this.amount = this.message = null;
|
43 |
|
44 | if (typeof(data) === 'string') {
|
45 | var params = URI.parse(data);
|
46 | if (params.amount) {
|
47 | params.amount = this._parseAmount(params.amount);
|
48 | }
|
49 | this._fromObject(params);
|
50 | } else if (typeof(data) === 'object') {
|
51 | this._fromObject(data);
|
52 | } else {
|
53 | throw new TypeError('Unrecognized data format.');
|
54 | }
|
55 | };
|
56 |
|
57 |
|
58 |
|
59 |
|
60 |
|
61 |
|
62 |
|
63 | URI.fromString = function fromString(str) {
|
64 | if (typeof(str) !== 'string') {
|
65 | throw new TypeError('Expected a string');
|
66 | }
|
67 | return new URI(str);
|
68 | };
|
69 |
|
70 |
|
71 |
|
72 |
|
73 |
|
74 |
|
75 |
|
76 | URI.fromObject = function fromObject(json) {
|
77 | return new URI(json);
|
78 | };
|
79 |
|
80 |
|
81 |
|
82 |
|
83 |
|
84 |
|
85 |
|
86 |
|
87 |
|
88 |
|
89 |
|
90 |
|
91 |
|
92 |
|
93 |
|
94 | URI.isValid = function(arg, knownParams) {
|
95 | try {
|
96 | new URI(arg, knownParams);
|
97 | } catch (err) {
|
98 | return false;
|
99 | }
|
100 | return true;
|
101 | };
|
102 |
|
103 |
|
104 |
|
105 |
|
106 |
|
107 |
|
108 |
|
109 |
|
110 | URI.parse = function(uri) {
|
111 | var info = URL.parse(uri, true);
|
112 |
|
113 | if (info.protocol !== 'bitcoin:') {
|
114 | throw new TypeError('Invalid bitcoin URI');
|
115 | }
|
116 |
|
117 |
|
118 | var group = /[^:]*:\/?\/?([^?]*)/.exec(uri);
|
119 | info.query.address = group && group[1] || undefined;
|
120 |
|
121 | return info.query;
|
122 | };
|
123 |
|
124 | URI.Members = ['address', 'amount', 'message', 'label', 'r'];
|
125 |
|
126 |
|
127 |
|
128 |
|
129 |
|
130 |
|
131 |
|
132 |
|
133 |
|
134 | URI.prototype._fromObject = function(obj) {
|
135 |
|
136 |
|
137 | if (!Address.isValid(obj.address)) {
|
138 | throw new TypeError('Invalid bitcoin address');
|
139 | }
|
140 |
|
141 | this.address = new Address(obj.address);
|
142 | this.network = this.address.network;
|
143 | this.amount = obj.amount;
|
144 |
|
145 | for (var key in obj) {
|
146 | if (key === 'address' || key === 'amount') {
|
147 | continue;
|
148 | }
|
149 |
|
150 | if (/^req-/.exec(key) && this.knownParams.indexOf(key) === -1) {
|
151 | throw Error('Unknown required argument ' + key);
|
152 | }
|
153 |
|
154 | var destination = URI.Members.indexOf(key) > -1 ? this : this.extras;
|
155 | destination[key] = obj[key];
|
156 | }
|
157 | };
|
158 |
|
159 |
|
160 |
|
161 |
|
162 |
|
163 |
|
164 |
|
165 |
|
166 | URI.prototype._parseAmount = function(amount) {
|
167 | amount = Number(amount);
|
168 | if (isNaN(amount)) {
|
169 | throw new TypeError('Invalid amount');
|
170 | }
|
171 | return Unit.fromBTC(amount).toSatoshis();
|
172 | };
|
173 |
|
174 | URI.prototype.toObject = URI.prototype.toJSON = function toObject() {
|
175 | var json = {};
|
176 | for (var i = 0; i < URI.Members.length; i++) {
|
177 | var m = URI.Members[i];
|
178 | if (this.hasOwnProperty(m) && typeof(this[m]) !== 'undefined') {
|
179 | json[m] = this[m].toString();
|
180 | }
|
181 | }
|
182 | _.extend(json, this.extras);
|
183 | return json;
|
184 | };
|
185 |
|
186 |
|
187 |
|
188 |
|
189 |
|
190 |
|
191 | URI.prototype.toString = function() {
|
192 | var query = {};
|
193 | if (this.amount) {
|
194 | query.amount = Unit.fromSatoshis(this.amount).toBTC();
|
195 | }
|
196 | if (this.message) {
|
197 | query.message = this.message;
|
198 | }
|
199 | if (this.label) {
|
200 | query.label = this.label;
|
201 | }
|
202 | if (this.r) {
|
203 | query.r = this.r;
|
204 | }
|
205 | _.extend(query, this.extras);
|
206 |
|
207 | return URL.format({
|
208 | protocol: 'bitcoin:',
|
209 | host: this.address,
|
210 | query: query
|
211 | });
|
212 | };
|
213 |
|
214 |
|
215 |
|
216 |
|
217 |
|
218 |
|
219 | URI.prototype.inspect = function() {
|
220 | return '<URI: ' + this.toString() + '>';
|
221 | };
|
222 |
|
223 | module.exports = URI;
|