core-3nweb-client-lib 0.50.6 → 0.52.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 (37) hide show
  1. package/build/api-defs/asmail.d.ts +29 -4
  2. package/build/api-defs/files.d.ts +6 -3
  3. package/build/core/asmail/asmail-cap-ipc.js +24 -3
  4. package/build/core/asmail/delivery/common.d.ts +3 -0
  5. package/build/core/asmail/delivery/common.js +5 -0
  6. package/build/core/asmail/delivery/index.js +6 -6
  7. package/build/core/asmail/delivery/msg.js +1 -6
  8. package/build/core/asmail/delivery/per-recipient-wip.js +3 -5
  9. package/build/core/asmail/filtering.d.ts +11 -0
  10. package/build/core/asmail/filtering.js +219 -0
  11. package/build/core/asmail/inbox/index.d.ts +1 -0
  12. package/build/core/asmail/inbox/index.js +3 -0
  13. package/build/core/asmail/index.d.ts +3 -0
  14. package/build/core/asmail/index.js +32 -4
  15. package/build/core/asmail/sending-params/index.d.ts +2 -0
  16. package/build/core/asmail/sending-params/index.js +11 -1
  17. package/build/core/asmail/sending-params/own-params.d.ts +2 -0
  18. package/build/core/asmail/sending-params/own-params.js +27 -5
  19. package/build/core/asmail/sending-params/params-from-others.d.ts +2 -0
  20. package/build/core/asmail/sending-params/params-from-others.js +28 -3
  21. package/build/core/keyring/index.d.ts +2 -0
  22. package/build/core/keyring/index.js +4 -2
  23. package/build/core/keyring/peer-keys/dataset/v2/logs.d.ts +13 -1
  24. package/build/core/keyring/peer-keys/dataset/v2/logs.js +17 -1
  25. package/build/core/keyring/peer-keys/dataset/v2/peer-keys-db.d.ts +2 -0
  26. package/build/core/keyring/peer-keys/dataset/v2/peer-keys-db.js +31 -1
  27. package/build/core/keyring/peer-keys/index.d.ts +2 -0
  28. package/build/core/keyring/peer-keys/index.js +11 -1
  29. package/build/core/storage/synced/upsyncer.js +2 -1
  30. package/build/lib-client/3nstorage/storage-owner.js +1 -2
  31. package/build/lib-client/asmail/sender.d.ts +0 -6
  32. package/build/lib-client/asmail/sender.js +20 -64
  33. package/build/lib-client/service-locator.d.ts +2 -3
  34. package/build/lib-client/service-locator.js +8 -3
  35. package/build/lib-common/canonical-address.js +3 -0
  36. package/build/tests/caps-api/asmail.js +42 -1
  37. package/package.json +2 -2
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright (C) 2016, 2020, 2022, 2024 - 2025 3NSoft Inc.
2
+ Copyright (C) 2016, 2020, 2022, 2024 - 2026 3NSoft Inc.
3
3
 
4
4
  This program is free software: you can redistribute it and/or modify it under
5
5
  the terms of the GNU General Public License as published by the Free Software
@@ -34,6 +34,10 @@ declare namespace web3n.asmail {
34
34
 
35
35
  config: ASMailConfigService;
36
36
 
37
+ getReportAddressForDomain(domain: string): Promise<string>;
38
+
39
+ filter: ASMailFilter;
40
+
37
41
  }
38
42
 
