core-3nweb-client-lib 0.49.7 → 0.50.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.
Files changed (44) hide show
  1. package/build/api-defs/asmail.d.ts +1 -0
  2. package/build/api-defs/files.d.ts +1 -1
  3. package/build/core/asmail/delivery/per-recipient-wip.js +4 -0
  4. package/build/core/asmail/inbox/index.d.ts +8 -31
  5. package/build/core/asmail/inbox/index.js +119 -164
  6. package/build/core/asmail/inbox/msg-indexing/index.js +8 -9
  7. package/build/core/asmail/inbox/msg-on-disk.d.ts +0 -5
  8. package/build/core/asmail/inbox/msg-on-disk.js +1 -22
  9. package/build/core/asmail/index.js +4 -4
  10. package/build/core/asmail/sending-params/index.d.ts +13 -14
  11. package/build/core/asmail/sending-params/index.js +15 -35
  12. package/build/core/asmail/sending-params/invitations-anon.d.ts +7 -31
  13. package/build/core/asmail/sending-params/invitations-anon.js +77 -127
  14. package/build/core/asmail/sending-params/own-params.d.ts +5 -25
  15. package/build/core/asmail/sending-params/own-params.js +144 -97
  16. package/build/core/asmail/sending-params/params-from-others.d.ts +6 -16
  17. package/build/core/asmail/sending-params/params-from-others.js +88 -58
  18. package/build/core/index.d.ts +2 -1
  19. package/build/core/index.js +4 -4
  20. package/build/core/keyring/index.js +2 -3
  21. package/build/core/keyring/introductory-keys/published-intro-key.d.ts +2 -2
  22. package/build/core/keyring/introductory-keys/published-intro-key.js +71 -71
  23. package/build/core/keyring/peer-keys/index.js +6 -7
  24. package/build/core/storage/index.d.ts +2 -1
  25. package/build/core/storage/index.js +4 -3
  26. package/build/core/storage/system-folders/index.d.ts +1 -2
  27. package/build/core/storage/system-folders/index.js +18 -22
  28. package/build/lib-client/asmail/recipient.d.ts +1 -0
  29. package/build/lib-client/asmail/recipient.js +11 -0
  30. package/build/lib-client/fs-utils/fs-sync-utils.d.ts +1 -1
  31. package/build/lib-client/fs-utils/fs-sync-utils.js +21 -15
  32. package/build/lib-client/xsp-fs/folder-node.js +13 -3
  33. package/build/lib-client/xsp-fs/util/file-based-json.js +1 -1
  34. package/build/lib-common/dataset-sync/per-device-json-array-logs.js +43 -28
  35. package/build/lib-common/dataset-sync/single-file.d.ts +12 -0
  36. package/build/lib-common/dataset-sync/single-file.js +73 -0
  37. package/build/lib-common/dataset-sync/utils.d.ts +16 -0
  38. package/build/lib-common/dataset-sync/utils.js +72 -0
  39. package/build/lib-common-on-node/device-fs-places.d.ts +3 -0
  40. package/build/{lib-client/xsp-fs/util/for-arrays.js → lib-common-on-node/device-fs-places.js} +21 -13
  41. package/build/tests/computer.3nweb.core/keyrings.js +2 -2
  42. package/build/tests/libs-for-tests/core-runner.js +2 -1
  43. package/package.json +1 -1
  44. package/build/lib-client/xsp-fs/util/for-arrays.d.ts +0 -1
@@ -1,17 +1,7 @@
1
1
  import { SendingParamsHolder } from '../sending-params';
2
- export { SendingParams } from '../msg/common';
3
- type ExposedFuncs = SendingParamsHolder['otherSides'];
4
- type WritableFile = web3n.files.WritableFile;
5
- type FileEvent = web3n.files.FileEvent;
6
- export declare class ParamsFromOthers {
7
- private readonly params;
8
- private readonly fileProc;
9
- private constructor();
10
- static makeAndInit(file: WritableFile): Promise<ParamsFromOthers>;
11
- private absorbRemoteChanges;
12
- protected onFileEvent(ev: FileEvent): Promise<void>;
13
- getFor: ExposedFuncs['get'];
14
- setFor: ExposedFuncs['set'];
15
- private persist;
16
- close(): Promise<void>;
17
- }
2
+ export type { SendingParams } from '../msg/common';
3
+ type WritableFS = web3n.files.WritableFS;
4
+ export type ParamsFromOthers = Awaited<ReturnType<typeof makeParamsFromOthers>>;
5
+ export declare function makeParamsFromOthers(fs: WritableFS, fileName: string): Promise<SendingParamsHolder['otherSides'] & {
6
+ close: () => Promise<void>;
7
+ }>;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- Copyright (C) 2017 - 2018, 2025 3NSoft Inc.
3
+ Copyright (C) 2017 - 2018, 2025 - 2026 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,73 +16,103 @@
16
16
  this program. If not, see <http://www.gnu.org/licenses/>.
