@serve.zone/dcrouter 18.1.0 → 18.1.1

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 (47) hide show
  1. package/deno.json +1 -1
  2. package/dist_serve/bundle.js +8 -8
  3. package/dist_ts/00_commitinfo_data.js +1 -1
  4. package/dist_ts/classes.dcrouter.d.ts +4 -1
  5. package/dist_ts/classes.dcrouter.js +30 -6
  6. package/dist_ts/db/documents/classes.authentication-event.doc.d.ts +25 -0
  7. package/dist_ts/db/documents/classes.authentication-event.doc.js +273 -0
  8. package/dist_ts/db/documents/classes.email-traffic-bucket.doc.d.ts +25 -0
  9. package/dist_ts/db/documents/classes.email-traffic-bucket.doc.js +200 -0
  10. package/dist_ts/db/documents/index.d.ts +2 -0
  11. package/dist_ts/db/documents/index.js +3 -1
  12. package/dist_ts/email/classes.accepted-email-spool.d.ts +1 -0
  13. package/dist_ts/email/classes.accepted-email-spool.js +9 -1
  14. package/dist_ts/monitoring/classes.metricsmanager.d.ts +19 -0
  15. package/dist_ts/monitoring/classes.metricsmanager.js +240 -44
  16. package/dist_ts/opsserver/handlers/admin.handler.d.ts +1 -0
  17. package/dist_ts/opsserver/handlers/admin.handler.js +61 -14
  18. package/dist_ts/opsserver/handlers/security.handler.js +21 -3
  19. package/dist_ts/opsserver/handlers/stats.handler.js +27 -10
  20. package/dist_ts/security/classes.authentication-event-manager.d.ts +35 -0
  21. package/dist_ts/security/classes.authentication-event-manager.js +185 -0
  22. package/dist_ts/security/index.d.ts +1 -0
  23. package/dist_ts/security/index.js +2 -1
  24. package/dist_ts_interfaces/data/stats.d.ts +16 -0
  25. package/dist_ts_migrations/index.js +74 -15
  26. package/dist_ts_web/00_commitinfo_data.js +1 -1
  27. package/dist_ts_web/elements/overview/ops-view-overview.js +3 -2
  28. package/dist_ts_web/elements/security/ops-view-security-authentication.js +20 -13
  29. package/dist_ts_web/elements/security/ops-view-security-overview.js +8 -11
  30. package/package.json +1 -1
  31. package/readme.md +8 -0
  32. package/ts/00_commitinfo_data.ts +1 -1
  33. package/ts/classes.dcrouter.ts +31 -5
  34. package/ts/db/documents/classes.authentication-event.doc.ts +248 -0
  35. package/ts/db/documents/classes.email-traffic-bucket.doc.ts +161 -0
  36. package/ts/db/documents/index.ts +2 -0
  37. package/ts/email/classes.accepted-email-spool.ts +8 -0
  38. package/ts/monitoring/classes.metricsmanager.ts +287 -50
  39. package/ts/opsserver/handlers/admin.handler.ts +74 -15
  40. package/ts/opsserver/handlers/security.handler.ts +23 -2
  41. package/ts/opsserver/handlers/stats.handler.ts +29 -9
  42. package/ts/security/classes.authentication-event-manager.ts +221 -0
  43. package/ts/security/index.ts +1 -0
  44. package/ts_web/00_commitinfo_data.ts +1 -1
  45. package/ts_web/elements/overview/ops-view-overview.ts +2 -1
  46. package/ts_web/elements/security/ops-view-security-authentication.ts +20 -13
  47. package/ts_web/elements/security/ops-view-security-overview.ts +7 -12
