core-3nweb-client-lib 0.19.5 → 0.20.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.
Files changed (47) hide show
  1. package/build/api-defs/asmail.d.ts +2 -2
  2. package/build/api-defs/web3n.d.ts +2 -1
  3. package/build/core/asmail/delivery/index.js +1 -1
  4. package/build/core/index.js +1 -1
  5. package/build/core/sign-up.js +5 -6
  6. package/build/ipc-via-protobuf/asmail-cap.js +4 -4
  7. package/build/ipc-via-protobuf/bytes.js +1 -1
  8. package/build/ipc-via-protobuf/connector-clients-side.js +3 -0
  9. package/build/ipc-via-protobuf/connector-services-side.js +1 -1
  10. package/build/ipc-via-protobuf/connector.d.ts +2 -2
  11. package/build/ipc-via-protobuf/connector.js +4 -1
  12. package/build/ipc-via-protobuf/file.d.ts +2 -1
  13. package/build/ipc-via-protobuf/file.js +1 -1
  14. package/build/ipc-via-protobuf/fs.d.ts +2 -1
  15. package/build/ipc-via-protobuf/fs.js +1 -1
  16. package/build/ipc-via-protobuf/log-cap.js +1 -1
  17. package/build/ipc-via-protobuf/mailerid.js +1 -1
  18. package/build/ipc-via-protobuf/proto-defs.js +1 -1
  19. package/build/ipc-via-protobuf/protobuf-msg.d.ts +2 -9
  20. package/build/ipc-via-protobuf/protobuf-msg.js +13 -70
  21. package/build/ipc-via-protobuf/protos/asmail.proto +1 -1
  22. package/build/ipc-via-protobuf/startup-cap.js +1 -1
  23. package/build/ipc-via-protobuf/storage-cap.js +1 -1
  24. package/build/lib-client/cryptor/cryptor-in-worker.d.ts +19 -5
  25. package/build/lib-client/cryptor/cryptor-in-worker.js +191 -157
  26. package/build/lib-client/cryptor/cryptor-wasm.js +1 -0
  27. package/build/lib-client/cryptor/cryptor.d.ts +5 -3
  28. package/build/lib-client/cryptor/cryptor.js +19 -7
  29. package/build/lib-client/cryptor/cryptor.wasm +0 -0
  30. package/build/lib-client/cryptor/{cryptor-in-proc.d.ts → in-proc-js.d.ts} +0 -0
  31. package/build/lib-client/cryptor/{cryptor-in-proc.js → in-proc-js.js} +0 -0
  32. package/build/lib-client/cryptor/in-proc-wasm.d.ts +2 -0
  33. package/build/lib-client/cryptor/in-proc-wasm.js +187 -0
  34. package/build/lib-client/cryptor/proto-defs.js +50 -0
  35. package/build/lib-client/cryptor/protos/cryptor.proto +45 -0
  36. package/build/lib-client/cryptor/wasm-mp1-modules.d.ts +5 -0
  37. package/build/lib-client/cryptor/wasm-mp1-modules.js +79 -0
  38. package/build/lib-client/cryptor/worker-js.d.ts +1 -0
  39. package/build/lib-client/cryptor/worker-js.js +139 -0
  40. package/build/lib-client/cryptor/worker-wasm.d.ts +1 -0
  41. package/build/lib-client/cryptor/worker-wasm.js +37 -0
  42. package/build/lib-client/key-derivation.js +1 -1
  43. package/build/lib-client/protobuf-loader.d.ts +12 -0
  44. package/build/lib-client/protobuf-loader.js +96 -0
  45. package/build/lib-index.d.ts +5 -3
  46. package/build/lib-index.js +5 -3
  47. package/package.json +2 -2
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- Copyright (C) 2020 3NSoft Inc.
3
+ Copyright (C) 2020 - 2021 3NSoft Inc.
4
4
 
5
5
  This program is free software: you can redistribute it and/or modify it under
6
6
  the terms of the GNU General Public License as published by the Free Software
@@ -16,16 +16,41 @@
16
16
  this program. If not, see <http://www.gnu.org/licenses/>.
17
17
  */
18
18
  Object.defineProperty(exports, "__esModule", { value: true });
19
- exports.makeInWorkerCryptor = void 0;
19
+ exports.makeInWorkerWasmCryptor = exports.makeInWorkerCryptor = void 0;
20
20
  const worker_threads_1 = require("worker_threads");
21
- const ecma_nacl_1 = require("ecma-nacl");
22
21
  const os_1 = require("os");
