@leofcoin/peernet 0.11.31 → 0.12.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/generate-account.js +50 -0
- package/dist/browser/messages.js +439 -0
- package/dist/browser/pako.js +6731 -0
- package/dist/browser/peernet-swarm.js +836 -0
- package/dist/browser/peernet.js +7576 -54848
- package/dist/browser/protons.js +3786 -0
- package/dist/browser/storage.js +12 -0
- package/dist/browser/wrtc.js +28 -0
- package/dist/commonjs/dht-6a1b6246.js +45 -0
- package/dist/commonjs/dht-response-e4a603ea.js +34 -0
- package/dist/commonjs/dht-response.js +3 -24
- package/dist/commonjs/dht.js +3 -35
- package/dist/commonjs/messages-bcb02ee9.js +189 -0
- package/dist/commonjs/{peernet-message.js → peernet-6eef77d5.js} +12 -7
- package/dist/commonjs/peernet.js +60 -1368
- package/dist/commonjs/peernet2.js +8 -0
- package/dist/commonjs/request-95ed03ec.js +33 -0
- package/dist/commonjs/request.js +3 -23
- package/dist/commonjs/response-bae4e2a2.js +33 -0
- package/dist/commonjs/response.js +3 -23
- package/dist/module/messages-421f88db.js +323 -0
- package/dist/module/peernet.js +53 -1451
- package/package.json +7 -12
- package/rollup.config.js +2 -21
- package/src/discovery/peer-discovery.js +4 -4
- package/src/handlers/data.js +2 -2
- package/src/handlers/message.js +4 -5
- package/src/messages/{chat-message.js → chat.js} +5 -2
- package/src/messages/data-response.js +5 -2
- package/src/messages/data.js +5 -2
- package/src/messages/dht-response.js +5 -2
- package/src/messages/dht.js +5 -2
- package/src/messages/peer-response.js +5 -2
- package/src/messages/peer.js +5 -2
- package/src/messages/{peernet-message.js → peernet.js} +5 -2
- package/src/messages/ps.js +5 -2
- package/src/messages/request.js +5 -2
- package/src/messages/response.js +5 -2
- package/src/messages.js +11 -0
- package/src/peernet.js +45 -32
- package/webpack.config.js +6 -3
package/dist/commonjs/peernet.js
CHANGED
|
@@ -1,25 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
require('@vandeurenglenn/debug');
|
|
4
|
-
var pako = require('pako');
|
|
5
|
-
var LeofcoinStorage = require('@leofcoin/storage');
|
|
6
|
-
var peernetMessage = require('./peernet-message.js');
|
|
7
|
-
var dht = require('./dht.js');
|
|
8
|
-
var dhtResponse = require('./dht-response.js');
|
|
9
|
-
var protons = require('protons');
|
|
10
|
-
var codecFormatInterface = require('@leofcoin/codec-format-interface');
|
|
11
|
-
var request = require('./request.js');
|
|
12
|
-
var response = require('./response.js');
|
|
13
4
|
var fetch = require('node-fetch');
|
|
14
|
-
var
|
|
15
|
-
var
|
|
16
|
-
var bip32 = require('bip32');
|
|
17
|
-
var createKeccakHash = require('keccak');
|
|
18
|
-
var ecc = require('tiny-secp256k1');
|
|
19
|
-
var Mnemonic = require('@leofcoin/mnemonic');
|
|
20
|
-
var MultiSignature = require('multi-signature');
|
|
21
|
-
var varint = require('varint');
|
|
22
|
-
var randombytes = require('randombytes');
|
|
5
|
+
var codecFormatInterface = require('@leofcoin/codec-format-interface');
|
|
6
|
+
var MultiWallet = require('@leofcoin/multi-wallet');
|
|
23
7
|
|
|
24
8
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
25
9
|
|
|
@@ -41,806 +25,8 @@ function _interopNamespace(e) {
|
|
|
41
25
|
return Object.freeze(n);
|
|
42
26
|
}
|
|
43
27
|
|
|
44
|
-
var pako__default = /*#__PURE__*/_interopDefaultLegacy(pako);
|
|
45
|
-
var LeofcoinStorage__default = /*#__PURE__*/_interopDefaultLegacy(LeofcoinStorage);
|
|
46
|
-
var protons__default = /*#__PURE__*/_interopDefaultLegacy(protons);
|
|
47
28
|
var fetch__default = /*#__PURE__*/_interopDefaultLegacy(fetch);
|
|
48
|
-
var MultiWallet__default = /*#__PURE__*/_interopDefaultLegacy(MultiWallet
|
|
49
|
-
var bs58check__default = /*#__PURE__*/_interopDefaultLegacy(bs58check);
|
|
50
|
-
var bs58check__namespace = /*#__PURE__*/_interopNamespace(bs58check);
|
|
51
|
-
var bip32__namespace = /*#__PURE__*/_interopNamespace(bip32);
|
|
52
|
-
var createKeccakHash__default = /*#__PURE__*/_interopDefaultLegacy(createKeccakHash);
|
|
53
|
-
var ecc__default = /*#__PURE__*/_interopDefaultLegacy(ecc);
|
|
54
|
-
var Mnemonic__default = /*#__PURE__*/_interopDefaultLegacy(Mnemonic);
|
|
55
|
-
var MultiSignature__default = /*#__PURE__*/_interopDefaultLegacy(MultiSignature);
|
|
56
|
-
var varint__default = /*#__PURE__*/_interopDefaultLegacy(varint);
|
|
57
|
-
var randombytes__default = /*#__PURE__*/_interopDefaultLegacy(randombytes);
|
|
58
|
-
|
|
59
|
-
/* socket-request-client version 1.6.3 */
|
|
60
|
-
|
|
61
|
-
class LittlePubSub {
|
|
62
|
-
constructor(verbose = true) {
|
|
63
|
-
this.subscribers = {};
|
|
64
|
-
this.verbose = verbose;
|
|
65
|
-
}
|
|
66
|
-
subscribe(event, handler, context) {
|
|
67
|
-
if (typeof context === 'undefined') {
|
|
68
|
-
context = handler;
|
|
69
|
-
}
|
|
70
|
-
this.subscribers[event] = this.subscribers[event] || { handlers: [], value: null};
|
|
71
|
-
this.subscribers[event].handlers.push(handler.bind(context));
|
|
72
|
-
}
|
|
73
|
-
unsubscribe(event, handler, context) {
|
|
74
|
-
if (typeof context === 'undefined') {
|
|
75
|
-
context = handler;
|
|
76
|
-
}
|
|
77
|
-
if (this.subscribers[event]) {
|
|
78
|
-
const index = this.subscribers[event].handlers.indexOf(handler.bind(context));
|
|
79
|
-
this.subscribers[event].handlers.splice(index);
|
|
80
|
-
if (this.subscribers[event].handlers.length === 0) delete this.subscribers[event];
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
publish(event, change) {
|
|
84
|
-
if (this.subscribers[event]) {
|
|
85
|
-
if (this.verbose || this.subscribers[event].value !== change) {
|
|
86
|
-
this.subscribers[event].value = change;
|
|
87
|
-
this.subscribers[event].handlers.forEach(handler => {
|
|
88
|
-
handler(change, this.subscribers[event].value);
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
var clientApi = _pubsub => {
|
|
96
|
-
const subscribe = (topic, cb) => {
|
|
97
|
-
_pubsub.subscribe(topic, cb);
|
|
98
|
-
};
|
|
99
|
-
const unsubscribe = (topic, cb) => {
|
|
100
|
-
_pubsub.unsubscribe(topic, cb);
|
|
101
|
-
};
|
|
102
|
-
const publish = (topic, value) => {
|
|
103
|
-
_pubsub.publish(topic, value);
|
|
104
|
-
};
|
|
105
|
-
const _connectionState = (state) => {
|
|
106
|
-
switch (state) {
|
|
107
|
-
case 0:
|
|
108
|
-
return 'connecting'
|
|
109
|
-
case 1:
|
|
110
|
-
return 'open'
|
|
111
|
-
case 2:
|
|
112
|
-
return 'closing'
|
|
113
|
-
case 3:
|
|
114
|
-
return 'closed'
|
|
115
|
-
}
|
|
116
|
-
};
|
|
117
|
-
const request = (client, request) => {
|
|
118
|
-
return new Promise((resolve, reject) => {
|
|
119
|
-
const state = _connectionState(client.readyState);
|
|
120
|
-
if (state !== 'open') return reject(`coudn't send request to ${client.id}, no open connection found.`)
|
|
121
|
-
request.id = Math.random().toString(36).slice(-12);
|
|
122
|
-
const handler = result => {
|
|
123
|
-
if (result && result.error) return reject(result.error)
|
|
124
|
-
resolve({result, id: request.id, handler});
|
|
125
|
-
unsubscribe(request.id, handler);
|
|
126
|
-
};
|
|
127
|
-
subscribe(request.id, handler);
|
|
128
|
-
send(client, request);
|
|
129
|
-
});
|
|
130
|
-
};
|
|
131
|
-
const send = async (client, request) => {
|
|
132
|
-
return client.send(JSON.stringify(request))
|
|
133
|
-
};
|
|
134
|
-
const pubsub = client => {
|
|
135
|
-
return {
|
|
136
|
-
publish: (topic = 'pubsub', value) => {
|
|
137
|
-
return send(client, {url: 'pubsub', params: { topic, value }})
|
|
138
|
-
},
|
|
139
|
-
subscribe: (topic = 'pubsub', cb) => {
|
|
140
|
-
subscribe(topic, cb);
|
|
141
|
-
return send(client, {url: 'pubsub', params: { topic, subscribe: true }})
|
|
142
|
-
},
|
|
143
|
-
unsubscribe: (topic = 'pubsub', cb) => {
|
|
144
|
-
unsubscribe(topic, cb);
|
|
145
|
-
return send(client, {url: 'pubsub', params: { topic, unsubscribe: true }})
|
|
146
|
-
},
|
|
147
|
-
subscribers: _pubsub.subscribers
|
|
148
|
-
}
|
|
149
|
-
};
|
|
150
|
-
const server = (client) => {
|
|
151
|
-
return {
|
|
152
|
-
uptime: async () => {
|
|
153
|
-
try {
|
|
154
|
-
const { result, id, handler } = await request(client, {url: 'uptime'});
|
|
155
|
-
unsubscribe(id, handler);
|
|
156
|
-
return result
|
|
157
|
-
} catch (e) {
|
|
158
|
-
throw e
|
|
159
|
-
}
|
|
160
|
-
},
|
|
161
|
-
ping: async () => {
|
|
162
|
-
try {
|
|
163
|
-
const now = new Date().getTime();
|
|
164
|
-
const { result, id, handler } = await request(client, {url: 'ping'});
|
|
165
|
-
unsubscribe(id, handler);
|
|
166
|
-
return (Number(result) - now)
|
|
167
|
-
} catch (e) {
|
|
168
|
-
throw e
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
};
|
|
173
|
-
const peernet = (client) => {
|
|
174
|
-
return {
|
|
175
|
-
join: async (params) => {
|
|
176
|
-
try {
|
|
177
|
-
params.join = true;
|
|
178
|
-
const requested = { url: 'peernet', params };
|
|
179
|
-
const { result, id, handler } = await request(client, requested);
|
|
180
|
-
unsubscribe(id, handler);
|
|
181
|
-
return result
|
|
182
|
-
} catch (e) {
|
|
183
|
-
throw e
|
|
184
|
-
}
|
|
185
|
-
},
|
|
186
|
-
leave: async (params) => {
|
|
187
|
-
try {
|
|
188
|
-
params.join = false;
|
|
189
|
-
const requested = { url: 'peernet', params };
|
|
190
|
-
const { result, id, handler } = await request(client, requested);
|
|
191
|
-
unsubscribe(id, handler);
|
|
192
|
-
return result
|
|
193
|
-
} catch (e) {
|
|
194
|
-
throw e
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
};
|
|
199
|
-
return { send, request, pubsub, server, subscribe, unsubscribe, publish, peernet }
|
|
200
|
-
};
|
|
201
|
-
|
|
202
|
-
if (!globalThis.PubSub) globalThis.PubSub = LittlePubSub;
|
|
203
|
-
if (!globalThis.pubsub) globalThis.pubsub = new LittlePubSub({verbose: false});
|
|
204
|
-
const socketRequestClient = (url, protocols = 'echo-protocol', options = { retry: false }) => {
|
|
205
|
-
const { retry } = options;
|
|
206
|
-
const api = clientApi(pubsub);
|
|
207
|
-
let tries = 0;
|
|
208
|
-
const onerror = error => {
|
|
209
|
-
if (pubsub.subscribers['error']) {
|
|
210
|
-
pubsub.publish('error', error);
|
|
211
|
-
} else {
|
|
212
|
-
console.error(error);
|
|
213
|
-
}
|
|
214
|
-
};
|
|
215
|
-
const onmessage = message => {
|
|
216
|
-
const {value, url, status, id} = JSON.parse(message.data.toString());
|
|
217
|
-
const publisher = id ? id : url;
|
|
218
|
-
if (status === 200) {
|
|
219
|
-
pubsub.publish(publisher, value);
|
|
220
|
-
} else {
|
|
221
|
-
pubsub.publish(publisher, {error: value});
|
|
222
|
-
}
|
|
223
|
-
};
|
|
224
|
-
const clientConnection = client => {
|
|
225
|
-
const startTime = new Date().getTime();
|
|
226
|
-
return {
|
|
227
|
-
client,
|
|
228
|
-
request: async req => {
|
|
229
|
-
const { result, id, handler } = await api.request(client, req);
|
|
230
|
-
pubsub.unsubscribe(id, handler);
|
|
231
|
-
return result
|
|
232
|
-
},
|
|
233
|
-
send: req => api.send(client, req),
|
|
234
|
-
subscribe: api.subscribe,
|
|
235
|
-
unsubscribe: api.unsubscribe,
|
|
236
|
-
subscribers: api.subscribers,
|
|
237
|
-
publish: api.publish,
|
|
238
|
-
pubsub: api.pubsub(client),
|
|
239
|
-
uptime: () => {
|
|
240
|
-
const now = new Date().getTime();
|
|
241
|
-
return (now - startTime)
|
|
242
|
-
},
|
|
243
|
-
peernet: api.peernet(client),
|
|
244
|
-
server: api.server(client),
|
|
245
|
-
close: exit => {
|
|
246
|
-
client.close();
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
};
|
|
250
|
-
return new Promise((resolve, reject) => {
|
|
251
|
-
const init = () => {
|
|
252
|
-
let ws;
|
|
253
|
-
if (typeof process === 'object' && !globalThis.WebSocket) {
|
|
254
|
-
ws = require('websocket').w3cwebsocket;
|
|
255
|
-
} else {
|
|
256
|
-
ws = WebSocket;
|
|
257
|
-
}
|
|
258
|
-
const client = new ws(url, protocols);
|
|
259
|
-
client.onmessage = onmessage;
|
|
260
|
-
client.onerror = onerror;
|
|
261
|
-
client.onopen = () => {
|
|
262
|
-
tries = 0;
|
|
263
|
-
resolve(clientConnection(client));
|
|
264
|
-
};
|
|
265
|
-
client.onclose = message => {
|
|
266
|
-
tries++;
|
|
267
|
-
if (!retry) return reject(options)
|
|
268
|
-
if (tries > 5) {
|
|
269
|
-
console.log(`${protocols} Client Closed`);
|
|
270
|
-
console.error(`could not connect to - ${url}/`);
|
|
271
|
-
return resolve(clientConnection(client))
|
|
272
|
-
}
|
|
273
|
-
if (message.code === 1006) {
|
|
274
|
-
console.log('Retrying in 10 seconds');
|
|
275
|
-
setTimeout(() => {
|
|
276
|
-
return init();
|
|
277
|
-
}, retry);
|
|
278
|
-
}
|
|
279
|
-
};
|
|
280
|
-
};
|
|
281
|
-
return init();
|
|
282
|
-
});
|
|
283
|
-
};
|
|
284
|
-
|
|
285
|
-
class Peer {
|
|
286
|
-
#connection
|
|
287
|
-
#connecting = false
|
|
288
|
-
#connected = false
|
|
289
|
-
#channelReady = false
|
|
290
|
-
#destroying = false
|
|
291
|
-
#destroyed = false
|
|
292
|
-
#isNegotiating = false
|
|
293
|
-
#firstNegotiation = true
|
|
294
|
-
#iceComplete = false
|
|
295
|
-
#remoteTracks = []
|
|
296
|
-
#remoteStreams = []
|
|
297
|
-
#pendingCandidates = []
|
|
298
|
-
#senderMap = new Map()
|
|
299
|
-
#messageQue = []
|
|
300
|
-
#chunksQue = {}
|
|
301
|
-
#iceCompleteTimer
|
|
302
|
-
#channel
|
|
303
|
-
#peerId
|
|
304
|
-
#chunkSize = 16 * 1024 // 16384
|
|
305
|
-
#queRunning = false
|
|
306
|
-
#MAX_BUFFERED_AMOUNT = 16 * 1024 * 1024
|
|
307
|
-
|
|
308
|
-
get connection() {
|
|
309
|
-
return this.#connection
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
get connected() {
|
|
313
|
-
return this.#connected
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
get readyState() {
|
|
317
|
-
return this.channel?.readyState
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
/**
|
|
321
|
-
* @params {Object} options
|
|
322
|
-
* @params {string} options.channelName - this peerid : otherpeer id
|
|
323
|
-
*/
|
|
324
|
-
constructor(options = {}) {
|
|
325
|
-
this._in = this._in.bind(this);
|
|
326
|
-
this.offerOptions = options.offerOptions;
|
|
327
|
-
this.initiator = options.initiator;
|
|
328
|
-
this.streams = options.streams;
|
|
329
|
-
this.socketClient = options.socketClient;
|
|
330
|
-
this.id = options.id;
|
|
331
|
-
this.to = options.to;
|
|
332
|
-
this.bw = {
|
|
333
|
-
up: 0,
|
|
334
|
-
down: 0
|
|
335
|
-
};
|
|
336
|
-
|
|
337
|
-
this.channelName = options.channelName;
|
|
338
|
-
|
|
339
|
-
this.#peerId = options.peerId;
|
|
340
|
-
this.options = options;
|
|
341
|
-
this.#init();
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
get peerId() {
|
|
345
|
-
return this.#peerId
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
set socketClient(value) {
|
|
349
|
-
// this.socketClient?.pubsub.unsubscribe('signal', this._in)
|
|
350
|
-
this._socketClient = value;
|
|
351
|
-
this._socketClient.pubsub.subscribe('signal', this._in);
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
get socketClient() {
|
|
355
|
-
return this._socketClient
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
splitMessage(message) {
|
|
359
|
-
const chunks = [];
|
|
360
|
-
message = pako__default["default"].deflate(message);
|
|
361
|
-
const size = message.byteLength || message.length;
|
|
362
|
-
let offset = 0;
|
|
363
|
-
return new Promise((resolve, reject) => {
|
|
364
|
-
const splitMessage = () => {
|
|
365
|
-
const chunk = message.slice(offset, offset + this.#chunkSize > size ? size : offset + this.#chunkSize);
|
|
366
|
-
offset += this.#chunkSize;
|
|
367
|
-
chunks.push(chunk);
|
|
368
|
-
if (offset < size) return splitMessage()
|
|
369
|
-
else resolve({chunks, size});
|
|
370
|
-
};
|
|
371
|
-
|
|
372
|
-
splitMessage();
|
|
373
|
-
})
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
async #runQue() {
|
|
377
|
-
this.#queRunning = true;
|
|
378
|
-
if (this.#messageQue.length > 0 && this.channel.bufferedAmount + this.#messageQue[0]?.length < this.#MAX_BUFFERED_AMOUNT) {
|
|
379
|
-
const message = this.#messageQue.shift();
|
|
380
|
-
|
|
381
|
-
switch (this.channel?.readyState) {
|
|
382
|
-
case 'open':
|
|
383
|
-
await this.channel.send(message);
|
|
384
|
-
if (this.#messageQue.length > 0) return this.#runQue()
|
|
385
|
-
else this.#queRunning = false;
|
|
386
|
-
break;
|
|
387
|
-
case 'closed':
|
|
388
|
-
case 'closing':
|
|
389
|
-
this.#messageQue = [];
|
|
390
|
-
this.#queRunning = false;
|
|
391
|
-
debug('channel already closed, this usually means a bad implementation, try checking the readyState or check if the peer is connected before sending');
|
|
392
|
-
break;
|
|
393
|
-
case undefined:
|
|
394
|
-
this.#messageQue = [];
|
|
395
|
-
this.#queRunning = false;
|
|
396
|
-
debug(`trying to send before a channel is created`);
|
|
397
|
-
break;
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
} else {
|
|
402
|
-
return setTimeout(() => this.#runQue(), 50)
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
#trySend({ size, id, chunks }) {
|
|
407
|
-
let offset = 0;
|
|
408
|
-
|
|
409
|
-
for (const chunk of chunks) {
|
|
410
|
-
const start = offset;
|
|
411
|
-
const end = offset + chunk.length;
|
|
412
|
-
|
|
413
|
-
const message = new TextEncoder().encode(JSON.stringify({ size, id, chunk, start, end }));
|
|
414
|
-
this.#messageQue.push(message);
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
if (!this.queRunning) return this.#runQue()
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
async send(message, id) {
|
|
421
|
-
const { chunks, size } = await this.splitMessage(message);
|
|
422
|
-
return this.#trySend({ size, id, chunks })
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
request(data) {
|
|
426
|
-
return new Promise((resolve, reject) => {
|
|
427
|
-
const id = Math.random().toString(36).slice(-12);
|
|
428
|
-
|
|
429
|
-
const _onData = message => {
|
|
430
|
-
if (message.id === id) {
|
|
431
|
-
resolve(message.data);
|
|
432
|
-
pubsub.unsubscribe(`peer:data`, _onData);
|
|
433
|
-
}
|
|
434
|
-
};
|
|
435
|
-
|
|
436
|
-
pubsub.subscribe(`peer:data`, _onData);
|
|
437
|
-
|
|
438
|
-
// cleanup subscriptions
|
|
439
|
-
// setTimeout(() => {
|
|
440
|
-
// pubsub.unsubscribe(`peer:data-request-${id}`, _onData)
|
|
441
|
-
// }, 5000);
|
|
442
|
-
|
|
443
|
-
this.send(data, id);
|
|
444
|
-
})
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
async #init() {
|
|
448
|
-
try {
|
|
449
|
-
const iceServers = [{
|
|
450
|
-
urls: 'stun:stun.l.google.com:19302' // Google's public STUN server
|
|
451
|
-
}, {
|
|
452
|
-
urls: "stun:openrelay.metered.ca:80",
|
|
453
|
-
}, {
|
|
454
|
-
urls: "turn:openrelay.metered.ca:443",
|
|
455
|
-
username: "openrelayproject",
|
|
456
|
-
credential: "openrelayproject",
|
|
457
|
-
}, {
|
|
458
|
-
urls: "turn:openrelay.metered.ca:443?transport=tcp",
|
|
459
|
-
username: "openrelayproject",
|
|
460
|
-
credential: "openrelayproject",
|
|
461
|
-
}];
|
|
462
|
-
|
|
463
|
-
this.#connection = new wrtc.RTCPeerConnection({iceServers});
|
|
464
|
-
|
|
465
|
-
this.#connection.onicecandidate = ({ candidate }) => {
|
|
466
|
-
if (candidate) {
|
|
467
|
-
this.address = candidate.address;
|
|
468
|
-
this.port = candidate.port;
|
|
469
|
-
this.protocol = candidate.protocol;
|
|
470
|
-
this.ipFamily = this.address.includes('::') ? 'ipv6': 'ipv4';
|
|
471
|
-
this._sendMessage({candidate});
|
|
472
|
-
}
|
|
473
|
-
};
|
|
474
|
-
// if (this.initiator) this.#connection.onnegotiationneeded = () => {
|
|
475
|
-
// console.log('create offer');
|
|
476
|
-
this.#connection.ondatachannel = (message) => {
|
|
477
|
-
message.channel.onopen = () => {
|
|
478
|
-
this.#connected = true;
|
|
479
|
-
pubsub.publish('peer:connected', this);
|
|
480
|
-
};
|
|
481
|
-
message.channel.onclose = () => this.close.bind(this);
|
|
482
|
-
|
|
483
|
-
message.channel.onmessage = (message) => {
|
|
484
|
-
this._handleMessage(this.id, message);
|
|
485
|
-
};
|
|
486
|
-
this.channel = message.channel;
|
|
487
|
-
};
|
|
488
|
-
if (this.initiator) {
|
|
489
|
-
|
|
490
|
-
this.channel = this.#connection.createDataChannel('messageChannel');
|
|
491
|
-
this.channel.onopen = () => {
|
|
492
|
-
this.#connected = true;
|
|
493
|
-
pubsub.publish('peer:connected', this);
|
|
494
|
-
// this.channel.send('hi')
|
|
495
|
-
};
|
|
496
|
-
this.channel.onclose = () => this.close.bind(this);
|
|
497
|
-
|
|
498
|
-
this.channel.onmessage = (message) => {
|
|
499
|
-
this._handleMessage(this.peerId, message);
|
|
500
|
-
};
|
|
501
|
-
|
|
502
|
-
const offer = await this.#connection.createOffer();
|
|
503
|
-
await this.#connection.setLocalDescription(offer);
|
|
504
|
-
|
|
505
|
-
this._sendMessage({'sdp': this.#connection.localDescription});
|
|
506
|
-
}
|
|
507
|
-
} catch (e) {
|
|
508
|
-
console.log(e);
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
_handleMessage(peerId, message) {
|
|
513
|
-
debug(`incoming message from ${peerId}`);
|
|
514
|
-
|
|
515
|
-
message = JSON.parse(new TextDecoder().decode(message.data));
|
|
516
|
-
// allow sharding (multiple peers share data)
|
|
517
|
-
pubsub.publish('peernet:shard', message);
|
|
518
|
-
const { id } = message;
|
|
519
|
-
|
|
520
|
-
if (!this.#chunksQue[id]) this.#chunksQue[id] = [];
|
|
521
|
-
|
|
522
|
-
if (message.size > this.#chunksQue[id].length || message.size === this.#chunksQue[id].length) {
|
|
523
|
-
for (const value of Object.values(message.chunk)) {
|
|
524
|
-
this.#chunksQue[id].push(value);
|
|
525
|
-
}
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
if (message.size === this.#chunksQue[id].length) {
|
|
529
|
-
let data = new Uint8Array(Object.values(this.#chunksQue[id]));
|
|
530
|
-
delete this.#chunksQue[id];
|
|
531
|
-
data = pako__default["default"].inflate(data);
|
|
532
|
-
pubsub.publish('peer:data', { id, data });
|
|
533
|
-
}
|
|
534
|
-
this.bw.down += message.byteLength || message.length;
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
_sendMessage(message) {
|
|
538
|
-
this.socketClient.send({url: 'signal', params: {
|
|
539
|
-
to: this.to,
|
|
540
|
-
from: this.id,
|
|
541
|
-
channelName: this.options.channelName,
|
|
542
|
-
...message
|
|
543
|
-
}});
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
async _in(message, data) {
|
|
547
|
-
// message = JSON.parse(message);
|
|
548
|
-
if (message.to !== this.id) return
|
|
549
|
-
// if (data.videocall) return this._startStream(true, false); // start video and audio stream
|
|
550
|
-
// if (data.call) return this._startStream(true, true); // start audio stream
|
|
551
|
-
if (message.candidate) {
|
|
552
|
-
debug(`incoming candidate ${this.channelName}`);
|
|
553
|
-
debug(message.candidate.candidate);
|
|
554
|
-
this.remoteAddress = message.candidate.address;
|
|
555
|
-
this.remotePort = message.candidate.port;
|
|
556
|
-
this.remoteProtocol = message.candidate.protocol;
|
|
557
|
-
this.remoteIpFamily = this.remoteAddress?.includes('::') ? 'ipv6': 'ipv4';
|
|
558
|
-
return this.#connection.addIceCandidate(new wrtc.RTCIceCandidate(message.candidate));
|
|
559
|
-
}
|
|
560
|
-
try {
|
|
561
|
-
if (message.sdp) {
|
|
562
|
-
if (message.sdp.type === 'offer') {
|
|
563
|
-
debug(`incoming offer ${this.channelName}`);
|
|
564
|
-
await this.#connection.setRemoteDescription(new wrtc.RTCSessionDescription(message.sdp));
|
|
565
|
-
const answer = await this.#connection.createAnswer();
|
|
566
|
-
await this.#connection.setLocalDescription(answer);
|
|
567
|
-
this._sendMessage({'sdp': this.#connection.localDescription});
|
|
568
|
-
}
|
|
569
|
-
if (message.sdp.type === 'answer') {
|
|
570
|
-
debug(`incoming answer ${this.channelName}`);
|
|
571
|
-
await this.#connection.setRemoteDescription(new wrtc.RTCSessionDescription(message.sdp));
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
} catch (e) {
|
|
575
|
-
console.log(e);
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
|
|
579
|
-
close() {
|
|
580
|
-
debug(`closing ${this.peerId}`);
|
|
581
|
-
this.#connected = false;
|
|
582
|
-
this.channel?.close();
|
|
583
|
-
this.#connection?.close();
|
|
584
|
-
|
|
585
|
-
this.socketClient.pubsub.unsubscribe('signal', this._in);
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
class Client {
|
|
590
|
-
#peerConnection
|
|
591
|
-
#connections = {}
|
|
592
|
-
#stars = {}
|
|
593
|
-
|
|
594
|
-
get connections() {
|
|
595
|
-
return { ...this.#connections }
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
get peers() {
|
|
599
|
-
return Object.entries(this.#connections)
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
constructor(id, identifiers = ['peernet-v0.1.0'], stars = []) {
|
|
603
|
-
this.id = id || Math.random().toString(36).slice(-12);
|
|
604
|
-
if (!Array.isArray(identifiers)) identifiers = [identifiers];
|
|
605
|
-
this.peerJoined = this.peerJoined.bind(this);
|
|
606
|
-
this.peerLeft = this.peerLeft.bind(this);
|
|
607
|
-
this.starLeft = this.starLeft.bind(this);
|
|
608
|
-
this.starJoined = this.starJoined.bind(this);
|
|
609
|
-
|
|
610
|
-
this._init(identifiers, stars);
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
async _init(identifiers, stars = []) {
|
|
614
|
-
if (stars.length === 0) {
|
|
615
|
-
stars.push('wss://star.leofcoin.org');
|
|
616
|
-
}
|
|
617
|
-
this.identifiers = identifiers;
|
|
618
|
-
this.starsConfig = stars;
|
|
619
|
-
// reconnectJob()
|
|
620
|
-
|
|
621
|
-
globalThis.wrtc = await Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require('wrtc')); });
|
|
622
|
-
for (const star of stars) {
|
|
623
|
-
try {
|
|
624
|
-
this.socketClient = await socketRequestClient(star, identifiers[0]);
|
|
625
|
-
const id = await this.socketClient.request({url: 'id', params: {from: this.id}});
|
|
626
|
-
this.socketClient.peerId = id;
|
|
627
|
-
this.#stars[id] = this.socketClient;
|
|
628
|
-
} catch (e) {
|
|
629
|
-
if (stars.indexOf(star) === stars.length -1 && !this.socketClient) throw new Error(`No star available to connect`);
|
|
630
|
-
}
|
|
631
|
-
}
|
|
632
|
-
const peers = await this.socketClient.peernet.join({id: this.id});
|
|
633
|
-
for (const id of peers) {
|
|
634
|
-
if (id !== this.id && !this.#connections[id]) this.#connections[id] = new Peer({channelName: `${id}:${this.id}`, socketClient: this.socketClient, id: this.id, to: id, peerId: id});
|
|
635
|
-
}
|
|
636
|
-
this.setupListeners();
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
setupListeners() {
|
|
640
|
-
this.socketClient.subscribe('peer:joined', this.peerJoined);
|
|
641
|
-
this.socketClient.subscribe('peer:left', this.peerLeft);
|
|
642
|
-
this.socketClient.subscribe('star:left', this.starLeft);
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
starJoined(id) {
|
|
646
|
-
if (this.#stars[id]) {
|
|
647
|
-
this.#stars[id].close();
|
|
648
|
-
delete this.#stars[id];
|
|
649
|
-
}
|
|
650
|
-
console.log(`star ${id} joined`);
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
async starLeft(id) {
|
|
654
|
-
if (this.#stars[id]) {
|
|
655
|
-
this.#stars[id].close();
|
|
656
|
-
delete this.#stars[id];
|
|
657
|
-
}
|
|
658
|
-
if (this.socketClient?.peerId === id) {
|
|
659
|
-
|
|
660
|
-
this.socketClient.unsubscribe('peer:joined', this.peerJoined);
|
|
661
|
-
this.socketClient.unsubscribe('peer:left', this.peerLeft);
|
|
662
|
-
this.socketClient.unsubscribe('star:left', this.starLeft);
|
|
663
|
-
this.socketClient.close();
|
|
664
|
-
this.socketClient = undefined;
|
|
665
|
-
|
|
666
|
-
for (const star of this.starsConfig) {
|
|
667
|
-
try {
|
|
668
|
-
this.socketClient = await socketRequestClient(star, this.identifiers[0]);
|
|
669
|
-
if (!this.socketClient?.client?._connection.connected) return
|
|
670
|
-
const id = await this.socketClient.request({url: 'id', params: {from: this.id}});
|
|
671
|
-
this.#stars[id] = this.socketClient;
|
|
672
|
-
|
|
673
|
-
this.socketClient.peerId = id;
|
|
674
|
-
|
|
675
|
-
const peers = await this.socketClient.peernet.join({id: this.id});
|
|
676
|
-
this.setupListeners();
|
|
677
|
-
for (const id of peers) {
|
|
678
|
-
if (id !== this.id) {
|
|
679
|
-
// close connection
|
|
680
|
-
if (this.#connections[id]) {
|
|
681
|
-
if (this.#connections[id].connected) await this.#connections[id].close();
|
|
682
|
-
delete this.#connections[id];
|
|
683
|
-
}
|
|
684
|
-
// reconnect
|
|
685
|
-
if (id !== this.id) this.#connections[id] = new Peer({channelName: `${id}:${this.id}`, socketClient: this.socketClient, id: this.id, to: id, peerId: id});
|
|
686
|
-
}
|
|
687
|
-
|
|
688
|
-
}
|
|
689
|
-
} catch (e) {
|
|
690
|
-
console.log(e);
|
|
691
|
-
if (this.starsConfig.indexOf(star) === this.starsConfig.length -1 && !this.socketClient) throw new Error(`No star available to connect`);
|
|
692
|
-
}
|
|
693
|
-
}
|
|
694
|
-
}
|
|
695
|
-
debug(`star ${id} left`);
|
|
696
|
-
}
|
|
697
|
-
|
|
698
|
-
peerLeft(peer) {
|
|
699
|
-
const id = peer.peerId || peer;
|
|
700
|
-
if (this.#connections[id]) {
|
|
701
|
-
this.#connections[id].close();
|
|
702
|
-
delete this.#connections[id];
|
|
703
|
-
}
|
|
704
|
-
debug(`peer ${id} left`);
|
|
705
|
-
}
|
|
706
|
-
|
|
707
|
-
peerJoined(peer, signal) {
|
|
708
|
-
const id = peer.peerId || peer;
|
|
709
|
-
if (this.#connections[id]) {
|
|
710
|
-
if (this.#connections[id].connected) this.#connections[id].close();
|
|
711
|
-
delete this.#connections[id];
|
|
712
|
-
}
|
|
713
|
-
// RTCPeerConnection
|
|
714
|
-
this.#connections[id] = new Peer({initiator: true, channelName: `${this.id}:${id}`, socketClient: this.socketClient, id: this.id, to: id, peerId: id});
|
|
715
|
-
debug(`peer ${id} joined`);
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
removePeer(peer) {
|
|
719
|
-
const id = peer.peerId || peer;
|
|
720
|
-
if (this.#connections[id]) {
|
|
721
|
-
this.#connections[id].connected && this.#connections[id].close();
|
|
722
|
-
delete this.#connections[id];
|
|
723
|
-
}
|
|
724
|
-
debug(`peer ${id} removed`);
|
|
725
|
-
}
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
}
|
|
729
|
-
|
|
730
|
-
var proto$5 = `
|
|
731
|
-
// PeernetDataMessage
|
|
732
|
-
message PeernetDataMessage {
|
|
733
|
-
required string hash = 1;
|
|
734
|
-
optional string store = 2;
|
|
735
|
-
}
|
|
736
|
-
`;
|
|
737
|
-
|
|
738
|
-
/**
|
|
739
|
-
* @extends {CodecFormat}
|
|
740
|
-
*/
|
|
741
|
-
class DataMessage extends codecFormatInterface.FormatInterface {
|
|
742
|
-
get keys() {
|
|
743
|
-
return ['hash', 'store']
|
|
744
|
-
}
|
|
745
|
-
/**
|
|
746
|
-
* @param {Buffer|String|Object|DataMessage} data - The data needed to create the DataMessage
|
|
747
|
-
*/
|
|
748
|
-
constructor(data) {
|
|
749
|
-
super(data, protons__default["default"](proto$5).PeernetDataMessage, {name: 'peernet-data'});
|
|
750
|
-
}
|
|
751
|
-
}
|
|
752
|
-
|
|
753
|
-
var proto$4 = `
|
|
754
|
-
// PsMessage
|
|
755
|
-
message PsMessage {
|
|
756
|
-
required bytes data = 1;
|
|
757
|
-
required bytes topic = 2;
|
|
758
|
-
}`;
|
|
759
|
-
|
|
760
|
-
class PsMessage extends codecFormatInterface.FormatInterface {
|
|
761
|
-
get keys() {
|
|
762
|
-
return ['data', 'topic']
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
constructor(buffer) {
|
|
766
|
-
const name = 'peernet-ps';
|
|
767
|
-
super(buffer, protons__default["default"](proto$4).PsMessage, {name});
|
|
768
|
-
}
|
|
769
|
-
}
|
|
770
|
-
|
|
771
|
-
var proto$3 = `
|
|
772
|
-
// PeernetPeerMessage
|
|
773
|
-
message PeernetPeerMessage {
|
|
774
|
-
required string id = 1;
|
|
775
|
-
}
|
|
776
|
-
`;
|
|
777
|
-
|
|
778
|
-
class PeerMessage extends codecFormatInterface.FormatInterface {
|
|
779
|
-
get keys() {
|
|
780
|
-
return ['id']
|
|
781
|
-
}
|
|
782
|
-
|
|
783
|
-
constructor(data) {
|
|
784
|
-
const name = 'peernet-peer';
|
|
785
|
-
super(data, protons__default["default"](proto$3).PeernetPeerMessage, {name});
|
|
786
|
-
}
|
|
787
|
-
}
|
|
788
|
-
|
|
789
|
-
var proto$2 = `
|
|
790
|
-
// PeernetPeerMessageResponse
|
|
791
|
-
message PeernetPeerMessageResponse {
|
|
792
|
-
required string id = 1;
|
|
793
|
-
}
|
|
794
|
-
`;
|
|
795
|
-
|
|
796
|
-
class PeerMessageResponse extends codecFormatInterface.FormatInterface {
|
|
797
|
-
get keys() {
|
|
798
|
-
return ['id']
|
|
799
|
-
}
|
|
800
|
-
|
|
801
|
-
constructor(data) {
|
|
802
|
-
const name = 'peernet-peer-response';
|
|
803
|
-
super(data, protons__default["default"](proto$2).PeernetPeerMessageResponse, {name});
|
|
804
|
-
}
|
|
805
|
-
}
|
|
806
|
-
|
|
807
|
-
var proto$1 = `
|
|
808
|
-
// PeernetDataMessageResponse
|
|
809
|
-
message PeernetDataMessageResponse {
|
|
810
|
-
required string hash = 1;
|
|
811
|
-
required bytes data = 2;
|
|
812
|
-
}
|
|
813
|
-
`;
|
|
814
|
-
|
|
815
|
-
class DataMessageResponse extends codecFormatInterface.FormatInterface {
|
|
816
|
-
get keys() {
|
|
817
|
-
return ['hash', 'data']
|
|
818
|
-
}
|
|
819
|
-
|
|
820
|
-
constructor(data) {
|
|
821
|
-
const name = 'peernet-data-response';
|
|
822
|
-
super(data, protons__default["default"](proto$1).PeernetDataMessageResponse, {name});
|
|
823
|
-
}
|
|
824
|
-
}
|
|
825
|
-
|
|
826
|
-
var proto = `
|
|
827
|
-
message ChatMessage {
|
|
828
|
-
required string value = 1;
|
|
829
|
-
required string author = 2;
|
|
830
|
-
required uint64 timestamp = 3;
|
|
831
|
-
repeated string files = 4;
|
|
832
|
-
}`;
|
|
833
|
-
|
|
834
|
-
class ChatMessage extends codecFormatInterface.FormatInterface {
|
|
835
|
-
get keys() {
|
|
836
|
-
return ['author', 'value', 'timestamp', 'files']
|
|
837
|
-
}
|
|
838
|
-
|
|
839
|
-
constructor(buffer) {
|
|
840
|
-
const name = 'chat-message';
|
|
841
|
-
super(buffer, protons__default["default"](proto).ChatMessage, {name});
|
|
842
|
-
}
|
|
843
|
-
}
|
|
29
|
+
var MultiWallet__default = /*#__PURE__*/_interopDefaultLegacy(MultiWallet);
|
|
844
30
|
|
|
845
31
|
const protoFor = (data) => {
|
|
846
32
|
if (!Buffer.isBuffer(data)) data = Buffer.from(data);
|
|
@@ -917,12 +103,12 @@ class PeerDiscovery {
|
|
|
917
103
|
async discover(peer) {
|
|
918
104
|
let id = this._getPeerId(peer.id);
|
|
919
105
|
if (id) return id
|
|
920
|
-
const data = new peernet.protos['peernet-peer']({id: this.id});
|
|
106
|
+
const data = await new peernet.protos['peernet-peer']({id: this.id});
|
|
921
107
|
const node = await peernet.prepareMessage(peer.id, data.encoded);
|
|
922
108
|
|
|
923
109
|
let response = await peer.request(node.encoded);
|
|
924
|
-
response = protoFor(response);
|
|
925
|
-
response = new peernet.protos['peernet-peer-response'](response.decoded.data);
|
|
110
|
+
response = await protoFor(response);
|
|
111
|
+
response = await new peernet.protos['peernet-peer-response'](response.decoded.data);
|
|
926
112
|
|
|
927
113
|
id = response.decoded.id;
|
|
928
114
|
if (id === this.id) return;
|
|
@@ -953,7 +139,7 @@ class PeerDiscovery {
|
|
|
953
139
|
peernet.peerMap.set(from, connections);
|
|
954
140
|
}
|
|
955
141
|
}
|
|
956
|
-
const data = new peernet.protos['peernet-peer-response']({id: this.id});
|
|
142
|
+
const data = await new peernet.protos['peernet-peer-response']({id: this.id});
|
|
957
143
|
const node = await peernet.prepareMessage(from, data.encoded);
|
|
958
144
|
|
|
959
145
|
peer.write(Buffer.from(JSON.stringify({id, data: node.encoded})));
|
|
@@ -1093,527 +279,6 @@ class DhtEarth {
|
|
|
1093
279
|
}
|
|
1094
280
|
}
|
|
1095
281
|
|
|
1096
|
-
/**
|
|
1097
|
-
* @params {String} network
|
|
1098
|
-
* @return {object} { identity, accounts, config }
|
|
1099
|
-
*/
|
|
1100
|
-
var generateAccount = async network => {
|
|
1101
|
-
let wallet = new MultiWallet__default["default"](network);
|
|
1102
|
-
/**
|
|
1103
|
-
* @type {string}
|
|
1104
|
-
*/
|
|
1105
|
-
const mnemonic = await wallet.generate();
|
|
1106
|
-
|
|
1107
|
-
wallet = new MultiWallet__default["default"](network);
|
|
1108
|
-
await wallet.recover(mnemonic, network);
|
|
1109
|
-
/**
|
|
1110
|
-
* @type {object}
|
|
1111
|
-
*/
|
|
1112
|
-
const account = wallet.account(0);
|
|
1113
|
-
/**
|
|
1114
|
-
* @type {object}
|
|
1115
|
-
*/
|
|
1116
|
-
const external = account.external(0);
|
|
1117
|
-
const internal = account.internal(0);
|
|
1118
|
-
|
|
1119
|
-
return {
|
|
1120
|
-
identity: {
|
|
1121
|
-
mnemonic,
|
|
1122
|
-
// multiWIF: wallet.export(),
|
|
1123
|
-
publicKey: external.publicKey,
|
|
1124
|
-
privateKey: external.privateKey,
|
|
1125
|
-
walletId: external.id
|
|
1126
|
-
},
|
|
1127
|
-
accounts: [['main account', external.address, internal.address]]
|
|
1128
|
-
// config: {
|
|
1129
|
-
// }
|
|
1130
|
-
}
|
|
1131
|
-
};
|
|
1132
|
-
|
|
1133
|
-
var testnets = {
|
|
1134
|
-
'leofcoin:olivia': {
|
|
1135
|
-
messagePrefix: '\u0019Leofcoin Signed Message:',
|
|
1136
|
-
pubKeyHash: 0x73, // o
|
|
1137
|
-
scriptHash: 0x76, // p
|
|
1138
|
-
multiTxHash: 0x8b4125, // omtx
|
|
1139
|
-
payments: {
|
|
1140
|
-
version: 0,
|
|
1141
|
-
unspent: 0x1fa443d7 // ounsp
|
|
1142
|
-
},
|
|
1143
|
-
wif: 0x7D, // s
|
|
1144
|
-
multiCodec: 0x7c4,
|
|
1145
|
-
bip32: { public: 0x13BBF2D5, private: 0x13BBCBC5 }
|
|
1146
|
-
},
|
|
1147
|
-
'bitcoin:testnet': {
|
|
1148
|
-
messagePrefix: '\x18Bitcoin Signed Message:\n',
|
|
1149
|
-
bech32: 'tb',
|
|
1150
|
-
pubKeyHash: 0x6f,
|
|
1151
|
-
scriptHash: 0xc4,
|
|
1152
|
-
wif: 0xef,
|
|
1153
|
-
bip32: {
|
|
1154
|
-
public: 0x043587cf,
|
|
1155
|
-
private: 0x04358394
|
|
1156
|
-
}
|
|
1157
|
-
}
|
|
1158
|
-
|
|
1159
|
-
};
|
|
1160
|
-
|
|
1161
|
-
// https://en.bitcoin.it/wiki/List_of_address_prefixes
|
|
1162
|
-
/**
|
|
1163
|
-
* Main network
|
|
1164
|
-
* @return {messagePrefix, pubKeyHash, scriptHash, wif, bip32}
|
|
1165
|
-
*/
|
|
1166
|
-
const leofcoin = {
|
|
1167
|
-
messagePrefix: '\u0019Leofcoin Signed Message:',
|
|
1168
|
-
pubKeyHash: 0x30, // L
|
|
1169
|
-
scriptHash: 0x37, // P
|
|
1170
|
-
multiTxHash: 0x3adeed, // Lmtx
|
|
1171
|
-
payments: {
|
|
1172
|
-
version: 0,
|
|
1173
|
-
unspent: 0x0d6e0327 // Lunsp
|
|
1174
|
-
},
|
|
1175
|
-
coin_type: 640,
|
|
1176
|
-
wif: 0x3F, // S
|
|
1177
|
-
multiCodec: 0x3c4,
|
|
1178
|
-
bip32: { public: 0x13BBF2D4, private: 0x13BBCBC4 },
|
|
1179
|
-
testnet: testnets['leofcoin:olivia']
|
|
1180
|
-
};
|
|
1181
|
-
|
|
1182
|
-
const bitcoin = {
|
|
1183
|
-
messagePrefix: '\x18Bitcoin Signed Message:\n',
|
|
1184
|
-
bech32: 'bc',
|
|
1185
|
-
pubKeyHash: 0x00,
|
|
1186
|
-
multiCodec: 0x00,
|
|
1187
|
-
scriptHash: 0x05,
|
|
1188
|
-
wif: 0x80,
|
|
1189
|
-
coin_type: 0,
|
|
1190
|
-
bip32: {
|
|
1191
|
-
public: 0x0488b21e, private: 0x0488ade4
|
|
1192
|
-
},
|
|
1193
|
-
testnet: testnets['bitcoin:testnet']
|
|
1194
|
-
};
|
|
1195
|
-
|
|
1196
|
-
const litecoin = {
|
|
1197
|
-
messagePrefix: '\x19Litecoin Signed Message:\n',
|
|
1198
|
-
pubKeyHash: 0x30,
|
|
1199
|
-
scriptHash: 0x32,
|
|
1200
|
-
wif: 0xb0,
|
|
1201
|
-
bip32: {
|
|
1202
|
-
public: 0x019da462,
|
|
1203
|
-
private: 0x019d9cfe
|
|
1204
|
-
}
|
|
1205
|
-
};
|
|
1206
|
-
|
|
1207
|
-
const ethereum = {
|
|
1208
|
-
messagePrefix: '\x19Ethereum Signed Message:\n',
|
|
1209
|
-
pubKeyHash: 0x30,
|
|
1210
|
-
scriptHash: 0x32,
|
|
1211
|
-
bip32: {
|
|
1212
|
-
private: 0x0488ADE4, public: 0x0488B21E
|
|
1213
|
-
},
|
|
1214
|
-
coin_type: 60,
|
|
1215
|
-
wif: 0x45,//E
|
|
1216
|
-
multiCodec: 0x3c5
|
|
1217
|
-
};
|
|
1218
|
-
|
|
1219
|
-
/**
|
|
1220
|
-
* Our & supported networks
|
|
1221
|
-
* @return {leofcoin, olivia}
|
|
1222
|
-
*/
|
|
1223
|
-
var networks = {
|
|
1224
|
-
leofcoin,
|
|
1225
|
-
bitcoin,
|
|
1226
|
-
litecoin,
|
|
1227
|
-
ethereum
|
|
1228
|
-
};
|
|
1229
|
-
|
|
1230
|
-
const fromNetworkString = network => {
|
|
1231
|
-
const parts = network.split(':');
|
|
1232
|
-
network = networks[parts[0]];
|
|
1233
|
-
if (parts[1]) {
|
|
1234
|
-
if (network[parts[1]]) network = network[parts[1]];
|
|
1235
|
-
|
|
1236
|
-
network.coin_type = 1;
|
|
1237
|
-
}
|
|
1238
|
-
return network;
|
|
1239
|
-
};
|
|
1240
|
-
|
|
1241
|
-
// import { createHash } from 'crypto'
|
|
1242
|
-
// import { createHash as _createHash } from './hash'
|
|
1243
|
-
|
|
1244
|
-
const { encode: encode$1, decode: decode$1 } = bs58check__default["default"];
|
|
1245
|
-
class HDWallet {
|
|
1246
|
-
|
|
1247
|
-
get chainCodeBuffer() {
|
|
1248
|
-
return this.ifNotLocked(() => this.hdnode.chainCode)
|
|
1249
|
-
}
|
|
1250
|
-
|
|
1251
|
-
get chainCode() {
|
|
1252
|
-
return this.ifNotLocked(() => this.chainCodeBuffer.toString('hex'))
|
|
1253
|
-
}
|
|
1254
|
-
|
|
1255
|
-
get privateKeyBuffer() {
|
|
1256
|
-
return this.ifNotLocked(() => this.hdnode.privateKey)
|
|
1257
|
-
}
|
|
1258
|
-
|
|
1259
|
-
get privateKey() {
|
|
1260
|
-
return this.ifNotLocked(() => this.privateKeyBuffer.toString('hex'))
|
|
1261
|
-
}
|
|
1262
|
-
|
|
1263
|
-
get publicKeyBuffer() {
|
|
1264
|
-
return this.ifNotLocked(() => this.hdnode.publicKey)
|
|
1265
|
-
}
|
|
1266
|
-
|
|
1267
|
-
get publicKey() {
|
|
1268
|
-
return this.ifNotLocked(() => this.publicKeyBuffer.toString('hex'))
|
|
1269
|
-
}
|
|
1270
|
-
|
|
1271
|
-
get ethereumAddress() {
|
|
1272
|
-
const buffer = ecc__default["default"].pointFromScalar(this.hdnode.__D, false);
|
|
1273
|
-
let hash = createKeccakHash__default["default"]('keccak256').update(buffer.slice(1)).digest();
|
|
1274
|
-
return `0x${hash.slice(-20).toString('hex')}`
|
|
1275
|
-
}
|
|
1276
|
-
|
|
1277
|
-
// async bitcoinAddress() {
|
|
1278
|
-
// const chainCode = this.privateKeyBuffer
|
|
1279
|
-
//
|
|
1280
|
-
// const node = bip32.fromPrivateKey(this.privateKeyBuffer, chainCode, networks['bitcoin'])
|
|
1281
|
-
// let buffer = await _createHash(node.publicKey, 'SHA-256')
|
|
1282
|
-
// buffer = createHash('ripemd160').update(buffer).digest()
|
|
1283
|
-
// // buffer = Buffer.from(`0x00${buffer.toString('hex')}`, 'hex')
|
|
1284
|
-
// // buffer = createHash('sha256').update(buffer).digest()
|
|
1285
|
-
// // const mainHash = buffer
|
|
1286
|
-
// // buffer = createHash('sha256').update(buffer).digest()
|
|
1287
|
-
// // const checksum = buffer.toString('hex').substring(0, 8)
|
|
1288
|
-
// // return base58.encode(Buffer.concat([mainHash, Buffer.from(checksum, 'hex')]))
|
|
1289
|
-
// const payload = Buffer.allocUnsafe(21)
|
|
1290
|
-
// payload.writeUInt8(networks['bitcoin'].pubKeyHash, 0)
|
|
1291
|
-
// buffer.copy(payload, 1)
|
|
1292
|
-
//
|
|
1293
|
-
// return encode(payload)
|
|
1294
|
-
// }
|
|
1295
|
-
|
|
1296
|
-
get leofcoinAddress() {
|
|
1297
|
-
return encode$1(this.neutered.publicKeyBuffer)
|
|
1298
|
-
}
|
|
1299
|
-
|
|
1300
|
-
get address() {
|
|
1301
|
-
return this.getAddressForCoin()
|
|
1302
|
-
}
|
|
1303
|
-
|
|
1304
|
-
getAddressForCoin(coin_type) {
|
|
1305
|
-
if (!coin_type) coin_type = this.hdnode.network.coin_type;
|
|
1306
|
-
if (coin_type === 1) {
|
|
1307
|
-
if (this.networkName?.split(':')[0] === 'ethereum') coin_type = 60;
|
|
1308
|
-
if (this.networkName?.split(':')[0] === 'leofcoin') coin_type = 640;
|
|
1309
|
-
}
|
|
1310
|
-
// if (coin_type === 0) return this.bitcoinAddress
|
|
1311
|
-
if (coin_type === 60) return this.ethereumAddress
|
|
1312
|
-
if (coin_type === 640) return this.leofcoinAddress
|
|
1313
|
-
}
|
|
1314
|
-
|
|
1315
|
-
get accountAddress() {
|
|
1316
|
-
return this.ifNotLocked(() => encode$1(this.hdnode.publicKeyBuffer))
|
|
1317
|
-
}
|
|
1318
|
-
|
|
1319
|
-
get isTestnet() {
|
|
1320
|
-
if (typeof network === 'string')
|
|
1321
|
-
this.hdnode.network = fromNetworkString(network);
|
|
1322
|
-
|
|
1323
|
-
return Boolean(this.hdnode.network.coin_type === 1)
|
|
1324
|
-
}
|
|
1325
|
-
|
|
1326
|
-
constructor(network, hdnode) {
|
|
1327
|
-
if (typeof network === 'string') {
|
|
1328
|
-
this.networkName = network;
|
|
1329
|
-
this.network = fromNetworkString(network);
|
|
1330
|
-
} else if (typeof network === 'object')
|
|
1331
|
-
this.network = network;
|
|
1332
|
-
|
|
1333
|
-
if (hdnode) this.defineHDNode(hdnode);
|
|
1334
|
-
}
|
|
1335
|
-
|
|
1336
|
-
ifNotLocked(fn, params) {
|
|
1337
|
-
if (!this.locked) return fn(params);
|
|
1338
|
-
return null
|
|
1339
|
-
}
|
|
1340
|
-
|
|
1341
|
-
defineHDNode(value) {
|
|
1342
|
-
Object.defineProperty(this, 'hdnode', {
|
|
1343
|
-
configurable: false,
|
|
1344
|
-
writable: false,
|
|
1345
|
-
value: value
|
|
1346
|
-
});
|
|
1347
|
-
}
|
|
1348
|
-
|
|
1349
|
-
validateNetwork(network) {
|
|
1350
|
-
if (!network && !this.network) return console.error(`expected network to be defined`);
|
|
1351
|
-
if (!network && this.network) network = this.network;
|
|
1352
|
-
if (typeof network === 'string') network = fromNetworkString(network);
|
|
1353
|
-
if (typeof network !== 'object') return console.error('network not found');
|
|
1354
|
-
return network;
|
|
1355
|
-
}
|
|
1356
|
-
|
|
1357
|
-
async generate(password, network) {
|
|
1358
|
-
network = this.validateNetwork(network);
|
|
1359
|
-
const mnemonic = new Mnemonic__default["default"]().generate();
|
|
1360
|
-
const seed = new Mnemonic__default["default"]().seedFromMnemonic(mnemonic, password);
|
|
1361
|
-
this.defineHDNode(bip32__namespace.fromSeed(seed, network));
|
|
1362
|
-
return mnemonic;
|
|
1363
|
-
}
|
|
1364
|
-
|
|
1365
|
-
/**
|
|
1366
|
-
* recover using mnemonic (recovery word list)
|
|
1367
|
-
*/
|
|
1368
|
-
async recover(mnemonic, password, network) {
|
|
1369
|
-
network = this.validateNetwork(network, password);
|
|
1370
|
-
const seed = new Mnemonic__default["default"]().seedFromMnemonic(mnemonic, password);
|
|
1371
|
-
this.defineHDNode(bip32__namespace.fromSeed(seed, network));
|
|
1372
|
-
}
|
|
1373
|
-
|
|
1374
|
-
load(base58, network) {
|
|
1375
|
-
network = this.validateNetwork(network);
|
|
1376
|
-
this.defineHDNode(bip32__namespace.fromBase58(base58, network));
|
|
1377
|
-
}
|
|
1378
|
-
|
|
1379
|
-
save() {
|
|
1380
|
-
return this.hdnode.toBase58();
|
|
1381
|
-
}
|
|
1382
|
-
|
|
1383
|
-
fromAddress(address, chainCode, network) {
|
|
1384
|
-
network = this.validateNetwork(network);
|
|
1385
|
-
// if (network.coin_type === 60) {
|
|
1386
|
-
// address = Buffer.from(address, 'hex')
|
|
1387
|
-
// } else {
|
|
1388
|
-
address = decode$1(address);
|
|
1389
|
-
// }
|
|
1390
|
-
|
|
1391
|
-
if (!chainCode || chainCode && !Buffer.isBuffer(chainCode)) chainCode = address.slice(1);
|
|
1392
|
-
this.defineHDNode(bip32__namespace.fromPublicKey(address, chainCode, network));
|
|
1393
|
-
}
|
|
1394
|
-
|
|
1395
|
-
fromPublicKey(hex, chainCode, network) {
|
|
1396
|
-
network = this.validateNetwork(network);
|
|
1397
|
-
if (!Buffer.isBuffer(hex)) hex = Buffer.from(hex, 'hex');
|
|
1398
|
-
if (!chainCode || chainCode && !Buffer.isBuffer(chainCode)) chainCode = hex.slice(1);
|
|
1399
|
-
this.defineHDNode(bip32__namespace.fromPublicKey(hex, chainCode, network));
|
|
1400
|
-
}
|
|
1401
|
-
}
|
|
1402
|
-
|
|
1403
|
-
const { subtle } = require('crypto').webcrypto;
|
|
1404
|
-
|
|
1405
|
-
const generateAesKey = async (length = 256) => {
|
|
1406
|
-
const key = await subtle.generateKey({
|
|
1407
|
-
name: 'AES-CBC',
|
|
1408
|
-
length
|
|
1409
|
-
}, true, ['encrypt', 'decrypt']);
|
|
1410
|
-
|
|
1411
|
-
return key;
|
|
1412
|
-
};
|
|
1413
|
-
|
|
1414
|
-
const importAesKey = async (exported, format = 'raw', length = 256) => {
|
|
1415
|
-
return await subtle.importKey(format, exported, {
|
|
1416
|
-
name: 'AES-CBC',
|
|
1417
|
-
length
|
|
1418
|
-
}, true, ['encrypt', 'decrypt'])
|
|
1419
|
-
};
|
|
1420
|
-
|
|
1421
|
-
const exportAesKey = async (key, format = 'raw') => {
|
|
1422
|
-
return await subtle.exportKey(format, key)
|
|
1423
|
-
};
|
|
1424
|
-
|
|
1425
|
-
const encryptAes = async (uint8Array, key, iv) => subtle.encrypt({
|
|
1426
|
-
name: 'AES-CBC',
|
|
1427
|
-
iv,
|
|
1428
|
-
}, key, uint8Array);
|
|
1429
|
-
|
|
1430
|
-
const uint8ArrayToHex = uint8Array =>
|
|
1431
|
-
[...uint8Array].map(x => x.toString(16).padStart(2, '0')).join('');
|
|
1432
|
-
|
|
1433
|
-
const arrayBufferToHex = arrayBuffer =>
|
|
1434
|
-
uint8ArrayToHex(new Uint8Array(arrayBuffer));
|
|
1435
|
-
|
|
1436
|
-
const hexToUint8Array = hex =>
|
|
1437
|
-
new Uint8Array(hex.match(/[\da-f]{2}/gi).map(x => parseInt(x, 16)));
|
|
1438
|
-
|
|
1439
|
-
const encrypt = async string => {
|
|
1440
|
-
const ec = new TextEncoder();
|
|
1441
|
-
const key = await generateAesKey();
|
|
1442
|
-
const iv = await randombytes__default["default"](16);
|
|
1443
|
-
|
|
1444
|
-
const ciphertext = await encryptAes(ec.encode(string), key, iv);
|
|
1445
|
-
const exported = await exportAesKey(key);
|
|
1446
|
-
|
|
1447
|
-
return {
|
|
1448
|
-
key: arrayBufferToHex(exported),
|
|
1449
|
-
iv: iv.toString('hex'),
|
|
1450
|
-
cipher: arrayBufferToHex(ciphertext)
|
|
1451
|
-
}
|
|
1452
|
-
};
|
|
1453
|
-
|
|
1454
|
-
const decrypt = async (cipher, key, iv) => {
|
|
1455
|
-
if (!key.type) key = await importAesKey(hexToUint8Array(key));
|
|
1456
|
-
cipher = new Uint8Array(hexToUint8Array(cipher));
|
|
1457
|
-
iv = new Uint8Array(hexToUint8Array(iv));
|
|
1458
|
-
|
|
1459
|
-
const dec = new TextDecoder();
|
|
1460
|
-
const plaintext = await subtle.decrypt({
|
|
1461
|
-
name: 'AES-CBC',
|
|
1462
|
-
iv,
|
|
1463
|
-
}, key, cipher);
|
|
1464
|
-
|
|
1465
|
-
return dec.decode(plaintext);
|
|
1466
|
-
};
|
|
1467
|
-
|
|
1468
|
-
const { encode, decode } = bs58check__namespace;
|
|
1469
|
-
|
|
1470
|
-
// TODO: multihash addresses
|
|
1471
|
-
class HDAccount {
|
|
1472
|
-
/**
|
|
1473
|
-
* @param {number} depth - acount depth
|
|
1474
|
-
*/
|
|
1475
|
-
constructor(node, depth = 0) {
|
|
1476
|
-
this.node = node;
|
|
1477
|
-
this.depth = depth;
|
|
1478
|
-
this._prefix = `m/44'/${node.network.coin_type}'/${depth}'/`;
|
|
1479
|
-
}
|
|
1480
|
-
|
|
1481
|
-
/**
|
|
1482
|
-
* @param {number} index - address index
|
|
1483
|
-
*/
|
|
1484
|
-
internal(index = 0) {
|
|
1485
|
-
return this.node.derivePath(`${this._prefix}1/${index}`)
|
|
1486
|
-
}
|
|
1487
|
-
|
|
1488
|
-
/**
|
|
1489
|
-
* @param {number} index - address index
|
|
1490
|
-
*/
|
|
1491
|
-
external(index = 0) {
|
|
1492
|
-
return this.node.derivePath(`${this._prefix}0/${index}`)
|
|
1493
|
-
}
|
|
1494
|
-
}
|
|
1495
|
-
|
|
1496
|
-
class MultiWallet extends HDWallet {
|
|
1497
|
-
constructor(network, hdnode) {
|
|
1498
|
-
super(network, hdnode);
|
|
1499
|
-
this.multiCodec = this.network.multiCodec;
|
|
1500
|
-
this.version = 0x00;
|
|
1501
|
-
}
|
|
1502
|
-
|
|
1503
|
-
get id() {
|
|
1504
|
-
const buffer = Buffer.concat([
|
|
1505
|
-
Buffer.from(varint__default["default"].encode(this.multiCodec)),
|
|
1506
|
-
Buffer.from(this.account(0).node.neutered.publicKey, 'hex')
|
|
1507
|
-
]);
|
|
1508
|
-
return encode(buffer)
|
|
1509
|
-
}
|
|
1510
|
-
|
|
1511
|
-
get multiWIF() {
|
|
1512
|
-
return this.ifNotLocked(() => this.encode())
|
|
1513
|
-
}
|
|
1514
|
-
|
|
1515
|
-
get neutered() {
|
|
1516
|
-
const neutered = this.ifNotLocked(() => new MultiWallet(this.networkName, this.hdnode.neutered()));
|
|
1517
|
-
if (neutered) this._neutered = neutered;
|
|
1518
|
-
return this._neutered
|
|
1519
|
-
}
|
|
1520
|
-
|
|
1521
|
-
fromId(id) {
|
|
1522
|
-
let buffer = decode(id);
|
|
1523
|
-
varint__default["default"].decode(buffer);
|
|
1524
|
-
buffer = buffer.slice(varint__default["default"].decode.bytes);
|
|
1525
|
-
this.fromPublicKey(buffer, null, this.networkName);
|
|
1526
|
-
}
|
|
1527
|
-
|
|
1528
|
-
async lock(multiWIF) {
|
|
1529
|
-
if (!multiWIF) multiWIF = this.multiWIF;
|
|
1530
|
-
this.encrypted = await encrypt(multiWIF.toString('hex'));
|
|
1531
|
-
this.locked = true;
|
|
1532
|
-
return this.encrypted
|
|
1533
|
-
}
|
|
1534
|
-
|
|
1535
|
-
async unlock({key, iv, cipher}) {
|
|
1536
|
-
const decrypted = await decrypt(cipher, key, iv);
|
|
1537
|
-
this.import(decrypted);
|
|
1538
|
-
this.locked = false;
|
|
1539
|
-
}
|
|
1540
|
-
|
|
1541
|
-
export() {
|
|
1542
|
-
return this.encode();
|
|
1543
|
-
}
|
|
1544
|
-
|
|
1545
|
-
/**
|
|
1546
|
-
* encodes the multiWIF and loads wallet from bs58
|
|
1547
|
-
*
|
|
1548
|
-
* @param {multiWIF} multiWIF - note a multiWIF is not the same as a wif
|
|
1549
|
-
*/
|
|
1550
|
-
import(multiWIF) {
|
|
1551
|
-
const { bs58, version, multiCodec } = this.decode(multiWIF);
|
|
1552
|
-
this.network = Object.values(networks).reduce((p, c) => {
|
|
1553
|
-
if (c.multiCodec===multiCodec) return c
|
|
1554
|
-
else if (c.testnet && c.testnet.multiCodec === multiCodec) return c.testnet
|
|
1555
|
-
else return p
|
|
1556
|
-
}, networks['leofcoin']);
|
|
1557
|
-
this.load(bs58, this.networkName);
|
|
1558
|
-
}
|
|
1559
|
-
|
|
1560
|
-
/**
|
|
1561
|
-
* @return base58Check encoded string
|
|
1562
|
-
*/
|
|
1563
|
-
encode() {
|
|
1564
|
-
const buffer = Buffer.concat([
|
|
1565
|
-
Buffer.from(varint__default["default"].encode(this.version)),
|
|
1566
|
-
Buffer.from(varint__default["default"].encode(this.multiCodec)),
|
|
1567
|
-
decode(this.save())
|
|
1568
|
-
]);
|
|
1569
|
-
return encode(buffer);
|
|
1570
|
-
}
|
|
1571
|
-
|
|
1572
|
-
decode(bs58) {
|
|
1573
|
-
let buffer = decode(bs58);
|
|
1574
|
-
const version = varint__default["default"].decode(buffer);
|
|
1575
|
-
buffer = buffer.slice(varint__default["default"].decode.bytes);
|
|
1576
|
-
const multiCodec = varint__default["default"].decode(buffer);
|
|
1577
|
-
buffer = buffer.slice(varint__default["default"].decode.bytes);
|
|
1578
|
-
bs58 = encode(buffer);
|
|
1579
|
-
if (version !== this.version) throw TypeError('Invalid version');
|
|
1580
|
-
if (this.multiCodec !== multiCodec) throw TypeError('Invalid multiCodec');
|
|
1581
|
-
return { version, multiCodec, bs58 };
|
|
1582
|
-
}
|
|
1583
|
-
|
|
1584
|
-
sign(hash) {
|
|
1585
|
-
return new MultiSignature__default["default"](this.version, this.network.multiCodec)
|
|
1586
|
-
.sign(hash, this.privateKeyBuffer);
|
|
1587
|
-
|
|
1588
|
-
}
|
|
1589
|
-
|
|
1590
|
-
verify(multiSignature, hash) {
|
|
1591
|
-
return new MultiSignature__default["default"](this.version, this.network.multiCodec)
|
|
1592
|
-
.verify(multiSignature, hash, this.publicKeyBuffer)
|
|
1593
|
-
}
|
|
1594
|
-
|
|
1595
|
-
/**
|
|
1596
|
-
* @param {number} account - account to return chain for
|
|
1597
|
-
* @return { internal(addressIndex), external(addressIndex) }
|
|
1598
|
-
*/
|
|
1599
|
-
account(index) {
|
|
1600
|
-
return new HDAccount(new MultiWallet(this.networkName, this.hdnode), index);
|
|
1601
|
-
}
|
|
1602
|
-
|
|
1603
|
-
/**
|
|
1604
|
-
* m / purpose' / coin_type' / account' / change / aadress_index
|
|
1605
|
-
*
|
|
1606
|
-
* see https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
|
|
1607
|
-
*/
|
|
1608
|
-
derivePath(path) {
|
|
1609
|
-
return new MultiWallet(this.networkName, this.hdnode.derivePath(path))
|
|
1610
|
-
}
|
|
1611
|
-
|
|
1612
|
-
derive(index) {
|
|
1613
|
-
return new MultiWallet(this.networkName, this.hdnode.derive(index));
|
|
1614
|
-
}
|
|
1615
|
-
}
|
|
1616
|
-
|
|
1617
282
|
class MessageHandler {
|
|
1618
283
|
constructor(network) {
|
|
1619
284
|
this.network = network;
|
|
@@ -1632,7 +297,7 @@ class MessageHandler {
|
|
|
1632
297
|
const hasher = new codecFormatInterface.CodecHash(message, {name: 'peernet-message'});
|
|
1633
298
|
let identity = await walletStore.get('identity');
|
|
1634
299
|
identity = JSON.parse(new TextDecoder().decode(identity));
|
|
1635
|
-
const wallet = new
|
|
300
|
+
const wallet = new MultiWallet__default["default"](this.network);
|
|
1636
301
|
wallet.recover(identity.mnemonic);
|
|
1637
302
|
return wallet.sign(Buffer.from(hasher.hash).slice(0, 32))
|
|
1638
303
|
}
|
|
@@ -1652,7 +317,7 @@ class MessageHandler {
|
|
|
1652
317
|
data,
|
|
1653
318
|
};
|
|
1654
319
|
const signature = await this.hashAndSignMessage(message);
|
|
1655
|
-
const node = new
|
|
320
|
+
const node = await new globalThis.peernet.protos['peernet-message']({
|
|
1656
321
|
...message,
|
|
1657
322
|
signature,
|
|
1658
323
|
});
|
|
@@ -1666,8 +331,8 @@ const dataHandler = async message => {
|
|
|
1666
331
|
|
|
1667
332
|
const {data, id} = message;
|
|
1668
333
|
|
|
1669
|
-
message = protoFor(data);
|
|
1670
|
-
const proto = protoFor(message.decoded.data);
|
|
334
|
+
message = await protoFor(data);
|
|
335
|
+
const proto = await protoFor(message.decoded.data);
|
|
1671
336
|
const from = message.decoded.from;
|
|
1672
337
|
|
|
1673
338
|
peernet._protoHandler({id, proto}, peernet.client.connections[from], from);
|
|
@@ -1733,6 +398,14 @@ class Peernet {
|
|
|
1733
398
|
return ['account', 'wallet', 'block', 'transaction', 'chain', 'data', 'message']
|
|
1734
399
|
}
|
|
1735
400
|
|
|
401
|
+
get protos() {
|
|
402
|
+
return globalThis.peernet.protos
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
get codecs() {
|
|
406
|
+
return codecFormatInterface.codecs
|
|
407
|
+
}
|
|
408
|
+
|
|
1736
409
|
addProto(name, proto) {
|
|
1737
410
|
if (!this.protos[name]) this.protos[name] = proto;
|
|
1738
411
|
}
|
|
@@ -1742,6 +415,10 @@ class Peernet {
|
|
|
1742
415
|
}
|
|
1743
416
|
|
|
1744
417
|
async addStore(name, prefix, root, isPrivate = true) {
|
|
418
|
+
if (!globalThis.LeofcoinStorage) {
|
|
419
|
+
const importee = await Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require(/* webpackChunkName: "storage" */ '@leofcoin/storage')); });
|
|
420
|
+
globalThis.LeofcoinStorage = importee.default;
|
|
421
|
+
}
|
|
1745
422
|
if (name === 'block' || name === 'transaction' || name === 'chain' ||
|
|
1746
423
|
name === 'data' || name === 'message') isPrivate = false;
|
|
1747
424
|
|
|
@@ -1749,7 +426,7 @@ class Peernet {
|
|
|
1749
426
|
if (this.hasDaemon) {
|
|
1750
427
|
Storage = LeofcoinStorageClient;
|
|
1751
428
|
} else {
|
|
1752
|
-
Storage =
|
|
429
|
+
Storage = LeofcoinStorage;
|
|
1753
430
|
}
|
|
1754
431
|
globalThis[`${name}Store`] = globalThis[`${name}Store`] ||
|
|
1755
432
|
await new Storage(name, root);
|
|
@@ -1814,6 +491,20 @@ class Peernet {
|
|
|
1814
491
|
this.storePrefix = options.storePrefix;
|
|
1815
492
|
this.root = options.root;
|
|
1816
493
|
|
|
494
|
+
const {
|
|
495
|
+
RequestMessage,
|
|
496
|
+
ResponseMessage,
|
|
497
|
+
PeerMessage,
|
|
498
|
+
PeerMessageResponse,
|
|
499
|
+
PeernetMessage,
|
|
500
|
+
DHTMessage,
|
|
501
|
+
DHTMessageResponse,
|
|
502
|
+
DataMessage,
|
|
503
|
+
DataMessageResponse,
|
|
504
|
+
PsMessage,
|
|
505
|
+
ChatMessage
|
|
506
|
+
} = await Promise.resolve().then(function () { return require(/* webpackChunkName: "messages" */ './messages-bcb02ee9.js'); });
|
|
507
|
+
|
|
1817
508
|
/**
|
|
1818
509
|
* proto Object containing protos
|
|
1819
510
|
* @type {Object}
|
|
@@ -1823,30 +514,26 @@ class Peernet {
|
|
|
1823
514
|
* @property {DataMessage} protos[peernet-data] messageNode
|
|
1824
515
|
* @property {DataMessageResponse} protos[peernet-data-response] messageNode
|
|
1825
516
|
*/
|
|
517
|
+
|
|
1826
518
|
globalThis.peernet.protos = {
|
|
1827
|
-
'peernet-request':
|
|
1828
|
-
'peernet-response':
|
|
519
|
+
'peernet-request': RequestMessage,
|
|
520
|
+
'peernet-response': ResponseMessage,
|
|
1829
521
|
'peernet-peer': PeerMessage,
|
|
1830
522
|
'peernet-peer-response': PeerMessageResponse,
|
|
1831
|
-
'peernet-message':
|
|
1832
|
-
'peernet-dht':
|
|
1833
|
-
'peernet-dht-response':
|
|
523
|
+
'peernet-message': PeernetMessage,
|
|
524
|
+
'peernet-dht': DHTMessage,
|
|
525
|
+
'peernet-dht-response': DHTMessageResponse,
|
|
1834
526
|
'peernet-data': DataMessage,
|
|
1835
527
|
'peernet-data-response': DataMessageResponse,
|
|
1836
528
|
'peernet-ps': PsMessage,
|
|
1837
529
|
'chat-message': ChatMessage,
|
|
1838
530
|
};
|
|
1839
531
|
|
|
1840
|
-
this.protos = globalThis.peernet.protos;
|
|
1841
|
-
this.codecs = codecFormatInterface.codecs;
|
|
1842
|
-
|
|
1843
532
|
this._messageHandler = new MessageHandler(this.network);
|
|
1844
533
|
|
|
1845
534
|
const {daemon, environment} = await target();
|
|
1846
535
|
this.hasDaemon = daemon;
|
|
1847
536
|
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
537
|
for (const store of this.defaultStores) {
|
|
1851
538
|
await this.addStore(store, options.storePrefix, options.root);
|
|
1852
539
|
}
|
|
@@ -1866,6 +553,9 @@ class Peernet {
|
|
|
1866
553
|
}
|
|
1867
554
|
} catch (e) {
|
|
1868
555
|
if (e.code === 'ERR_NOT_FOUND') {
|
|
556
|
+
|
|
557
|
+
const importee = await Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require(/* webpackChunkName: "generate-account" */ '@leofcoin/generate-account')); });
|
|
558
|
+
const generateAccount = importee.default;
|
|
1869
559
|
const {identity, accounts, config} = await generateAccount(this.network);
|
|
1870
560
|
walletStore.put('version', new TextEncoder().encode(1));
|
|
1871
561
|
walletStore.put('accounts', new TextEncoder().encode(JSON.stringify(accounts)));
|
|
@@ -1898,11 +588,13 @@ class Peernet {
|
|
|
1898
588
|
*/
|
|
1899
589
|
pubsub.subscribe('peer:data', dataHandler);
|
|
1900
590
|
|
|
591
|
+
|
|
592
|
+
const importee = await Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require(/* webpackChunkName: "peernet-swarm" */ '@leofcoin/peernet-swarm')); });
|
|
1901
593
|
/**
|
|
1902
594
|
* @access public
|
|
1903
595
|
* @type {PeernetClient}
|
|
1904
596
|
*/
|
|
1905
|
-
this.client = new
|
|
597
|
+
this.client = new importee.default(this.id);
|
|
1906
598
|
if (globalThis.onbeforeunload) {
|
|
1907
599
|
globalThis.addEventListener('beforeunload', async () => this.client.close());
|
|
1908
600
|
}
|
|
@@ -1942,7 +634,7 @@ class Peernet {
|
|
|
1942
634
|
if (store.private) has = false;
|
|
1943
635
|
else has = await store.has(hash);
|
|
1944
636
|
}
|
|
1945
|
-
const data = new
|
|
637
|
+
const data = await new this.protos['peernet-dht-response']({hash, has});
|
|
1946
638
|
const node = await this.prepareMessage(from, data.encoded);
|
|
1947
639
|
|
|
1948
640
|
this.sendMessage(peer, id, node.encoded);
|
|
@@ -1958,7 +650,7 @@ class Peernet {
|
|
|
1958
650
|
data = await store.get(hash);
|
|
1959
651
|
|
|
1960
652
|
if (data) {
|
|
1961
|
-
data = new
|
|
653
|
+
data = await new this.protos['peernet-data-response']({hash, data});
|
|
1962
654
|
|
|
1963
655
|
const node = await this.prepareMessage(from, data.encoded);
|
|
1964
656
|
this.sendMessage(peer, id, node.encoded);
|
|
@@ -1985,16 +677,16 @@ class Peernet {
|
|
|
1985
677
|
*/
|
|
1986
678
|
async walk(hash) {
|
|
1987
679
|
if (!hash) throw new Error('hash expected, received undefined')
|
|
1988
|
-
const data = new dht({hash});
|
|
680
|
+
const data = await new this.protos['peernet-dht']({hash});
|
|
1989
681
|
this.client.id;
|
|
1990
682
|
const walk = async peer => {
|
|
1991
683
|
const node = await this.prepareMessage(peer.peerId, data.encoded);
|
|
1992
684
|
let result = await peer.request(node.encoded);
|
|
1993
685
|
result = new Uint8Array(Object.values(result));
|
|
1994
|
-
let proto = protoFor(result);
|
|
686
|
+
let proto = await protoFor(result);
|
|
1995
687
|
if (proto.name !== 'peernet-message') throw encapsulatedError()
|
|
1996
688
|
const from = proto.decoded.from;
|
|
1997
|
-
proto = protoFor(proto.decoded.data);
|
|
689
|
+
proto = await protoFor(proto.decoded.data);
|
|
1998
690
|
if (proto.name !== 'peernet-dht-response') throw dhtError(proto.name)
|
|
1999
691
|
|
|
2000
692
|
// TODO: give ip and port (just used for location)
|
|
@@ -2093,7 +785,7 @@ class Peernet {
|
|
|
2093
785
|
if (peer.peerId === id) return peer
|
|
2094
786
|
});
|
|
2095
787
|
|
|
2096
|
-
let data = new
|
|
788
|
+
let data = await new this.protos['peernet-data']({hash, store: store?.name ? store?.name : store});
|
|
2097
789
|
|
|
2098
790
|
const node = await this.prepareMessage(id, data.encoded);
|
|
2099
791
|
if (closest[0]) data = await closest[0].request(node.encoded);
|
|
@@ -2104,8 +796,8 @@ class Peernet {
|
|
|
2104
796
|
if (closest[0]) data = await closest[0].request(node.encoded);
|
|
2105
797
|
}
|
|
2106
798
|
data = new Uint8Array(Object.values(data));
|
|
2107
|
-
let proto = protoFor(data);
|
|
2108
|
-
proto = protoFor(proto.decoded.data);
|
|
799
|
+
let proto = await protoFor(data);
|
|
800
|
+
proto = await protoFor(proto.decoded.data);
|
|
2109
801
|
// TODO: store data automaticly or not
|
|
2110
802
|
return proto.decoded.data
|
|
2111
803
|
|
|
@@ -2238,7 +930,7 @@ class Peernet {
|
|
|
2238
930
|
if (topic instanceof Uint8Array === false) topic = new TextEncoder().encode(topic);
|
|
2239
931
|
if (data instanceof Uint8Array === false) data = new TextEncoder().encode(JSON.stringify(data));
|
|
2240
932
|
const id = Math.random().toString(36).slice(-12);
|
|
2241
|
-
data = new
|
|
933
|
+
data = await new this.protos['peernet-ps']({data, topic});
|
|
2242
934
|
for (const peer of this.connections) {
|
|
2243
935
|
if (peer.peerId !== this.peerId) {
|
|
2244
936
|
const node = await this.prepareMessage(peer.peerId, data.encoded);
|
|
@@ -2249,7 +941,7 @@ class Peernet {
|
|
|
2249
941
|
}
|
|
2250
942
|
|
|
2251
943
|
createHash(data, name) {
|
|
2252
|
-
return new
|
|
944
|
+
return new CodeHash(data, {name})
|
|
2253
945
|
}
|
|
2254
946
|
|
|
2255
947
|
/**
|