@jwilleke/ngdpbase-types 5.41.1 → 5.42.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/lib/src/managers/AddonsManager.d.ts +8 -0
- package/lib/src/managers/AttachmentManager.d.ts +59 -0
- package/lib/src/managers/AuditManager.d.ts +477 -0
- package/lib/src/managers/AuthManager.d.ts +247 -15
- package/lib/src/managers/AuthManager.js +588 -45
- package/lib/src/managers/ConsentManager.d.ts +15 -0
- package/lib/src/managers/ImportManager.d.ts +15 -0
- package/lib/src/providers/BaseAttachmentProvider.d.ts +4 -0
- package/lib/src/providers/BaseAuditProvider.d.ts +492 -0
- package/lib/src/providers/BaseAuthProvider.d.ts +2 -0
- package/lib/src/providers/BaseCredentialsProvider.d.ts +2 -2
- package/lib/src/providers/BaseCredentialsProvider.js +1 -1
- package/lib/src/providers/BasicAttachmentProvider.d.ts +9 -0
- package/lib/src/providers/FileCredentialsProvider.js +1 -1
- package/lib/src/providers/NullAuditProvider.d.ts +82 -0
- package/lib/src/providers/TotpAuthProvider.d.ts +55 -0
- package/lib/src/providers/TotpAuthProvider.js +145 -0
- package/lib/src/types/Consent.d.ts +17 -4
- package/lib/src/types/Consent.js +11 -1
- package/lib/src/types/Provider.d.ts +6 -0
- package/lib/src/types/express.d.ts +22 -0
- package/lib/src/utils/auditChain.d.ts +83 -0
- package/lib/src/utils/auditHeadWitness.d.ts +97 -0
- package/lib/src/utils/auditLifecycle.d.ts +71 -0
- package/lib/src/utils/browserDescription.d.ts +18 -0
- package/lib/src/utils/browserDescription.js +12 -0
- package/lib/src/utils/postureRecord.d.ts +73 -0
- package/lib/src/utils/privateStorePath.d.ts +6 -0
- package/lib/src/utils/privateStorePath.js +8 -0
- package/lib/src/utils/securityPosture.d.ts +52 -0
- package/lib/src/utils/tlsConfig.d.ts +59 -0
- package/lib/src/utils/totpSeedCipher.d.ts +4 -0
- package/lib/src/utils/totpSeedCipher.js +45 -0
- package/package.json +5 -2
|
@@ -175,6 +175,14 @@ export interface AddonProfileSection {
|
|
|
175
175
|
title: string;
|
|
176
176
|
/** Raw HTML rendered inside the card body; should contain form input fields. */
|
|
177
177
|
html: string;
|
|
178
|
+
/**
|
|
179
|
+
* Font Awesome icon shown before the title in the card's header, such as
|
|
180
|
+
* `'fa-book'` (#1541). Optional; the host shows `fa-puzzle-piece` when it is
|
|
181
|
+
* missing or not a plain `fa-` name.
|
|
182
|
+
*/
|
|
183
|
+
icon?: string;
|
|
184
|
+
/** Optional muted text shown after the title in the card's header (#1541). */
|
|
185
|
+
hint?: string;
|
|
178
186
|
}
|
|
179
187
|
/**
|
|
180
188
|
* One entry per addon that contributed a profile section, returned by
|
|
@@ -56,6 +56,8 @@ interface BaseAttachmentProvider {
|
|
|
56
56
|
filesInStoreForPage(location: StoreFileLocation, pageName: string): Promise<StoreFileEntry[]>;
|
|
57
57
|
setFileMentionInStore(location: StoreFileLocation, id: string, pageName: string, mentioned: boolean): Promise<boolean>;
|
|
58
58
|
deleteFileInStore(location: StoreFileLocation, id: string): Promise<StoreFileEntry | null>;
|
|
59
|
+
readStoreRenumbered(location: StoreFileLocation): Promise<Map<string, string>>;
|
|
60
|
+
noteStoreRenumbered(location: StoreFileLocation, pairs: ReadonlyMap<string, string>): Promise<void>;
|
|
59
61
|
searchFilesInStore(location: StoreFileLocation, query: AssetQuery): Promise<AssetRecord[]>;
|
|
60
62
|
privateRecordsInSharedIndex(): Array<{
|
|
61
63
|
id: string;
|
|
@@ -117,6 +119,23 @@ export interface PutOptions {
|
|
|
117
119
|
* record names the file by id only, so it is not recorded there.
|
|
118
120
|
*/
|
|
119
121
|
importedFrom?: string;
|
|
122
|
+
/**
|
|
123
|
+
* A takeout import's file (#2188): the ids it had, the one to try first
|
|
124
|
+
* first, so a page still linking `/attachments/{id}` finds it again. The
|
|
125
|
+
* file is stored under the first that is free ({@link restoreIdIsFree});
|
|
126
|
+
* when none is, it gets a new id, as any upload does. Honoured only in a
|
|
127
|
+
* vault, never a shared folder or the shared pool; the import passes it
|
|
128
|
+
* only for one of its user's own stores. The stored id is in the returned
|
|
129
|
+
* metadata either way.
|
|
130
|
+
*/
|
|
131
|
+
restoreIds?: readonly string[];
|
|
132
|
+
/**
|
|
133
|
+
* The ids files on the site held when the caller's run began, from
|
|
134
|
+
* {@link heldFileIds}, read once per run (#2188). With it, a restore checks
|
|
135
|
+
* the set instead of every store's folder on disk, and adds the id it
|
|
136
|
+
* stores to it.
|
|
137
|
+
*/
|
|
138
|
+
heldIds?: Set<string>;
|
|
120
139
|
}
|
|
121
140
|
/**
|
|
122
141
|
* The page-tied upload's options (#1396, #1398): today's callers name the page
|
|
@@ -216,6 +235,10 @@ declare class AttachmentManager extends BaseManager implements CatalogSource {
|
|
|
216
235
|
/** What the last check for vault pages using shared-pool files found, and the degraded reason it set (#1842). */
|
|
217
236
|
private poolFileFindings;
|
|
218
237
|
private poolFileReason;
|
|
238
|
+
/** #2188: ids a restore has claimed and not yet written; one id is claimed by one put at a time. */
|
|
239
|
+
private readonly claimedRestoreIds;
|
|
240
|
+
/** #2188: ids a restore has stored since start, which a run's held ids read earlier may not list. */
|
|
241
|
+
private readonly restoredIds;
|
|
219
242
|
private maxSize;
|
|
220
243
|
private allowedTypes;
|
|
221
244
|
/**
|
|
@@ -365,6 +388,42 @@ declare class AttachmentManager extends BaseManager implements CatalogSource {
|
|
|
365
388
|
* store's file by id only, #2048), and FileManager, the owner, records it.
|
|
366
389
|
*/
|
|
367
390
|
storeInPlace(ctx: ActorContext, place: FilePlace, file: PutFile, options?: PutOptions): Promise<StoredInPlace>;
|
|
391
|
+
/**
|
|
392
|
+
* Whether a file brought back by a takeout re-import may be stored under
|
|
393
|
+
* the id it had, `id` (#2188). Only an id of the shape a store gives
|
|
394
|
+
* (`isRestorableFileId`), and only when no file holds it: not the target
|
|
395
|
+
* store's index, not the shared pool, and no file on disk in any store of
|
|
396
|
+
* any owner or shared folder. A store names each file's bytes by its id
|
|
397
|
+
* (`{id}.ext`) in the clear, sealed or not, so another owner's sealed store
|
|
398
|
+
* is checked without its key. An id another file holds is never reused, so
|
|
399
|
+
* a takeout cannot claim another file's id, its own or anyone's.
|
|
400
|
+
*
|
|
401
|
+
* With `held` ({@link heldFileIds}, read once by the caller's run), the
|
|
402
|
+
* stores on disk are not read again: the id is free when the set lacks it,
|
|
403
|
+
* unless a restore stored that id since, which only the disk can settle.
|
|
404
|
+
*/
|
|
405
|
+
private restoreIdIsFree;
|
|
406
|
+
/**
|
|
407
|
+
* The ids of every file on disk in any store of any owner or shared folder,
|
|
408
|
+
* by the names of their bytes (#2188). With `only`, stops at that id.
|
|
409
|
+
*/
|
|
410
|
+
private storeIdsOnDisk;
|
|
411
|
+
/**
|
|
412
|
+
* The ids files in the site's stores hold now, read once, for a takeout
|
|
413
|
+
* import to pass as `PutOptions.heldIds` to each file it puts (#2188).
|
|
414
|
+
* Ids only, from the names of the bytes on disk; no store is opened.
|
|
415
|
+
*/
|
|
416
|
+
heldFileIds(): Promise<Set<string>>;
|
|
417
|
+
/**
|
|
418
|
+
* The ids a takeout import gave the files of `ctx`'s own store `store` that
|
|
419
|
+
* could not keep their own, as takeout id → id here (#2188), or null when
|
|
420
|
+
* this context cannot open the store. Ids only.
|
|
421
|
+
*/
|
|
422
|
+
ownStoreRenumbered(ctx: ActorContext, store: string): Promise<Map<string, string> | null>;
|
|
423
|
+
/** Adds `pairs` to {@link ownStoreRenumbered}'s, for a run that stored files under new ids (#2188). */
|
|
424
|
+
noteOwnStoreRenumbered(ctx: ActorContext, store: string, pairs: ReadonlyMap<string, string>): Promise<void>;
|
|
425
|
+
/** `ctx`'s own store `store`, as {@link ownStoreFingerprints} reaches it, or null. */
|
|
426
|
+
private ownStoreLocation;
|
|
368
427
|
/**
|
|
369
428
|
* The username an upload is recorded under (#1926): the person the context
|
|
370
429
|
* names. Asked after policy has allowed the upload and before anything is
|
|
@@ -0,0 +1,477 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The caller may not query the audit log (#1116, #1165).
|
|
3
|
+
*
|
|
4
|
+
* A distinct type rather than a bare Error so a route can tell an
|
|
5
|
+
* authorization refusal from a genuine fault. #1165 was hard to diagnose
|
|
6
|
+
* precisely because it could not: the route's catch-all turned this refusal
|
|
7
|
+
* into `500 Error loading audit logs`, so "you may not read this" and
|
|
8
|
+
* "auditing is broken" were the same plain-text page.
|
|
9
|
+
*
|
|
10
|
+
* Matching on the message string would work today and break the first time
|
|
11
|
+
* somebody rewords it, which is why this is a type.
|
|
12
|
+
*/
|
|
13
|
+
export declare class AuditQueryForbiddenError extends Error {
|
|
14
|
+
constructor(message: string);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* AuditManager - Comprehensive audit trail system for access control and security monitoring
|
|
18
|
+
*
|
|
19
|
+
* Extends BaseManager following the JSPWiki modular manager pattern with provider architecture.
|
|
20
|
+
* Follows the provider pattern established in CacheManager, AttachmentManager, PageManager.
|
|
21
|
+
* Supports pluggable audit storage backends (file, database, cloud logging).
|
|
22
|
+
*
|
|
23
|
+
* @class AuditManager
|
|
24
|
+
* @extends BaseManager
|
|
25
|
+
*
|
|
26
|
+
* @property {BaseAuditProvider|null} provider - The active audit provider
|
|
27
|
+
* @property {string|null} providerClass - The class name of the loaded provider
|
|
28
|
+
*
|
|
29
|
+
* @see {@link BaseManager} for base functionality
|
|
30
|
+
* @see {@link FileAuditProvider} for default provider implementation
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* const auditManager = engine.getManager('AuditManager');
|
|
34
|
+
* await auditManager.logAccess('admin', 'Main', 'view', 'granted');
|
|
35
|
+
*/
|
|
36
|
+
import BaseManager, { type BackupData, type ManagerBackupOptions, type ManagerRestoreOptions } from './BaseManager.js';
|
|
37
|
+
import { type ActorContext } from '../context/ActorContext.js';
|
|
38
|
+
import type { PermissionSubject } from './UserManager.js';
|
|
39
|
+
import { type AuditEventName } from '../utils/auditEventNames.js';
|
|
40
|
+
import { WikiEngine } from '../types/WikiEngine.js';
|
|
41
|
+
import type { ReportedValues } from './AuthManager.js';
|
|
42
|
+
import type { AuditReport } from '../providers/BaseAuditProvider.js';
|
|
43
|
+
import { type AuditRecordOutcome } from '../utils/auditEvents.js';
|
|
44
|
+
/**
|
|
45
|
+
* Base audit event structure
|
|
46
|
+
*/
|
|
47
|
+
interface AuditEvent {
|
|
48
|
+
eventType: AuditEventName;
|
|
49
|
+
user: string;
|
|
50
|
+
userId?: string;
|
|
51
|
+
sessionId?: string;
|
|
52
|
+
ipAddress?: string;
|
|
53
|
+
userAgent?: string;
|
|
54
|
+
resource?: string;
|
|
55
|
+
resourceType?: string;
|
|
56
|
+
action?: string;
|
|
57
|
+
result?: string;
|
|
58
|
+
reason?: string;
|
|
59
|
+
policyId?: string;
|
|
60
|
+
policyName?: string;
|
|
61
|
+
severity?: 'low' | 'medium' | 'high' | 'critical';
|
|
62
|
+
duration?: number;
|
|
63
|
+
context?: Record<string, unknown>;
|
|
64
|
+
metadata?: Record<string, unknown>;
|
|
65
|
+
timestamp?: string;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* User information for audit events
|
|
69
|
+
*/
|
|
70
|
+
interface AuditUser {
|
|
71
|
+
username?: string;
|
|
72
|
+
id?: string;
|
|
73
|
+
roles?: string[];
|
|
74
|
+
attributes?: Record<string, unknown>;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Context for access control decisions
|
|
78
|
+
*/
|
|
79
|
+
interface AccessContext {
|
|
80
|
+
user?: AuditUser;
|
|
81
|
+
sessionId?: string;
|
|
82
|
+
ipAddress?: string;
|
|
83
|
+
userAgent?: string;
|
|
84
|
+
resource?: string;
|
|
85
|
+
resourceType?: string;
|
|
86
|
+
action?: string;
|
|
87
|
+
requestMethod?: string;
|
|
88
|
+
requestPath?: string;
|
|
89
|
+
timestamp?: string;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Policy information
|
|
93
|
+
*/
|
|
94
|
+
interface PolicyInfo {
|
|
95
|
+
id: string;
|
|
96
|
+
name: string;
|
|
97
|
+
priority?: number;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Context for authentication events
|
|
101
|
+
*/
|
|
102
|
+
interface AuthenticationContext {
|
|
103
|
+
username?: string;
|
|
104
|
+
ipAddress?: string;
|
|
105
|
+
userAgent?: string;
|
|
106
|
+
loginMethod?: string;
|
|
107
|
+
attemptedUsername?: string;
|
|
108
|
+
/** #1633: an outside provider's reported `amr` / `acr`, and whether it is trusted; never a token. */
|
|
109
|
+
reported?: ReportedValues;
|
|
110
|
+
/** #1523 slice 1c: the second-factor prompt was skipped on a remembered browser. Not a factor. */
|
|
111
|
+
knownDevice?: boolean;
|
|
112
|
+
/** #1523: the RFC 8176 methods of a completed sign-in, so a remembered browser's row can be checked against it. */
|
|
113
|
+
amr?: string[];
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* What a remembered browser's row is checked against (#1523): the fields of
|
|
117
|
+
* one `authentication-success` record, never the rest of it.
|
|
118
|
+
*/
|
|
119
|
+
export interface AuthenticationRecordSummary {
|
|
120
|
+
id: string;
|
|
121
|
+
user: string;
|
|
122
|
+
loginMethod?: string;
|
|
123
|
+
amr?: string[];
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Context for security events
|
|
127
|
+
*/
|
|
128
|
+
interface SecurityContext {
|
|
129
|
+
/**
|
|
130
|
+
* The context the event happened in (#1762 slice 4): the row's "who" is
|
|
131
|
+
* built from it (`actorOf`), so under a proxy grant it names both people.
|
|
132
|
+
* Mandatory: null only for a caller with no context (a sign-in throttle,
|
|
133
|
+
* before anyone is signed in). Never stored on the row itself.
|
|
134
|
+
*/
|
|
135
|
+
subject: ActorContext | null;
|
|
136
|
+
/** The named user, for a caller with no context (a sign-in throttle, before anyone is signed in). */
|
|
137
|
+
user?: AuditUser;
|
|
138
|
+
ipAddress?: string;
|
|
139
|
+
userAgent?: string;
|
|
140
|
+
[key: string]: unknown;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Filters for searching audit logs
|
|
144
|
+
*/
|
|
145
|
+
interface AuditFilters {
|
|
146
|
+
user?: string;
|
|
147
|
+
/** The person who actually acted, under a proxy grant (#1762). */
|
|
148
|
+
actor?: string;
|
|
149
|
+
eventType?: string;
|
|
150
|
+
result?: string;
|
|
151
|
+
severity?: 'low' | 'medium' | 'high' | 'critical';
|
|
152
|
+
startDate?: string | Date;
|
|
153
|
+
endDate?: string | Date;
|
|
154
|
+
resource?: string;
|
|
155
|
+
action?: string;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Options for searching audit logs
|
|
159
|
+
*/
|
|
160
|
+
interface AuditSearchOptions {
|
|
161
|
+
limit?: number;
|
|
162
|
+
offset?: number;
|
|
163
|
+
sortBy?: string;
|
|
164
|
+
sortOrder?: 'asc' | 'desc';
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Search results structure
|
|
168
|
+
*/
|
|
169
|
+
interface AuditSearchResults {
|
|
170
|
+
results: AuditEvent[];
|
|
171
|
+
total: number;
|
|
172
|
+
limit: number;
|
|
173
|
+
offset: number;
|
|
174
|
+
hasMore: boolean;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Audit statistics structure
|
|
178
|
+
*/
|
|
179
|
+
interface AuditStats {
|
|
180
|
+
totalEvents: number;
|
|
181
|
+
eventsByType: Record<string, number>;
|
|
182
|
+
eventsByResult: Record<string, number>;
|
|
183
|
+
eventsBySeverity: Record<string, number>;
|
|
184
|
+
eventsByUser: Record<string, number>;
|
|
185
|
+
recentActivity: AuditEvent[];
|
|
186
|
+
securityIncidents: number;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Who is asking for audit records (#1116): the request's subject (#1762
|
|
190
|
+
* slice 4), so the decision is the PDP's for the subject as it is — under a
|
|
191
|
+
* proxy grant, bounded by the grant and the actor — and the export row names
|
|
192
|
+
* both people. The permission decision is derived inside AuditManager, never
|
|
193
|
+
* passed in.
|
|
194
|
+
*/
|
|
195
|
+
export type AuditQueryCaller = PermissionSubject;
|
|
196
|
+
declare class AuditManager extends BaseManager {
|
|
197
|
+
private provider;
|
|
198
|
+
private providerClass;
|
|
199
|
+
/**
|
|
200
|
+
* Creates a new AuditManager instance
|
|
201
|
+
*
|
|
202
|
+
* @constructor
|
|
203
|
+
* @param {WikiEngine} engine - The wiki engine instance
|
|
204
|
+
*/
|
|
205
|
+
constructor(engine: WikiEngine);
|
|
206
|
+
/**
|
|
207
|
+
* Initialize the AuditManager and load the configured provider
|
|
208
|
+
*
|
|
209
|
+
* @async
|
|
210
|
+
* @param {Record<string, unknown>} [config={}] - Configuration object (unused, reads from ConfigurationManager)
|
|
211
|
+
* @returns {Promise<void>}
|
|
212
|
+
* @throws {Error} If ConfigurationManager is not available or provider fails to load
|
|
213
|
+
*/
|
|
214
|
+
initialize(config?: Record<string, unknown>): Promise<void>;
|
|
215
|
+
/**
|
|
216
|
+
* Load the audit provider dynamically
|
|
217
|
+
*
|
|
218
|
+
* @private
|
|
219
|
+
* @returns {Promise<void>}
|
|
220
|
+
*/
|
|
221
|
+
/**
|
|
222
|
+
* Whether auditing is running degraded — configured but not actually working
|
|
223
|
+
* (#1118).
|
|
224
|
+
*
|
|
225
|
+
* Distinct from auditing being OFF. An operator who selects
|
|
226
|
+
* `nullauditprovider`, or sets `ngdpbase.audit.enabled: false`, has made a
|
|
227
|
+
* decision that is on the record. An instance whose configured provider
|
|
228
|
+
* failed has not, and until this existed it had no way to say so: the server
|
|
229
|
+
* booted healthy, the audit page rendered empty, and the only thing that
|
|
230
|
+
* would have recorded the problem was the thing that failed.
|
|
231
|
+
*/
|
|
232
|
+
private degraded;
|
|
233
|
+
/** True when audit is configured but not working. */
|
|
234
|
+
isDegraded(): boolean;
|
|
235
|
+
/** Why audit is degraded, or null. */
|
|
236
|
+
degradedReason(): string | null;
|
|
237
|
+
/**
|
|
238
|
+
* What this instance's auditing actually does right now (#1118).
|
|
239
|
+
*
|
|
240
|
+
* Reportable rather than inferable: a security property that has to be
|
|
241
|
+
* deduced from configuration is not one an instance can be assessed on.
|
|
242
|
+
*/
|
|
243
|
+
getAuditPosture(): {
|
|
244
|
+
provider: string;
|
|
245
|
+
configured: string;
|
|
246
|
+
degraded: boolean;
|
|
247
|
+
reason: string | null;
|
|
248
|
+
guarantees: AuditReport | null;
|
|
249
|
+
};
|
|
250
|
+
/**
|
|
251
|
+
* Begin a new audit chain, recording that the old one was abandoned (#1124).
|
|
252
|
+
*
|
|
253
|
+
* Exposed so the operator command can reach it. Never called automatically —
|
|
254
|
+
* a system that silently repairs its own audit chain is worse than one that
|
|
255
|
+
* stays visibly broken.
|
|
256
|
+
*/
|
|
257
|
+
restartAuditChain(reason: string, ctx: ActorContext): Promise<string>;
|
|
258
|
+
/**
|
|
259
|
+
* Fall back to the inert provider, recording that we did (#1118).
|
|
260
|
+
*
|
|
261
|
+
* @private
|
|
262
|
+
*/
|
|
263
|
+
private degradeToNull;
|
|
264
|
+
private loadProvider;
|
|
265
|
+
/**
|
|
266
|
+
* Normalize provider name to PascalCase class name
|
|
267
|
+
*
|
|
268
|
+
* @param {string} providerName - Lowercase provider name (e.g., 'fileauditprovider')
|
|
269
|
+
* @returns {string} PascalCase class name (e.g., 'FileAuditProvider')
|
|
270
|
+
* @private
|
|
271
|
+
*/
|
|
272
|
+
private normalizeProviderName;
|
|
273
|
+
/**
|
|
274
|
+
* Log an audit event
|
|
275
|
+
*
|
|
276
|
+
* @param {AuditEvent} auditEvent - Audit event data
|
|
277
|
+
* @returns {Promise<string>} Event ID
|
|
278
|
+
*/
|
|
279
|
+
logAuditEvent(auditEvent: AuditEvent): Promise<string>;
|
|
280
|
+
/**
|
|
281
|
+
* The one door for the helpers below (#1205): through `recordAuditEvent`,
|
|
282
|
+
* so the `enabled` switch, the on-failure rule, and the outcome are the same as for
|
|
283
|
+
* every other emitter. Calling `logAuditEvent` directly skipped all three.
|
|
284
|
+
*/
|
|
285
|
+
private record;
|
|
286
|
+
/** {@link record}, and the stored record's id when it was recorded (#1523). */
|
|
287
|
+
private recordWithId;
|
|
288
|
+
/**
|
|
289
|
+
* Log access control decision
|
|
290
|
+
*
|
|
291
|
+
* @param {AccessContext} context - Access context
|
|
292
|
+
* @param {string} result - 'allow', 'deny', 'error'
|
|
293
|
+
* @param {string} reason - Reason for the decision
|
|
294
|
+
* @param {PolicyInfo | null} policy - Policy that made the decision
|
|
295
|
+
* @returns What became of the record (#1205)
|
|
296
|
+
*/
|
|
297
|
+
logAccessDecision(context: AccessContext, result: string, reason: string, policy?: PolicyInfo | null): Promise<AuditRecordOutcome>;
|
|
298
|
+
/**
|
|
299
|
+
* Log policy evaluation
|
|
300
|
+
*
|
|
301
|
+
* @param {AccessContext} context - Evaluation context
|
|
302
|
+
* @param {PolicyInfo[]} policies - Policies evaluated
|
|
303
|
+
* @param {string} finalResult - Final result
|
|
304
|
+
* @param {number} duration - Evaluation duration in ms
|
|
305
|
+
* @returns What became of the record (#1205)
|
|
306
|
+
*/
|
|
307
|
+
logPolicyEvaluation(context: AccessContext, policies: PolicyInfo[], finalResult: string, duration: number): Promise<AuditRecordOutcome>;
|
|
308
|
+
/**
|
|
309
|
+
* Log authentication event
|
|
310
|
+
*
|
|
311
|
+
* @param {AuthenticationContext} context - Authentication context
|
|
312
|
+
* @param {string} result - 'success', 'failure', 'logout'
|
|
313
|
+
* @param {string} reason - Reason for result
|
|
314
|
+
* @returns What became of the record (#1205), and its id when it was
|
|
315
|
+
* recorded: a remembered browser's row names its sign-in's record (#1523)
|
|
316
|
+
*/
|
|
317
|
+
logAuthentication(context: AuthenticationContext, result: string, reason: string): Promise<{
|
|
318
|
+
outcome: AuditRecordOutcome;
|
|
319
|
+
id?: string;
|
|
320
|
+
}>;
|
|
321
|
+
/**
|
|
322
|
+
* The `authentication-success` record with this id, or null (#1523): a
|
|
323
|
+
* remembered browser counts only while the record of the sign-in that
|
|
324
|
+
* remembered it says the same as its row. Only the fields that check needs
|
|
325
|
+
* leave this method, so it is not an audit query and asks no caller; a
|
|
326
|
+
* record of any other kind is null. Null too when the provider cannot look
|
|
327
|
+
* a record up by id.
|
|
328
|
+
*/
|
|
329
|
+
authenticationRecord(id: string): Promise<AuthenticationRecordSummary | null>;
|
|
330
|
+
/**
|
|
331
|
+
* Log security event
|
|
332
|
+
*
|
|
333
|
+
* @param {SecurityContext} context - Security context
|
|
334
|
+
* @param {string} eventType - Type of security event
|
|
335
|
+
* @param {string} severity - 'low', 'medium', 'high', 'critical'
|
|
336
|
+
* @param {string} description - Event description
|
|
337
|
+
* @returns What became of the record (#1205)
|
|
338
|
+
*/
|
|
339
|
+
logSecurityEvent(context: SecurityContext, eventType: string, severity: 'low' | 'medium' | 'high' | 'critical', description: string): Promise<AuditRecordOutcome>;
|
|
340
|
+
/**
|
|
341
|
+
* #1116: the gate on every audit query, inside the door.
|
|
342
|
+
*
|
|
343
|
+
* The audit list was the counterexample to the list-gate rule: this manager
|
|
344
|
+
* applied no authorization of its own, safe only because one admin-system
|
|
345
|
+
* check gated the whole page at the route — exactly the reasoning that
|
|
346
|
+
* stops working the moment a second caller appears. The caller supplies its
|
|
347
|
+
* subject; the decision is derived here, by the PDP (#1762 slice 4: the
|
|
348
|
+
* subject as it is, so a person acting for someone is bounded by the grant
|
|
349
|
+
* and by what they hold themselves, never by the represented person's roles
|
|
350
|
+
* alone). Fail closed: no caller, no username, no PDP, or no permission all
|
|
351
|
+
* refuse. The audit log has no per-record narrowing, and a list that
|
|
352
|
+
* cannot be narrowed refuses rather than returning everything.
|
|
353
|
+
*/
|
|
354
|
+
private assertQueryCallerAllowed;
|
|
355
|
+
/**
|
|
356
|
+
* Search audit logs
|
|
357
|
+
*
|
|
358
|
+
* @param {AuditFilters} filters - Search filters
|
|
359
|
+
* @param {AuditSearchOptions} options - Search options
|
|
360
|
+
* @param {AuditQueryCaller} caller - Who is asking: the request's subject (the decision is made here)
|
|
361
|
+
* @returns {Promise<AuditSearchResults>} Search results
|
|
362
|
+
*/
|
|
363
|
+
searchAuditLogs(filters?: AuditFilters, options?: AuditSearchOptions, caller?: AuditQueryCaller): Promise<AuditSearchResults>;
|
|
364
|
+
/**
|
|
365
|
+
* The audit entries about one person, newest first, a page at a time
|
|
366
|
+
* (#1537): the one audit log, filtered to the rows where the person is the
|
|
367
|
+
* `user` (the account acted on, or the person represented under a proxy
|
|
368
|
+
* grant), the `actor` (who actually did it under a proxy grant), or the
|
|
369
|
+
* owner of the resource the row names (`metadata.owner`: the user's
|
|
370
|
+
* identity `@id` on rows from #2041 on, their username on older rows).
|
|
371
|
+
* Nothing is removed from the log by reading it.
|
|
372
|
+
*
|
|
373
|
+
* Decided by the PDP with the caller's subject: a person asking about
|
|
374
|
+
* themselves needs `profile-manage` (granted to every account); asking about
|
|
375
|
+
* anyone else is reading the audit log, `admin-system`. Under a proxy grant
|
|
376
|
+
* the subject's username is the person represented, and the PDP bounds the
|
|
377
|
+
* answer by the grant. Refused with {@link AuditQueryForbiddenError}.
|
|
378
|
+
*
|
|
379
|
+
* @param person - The username whose entries are listed
|
|
380
|
+
* @param options - `limit` (capped by the provider) and `offset`
|
|
381
|
+
* @param caller - Who is asking: the request's subject
|
|
382
|
+
*/
|
|
383
|
+
searchEntriesAbout(person: string, options?: {
|
|
384
|
+
limit?: number;
|
|
385
|
+
offset?: number;
|
|
386
|
+
}, caller?: AuditQueryCaller): Promise<AuditSearchResults>;
|
|
387
|
+
/**
|
|
388
|
+
* Get audit statistics
|
|
389
|
+
*
|
|
390
|
+
* @param {AuditFilters} filters - Optional filters
|
|
391
|
+
* @returns {Promise<AuditStats>} Audit statistics
|
|
392
|
+
*/
|
|
393
|
+
getAuditStats(filters?: AuditFilters, caller?: AuditQueryCaller): Promise<AuditStats>;
|
|
394
|
+
/**
|
|
395
|
+
* Export audit logs
|
|
396
|
+
*
|
|
397
|
+
* @param {AuditFilters} filters - Export filters
|
|
398
|
+
* @param {string} format - Export format ('json', 'csv')
|
|
399
|
+
* @param {AuditQueryCaller} caller - Who is asking (#1116)
|
|
400
|
+
* @returns {Promise<string>} Exported data
|
|
401
|
+
*/
|
|
402
|
+
exportAuditLogs(filters?: AuditFilters, format?: string, caller?: AuditQueryCaller): Promise<string>;
|
|
403
|
+
/**
|
|
404
|
+
* Flush audit queue to disk
|
|
405
|
+
*
|
|
406
|
+
* @returns {Promise<void>}
|
|
407
|
+
*/
|
|
408
|
+
flushAuditQueue(): Promise<void>;
|
|
409
|
+
/**
|
|
410
|
+
* Clean up old audit logs based on retention policy
|
|
411
|
+
*
|
|
412
|
+
* @returns {Promise<void>}
|
|
413
|
+
*/
|
|
414
|
+
cleanupOldLogs(): Promise<void>;
|
|
415
|
+
/**
|
|
416
|
+
* The most recent record of a lifecycle phase, or null (#1149).
|
|
417
|
+
*
|
|
418
|
+
* A provider that cannot be searched returns null rather than throwing: an
|
|
419
|
+
* instance must still boot when its audit history is unreadable, and
|
|
420
|
+
* `assessPreviousRun` already treats missing evidence as `none` or `unknown`
|
|
421
|
+
* rather than inventing a verdict.
|
|
422
|
+
*/
|
|
423
|
+
private lastLifecycleRecord;
|
|
424
|
+
/**
|
|
425
|
+
* Record that this process started, and what became of the previous one
|
|
426
|
+
* (#1149).
|
|
427
|
+
*
|
|
428
|
+
* The assessment is read BEFORE the new start is written, or the record
|
|
429
|
+
* being written would be the one it found.
|
|
430
|
+
*/
|
|
431
|
+
private recordStart;
|
|
432
|
+
/**
|
|
433
|
+
* Record the security posture, and compare it against the previous start
|
|
434
|
+
* (#1156, D19).
|
|
435
|
+
*
|
|
436
|
+
* `config-change` audits what goes through `setProperty()`. This closes the
|
|
437
|
+
* two holes that leaves: an `app-custom-config.json` edited directly on disk
|
|
438
|
+
* emits nothing, and the state an instance STARTED in was never stated.
|
|
439
|
+
* Comparing consecutive boots surfaces an edit nothing observed.
|
|
440
|
+
*
|
|
441
|
+
* Emitted after `system-start`, deliberately: the start record establishes
|
|
442
|
+
* that this run began, and the posture record says what it began with.
|
|
443
|
+
*/
|
|
444
|
+
private recordPosture;
|
|
445
|
+
/** Record that this process is stopping (#1149). */
|
|
446
|
+
private recordShutdown;
|
|
447
|
+
private emitLifecycle;
|
|
448
|
+
/** The active provider's file backup and staged restore, when it keeps files (FileAuditProvider, #1876). */
|
|
449
|
+
private fileProvider;
|
|
450
|
+
/**
|
|
451
|
+
* The audit log in a backup (#1876): the provider's own files beside the
|
|
452
|
+
* document, with the hash chain they carry (`FileAuditProvider.backupFiles`).
|
|
453
|
+
* A provider that keeps no files is not in the file backup: the database
|
|
454
|
+
* provider's records are in the application database, which DatabaseManager
|
|
455
|
+
* backs up after writing the audit queue (#1537).
|
|
456
|
+
*/
|
|
457
|
+
backup(options?: ManagerBackupOptions): Promise<BackupData>;
|
|
458
|
+
/**
|
|
459
|
+
* Staged for the next start with the rest of a site restore (#1876); the
|
|
460
|
+
* live log keeps recording until then.
|
|
461
|
+
*
|
|
462
|
+
* A site whose audit provider keeps no files (the database provider, #1537)
|
|
463
|
+
* stages nothing from a backup's audit files and does not fail the restore:
|
|
464
|
+
* its audit records are restored with the databases, and the file part is
|
|
465
|
+
* left out, so BackupManager reports "the audit log" as not restored. The
|
|
466
|
+
* files stay in the backup.
|
|
467
|
+
*/
|
|
468
|
+
restore(backupData: BackupData, options?: ManagerRestoreOptions): Promise<void>;
|
|
469
|
+
restoreIsStaged(): boolean;
|
|
470
|
+
/**
|
|
471
|
+
* Shutdown the audit manager
|
|
472
|
+
*
|
|
473
|
+
* @returns {Promise<void>}
|
|
474
|
+
*/
|
|
475
|
+
shutdown(): Promise<void>;
|
|
476
|
+
}
|
|
477
|
+
export default AuditManager;
|