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
@@ -299,6 +299,7 @@ declare namespace web3n.asmail {
299
299
  objNotFound?: true;
300
300
  objId?: string;
301
301
  msgIsBroken?: true;
302
+ failToDecrypt?: true;
302
303
  }
303
304
 
304
305
  interface ASMailSendException extends RuntimeException {
@@ -1172,7 +1172,7 @@ declare namespace web3n.files {
1172
1172
 
1173
1173
  interface FileChangeEvent extends FSChangeEvent {
1174
1174
  type: 'file-change';
1175
- newVersion?: number;
1175
+ newVersion: number;
1176
1176
  }
1177
1177
 
1178
1178
  type RemoteEvent = RemoteVersionArchivalEvent | RemoteArchVerRemovalEvent |
@@ -132,9 +132,13 @@ class WIP {
132
132
  const recipient = this.state.recipient;
133
133
  const sp = this.msg.r.correspondents.paramsForSendingTo(recipient);
134
134
  if (sp) {
135
+ // DEBUG
136
+ // console.log(`sending params for sending to ${recipient} invitation are`, sp);
135
137
  this.sender = await sender_1.MailSender.fresh(this.msg.r.makeNet(), this.msg.r.asmailResolver, (sp.auth ? senderAddress : undefined), recipient, sp.invitation);
136
138
  }
137
139
  else {
140
+ // DEBUG
141
+ // console.log(`have no sending params to use for sending to ${recipient}`);
138
142
  this.sender = await sender_1.MailSender.fresh(this.msg.r.makeNet(), this.msg.r.asmailResolver, undefined, recipient);
139
143
  }
140
144
  await this.sender.startSession();
@@ -72,35 +72,12 @@ export interface ResourcesForReceiving {
72
72
  * messages have not been removed via direct action or due to expiry.
73
73
  * This object is also responsible for expiring messages on the server.
74
74
  */
75
- export declare class InboxOnServer {
76
- private readonly r;
77
- private readonly msgReceiver;
78
- private readonly storages;
79
- private readonly cryptor;
80
- private readonly random;
81
- private readonly downloader;
82
- private readonly cache;
83
- private readonly index;
84
- private readonly logError;
85
- private readonly inboxEvents;
86
- private readonly procs;
87
- private readonly recentlyOpenedMsgs;
88
- private constructor();
89
- static makeAndStart(cachePath: string, syncedFS: WritableFS, localFS: WritableFS, r: ResourcesForReceiving): Promise<InboxOnServer>;
90
- close(): Promise<void>;
91
- makeCAP(): InboxService;
92
- private removeMsg;
93
- private removeMsgFromServerAndCache;
94
- private msgFromDiskOrDownload;
95
- private startCachingAndAddKeyToIndex;
96
- private markOwnParams;
97
- private absorbSendingParams;
98
- private listMsgs;
99
- private listNewMsgs;
100
- private getMsg;
101
- private msgToUIForm;
102
- suspendNetworkActivity(): void;
103
- resumeNetworkActivity(): void;
104
- get connectivityEvent$(): import("rxjs").Observable<import("./inbox-events").InboxConnectionStatus>;
105
- }
75
+ export type InboxOnServer = Awaited<ReturnType<typeof makeInboxOnServer>>;
76
+ export declare function makeInboxOnServer(cachePath: string, syncedFS: WritableFS, localFS: WritableFS, r: ResourcesForReceiving): Promise<{
77
+ connectivityEvent$: import("rxjs").Observable<import("./inbox-events").InboxConnectionStatus>;
78
+ resumeNetworkActivity: () => void;
79
+ suspendNetworkActivity: () => void;
80
+ close: () => Promise<void>;
81
+ makeCAP: () => InboxService;
82
+ }>;
106
83
  export {};
@@ -16,8 +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.InboxOnServer = void 0;
20
- const error_1 = require("../../../lib-common/exceptions/error");
19
+ exports.makeInboxOnServer = makeInboxOnServer;
21
20
  const synced_1 = require("../../../lib-common/processes/synced");
22
21
  const recipient_1 = require("../../../lib-client/asmail/recipient");
23
22
  const opener_1 = require("../msg/opener");
@@ -32,189 +31,165 @@ const cached_msgs_1 = require("./cached-msgs");
32
31
  const timed_cache_1 = require("../../../lib-common/timed-cache");
33
32
  const fs_sync_utils_1 = require("../../../lib-client/fs-utils/fs-sync-utils");
34
33
  const MSG_INDEX_FOLDER = 'msg-index';
35
- /**
36
- * Instance of this class represents inbox-on-mail-server.
37
- * It uses api to manage messages on a ASMail server, caching and recording
38
- * some information to allow faster response, and to keep message keys, while
39
- * messages have not been removed via direct action or due to expiry.
40
- * This object is also responsible for expiring messages on the server.
41
- */
42
- class InboxOnServer {
43
- constructor(r, msgReceiver, storages, cryptor, random, downloader, cache, index, logError) {
44
- this.r = r;
45
- this.msgReceiver = msgReceiver;
46
- this.storages = storages;
47
- this.cryptor = cryptor;
48
- this.random = random;
49
- this.downloader = downloader;
50
- this.cache = cache;
51
- this.index = index;
52
- this.logError = logError;
53
- this.procs = new synced_1.NamedProcs();
54
- this.recentlyOpenedMsgs = (0, timed_cache_1.makeTimedCache)(60 * 1000);
55
- this.inboxEvents = new inbox_events_1.InboxEvents(this.msgReceiver, this.getMsg.bind(this), this.listNewMsgs.bind(this), this.removeMsg.bind(this), this.logError);
56
- Object.seal(this);
34
+ async function makeInboxOnServer(cachePath, syncedFS, localFS, r) {
35
+ const procs = new synced_1.NamedProcs();
36
+ const recentlyOpenedMsgs = (0, timed_cache_1.makeTimedCache)(60 * 1000);
37
+ const { getStorages, cryptor, random, logError, } = r;
38
+ (0, file_1.ensureCorrectFS)(syncedFS, 'synced', true);
39
+ const indexSyncedFS = await (0, fs_sync_utils_1.getOrMakeDirOnInit)(syncedFS, MSG_INDEX_FOLDER);
40
+ const indexLocalFS = await localFS.writableSubRoot(MSG_INDEX_FOLDER);
41
+ const msgReceiver = new recipient_1.MailRecipient(r.address, r.getSigner, () => r.asmailResolver(r.address), r.makeNet());
42
+ const downloader = new msg_downloader_1.MsgDownloader(msgReceiver);
43
+ const cache = await cached_msgs_1.CachedMessages.makeFor(cachePath, downloader, r.logError);
44
+ const index = await (0, msg_indexing_1.makeMsgIndex)(indexSyncedFS, indexLocalFS, r.logError);
45
+ const inboxEvents = new inbox_events_1.InboxEvents(msgReceiver, getMsg, listNewMsgs, removeMsg, r.logError);
46
+ async function close() {
47
+ index.stopSyncing();
48
+ inboxEvents.close();
57
49
  }
58
- static async makeAndStart(cachePath, syncedFS, localFS, r) {
59
- try {
60
- (0, file_1.ensureCorrectFS)(syncedFS, 'synced', true);
61
- const msgReceiver = new recipient_1.MailRecipient(r.address, r.getSigner, () => r.asmailResolver(r.address), r.makeNet());
62
- const downloader = new msg_downloader_1.MsgDownloader(msgReceiver);
63
- const cache = await cached_msgs_1.CachedMessages.makeFor(cachePath, downloader, r.logError);
64
- const indexSyncedFS = await (0, fs_sync_utils_1.getOrMakeSyncedDirOnInit)(syncedFS, MSG_INDEX_FOLDER);
65
- const indexLocalFS = await localFS.writableSubRoot(MSG_INDEX_FOLDER);
66
- const index = await (0, msg_indexing_1.makeMsgIndex)(indexSyncedFS, indexLocalFS, r.logError);
67
- const inbox = new InboxOnServer(r.correspondents, msgReceiver, r.getStorages, r.cryptor, r.random, downloader, cache, index, r.logError);
68
- return inbox;
69
- }
70
- catch (err) {
71
- throw (0, error_1.errWithCause)(err, 'Failed to initialize Inbox');
72
- }
73
- }
74
- async close() {
75
- this.index.stopSyncing();
76
- this.inboxEvents.close();
77
- }
78
- makeCAP() {
50
+ function makeCAP() {
79
51
  const service = {
80
- getMsg: this.getMsg.bind(this),
81
- listMsgs: this.listMsgs.bind(this),
82
- removeMsg: this.removeMsg.bind(this),
83
- subscribe: this.inboxEvents.subscribe.bind(this.inboxEvents)
52
+ getMsg,
53
+ listMsgs,
54
+ removeMsg,
55
+ subscribe: inboxEvents.subscribe.bind(inboxEvents)
84
56
  };
85
57
  return Object.freeze(service);
86
58
  }
87
- async removeMsg(msgId) {
59
+ async function removeMsg(msgId) {
88
60
  // check for an already started process
89
61
  const procId = 'removal of ' + msgId;
90
- const promise = this.procs.latestTaskAtThisMoment(procId);
62
+ const promise = procs.latestTaskAtThisMoment(procId);
91
63
  if (promise) {
92
64
  return promise;
93
65
  }
94
66
  // start removal process
95
- return this.procs.start(procId, (async () => {
67
+ return procs.start(procId, (async () => {
96
68
  await Promise.all([
97
- this.index.remove(msgId),
98
- this.removeMsgFromServerAndCache(msgId)
69
+ index.remove(msgId),
70
+ removeMsgFromServerAndCache(msgId)
99
71
  ]);
100
72
  }));
101
73
  }
102
- async removeMsgFromServerAndCache(msgId) {
74
+ async function removeMsgFromServerAndCache(msgId) {
103
75
  await Promise.all([
104
- this.cache.deleteMsg(msgId),
76
+ cache.deleteMsg(msgId),
105
77
  // XXX the following is suspicious, as it swallows other exceptions too
106
- this.msgReceiver.removeMsg(msgId).catch(() => { })
78
+ msgReceiver.removeMsg(msgId).catch(() => { })
107
79
  ]);
108
80
  }
109
- async msgFromDiskOrDownload(msgId) {
110
- const msgOnDisk = await this.cache.findMsg(msgId);
81
+ async function msgFromDiskOrDownload(msgId) {
82
+ const msgOnDisk = await cache.findMsg(msgId);
111
83
  if (msgOnDisk) {
112
84
  return msgOnDisk;
113
85
  }
114
- const meta = await this.downloader.getMsgMeta(msgId);
115
- return await this.cache.addMsg(msgId, meta);
86
+ const meta = await downloader.getMsgMeta(msgId);
87
+ return await cache.addMsg(msgId, meta);
88
+ }
89
+ function checkerOfMidKeyCerts(deliveryTS) {
90
+ return (certs) => (0, key_verification_1.checkAndExtractPKeyWithAddress)(msgReceiver.getNet(), r.correspondents.midResolver, certs, Math.round(deliveryTS / 1000));
91
+ }
92
+ function msgReadingAndOpening(msgId, mainObjId, msgOnDisk) {
93
+ // lazy main obj source
94
+ let mainObjSrc = undefined;
95
+ async function getMainObjHeader() {
96
+ if (!mainObjSrc) {
97
+ mainObjSrc = await msgOnDisk.getMsgObj(mainObjId);
98
+ }
99
+ return mainObjSrc.readHeader();
100
+ }
101
+ async function getOpenedMsg(mainObjFileKey, msgKeyPackLen) {
102
+ if (!mainObjSrc) {
103
+ mainObjSrc = await msgOnDisk.getMsgObj(mainObjId);
104
+ }
105
+ return await (0, opener_1.openMsg)(msgId, mainObjId, mainObjSrc, msgKeyPackLen, mainObjFileKey, cryptor);
106
+ }
107
+ return {
108
+ getMainObjHeader, getOpenedMsg
109
+ };
116
110
  }
117
- async startCachingAndAddKeyToIndex(msgId) {
118
- const msgOnDisk = await this.msgFromDiskOrDownload(msgId);
111
+ async function startCachingAndAddKeyToIndex(msgId) {
112
+ const msgOnDisk = await msgFromDiskOrDownload(msgId);
119
113
  const meta = await msgOnDisk.getMsgMeta();
114
+ const { getMainObjHeader, getOpenedMsg } = msgReadingAndOpening(msgId, meta.extMeta.objIds[0], msgOnDisk);
120
115
  try {
121
- // setup closures, some memoized, for use by keyring
122
- let mainObjSrc = undefined;
123
- const mainObjId = meta.extMeta.objIds[0];
124
- const getMainObjHeader = async () => {
125
- if (!mainObjSrc) {
126
- mainObjSrc = await msgOnDisk.getMsgObj(mainObjId);
127
- }
128
- return mainObjSrc.readHeader();
129
- };
130
- const getOpenedMsg = async (mainObjFileKey, msgKeyPackLen) => {
131
- if (!mainObjSrc) {
132
- mainObjSrc = await msgOnDisk.getMsgObj(mainObjId);
133
- }
134
- const openedMsg = await (0, opener_1.openMsg)(msgId, mainObjId, mainObjSrc, msgKeyPackLen, mainObjFileKey, this.cryptor);
135
- return openedMsg;
136
- };
137
- const checkMidKeyCerts = (certs) => {
138
- return (0, key_verification_1.checkAndExtractPKeyWithAddress)(this.msgReceiver.getNet(), this.r.midResolver, certs, Math.round(msgOnDisk.deliveryTS / 1000));
139
- };
140
- const decrOut = await this.r.msgDecryptor(meta.extMeta, getMainObjHeader, getOpenedMsg, checkMidKeyCerts);
116
+ const decrOut = await r.correspondents.msgDecryptor(meta.extMeta, getMainObjHeader, getOpenedMsg, checkerOfMidKeyCerts(msgOnDisk.deliveryTS));
141
117
  if (decrOut) {
142
118
  const { decrInfo, openedMsg } = decrOut;
143
119
  openedMsg.setMsgKeyRole(decrInfo.keyStatus);
120
+ // XXX we have never used this part of protocol, should it be removed at all from ASMail protocol?
144
121
  checkServerAuthIfPresent(meta, decrInfo);
145
122
  // add records cache and to index
146
- this.recentlyOpenedMsgs.set(msgId, openedMsg);
123
+ recentlyOpenedMsgs.set(msgId, openedMsg);
147
124
  const msgInfo = {
148
125
  msgType: openedMsg.getSection('Msg Type'),
149
126
  msgId,
150
127
  deliveryTS: msgOnDisk.deliveryTS
151
128
  };
152
- await this.index.add(msgInfo, decrInfo);
129
+ await index.add(msgInfo, decrInfo);
153
130
  await Promise.all([
154
- this.absorbSendingParams(openedMsg),
155
- this.markOwnParams(meta, openedMsg.sender)
131
+ absorbSendingParams(openedMsg),
132
+ markOwnParams(meta, openedMsg.sender)
156
133
  ]);
157
134
  }
158
135
  else {
159
136
  // check, if msg has already been indexed
160
- const knownDecr = await this.index.getKeyFor(msgId, msgOnDisk.deliveryTS);
137
+ const knownDecr = await index.getKeyFor(msgId, msgOnDisk.deliveryTS);
161
138
  if (!knownDecr) {
162
- await msgOnDisk.updateMsgKeyStatus('not-found');
163
139
  return false;
164
140
  }
165
- // TODO try to open main message, just as a check
166
141
  }
167
- await msgOnDisk.updateMsgKeyStatus('ok');
168
142
  return true;
169
143
  }
170
144
  catch (exc) {
171
- await this.logError(exc, `Problem with opening message ${msgId}`);
172
- if (msgOnDisk.keyStatus !== 'ok') {
173
- await msgOnDisk.updateMsgKeyStatus('fail');
174
- }
145
+ await logError(exc, `Problem with opening message ${msgId}`);
175
146
  return false;
176
147
  }
177
148
  }
178
- async markOwnParams(meta, sender) {
149
+ async function markOwnParams(meta, sender) {
150
+ // DEBUG
151
+ // console.log(` markOwnParams (if invite used) ->`, {sender, 'meta.invite':meta.invite});
179
152
  if (!meta.invite) {
180
153
  return;
181
154
  }
182
- await this.r.markOwnSendingParamsAsUsed(sender, meta.invite);
155
+ await r.correspondents.markOwnSendingParamsAsUsed(sender, meta.invite);
183
156
  }
184
- async absorbSendingParams(openedMsg) {
157
+ async function absorbSendingParams(openedMsg) {
185
158
  const sendingParams = openedMsg.nextSendingParams;
159
+ // DEBUG
160
+ // console.log(` openedMsg.nextSendingParams ->`, openedMsg.nextSendingParams);
186
161
  if (!sendingParams) {
187
162
  return;
188
163
  }
189
164
  const address = openedMsg.sender;
190
- await this.r.saveParamsForSendingTo(address, sendingParams);
165
+ await r.correspondents.saveParamsForSendingTo(address, sendingParams);
191
166
  }
192
- async listMsgs(fromTS) {
193
- const checkServer = true; // XXX in future this will be an option from req
194
- if (!checkServer) {
195
- return this.index.listMsgs(fromTS);
196
- }
197
- // check for an already started process
198
- const procId = 'listing msgs';
199
- const promise = this.procs.latestTaskAtThisMoment(procId);
167
+ function debouncingProc(procId, action) {
168
+ const promise = procs.latestTaskAtThisMoment(procId);
200
169
  if (promise) {
201
170
  return promise;
202
171
  }
203
- // start message listing process
204
- return this.procs.start(procId, async () => {
172
+ return procs.start(procId, action);
173
+ }
174
+ async function listMsgs(fromTS) {
175
+ const checkServer = true; // XXX in future this will be an option from req
176
+ if (!checkServer) {
177
+ return index.listMsgs(fromTS);
178
+ }
179
+ return debouncingProc('listing msgs', async () => {
205
180
  // message listing info is located in index, yet, process involves
206
181
  // getting and caching messages' metadata
207
182
  let msgIds;
208
183
  try {
209
- msgIds = await this.msgReceiver.listMsgs(fromTS);
184
+ msgIds = await msgReceiver.listMsgs(fromTS);
210
185
  }
211
186
  catch (exc) {
212
187
  if (exc.type !== 'connect') {
213
188
  throw exc;
214
189
  }
215
- return this.index.listMsgs(fromTS);
190
+ return index.listMsgs(fromTS);
216
191
  }
217
- const indexedMsgs = await this.index.listMsgs(fromTS);
192
+ const indexedMsgs = await index.listMsgs(fromTS);
218
193
  for (const info of indexedMsgs) {
219
194
  const ind = msgIds.indexOf(info.msgId);
220
195
  if (ind >= 0) {
@@ -224,17 +199,17 @@ class InboxOnServer {
224
199
  if (msgIds.length === 0) {
225
200
  return indexedMsgs;
226
201
  }
227
- await Promise.all(msgIds.map(msgId => this.startCachingAndAddKeyToIndex(msgId)
202
+ await Promise.all(msgIds.map(msgId => startCachingAndAddKeyToIndex(msgId)
228
203
  .catch(async (exc) => {
229
- await this.logError(exc, `Failed to start caching message ${msgId}`);
204
+ await logError(exc, `Failed to start caching message ${msgId}`);
230
205
  })));
231
- return this.index.listMsgs(fromTS);
206
+ return index.listMsgs(fromTS);
232
207
  });
233
208
  }
234
- async listNewMsgs(fromTS) {
235
- const msgIds = await this.msgReceiver.listMsgs(fromTS);
209
+ async function listNewMsgs(fromTS) {
210
+ const msgIds = await msgReceiver.listMsgs(fromTS);
236
211
  // remove from listing messages already in index
237
- const indexedMsgs = await this.index.listMsgs(fromTS);
212
+ const indexedMsgs = await index.listMsgs(fromTS);
238
213
  for (const info of indexedMsgs) {
239
214
  const ind = msgIds.indexOf(info.msgId);
240
215
  if (ind >= 0) {
@@ -245,54 +220,39 @@ class InboxOnServer {
245
220
  return [];
246
221
  }
247
222
  // cache and index these
248
- await Promise.all(msgIds.map(msgId => this.startCachingAndAddKeyToIndex(msgId)));
223
+ await Promise.all(msgIds.map(msgId => startCachingAndAddKeyToIndex(msgId)));
249
224
  // get info's from index, focusing on specific messages only
250
- return (await this.index.listMsgs(fromTS)).filter(({ msgId }) => msgIds.includes(msgId));
225
+ return (await index.listMsgs(fromTS)).filter(({ msgId }) => msgIds.includes(msgId));
251
226
  }
252
- async getMsg(msgId) {
227
+ async function getMsg(msgId) {
253
228
  if (!msgId || (typeof msgId !== 'string')) {
254
229
  throw `Given message id is not a non-empty string`;
255
230
  }
256
- const procId = `get msg #${msgId}`;
257
- const promise = this.procs.latestTaskAtThisMoment(procId);
258
- if (promise) {
259
- return promise;
260
- }
261
- return this.procs.start(procId, async () => {
262
- const msgOnDisk = await this.msgFromDiskOrDownload(msgId);
263
- let msg = this.recentlyOpenedMsgs.get(msgId);
231
+ return debouncingProc(`get msg #${msgId}`, async () => {
232
+ const msgOnDisk = await msgFromDiskOrDownload(msgId);
233
+ let msg = recentlyOpenedMsgs.get(msgId);
264
234
  if (msg) {
265
- return this.msgToUIForm(msg, msgOnDisk.deliveryTS, msgOnDisk);
266
- }
267
- if ((msgOnDisk.keyStatus === 'not-found')
268
- || (msgOnDisk.keyStatus === 'fail')) {
269
- // XXX
270
- // message cannot be opened, and should be removed
271
- // await Promise.all([
272
- // this.index.remove(msgInfo),
273
- // this.removeMsgFromServerAndCache(msgId)
274
- // ]);
275
- throw (0, recipient_1.makeMsgNotFoundException)(msgId);
276
- }
277
- else if (msgOnDisk.keyStatus === 'not-checked') {
278
- await this.startCachingAndAddKeyToIndex(msgId);
279
- }
280
- else if (msgOnDisk.keyStatus !== 'ok') {
281
- throw new Error(`Unknown message key status ${msgOnDisk.keyStatus}`);
235
+ return msgToUIForm(msg, msgOnDisk.deliveryTS, msgOnDisk);
282
236
  }
283
237
  const meta = await msgOnDisk.getMsgMeta();
284
238
  const mainObjId = meta.extMeta.objIds[0];
285
239
  const mainObj = await msgOnDisk.getMsgObj(mainObjId);
286
- const msgKey = await this.index.getKeyFor(msgId, meta.deliveryCompletion);
240
+ let msgKey = await index.getKeyFor(msgId, meta.deliveryCompletion);
287
241
  if (!msgKey) {
288
- throw (0, recipient_1.makeMsgNotFoundException)(msgId);
242
+ if (!(await startCachingAndAddKeyToIndex(msgId))) {
243
+ throw (0, recipient_1.makeFailToDecryptMsgException)(msgId);
244
+ }
245
+ msgKey = await index.getKeyFor(msgId, meta.deliveryCompletion);
246
+ if (!msgKey) {
247
+ throw (0, recipient_1.makeFailToDecryptMsgException)(msgId);
248
+ }
289
249
  }
290
- msg = await (0, opener_1.openMsg)(msgId, mainObjId, mainObj, msgKey.mainObjHeaderOfs, msgKey.msgKey, this.cryptor);
250
+ msg = await (0, opener_1.openMsg)(msgId, mainObjId, mainObj, msgKey.mainObjHeaderOfs, msgKey.msgKey, cryptor);
291
251
  msg.setMsgKeyRole(msgKey.msgKeyRole);
292
- return this.msgToUIForm(msg, msgOnDisk.deliveryTS, msgOnDisk);
252
+ return msgToUIForm(msg, msgOnDisk.deliveryTS, msgOnDisk);
293
253
  });
294
254
  }
295
- msgToUIForm(msg, deliveryTS, msgOnDisk) {
255
+ function msgToUIForm(msg, deliveryTS, msgOnDisk) {
296
256
  const m = {
297
257
  sender: msg.sender,
298
258
  establishedSenderKeyChain: msg.establishedKeyChain,
@@ -317,23 +277,18 @@ class InboxOnServer {
317
277
  }
318
278
  const attachments = msg.attachmentsJSON;
319
279
  if (attachments) {
320
- m.attachments = (0, fs_1.fsForAttachments)(msgOnDisk, attachments, this.storages, this.cryptor, this.random, this.logError);
280
+ m.attachments = (0, fs_1.fsForAttachments)(msgOnDisk, attachments, getStorages, cryptor, random, logError);
321
281
  }
322
282
  return m;
323
283
  }
324
- suspendNetworkActivity() {
325
- this.inboxEvents.suspendNetworkActivity();
326
- }
327
- resumeNetworkActivity() {
328
- this.inboxEvents.resumeNetworkActivity();
329
- }
330
- get connectivityEvent$() {
331
- return this.inboxEvents.connectionEvent$;
332
- }
284
+ return {
285
+ connectivityEvent$: inboxEvents.connectionEvent$,
286
+ resumeNetworkActivity: inboxEvents.resumeNetworkActivity.bind(inboxEvents),
287
+ suspendNetworkActivity: inboxEvents.suspendNetworkActivity.bind(inboxEvents),
288
+ close,
289
+ makeCAP
290
+ };
333
291
  }
334
- exports.InboxOnServer = InboxOnServer;
335
- Object.freeze(InboxOnServer.prototype);
336
- Object.freeze(InboxOnServer);
337
292
  function checkServerAuthIfPresent(meta, { correspondent }) {
338
293
  // if sender authenticated to server, check that it matches address,
339
294
  // recovered from message decryption
@@ -27,9 +27,9 @@ const INDEX_DIR = 'index';
27
27
  const NUM_OF_ENTRIES_TO_CHOP_DB = 200;
28
28
  async function makeMsgIndex(syncedFS, localFS, logError) {
29
29
  // file systems within dataset
30
- const logsFS = await (0, fs_sync_utils_1.getOrMakeSyncedDirOnInit)(syncedFS, LOGS_DIR);
30
+ const logsFS = await (0, fs_sync_utils_1.getOrMakeDirOnInit)(syncedFS, LOGS_DIR);
31
31
  const localLogsFS = await localFS.writableSubRoot(LOGS_DIR);
32
- const indexFS = await (0, fs_sync_utils_1.getOrMakeSyncedDirOnInit)(syncedFS, INDEX_DIR);
32
+ const indexFS = await (0, fs_sync_utils_1.getOrMakeDirOnInit)(syncedFS, INDEX_DIR);
33
33
  const logs = await (0, logs_1.makeRecentMsgIndexChangesLogs)(logsFS, localLogsFS, logError);
34
34
  const indexed = await (0, sql_db_1.makeSqliteDBs)(indexFS);
35
35
  async function add(msgInfo, decrInfo) {
@@ -45,13 +45,12 @@ async function makeMsgIndex(syncedFS, localFS, logError) {
45
45
  }
46
46
  }
47
47
  async function periodicCheckAndUploadOfData() {
48
- // XXX disable uploading for a moment by commenting out
49
- // const shardTS = Date.now() - 10*60*1000;
50
- // const countBefore = indexed.numberOfRecordsInLatestBefore(shardTS);
51
- // if (countBefore >= NUM_OF_ENTRIES_TO_CHOP_DB) {
52
- // const syncedIndexDbVersion = await indexed.makeNewShardWithRecordsUpToTS(shardTS);
53
- // await logs.cutLogOnDatasetSyncAndUpload(syncedIndexDbVersion, { shardTS });
54
- // }
48
+ const shardTS = Date.now() - 10 * 60 * 1000;
49
+ const countBefore = indexed.numberOfRecordsInLatestBefore(shardTS);
50
+ if (countBefore >= NUM_OF_ENTRIES_TO_CHOP_DB) {
51
+ const syncedIndexDbVersion = await indexed.makeNewShardWithRecordsUpToTS(shardTS);
52
+ await logs.cutLogOnDatasetSyncAndUpload(syncedIndexDbVersion, { shardTS });
53
+ }
55
54
  }
56
55
  function millisBeforeNextRun() {
57
56
  return 30 * 60 * 1000 + Math.floor(10 * 60 * 1000 * Math.random());
@@ -2,14 +2,12 @@ import { ObjOnDisk } from '../../../lib-client/objs-on-disk/obj-on-disk';
2
2
  import { MsgMeta } from '../../../lib-common/service-api/asmail/retrieval';
3
3
  import { ObjSource } from 'xsp-files';
4
4
  import { MsgDownloader } from './msg-downloader';
5
- export type MsgKeyStatus = 'not-checked' | 'not-found' | 'fail' | 'ok';
6
5
  export interface ObjSize {
7
6
  header: number;
8
7
  segments: number;
9
8
  }
10
9
  export interface MsgStatus {
11
10
  msgId: string;
12
- keyStatus: MsgKeyStatus;
13
11
  onDisk: boolean;
14
12
  mainObjId: string;
15
13
  deliveryTS: number;
@@ -31,7 +29,4 @@ export declare class MsgOnDisk {
31
29
  getObjFile(objId: string): Promise<ObjOnDisk>;
32
30
  getMsgObj(objId: string): Promise<ObjSource>;
33
31
  get deliveryTS(): number;
34
- get keyStatus(): MsgKeyStatus;
35
- updateMsgKeyStatus(newStatus: Exclude<MsgKeyStatus, 'not-checked'>): Promise<void>;
36
- private saveStatusToDisk;
37
32
  }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- Copyright (C) 2016 - 2019 3NSoft Inc.
3
+ Copyright (C) 2016 - 2019, 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
@@ -27,7 +27,6 @@ const STATUS_FNAME = 'status.json';
27
27
  function makeInitMsgStatus(msgId, meta) {
28
28
  return {
29
29
  msgId,
30
- keyStatus: 'not-checked',
31
30
  onDisk: false,
32
31
  mainObjId: meta.extMeta.objIds[0],
33
32
  deliveryTS: meta.deliveryStart
@@ -94,26 +93,6 @@ class MsgOnDisk {
94
93
  get deliveryTS() {
95
94
  return this.status.deliveryTS;
96
95
  }
97
- get keyStatus() {
98
- return this.status.keyStatus;
99
- }
100
- updateMsgKeyStatus(newStatus) {
101
- return this.syncProc.startOrChain(async () => {
102
- if (this.status.keyStatus === 'not-checked') {
103
- this.status.keyStatus = newStatus;
104
- }
105
- else if (this.status.keyStatus === newStatus) {
106
- return;
107
- }
108
- else {
109
- throw Error(`Message has key status ${this.status.keyStatus}, and can't be updated to ${newStatus}`);
110
- }
111
- await this.saveStatusToDisk();
112
- });
113
- }
114
- async saveStatusToDisk() {
115
- await writeJSON(this.msgFolderPath, STATUS_FNAME, this.status);
116
- }
117
96
  }
118
97
  exports.MsgOnDisk = MsgOnDisk;
119
98
  Object.freeze(MsgOnDisk.prototype);
@@ -61,8 +61,8 @@ class ASMail {
61
61
  }
62
62
  }
63
63
  async setupSendingParams(syncedFS) {
64
- const fs = await (0, fs_sync_utils_1.getOrMakeSyncedDirOnInit)(syncedFS, SEND_PARAMS_DATA_FOLDER);
65
- this.sendingParams = await sending_params_1.SendingParamsHolder.makeAndInit(fs, this.config.makeParamSetterAndGetter('anon-sender/invites'), this.random);
64
+ const fs = await (0, fs_sync_utils_1.getOrMakeDirOnInit)(syncedFS, SEND_PARAMS_DATA_FOLDER);
65
+ this.sendingParams = await (0, sending_params_1.makeSendingParamsHolder)(fs, this.config.makeParamSetterAndGetter('anon-sender/invites'), this.random);
66
66
  }
67
67
  async setupDelivery(localFS, getSigner, makeResolver) {
68
68
  const fs = await localFS.writableSubRoot(DELIVERY_DATA_FOLDER);
@@ -88,9 +88,9 @@ class ASMail {
88
88
  }
89
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.getOrMakeSyncedDirOnInit)(syncedFS, INBOX_DATA_FOLDER);
91
+ const inboxSyncedFS = await (0, fs_sync_utils_1.getOrMakeDirOnInit)(syncedFS, INBOX_DATA_FOLDER);
92
92
  const inboxLocalFS = await localFS.writableSubRoot(INBOX_DATA_FOLDER);
93
- this.inbox = await inbox_1.InboxOnServer.makeAndStart(cachePath, inboxSyncedFS, inboxLocalFS, {
93
+ this.inbox = await (0, inbox_1.makeInboxOnServer)(cachePath, inboxSyncedFS, inboxLocalFS, {
94
94
  address: this.address,
95
95
  cryptor: this.cryptor,
96
96
  random: this.random,
@@ -6,18 +6,17 @@ export { SendingParams } from './params-from-others';
6
6
  type WritableFS = web3n.files.WritableFS;
7
7
  type SendingResources = ResourcesForSending['correspondents'];
8
8
  type ReceptionResources = ResourcesForReceiving['correspondents'];
9
- export declare class SendingParamsHolder {
10
- private readonly paramsFromOthers;
11
- private readonly ownParams;
12
- readonly thisSide: {
13
- getUpdated: SendingResources['newParamsForSendingReplies'];
14
- setAsUsed: ReceptionResources['markOwnSendingParamsAsUsed'];
15
- };
16
- readonly otherSides: {
17
- get: SendingResources['paramsForSendingTo'];
18
- set: ReceptionResources['saveParamsForSendingTo'];
19
- };
20
- private constructor();
21
- static makeAndInit(fs: WritableFS, anonInvitesOnServer: ParamOnServer<'anon-sender/invites'>, random: AsyncRNG): Promise<SendingParamsHolder>;
22
- close(): Promise<void>;
9
+ export interface SendingParamsThisSide {
10
+ getUpdated: SendingResources['newParamsForSendingReplies'];
11
+ setAsUsed: ReceptionResources['markOwnSendingParamsAsUsed'];
23
12
  }
13
+ export interface SendingParamsOtherSides {
14
+ get: SendingResources['paramsForSendingTo'];
15
+ set: ReceptionResources['saveParamsForSendingTo'];
16
+ }
17
+ export interface SendingParamsHolder {
18
+ thisSide: SendingParamsThisSide;
19
+ otherSides: SendingParamsOtherSides;
20
+ close: () => Promise<void>;
21
+ }
22
+ export declare function makeSendingParamsHolder(fs: WritableFS, anonInvitesOnServer: ParamOnServer<'anon-sender/invites'>, random: AsyncRNG): Promise<SendingParamsHolder>;