@@ -0,0 +1,185 @@
1
+ import * as plugins from '../plugins.js';
2
+ import { logger } from '../logger.js';
3
+ import { AuthenticationEventDoc } from '../db/documents/classes.authentication-event.doc.js';
4
+ import { SecurityEventType, SecurityLogLevel, SecurityLogger, } from './classes.securitylogger.js';
5
+ const MAX_IN_MEMORY_EVENTS = 10_000;
6
+ const MAX_PERSIST_BATCH_SIZE = 500;
7
+ export class AuthenticationEventManager {
8
+ dcRouterRef;
9
+ pendingEvents = new Map();
10
+ recentEvents = new Map();
11
+ flushInFlight;
12
+ pruneInFlight;
13
+ windowStatsInFlight = new Map();
14
+ constructor(dcRouterRef) {
15
+ this.dcRouterRef = dcRouterRef;
16
+ }
17
+ canPersist() {
18
+ return this.dcRouterRef.options.dbConfig?.enabled !== false
19
+ && Boolean(this.dcRouterRef.dcRouterDb?.isReady());
20
+ }
21
+ rememberEvent(eventArg) {
22
+ this.pendingEvents.set(eventArg.id, eventArg);
23
+ this.recentEvents.set(eventArg.id, eventArg);
24
+ while (this.pendingEvents.size > MAX_IN_MEMORY_EVENTS) {
25
+ const oldestId = this.pendingEvents.keys().next().value;
26
+ if (!oldestId)
27
+ break;
28
+ this.pendingEvents.delete(oldestId);
29
+ logger.log('error', 'Authentication event persistence buffer reached its limit; oldest event dropped');
30
+ }
31
+ while (this.recentEvents.size > MAX_IN_MEMORY_EVENTS) {
32
+ const oldestId = this.recentEvents.keys().next().value;
33
+ if (!oldestId)
34
+ break;
35
+ this.recentEvents.delete(oldestId);
36
+ }
37
+ }
38
+ async flushBufferedUnlocked() {
39
+ if (!this.canPersist() || this.pendingEvents.size === 0)
40
+ return;
41
+ const events = [...this.pendingEvents.values()];
42
+ for (let offset = 0; offset < events.length; offset += MAX_PERSIST_BATCH_SIZE) {
43
+ const batch = events.slice(offset, offset + MAX_PERSIST_BATCH_SIZE);
44
+ await AuthenticationEventDoc.upsertMany(batch);
45
+ for (const event of batch) {
46
+ if (this.pendingEvents.get(event.id) === event) {
47
+ this.pendingEvents.delete(event.id);
48
+ }
49
+ }
50
+ }
51
+ }
52
+ async recordAttempt(optionsArg) {
53
+ const event = {
54
+ id: `auth-${plugins.uuid.v4()}`,
55
+ timestamp: Date.now(),
56
+ username: String(optionsArg.username || '').trim().toLowerCase() || 'unknown',
57
+ success: optionsArg.success,
58
+ requestedAuthSource: optionsArg.requestedAuthSource,
59
+ ...(optionsArg.userId ? { userId: optionsArg.userId } : {}),
60
+ ...(optionsArg.resolvedAuthSource
61
+ ? { resolvedAuthSource: optionsArg.resolvedAuthSource }
62
+ : {}),
63
+ ...(optionsArg.failureReason ? { failureReason: optionsArg.failureReason } : {}),
64
+ };
65
+ // Buffer before any asynchronous persistence so authentication cannot be
66
+ // held behind a slow database and the bounded drop policy remains effective.
67
+ this.rememberEvent(event);
68
+ try {
69
+ SecurityLogger.getInstance().logEvent({
70
+ level: event.success ? SecurityLogLevel.INFO : SecurityLogLevel.WARN,
71
+ type: SecurityEventType.AUTHENTICATION,
72
+ message: event.success ? 'Authentication succeeded' : 'Authentication failed',
73
+ userId: event.userId,
74
+ success: event.success,
75
+ details: { authenticationEvent: event },
76
+ });
77
+ }
78
+ catch (error) {
79
+ logger.log('warn', `Unable to mirror authentication event to the security log: ${error.message}`);
80
+ }
81
+ return event;
82
+ }
83
+ flushBuffered() {
84
+ if (this.flushInFlight)
85
+ return this.flushInFlight;
86
+ const run = this.flushBufferedUnlocked();
87
+ this.flushInFlight = run;
88
+ run.then(() => { if (this.flushInFlight === run)
89
+ this.flushInFlight = undefined; }, () => { if (this.flushInFlight === run)
90
+ this.flushInFlight = undefined; });
91
+ return run;
92
+ }
93
+ pruneBefore(cutoffArg) {
94
+ if (this.pruneInFlight)
95
+ return this.pruneInFlight;
96
+ const run = this.canPersist()
97
+ ? AuthenticationEventDoc.pruneBefore(cutoffArg)
98
+ : Promise.resolve(0);
99
+ this.pruneInFlight = run;
100
+ run.then(() => { if (this.pruneInFlight === run)
101
+ this.pruneInFlight = undefined; }, () => { if (this.pruneInFlight === run)
102
+ this.pruneInFlight = undefined; });
103
+ return run;
104
+ }
105
+ getInMemoryWindow(cutoffArg, limitArg) {
106
+ const events = [...this.recentEvents.values()]
107
+ .filter((event) => event.timestamp >= cutoffArg)
108
+ .sort((a, b) => b.timestamp - a.timestamp || b.id.localeCompare(a.id));
109
+ return {
110
+ windowStart: cutoffArg,
111
+ successes: events.filter((event) => event.success).length,
112
+ failures: events.filter((event) => !event.success).length,
113
+ events: events.slice(0, limitArg),
114
+ };
115
+ }
116
+ async getWindowStatsUnlocked(windowMsArg = 24 * 60 * 60 * 1000, limitArg = 100) {
117
+ const cutoff = Date.now() - windowMsArg;
118
+ if (!this.canPersist()) {
119
+ return this.getInMemoryWindow(cutoff, limitArg);
120
+ }
121
+ try {
122
+ await this.flushBuffered();
123
+ }
124
+ catch (error) {
125
+ logger.log('warn', `Unable to flush authentication event buffer: ${error.message}`);
126
+ }
127
+ try {
128
+ const durable = await AuthenticationEventDoc.getWindowSummary(cutoff, limitArg);
129
+ const buffered = [...this.pendingEvents.values()]
130
+ .filter((event) => event.timestamp >= cutoff);
131
+ const existingIds = new Set();
132
+ const bufferedIds = buffered.map((event) => event.id);
133
+ for (let offset = 0; offset < bufferedIds.length; offset += MAX_PERSIST_BATCH_SIZE) {
134
+ const existingBatch = await AuthenticationEventDoc.findExistingIds(bufferedIds.slice(offset, offset + MAX_PERSIST_BATCH_SIZE));
135
+ existingBatch.forEach((id) => existingIds.add(id));
136
+ }
137
+ const unpersisted = buffered.filter((event) => !existingIds.has(event.id));
138
+ const mergedById = new Map();
139
+ for (const event of durable.events)
140
+ mergedById.set(event.id, event);
141
+ for (const event of unpersisted) {
142
+ if (!mergedById.has(event.id))
143
+ mergedById.set(event.id, event);
144
+ }
145
+ const mergedEvents = [...mergedById.values()]
146
+ .sort((a, b) => b.timestamp - a.timestamp || b.id.localeCompare(a.id))
147
+ .slice(0, limitArg);
148
+ return {
149
+ windowStart: cutoff,
150
+ successes: durable.successes + unpersisted.filter((event) => event.success).length,
151
+ failures: durable.failures + unpersisted.filter((event) => !event.success).length,
152
+ events: mergedEvents,
153
+ };
154
+ }
155
+ catch (error) {
156
+ logger.log('warn', `Unable to query durable authentication events: ${error.message}`);
157
+ return this.getInMemoryWindow(cutoff, limitArg);
158
+ }
159
+ }
160
+ getWindowStats(windowMsArg = 24 * 60 * 60 * 1000, limitArg = 100) {
161
+ if (!Number.isSafeInteger(windowMsArg) || windowMsArg <= 0) {
162
+ return Promise.reject(new Error('Authentication window must be a positive integer'));
163
+ }
164
+ if (!Number.isSafeInteger(limitArg) || limitArg <= 0 || limitArg > 500) {
165
+ return Promise.reject(new Error('Authentication event limit must be from 1 to 500'));
166
+ }
167
+ const key = `${windowMsArg}:${limitArg}`;
168
+ const existing = this.windowStatsInFlight.get(key);
169
+ if (existing)
170
+ return existing;
171
+ const run = this.getWindowStatsUnlocked(windowMsArg, limitArg);
172
+ this.windowStatsInFlight.set(key, run);
173
+ run.then(() => { if (this.windowStatsInFlight.get(key) === run)
174
+ this.windowStatsInFlight.delete(key); }, () => { if (this.windowStatsInFlight.get(key) === run)
175
+ this.windowStatsInFlight.delete(key); });
176
+ return run;
177
+ }
178
+ /** Test-only reset for the DcRouter-owned in-process buffers. */
179
+ async resetForTests() {
180
+ await this.flushInFlight?.catch(() => undefined);
181
+ this.pendingEvents.clear();
182
+ this.recentEvents.clear();
183
+ }
184
+ }
185
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5hdXRoZW50aWNhdGlvbi1ldmVudC1tYW5hZ2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vdHMvc2VjdXJpdHkvY2xhc3Nlcy5hdXRoZW50aWNhdGlvbi1ldmVudC1tYW5hZ2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sZUFBZSxDQUFDO0FBQ3pDLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFFdEMsT0FBTyxFQUFFLHNCQUFzQixFQUFFLE1BQU0scURBQXFELENBQUM7QUFPN0YsT0FBTyxFQUNMLGlCQUFpQixFQUNqQixnQkFBZ0IsRUFDaEIsY0FBYyxHQUNmLE1BQU0sNkJBQTZCLENBQUM7QUFFckMsTUFBTSxvQkFBb0IsR0FBRyxNQUFNLENBQUM7QUFDcEMsTUFBTSxzQkFBc0IsR0FBRyxHQUFHLENBQUM7QUFTbkMsTUFBTSxPQUFPLDBCQUEwQjtJQU9qQjtJQU5aLGFBQWEsR0FBRyxJQUFJLEdBQUcsRUFBZ0MsQ0FBQztJQUN4RCxZQUFZLEdBQUcsSUFBSSxHQUFHLEVBQWdDLENBQUM7SUFDdkQsYUFBYSxDQUFpQjtJQUM5QixhQUFhLENBQW1CO0lBQ2hDLG1CQUFtQixHQUFHLElBQUksR0FBRyxFQUErQyxDQUFDO0lBRXJGLFlBQW9CLFdBQXFCO1FBQXJCLGdCQUFXLEdBQVgsV0FBVyxDQUFVO0lBQUcsQ0FBQztJQUVyQyxVQUFVO1FBQ2hCLE9BQU8sSUFBSSxDQUFDLFdBQVcsQ0FBQyxPQUFPLENBQUMsUUFBUSxFQUFFLE9BQU8sS0FBSyxLQUFLO2VBQ3RELE9BQU8sQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLFVBQVUsRUFBRSxPQUFPLEVBQUUsQ0FBQyxDQUFDO0lBQ3ZELENBQUM7SUFFTyxhQUFhLENBQUMsUUFBOEI7UUFDbEQsSUFBSSxDQUFDLGFBQWEsQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLEVBQUUsRUFBRSxRQUFRLENB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
@@ -3,3 +3,4 @@ export { IPReputationChecker, ReputationThreshold, IPType, type IReputationResul
3
3
  export { ContentScanner, ThreatCategory, type IScanResult, type IContentScannerOptions } from './classes.contentscanner.js';
4
4
  export { SecurityPolicyManager, type ISecurityPolicyManagerOptions, type IRemoteIngressFirewallSnapshot, } from './classes.security-policy-manager.js';
5
5
  export * from './classes.route-policy-augmenter.js';
6
+ export * from './classes.authentication-event-manager.js';
@@ -3,4 +3,5 @@ export { IPReputationChecker, ReputationThreshold, IPType } from './classes.ipre
3
3
  export { ContentScanner, ThreatCategory } from './classes.contentscanner.js';
4
4
  export { SecurityPolicyManager, } from './classes.security-policy-manager.js';
5
5
  export * from './classes.route-policy-augmenter.js';
6
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9zZWN1cml0eS9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ0wsY0FBYyxFQUNkLGdCQUFnQixFQUNoQixpQkFBaUIsRUFFbEIsTUFBTSw2QkFBNkIsQ0FBQztBQUVyQyxPQUFPLEVBQ0wsbUJBQW1CLEVBQ25CLG1CQUFtQixFQUNuQixNQUFNLEVBR1AsTUFBTSxrQ0FBa0MsQ0FBQztBQUUxQyxPQUFPLEVBQ0wsY0FBYyxFQUNkLGNBQWMsRUFHZixNQUFNLDZCQUE2QixDQUFDO0FBRXJDLE9BQU8sRUFDTCxxQkFBcUIsR0FHdEIsTUFBTSxzQ0FBc0MsQ0FBQztBQUM5QyxjQUFjLHFDQUFxQyxDQUFDIn0=
6
+ export * from './classes.authentication-event-manager.js';
7
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9zZWN1cml0eS9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ0wsY0FBYyxFQUNkLGdCQUFnQixFQUNoQixpQkFBaUIsRUFFbEIsTUFBTSw2QkFBNkIsQ0FBQztBQUVyQyxPQUFPLEVBQ0wsbUJBQW1CLEVBQ25CLG1CQUFtQixFQUNuQixNQUFNLEVBR1AsTUFBTSxrQ0FBa0MsQ0FBQztBQUUxQyxPQUFPLEVBQ0wsY0FBYyxFQUNkLGNBQWMsRUFHZixNQUFNLDZCQUE2QixDQUFDO0FBRXJDLE9BQU8sRUFDTCxxQkFBcUIsR0FHdEIsTUFBTSxzQ0FBc0MsQ0FBQztBQUM5QyxjQUFjLHFDQUFxQyxDQUFDO0FBQ3BELGNBQWMsMkNBQTJDLENBQUMifQ==
@@ -82,6 +82,19 @@ export interface ISecurityEvent {
82
82
  domain?: string;
83
83
  success?: boolean;
84
84
  }
85
+ export type TAuthenticationSource = 'auto' | 'local' | 'idp.global';
86
+ export type TResolvedAuthenticationSource = Exclude<TAuthenticationSource, 'auto'>;
87
+ export type TAuthenticationFailureReason = 'invalidCredentials' | 'serviceUnavailable' | 'identityIssuanceFailed' | 'internalError';
88
+ export interface IAuthenticationEvent {
89
+ id: string;
90
+ timestamp: number;
91
+ username: string;
92
+ userId?: string;
93
+ success: boolean;
94
+ requestedAuthSource: TAuthenticationSource;
95
+ resolvedAuthSource?: TResolvedAuthenticationSource;
96
+ failureReason?: TAuthenticationFailureReason;
97
+ }
85
98
  export interface ISecurityMetrics {
86
99
  blockedIPs: string[];
87
100
  reputationScores: {
@@ -91,6 +104,9 @@ export interface ISecurityMetrics {
91
104
  malwareDetected: number;
92
105
  phishingDetected: number;
93
106
  authenticationFailures: number;
107
+ authenticationSuccesses: number;
108
+ authenticationWindowStart: number;
109
+ authenticationEvents?: IAuthenticationEvent[];
94
110
  suspiciousActivities: number;
95
111
  recentEvents?: ISecurityEvent[];
96
112
  }