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.
- package/build/api-defs/asmail.d.ts +1 -0
- package/build/api-defs/files.d.ts +1 -1
- package/build/core/asmail/delivery/per-recipient-wip.js +4 -0
- package/build/core/asmail/inbox/index.d.ts +8 -31
- package/build/core/asmail/inbox/index.js +119 -164
- package/build/core/asmail/inbox/msg-indexing/index.js +8 -9
- package/build/core/asmail/inbox/msg-on-disk.d.ts +0 -5
- package/build/core/asmail/inbox/msg-on-disk.js +1 -22
- package/build/core/asmail/index.js +4 -4
- package/build/core/asmail/sending-params/index.d.ts +13 -14
- package/build/core/asmail/sending-params/index.js +15 -35
- package/build/core/asmail/sending-params/invitations-anon.d.ts +7 -31
- package/build/core/asmail/sending-params/invitations-anon.js +77 -127
- package/build/core/asmail/sending-params/own-params.d.ts +5 -25
- package/build/core/asmail/sending-params/own-params.js +144 -97
- package/build/core/asmail/sending-params/params-from-others.d.ts +6 -16
- package/build/core/asmail/sending-params/params-from-others.js +88 -58
- package/build/core/index.d.ts +2 -1
- package/build/core/index.js +4 -4
- package/build/core/keyring/index.js +2 -3
- package/build/core/keyring/introductory-keys/published-intro-key.d.ts +2 -2
- package/build/core/keyring/introductory-keys/published-intro-key.js +71 -71
- package/build/core/keyring/peer-keys/index.js +6 -7
- package/build/core/storage/index.d.ts +2 -1
- package/build/core/storage/index.js +4 -3
- package/build/core/storage/system-folders/index.d.ts +1 -2
- package/build/core/storage/system-folders/index.js +18 -22
- package/build/lib-client/asmail/recipient.d.ts +1 -0
- package/build/lib-client/asmail/recipient.js +11 -0
- package/build/lib-client/fs-utils/fs-sync-utils.d.ts +1 -1
- package/build/lib-client/fs-utils/fs-sync-utils.js +21 -15
- package/build/lib-client/xsp-fs/folder-node.js +13 -3
- package/build/lib-client/xsp-fs/util/file-based-json.js +1 -1
- package/build/lib-common/dataset-sync/per-device-json-array-logs.js +43 -28
- package/build/lib-common/dataset-sync/single-file.d.ts +12 -0
- package/build/lib-common/dataset-sync/single-file.js +73 -0
- package/build/lib-common/dataset-sync/utils.d.ts +16 -0
- package/build/lib-common/dataset-sync/utils.js +72 -0
- package/build/lib-common-on-node/device-fs-places.d.ts +3 -0
- package/build/{lib-client/xsp-fs/util/for-arrays.js → lib-common-on-node/device-fs-places.js} +21 -13
- package/build/tests/computer.3nweb.core/keyrings.js +2 -2
- package/build/tests/libs-for-tests/core-runner.js +2 -1
- package/package.json +1 -1
- 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
|
|
4
|
-
type
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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.
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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
|
-
|
|
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.
|
package/build/core/index.d.ts
CHANGED
|
@@ -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>;
|
package/build/core/index.js
CHANGED
|
@@ -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.
|
|
38
|
-
const publishedKeys = await (0, published_intro_key_1.makeHolderOfPublishedIntroKey)(
|
|
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
|
|
5
|
+
type WritableFS = web3n.files.WritableFS;
|
|
6
6
|
type IntroKeyCAP = web3n.keys.Keyrings['introKeyOnASMailServer'];
|
|
7
|
-
export declare function makeHolderOfPublishedIntroKey(
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
-
|
|
53
|
-
|
|
39
|
+
const { stopFileWatching, triggerUpload } = (0, single_file_1.watchAndApplyChangesFromOtherDevices)(keysFile, changeProc, onChangeFromOtherDevices, doOnConflict);
|
|
40
|
+
if (keysFile.isNew) {
|
|
41
|
+
await update();
|
|
54
42
|
}
|
|
55
|
-
|
|
56
|
-
|
|
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
|
|
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
|
-
|
|
84
|
-
await
|
|
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 (!
|
|
72
|
+
if (!keys.current) {
|
|
91
73
|
return;
|
|
92
74
|
}
|
|
93
|
-
const current =
|
|
75
|
+
const current = keys.current;
|
|
94
76
|
current.keyPair.retiredAt = retiredAt;
|
|
95
|
-
|
|
96
|
-
|
|
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 (
|
|
112
|
-
&& (
|
|
122
|
+
if (keys.current
|
|
123
|
+
&& (keys.current.keyPair.skey.kid === kid)) {
|
|
113
124
|
return {
|
|
114
125
|
role: 'published_intro',
|
|
115
|
-
pair:
|
|
126
|
+
pair: keys.current.keyPair
|
|
116
127
|
};
|
|
117
128
|
}
|
|
118
129
|
// check previous key
|
|
119
|
-
const pair =
|
|
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 =
|
|
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 (!
|
|
155
|
+
if (!keys.current) {
|
|
145
156
|
return;
|
|
146
157
|
}
|
|
147
|
-
return
|
|
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
|
-
|
|
153
|
-
|
|
154
|
-
if (!published.current) {
|
|
165
|
+
function updateIfCurrentExpired() {
|
|
166
|
+
if (!keys.current) {
|
|
155
167
|
return;
|
|
156
168
|
}
|
|
157
|
-
const { pkeyCert } =
|
|
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.
|
|
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.
|
|
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
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
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
|
-
|
|
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
|
|
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<
|
|
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
|
|
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
|
|
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
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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
|
-
|
|
71
|
-
|
|
72
|
-
|
|
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 {
|
|
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 {
|