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