@leofcoin/peernet 0.12.1 → 0.13.0
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 +404 -0
- package/dist/browser/pako.js +6731 -0
- package/dist/browser/peernet-swarm.js +836 -0
- package/dist/browser/peernet.js +8375 -51506
- package/dist/browser/{160.peernet.js → protons.js} +58 -38
- package/dist/browser/storage.js +12 -0
- package/dist/browser/wrtc.js +28 -0
- package/dist/commonjs/messages-f46a3ca1.js +194 -0
- package/dist/commonjs/peernet.js +120 -1381
- package/dist/commonjs/{peernet-message.js → peernet2.js} +0 -0
- package/dist/module/messages-bce1b91d.js +302 -0
- package/dist/module/peernet.js +111 -1484
- 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/file.js +21 -0
- package/src/messages/{peernet-message.js → peernet.js} +0 -0
- package/src/messages.js +13 -0
- package/src/peernet.js +110 -28
- package/src/proto/file.proto.js +14 -0
- package/test.js +43 -31
- package/webpack.config.js +6 -3
package/dist/commonjs/peernet.js
CHANGED
|
@@ -1,24 +1,11 @@
|
|
|
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
|
-
|
|
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');
|
|
8
|
+
require('path');
|
|
22
9
|
|
|
23
10
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
24
11
|
|
|
@@ -40,829 +27,9 @@ function _interopNamespace(e) {
|
|
|
40
27
|
return Object.freeze(n);
|
|
41
28
|
}
|
|
42
29
|
|
|
43
|
-
var
|
|
44
|
-
var LeofcoinStorage__default = /*#__PURE__*/_interopDefaultLegacy(LeofcoinStorage);
|
|
30
|
+
var PubSub__default = /*#__PURE__*/_interopDefaultLegacy(PubSub);
|
|
45
31
|
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
|
-
}
|
|
32
|
+
var MultiWallet__default = /*#__PURE__*/_interopDefaultLegacy(MultiWallet);
|
|
866
33
|
|
|
867
34
|
const protoFor = (data) => {
|
|
868
35
|
if (!Buffer.isBuffer(data)) data = Buffer.from(data);
|
|
@@ -1115,527 +282,6 @@ class DhtEarth {
|
|
|
1115
282
|
}
|
|
1116
283
|
}
|
|
1117
284
|
|
|
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
285
|
class MessageHandler {
|
|
1640
286
|
constructor(network) {
|
|
1641
287
|
this.network = network;
|
|
@@ -1654,7 +300,7 @@ class MessageHandler {
|
|
|
1654
300
|
const hasher = new codecFormatInterface.CodecHash(message, {name: 'peernet-message'});
|
|
1655
301
|
let identity = await walletStore.get('identity');
|
|
1656
302
|
identity = JSON.parse(new TextDecoder().decode(identity));
|
|
1657
|
-
const wallet = new
|
|
303
|
+
const wallet = new MultiWallet__default["default"](this.network);
|
|
1658
304
|
wallet.recover(identity.mnemonic);
|
|
1659
305
|
return wallet.sign(Buffer.from(hasher.hash).slice(0, 32))
|
|
1660
306
|
}
|
|
@@ -1674,7 +320,7 @@ class MessageHandler {
|
|
|
1674
320
|
data,
|
|
1675
321
|
};
|
|
1676
322
|
const signature = await this.hashAndSignMessage(message);
|
|
1677
|
-
const node = await new
|
|
323
|
+
const node = await new globalThis.peernet.protos['peernet-message']({
|
|
1678
324
|
...message,
|
|
1679
325
|
signature,
|
|
1680
326
|
});
|
|
@@ -1709,7 +355,8 @@ const nothingFoundError = (hash) => {
|
|
|
1709
355
|
};
|
|
1710
356
|
|
|
1711
357
|
globalThis.leofcoin = globalThis.leofcoin || {};
|
|
1712
|
-
globalThis.
|
|
358
|
+
globalThis.pubsub = globalThis.pubsub || new PubSub__default["default"]();
|
|
359
|
+
globalThis.globalSub = globalThis.globalSub || new PubSub__default["default"]({verbose: true});
|
|
1713
360
|
|
|
1714
361
|
/**
|
|
1715
362
|
* @access public
|
|
@@ -1755,16 +402,12 @@ class Peernet {
|
|
|
1755
402
|
return ['account', 'wallet', 'block', 'transaction', 'chain', 'data', 'message']
|
|
1756
403
|
}
|
|
1757
404
|
|
|
1758
|
-
get protos() {
|
|
1759
|
-
return globalThis.peernet.protos
|
|
1760
|
-
}
|
|
1761
|
-
|
|
1762
405
|
get codecs() {
|
|
1763
406
|
return codecFormatInterface.codecs
|
|
1764
407
|
}
|
|
1765
408
|
|
|
1766
409
|
addProto(name, proto) {
|
|
1767
|
-
if (!
|
|
410
|
+
if (!globalThis.peernet.protos[name]) globalThis.peernet.protos[name] = proto;
|
|
1768
411
|
}
|
|
1769
412
|
|
|
1770
413
|
addCodec(name, codec) {
|
|
@@ -1772,6 +415,10 @@ class Peernet {
|
|
|
1772
415
|
}
|
|
1773
416
|
|
|
1774
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
|
+
}
|
|
1775
422
|
if (name === 'block' || name === 'transaction' || name === 'chain' ||
|
|
1776
423
|
name === 'data' || name === 'message') isPrivate = false;
|
|
1777
424
|
|
|
@@ -1779,7 +426,7 @@ class Peernet {
|
|
|
1779
426
|
if (this.hasDaemon) {
|
|
1780
427
|
Storage = LeofcoinStorageClient;
|
|
1781
428
|
} else {
|
|
1782
|
-
Storage =
|
|
429
|
+
Storage = LeofcoinStorage;
|
|
1783
430
|
}
|
|
1784
431
|
globalThis[`${name}Store`] = globalThis[`${name}Store`] ||
|
|
1785
432
|
await new Storage(name, root);
|
|
@@ -1844,6 +491,22 @@ class Peernet {
|
|
|
1844
491
|
this.storePrefix = options.storePrefix;
|
|
1845
492
|
this.root = options.root;
|
|
1846
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
|
+
PeernetFile
|
|
507
|
+
// FolderMessageResponse
|
|
508
|
+
} = await Promise.resolve().then(function () { return require(/* webpackChunkName: "messages" */ './messages-f46a3ca1.js'); });
|
|
509
|
+
|
|
1847
510
|
/**
|
|
1848
511
|
* proto Object containing protos
|
|
1849
512
|
* @type {Object}
|
|
@@ -1853,18 +516,20 @@ class Peernet {
|
|
|
1853
516
|
* @property {DataMessage} protos[peernet-data] messageNode
|
|
1854
517
|
* @property {DataMessageResponse} protos[peernet-data-response] messageNode
|
|
1855
518
|
*/
|
|
519
|
+
|
|
1856
520
|
globalThis.peernet.protos = {
|
|
1857
|
-
'peernet-request':
|
|
1858
|
-
'peernet-response':
|
|
521
|
+
'peernet-request': RequestMessage,
|
|
522
|
+
'peernet-response': ResponseMessage,
|
|
1859
523
|
'peernet-peer': PeerMessage,
|
|
1860
524
|
'peernet-peer-response': PeerMessageResponse,
|
|
1861
|
-
'peernet-message':
|
|
1862
|
-
'peernet-dht':
|
|
1863
|
-
'peernet-dht-response':
|
|
525
|
+
'peernet-message': PeernetMessage,
|
|
526
|
+
'peernet-dht': DHTMessage,
|
|
527
|
+
'peernet-dht-response': DHTMessageResponse,
|
|
1864
528
|
'peernet-data': DataMessage,
|
|
1865
529
|
'peernet-data-response': DataMessageResponse,
|
|
1866
530
|
'peernet-ps': PsMessage,
|
|
1867
531
|
'chat-message': ChatMessage,
|
|
532
|
+
'peernet-file': PeernetFile
|
|
1868
533
|
};
|
|
1869
534
|
|
|
1870
535
|
this._messageHandler = new MessageHandler(this.network);
|
|
@@ -1891,6 +556,9 @@ class Peernet {
|
|
|
1891
556
|
}
|
|
1892
557
|
} catch (e) {
|
|
1893
558
|
if (e.code === 'ERR_NOT_FOUND') {
|
|
559
|
+
|
|
560
|
+
const importee = await Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require(/* webpackChunkName: "generate-account" */ '@leofcoin/generate-account')); });
|
|
561
|
+
const generateAccount = importee.default;
|
|
1894
562
|
const {identity, accounts, config} = await generateAccount(this.network);
|
|
1895
563
|
walletStore.put('version', new TextEncoder().encode(1));
|
|
1896
564
|
walletStore.put('accounts', new TextEncoder().encode(JSON.stringify(accounts)));
|
|
@@ -1923,11 +591,13 @@ class Peernet {
|
|
|
1923
591
|
*/
|
|
1924
592
|
pubsub.subscribe('peer:data', dataHandler);
|
|
1925
593
|
|
|
594
|
+
|
|
595
|
+
const importee = await Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require(/* webpackChunkName: "peernet-swarm" */ '@leofcoin/peernet-swarm')); });
|
|
1926
596
|
/**
|
|
1927
597
|
* @access public
|
|
1928
598
|
* @type {PeernetClient}
|
|
1929
599
|
*/
|
|
1930
|
-
this.client = new
|
|
600
|
+
this.client = new importee.default(this.id);
|
|
1931
601
|
if (globalThis.onbeforeunload) {
|
|
1932
602
|
globalThis.addEventListener('beforeunload', async () => this.client.close());
|
|
1933
603
|
}
|
|
@@ -1967,7 +637,7 @@ class Peernet {
|
|
|
1967
637
|
if (store.private) has = false;
|
|
1968
638
|
else has = await store.has(hash);
|
|
1969
639
|
}
|
|
1970
|
-
const data = await new
|
|
640
|
+
const data = await new globalThis.peernet.protos['peernet-dht-response']({hash, has});
|
|
1971
641
|
const node = await this.prepareMessage(from, data.encoded);
|
|
1972
642
|
|
|
1973
643
|
this.sendMessage(peer, id, node.encoded);
|
|
@@ -1983,7 +653,7 @@ class Peernet {
|
|
|
1983
653
|
data = await store.get(hash);
|
|
1984
654
|
|
|
1985
655
|
if (data) {
|
|
1986
|
-
data = await new
|
|
656
|
+
data = await new globalThis.peernet.protos['peernet-data-response']({hash, data});
|
|
1987
657
|
|
|
1988
658
|
const node = await this.prepareMessage(from, data.encoded);
|
|
1989
659
|
this.sendMessage(peer, id, node.encoded);
|
|
@@ -2010,7 +680,7 @@ class Peernet {
|
|
|
2010
680
|
*/
|
|
2011
681
|
async walk(hash) {
|
|
2012
682
|
if (!hash) throw new Error('hash expected, received undefined')
|
|
2013
|
-
const data = await new dht({hash});
|
|
683
|
+
const data = await new globalThis.peernet.protos['peernet-dht']({hash});
|
|
2014
684
|
this.client.id;
|
|
2015
685
|
const walk = async peer => {
|
|
2016
686
|
const node = await this.prepareMessage(peer.peerId, data.encoded);
|
|
@@ -2118,7 +788,7 @@ class Peernet {
|
|
|
2118
788
|
if (peer.peerId === id) return peer
|
|
2119
789
|
});
|
|
2120
790
|
|
|
2121
|
-
let data = await new
|
|
791
|
+
let data = await new globalThis.peernet.protos['peernet-data']({hash, store: store?.name ? store?.name : store});
|
|
2122
792
|
|
|
2123
793
|
const node = await this.prepareMessage(id, data.encoded);
|
|
2124
794
|
if (closest[0]) data = await closest[0].request(node.encoded);
|
|
@@ -2196,6 +866,75 @@ class Peernet {
|
|
|
2196
866
|
}
|
|
2197
867
|
}
|
|
2198
868
|
|
|
869
|
+
get folder() {
|
|
870
|
+
return {
|
|
871
|
+
/**
|
|
872
|
+
* Get content for given data hash
|
|
873
|
+
*
|
|
874
|
+
* @param {String} hash
|
|
875
|
+
*/
|
|
876
|
+
get: async (hash) => {
|
|
877
|
+
debug(`get data ${hash}`);
|
|
878
|
+
const data = await dataStore.has(hash);
|
|
879
|
+
if (data) return await dataStore.get(hash)
|
|
880
|
+
return this.requestData(hash, 'data')
|
|
881
|
+
},
|
|
882
|
+
/**
|
|
883
|
+
* put data content
|
|
884
|
+
*
|
|
885
|
+
* @param {String} hash
|
|
886
|
+
* @param {Buffer} data
|
|
887
|
+
*/
|
|
888
|
+
put: async (hash, data) => await dataStore.put(hash, data),
|
|
889
|
+
/**
|
|
890
|
+
* @param {String} hash
|
|
891
|
+
* @return {Boolean}
|
|
892
|
+
*/
|
|
893
|
+
has: async (hash) => await dataStore.has(hash),
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
async addFolder(files) {
|
|
898
|
+
const links = [];
|
|
899
|
+
for (const file of files) {
|
|
900
|
+
const fileNode = await new globalThis.peernet.protos['peernet-file'](file);
|
|
901
|
+
const hash = await fileNode.hash;
|
|
902
|
+
await dataStore.put(hash, fileNode.encoded);
|
|
903
|
+
links.push({hash, path: file.path});
|
|
904
|
+
}
|
|
905
|
+
const node = await new globalThis.peernet.protos['peernet-file']({path: '/', links});
|
|
906
|
+
const hash = await node.hash;
|
|
907
|
+
await dataStore.put(hash, node.encoded);
|
|
908
|
+
|
|
909
|
+
return hash
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
async ls(hash) {
|
|
913
|
+
let data;
|
|
914
|
+
const has = await dataStore.has(hash);
|
|
915
|
+
if (has) data = await dataStore.get(hash);
|
|
916
|
+
else data = await this.requestData(hash, 'data');
|
|
917
|
+
|
|
918
|
+
const node = await new peernet.protos['peernet-file'](data);
|
|
919
|
+
const paths = [];
|
|
920
|
+
if (node.decoded?.links.length === 0) throw new Error(`${hash} is a file`)
|
|
921
|
+
for (const {path, hash} of node.decoded.links) {
|
|
922
|
+
paths.push({path, hash});
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
return paths
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
async cat(hash) {
|
|
929
|
+
let data;
|
|
930
|
+
const has = await dataStore.has(hash);
|
|
931
|
+
if (has) data = await dataStore.get(hash);
|
|
932
|
+
else data = await this.requestData(hash, 'data');
|
|
933
|
+
const node = await new peernet.protos['peernet-file'](data);
|
|
934
|
+
if (node.decoded?.links.length > 0) throw new Error(`${hash} is a directory`)
|
|
935
|
+
return node.decoded.content
|
|
936
|
+
}
|
|
937
|
+
|
|
2199
938
|
/**
|
|
2200
939
|
* goes trough given stores and tries to find data for given hash
|
|
2201
940
|
* @param {Array} stores
|
|
@@ -2263,7 +1002,7 @@ class Peernet {
|
|
|
2263
1002
|
if (topic instanceof Uint8Array === false) topic = new TextEncoder().encode(topic);
|
|
2264
1003
|
if (data instanceof Uint8Array === false) data = new TextEncoder().encode(JSON.stringify(data));
|
|
2265
1004
|
const id = Math.random().toString(36).slice(-12);
|
|
2266
|
-
data = await new
|
|
1005
|
+
data = await new globalThis.peernet.protos['peernet-ps']({data, topic});
|
|
2267
1006
|
for (const peer of this.connections) {
|
|
2268
1007
|
if (peer.peerId !== this.peerId) {
|
|
2269
1008
|
const node = await this.prepareMessage(peer.peerId, data.encoded);
|
|
@@ -2274,7 +1013,7 @@ class Peernet {
|
|
|
2274
1013
|
}
|
|
2275
1014
|
|
|
2276
1015
|
createHash(data, name) {
|
|
2277
|
-
return new
|
|
1016
|
+
return new CodeHash(data, {name})
|
|
2278
1017
|
}
|
|
2279
1018
|
|
|
2280
1019
|
/**
|