17
17
  */
18
18
  Object.defineProperty(exports, "__esModule", { value: true });
19
- exports.ParamsFromOthers = void 0;
20
- const file_based_json_1 = require("../../../lib-client/xsp-fs/util/file-based-json");
21
- class ParamsFromOthers {
22
- constructor() {
23
- this.params = new Map();
24
- this.getFor = (address) => {
25
- const p = this.params.get(address);
26
- if (!p) {
27
- return;
19
+ exports.makeParamsFromOthers = makeParamsFromOthers;
20
+ const single_file_1 = require("../../../lib-common/dataset-sync/single-file");
21
+ async function makeParamsFromOthers(fs, fileName) {
22
+ const { file: paramsFile, changeProc } = await (0, single_file_1.initSyncedFile)(fs, fileName, newFile => newFile.writeJSON([]));
23
+ function parseParamsFromJSON(json) {
24
+ if (Array.isArray(json)) {
25
+ // older serialization form
26
+ const p = {};
27
+ for (const paramsForSending of json) {
28
+ const { address, timestamp, auth, invitation } = paramsForSending;
29
+ p[address] = { timestamp, auth, invitation };
28
30
  }
29
- return copyParams(p);
30
- };
31
- this.setFor = (address, params) => {
32
- return this.fileProc.order.startOrChain(async () => {
33
- const existing = this.params.get(address);
34
- if (existing && (existing.timestamp >= params.timestamp)) {
35
- return;
36
- }
37
- const p = { address };
38
- copyParams(params, p);
39
- this.params.set(p.address, p);
40
- await this.persist();
41
- });
42
- };
43
- this.fileProc = new file_based_json_1.JsonFileProc(this.onFileEvent.bind(this));
44
- Object.seal(this);
45
- }
46
- static async makeAndInit(file) {
47
- const paramsFromOthers = new ParamsFromOthers();
48
- await paramsFromOthers.fileProc.start(file, []);
49
- await paramsFromOthers.absorbRemoteChanges();
50
- return paramsFromOthers;
31
+ return p;
32
+ }
33
+ else if (json && (typeof json === 'object')) {
34
+ return json;
35
+ }
36
+ else {
37
+ return {};
38
+ }
51
39
  }
52
- async absorbRemoteChanges() {
53
- // XXX
54
- // - check for changes: what is needed here from fileProc, and what is
55
- // generic in absorbing remote changes to refactor it into JsonFileProc
56
- // - absorb and sync, if needed: what can be in JsonFileProc
57
- // Code from pre-v.sync:
58
- // const { json } = await this.fileProc.get();
59
- // this.setFromJSON(json);
40
+ let params = parseParamsFromJSON(await paramsFile.readJSON());
41
+ async function onChangeFromOtherDevices(newVersion) {
42
+ changeProc.startOrChain(async () => {
43
+ const { version, json } = await paramsFile.v.readJSON();
44
+ if (version === newVersion) {
45
+ const incomingParams = parseParamsFromJSON(json);
46
+ mergeIncomingParams(incomingParams);
47
+ }
48
+ });
60
49
  }
61
- async onFileEvent(ev) {
62
- if (ev.src === 'local') {
63
- return;
50
+ function mergeIncomingParams(incomingParams) {
51
+ for (const [address, inP] of Object.entries(incomingParams)) {
52
+ const existing = params[address];
53
+ if (existing && (existing.timestamp >= inP.timestamp)) {
54
+ return;
55
+ }
56
+ params[address] = inP;
64
57
  }
65
- switch (ev.type) {
66
- case 'file-change':
67
- await this.fileProc.order.startOrChain(() => this.absorbRemoteChanges());
68
- break;
69
- case 'removed':
70
- throw new Error(`Unexpected removal of file with invites info`);
71
- default:
58
+ }
59
+ function doOnConflict() {
60
+ return changeProc.startOrChain(async () => {
61
+ const { remote, state } = await paramsFile.v.sync.status(false);
62
+ if ((state !== 'conflicting') || !(remote === null || remote === void 0 ? void 0 : remote.latest)) {
72
63
  return;
64
+ }
65
+ const onRemote = parseParamsFromJSON((await paramsFile.v.readJSON({ remoteVersion: remote.latest })).json);
66
+ const numRemRecs = Object.keys(onRemote).length;
67
+ const numExistingRecs = Object.keys(params).length;
68
+ let paramsWhereUpdated = (numExistingRecs > numRemRecs);
69
+ for (const [address, inP] of Object.entries(onRemote)) {
70
+ const existing = params[address];
71
+ if (existing.timestamp < inP.timestamp) {
72
+ params[address] = inP;
73
+ paramsWhereUpdated = true;
74
+ }
75
+ else if (existing.timestamp > inP.timestamp) {
76
+ paramsWhereUpdated = true;
77
+ }
78
+ }
79
+ if (paramsWhereUpdated) {
80
+ await paramsFile.v.sync.upload({ uploadVersion: remote.latest + 1 });
81
+ }
82
+ else {
83
+ await paramsFile.v.sync.adoptRemote({ remoteVersion: remote.latest });
84
+ }
85
+ });
86
+ }
87
+ const { stopFileWatching, triggerUpload } = (0, single_file_1.watchAndApplyChangesFromOtherDevices)(paramsFile, changeProc, onChangeFromOtherDevices, doOnConflict);
88
+ function get(address) {
89
+ const p = params[address];
90
+ if (!p) {
91
+ return;
73
92
  }
93
+ return copyParams(p);
74
94
  }
75
- async persist() {
76
- const json = Array.from(this.params.values());
77
- await this.fileProc.save(json, false);
95
+ ;
96
+ async function set(address, params) {
97
+ return changeProc.startOrChain(async () => {
98
+ const existing = params[address];
99
+ if (existing && (existing.timestamp >= params.timestamp)) {
100
+ return;
101
+ }
102
+ params[address] = copyParams(params);
103
+ await paramsFile.writeJSON(params);
104
+ triggerUpload();
105
+ });
78
106
  }
79
- async close() {
80
- await this.fileProc.close();
107
+ async function close() {
108
+ stopFileWatching();
81
109
  }
110
+ return {
111
+ get,
112
+ set,
113
+ close
114
+ };
82
115
  }
83
- exports.ParamsFromOthers = ParamsFromOthers;
84
- Object.freeze(ParamsFromOthers.prototype);
85
- Object.freeze(ParamsFromOthers);
86
116
  /**
87
117
  * This copies SendingParams' fields, returning a copy, which was either
88
118
  * created, or given.
@@ -7,6 +7,7 @@ export type { makeCryptor } from 'ecma-nacl-cryptors';
7
7
  type RequestedCAPs = web3n.caps.common.RequestedCAPs;
8
8
  type W3N = web3n.caps.common.W3N;
9
9
  type ProgressCB = web3n.startup.ProgressCB;
10
+ type FSItem = web3n.files.FSItem;
10
11
  export interface CoreConf {
11
12
  dataDir: string;
12
13
  signUpUrl: string;
@@ -27,7 +28,7 @@ export declare class Core {
27
28
  private closingProc;
28
29
  private isInitialized;
29
30
  private constructor();
30
- static make(conf: CoreConf, makeNet: MakeNet, makeResolver: ServiceLocatorMaker, makeCryptor: makeCryptor, random: AsyncRNG): Core;
31
+ static make(conf: CoreConf, makeNet: MakeNet, makeResolver: ServiceLocatorMaker, sysFilesOnDevice: () => Promise<FSItem>, makeCryptor: makeCryptor, random: AsyncRNG): Core;
31
32
  start(saveStorageKeyForAutologin?: (storageKey: Uint8Array) => void): {
32
33
  capsForStartup: web3n.startup.W3N;
33
34
  coreInit: Promise<string>;
@@ -31,7 +31,7 @@ const constants_1 = require("./storage/common/constants");
31
31
  const config_1 = require("./asmail/config");
32
32
  const deferred_1 = require("../lib-common/processes/deferred");
33
33
  class Core {
34
- constructor(makeNet, makeResolver, makeCryptor, random, appDirs, logger, signUpUrl) {
34
+ constructor(makeNet, makeResolver, makeCryptor, random, appDirs, sysFilesOnDevice, logger, signUpUrl) {
35
35
  this.makeNet = makeNet;
36
36
  this.makeResolver = makeResolver;
37
37
  this.random = random;
@@ -43,14 +43,14 @@ class Core {
43
43
  this.closingProc = undefined;
44
44
  this.isInitialized = false;
45
45
  this.cryptor = makeCryptor(this.logger.logError, this.logger.logWarning);
46
- this.storages = new storage_1.Storages(this.cryptor.cryptor.sbox, this.random, this.appDirs.storagePathFor);
46
+ this.storages = new storage_1.Storages(this.cryptor.cryptor.sbox, this.random, this.appDirs.storagePathFor, sysFilesOnDevice);
47
47
  this.asmail = new asmail_1.ASMail(this.cryptor.cryptor.sbox, this.random, this.makeNet, this.appDirs.inboxPathFor, this.logger);
48
48
  Object.seal(this);
49
49
  }
50
- static make(conf, makeNet, makeResolver, makeCryptor, random) {
50
+ static make(conf, makeNet, makeResolver, sysFilesOnDevice, makeCryptor, random) {
51
51
  const dirs = (0, app_files_1.appDirs)(conf.dataDir);
52
52
  const logger = (0, log_to_file_1.makeLogger)(dirs.getUtilFS());
53
- const core = new Core(makeNet, makeResolver, makeCryptor, random, dirs, logger, conf.signUpUrl);
53
+ const core = new Core(makeNet, makeResolver, makeCryptor, random, dirs, sysFilesOnDevice, logger, conf.signUpUrl);
54
54
  return core;
55
55
  }
56
56
  start(saveStorageKeyForAutologin) {
@@ -31,11 +31,10 @@ const buffer_utils_1 = require("../../lib-common/buffer-utils");
31
31
  var common_2 = require("./common");
32
32
  Object.defineProperty(exports, "KEY_USE", { enumerable: true, get: function () { return common_2.KEY_USE; } });
33
33
  const INTRO_KEYS_FOLDER = 'introductory-keys';
34
- const INTRO_KEY_ON_SERVER_FILE = `published-on-server.json`;
35
34
  async function makeKeyrings(cryptor, random, logger, fs, localFS, getSigner, pkeyOnServer) {
36
35
  const workLabel = cryptor_work_labels_1.cryptoWorkLabels.makeRandom('asmail');
37
- const introKeysFS = await (0, fs_sync_utils_1.getOrMakeSyncedDirOnInit)(fs, INTRO_KEYS_FOLDER);
38
- const publishedKeys = await (0, published_intro_key_1.makeHolderOfPublishedIntroKey)(await introKeysFS.writableFile(INTRO_KEY_ON_SERVER_FILE), getSigner, random, pkeyOnServer);
36
+ const introKeysFS = await (0, fs_sync_utils_1.getOrMakeDirOnInit)(fs, INTRO_KEYS_FOLDER);
37
+ const publishedKeys = await (0, published_intro_key_1.makeHolderOfPublishedIntroKey)(introKeysFS, getSigner, random, pkeyOnServer);
39
38
  const peerKeys = await (0, peer_keys_1.makePeersKeyring)(fs, localFS, random, logger);
40
39
  async function generateIntroKeysToSendMsg(address, introPKeyFromServer) {
41
40
  if (introPKeyFromServer.alg !== ecma_nacl_1.box.JWK_ALG_NAME) {
@@ -2,9 +2,9 @@ import { ParamOnServer } from '../../../lib-client/asmail/service-config';
2
2
  import { AsyncRNG } from '../../../lib-common/rng-def';
3
3
  import { GetSigner } from '../../id-manager';
4
4
  import { JWKeyPair, MsgKeyRole } from '../common';
5
- type WritableFile = web3n.files.WritableFile;
5
+ type WritableFS = web3n.files.WritableFS;
6
6
  type IntroKeyCAP = web3n.keys.Keyrings['introKeyOnASMailServer'];
7
- export declare function makeHolderOfPublishedIntroKey(file: WritableFile, getSigner: GetSigner, random: AsyncRNG, pkeyOnServer: ParamOnServer<'init-pub-key'>): Promise<{
7
+ export declare function makeHolderOfPublishedIntroKey(introKeysFS: WritableFS, getSigner: GetSigner, random: AsyncRNG, pkeyOnServer: ParamOnServer<'init-pub-key'>): Promise<{
8
8
  startExpiryCheckProcess: () => void;
9
9
  close: () => Promise<void>;
10
10
  makeIntroKeyCAP: () => IntroKeyCAP;
@@ -17,53 +17,34 @@
17
17
  */
18
18
  Object.defineProperty(exports, "__esModule", { value: true });
19
19
  exports.makeHolderOfPublishedIntroKey = makeHolderOfPublishedIntroKey;
20
- const file_based_json_1 = require("../../../lib-client/xsp-fs/util/file-based-json");
20
+ const single_file_1 = require("../../../lib-common/dataset-sync/single-file");
21
21
  const jwkeys_1 = require("../../../lib-common/jwkeys");
22
22
  const common_1 = require("../common");
23
23
  const INTRO_KEY_VALIDITY = 31 * 24 * 60 * 60;
24
24
  const UPDATE_BEFORE_EXPIRY = 7 * 24 * 60 * 60;
25
- async function makeHolderOfPublishedIntroKey(file, getSigner, random, pkeyOnServer) {
25
+ const MAX_NUM_OF_PREV = 3;
26
+ const INTRO_KEY_ON_SERVER_FILE = `published-on-server.json`;
27
+ async function makeHolderOfPublishedIntroKey(introKeysFS, getSigner, random, pkeyOnServer) {
26
28
  var _a;
27
- let published = {
28
- previous: []
29
- };
30
- // XXX JsonFileProc is too little, in comparison to operations syn, and watching file
31
- const fileProc = new file_based_json_1.JsonFileProc(onFileEvent);
32
- async function onFileEvent(ev) {
33
- if (ev.src === 'local') {
34
- return;
35
- }
36
- switch (ev.type) {
37
- case 'file-change':
38
- await fileProc.order.startOrChain(() => absorbRemoteChanges());
39
- break;
40
- case 'removed':
41
- throw new Error(`Unexpected removal of file with parameter "anon-sender/invites"`);
42
- default:
43
- return;
44
- }
45
- }
46
- function setFromJSON(json) {
47
- if (!Array.isArray(json.previous)) { // migration part
48
- json.previous = (json.previous ? [json.previous] : []);
49
- }
50
- published = json;
29
+ const { file: keysFile, changeProc } = await (0, single_file_1.initSyncedFile)(introKeysFS, INTRO_KEY_ON_SERVER_FILE, newFile => newFile.writeJSON({ previous: [] }));
30
+ let keys = await keysFile.readJSON();
31
+ async function onChangeFromOtherDevices(newVersion) {
32
+ changeProc.startOrChain(async () => {
33
+ const { version, json } = await keysFile.v.readJSON();
34
+ if (version === newVersion) {
35
+ keys = json;
36
+ }
37
+ });
51
38
  }
52
- function toFileJSON() {
53
- return published;
39
+ const { stopFileWatching, triggerUpload } = (0, single_file_1.watchAndApplyChangesFromOtherDevices)(keysFile, changeProc, onChangeFromOtherDevices, doOnConflict);
40
+ if (keysFile.isNew) {
41
+ await update();
54
42
  }
55
- // private toServerParam(): PKeyCertChain|undefined {
56
- // return published.current?.certs;
57
- // }
58
- async function absorbRemoteChanges() {
59
- // XXX
60
- // - check for changes: what is needed here from fileProc, and what is
61
- // generic in absorbing remote changes to refactor it into JsonFileProc
62
- // - absorb and sync, if needed: what can be in JsonFileProc
63
- // Code from pre-v.sync:
64
- // const { json } = await fileProc.get();
65
- // setFromJSON(json);
43
+ else {
44
+ updateIfCurrentExpired();
66
45
  }
46
+ let periodicExpiryCheck = setTimeout(updateIfCurrentExpired, UPDATE_BEFORE_EXPIRY * 1000 / 20);
47
+ (_a = periodicExpiryCheck.unref) === null || _a === void 0 ? void 0 : _a.call(periodicExpiryCheck);
67
48
  async function makeNewIntroKey() {
68
49
  const signer = await getSigner();
69
50
  const pair = await (0, common_1.generateKeyPair)(random);
@@ -76,24 +57,54 @@ async function makeHolderOfPublishedIntroKey(file, getSigner, random, pkeyOnServ
76
57
  return { pair, certs };
77
58
  }
78
59
  function update() {
79
- return fileProc.order.startOrChain(async () => {
60
+ return changeProc.startOrChain(async () => {
80
61
  const { certs, pair: keyPair } = await makeNewIntroKey();
81
62
  await pkeyOnServer.setOnServer(certs);
82
63
  retireCurrent(keyPair.createdAt);
83
- published.current = { keyPair, certs };
84
- await fileProc.save(toFileJSON(), false);
64
+ keys.current = { keyPair, certs };
65
+ await keysFile.writeJSON(keys);
66
+ triggerUpload();
85
67
  return certs;
86
68
  });
87
69
  }
88
70
  ;
89
71
  function retireCurrent(retiredAt) {
90
- if (!published.current) {
72
+ if (!keys.current) {
91
73
  return;
92
74
  }
93
- const current = published.current;
75
+ const current = keys.current;
94
76
  current.keyPair.retiredAt = retiredAt;
95
- published.previous.push(current.keyPair);
96
- published.current = undefined;
77
+ keys.previous.push(current.keyPair);
78
+ if (keys.previous.length > MAX_NUM_OF_PREV) {
79
+ keys.previous.splice(0, keys.previous.length - MAX_NUM_OF_PREV);
80
+ }
81
+ keys.current = undefined;
82
+ }
83
+ function doOnConflict() {
84
+ return changeProc.startOrChain(async () => {
85
+ var _a, _b, _c, _d, _e, _f;
86
+ const { remote, state } = await keysFile.v.sync.status(false);
87
+ if ((state !== 'conflicting') || !(remote === null || remote === void 0 ? void 0 : remote.latest)) {
88
+ return;
89
+ }
90
+ const onRemote = (await keysFile.v.readJSON({ remoteVersion: remote.latest })).json;
91
+ if (((_a = onRemote.current) === null || _a === void 0 ? void 0 : _a.keyPair.pkey.kid) === ((_b = keys.current) === null || _b === void 0 ? void 0 : _b.keyPair.pkey.kid)) {
92
+ await keysFile.v.sync.adoptRemote();
93
+ return;
94
+ }
95
+ const certsOnServer = await pkeyOnServer.getFromServer();
96
+ const currentOnServer = (certsOnServer ? (0, jwkeys_1.getPubKey)(certsOnServer.pkeyCert) : undefined);
97
+ if ((currentOnServer === null || currentOnServer === void 0 ? void 0 : currentOnServer.kid) === ((_c = keys.current) === null || _c === void 0 ? void 0 : _c.keyPair.pkey.kid)) {
98
+ await keysFile.v.sync.upload({ uploadVersion: remote.latest + 1 });
99
+ }
100
+ else if ((currentOnServer === null || currentOnServer === void 0 ? void 0 : currentOnServer.kid) === ((_d = onRemote.current) === null || _d === void 0 ? void 0 : _d.keyPair.pkey.kid)) {
101
+ await keysFile.v.sync.adoptRemote({ remoteVersion: remote.latest });
102
+ }
103
+ else {
104
+ await pkeyOnServer.setOnServer((_f = (_e = keys.current) === null || _e === void 0 ? void 0 : _e.certs) !== null && _f !== void 0 ? _f : null);
105
+ await keysFile.v.sync.upload({ uploadVersion: remote.latest + 1 });
106
+ }
107
+ });
97
108
  }
98
109
  /**
99
110
  * This looks for a published key with a given key id. If it is found, an
@@ -108,15 +119,15 @@ async function makeHolderOfPublishedIntroKey(file, getSigner, random, pkeyOnServ
108
119
  */
109
120
  function find(kid) {
110
121
  // check current key
111
- if (published.current
112
- && (published.current.keyPair.skey.kid === kid)) {
122
+ if (keys.current
123
+ && (keys.current.keyPair.skey.kid === kid)) {
113
124
  return {
114
125
  role: 'published_intro',
115
- pair: published.current.keyPair
126
+ pair: keys.current.keyPair
116
127
  };
117
128
  }
118
129
  // check previous key
119
- const pair = published.previous.find(({ skey }) => (skey.kid === kid));
130
+ const pair = keys.previous.find(({ skey }) => (skey.kid === kid));
120
131
  if (pair) {
121
132
  return {
122
133
  role: 'prev_published_intro',
@@ -137,24 +148,25 @@ async function makeHolderOfPublishedIntroKey(file, getSigner, random, pkeyOnServ
137
148
  }
138
149
  async function getCurrent() {
139
150
  var _a;
140
- const certs = (_a = published.current) === null || _a === void 0 ? void 0 : _a.certs;
151
+ const certs = (_a = keys.current) === null || _a === void 0 ? void 0 : _a.certs;
141
152
  return (certs ? certs : null);
142
153
  }
143
154
  async function removeCurrent() {
144
- if (!published.current) {
155
+ if (!keys.current) {
145
156
  return;
146
157
  }
147
- return fileProc.order.startOrChain(async () => {
158
+ return changeProc.startOrChain(async () => {
148
159
  await pkeyOnServer.setOnServer(null);
149
160
  retireCurrent(Math.floor(Date.now() / 1000));
161
+ await keysFile.writeJSON(keys);
162
+ triggerUpload();
150
163
  });
151
164
  }
152
- let periodicExpiryCheck = undefined;
153
- function startExpiryCheckProcess() {
154
- if (!published.current) {
165
+ function updateIfCurrentExpired() {
166
+ if (!keys.current) {
155
167
  return;
156
168
  }
157
- const { pkeyCert } = published.current.certs;
169
+ const { pkeyCert } = keys.current.certs;
158
170
  const expiryInSeconds = (0, jwkeys_1.getKeyCert)(pkeyCert).expiresAt;
159
171
  const now = Math.floor(Date.now() / 1000);
160
172
  if (expiryInSeconds < (now + UPDATE_BEFORE_EXPIRY)) {
@@ -162,26 +174,14 @@ async function makeHolderOfPublishedIntroKey(file, getSigner, random, pkeyOnServ
162
174
  }
163
175
  }
164
176
  async function close() {
177
+ stopFileWatching();
165
178
  if (periodicExpiryCheck) {
166
179
  clearTimeout(periodicExpiryCheck);
167
180
  periodicExpiryCheck = undefined;
168
181
  }
169
- await fileProc.close();
170
- }
171
- if (file.isNew) {
172
- await fileProc.start(file, toFileJSON);
173
- await update();
174
- }
175
- else {
176
- await fileProc.start(file, undefined);
177
- setFromJSON((await fileProc.get()).json);
178
- await absorbRemoteChanges();
179
- startExpiryCheckProcess();
180
- periodicExpiryCheck = setTimeout(startExpiryCheckProcess, UPDATE_BEFORE_EXPIRY * 1000 / 20);
181
- (_a = periodicExpiryCheck.unref) === null || _a === void 0 ? void 0 : _a.call(periodicExpiryCheck);
182
182
  }
183
183
  return {
184
- startExpiryCheckProcess,
184
+ startExpiryCheckProcess: updateIfCurrentExpired,
185
185
  close,
186
186
  makeIntroKeyCAP,
187
187
  find
@@ -30,9 +30,9 @@ const LOGS_DIR = 'peer-keys-logs';
30
30
  const PEER_KEYS_FOLDER = 'peer-keys-db';
31
31
  const NUM_OF_LOGS_TO_START_CUT = 200;
32
32
  async function makePeersKeyring(keyringFS, localFS, random, logger) {
33
- const logsFS = await (0, fs_sync_utils_1.getOrMakeSyncedDirOnInit)(keyringFS, LOGS_DIR);
33
+ const logsFS = await (0, fs_sync_utils_1.getOrMakeDirOnInit)(keyringFS, LOGS_DIR);
34
34
  const logsLocalFS = await localFS.writableSubRoot(LOGS_DIR);
35
- const peerKeysFS = await (0, fs_sync_utils_1.getOrMakeSyncedDirOnInit)(keyringFS, PEER_KEYS_FOLDER);
35
+ const peerKeysFS = await (0, fs_sync_utils_1.getOrMakeDirOnInit)(keyringFS, PEER_KEYS_FOLDER);
36
36
  // XXX log and saving reduction(!):
37
37
  // - we don't need to log message counts
38
38
  // - we don't have to immediately save changes in message counts
@@ -165,11 +165,10 @@ async function makePeersKeyring(keyringFS, localFS, random, logger) {
165
165
  await logs.recordGettingCryptoFromPeer(entryToLog, peerAddr);
166
166
  }
167
167
  async function periodicCheckAndUploadOfData() {
168
- // XXX disable uploading for a moment by commenting out
169
- // if (logs.numOfLogs() >= NUM_OF_LOGS_TO_START_CUT) {
170
- // const syncedIndexDbVersion = await keysDB.saveAndSync();
171
- // await logs.cutLogOnDatasetSyncAndUpload(syncedIndexDbVersion);
172
- // }
168
+ if (logs.numOfLogs() >= NUM_OF_LOGS_TO_START_CUT) {
169
+ const syncedIndexDbVersion = await keysDB.saveAndSync();
170
+ await logs.cutLogOnDatasetSyncAndUpload(syncedIndexDbVersion);
171
+ }
173
172
  }
174
173
  function millisBeforeNextRun() {
175
174
  return 30 * 60 * 1000 + Math.floor(10 * 60 * 1000 * Math.random());
@@ -17,10 +17,11 @@ export declare class Storages implements FactoryOfFSs {
17
17
  private readonly cryptor;
18
18
  private readonly random;
19
19
  private readonly storageDirForUser;
20
+ private readonly sysFilesOnDevice;
20
21
  private synced;
21
22
  private local;
22
23
  private preCloseWaits;
23
- constructor(cryptor: AsyncSBoxCryptor, random: AsyncRNG, storageDirForUser: StoragePathForUser);
24
+ constructor(cryptor: AsyncSBoxCryptor, random: AsyncRNG, storageDirForUser: StoragePathForUser, sysFilesOnDevice: () => Promise<FSItem>);
24
25
  makeStorageCAP(appDomain: string, policy: StoragePolicy): {
25
26
  cap: Service;
26
27
  close: () => void;
@@ -216,10 +216,11 @@ class StorageAndFS {
216
216
  Object.freeze(StorageAndFS.prototype);
217
217
  Object.freeze(StorageAndFS);
218
218
  class Storages {
219
- constructor(cryptor, random, storageDirForUser) {
219
+ constructor(cryptor, random, storageDirForUser, sysFilesOnDevice) {
220
220
  this.cryptor = cryptor;
221
221
  this.random = random;
222
222
  this.storageDirForUser = storageDirForUser;
223
+ this.sysFilesOnDevice = sysFilesOnDevice;
223
224
  this.synced = undefined;
224
225
  this.local = undefined;
225
226
  this.preCloseWaits = new Set();
@@ -349,7 +350,7 @@ class Storages {
349
350
  fs = await this.local.userFS();
350
351
  }
351
352
  else if (type === 'device') {
352
- fs = await (0, system_folders_1.userFilesOnDevice)();
353
+ return await (0, system_folders_1.userFilesOnDevice)();
353
354
  }
354
355
  else {
355
356
  throw new Error(`Unknown storage type ${type}`);
@@ -375,7 +376,7 @@ class Storages {
375
376
  };
376
377
  }
377
378
  else if (type === 'device') {
378
- return (0, system_folders_1.sysFilesOnDevice)();
379
+ return this.sysFilesOnDevice();
379
380
  }
380
381
  else {
381
382
  throw new Error(`Unknown storage type ${type}`);
@@ -13,6 +13,5 @@ export declare const sysFolders: {
13
13
  * @param root
14
14
  */
15
15
  export declare function initSysFolders(root: WritableFS): Promise<void>;
16
- export declare function userFilesOnDevice(): Promise<WritableFS>;
17
- export declare function sysFilesOnDevice(): Promise<FSItem>;
16
+ export declare function userFilesOnDevice(): Promise<FSItem>;
18
17
  export {};
@@ -19,7 +19,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
19
19
  exports.sysFolders = void 0;
20
20
  exports.initSysFolders = initSysFolders;
21
21
  exports.userFilesOnDevice = userFilesOnDevice;
22
- exports.sysFilesOnDevice = sysFilesOnDevice;
23
22
  const fs_collection_1 = require("../../../lib-client/fs-utils/fs-collection");
24
23
  const lib_index_1 = require("../../../lib-index");
25
24
  exports.sysFolders = {
@@ -40,38 +39,35 @@ async function initSysFolders(root) {
40
39
  for (const sysFolder of Object.values(exports.sysFolders)) {
41
40
  await root.makeFolder(sysFolder);
42
41
  if ((_a = root.v) === null || _a === void 0 ? void 0 : _a.sync) {
43
- // XXX must add work with not-online condition
42
+ // XXX need not-online condition, but it runs only on first install, when network is required
44
43
  await root.v.sync.upload(sysFolder);
45
44
  }
46
45
  }
47
46
  if ((_b = root.v) === null || _b === void 0 ? void 0 : _b.sync) {
48
- // XXX must add work with not-online condition
47
+ // XXX need not-online condition, but it runs only on first install, when network is required
49
48
  await root.v.sync.upload('.');
50
49
  }
51
50
  }
52
51
  async function userFilesOnDevice() {
53
52
  if (process.platform === 'win32') {
54
- return lib_index_1.DeviceFS.makeWritable(process.env.USERPROFILE);
55
- }
56
- else {
57
- return lib_index_1.DeviceFS.makeWritable(process.env.HOME);
58
- }
59
- }
60
- async function sysFilesOnDevice() {
61
- const c = (0, fs_collection_1.makeFSCollection)();
62
- if (process.platform === 'win32') {
63
- const sysDrive = process.env.SystemDrive;
64
- await c.set(sysDrive, {
65
- isFolder: true,
66
- item: await lib_index_1.DeviceFS.makeWritable(sysDrive)
67
- });
53
+ if (process.env.USERPROFILE) {
54
+ return {
55
+ isFolder: true,
56
+ item: await lib_index_1.DeviceFS.makeWritable(process.env.USERPROFILE)
57
+ };
58
+ }
68
59
  }
69
60
  else {
70
- await c.set('', {
71
- isFolder: true,
72
- item: await lib_index_1.DeviceFS.makeWritable('/')
73
- });
61
+ if (process.env.HOME) {
62
+ return {
63
+ isFolder: true,
64
+ item: await lib_index_1.DeviceFS.makeWritable(process.env.HOME)
65
+ };
66
+ }
74
67
  }
75
- return { isCollection: true, item: c };
68
+ return {
69
+ isCollection: true,
70
+ item: (0, fs_collection_1.makeFSCollection)()
71
+ };
76
72
  }
77
73
  Object.freeze(exports);
@@ -5,6 +5,7 @@ import { SubscribingClient } from '../../lib-common/ipc/ws-ipc';
5
5
  type InboxException = web3n.asmail.InboxException;
6
6
  type Observer<T> = web3n.Observer<T>;
7
7
  export declare function makeMsgNotFoundException(msgId: string): InboxException;
8
+ export declare function makeFailToDecryptMsgException(msgId: string): InboxException;
8
9
  export declare function makeObjNotFoundException(msgId: string, objId: string): InboxException;
9
10
  export declare function makeMsgIsBrokenException(msgId: string): InboxException;
10
11
  export declare class MailRecipient extends ServiceUser {