39
43
  interface PreFlightOnlyService {
@@ -307,6 +311,7 @@ declare namespace web3n.asmail {
307
311
  interface ASMailSendException extends RuntimeException {
308
312
  type: 'asmail-delivery';
309
313
  address?: string;
314
+ id?: string;
310
315
 
311
316
  // errors that are due to remote side,
312
317
  // these will be placed into ProgressDelivery object
@@ -319,10 +324,11 @@ declare namespace web3n.asmail {
319
324
  allowedSize?: number;
320
325
  recipientHasNoPubKey?: true;
321
326
  recipientPubKeyFailsValidation?: true;
322
- msgNotFound?: true;
323
327
 
324
328
  // errors that are due to this side
325
329
  msgCancelled?: true;
330
+ recipientBlocked?: true;
331
+ msgNotFound?: true;
326
332
  }
327
333
 
328
334
  interface ASMailConfigService {
@@ -378,7 +384,7 @@ declare namespace web3n.asmail {
378
384
  */
379
385
  interface AddressesList {
380
386
  [address: string]: number;
381
- }
387
+ }
382
388
 
383
389
  /**
384
390
  * Invites list is a map from invites to respective maximum message size in
@@ -386,6 +392,25 @@ declare namespace web3n.asmail {
386
392
  */
387
393
  interface InvitesList {
388
394
  [invite: string]: number;
389
- }
395
+ }
396
+
397
+ interface ASMailFilter {
398
+ listRules(): Promise<FilteringRule[]>;
399
+ addRule(rule: FilteringRule): Promise<{ ruleIndex: number; rule: FilteringRule; }>;
400
+ removeRule(ruleIndex: number, rule: FilteringRule): Promise<boolean>;
401
+ }
402
+
403
+ interface BlockAddressRule {
404
+ ruleType: 'block-address';
405
+ domain: string;
406
+ username: string;
407
+ }
408
+
409
+ interface BlockDomainRule {
410
+ ruleType: 'block-domain';
411
+ domain: string;
412
+ }
413
+
414
+ type FilteringRule = BlockAddressRule | BlockDomainRule;
390
415
 
391
416
  }
@@ -70,6 +70,7 @@ declare namespace web3n.files {
70
70
  type: 'fs-sync';
71
71
  path: string;
72
72
  localVersion?: number;
73
+ uploadVersion?: number;
73
74
  remoteVersion?: number;
74
75
  alreadyUploading?: true;
75
76
  uploadTaskId?: number;
@@ -1681,8 +1682,8 @@ declare namespace web3n.files {
1681
1682
  upload(path: string, opts?: OptionsToUploadLocal): Promise<number|undefined>;
1682
1683
 
1683
1684
  /**
1684
- * This method is for resolving conflicts on folders.
1685
- * It adopts given folder item, that is present in remote version and is missing in local version.
1685
+ * This method is for resolving conflicts on folders, an action item by item.
1686
+ * It adopts only given folder item, that is present in remote version and is missing in local version.
1686
1687
  * Returns new local version.
1687
1688
  * @param path
1688
1689
  * @param remoteItemName
@@ -1694,7 +1695,9 @@ declare namespace web3n.files {
1694
1695
 
1695
1696
  /**
1696
1697
  * This method is for resolving conflicts on folders.
1697
- * It absorbs folder changes done in remote version.
1698
+ * It completely absorbs folder changes done in remote version.
1699
+ * Such wholesome may or may not be appriate in all circumstances, so use `adoptRemoteFolderItem`
1700
+ * for a more nuanced item-by-item operations.
1698
1701
  * Returns new local version, if there were remote items to adopt and their were added to local state.
1699
1702
  * @param path
1700
1703
  * @param opts
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- Copyright (C) 2020 - 2023, 2025 3NSoft Inc.
3
+ Copyright (C) 2020 - 2023, 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
@@ -58,7 +58,9 @@ function exposeASMailCAP(cap, expServices) {
58
58
  removeMsg: removeMsg.wrapService(box.removeMsg),
59
59
  subscribe: inboxSubscribe.wrapService(box.subscribe, expServices)
60
60
  },
61
- config: exposeConfigCAP(cap.config)
61
+ config: exposeConfigCAP(cap.config),
62
+ getReportAddressForDomain: (0, service_side_wrap_1.wrapReqReplyFunc)(cap, cap.getReportAddressForDomain),
63
+ filter: exposeFilterCAP(cap.filter)
62
64
  };
63
65
  }
64
66
  }
@@ -83,7 +85,9 @@ function makeASMailBasedOnListing(caller, objPath, capLists) {
83
85
  removeMsg: removeMsg.makeCaller(caller, inboxPath),
84
86
  subscribe: inboxSubscribe.makeCaller(caller, inboxPath)
85
87
  },
86
- config: makeConfigCaller(caller, objPath.concat('config'))
88
+ config: makeConfigCaller(caller, objPath.concat('config')),
89
+ getReportAddressForDomain: (0, caller_side_wrap_1.makeReqRepFuncCaller)(caller, objPath.concat('getReportAddressForDomain')),
90
+ filter: makeFilterCaller(caller, objPath.concat('filter'))
87
91
  };
88
92
  }
89
93
  else if (capLists === 'preflight') {
@@ -612,4 +616,21 @@ function makeConfigCaller(caller, objPath) {
612
616
  setOnServer: callConfig(caller, objPath, 'setOnServer')
613
617
  };
614
618
  }
619
+ function exposeFilterCAP(cap) {
620
+ return {
621
+ addRule: (0, service_side_wrap_1.wrapReqReplySrvMethod)(cap, 'addRule'),
622
+ listRules: (0, service_side_wrap_1.wrapReqReplySrvMethod)(cap, 'listRules'),
623
+ removeRule: (0, service_side_wrap_1.wrapReqReplySrvMethod)(cap, 'removeRule')
624
+ };
625
+ }
626
+ function callFilder(caller, objPath, method) {
627
+ return (0, caller_side_wrap_1.makeReqRepObjCaller)(caller, objPath, method);
628
+ }
629
+ function makeFilterCaller(caller, objPath) {
630
+ return {
631
+ addRule: callFilder(caller, objPath, 'addRule'),
632
+ listRules: callFilder(caller, objPath, 'listRules'),
633
+ removeRule: callFilder(caller, objPath, 'removeRule')
634
+ };
635
+ }
615
636
  Object.freeze(exports);
@@ -14,6 +14,7 @@ type AttachmentsContainer = web3n.asmail.AttachmentsContainer;
14
14
  type FS = web3n.files.FS;
15
15
  type WritableFS = web3n.files.WritableFS;
16
16
  type JsonKey = web3n.keys.JsonKey;
17
+ type ASMailSendException = web3n.asmail.ASMailSendException;
17
18
  export declare class Attachments {
18
19
  container: AttachmentsContainer | undefined;
19
20
  fs: FS | undefined;
@@ -66,6 +67,7 @@ export interface ResourcesForSending {
66
67
  * @param address
67
68
  */
68
69
  newParamsForSendingReplies: (address: string) => Promise<SendingParams | undefined>;
70
+ isAddressBlocked(address: string): boolean;
69
71
  };
70
72
  cryptor: AsyncSBoxCryptor;
71
73
  random: AsyncRNG;
@@ -79,4 +81,5 @@ export interface SavedMsgToSend {
79
81
  recipients: string[];
80
82
  retryOpts: DeliveryOptions['retryRecipient'];
81
83
  }
84
+ export declare function makeDeliveryException(params: Partial<ASMailSendException>): ASMailSendException;
82
85
  export {};
@@ -18,8 +18,10 @@
18
18
  Object.defineProperty(exports, "__esModule", { value: true });
19
19
  exports.SEG_SIZE_IN_K_QUATS = exports.Attachments = void 0;
20
20
  exports.estimatePackedSizeOf = estimatePackedSizeOf;
21
+ exports.makeDeliveryException = makeDeliveryException;
21
22
  const attachments_container_1 = require("../msg/attachments-container");
22
23
  const buffer_utils_1 = require("../../../lib-common/buffer-utils");
24
+ const runtime_1 = require("../../../lib-common/exceptions/runtime");
23
25
  const ATTACHMENTS_NAME = 'attachments';
24
26
  class Attachments {
25
27
  constructor(container, fs) {
@@ -138,4 +140,7 @@ function estimatePackedSizeOf(size) {
138
140
  }
139
141
  return 148 + numOfCompleteSegs * exports.SEG_SIZE_IN_K_QUATS * 256 + lastSegSize;
140
142
  }
143
+ function makeDeliveryException(params) {
144
+ return (0, runtime_1.makeRuntimeException)('asmail-delivery', params, {});
145
+ }
141
146
  Object.freeze(exports);
@@ -104,12 +104,7 @@ class Delivery {
104
104
  const msg = this.msgs.get(id);
105
105
  if (!msg) {
106
106
  if (observer.error) {
107
- const exc = {
108
- runtimeException: true,
109
- type: 'asmail-delivery',
110
- msgNotFound: true
111
- };
112
- observer.error(exc);
107
+ observer.error((0, common_1.makeDeliveryException)({ id, msgNotFound: true }));
113
108
  }
114
109
  return () => { };
115
110
  }
@@ -149,6 +144,11 @@ class Delivery {
149
144
  if (!Array.isArray(recipients) || (recipients.length === 0)) {
150
145
  throw new Error(`Given invalid recipients: ${recipients} for message ${id}`);
151
146
  }
147
+ for (const recipient of recipients) {
148
+ if (this.r.correspondents.isAddressBlocked(recipient)) {
149
+ throw (0, common_1.makeDeliveryException)({ address: recipient, recipientBlocked: true });
150
+ }
151
+ }
152
152
  if (this.msgs.has(id)) {
153
153
  throw new Error(`Message with id ${id} has already been added for delivery`);
154
154
  }
@@ -235,12 +235,7 @@ class Msg {
235
235
  return;
236
236
  }
237
237
  await filesProc.catch(() => { });
238
- const exc = {
239
- runtimeException: true,
240
- type: 'asmail-delivery',
241
- msgCancelled: true
242
- };
243
- this.progressPublisher.error(exc);
238
+ this.progressPublisher.error((0, common_1.makeDeliveryException)({ id: this.id, msgCancelled: true }));
244
239
  }
245
240
  /**
246
241
  * This starts sending a message to all recipients in parallel, and should be
@@ -21,6 +21,7 @@ const buffer_utils_1 = require("../../../lib-common/buffer-utils");
21
21
  const sender_1 = require("../../../lib-client/asmail/sender");
22
22
  const synced_1 = require("../../../lib-common/processes/synced");
23
23
  const key_verification_1 = require("../key-verification");
24
+ const common_1 = require("./common");
24
25
  const MSG_SIZE_FOR_STATE_RECORDING = 1024 * 1024;
25
26
  const EMPTY_BYTE_ARR = new Uint8Array(0);
26
27
  /**
@@ -209,14 +210,11 @@ class WIP {
209
210
  }
210
211
  const certs = await this.sender.getRecipientsInitPubKey();
211
212
  return (0, key_verification_1.checkAndExtractPKey)(this.sender.net, this.msg.r.midResolver, recipient, certs).catch(err => {
212
- const exc = {
213
- runtimeException: true,
214
- type: 'asmail-delivery',
213
+ throw (0, common_1.makeDeliveryException)({
215
214
  address: recipient,
216
215
  recipientPubKeyFailsValidation: true,
217
216
  cause: err
218
- };
219
- throw exc;
217
+ });
220
218
  });
221
219
  }
222
220
  /**
@@ -0,0 +1,11 @@
1
+ import { LogError } from "../../lib-client/logging/log-to-file";
2
+ type WritableFS = web3n.files.WritableFS;
3
+ type ASMailFilter = web3n.asmail.ASMailFilter;
4
+ type FilteringRule = web3n.asmail.FilteringRule;
5
+ export declare function makeAddressFilter(fs: WritableFS, logError: LogError, onRuleAddition: (r: FilteringRule) => Promise<void>): Promise<{
6
+ makeCAP: () => ASMailFilter;
7
+ isAddressBlocked: (address: string) => boolean;
8
+ close: () => void;
9
+ }>;
10
+ export type AddressFilter = Awaited<ReturnType<typeof makeAddressFilter>>;
11
+ export {};
@@ -0,0 +1,219 @@
1
+ "use strict";
2
+ /*
3
+ Copyright (C) 2026 3NSoft Inc.
4
+
5
+ This program is free software: you can redistribute it and/or modify it under
6
+ the terms of the GNU General Public License as published by the Free Software
7
+ Foundation, either version 3 of the License, or (at your option) any later
8
+ version.
9
+
10
+ This program is distributed in the hope that it will be useful, but
11
+ WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
+ See the GNU General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License along with
16
+ this program. If not, see <http://www.gnu.org/licenses/>.
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.makeAddressFilter = makeAddressFilter;
20
+ const canonical_address_1 = require("../../lib-common/canonical-address");
21
+ const single_file_1 = require("../../lib-common/dataset-sync/single-file");
22
+ const json_utils_1 = require("../../lib-common/json-utils");
23
+ const RULES_FNAME = 'rules.json';
24
+ async function makeAddressFilter(fs, logError, onRuleAddition) {
25
+ const { file: rulesFile, changeProc } = await (0, single_file_1.initSyncedFile)(fs, RULES_FNAME, newFile => newFile.writeJSON([]));
26
+ let rules = await prepareRulesReadFromFile(await rulesFile.readJSON());
27
+ async function saveRulesAndTriggerSync() {
28
+ await changeProc.startOrChain(() => rulesFile.writeJSON(rules));
29
+ triggerUpload();
30
+ }
31
+ const { stopFileWatching, triggerUpload } = (0, single_file_1.watchAndApplyChangesFromOtherDevices)(rulesFile, changeProc, onChangeFromOtherDevices, doOnConflict);
32
+ async function onChangeFromOtherDevices(newVersion) {
33
+ changeProc.startOrChain(async () => {
34
+ const { version, json } = await rulesFile.v.readJSON();
35
+ if (version === newVersion) {
36
+ rules = await prepareRulesReadFromFile(json);
37
+ }
38
+ });
39
+ }
40
+ function doOnConflict() {
41
+ return changeProc.startOrChain(async () => {
42
+ const { remote, synced } = await rulesFile.v.sync.status(true);
43
+ const syncedRules = await prepareRulesReadFromFile((await rulesFile.v.readJSON({ remoteVersion: synced === null || synced === void 0 ? void 0 : synced.latest })).json);
44
+ const remoteRules = await prepareRulesReadFromFile((await rulesFile.v.readJSON({ remoteVersion: remote === null || remote === void 0 ? void 0 : remote.latest })).json);
45
+ const localRules = rules.concat();
46
+ const mergedRules = [];
47
+ while (remoteRules.length > 0) {
48
+ const r = remoteRules.shift();
49
+ const si = syncedRules.findIndex(sr => (0, json_utils_1.deepEqual)(sr, r));
50
+ const li = localRules.findIndex(lr => (0, json_utils_1.deepEqual)(lr, r));
51
+ if (si >= 0) {
52
+ if (li >= 0) {
53
+ // rule stays as is
54
+ mergedRules.push(r);
55
+ }
56
+ else {
57
+ // rule removed in local
58
+ }
59
+ }
60
+ else {
61
+ if (li >= 0) {
62
+ // rule added in local and remote
63
+ mergedRules.push(r);
64
+ }
65
+ else {
66
+ // rule added in remote
67
+ mergedRules.push(r);
68
+ }
69
+ }
70
+ if (si > 0) {
71
+ syncedRules.splice(si, 1);
72
+ }
73
+ if (li > 0) {
74
+ localRules.splice(li, 1);
75
+ }
76
+ }
77
+ while (localRules.length > 0) {
78
+ const l = localRules.shift();
79
+ const si = syncedRules.findIndex(sr => (0, json_utils_1.deepEqual)(sr, l));
80
+ if (si >= 0) {
81
+ // rule was removed in remote
82
+ }
83
+ else {
84
+ // rule was added in local
85
+ mergedRules.push(l);
86
+ }
87
+ if (si > 0) {
88
+ syncedRules.splice(si, 1);
89
+ }
90
+ }
91
+ rules = mergedRules;
92
+ await rulesFile.writeJSON(rules);
93
+ await rulesFile.v.sync.upload({ uploadVersion: remote.latest + 1 });
94
+ });
95
+ }
96
+ async function prepareRulesReadFromFile(rulesFromFile) {
97
+ if (!Array.isArray(rulesFromFile)) {
98
+ await logError(`Expected array with rules`, `Reading of ASMail filter rules produced unexpected data`);
99
+ return [];
100
+ }
101
+ const rules = [];
102
+ const errors = [];
103
+ for (const r of rulesFromFile) {
104
+ try {
105
+ rules.push(prepareRuleFrom(r));
106
+ }
107
+ catch (err) {
108
+ errors.push(err);
109
+ }
110
+ }
111
+ if (errors.length > 0) {
112
+ await logError(errors[0], `Reading of ASMail filter rules produced produced ${errors.length} errors, the first one is here`);
113
+ }
114
+ return rules;
115
+ }
116
+ function groupRulesByDomains(rules) {
117
+ const m = new Map();
118
+ for (const rule of rules) {
119
+ const domain = rule.domain;
120
+ let domainRules = m.get(domain);
121
+ if (!domainRules) {
122
+ domainRules = [];
123
+ m.set(domain, domainRules);
124
+ }
125
+ domainRules.push(rule);
126
+ }
127
+ return m;
128
+ }
129
+ let rulesByDomain = groupRulesByDomains(rules);
130
+ async function addRule(ruleToAdd) {
131
+ const rule = prepareRuleFrom(ruleToAdd);
132
+ const ruleIndex = rules.push(rule) - 1;
133
+ rulesByDomain = groupRulesByDomains(rules);
134
+ await saveRulesAndTriggerSync();
135
+ await onRuleAddition(rule);
136
+ return { rule, ruleIndex };
137
+ }
138
+ async function removeRule(ruleIndex, rule) {
139
+ if ((ruleIndex < 0) || (ruleIndex >= rules.length) || !(0, json_utils_1.deepEqual)(rules[ruleIndex], rule)) {
140
+ return false;
141
+ }
142
+ rules.splice(ruleIndex, 1);
143
+ await saveRulesAndTriggerSync();
144
+ return true;
145
+ }
146
+ async function listRules() {
147
+ return rules;
148
+ }
149
+ function isAddressBlocked(address) {
150
+ const cAddr = (0, canonical_address_1.checkAndTransformAddress)(address);
151
+ if (!cAddr) {
152
+ return true;
153
+ }
154
+ const { uName, dName } = cAddrIntoParts(cAddr);
155
+ const domainRules = rulesByDomain.get(dName);
156
+ if (!domainRules) {
157
+ return false;
158
+ }
159
+ for (const rule of domainRules) {
160
+ if (rule.ruleType === 'block-domain') {
161
+ return true;
162
+ }
163
+ else if (rule.ruleType === 'block-address') {
164
+ if (uName == rule.username) {
165
+ return true;
166
+ }
167
+ }
168
+ }
169
+ return false;
170
+ }
171
+ function makeCAP() {
172
+ return {
173
+ addRule,
174
+ removeRule,
175
+ listRules
176
+ };
177
+ }
178
+ function close() {
179
+ stopFileWatching();
180
+ }
181
+ return {
182
+ makeCAP,
183
+ isAddressBlocked,
184
+ close
185
+ };
186
+ }
187
+ function cAddrIntoParts(cAddr) {
188
+ const atInd = cAddr.lastIndexOf('@');
189
+ if (atInd < 0) {
190
+ throw TypeError(`No @ in given canonical address: ${cAddr}`);
191
+ }
192
+ return {
193
+ uName: cAddr.substring(0, atInd),
194
+ dName: cAddr.substring(atInd + 1)
195
+ };
196
+ }
197
+ function prepareRuleFrom(r) {
198
+ switch (r.ruleType) {
199
+ case 'block-address': {
200
+ const cAddr = (0, canonical_address_1.toCanonicalAddress)(`${r.username}@${r.domain}`);
201
+ const { uName, dName } = cAddrIntoParts(cAddr);
202
+ return {
203
+ ruleType: 'block-address',
204
+ domain: dName, username: uName
205
+ };
206
+ }
207
+ case 'block-domain': {
208
+ const cAddr = (0, canonical_address_1.toCanonicalAddress)(`@${r.domain}`);
209
+ const { dName } = cAddrIntoParts(cAddr);
210
+ return {
211
+ ruleType: 'block-domain',
212
+ domain: dName
213
+ };
214
+ }
215
+ default:
216
+ throw TypeError(`Unknown rule type: ${r.ruleType}`);
217
+ }
218
+ }
219
+ Object.freeze(exports);
@@ -62,6 +62,7 @@ export interface ResourcesForReceiving {
62
62
  */
63
63
  saveParamsForSendingTo: (address: string, params: SendingParams) => Promise<void>;
64
64
  midResolver: ServiceLocator;
65
+ isAddressBlocked(address: string): boolean;
65
66
  };
66
67
  logError: LogError;
67
68
  }
@@ -116,6 +116,9 @@ async function makeInboxOnServer(cachePath, syncedFS, localFS, r) {
116
116
  const decrOut = await r.correspondents.msgDecryptor(meta.extMeta, getMainObjHeader, getOpenedMsg, checkerOfMidKeyCerts(msgOnDisk.deliveryTS));
117
117
  if (decrOut) {
118
118
  const { decrInfo, openedMsg } = decrOut;
119
+ if (r.correspondents.isAddressBlocked(decrInfo.correspondent)) {
120
+ return false;
121
+ }
119
122
  openedMsg.setMsgKeyRole(decrInfo.keyStatus);
120
123
  // XXX we have never used this part of protocol, should it be removed at all from ASMail protocol?
121
124
  checkServerAuthIfPresent(meta, decrInfo);
@@ -23,6 +23,8 @@ export declare class ASMail {
23
23
  private delivery;
24
24
  private config;
25
25
  private sendingParams;
26
+ private getReportAddressForDomain;
27
+ private filter;
26
28
  constructor(cryptor: AsyncSBoxCryptor, random: AsyncRNG, makeNet: MakeNet, inboxPathForUser: InboxPathForUser, logger: Logger);
27
29
  init(address: string, getSigner: GetSigner, syncedFS: WritableFS, localFS: WritableFS, getStorages: StorageGetter, makeResolver: ServiceLocatorMaker, config: ConfigOfASMailServer, keyring: KeyringForASMail): Promise<void>;
28
30
  private setupSendingParams;
@@ -34,5 +36,6 @@ export declare class ASMail {
34
36
  suspendNetworkActivity(): void;
35
37
  resumeNetworkActivity(): void;
36
38
  get connectivityEvent$(): import("rxjs").Observable<import("./inbox/inbox-events").InboxConnectionStatus>;
39
+ private applyNewFilteringRuleToPeersInfo;
37
40
  }
38
41
  export {};
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- Copyright (C) 2015 - 2018, 2020 - 2022, 2025 3NSoft Inc.
3
+ Copyright (C) 2015 - 2018, 2020 - 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
@@ -22,9 +22,11 @@ const error_1 = require("../../lib-common/exceptions/error");
22
22
  const delivery_1 = require("./delivery");
23
23
  const sending_params_1 = require("./sending-params");
24
24
  const fs_sync_utils_1 = require("../../lib-client/fs-utils/fs-sync-utils");
25
+ const filtering_1 = require("./filtering");
25
26
  const INBOX_DATA_FOLDER = 'inbox';
26
27
  const DELIVERY_DATA_FOLDER = 'delivery';
27
28
  const SEND_PARAMS_DATA_FOLDER = 'sending-params';
29
+ const FILTERS_DATA_FOLDER = 'filtering';
28
30
  class ASMail {
29
31
  constructor(cryptor, random, makeNet, inboxPathForUser, logger) {
30
32
  this.cryptor = cryptor;
@@ -38,16 +40,20 @@ class ASMail {
38
40
  this.delivery = undefined;
39
41
  this.config = undefined;
40
42
  this.sendingParams = undefined;
43
+ this.getReportAddressForDomain = undefined;
44
+ this.filter = undefined;
41
45
  Object.seal(this);
42
46
  }
43
47
  async init(address, getSigner, syncedFS, localFS, getStorages, makeResolver, config, keyring) {
44
48
  try {
45
49
  this.address = address;
50
+ this.getReportAddressForDomain = makeResolver('report', this.logger.logError);
46
51
  // XXX this should be part of proper syncing logic
47
52
  // await getRemoteFolderChanges(syncedFS);
48
53
  this.config = config;
49
54
  this.keyring = keyring;
50
55
  await this.setupSendingParams(syncedFS);
56
+ this.filter = await (0, filtering_1.makeAddressFilter)(await (0, fs_sync_utils_1.getOrMakeDirOnInit)(syncedFS, FILTERS_DATA_FOLDER), this.logger.logError, this.applyNewFilteringRuleToPeersInfo.bind(this));
51
57
  await Promise.all([
52
58
  this.setupInbox(syncedFS, localFS, getSigner, getStorages, makeResolver),
53
59
  this.setupDelivery(localFS, getSigner, makeResolver)
@@ -78,7 +84,8 @@ class ASMail {
78
84
  generateIntroKeysToSendMsg: this.keyring.generateIntroKeysToSendMsg,
79
85
  getEstablishedKeysToSendMsg: this.keyring.getEstablishedKeysToSendMsg,
80
86
  paramsForSendingTo: this.sendingParams.otherSides.get,
81
- newParamsForSendingReplies: this.sendingParams.thisSide.getUpdated
87
+ newParamsForSendingReplies: this.sendingParams.thisSide.getUpdated,
88
+ isAddressBlocked: this.filter.isAddressBlocked
82
89
  },
83
90
  notifyMsgProgress: () => { throw new Error(`Method not set`); },
84
91
  makeNet: this.makeNet,
@@ -101,7 +108,8 @@ class ASMail {
101
108
  msgDecryptor: this.keyring.decrypt,
102
109
  markOwnSendingParamsAsUsed: this.sendingParams.thisSide.setAsUsed,
103
110
  saveParamsForSendingTo: this.sendingParams.otherSides.set,
104
- midResolver: makeResolver('mailerid', this.logger.logError)
111
+ midResolver: makeResolver('mailerid', this.logger.logError),
112
+ isAddressBlocked: this.filter.isAddressBlocked
105
113
  },
106
114
  makeNet: this.makeNet,
107
115
  logError: this.logger.logError
@@ -112,7 +120,9 @@ class ASMail {
112
120
  getUserId: async () => this.address,
113
121
  delivery: this.delivery.makeCAP(),
114
122
  inbox: this.inbox.makeCAP(),
115
- config: this.config.makeCAP()
123
+ config: this.config.makeCAP(),
124
+ getReportAddressForDomain: this.getReportAddressForDomain,
125
+ filter: this.filter.makeCAP()
116
126
  };
117
127
  return Object.freeze(w);
118
128
  }
@@ -133,6 +143,7 @@ class ASMail {
133
143
  await this.delivery.close();
134
144
  await this.keyring.close();
135
145
  await this.sendingParams.close();
146
+ this.filter.close();
136
147
  }
137
148
  suspendNetworkActivity() {
138
149
  this.inbox.suspendNetworkActivity();
@@ -143,6 +154,23 @@ class ASMail {
143
154
  get connectivityEvent$() {
144
155
  return this.inbox.connectivityEvent$;
145
156
  }
157
+ async applyNewFilteringRuleToPeersInfo(r) {
158
+ switch (r.ruleType) {
159
+ case 'block-address': {
160
+ const { username, domain } = r;
161
+ const cAddr = `${username}@${domain}`;
162
+ await this.keyring.forgetCorrespondentAt(cAddr);
163
+ await this.sendingParams.forgetCorrespondentAt(cAddr);
164
+ break;
165
+ }
166
+ case 'block-domain': {
167
+ const { domain } = r;
168
+ await this.keyring.forgetCorrespondentAt(domain);
169
+ await this.sendingParams.forgetCorrespondentAt(domain);
170
+ break;
171
+ }
172
+ }
173
+ }
146
174
  }
147
175
  exports.ASMail = ASMail;
148
176
  Object.freeze(ASMail.prototype);
@@ -18,5 +18,7 @@ export interface SendingParamsHolder {
18
18
  thisSide: SendingParamsThisSide;
19
19
  otherSides: SendingParamsOtherSides;
20
20
  close: () => Promise<void>;
21
+ forgetCorrespondentAt(cAddr: string): Promise<void>;
22
+ forgetAllCorrespondentsAtDomain(domain: string): Promise<void>;
21
23
  }
22
24
  export declare function makeSendingParamsHolder(fs: WritableFS, anonInvitesOnServer: ParamOnServer<'anon-sender/invites'>, random: AsyncRNG): Promise<SendingParamsHolder>;
@@ -32,10 +32,20 @@ async function makeSendingParamsHolder(fs, anonInvitesOnServer, random) {
32
32
  await thisSide.close();
33
33
  await otherSides.close();
34
34
  }
35
+ async function forgetCorrespondentAt(cAddr) {
36
+ await otherSides.forgetCorrespondentAt(cAddr);
37
+ await thisSide.forgetCorrespondentAt(cAddr);
38
+ }
39
+ async function forgetAllCorrespondentsAtDomain(domain) {
40
+ await otherSides.forgetAllCorrespondentsAtDomain(domain);
41
+ await thisSide.forgetAllCorrespondentsAtDomain(domain);
42
+ }
35
43
  return {
36
44
  thisSide,
37
45
  otherSides,
38
- close
46
+ close,
47
+ forgetCorrespondentAt,
48
+ forgetAllCorrespondentsAtDomain
39
49
  };
40
50
  }
41
51
  Object.freeze(exports);
@@ -4,5 +4,7 @@ type WritableFS = web3n.files.WritableFS;
4
4
  export type OwnSendingParams = Awaited<ReturnType<typeof makeOwnSendingParams>>;
5
5
  export declare function makeOwnSendingParams(fs: WritableFS, fileName: string, anonInvites: AnonymousInvites): Promise<SendingParamsHolder['thisSide'] & {
6
6
  close: () => Promise<void>;
7
+ forgetCorrespondentAt(cAddr: string): Promise<void>;
8
+ forgetAllCorrespondentsAtDomain(domain: string): Promise<void>;
7
9
  }>;
8
10
  export {};