23
22
  const processes_1 = require("../../lib-common/processes");
24
23
  const error_1 = require("../../lib-common/exceptions/error");
25
- const WORKER_MARKER = 'crypto worker';
24
+ const path_1 = require("path");
25
+ const protobuf_loader_1 = require("../protobuf-loader");
26
+ const assert_1 = require("../../lib-common/assert");
26
27
  const MAX_IDLE_MILLIS = 60 * 1000;
28
+ const jsWorkerFName = 'worker-js.js';
29
+ const wasmWorkerFName = 'worker-wasm.js';
30
+ function workerScriptFor(impl) {
31
+ // There is a bug with electrons 12, 13, that doesn't let
32
+ // worker_thread read files from asar pack, even though main thread
33
+ // makes call from here.
34
+ // Therefore, in case this runs from asar pack, we should switch to
35
+ // unpacked in path that is given to worker thread.
36
+ // Of course, asarUnpack should be used in electron-builder.
37
+ const asarInd = __dirname.indexOf('app.asar');
38
+ const dirWithThis = ((asarInd < 0) ?
39
+ __dirname : `${__dirname.substring(0, asarInd + 8)}.unpacked${__dirname.substring(asarInd + 8)}`);
40
+ if (impl === 'js') {
41
+ return path_1.join(dirWithThis, jsWorkerFName);
42
+ }
43
+ else if (impl === 'wasm') {
44
+ return path_1.join(dirWithThis, wasmWorkerFName);
45
+ }
46
+ else {
47
+ throw new Error(`Unknown worker implementation ${impl}`);
48
+ }
49
+ }
27
50
  class Workers {
28
- constructor(logWarning, maxThreads) {
51
+ constructor(workerScript, logErr, logWarning, maxThreads) {
52
+ this.workerScript = workerScript;
53
+ this.logErr = logErr;
29
54
  this.logWarning = logWarning;
30
55
  this.idleWorkers = [];
31
56
  this.allWorkers = new Set();
@@ -62,19 +87,25 @@ class Workers {
62
87
  return worker;
63
88
  }
64
89
  }
90
+ async doRequest(request, trans, d) {
91
+ if (this.isClosed) {
92
+ new Error(`Async cryptor is already closed`);
93
+ }
94
+ const worker = await this.getIdleWorker();
95
+ this.replySinks.set(worker, d);
96
+ if (trans) {
97
+ worker.postMessage(request, trans);
98
+ }
99
+ else {
100
+ worker.postMessage(request);
101
+ }
102
+ return d.res.promise;
103
+ }
65
104
  async makeWorker() {
66
- // There is a bug with electrons 12, 13, that doesn't let
67
- // worker_thread read this file from asar pack, even though main thread
68
- // makes call from here.
69
- // Therefore, in case this runs from asar pack, we should switch to
70
- // unpacked in path that is given to worker thread.
71
- // Of course, asarUnpack should be used in electron-builder.
72
- const asarInd = __filename.indexOf('app.asar');
73
- const pathOfThis = ((asarInd < 0) ?
74
- __filename : `${__filename.substring(0, asarInd + 8)}.unpacked${__filename.substring(asarInd + 8)}`);
75
- const worker = new worker_threads_1.Worker(pathOfThis, {
76
- workerData: WORKER_MARKER
77
- });
105
+ const workerData = {
106
+ loadDir: path_1.dirname(this.workerScript)
107
+ };
108
+ const worker = new worker_threads_1.Worker(this.workerScript, { workerData });
78
109
  this.allWorkers.add(worker);
79
110
  worker.on('message', (reply) => {
80
111
  const sink = this.replySinks.get(worker);
@@ -87,7 +118,7 @@ class Workers {
87
118
  }
88
119
  return;
89
120
  }
90
- const { res, interim, err } = reply;
121
+ const { res, interim, err } = this.processReply(reply);
91
122
  if (res !== undefined) {
92
123
  this.replySinks.delete(worker);
93
124
  this.declareIdle(worker);
@@ -114,13 +145,19 @@ class Workers {
114
145
  const sink = this.replySinks.get(worker);
115
146
  if (sink) {
116
147
  this.replySinks.delete(worker);
117
- sink.res.reject(error_1.errWithCause(err, `Error in cryptor worker thread`));
148
+ const errWrapped = error_1.errWithCause(err, `Error in cryptor worker thread`);
149
+ this.logErr(errWrapped);
150
+ sink.res.reject(errWrapped);
118
151
  }
119
152
  this.detachWorker(worker);
120
153
  worker.terminate();
121
154
  this.makeWorker();
122
155
  });
123
- worker.on('exit', err => { });
156
+ worker.on('exit', err => {
157
+ if (err && !this.isClosed) {
158
+ this.logErr(error_1.errWithCause(err, `Worker exited with error ${err}`));
159
+ }
160
+ });
124
161
  const workerReady = new Promise((resolve, reject) => {
125
162
  const errOnStart = (err) => reject(error_1.errWithCause(err, `Failed to start cryptor worker in thread`));
126
163
  const earlyExit = (exitCode) => reject(new Error(`Thread with worker cryptor exited early with code ${exitCode}`));
@@ -154,22 +191,6 @@ class Workers {
154
191
  this.idleWorkers.push({ worker, since });
155
192
  }
156
193
  }
157
- async call(func, args, trans, interim) {
158
- if (this.isClosed) {
159
- new Error(`Async cryptor is already closed`);
160
- }
161
- const worker = await this.getIdleWorker();
162
- const request = { func, args };
163
- const res = processes_1.defer();
164
- this.replySinks.set(worker, { res, interim });
165
- if (trans) {
166
- worker.postMessage(request, trans);
167
- }
168
- else {
169
- worker.postMessage(request);
170
- }
171
- return res.promise;
172
- }
173
194
  async close() {
174
195
  if (this.isClosed) {
175
196
  return;
@@ -189,21 +210,34 @@ class Workers {
189
210
  }
190
211
  Object.freeze(Workers.prototype);
191
212
  Object.freeze(Workers);
192
- function transfer(...arrs) {
193
- const transferLst = [];
194
- for (const arr of arrs) {
195
- const buffer = arr.buffer;
196
- if (!transferLst.includes(buffer)) {
197
- transferLst.push(buffer);
198
- }
213
+ class JsWorkers extends Workers {
214
+ constructor(logErr, logWarning, maxThreads) {
215
+ super(workerScriptFor('js'), logErr, logWarning, maxThreads);
199
216
  }
200
- return transferLst;
201
- }
202
- function makeInWorkerCryptor(logWarning, maxThreads) {
203
- if (worker_threads_1.workerData === WORKER_MARKER) {
204
- throw new Error(`This method can't be called in crypto worker thread`);
217
+ call(func, args, trans, interim) {
218
+ return this.doRequest({ func, args }, trans, { res: processes_1.defer(), interim });
219
+ }
220
+ processReply(reply) {
221
+ return reply;
205
222
  }
206
- const workers = new Workers(logWarning, maxThreads);
223
+ }
224
+ Object.freeze(JsWorkers.prototype);
225
+ Object.freeze(JsWorkers);
226
+ // XXX can we have no-copy transfer to worker?
227
+ // function transfer(...arrs: Uint8Array[]): ArrayBuffer[]|undefined {
228
+ // const transferLst: ArrayBuffer[] = [];
229
+ // for (const arr of arrs) {
230
+ // const buffer = arr.buffer;
231
+ // if (!transferLst.includes(buffer)) {
232
+ // transferLst.push(buffer);
233
+ // }
234
+ // }
235
+ // return transferLst;
236
+ // }
237
+ exports.makeInWorkerCryptor = (logErr, logWarning, maxThreads) => {
238
+ assert_1.assert(typeof logErr === 'function');
239
+ assert_1.assert(typeof logWarning === 'function');
240
+ const workers = new JsWorkers(logErr, logWarning, maxThreads);
207
241
  const close = workers.close.bind(workers);
208
242
  const cryptor = {
209
243
  scrypt: (passwd, salt, logN, r, p, dkLen, progressCB) => workers.call('scrypt', [passwd, salt, logN, r, p, dkLen], undefined, progressCB),
@@ -226,119 +260,119 @@ function makeInWorkerCryptor(logWarning, maxThreads) {
226
260
  }
227
261
  };
228
262
  return { cryptor, close };
263
+ };
264
+ class WasmWorkers extends Workers {
265
+ constructor(logErr, logWarning, maxThreads) {
266
+ super(workerScriptFor('wasm'), logErr, logWarning, maxThreads);
267
+ this.reqType = makeProtobufType('Request');
268
+ this.replyType = makeProtobufType('Reply');
269
+ }
270
+ call(req, interim) {
271
+ const msg = this.reqType.pack(req);
272
+ return this.doRequest(msg, undefined, { res: processes_1.defer(), interim });
273
+ }
274
+ processReply(replyBytes) {
275
+ const { res, interim, err } = this.replyType.unpack(replyBytes);
276
+ return {
277
+ res: res ? res.val : undefined,
278
+ interim: interim ? interim.val : undefined,
279
+ err: err ? toLocalErr(err) : undefined,
280
+ };
281
+ }
229
282
  }
230
- exports.makeInWorkerCryptor = makeInWorkerCryptor;
231
- if (worker_threads_1.workerData === WORKER_MARKER) {
232
- if (!worker_threads_1.parentPort) {
233
- throw new Error(`Missing expected parentPort from module`);
283
+ Object.freeze(WasmWorkers.prototype);
284
+ Object.freeze(WasmWorkers);
285
+ function toArgs(...args) {
286
+ return args.map(val => ({ val }));
287
+ }
288
+ function toLocalErr(replyErr) {
289
+ if (replyErr.condition === 'cipher-verification') {
290
+ return { failedCipherVerification: true };
291
+ }
292
+ else if (replyErr.condition === 'signature-verification') {
293
+ return { failedSignatureVerification: true };
294
+ }
295
+ else {
296
+ return new Error(`WASM cryptor ${replyErr.condition}: ${replyErr.message}`);
234
297
  }
235
- workerMain(worker_threads_1.parentPort);
236
298
  }
237
- function workerMain(port) {
238
- const arrFactory = ecma_nacl_1.arrays.makeFactory();
239
- const wipe = ecma_nacl_1.arrays.wipe;
240
- const funcs = {
241
- 'scrypt': args => {
242
- const progressCB = (n) => {
243
- const reply = { interim: n };
244
- port.postMessage(reply);
245
- };
246
- const res = ecma_nacl_1.scrypt(args[0], args[1], args[2], args[3], args[4], args[5], progressCB, arrFactory);
247
- wipe(args[0]);
248
- return { res };
249
- // electron v.11.0.3 worker thread fails on memory move
250
- // return { res, trans: transfer(res) };
251
- },
252
- 'box.calc_dhshared_key': args => {
253
- const res = ecma_nacl_1.box.calc_dhshared_key(args[0], args[1], arrFactory);
254
- wipe(args[0], args[1]);
255
- return { res };
256
- // electron v.11.0.3 worker thread fails on memory move
257
- // return { res, trans: transfer(res) };
258
- },
259
- 'box.generate_pubkey': args => {
260
- const res = ecma_nacl_1.box.generate_pubkey(args[0], arrFactory);
261
- wipe(args[0]);
262
- return { res };
263
- // electron v.11.0.3 worker thread fails on memory move
264
- // return { res, trans: transfer(res) };
265
- },
266
- 'sbox.open': args => {
267
- const res = ecma_nacl_1.secret_box.open(args[0], args[1], args[2], arrFactory);
268
- wipe(args[2]);
269
- return { res };
270
- // electron v.11.0.3 worker thread fails on memory move
271
- // return { res, trans: transfer(res) };
272
- },
273
- 'sbox.pack': args => {
274
- const res = ecma_nacl_1.secret_box.pack(args[0], args[1], args[2], arrFactory);
275
- wipe(args[2]);
276
- return { res };
277
- // electron v.11.0.3 worker thread fails on memory move
278
- // return { res, trans: transfer(res) };
279
- },
280
- 'sbox.formatWN.open': args => {
281
- const res = ecma_nacl_1.secret_box.formatWN.open(args[0], args[1], arrFactory);
282
- wipe(args[1]);
283
- return { res };
284
- // electron v.11.0.3 worker thread fails on memory move
285
- // return { res, trans: transfer(res) };
286
- },
287
- 'sbox.formatWN.pack': args => {
288
- const res = ecma_nacl_1.secret_box.formatWN.pack(args[0], args[1], args[2], arrFactory);
289
- wipe(args[2]);
290
- return { res };
291
- // electron v.11.0.3 worker thread fails on memory move
292
- // return { res, trans: transfer(res) };
293
- },
294
- 'sign.generate_keypair': args => {
295
- const pair = ecma_nacl_1.signing.generate_keypair(args[0], arrFactory);
296
- wipe(args[0]);
297
- return { res: pair };
298
- // electron v.11.0.3 worker thread fails on memory move
299
- // return { res: pair, trans: transfer(pair.pkey, pair.skey) };
299
+ function makeProtobufType(type) {
300
+ const protoFile = 'cryptor.proto';
301
+ const typeName = `cryptor.${type}`;
302
+ try {
303
+ // make sure to copy protos with compile step (use npm script)
304
+ return protobuf_loader_1.ProtoType.makeFrom(__dirname, protoFile, typeName);
305
+ }
306
+ catch (err) {
307
+ // we won't get here if referenced module exists, but metro packager
308
+ // in LiqudCore needs static path require
309
+ const fallback = require('./proto-defs');
310
+ return protobuf_loader_1.ProtoType.makeFrom(__dirname, protoFile, typeName, fallback);
311
+ }
312
+ }
313
+ exports.makeInWorkerWasmCryptor = (logErr, logWarning, maxThreads) => {
314
+ assert_1.assert(typeof logErr === 'function');
315
+ assert_1.assert(typeof logWarning === 'function');
316
+ const workers = new WasmWorkers(logErr, logWarning, maxThreads);
317
+ const close = workers.close.bind(workers);
318
+ const boolValType = makeProtobufType('BoolVal');
319
+ const kpairType = makeProtobufType('Keypair');
320
+ const cryptor = {
321
+ scrypt: (passwd, salt, logN, r, p, dkLen, progressCB) => workers.call({
322
+ func: 1,
323
+ scryptArgs: { passwd, salt, logN, r, p, dkLen }
324
+ }, (bytes) => progressCB(bytes[0])),
325
+ box: {
326
+ calc_dhshared_key: (pk, sk) => workers.call({
327
+ func: 2,
328
+ byteArgs: toArgs(pk, sk)
329
+ }),
330
+ generate_pubkey: (sk) => workers.call({
331
+ func: 3,
332
+ byteArgs: toArgs(sk)
333
+ })
300
334
  },
301
- 'sign.signature': args => {
302
- const res = ecma_nacl_1.signing.signature(args[0], args[1], arrFactory);
303
- wipe(args[1]);
304
- return { res };
305
- // electron v.11.0.3 worker thread fails on memory move
306
- // return { res, trans: transfer(res) };
335
+ sbox: {
336
+ open: (c, n, k) => workers.call({
337
+ func: 4,
338
+ byteArgs: toArgs(c, n, k)
339
+ }),
340
+ pack: (m, n, k) => workers.call({
341
+ func: 5,
342
+ byteArgs: toArgs(m, n, k)
343
+ }),
344
+ formatWN: {
345
+ open: (cn, k) => workers.call({
346
+ func: 6,
347
+ byteArgs: toArgs(cn, k)
348
+ }),
349
+ pack: (m, n, k) => workers.call({
350
+ func: 7,
351
+ byteArgs: toArgs(m, n, k)
352
+ })
353
+ }
307
354
  },
308
- 'sign.verify': args => {
309
- const ok = ecma_nacl_1.signing.verify(args[0], args[1], args[2], arrFactory);
310
- return { res: ok };
355
+ signing: {
356
+ generate_keypair: async (seed) => {
357
+ const rep = await workers.call({
358
+ func: 8,
359
+ byteArgs: toArgs(seed)
360
+ });
361
+ return kpairType.unpack(rep);
362
+ },
363
+ signature: (m, sk) => workers.call({
364
+ func: 9,
365
+ byteArgs: toArgs(m, sk)
366
+ }),
367
+ verify: async (sig, m, pk) => {
368
+ const rep = await workers.call({
369
+ func: 10,
370
+ byteArgs: toArgs(sig, m, pk)
371
+ });
372
+ return boolValType.unpack(rep).val;
373
+ }
311
374
  }
312
375
  };
313
- function wrapError(err) {
314
- const exc = {
315
- runtimeException: true,
316
- type: 'cryptor'
317
- };
318
- if (err.failedCipherVerification) {
319
- exc.failedCipherVerification = true;
320
- }
321
- else {
322
- exc.message = `Error occured in cryptor worker thread`;
323
- exc.cause = error_1.stringifyErr(err);
324
- }
325
- return exc;
326
- }
327
- port.on('message', (msg) => {
328
- const { args, func } = msg;
329
- const code = funcs[func];
330
- if (!code) {
331
- throw new Error(`Function ${func} is unknown`);
332
- }
333
- try {
334
- const { res, trans } = code(args);
335
- const reply = { res };
336
- port.postMessage(reply, trans);
337
- }
338
- catch (err) {
339
- const reply = { err: wrapError(err) };
340
- port.postMessage(reply);
341
- }
342
- });
343
- }
376
+ return { cryptor, close };
377
+ };
344
378
  Object.freeze(exports);