@brightchain/brightchain-api-lib 0.25.0 → 0.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -3
- package/src/lib/application.d.ts +3 -14
- package/src/lib/application.d.ts.map +1 -1
- package/src/lib/application.js +89 -34
- package/src/lib/application.js.map +1 -1
- package/src/lib/databaseInit.d.ts +7 -11
- package/src/lib/databaseInit.d.ts.map +1 -1
- package/src/lib/databaseInit.js +41 -107
- package/src/lib/databaseInit.js.map +1 -1
- package/src/lib/datastore/block-document-store-factory.d.ts +3 -0
- package/src/lib/datastore/block-document-store-factory.d.ts.map +1 -1
- package/src/lib/datastore/block-document-store-factory.js +15 -18
- package/src/lib/datastore/block-document-store-factory.js.map +1 -1
- package/src/lib/datastore/block-document-store.d.ts +2 -191
- package/src/lib/datastore/block-document-store.d.ts.map +1 -1
- package/src/lib/datastore/block-document-store.js +4 -628
- package/src/lib/datastore/block-document-store.js.map +1 -1
- package/src/lib/datastore/document-store.d.ts +1 -62
- package/src/lib/datastore/document-store.d.ts.map +1 -1
- package/src/lib/datastore/memory-document-store.d.ts +1 -8
- package/src/lib/datastore/memory-document-store.d.ts.map +1 -1
- package/src/lib/datastore/memory-document-store.js +3 -214
- package/src/lib/datastore/memory-document-store.js.map +1 -1
- package/src/lib/environment.d.ts +4 -47
- package/src/lib/environment.d.ts.map +1 -1
- package/src/lib/environment.js +2 -136
- package/src/lib/environment.js.map +1 -1
- package/src/lib/interfaces/environment.d.ts +3 -25
- package/src/lib/interfaces/environment.d.ts.map +1 -1
- package/src/lib/middleware/index.d.ts +1 -1
- package/src/lib/middleware/index.d.ts.map +1 -1
- package/src/lib/middleware/index.js +3 -2
- package/src/lib/middleware/index.js.map +1 -1
- package/src/lib/middleware/validateBody.d.ts +1 -12
- package/src/lib/middleware/validateBody.d.ts.map +1 -1
- package/src/lib/middleware/validateBody.js +4 -32
- package/src/lib/middleware/validateBody.js.map +1 -1
- package/src/lib/middlewares.d.ts.map +1 -1
- package/src/lib/middlewares.js +7 -1
- package/src/lib/middlewares.js.map +1 -1
- package/src/lib/plugins/brightchain-database-plugin.d.ts +27 -79
- package/src/lib/plugins/brightchain-database-plugin.d.ts.map +1 -1
- package/src/lib/plugins/brightchain-database-plugin.js +27 -97
- package/src/lib/plugins/brightchain-database-plugin.js.map +1 -1
- package/src/lib/services/emailGateway/antiSpamFilter.d.ts +229 -0
- package/src/lib/services/emailGateway/antiSpamFilter.d.ts.map +1 -0
- package/src/lib/services/emailGateway/antiSpamFilter.js +325 -0
- package/src/lib/services/emailGateway/antiSpamFilter.js.map +1 -0
- package/src/lib/services/emailGateway/bounceProcessor.d.ts +171 -0
- package/src/lib/services/emailGateway/bounceProcessor.d.ts.map +1 -0
- package/src/lib/services/emailGateway/bounceProcessor.js +378 -0
- package/src/lib/services/emailGateway/bounceProcessor.js.map +1 -0
- package/src/lib/services/emailGateway/emailAuthVerifier.d.ts +99 -0
- package/src/lib/services/emailGateway/emailAuthVerifier.d.ts.map +1 -0
- package/src/lib/services/emailGateway/emailAuthVerifier.js +202 -0
- package/src/lib/services/emailGateway/emailAuthVerifier.js.map +1 -0
- package/src/lib/services/emailGateway/emailGatewayConfig.d.ts +73 -0
- package/src/lib/services/emailGateway/emailGatewayConfig.d.ts.map +1 -0
- package/src/lib/services/emailGateway/emailGatewayConfig.js +107 -0
- package/src/lib/services/emailGateway/emailGatewayConfig.js.map +1 -0
- package/src/lib/services/emailGateway/emailGatewayService.d.ts +152 -0
- package/src/lib/services/emailGateway/emailGatewayService.d.ts.map +1 -0
- package/src/lib/services/emailGateway/emailGatewayService.js +201 -0
- package/src/lib/services/emailGateway/emailGatewayService.js.map +1 -0
- package/src/lib/services/emailGateway/gatewayObservability.d.ts +123 -0
- package/src/lib/services/emailGateway/gatewayObservability.d.ts.map +1 -0
- package/src/lib/services/emailGateway/gatewayObservability.js +186 -0
- package/src/lib/services/emailGateway/gatewayObservability.js.map +1 -0
- package/src/lib/services/emailGateway/inboundProcessor.d.ts +113 -0
- package/src/lib/services/emailGateway/inboundProcessor.d.ts.map +1 -0
- package/src/lib/services/emailGateway/inboundProcessor.js +298 -0
- package/src/lib/services/emailGateway/inboundProcessor.js.map +1 -0
- package/src/lib/services/emailGateway/index.d.ts +23 -0
- package/src/lib/services/emailGateway/index.d.ts.map +1 -0
- package/src/lib/services/emailGateway/index.js +26 -0
- package/src/lib/services/emailGateway/index.js.map +1 -0
- package/src/lib/services/emailGateway/outboundDeliveryWorker.d.ts +111 -0
- package/src/lib/services/emailGateway/outboundDeliveryWorker.d.ts.map +1 -0
- package/src/lib/services/emailGateway/outboundDeliveryWorker.js +97 -0
- package/src/lib/services/emailGateway/outboundDeliveryWorker.js.map +1 -0
- package/src/lib/services/emailGateway/outboundQueue.d.ts +135 -0
- package/src/lib/services/emailGateway/outboundQueue.d.ts.map +1 -0
- package/src/lib/services/emailGateway/outboundQueue.js +227 -0
- package/src/lib/services/emailGateway/outboundQueue.js.map +1 -0
- package/src/lib/services/emailGateway/outboundQueueStore.d.ts +110 -0
- package/src/lib/services/emailGateway/outboundQueueStore.d.ts.map +1 -0
- package/src/lib/services/emailGateway/outboundQueueStore.js +131 -0
- package/src/lib/services/emailGateway/outboundQueueStore.js.map +1 -0
- package/src/lib/services/emailGateway/recipientLookupService.d.ts +135 -0
- package/src/lib/services/emailGateway/recipientLookupService.d.ts.map +1 -0
- package/src/lib/services/emailGateway/recipientLookupService.js +294 -0
- package/src/lib/services/emailGateway/recipientLookupService.js.map +1 -0
- package/src/lib/services/emailGateway/retryBackoff.d.ts +79 -0
- package/src/lib/services/emailGateway/retryBackoff.d.ts.map +1 -0
- package/src/lib/services/emailGateway/retryBackoff.js +77 -0
- package/src/lib/services/emailGateway/retryBackoff.js.map +1 -0
- package/src/lib/services/index.d.ts +1 -0
- package/src/lib/services/index.d.ts.map +1 -1
- package/src/lib/services/index.js +1 -0
- package/src/lib/services/index.js.map +1 -1
- package/src/lib/services/quorumDatabaseAdapter.d.ts +7 -1
- package/src/lib/services/quorumDatabaseAdapter.d.ts.map +1 -1
- package/src/lib/services/quorumDatabaseAdapter.js +83 -0
- package/src/lib/services/quorumDatabaseAdapter.js.map +1 -1
- package/src/lib/services/sessionAdapter.d.ts +2 -61
- package/src/lib/services/sessionAdapter.d.ts.map +1 -1
- package/src/lib/services/sessionAdapter.js +2 -102
- package/src/lib/services/sessionAdapter.js.map +1 -1
- package/src/lib/shared-types.d.ts +7 -15
- package/src/lib/shared-types.d.ts.map +1 -1
- package/src/lib/types/backend-id.d.ts +1 -2
- package/src/lib/types/backend-id.d.ts.map +1 -1
- package/src/lib/validation/userValidation.d.ts +2 -43
- package/src/lib/validation/userValidation.d.ts.map +1 -1
- package/src/lib/validation/userValidation.js +6 -144
- package/src/lib/validation/userValidation.js.map +1 -1
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Email Authentication Verifier — parses SPF/DKIM/DMARC authentication
|
|
4
|
+
* results from inbound email messages.
|
|
5
|
+
*
|
|
6
|
+
* In a typical deployment, Postfix and its milters (e.g. OpenDKIM,
|
|
7
|
+
* opendmarc, pypolicyd-spf) perform the actual SPF, DKIM, and DMARC
|
|
8
|
+
* verification before depositing the message in the Mail Drop Directory.
|
|
9
|
+
* These results are recorded in the `Authentication-Results` header
|
|
10
|
+
* (RFC 8601).
|
|
11
|
+
*
|
|
12
|
+
* This verifier parses those headers from the raw message to extract
|
|
13
|
+
* structured `IEmailAuthenticationResult` metadata that the
|
|
14
|
+
* InboundProcessor stores alongside the message.
|
|
15
|
+
*
|
|
16
|
+
* @see Requirements 6.4, 6.5
|
|
17
|
+
* @module emailAuthVerifier
|
|
18
|
+
*/
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.EmailAuthVerifier = void 0;
|
|
21
|
+
exports.defaultAuthResult = defaultAuthResult;
|
|
22
|
+
const VALID_SPF_STATUSES = new Set([
|
|
23
|
+
'pass',
|
|
24
|
+
'fail',
|
|
25
|
+
'softfail',
|
|
26
|
+
'neutral',
|
|
27
|
+
'none',
|
|
28
|
+
'temperror',
|
|
29
|
+
'permerror',
|
|
30
|
+
]);
|
|
31
|
+
const VALID_DKIM_STATUSES = new Set([
|
|
32
|
+
'pass',
|
|
33
|
+
'fail',
|
|
34
|
+
'none',
|
|
35
|
+
'temperror',
|
|
36
|
+
'permerror',
|
|
37
|
+
]);
|
|
38
|
+
const VALID_DMARC_STATUSES = new Set([
|
|
39
|
+
'pass',
|
|
40
|
+
'fail',
|
|
41
|
+
'none',
|
|
42
|
+
'temperror',
|
|
43
|
+
'permerror',
|
|
44
|
+
]);
|
|
45
|
+
// ─── Default result ─────────────────────────────────────────────────────────
|
|
46
|
+
/**
|
|
47
|
+
* Returns a default `IEmailAuthenticationResult` with all statuses set to `'none'`.
|
|
48
|
+
*/
|
|
49
|
+
function defaultAuthResult() {
|
|
50
|
+
return {
|
|
51
|
+
spf: { status: 'none' },
|
|
52
|
+
dkim: { status: 'none' },
|
|
53
|
+
dmarc: { status: 'none' },
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
// ─── Implementation ─────────────────────────────────────────────────────────
|
|
57
|
+
/**
|
|
58
|
+
* Parses `Authentication-Results` headers from raw RFC 5322 messages to
|
|
59
|
+
* extract SPF, DKIM, and DMARC verification results.
|
|
60
|
+
*
|
|
61
|
+
* This is an adapter/stub that reads results already computed by
|
|
62
|
+
* Postfix milters. It does NOT perform cryptographic DKIM verification
|
|
63
|
+
* or DNS lookups itself.
|
|
64
|
+
*
|
|
65
|
+
* @see Requirements 6.4, 6.5
|
|
66
|
+
*/
|
|
67
|
+
class EmailAuthVerifier {
|
|
68
|
+
/**
|
|
69
|
+
* Parse authentication results from the raw message headers.
|
|
70
|
+
*
|
|
71
|
+
* Extracts the `Authentication-Results` header value and parses
|
|
72
|
+
* individual method results (spf=, dkim=, dmarc=).
|
|
73
|
+
*
|
|
74
|
+
* @param rawMessage - Raw RFC 5322 message bytes
|
|
75
|
+
* @param _senderIp - Sender IP (unused; reserved for future direct verification)
|
|
76
|
+
* @returns Structured authentication results
|
|
77
|
+
*/
|
|
78
|
+
verify(rawMessage, _senderIp) {
|
|
79
|
+
const headerValue = this.extractAuthResultsHeader(rawMessage);
|
|
80
|
+
if (!headerValue) {
|
|
81
|
+
return defaultAuthResult();
|
|
82
|
+
}
|
|
83
|
+
return this.parseAuthResultsHeader(headerValue);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Check whether the authentication result indicates a DMARC reject
|
|
87
|
+
* condition — i.e. DMARC status is `'fail'`.
|
|
88
|
+
*
|
|
89
|
+
* The caller (InboundProcessor) uses this to decide whether to move
|
|
90
|
+
* the message to the error directory with a 550-equivalent rejection.
|
|
91
|
+
*
|
|
92
|
+
* @param result - The parsed authentication result
|
|
93
|
+
* @returns `true` if DMARC failed (reject policy should apply)
|
|
94
|
+
*
|
|
95
|
+
* @see Requirement 6.5
|
|
96
|
+
*/
|
|
97
|
+
static shouldRejectDmarc(result) {
|
|
98
|
+
return result.dmarc.status === 'fail';
|
|
99
|
+
}
|
|
100
|
+
// ─── Header extraction ──────────────────────────────────────────────
|
|
101
|
+
/**
|
|
102
|
+
* Extract the value of the first `Authentication-Results` header from
|
|
103
|
+
* the raw message bytes.
|
|
104
|
+
*
|
|
105
|
+
* RFC 5322 headers end at the first blank line (`\r\n\r\n` or `\n\n`).
|
|
106
|
+
* Header continuation (folding) is handled by joining lines that start
|
|
107
|
+
* with whitespace.
|
|
108
|
+
*/
|
|
109
|
+
extractAuthResultsHeader(rawMessage) {
|
|
110
|
+
const text = typeof rawMessage === 'string'
|
|
111
|
+
? rawMessage
|
|
112
|
+
: Buffer.isBuffer(rawMessage)
|
|
113
|
+
? rawMessage.toString('utf-8')
|
|
114
|
+
: new TextDecoder().decode(rawMessage);
|
|
115
|
+
// Split headers from body at the first blank line.
|
|
116
|
+
const headerEndCrLf = text.indexOf('\r\n\r\n');
|
|
117
|
+
const headerEndLf = text.indexOf('\n\n');
|
|
118
|
+
let headerSection;
|
|
119
|
+
if (headerEndCrLf >= 0 &&
|
|
120
|
+
(headerEndLf < 0 || headerEndCrLf <= headerEndLf)) {
|
|
121
|
+
headerSection = text.substring(0, headerEndCrLf);
|
|
122
|
+
}
|
|
123
|
+
else if (headerEndLf >= 0) {
|
|
124
|
+
headerSection = text.substring(0, headerEndLf);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
// No blank line — treat entire content as headers.
|
|
128
|
+
headerSection = text;
|
|
129
|
+
}
|
|
130
|
+
// Unfold continuation lines (lines starting with whitespace are
|
|
131
|
+
// continuations of the previous header per RFC 5322 §2.2.3).
|
|
132
|
+
const unfolded = headerSection.replace(/\r?\n([ \t])/g, ' ');
|
|
133
|
+
// Split into individual header lines.
|
|
134
|
+
const lines = unfolded.split(/\r?\n/);
|
|
135
|
+
for (const line of lines) {
|
|
136
|
+
const match = line.match(/^Authentication-Results:\s*(.+)$/i);
|
|
137
|
+
if (match) {
|
|
138
|
+
return match[1].trim();
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
// ─── Header parsing ─────────────────────────────────────────────────
|
|
144
|
+
/**
|
|
145
|
+
* Parse an `Authentication-Results` header value into structured results.
|
|
146
|
+
*
|
|
147
|
+
* The header format (RFC 8601) is roughly:
|
|
148
|
+
* `authserv-id; method=status (details); method=status ...`
|
|
149
|
+
*
|
|
150
|
+
* We split on `;` and look for `spf=`, `dkim=`, `dmarc=` prefixes.
|
|
151
|
+
*/
|
|
152
|
+
parseAuthResultsHeader(headerValue) {
|
|
153
|
+
const result = defaultAuthResult();
|
|
154
|
+
// Split on semicolons — first segment is the authserv-id, rest are results.
|
|
155
|
+
const segments = headerValue.split(';').map((s) => s.trim());
|
|
156
|
+
// Skip the first segment (authserv-id).
|
|
157
|
+
for (let i = 1; i < segments.length; i++) {
|
|
158
|
+
const segment = segments[i];
|
|
159
|
+
if (!segment)
|
|
160
|
+
continue;
|
|
161
|
+
this.parseMethodResult(segment, result);
|
|
162
|
+
}
|
|
163
|
+
return result;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Parse a single method result segment like `spf=pass (details here)`.
|
|
167
|
+
*/
|
|
168
|
+
parseMethodResult(segment, result) {
|
|
169
|
+
// Match pattern: method=status with optional details in parentheses or after whitespace
|
|
170
|
+
// Examples:
|
|
171
|
+
// spf=pass (sender SPF authorized)
|
|
172
|
+
// dkim=pass header.d=example.com
|
|
173
|
+
// dmarc=fail (p=reject)
|
|
174
|
+
const methodMatch = segment.match(/^\s*(spf|dkim|dmarc)\s*=\s*(\S+)/i);
|
|
175
|
+
if (!methodMatch)
|
|
176
|
+
return;
|
|
177
|
+
const method = methodMatch[1].toLowerCase();
|
|
178
|
+
const rawStatus = methodMatch[2].toLowerCase();
|
|
179
|
+
// Extract optional details in parentheses.
|
|
180
|
+
const detailsMatch = segment.match(/\(([^)]*)\)/);
|
|
181
|
+
const details = detailsMatch ? detailsMatch[1].trim() : undefined;
|
|
182
|
+
switch (method) {
|
|
183
|
+
case 'spf':
|
|
184
|
+
if (VALID_SPF_STATUSES.has(rawStatus)) {
|
|
185
|
+
result.spf = { status: rawStatus, details };
|
|
186
|
+
}
|
|
187
|
+
break;
|
|
188
|
+
case 'dkim':
|
|
189
|
+
if (VALID_DKIM_STATUSES.has(rawStatus)) {
|
|
190
|
+
result.dkim = { status: rawStatus, details };
|
|
191
|
+
}
|
|
192
|
+
break;
|
|
193
|
+
case 'dmarc':
|
|
194
|
+
if (VALID_DMARC_STATUSES.has(rawStatus)) {
|
|
195
|
+
result.dmarc = { status: rawStatus, details };
|
|
196
|
+
}
|
|
197
|
+
break;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
exports.EmailAuthVerifier = EmailAuthVerifier;
|
|
202
|
+
//# sourceMappingURL=emailAuthVerifier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emailAuthVerifier.js","sourceRoot":"","sources":["../../../../../../brightchain-api-lib/src/lib/services/emailGateway/emailAuthVerifier.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Email Gateway Configuration
|
|
3
|
+
*
|
|
4
|
+
* Defines the `IEmailGatewayConfig` interface and a `loadGatewayConfig()` loader
|
|
5
|
+
* that reads values from `CoreConstants.SiteEmailDomain` and environment variables
|
|
6
|
+
* with sensible defaults.
|
|
7
|
+
*
|
|
8
|
+
* All Node.js-specific gateway configuration lives here in brightchain-api-lib.
|
|
9
|
+
* The shared `ISpamThresholds` interface is imported from brightchain-lib.
|
|
10
|
+
*
|
|
11
|
+
* @see Requirements 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7
|
|
12
|
+
* @module emailGatewayConfig
|
|
13
|
+
*/
|
|
14
|
+
import { type ISpamThresholds } from '@brightchain/brightchain-lib';
|
|
15
|
+
/**
|
|
16
|
+
* Complete configuration for the Email Gateway.
|
|
17
|
+
*
|
|
18
|
+
* Each field maps to an environment variable (noted in comments) with a
|
|
19
|
+
* default value applied by `loadGatewayConfig()` when the variable is unset.
|
|
20
|
+
*
|
|
21
|
+
* @see Requirements 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7
|
|
22
|
+
*/
|
|
23
|
+
export interface IEmailGatewayConfig {
|
|
24
|
+
/** Canonical email domain for this BrightChain instance (from CoreConstants.SiteEmailDomain). Req 8.1 */
|
|
25
|
+
canonicalDomain: string;
|
|
26
|
+
/** Postfix MTA hostname. env: GATEWAY_POSTFIX_HOST. Req 8.2 */
|
|
27
|
+
postfixHost: string;
|
|
28
|
+
/** Postfix MTA port. env: GATEWAY_POSTFIX_PORT. Req 8.2 */
|
|
29
|
+
postfixPort: number;
|
|
30
|
+
/** Optional Postfix authentication credentials. env: GATEWAY_POSTFIX_USER / GATEWAY_POSTFIX_PASS. Req 8.2 */
|
|
31
|
+
postfixAuth?: {
|
|
32
|
+
user: string;
|
|
33
|
+
pass: string;
|
|
34
|
+
};
|
|
35
|
+
/** Path to the DKIM private key file. env: GATEWAY_DKIM_KEY_PATH. Req 8.3 */
|
|
36
|
+
dkimKeyPath: string;
|
|
37
|
+
/** DKIM selector for DNS lookup. env: GATEWAY_DKIM_SELECTOR. Req 8.3 */
|
|
38
|
+
dkimSelector: string;
|
|
39
|
+
/** Directory where Postfix deposits inbound mail (Maildir format). env: GATEWAY_MAIL_DROP_DIR. Req 8.6 */
|
|
40
|
+
mailDropDirectory: string;
|
|
41
|
+
/** Directory for messages that fail inbound processing. env: GATEWAY_ERROR_DIR. Req 8.6 */
|
|
42
|
+
errorDirectory: string;
|
|
43
|
+
/** Maximum outbound message size in bytes. env: GATEWAY_MAX_MESSAGE_SIZE. Req 8.4 */
|
|
44
|
+
maxMessageSizeBytes: number;
|
|
45
|
+
/** TCP port for the Recipient Lookup Service (socketmap). env: GATEWAY_LOOKUP_PORT. Req 8.7 */
|
|
46
|
+
recipientLookupPort: number;
|
|
47
|
+
/** Cache TTL in seconds for positive recipient lookups. env: GATEWAY_LOOKUP_CACHE_TTL. Req 8.7 */
|
|
48
|
+
recipientLookupCacheTtlSeconds: number;
|
|
49
|
+
/** Anti-spam engine selection. env: GATEWAY_SPAM_ENGINE. Req 8.4 */
|
|
50
|
+
spamEngine: 'spamassassin' | 'rspamd';
|
|
51
|
+
/** Score thresholds for spam classification. env: GATEWAY_SPAM_PROBABLE / GATEWAY_SPAM_DEFINITE. Req 8.4 */
|
|
52
|
+
spamThresholds: ISpamThresholds;
|
|
53
|
+
/** Maximum concurrent outbound SMTP connections. env: GATEWAY_QUEUE_CONCURRENCY. Req 8.4 */
|
|
54
|
+
queueConcurrency: number;
|
|
55
|
+
/** Maximum number of delivery retry attempts. env: GATEWAY_RETRY_MAX_COUNT. Req 8.4 */
|
|
56
|
+
retryMaxCount: number;
|
|
57
|
+
/** Maximum total retry duration in milliseconds. env: GATEWAY_RETRY_MAX_DURATION. Req 8.4 */
|
|
58
|
+
retryMaxDurationMs: number;
|
|
59
|
+
/** Base interval in milliseconds for exponential back-off. env: GATEWAY_RETRY_BASE_INTERVAL. Req 8.4 */
|
|
60
|
+
retryBaseIntervalMs: number;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Load the Email Gateway configuration from `CoreConstants` and environment variables.
|
|
64
|
+
*
|
|
65
|
+
* Reads `CoreConstants.SiteEmailDomain` for the canonical domain (Req 8.1) and
|
|
66
|
+
* environment variables for all other settings, applying defaults where unset.
|
|
67
|
+
*
|
|
68
|
+
* @returns A fully populated `IEmailGatewayConfig`.
|
|
69
|
+
*
|
|
70
|
+
* @see Requirements 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7
|
|
71
|
+
*/
|
|
72
|
+
export declare function loadGatewayConfig(): IEmailGatewayConfig;
|
|
73
|
+
//# sourceMappingURL=emailGatewayConfig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emailGatewayConfig.d.ts","sourceRoot":"","sources":["../../../../../../brightchain-api-lib/src/lib/services/emailGateway/emailGatewayConfig.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAEL,KAAK,eAAe,EACrB,MAAM,8BAA8B,CAAC;AAEtC;;;;;;;GAOG;AACH,MAAM,WAAW,mBAAmB;IAClC,yGAAyG;IACzG,eAAe,EAAE,MAAM,CAAC;IAExB,+DAA+D;IAC/D,WAAW,EAAE,MAAM,CAAC;IAEpB,2DAA2D;IAC3D,WAAW,EAAE,MAAM,CAAC;IAEpB,6GAA6G;IAC7G,WAAW,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAE7C,6EAA6E;IAC7E,WAAW,EAAE,MAAM,CAAC;IAEpB,wEAAwE;IACxE,YAAY,EAAE,MAAM,CAAC;IAErB,0GAA0G;IAC1G,iBAAiB,EAAE,MAAM,CAAC;IAE1B,2FAA2F;IAC3F,cAAc,EAAE,MAAM,CAAC;IAEvB,qFAAqF;IACrF,mBAAmB,EAAE,MAAM,CAAC;IAE5B,+FAA+F;IAC/F,mBAAmB,EAAE,MAAM,CAAC;IAE5B,kGAAkG;IAClG,8BAA8B,EAAE,MAAM,CAAC;IAEvC,oEAAoE;IACpE,UAAU,EAAE,cAAc,GAAG,QAAQ,CAAC;IAEtC,4GAA4G;IAC5G,cAAc,EAAE,eAAe,CAAC;IAEhC,4FAA4F;IAC5F,gBAAgB,EAAE,MAAM,CAAC;IAEzB,uFAAuF;IACvF,aAAa,EAAE,MAAM,CAAC;IAEtB,6FAA6F;IAC7F,kBAAkB,EAAE,MAAM,CAAC;IAE3B,wGAAwG;IACxG,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAmED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,IAAI,mBAAmB,CAuDvD"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Email Gateway Configuration
|
|
4
|
+
*
|
|
5
|
+
* Defines the `IEmailGatewayConfig` interface and a `loadGatewayConfig()` loader
|
|
6
|
+
* that reads values from `CoreConstants.SiteEmailDomain` and environment variables
|
|
7
|
+
* with sensible defaults.
|
|
8
|
+
*
|
|
9
|
+
* All Node.js-specific gateway configuration lives here in brightchain-api-lib.
|
|
10
|
+
* The shared `ISpamThresholds` interface is imported from brightchain-lib.
|
|
11
|
+
*
|
|
12
|
+
* @see Requirements 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7
|
|
13
|
+
* @module emailGatewayConfig
|
|
14
|
+
*/
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.loadGatewayConfig = loadGatewayConfig;
|
|
17
|
+
const brightchain_lib_1 = require("@brightchain/brightchain-lib");
|
|
18
|
+
/** Default mail drop directory path */
|
|
19
|
+
const DEFAULT_MAIL_DROP_DIR = '/var/spool/brightchain/incoming/';
|
|
20
|
+
/** Default error directory path */
|
|
21
|
+
const DEFAULT_ERROR_DIR = '/var/spool/brightchain/errors/';
|
|
22
|
+
/** Default maximum message size: 25 MB */
|
|
23
|
+
const DEFAULT_MAX_MESSAGE_SIZE = 25 * 1024 * 1024;
|
|
24
|
+
/** Default recipient lookup port */
|
|
25
|
+
const DEFAULT_LOOKUP_PORT = 2526;
|
|
26
|
+
/** Default recipient lookup cache TTL in seconds */
|
|
27
|
+
const DEFAULT_LOOKUP_CACHE_TTL = 300;
|
|
28
|
+
/** Default queue concurrency */
|
|
29
|
+
const DEFAULT_QUEUE_CONCURRENCY = 10;
|
|
30
|
+
/** Default retry max count */
|
|
31
|
+
const DEFAULT_RETRY_MAX_COUNT = 5;
|
|
32
|
+
/** Default retry max duration: 48 hours in ms */
|
|
33
|
+
const DEFAULT_RETRY_MAX_DURATION = 48 * 60 * 60 * 1000;
|
|
34
|
+
/** Default retry base interval: 60 seconds in ms */
|
|
35
|
+
const DEFAULT_RETRY_BASE_INTERVAL = 60_000;
|
|
36
|
+
/** Default probable spam score threshold */
|
|
37
|
+
const DEFAULT_SPAM_PROBABLE = 5.0;
|
|
38
|
+
/** Default definite spam score threshold */
|
|
39
|
+
const DEFAULT_SPAM_DEFINITE = 10.0;
|
|
40
|
+
/**
|
|
41
|
+
* Parse an integer from an environment variable, returning a default if unset or invalid.
|
|
42
|
+
*/
|
|
43
|
+
function envInt(name, defaultValue) {
|
|
44
|
+
const raw = process.env[name];
|
|
45
|
+
if (raw === undefined || raw === '') {
|
|
46
|
+
return defaultValue;
|
|
47
|
+
}
|
|
48
|
+
const parsed = parseInt(raw, 10);
|
|
49
|
+
return Number.isNaN(parsed) ? defaultValue : parsed;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Parse a float from an environment variable, returning a default if unset or invalid.
|
|
53
|
+
*/
|
|
54
|
+
function envFloat(name, defaultValue) {
|
|
55
|
+
const raw = process.env[name];
|
|
56
|
+
if (raw === undefined || raw === '') {
|
|
57
|
+
return defaultValue;
|
|
58
|
+
}
|
|
59
|
+
const parsed = parseFloat(raw);
|
|
60
|
+
return Number.isNaN(parsed) ? defaultValue : parsed;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Read a string environment variable, returning a default if unset.
|
|
64
|
+
*/
|
|
65
|
+
function envString(name, defaultValue) {
|
|
66
|
+
const raw = process.env[name];
|
|
67
|
+
return raw !== undefined && raw !== '' ? raw : defaultValue;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Load the Email Gateway configuration from `CoreConstants` and environment variables.
|
|
71
|
+
*
|
|
72
|
+
* Reads `CoreConstants.SiteEmailDomain` for the canonical domain (Req 8.1) and
|
|
73
|
+
* environment variables for all other settings, applying defaults where unset.
|
|
74
|
+
*
|
|
75
|
+
* @returns A fully populated `IEmailGatewayConfig`.
|
|
76
|
+
*
|
|
77
|
+
* @see Requirements 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7
|
|
78
|
+
*/
|
|
79
|
+
function loadGatewayConfig() {
|
|
80
|
+
const postfixUser = process.env['GATEWAY_POSTFIX_USER'];
|
|
81
|
+
const postfixPass = process.env['GATEWAY_POSTFIX_PASS'];
|
|
82
|
+
return {
|
|
83
|
+
canonicalDomain: brightchain_lib_1.CoreConstants.SiteEmailDomain,
|
|
84
|
+
postfixHost: envString('GATEWAY_POSTFIX_HOST', 'localhost'),
|
|
85
|
+
postfixPort: envInt('GATEWAY_POSTFIX_PORT', 25),
|
|
86
|
+
postfixAuth: postfixUser && postfixPass
|
|
87
|
+
? { user: postfixUser, pass: postfixPass }
|
|
88
|
+
: undefined,
|
|
89
|
+
dkimKeyPath: envString('GATEWAY_DKIM_KEY_PATH', '/etc/dkim/private.key'),
|
|
90
|
+
dkimSelector: envString('GATEWAY_DKIM_SELECTOR', 'default'),
|
|
91
|
+
mailDropDirectory: envString('GATEWAY_MAIL_DROP_DIR', DEFAULT_MAIL_DROP_DIR),
|
|
92
|
+
errorDirectory: envString('GATEWAY_ERROR_DIR', DEFAULT_ERROR_DIR),
|
|
93
|
+
maxMessageSizeBytes: envInt('GATEWAY_MAX_MESSAGE_SIZE', DEFAULT_MAX_MESSAGE_SIZE),
|
|
94
|
+
recipientLookupPort: envInt('GATEWAY_LOOKUP_PORT', DEFAULT_LOOKUP_PORT),
|
|
95
|
+
recipientLookupCacheTtlSeconds: envInt('GATEWAY_LOOKUP_CACHE_TTL', DEFAULT_LOOKUP_CACHE_TTL),
|
|
96
|
+
spamEngine: envString('GATEWAY_SPAM_ENGINE', 'spamassassin'),
|
|
97
|
+
spamThresholds: {
|
|
98
|
+
probableSpamScore: envFloat('GATEWAY_SPAM_PROBABLE', DEFAULT_SPAM_PROBABLE),
|
|
99
|
+
definiteSpamScore: envFloat('GATEWAY_SPAM_DEFINITE', DEFAULT_SPAM_DEFINITE),
|
|
100
|
+
},
|
|
101
|
+
queueConcurrency: envInt('GATEWAY_QUEUE_CONCURRENCY', DEFAULT_QUEUE_CONCURRENCY),
|
|
102
|
+
retryMaxCount: envInt('GATEWAY_RETRY_MAX_COUNT', DEFAULT_RETRY_MAX_COUNT),
|
|
103
|
+
retryMaxDurationMs: envInt('GATEWAY_RETRY_MAX_DURATION', DEFAULT_RETRY_MAX_DURATION),
|
|
104
|
+
retryBaseIntervalMs: envInt('GATEWAY_RETRY_BASE_INTERVAL', DEFAULT_RETRY_BASE_INTERVAL),
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=emailGatewayConfig.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emailGatewayConfig.js","sourceRoot":"","sources":["../../../../../../brightchain-api-lib/src/lib/services/emailGateway/emailGatewayConfig.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;GAYG;;AA+IH,8CAuDC;AApMD,kEAGsC;AA+DtC,uCAAuC;AACvC,MAAM,qBAAqB,GAAG,kCAAkC,CAAC;AAEjE,mCAAmC;AACnC,MAAM,iBAAiB,GAAG,gCAAgC,CAAC;AAE3D,0CAA0C;AAC1C,MAAM,wBAAwB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AAElD,oCAAoC;AACpC,MAAM,mBAAmB,GAAG,IAAI,CAAC;AAEjC,oDAAoD;AACpD,MAAM,wBAAwB,GAAG,GAAG,CAAC;AAErC,gCAAgC;AAChC,MAAM,yBAAyB,GAAG,EAAE,CAAC;AAErC,8BAA8B;AAC9B,MAAM,uBAAuB,GAAG,CAAC,CAAC;AAElC,iDAAiD;AACjD,MAAM,0BAA0B,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAEvD,oDAAoD;AACpD,MAAM,2BAA2B,GAAG,MAAM,CAAC;AAE3C,4CAA4C;AAC5C,MAAM,qBAAqB,GAAG,GAAG,CAAC;AAElC,4CAA4C;AAC5C,MAAM,qBAAqB,GAAG,IAAI,CAAC;AAEnC;;GAEG;AACH,SAAS,MAAM,CAAC,IAAY,EAAE,YAAoB;IAChD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC9B,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,EAAE,EAAE,CAAC;QACpC,OAAO,YAAY,CAAC;IACtB,CAAC;IACD,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACjC,OAAO,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC;AACtD,CAAC;AAED;;GAEG;AACH,SAAS,QAAQ,CAAC,IAAY,EAAE,YAAoB;IAClD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC9B,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,EAAE,EAAE,CAAC;QACpC,OAAO,YAAY,CAAC;IACtB,CAAC;IACD,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;IAC/B,OAAO,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC;AACtD,CAAC;AAED;;GAEG;AACH,SAAS,SAAS,CAAC,IAAY,EAAE,YAAoB;IACnD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC9B,OAAO,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC;AAC9D,CAAC;AAED;;;;;;;;;GASG;AACH,SAAgB,iBAAiB;IAC/B,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;IACxD,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;IAExD,OAAO;QACL,eAAe,EAAE,+BAAa,CAAC,eAAe;QAC9C,WAAW,EAAE,SAAS,CAAC,sBAAsB,EAAE,WAAW,CAAC;QAC3D,WAAW,EAAE,MAAM,CAAC,sBAAsB,EAAE,EAAE,CAAC;QAC/C,WAAW,EACT,WAAW,IAAI,WAAW;YACxB,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,EAAE;YAC1C,CAAC,CAAC,SAAS;QACf,WAAW,EAAE,SAAS,CAAC,uBAAuB,EAAE,uBAAuB,CAAC;QACxE,YAAY,EAAE,SAAS,CAAC,uBAAuB,EAAE,SAAS,CAAC;QAC3D,iBAAiB,EAAE,SAAS,CAC1B,uBAAuB,EACvB,qBAAqB,CACtB;QACD,cAAc,EAAE,SAAS,CAAC,mBAAmB,EAAE,iBAAiB,CAAC;QACjE,mBAAmB,EAAE,MAAM,CACzB,0BAA0B,EAC1B,wBAAwB,CACzB;QACD,mBAAmB,EAAE,MAAM,CAAC,qBAAqB,EAAE,mBAAmB,CAAC;QACvE,8BAA8B,EAAE,MAAM,CACpC,0BAA0B,EAC1B,wBAAwB,CACzB;QACD,UAAU,EAAE,SAAS,CAAC,qBAAqB,EAAE,cAAc,CAE/C;QACZ,cAAc,EAAE;YACd,iBAAiB,EAAE,QAAQ,CACzB,uBAAuB,EACvB,qBAAqB,CACtB;YACD,iBAAiB,EAAE,QAAQ,CACzB,uBAAuB,EACvB,qBAAqB,CACtB;SACF;QACD,gBAAgB,EAAE,MAAM,CACtB,2BAA2B,EAC3B,yBAAyB,CAC1B;QACD,aAAa,EAAE,MAAM,CAAC,yBAAyB,EAAE,uBAAuB,CAAC;QACzE,kBAAkB,EAAE,MAAM,CACxB,4BAA4B,EAC5B,0BAA0B,CAC3B;QACD,mBAAmB,EAAE,MAAM,CACzB,6BAA6B,EAC7B,2BAA2B,CAC5B;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EmailGatewayService — orchestrator that bridges BrightChain's internal
|
|
3
|
+
* gossip-based messaging with external SMTP email delivery via Postfix.
|
|
4
|
+
*
|
|
5
|
+
* Responsibilities:
|
|
6
|
+
* - Listen for gossip announcements containing outbound email
|
|
7
|
+
* - Extract message blocks from the Block Store
|
|
8
|
+
* - Detect external recipients by comparing domain against canonicalDomain
|
|
9
|
+
* - Enqueue outbound messages for SMTP delivery
|
|
10
|
+
*
|
|
11
|
+
* @see Requirements 1.1, 1.2, 1.4
|
|
12
|
+
* @module emailGatewayService
|
|
13
|
+
*/
|
|
14
|
+
import type { IBlockStore, IEmailMetadata, IGossipService } from '@brightchain/brightchain-lib';
|
|
15
|
+
import { EmailMessageService, OutboundDeliveryStatus } from '@brightchain/brightchain-lib';
|
|
16
|
+
import type { IEmailGatewayConfig } from './emailGatewayConfig';
|
|
17
|
+
/**
|
|
18
|
+
* Minimal interface for the outbound email queue.
|
|
19
|
+
*
|
|
20
|
+
* The full `OutboundQueue` class (task 4.2) will implement this.
|
|
21
|
+
* Using an interface here keeps the orchestrator decoupled from the
|
|
22
|
+
* queue's internal persistence and concurrency details.
|
|
23
|
+
*/
|
|
24
|
+
export interface IOutboundQueue {
|
|
25
|
+
/**
|
|
26
|
+
* Add a message to the outbound delivery queue.
|
|
27
|
+
*
|
|
28
|
+
* @param message - Outbound message payload with recipient, content, and retry metadata
|
|
29
|
+
*/
|
|
30
|
+
enqueue(message: IOutboundQueueItem): Promise<void>;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* A single item placed on the outbound delivery queue.
|
|
34
|
+
*/
|
|
35
|
+
export interface IOutboundQueueItem {
|
|
36
|
+
/** RFC 5322 Message-ID */
|
|
37
|
+
messageId: string;
|
|
38
|
+
/** Sender email address */
|
|
39
|
+
from: string;
|
|
40
|
+
/** External recipient email addresses */
|
|
41
|
+
to: string[];
|
|
42
|
+
/** Email subject */
|
|
43
|
+
subject?: string;
|
|
44
|
+
/** Full email metadata for serialization */
|
|
45
|
+
metadata: IEmailMetadata;
|
|
46
|
+
/** Timestamp when the item was enqueued */
|
|
47
|
+
enqueuedAt: Date;
|
|
48
|
+
/** Current delivery status */
|
|
49
|
+
status: OutboundDeliveryStatus;
|
|
50
|
+
/** Number of delivery attempts so far */
|
|
51
|
+
retryCount: number;
|
|
52
|
+
/** Earliest time at which the next delivery attempt should be made */
|
|
53
|
+
nextAttemptAt?: Date;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Orchestrator service for the Email Gateway.
|
|
57
|
+
*
|
|
58
|
+
* Listens for gossip announcements that carry outbound email, extracts the
|
|
59
|
+
* message content from the Block Store, identifies external recipients by
|
|
60
|
+
* comparing their domain against the configured `canonicalDomain`, and
|
|
61
|
+
* enqueues qualifying messages in the OutboundQueue for SMTP delivery.
|
|
62
|
+
*
|
|
63
|
+
* Lifecycle:
|
|
64
|
+
* - `start()` registers the gossip announcement listener
|
|
65
|
+
* - `stop()` removes the listener and performs cleanup
|
|
66
|
+
*
|
|
67
|
+
* @see Requirements 1.1, 1.2, 1.4
|
|
68
|
+
*/
|
|
69
|
+
export declare class EmailGatewayService {
|
|
70
|
+
private readonly config;
|
|
71
|
+
private readonly gossipService;
|
|
72
|
+
private readonly blockStore;
|
|
73
|
+
private readonly emailMessageService;
|
|
74
|
+
private outboundQueue?;
|
|
75
|
+
/** Bound reference kept so we can unsubscribe on stop(). */
|
|
76
|
+
private readonly boundAnnouncementHandler;
|
|
77
|
+
/** Whether the service is currently running. */
|
|
78
|
+
private running;
|
|
79
|
+
/**
|
|
80
|
+
* @param config - Gateway configuration (canonical domain, limits, etc.)
|
|
81
|
+
* @param gossipService - Gossip protocol service for subscribing to announcements
|
|
82
|
+
* @param blockStore - Block store for retrieving message content blocks
|
|
83
|
+
* @param emailMessageService - Email message service for retrieving email metadata
|
|
84
|
+
* @param outboundQueue - Queue for outbound SMTP delivery (optional; set later via `setOutboundQueue`)
|
|
85
|
+
*/
|
|
86
|
+
constructor(config: IEmailGatewayConfig, gossipService: IGossipService, blockStore: IBlockStore, emailMessageService: EmailMessageService, outboundQueue?: IOutboundQueue | undefined);
|
|
87
|
+
/**
|
|
88
|
+
* Start the gateway service.
|
|
89
|
+
*
|
|
90
|
+
* Registers a gossip announcement listener that intercepts outbound
|
|
91
|
+
* email announcements and delegates them to the outbound queue.
|
|
92
|
+
*/
|
|
93
|
+
start(): void;
|
|
94
|
+
/**
|
|
95
|
+
* Stop the gateway service.
|
|
96
|
+
*
|
|
97
|
+
* Removes the gossip listener and marks the service as stopped.
|
|
98
|
+
*/
|
|
99
|
+
stop(): void;
|
|
100
|
+
/**
|
|
101
|
+
* Whether the service is currently running.
|
|
102
|
+
*/
|
|
103
|
+
isRunning(): boolean;
|
|
104
|
+
/**
|
|
105
|
+
* Wire the outbound queue after construction.
|
|
106
|
+
*
|
|
107
|
+
* Useful when the queue is created after the gateway service (e.g.
|
|
108
|
+
* during staged initialisation).
|
|
109
|
+
*/
|
|
110
|
+
setOutboundQueue(queue: IOutboundQueue): void;
|
|
111
|
+
/**
|
|
112
|
+
* Determine whether an email address is external (not on the canonical domain).
|
|
113
|
+
*
|
|
114
|
+
* Extracts the domain portion of the address and compares it
|
|
115
|
+
* case-insensitively against `config.canonicalDomain`.
|
|
116
|
+
*
|
|
117
|
+
* @param emailAddress - A full email address (e.g. `alice@example.com`)
|
|
118
|
+
* @returns `true` when the address belongs to an external domain
|
|
119
|
+
*
|
|
120
|
+
* @see Requirement 1.1 — detect recipients whose domain ≠ canonical domain
|
|
121
|
+
*/
|
|
122
|
+
isExternalRecipient(emailAddress: string): boolean;
|
|
123
|
+
/**
|
|
124
|
+
* Partition a list of email addresses into internal and external groups.
|
|
125
|
+
*
|
|
126
|
+
* @param addresses - Array of email addresses
|
|
127
|
+
* @returns Object with `internal` and `external` arrays
|
|
128
|
+
*
|
|
129
|
+
* @see Requirement 1.4 — mixed internal/external recipient handling
|
|
130
|
+
*/
|
|
131
|
+
partitionRecipients(addresses: string[]): {
|
|
132
|
+
internal: string[];
|
|
133
|
+
external: string[];
|
|
134
|
+
};
|
|
135
|
+
/**
|
|
136
|
+
* Handle a gossip message-delivery announcement.
|
|
137
|
+
*
|
|
138
|
+
* When an announcement carries `messageDelivery` metadata the handler:
|
|
139
|
+
* 1. Retrieves the email metadata from the EmailMessageService
|
|
140
|
+
* 2. Identifies external recipients
|
|
141
|
+
* 3. Enqueues the message in the OutboundQueue for SMTP delivery
|
|
142
|
+
*
|
|
143
|
+
* Internal-only messages are ignored — they are already delivered via gossip.
|
|
144
|
+
*
|
|
145
|
+
* @param announcement - The gossip BlockAnnouncement with messageDelivery metadata
|
|
146
|
+
*
|
|
147
|
+
* @see Requirement 1.2 — extract message from Block Store and enqueue
|
|
148
|
+
* @see Requirement 1.4 — route external recipients to gateway
|
|
149
|
+
*/
|
|
150
|
+
private handleAnnouncement;
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=emailGatewayService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emailGatewayService.d.ts","sourceRoot":"","sources":["../../../../../../brightchain-api-lib/src/lib/services/emailGateway/emailGatewayService.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAEV,WAAW,EACX,cAAc,EACd,cAAc,EACf,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,mBAAmB,EACnB,sBAAsB,EACvB,MAAM,8BAA8B,CAAC;AAEtC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAOhE;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,OAAO,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACrD;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,0BAA0B;IAC1B,SAAS,EAAE,MAAM,CAAC;IAElB,2BAA2B;IAC3B,IAAI,EAAE,MAAM,CAAC;IAEb,yCAAyC;IACzC,EAAE,EAAE,MAAM,EAAE,CAAC;IAEb,oBAAoB;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,4CAA4C;IAC5C,QAAQ,EAAE,cAAc,CAAC;IAEzB,2CAA2C;IAC3C,UAAU,EAAE,IAAI,CAAC;IAEjB,8BAA8B;IAC9B,MAAM,EAAE,sBAAsB,CAAC;IAE/B,yCAAyC;IACzC,UAAU,EAAE,MAAM,CAAC;IAEnB,sEAAsE;IACtE,aAAa,CAAC,EAAE,IAAI,CAAC;CACtB;AAID;;;;;;;;;;;;;GAaG;AACH,qBAAa,mBAAmB;IAiB5B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,mBAAmB;IACpC,OAAO,CAAC,aAAa,CAAC;IApBxB,4DAA4D;IAC5D,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAE/B;IAEV,gDAAgD;IAChD,OAAO,CAAC,OAAO,CAAS;IAExB;;;;;;OAMG;gBAEgB,MAAM,EAAE,mBAAmB,EAC3B,aAAa,EAAE,cAAc,EAC7B,UAAU,EAAE,WAAW,EACvB,mBAAmB,EAAE,mBAAmB,EACjD,aAAa,CAAC,EAAE,cAAc,YAAA;IAQxC;;;;;OAKG;IACH,KAAK,IAAI,IAAI;IAQb;;;;OAIG;IACH,IAAI,IAAI,IAAI;IAQZ;;OAEG;IACH,SAAS,IAAI,OAAO;IAIpB;;;;;OAKG;IACH,gBAAgB,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI;IAM7C;;;;;;;;;;OAUG;IACH,mBAAmB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO;IAUlD;;;;;;;OAOG;IACH,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG;QACxC,QAAQ,EAAE,MAAM,EAAE,CAAC;QACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;KACpB;IAeD;;;;;;;;;;;;;;OAcG;YACW,kBAAkB;CAoDjC"}
|