core-3nweb-client-lib 0.49.5 → 0.49.7
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/files.d.ts +11 -5
- package/build/core/asmail/delivery/common.d.ts +8 -28
- package/build/core/asmail/delivery/common.js +1 -47
- package/build/core/asmail/delivery/index.js +3 -8
- package/build/core/asmail/delivery/msg.js +1 -7
- package/build/core/asmail/delivery/per-recipient-wip.js +3 -29
- package/build/core/asmail/inbox/index.d.ts +1 -2
- package/build/core/asmail/inbox/index.js +14 -15
- package/build/core/asmail/inbox/msg-indexing/dataset/v0/sql-db-v-none.d.ts +11 -0
- package/build/core/asmail/inbox/msg-indexing/dataset/v0/sql-db-v-none.js +25 -0
- package/build/core/asmail/inbox/msg-indexing/dataset/v1/logs.d.ts +33 -0
- package/build/core/asmail/inbox/msg-indexing/dataset/v1/logs.js +72 -0
- package/build/core/asmail/inbox/msg-indexing/dataset/v1/sql-db.d.ts +28 -0
- package/build/core/asmail/inbox/msg-indexing/dataset/v1/sql-db.js +477 -0
- package/build/core/asmail/inbox/msg-indexing/index.d.ts +12 -26
- package/build/core/asmail/inbox/msg-indexing/index.js +47 -68
- package/build/core/asmail/inbox/msg-on-disk.js +1 -2
- package/build/core/asmail/index.js +8 -7
- package/build/core/asmail/msg/common.d.ts +0 -1
- package/build/core/asmail/msg/common.js +1 -1
- package/build/core/asmail/msg/packer.js +1 -3
- package/build/core/index.js +7 -4
- package/build/core/keyring/common.d.ts +1 -0
- package/build/core/keyring/common.js +2 -1
- package/build/core/keyring/index.d.ts +7 -44
- package/build/core/keyring/index.js +89 -222
- package/build/core/keyring/introductory-keys/published-intro-key.d.ts +17 -0
- package/build/core/keyring/introductory-keys/published-intro-key.js +190 -0
- package/build/core/keyring/peer-keys/dataset/v1/json-files.d.ts +105 -0
- package/build/core/keyring/peer-keys/dataset/v1/json-files.js +89 -0
- package/build/core/keyring/peer-keys/dataset/v2/logs.d.ts +43 -0
- package/build/core/keyring/peer-keys/dataset/v2/logs.js +116 -0
- package/build/core/keyring/peer-keys/dataset/v2/peer-keys-db.d.ts +73 -0
- package/build/core/keyring/peer-keys/dataset/v2/peer-keys-db.js +543 -0
- package/build/core/keyring/peer-keys/index.d.ts +24 -0
- package/build/core/keyring/peer-keys/index.js +208 -0
- package/build/core/storage/synced/obj-files.js +10 -3
- package/build/core/storage/synced/obj-status.d.ts +1 -1
- package/build/core/storage/synced/obj-status.js +8 -2
- package/build/core/storage/synced/storage.d.ts +4 -4
- package/build/core/storage/system-folders/apps-data.d.ts +0 -1
- package/build/core/storage/system-folders/apps-data.js +2 -6
- package/build/lib-client/fs-utils/fs-sync-utils.d.ts +1 -1
- package/build/lib-client/fs-utils/fs-sync-utils.js +70 -13
- package/build/lib-client/xsp-fs/fs.js +3 -1
- package/build/lib-client/xsp-fs/node-in-fs.d.ts +1 -0
- package/build/lib-client/xsp-fs/node-in-fs.js +7 -2
- package/build/lib-client/xsp-fs/node-persistence.js +1 -3
- package/build/lib-client/xsp-fs/xsp-payload-v2.js +1 -2
- package/build/lib-common/dataset-sync/per-device-json-array-logs.d.ts +58 -0
- package/build/lib-common/dataset-sync/per-device-json-array-logs.js +432 -0
- package/build/lib-common/number-line.d.ts +10 -0
- package/build/lib-common/number-line.js +66 -0
- package/build/lib-common/objs-on-disk/obj-version-file.d.ts +1 -1
- package/build/lib-common/objs-on-disk/obj-version-file.js +3 -3
- package/build/lib-common/rng-def.d.ts +1 -0
- package/build/lib-common/rng-def.js +8 -0
- package/build/lib-sqlite-on-3nstorage/for-sqlite.d.ts +38 -0
- package/build/lib-sqlite-on-3nstorage/for-sqlite.js +162 -0
- package/build/lib-sqlite-on-3nstorage/index.d.ts +18 -5
- package/build/lib-sqlite-on-3nstorage/index.js +49 -26
- package/build/tests/caps-api/file-sink-checks/splice.js +72 -1
- package/build/tests/caps-api/fs-checks/sync-on-one-dev/upload.js +27 -1
- package/build/tests/caps-api/fs-checks/sync-with-two-devs/update-propagation.js +12 -3
- package/build/tests/computer.3nweb.core/inbox/msg-indexing.js +16 -12
- package/build/tests/computer.3nweb.core/keyrings.js +113 -28
- package/build/tests/jasmine.js +2 -2
- package/build/tests/units/number-line.js +9 -9
- package/package.json +2 -1
- package/build/core/asmail/inbox/msg-indexing/logs-n-entries.d.ts +0 -52
- package/build/core/asmail/inbox/msg-indexing/logs-n-entries.js +0 -333
- package/build/core/asmail/inbox/msg-indexing/sql-indexing.d.ts +0 -4
- package/build/core/asmail/inbox/msg-indexing/sql-indexing.js +0 -319
- package/build/core/keyring/correspondent-keys.d.ts +0 -149
- package/build/core/keyring/correspondent-keys.js +0 -403
- package/build/core/keyring/id-to-email-map.d.ts +0 -38
- package/build/core/keyring/id-to-email-map.js +0 -105
- package/build/core/keyring/keyring-storage.d.ts +0 -9
- package/build/core/keyring/keyring-storage.js +0 -54
- package/build/core/keyring/published-intro-key.d.ts +0 -45
- package/build/core/keyring/published-intro-key.js +0 -200
|
@@ -49,7 +49,7 @@ class ASMail {
|
|
|
49
49
|
this.keyring = keyring;
|
|
50
50
|
await this.setupSendingParams(syncedFS);
|
|
51
51
|
await Promise.all([
|
|
52
|
-
this.setupInbox(syncedFS, getSigner, getStorages, makeResolver),
|
|
52
|
+
this.setupInbox(syncedFS, localFS, getSigner, getStorages, makeResolver),
|
|
53
53
|
this.setupDelivery(localFS, getSigner, makeResolver)
|
|
54
54
|
]);
|
|
55
55
|
await (0, fs_sync_utils_1.uploadFolderChangesIfAny)(syncedFS);
|
|
@@ -61,7 +61,7 @@ class ASMail {
|
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
async setupSendingParams(syncedFS) {
|
|
64
|
-
const fs = await (0, fs_sync_utils_1.
|
|
64
|
+
const fs = await (0, fs_sync_utils_1.getOrMakeSyncedDirOnInit)(syncedFS, SEND_PARAMS_DATA_FOLDER);
|
|
65
65
|
this.sendingParams = await sending_params_1.SendingParamsHolder.makeAndInit(fs, this.config.makeParamSetterAndGetter('anon-sender/invites'), this.random);
|
|
66
66
|
}
|
|
67
67
|
async setupDelivery(localFS, getSigner, makeResolver) {
|
|
@@ -75,8 +75,8 @@ class ASMail {
|
|
|
75
75
|
midResolver: makeResolver('mailerid', this.logger.logError),
|
|
76
76
|
correspondents: {
|
|
77
77
|
needIntroKeyFor: this.keyring.needIntroKeyFor,
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
generateIntroKeysToSendMsg: this.keyring.generateIntroKeysToSendMsg,
|
|
79
|
+
getEstablishedKeysToSendMsg: this.keyring.getEstablishedKeysToSendMsg,
|
|
80
80
|
paramsForSendingTo: this.sendingParams.otherSides.get,
|
|
81
81
|
newParamsForSendingReplies: this.sendingParams.thisSide.getUpdated
|
|
82
82
|
},
|
|
@@ -86,10 +86,11 @@ class ASMail {
|
|
|
86
86
|
logWarning: this.logger.logWarning
|
|
87
87
|
});
|
|
88
88
|
}
|
|
89
|
-
async setupInbox(syncedFS, getSigner, getStorages, makeResolver) {
|
|
89
|
+
async setupInbox(syncedFS, localFS, getSigner, getStorages, makeResolver) {
|
|
90
90
|
const cachePath = this.inboxPathForUser(this.address);
|
|
91
|
-
const inboxSyncedFS = await (0, fs_sync_utils_1.
|
|
92
|
-
|
|
91
|
+
const inboxSyncedFS = await (0, fs_sync_utils_1.getOrMakeSyncedDirOnInit)(syncedFS, INBOX_DATA_FOLDER);
|
|
92
|
+
const inboxLocalFS = await localFS.writableSubRoot(INBOX_DATA_FOLDER);
|
|
93
|
+
this.inbox = await inbox_1.InboxOnServer.makeAndStart(cachePath, inboxSyncedFS, inboxLocalFS, {
|
|
93
94
|
address: this.address,
|
|
94
95
|
cryptor: this.cryptor,
|
|
95
96
|
random: this.random,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/*
|
|
3
|
-
Copyright (C) 2015 - 2018, 2020, 2022 3NSoft Inc.
|
|
3
|
+
Copyright (C) 2015 - 2018, 2020, 2022, 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
|
|
@@ -153,7 +153,7 @@ class MsgPacker {
|
|
|
153
153
|
const fPath = appendedPath(fsPath, fName);
|
|
154
154
|
if (entry.isFile) {
|
|
155
155
|
await fs.readonlyFile(fName);
|
|
156
|
-
this.addFileInto(folder, fName, fPath);
|
|
156
|
+
await this.addFileInto(folder, fName, fPath);
|
|
157
157
|
}
|
|
158
158
|
else if (entry.isFolder) {
|
|
159
159
|
const f = await fs.readonlySubRoot(fName);
|
|
@@ -331,8 +331,6 @@ class MsgPacker {
|
|
|
331
331
|
if (this.hasAttachments) {
|
|
332
332
|
this.main['Attachments'] = attachments;
|
|
333
333
|
}
|
|
334
|
-
// DEBUG log
|
|
335
|
-
console.log(` message packer allObjs has ${this.allObjs.size} items`);
|
|
336
334
|
}
|
|
337
335
|
throwupOnMissingParts() {
|
|
338
336
|
if (!this.meta) {
|
package/build/core/index.js
CHANGED
|
@@ -38,12 +38,12 @@ class Core {
|
|
|
38
38
|
this.appDirs = appDirs;
|
|
39
39
|
this.logger = logger;
|
|
40
40
|
this.signUpUrl = signUpUrl;
|
|
41
|
+
this.keyrings = undefined;
|
|
41
42
|
this.idManager = undefined;
|
|
42
43
|
this.closingProc = undefined;
|
|
43
44
|
this.isInitialized = false;
|
|
44
45
|
this.cryptor = makeCryptor(this.logger.logError, this.logger.logWarning);
|
|
45
46
|
this.storages = new storage_1.Storages(this.cryptor.cryptor.sbox, this.random, this.appDirs.storagePathFor);
|
|
46
|
-
this.keyrings = new keyring_1.Keyrings(this.cryptor.cryptor.sbox, this.random, this.logger);
|
|
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
|
}
|
|
@@ -265,9 +265,10 @@ class Core {
|
|
|
265
265
|
}
|
|
266
266
|
}
|
|
267
267
|
makeKeyringsCAP(requestedCAPs) {
|
|
268
|
+
var _a;
|
|
268
269
|
if (requestedCAPs.keyrings
|
|
269
270
|
&& (requestedCAPs.keyrings === 'all')) {
|
|
270
|
-
return this.keyrings.makeKeyringsCAP();
|
|
271
|
+
return (_a = this.keyrings) === null || _a === void 0 ? void 0 : _a.makeKeyringsCAP();
|
|
271
272
|
}
|
|
272
273
|
else {
|
|
273
274
|
return undefined;
|
|
@@ -292,9 +293,10 @@ class Core {
|
|
|
292
293
|
async close() {
|
|
293
294
|
if (!this.closingProc) {
|
|
294
295
|
this.closingProc = (async () => {
|
|
296
|
+
var _a;
|
|
295
297
|
if (this.isInitialized) {
|
|
296
298
|
await this.asmail.close();
|
|
297
|
-
await this.keyrings.close();
|
|
299
|
+
await ((_a = this.keyrings) === null || _a === void 0 ? void 0 : _a.close());
|
|
298
300
|
await this.storages.close();
|
|
299
301
|
this.asmail = undefined;
|
|
300
302
|
this.keyrings = undefined;
|
|
@@ -323,7 +325,8 @@ class Core {
|
|
|
323
325
|
const asmailServerConfig = new config_1.ConfigOfASMailServer(address, getSigner, this.makeResolver('asmail', this.logger.logError), this.makeNet());
|
|
324
326
|
emitBootEvent({ coreApp: constants_1.KEYRINGS_APP_NAME, message: `starting initialization` });
|
|
325
327
|
const keyringsSyncedFS = await this.storages.makeSyncedFSForApp(constants_1.KEYRINGS_APP_NAME);
|
|
326
|
-
await this.
|
|
328
|
+
const keyringsLocalFS = await this.storages.makeLocalFSForApp(constants_1.KEYRINGS_APP_NAME);
|
|
329
|
+
this.keyrings = await (0, keyring_1.makeKeyrings)(this.cryptor.cryptor.sbox, this.random, this.logger, keyringsSyncedFS, keyringsLocalFS, this.idManager.getSigner, asmailServerConfig.makeParamSetterAndGetter('init-pub-key'));
|
|
327
330
|
emitBootEvent({ coreApp: constants_1.KEYRINGS_APP_NAME, message: `✔️ initialized` });
|
|
328
331
|
emitBootEvent({ coreApp: constants_1.ASMAIL_APP_NAME, message: `starting initialization` });
|
|
329
332
|
const inboxSyncedFS = await this.storages.makeSyncedFSForApp(constants_1.ASMAIL_APP_NAME);
|
|
@@ -4,6 +4,7 @@ type JsonKeyShort = web3n.keys.JsonKeyShort;
|
|
|
4
4
|
export type MsgKeyRole = 'suggested' | 'in_use' | 'old' | 'published_intro' | 'prev_published_intro' | 'introductory';
|
|
5
5
|
export declare const KID_LENGTH = 16;
|
|
6
6
|
export declare const PID_LENGTH = 2;
|
|
7
|
+
export declare const MIN_PERIOD_FOR_PAIR: number;
|
|
7
8
|
export interface JWKeyPair {
|
|
8
9
|
skey: JsonKey;
|
|
9
10
|
pkey: JsonKey;
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
this program. If not, see <http://www.gnu.org/licenses/>.
|
|
17
17
|
*/
|
|
18
18
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
-
exports.KEY_USE = exports.PID_LENGTH = exports.KID_LENGTH = void 0;
|
|
19
|
+
exports.KEY_USE = exports.MIN_PERIOD_FOR_PAIR = exports.PID_LENGTH = exports.KID_LENGTH = void 0;
|
|
20
20
|
exports.generateKeyPair = generateKeyPair;
|
|
21
21
|
exports.generateSymmetricKey = generateSymmetricKey;
|
|
22
22
|
exports.extractSKeyBytes = extractSKeyBytes;
|
|
@@ -31,6 +31,7 @@ const buffer_utils_1 = require("../../lib-common/buffer-utils");
|
|
|
31
31
|
const rng_def_1 = require("../../lib-common/rng-def");
|
|
32
32
|
exports.KID_LENGTH = 16;
|
|
33
33
|
exports.PID_LENGTH = 2;
|
|
34
|
+
exports.MIN_PERIOD_FOR_PAIR = 15 * 60 * 1000;
|
|
34
35
|
exports.KEY_USE = {
|
|
35
36
|
PUBLIC: 'asmail-pub-key',
|
|
36
37
|
SECRET: 'asmail-sec-key',
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { IdToEmailMap } from './id-to-email-map';
|
|
2
1
|
import { MsgKeyRole } from './common';
|
|
3
2
|
import { AsyncSBoxCryptor } from 'xsp-files';
|
|
4
3
|
import { ResourcesForSending } from '../asmail/delivery/common';
|
|
@@ -28,49 +27,13 @@ type SendingResources = ResourcesForSending['correspondents'];
|
|
|
28
27
|
type ReceptionResources = ResourcesForReceiving['correspondents'];
|
|
29
28
|
export interface KeyringForASMail {
|
|
30
29
|
needIntroKeyFor: SendingResources['needIntroKeyFor'];
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
generateIntroKeysToSendMsg: SendingResources['generateIntroKeysToSendMsg'];
|
|
31
|
+
getEstablishedKeysToSendMsg: SendingResources['getEstablishedKeysToSendMsg'];
|
|
33
32
|
decrypt: ReceptionResources['msgDecryptor'];
|
|
34
33
|
close(): Promise<void>;
|
|
35
34
|
}
|
|
36
|
-
export
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
private readonly cryptor;
|
|
42
|
-
private readonly random;
|
|
43
|
-
private readonly logger;
|
|
44
|
-
/**
|
|
45
|
-
* This is a map from correspondents' canonical addresses to key objects.
|
|
46
|
-
*/
|
|
47
|
-
private readonly corrKeys;
|
|
48
|
-
readonly pairIdToEmailMap: IdToEmailMap;
|
|
49
|
-
private readonly workLabel;
|
|
50
|
-
private storage;
|
|
51
|
-
private publishedKeys;
|
|
52
|
-
constructor(cryptor: AsyncSBoxCryptor, random: AsyncRNG, logger: Logger);
|
|
53
|
-
private readonly asKeyPairsStorage;
|
|
54
|
-
private addCorrespondent;
|
|
55
|
-
init(fs: WritableFS, getSigner: GetSigner, pkeyOnServer: ParamOnServer<'init-pub-key'>): Promise<void>;
|
|
56
|
-
forASMail(): KeyringForASMail;
|
|
57
|
-
private saveChanges;
|
|
58
|
-
private needIntroKeyFor;
|
|
59
|
-
private generateKeysToSend;
|
|
60
|
-
private nextCrypto;
|
|
61
|
-
private decryptMsgKeyWithIntroPair;
|
|
62
|
-
private findEstablishedReceptionPairs;
|
|
63
|
-
private decryptMsgKeyWithEstablishedPair;
|
|
64
|
-
/**
|
|
65
|
-
* This method updates message counts and a timestamp in a given reception
|
|
66
|
-
* pair.
|
|
67
|
-
* @param rp is a sending pair, in which changes should be done. Note this
|
|
68
|
-
* must be a shared structure at this point, not a copy of a pair.
|
|
69
|
-
* @param msgCount is a message count that should be added to the pair.
|
|
70
|
-
*/
|
|
71
|
-
private updateReceivedMsgCountIn;
|
|
72
|
-
private absorbSuggestedNextKeyPair;
|
|
73
|
-
private decrypt;
|
|
74
|
-
close(): Promise<void>;
|
|
75
|
-
makeKeyringsCAP(): Service;
|
|
76
|
-
}
|
|
35
|
+
export declare function makeKeyrings(cryptor: AsyncSBoxCryptor, random: AsyncRNG, logger: Logger, fs: WritableFS, localFS: WritableFS, getSigner: GetSigner, pkeyOnServer: ParamOnServer<'init-pub-key'>): Promise<{
|
|
36
|
+
close: () => Promise<void>;
|
|
37
|
+
makeKeyringsCAP: () => Service;
|
|
38
|
+
forASMail: () => KeyringForASMail;
|
|
39
|
+
}>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/*
|
|
3
|
-
Copyright (C) 2015 - 2018, 2022, 2025 3NSoft Inc.
|
|
3
|
+
Copyright (C) 2015 - 2018, 2022, 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,124 +16,54 @@
|
|
|
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
|
-
|
|
21
|
-
const
|
|
19
|
+
exports.KEY_USE = void 0;
|
|
20
|
+
exports.makeKeyrings = makeKeyrings;
|
|
21
|
+
const peer_keys_1 = require("./peer-keys");
|
|
22
22
|
const common_1 = require("./common");
|
|
23
23
|
const async_cryptor_wrap_1 = require("../../lib-common/async-cryptor-wrap");
|
|
24
24
|
const xsp_files_1 = require("xsp-files");
|
|
25
|
-
const buffer_utils_1 = require("../../lib-common/buffer-utils");
|
|
26
25
|
const canonical_address_1 = require("../../lib-common/canonical-address");
|
|
27
|
-
const common_2 = require("../asmail/delivery/common");
|
|
28
|
-
const keyring_storage_1 = require("./keyring-storage");
|
|
29
26
|
const cryptor_work_labels_1 = require("../../lib-client/cryptor-work-labels");
|
|
30
|
-
const published_intro_key_1 = require("./published-intro-key");
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
Object.seal(this);
|
|
53
|
-
}
|
|
54
|
-
addCorrespondent(address, serialForm) {
|
|
55
|
-
const ck = (serialForm ?
|
|
56
|
-
new correspondent_keys_1.CorrespondentKeys(this.asKeyPairsStorage, this.random, undefined, serialForm) :
|
|
57
|
-
new correspondent_keys_1.CorrespondentKeys(this.asKeyPairsStorage, this.random, address));
|
|
58
|
-
if (this.corrKeys.has(ck.correspondent)) {
|
|
59
|
-
throw new Error(`Correspondent with address ${ck.correspondent} is already present.`);
|
|
60
|
-
}
|
|
61
|
-
this.corrKeys.set(ck.correspondent, ck);
|
|
62
|
-
if (serialForm) {
|
|
63
|
-
ck.mapAllKeysIntoRing();
|
|
64
|
-
}
|
|
65
|
-
return ck;
|
|
66
|
-
}
|
|
67
|
-
async init(fs, getSigner, pkeyOnServer) {
|
|
68
|
-
this.publishedKeys = await published_intro_key_1.PublishedIntroKey.makeAndInit(await fs.writableFile(FILE_FOR_INTRO_KEY_ON_SERVER), getSigner, this.random, pkeyOnServer);
|
|
69
|
-
this.storage = (0, keyring_storage_1.makeKeyringStorage)(fs);
|
|
70
|
-
await this.storage.start();
|
|
71
|
-
const serialForm = await this.storage.load();
|
|
72
|
-
if (serialForm) {
|
|
73
|
-
const json = JSON.parse(serialForm);
|
|
74
|
-
// TODO check json's fields
|
|
75
|
-
// init data
|
|
76
|
-
json.corrKeys.forEach((info) => {
|
|
77
|
-
this.addCorrespondent(undefined, info);
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
else {
|
|
81
|
-
// save initial file, as there was none initially
|
|
82
|
-
this.saveChanges();
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
forASMail() {
|
|
86
|
-
return {
|
|
87
|
-
close: this.close.bind(this),
|
|
88
|
-
decrypt: this.decrypt.bind(this),
|
|
89
|
-
generateKeysToSend: this.generateKeysToSend.bind(this),
|
|
90
|
-
needIntroKeyFor: this.needIntroKeyFor.bind(this),
|
|
91
|
-
nextCrypto: this.nextCrypto.bind(this),
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
saveChanges() {
|
|
95
|
-
// pack bytes that need to be encrypted and saved
|
|
96
|
-
const dataToSave = {
|
|
97
|
-
corrKeys: []
|
|
27
|
+
const published_intro_key_1 = require("./introductory-keys/published-intro-key");
|
|
28
|
+
const fs_sync_utils_1 = require("../../lib-client/fs-utils/fs-sync-utils");
|
|
29
|
+
const ecma_nacl_1 = require("ecma-nacl");
|
|
30
|
+
const buffer_utils_1 = require("../../lib-common/buffer-utils");
|
|
31
|
+
var common_2 = require("./common");
|
|
32
|
+
Object.defineProperty(exports, "KEY_USE", { enumerable: true, get: function () { return common_2.KEY_USE; } });
|
|
33
|
+
const INTRO_KEYS_FOLDER = 'introductory-keys';
|
|
34
|
+
const INTRO_KEY_ON_SERVER_FILE = `published-on-server.json`;
|
|
35
|
+
async function makeKeyrings(cryptor, random, logger, fs, localFS, getSigner, pkeyOnServer) {
|
|
36
|
+
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);
|
|
39
|
+
const peerKeys = await (0, peer_keys_1.makePeersKeyring)(fs, localFS, random, logger);
|
|
40
|
+
async function generateIntroKeysToSendMsg(address, introPKeyFromServer) {
|
|
41
|
+
if (introPKeyFromServer.alg !== ecma_nacl_1.box.JWK_ALG_NAME) {
|
|
42
|
+
// XXX make some standard runtime exception, for unknown alg
|
|
43
|
+
throw new Error(`Unknown alg in introductory key: ${introPKeyFromServer.alg}`);
|
|
44
|
+
}
|
|
45
|
+
const oneTime = await (0, common_1.generateKeyPair)(random);
|
|
46
|
+
const currentPair = {
|
|
47
|
+
recipientKid: introPKeyFromServer.kid,
|
|
48
|
+
senderPKey: oneTime.pkey
|
|
98
49
|
};
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
needIntroKeyFor(address) {
|
|
106
|
-
address = (0, canonical_address_1.toCanonicalAddress)(address);
|
|
107
|
-
return !this.corrKeys.has(address);
|
|
50
|
+
const msgMasterKey = ecma_nacl_1.box.calc_dhshared_key(buffer_utils_1.base64.open(introPKeyFromServer.k), buffer_utils_1.base64.open(oneTime.skey.k));
|
|
51
|
+
const nextNonce = await random(xsp_files_1.NONCE_LENGTH);
|
|
52
|
+
const encryptor = (0, async_cryptor_wrap_1.makeEncryptor)(cryptor, workLabel, msgMasterKey, nextNonce);
|
|
53
|
+
msgMasterKey.fill(0);
|
|
54
|
+
const nextMsgCrypto = await peerKeys.suggestPairForPeerIntroKey(address, introPKeyFromServer);
|
|
55
|
+
return { encryptor, currentPair, msgCount: 1, nextMsgCrypto };
|
|
108
56
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
address = (0, canonical_address_1.toCanonicalAddress)(address);
|
|
112
|
-
let ck = this.corrKeys.get(address);
|
|
113
|
-
if (!ck) {
|
|
114
|
-
if (!introPKeyFromServer) {
|
|
115
|
-
throw new Error(`There are no known keys for given address ${address} and a key from a mail server is not given either.`);
|
|
116
|
-
}
|
|
117
|
-
ck = this.addCorrespondent(address);
|
|
118
|
-
}
|
|
119
|
-
const { msgMasterKey, currentPair, msgCount } = await ck.getSendingPair(introPKeyFromServer);
|
|
57
|
+
async function getEstablishedKeysToSendMsg(address) {
|
|
58
|
+
const { msgMasterKey, currentPair, msgCount, nextMsgCrypto } = await peerKeys.getSendingCryptoWithinEstablishedPair((0, canonical_address_1.toCanonicalAddress)(address));
|
|
120
59
|
// prepare message encryptor
|
|
121
|
-
const nextNonce = await
|
|
122
|
-
const encryptor = (0, async_cryptor_wrap_1.makeEncryptor)(
|
|
60
|
+
const nextNonce = await random(xsp_files_1.NONCE_LENGTH);
|
|
61
|
+
const encryptor = (0, async_cryptor_wrap_1.makeEncryptor)(cryptor, workLabel, msgMasterKey, nextNonce);
|
|
123
62
|
msgMasterKey.fill(0);
|
|
124
|
-
return { encryptor, currentPair, msgCount };
|
|
63
|
+
return { encryptor, currentPair, msgCount, nextMsgCrypto };
|
|
125
64
|
}
|
|
126
|
-
async
|
|
127
|
-
|
|
128
|
-
let ck = this.corrKeys.get(address);
|
|
129
|
-
if (!ck) {
|
|
130
|
-
throw new Error(`No correspondent keys found for ${address}`);
|
|
131
|
-
}
|
|
132
|
-
const suggestPair = await ck.suggestPair();
|
|
133
|
-
return suggestPair;
|
|
134
|
-
}
|
|
135
|
-
async decryptMsgKeyWithIntroPair(recipientKid, senderPKey, getMainObjHeader) {
|
|
136
|
-
const recipKey = this.publishedKeys.find(recipientKid);
|
|
65
|
+
async function decryptMsgKeyWithIntroPair(recipientKid, senderPKey, getMainObjHeader) {
|
|
66
|
+
const recipKey = publishedKeys.find(recipientKid);
|
|
137
67
|
if (!recipKey) {
|
|
138
68
|
return;
|
|
139
69
|
}
|
|
@@ -142,16 +72,17 @@ class Keyrings {
|
|
|
142
72
|
if (h.length < msgKeyPackLen) {
|
|
143
73
|
return;
|
|
144
74
|
}
|
|
145
|
-
const
|
|
75
|
+
const msgMasterKey = ecma_nacl_1.box.calc_dhshared_key(buffer_utils_1.base64.open(senderPKey), buffer_utils_1.base64.open(recipKey.pair.skey.k));
|
|
76
|
+
const masterDecr = (0, async_cryptor_wrap_1.makeDecryptor)(cryptor, workLabel, msgMasterKey);
|
|
146
77
|
try {
|
|
147
78
|
const mainObjFileKey = await masterDecr.open(h.subarray(0, msgKeyPackLen));
|
|
148
|
-
const
|
|
79
|
+
const decrInfo = {
|
|
149
80
|
correspondent: undefined,
|
|
150
81
|
keyStatus: recipKey.role,
|
|
151
82
|
key: mainObjFileKey,
|
|
152
83
|
msgKeyPackLen
|
|
153
84
|
};
|
|
154
|
-
return
|
|
85
|
+
return { decrInfo, introKey: recipKey.pair };
|
|
155
86
|
}
|
|
156
87
|
catch (err) {
|
|
157
88
|
if (!err.failedCipherVerification) {
|
|
@@ -162,60 +93,35 @@ class Keyrings {
|
|
|
162
93
|
masterDecr.destroy();
|
|
163
94
|
}
|
|
164
95
|
}
|
|
165
|
-
|
|
166
|
-
const
|
|
167
|
-
if (!emails) {
|
|
168
|
-
return;
|
|
169
|
-
}
|
|
170
|
-
const decryptors = [];
|
|
171
|
-
for (const email of emails) {
|
|
172
|
-
const ck = this.corrKeys.get(email);
|
|
173
|
-
if (!ck) {
|
|
174
|
-
return;
|
|
175
|
-
}
|
|
176
|
-
const rp = ck.getReceivingPair(pid);
|
|
177
|
-
if (!rp) {
|
|
178
|
-
return;
|
|
179
|
-
}
|
|
180
|
-
decryptors.push({
|
|
181
|
-
correspondent: email,
|
|
182
|
-
role: rp.role,
|
|
183
|
-
pair: rp.pair
|
|
184
|
-
});
|
|
185
|
-
}
|
|
186
|
-
return decryptors;
|
|
187
|
-
}
|
|
188
|
-
async decryptMsgKeyWithEstablishedPair(pid, getMainObjHeader) {
|
|
189
|
-
const pairs = this.findEstablishedReceptionPairs(pid);
|
|
96
|
+
async function decryptMsgKeyWithEstablishedPair(pid, getMainObjHeader) {
|
|
97
|
+
const pairs = peerKeys.findEstablishedReceptionPairs(pid);
|
|
190
98
|
if (!pairs) {
|
|
191
99
|
return;
|
|
192
100
|
}
|
|
193
101
|
// try to open main object's file key from a header
|
|
194
102
|
const h = await getMainObjHeader();
|
|
195
|
-
for (const {
|
|
196
|
-
const
|
|
197
|
-
|
|
198
|
-
masterKey.fill(0);
|
|
103
|
+
for (const { msgMasterKey, pairAlg, peerCAddr, ratchetStage, peerKId, recipientKId } of pairs) {
|
|
104
|
+
const masterDecr = (0, async_cryptor_wrap_1.makeDecryptor)(cryptor, workLabel, msgMasterKey);
|
|
105
|
+
msgMasterKey.fill(0);
|
|
199
106
|
try {
|
|
200
|
-
const msgKeyPackLen =
|
|
107
|
+
const msgKeyPackLen = (0, common_1.msgKeyPackSizeFor)(pairAlg);
|
|
201
108
|
if (h.length < msgKeyPackLen) {
|
|
202
109
|
continue;
|
|
203
110
|
}
|
|
204
111
|
const mainObjFileKey = await masterDecr.open(h.subarray(0, msgKeyPackLen));
|
|
205
112
|
const keyInfo = {
|
|
206
|
-
correspondent:
|
|
207
|
-
keyStatus:
|
|
113
|
+
correspondent: peerKeys.getPeerAddressForCanonical(peerCAddr) || peerCAddr,
|
|
114
|
+
keyStatus: ratchetStage,
|
|
208
115
|
key: mainObjFileKey,
|
|
209
116
|
msgKeyPackLen
|
|
210
117
|
};
|
|
211
118
|
// set pair as in use
|
|
212
119
|
if (keyInfo.keyStatus === 'suggested') {
|
|
213
|
-
|
|
214
|
-
corrKeys.markPairAsInUse(pair);
|
|
120
|
+
await peerKeys.markPairAsInUse(peerCAddr, peerKId, recipientKId);
|
|
215
121
|
}
|
|
216
122
|
return {
|
|
217
123
|
keyInfo,
|
|
218
|
-
incrMsgCount: msgCount =>
|
|
124
|
+
incrMsgCount: msgCount => peerKeys.updateReceivedMsgCountIn(peerCAddr, peerKId, recipientKId, msgCount, Date.now())
|
|
219
125
|
};
|
|
220
126
|
}
|
|
221
127
|
catch (err) {
|
|
@@ -228,58 +134,13 @@ class Keyrings {
|
|
|
228
134
|
}
|
|
229
135
|
}
|
|
230
136
|
}
|
|
231
|
-
|
|
232
|
-
* This method updates message counts and a timestamp in a given reception
|
|
233
|
-
* pair.
|
|
234
|
-
* @param rp is a sending pair, in which changes should be done. Note this
|
|
235
|
-
* must be a shared structure at this point, not a copy of a pair.
|
|
236
|
-
* @param msgCount is a message count that should be added to the pair.
|
|
237
|
-
*/
|
|
238
|
-
updateReceivedMsgCountIn(rp, msgCount) {
|
|
239
|
-
const lastTS = Date.now();
|
|
240
|
-
if (!rp.receivedMsgs) {
|
|
241
|
-
rp.receivedMsgs = { counts: [], lastTS };
|
|
242
|
-
}
|
|
243
|
-
(0, common_2.addToNumberLineSegments)(rp.receivedMsgs.counts, msgCount);
|
|
244
|
-
rp.receivedMsgs.lastTS = lastTS;
|
|
245
|
-
this.saveChanges();
|
|
246
|
-
}
|
|
247
|
-
absorbSuggestedNextKeyPair(correspondent, pair) {
|
|
248
|
-
let ck = this.corrKeys.get(correspondent);
|
|
249
|
-
if (!ck) {
|
|
250
|
-
ck = this.addCorrespondent(correspondent);
|
|
251
|
-
}
|
|
252
|
-
if (pair.isSenderIntroKey) {
|
|
253
|
-
const usedIntro = this.publishedKeys.find(pair.senderKid);
|
|
254
|
-
if (!usedIntro) {
|
|
255
|
-
throw new Error(`Recently used published intro key is not found`);
|
|
256
|
-
}
|
|
257
|
-
ck.ratchetUpSendingPair(pair, usedIntro.pair);
|
|
258
|
-
}
|
|
259
|
-
else {
|
|
260
|
-
ck.ratchetUpSendingPair(pair);
|
|
261
|
-
}
|
|
262
|
-
// if (ck) {
|
|
263
|
-
// ck.ratchetUpSendingPair(pair);
|
|
264
|
-
// } else {
|
|
265
|
-
// if (!pair.isSenderIntroKey) {
|
|
266
|
-
// throw new Error(`Expected addition of correspondent to be done, when new `);
|
|
267
|
-
// }
|
|
268
|
-
// const usedIntro = this.publishedKeys.find(pair.senderKid);
|
|
269
|
-
// if (!usedIntro) {
|
|
270
|
-
// throw new Error(`Recently used published intro key is not found`);
|
|
271
|
-
// }
|
|
272
|
-
// ck = this.addCorrespondent(correspondent);
|
|
273
|
-
// ck.ratchetUpSendingPair(pair, usedIntro.pair);
|
|
274
|
-
// }
|
|
275
|
-
this.saveChanges();
|
|
276
|
-
}
|
|
277
|
-
async decrypt(msgMeta, getMainObjHeader, getOpenedMsg, checkMidKeyCerts) {
|
|
137
|
+
async function decrypt(msgMeta, getMainObjHeader, getOpenedMsg, checkMidKeyCerts) {
|
|
278
138
|
let decrInfo;
|
|
139
|
+
let introKey = undefined;
|
|
279
140
|
let incrMsgCount;
|
|
280
141
|
let openedMsg;
|
|
281
142
|
if (msgMeta.pid) {
|
|
282
|
-
const r = await
|
|
143
|
+
const r = await decryptMsgKeyWithEstablishedPair(msgMeta.pid, getMainObjHeader);
|
|
283
144
|
if (!r) {
|
|
284
145
|
return;
|
|
285
146
|
}
|
|
@@ -288,10 +149,12 @@ class Keyrings {
|
|
|
288
149
|
openedMsg = await getOpenedMsg(decrInfo.key, decrInfo.msgKeyPackLen);
|
|
289
150
|
}
|
|
290
151
|
else {
|
|
291
|
-
|
|
292
|
-
if (!
|
|
152
|
+
const r = await decryptMsgKeyWithIntroPair(msgMeta.recipientKid, msgMeta.senderPKey, getMainObjHeader);
|
|
153
|
+
if (!r) {
|
|
293
154
|
return;
|
|
294
155
|
}
|
|
156
|
+
decrInfo = r.decrInfo;
|
|
157
|
+
introKey = r.introKey;
|
|
295
158
|
openedMsg = await getOpenedMsg(decrInfo.key, decrInfo.msgKeyPackLen);
|
|
296
159
|
const certs = openedMsg.introCryptoCerts;
|
|
297
160
|
const { address, pkey } = await checkMidKeyCerts(certs);
|
|
@@ -310,46 +173,50 @@ class Keyrings {
|
|
|
310
173
|
incrMsgCount(openedMsg.msgCount);
|
|
311
174
|
}
|
|
312
175
|
// absorb next crypto
|
|
313
|
-
const
|
|
314
|
-
if (
|
|
176
|
+
const suggestedPair = openedMsg.nextCrypto;
|
|
177
|
+
if (suggestedPair) {
|
|
315
178
|
try {
|
|
316
|
-
if (
|
|
317
|
-
if (
|
|
318
|
-
throw new Error(`Introductory message is not referencing used intro key in the next crypto`);
|
|
319
|
-
}
|
|
320
|
-
if (msgMeta.recipientKid !== pair.senderKid) {
|
|
179
|
+
if (introKey) {
|
|
180
|
+
if (introKey.pkey.kid !== suggestedPair.senderKid) {
|
|
321
181
|
throw new Error(`Introductory message is referencing wrong key in the next crypto`);
|
|
322
182
|
}
|
|
183
|
+
await peerKeys.absorbNextPairSuggestedByPeer(decrInfo.correspondent, suggestedPair, introKey);
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
await peerKeys.absorbNextPairSuggestedByPeer(decrInfo.correspondent, suggestedPair);
|
|
323
187
|
}
|
|
324
|
-
this.absorbSuggestedNextKeyPair(decrInfo.correspondent, pair);
|
|
325
188
|
}
|
|
326
189
|
catch (err) {
|
|
327
|
-
|
|
190
|
+
logger.logError(err, `Fail to absorb next suggested key for messaging`);
|
|
328
191
|
}
|
|
329
192
|
}
|
|
330
193
|
return { decrInfo, openedMsg };
|
|
331
194
|
}
|
|
332
195
|
;
|
|
333
|
-
async close() {
|
|
334
|
-
await
|
|
335
|
-
await
|
|
196
|
+
async function close() {
|
|
197
|
+
await publishedKeys.close();
|
|
198
|
+
await peerKeys.close();
|
|
336
199
|
}
|
|
337
|
-
makeKeyringsCAP() {
|
|
200
|
+
function makeKeyringsCAP() {
|
|
338
201
|
const w = {
|
|
339
|
-
introKeyOnASMailServer:
|
|
340
|
-
getCorrespondentKeys: async (
|
|
341
|
-
var _a;
|
|
342
|
-
const cAddr = (0, canonical_address_1.toCanonicalAddress)(addr);
|
|
343
|
-
return (_a = this.corrKeys.get(cAddr)) === null || _a === void 0 ? void 0 : _a.toInfo();
|
|
344
|
-
}
|
|
202
|
+
introKeyOnASMailServer: publishedKeys.makeIntroKeyCAP(),
|
|
203
|
+
getCorrespondentKeys: async (peerAddr) => peerKeys.getPeerKeysInfo(peerAddr)
|
|
345
204
|
};
|
|
346
205
|
return Object.freeze(w);
|
|
347
206
|
}
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
207
|
+
function forASMail() {
|
|
208
|
+
return {
|
|
209
|
+
close,
|
|
210
|
+
decrypt,
|
|
211
|
+
generateIntroKeysToSendMsg,
|
|
212
|
+
getEstablishedKeysToSendMsg,
|
|
213
|
+
needIntroKeyFor: peerKeys.needIntroKeyFor
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
return {
|
|
217
|
+
close,
|
|
218
|
+
makeKeyringsCAP,
|
|
219
|
+
forASMail
|
|
220
|
+
};
|
|
354
221
|
}
|
|
355
222
|
Object.freeze(exports);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ParamOnServer } from '../../../lib-client/asmail/service-config';
|
|
2
|
+
import { AsyncRNG } from '../../../lib-common/rng-def';
|
|
3
|
+
import { GetSigner } from '../../id-manager';
|
|
4
|
+
import { JWKeyPair, MsgKeyRole } from '../common';
|
|
5
|
+
type WritableFile = web3n.files.WritableFile;
|
|
6
|
+
type IntroKeyCAP = web3n.keys.Keyrings['introKeyOnASMailServer'];
|
|
7
|
+
export declare function makeHolderOfPublishedIntroKey(file: WritableFile, getSigner: GetSigner, random: AsyncRNG, pkeyOnServer: ParamOnServer<'init-pub-key'>): Promise<{
|
|
8
|
+
startExpiryCheckProcess: () => void;
|
|
9
|
+
close: () => Promise<void>;
|
|
10
|
+
makeIntroKeyCAP: () => IntroKeyCAP;
|
|
11
|
+
find: (kid: string) => {
|
|
12
|
+
role: MsgKeyRole;
|
|
13
|
+
pair: JWKeyPair;
|
|
14
|
+
replacedAt?: number;
|
|
15
|
+
} | undefined;
|
|
16
|
+
}>;
|
|
17
|
+
export {};
|