@jwilleke/ngdpbase-types 5.42.0 → 5.44.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/context/ApiContext.d.ts +10 -3
- package/lib/src/context/ApiContext.js +37 -4
- package/lib/src/context/BaseContext.d.ts +20 -20
- package/lib/src/context/BaseContext.js +41 -24
- package/lib/src/context/JobContext.d.ts +31 -0
- package/lib/src/context/JobContext.js +34 -1
- package/lib/src/ice/runExport.d.ts +8 -3
- package/lib/src/ice/searchExportSource.d.ts +44 -0
- package/lib/src/ice/types.d.ts +6 -0
- package/lib/src/managers/AddonsManager.d.ts +0 -28
- package/lib/src/managers/AgentTokenManager.d.ts +8 -0
- package/lib/src/managers/AttachmentManager.d.ts +11 -0
- package/lib/src/managers/AuditManager.d.ts +0 -1
- package/lib/src/managers/AuthManager.d.ts +38 -0
- package/lib/src/managers/AuthManager.js +84 -12
- package/lib/src/managers/BackupManager.d.ts +9 -2
- package/lib/src/managers/BackupManager.js +42 -19
- package/lib/src/managers/BaseManager.d.ts +17 -3
- package/lib/src/managers/BaseManager.js +12 -8
- package/lib/src/managers/ConfigurationManager.d.ts +28 -0
- package/lib/src/managers/ConsentManager.d.ts +1 -1
- package/lib/src/managers/DatabaseManager.js +17 -8
- package/lib/src/managers/EmailManager.d.ts +1 -1
- package/lib/src/managers/ExportManager.d.ts +1 -44
- package/lib/src/managers/ExportManager.js +3 -115
- package/lib/src/managers/ImportManager.d.ts +7 -0
- package/lib/src/managers/PageManager.d.ts +194 -23
- package/lib/src/managers/PolicyEvaluator.d.ts +182 -24
- package/lib/src/managers/ShareManager.d.ts +3 -2
- package/lib/src/managers/ThemeManager.d.ts +20 -1
- package/lib/src/managers/UserManager.d.ts +19 -5
- package/lib/src/managers/ValidationManager.d.ts +3 -1
- package/lib/src/providers/AgentTokenAuthProvider.js +1 -1
- package/lib/src/providers/BaseAuthProvider.d.ts +2 -0
- package/lib/src/providers/FileLoggingProvider.d.ts +12 -1
- package/lib/src/providers/FileLoggingProvider.js +37 -4
- package/lib/src/security/PolicyDecisionPoint.d.ts +107 -4
- package/lib/src/security/PolicyInformationPoint.d.ts +113 -7
- package/lib/src/security/ownedRecords.d.ts +69 -0
- package/lib/src/security/permissions.generated.d.ts +8 -0
- package/lib/src/security/signedOutWrites.d.ts +69 -0
- package/lib/src/security/signedOutWrites.js +146 -0
- package/lib/src/types/Page.d.ts +0 -7
- package/lib/src/types/Policy.d.ts +65 -8
- package/lib/src/types/Policy.js +6 -0
- package/lib/src/types/Provider.d.ts +12 -0
- package/lib/src/types/User.d.ts +6 -0
- package/lib/src/utils/addonConfigLayer.d.ts +6 -3
- package/lib/src/utils/addonConfigLayer.js +61 -3
- package/lib/src/utils/addonHost.d.ts +25 -0
- package/lib/src/utils/addonHost.js +29 -1
- package/lib/src/utils/addonPageSync.d.ts +0 -12
- package/lib/src/utils/auditEventNames.generated.d.ts +2 -0
- package/lib/src/utils/auditEventNames.generated.js +2 -0
- package/lib/src/utils/auditEvents.d.ts +2 -0
- package/lib/src/utils/auditEvents.js +3 -1
- package/lib/src/utils/availability.d.ts +15 -0
- package/lib/src/utils/availability.js +88 -0
- package/lib/src/utils/frontmatterAccess.d.ts +15 -24
- package/lib/src/utils/legacyStoreKeys.d.ts +16 -0
- package/lib/src/utils/pageTitleConflict.d.ts +32 -0
- package/lib/src/utils/pageWritePolicies.d.ts +74 -0
- package/lib/src/utils/permissionCatalog.d.ts +2 -0
- package/lib/src/utils/permissionCatalog.js +19 -0
- package/lib/src/utils/plainAttention.d.ts +19 -0
- package/lib/src/utils/plainAttention.js +18 -0
- package/lib/src/utils/policyAttributes.d.ts +232 -0
- package/lib/src/utils/policyAttributes.js +404 -0
- package/lib/src/utils/privateStoreAccess.d.ts +24 -4
- package/lib/src/utils/privateStoreAccess.js +19 -4
- package/lib/src/utils/roleGrants.d.ts +1 -1
- package/lib/src/utils/username.d.ts +13 -2
- package/lib/src/utils/username.js +18 -3
- package/package.json +7 -7
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import BaseManager from './BaseManager.js';
|
|
2
|
-
import type { Policy, PolicySubject, PolicyResource } from '../types/Policy.js';
|
|
2
|
+
import type { Policy, PolicySubject, PolicyResource, PolicyCondition } from '../types/Policy.js';
|
|
3
|
+
import { type DeclaredEnvironmentAttribute, type DeclaredSubjectAttribute } from '../utils/policyAttributes.js';
|
|
3
4
|
import { WikiEngine } from '../types/WikiEngine.js';
|
|
5
|
+
import type { ActorContext } from '../context/ActorContext.js';
|
|
4
6
|
/**
|
|
5
7
|
* User context for policy evaluation
|
|
6
8
|
*/
|
|
@@ -17,15 +19,61 @@ interface UserContext {
|
|
|
17
19
|
* PIP (#1504): today a page's `system-category`.
|
|
18
20
|
*/
|
|
19
21
|
export type ResourceAttributes = Record<string, unknown>;
|
|
22
|
+
/**
|
|
23
|
+
* Reads one attribute a condition names, `subject:id` or `resource:owner`
|
|
24
|
+
* (#2255). Supplied by the PDP from the PIP; `undefined` or `null` is a
|
|
25
|
+
* missing attribute. Asked only when a matching policy has a condition. A
|
|
26
|
+
* reader may be async (an identity is resolved through IdentityManager), and
|
|
27
|
+
* the evaluator awaits every read.
|
|
28
|
+
*/
|
|
29
|
+
export type AttributeReader = (name: string) => unknown | Promise<unknown>;
|
|
20
30
|
/**
|
|
21
31
|
* Access evaluation context
|
|
22
32
|
*/
|
|
23
33
|
interface AccessContext {
|
|
24
34
|
pageName: string;
|
|
35
|
+
/**
|
|
36
|
+
* The action asked. `actions` widens it: a policy granting any of them
|
|
37
|
+
* matches (#2255: a page write is `page-edit` or `pushed-pages-edit`).
|
|
38
|
+
*/
|
|
25
39
|
action: string;
|
|
40
|
+
actions?: readonly string[];
|
|
26
41
|
userContext?: UserContext;
|
|
27
42
|
attributes?: ResourceAttributes;
|
|
43
|
+
/** For a policy's `condition`; without one every condition is unknown. */
|
|
44
|
+
readAttribute?: AttributeReader;
|
|
28
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* What is wrong with a policy's condition, one sentence each (#2255, #2261,
|
|
48
|
+
* #2330); empty when it is fine. Each sentence says what is wrong, then what to
|
|
49
|
+
* change. A node is one XACML function in lowercase: a comparison such as
|
|
50
|
+
* `string-equal` over two arguments, or `and`, `or` or `not` over other
|
|
51
|
+
* conditions, nested at most {@link MAX_CONDITION_DEPTH} deep, at most
|
|
52
|
+
* {@link MAX_CONDITION_NODES} function nodes in all, an `is-in` list of at most
|
|
53
|
+
* {@link MAX_IN_ITEMS} and an `and` or `or` of at most {@link MAX_GROUP_CHILDREN}.
|
|
54
|
+
* An argument is an attribute (`attributeid`, `datatype`) or a literal (`value`,
|
|
55
|
+
* `datatype`); `datatype` is required, must be the type the attribute is declared with
|
|
56
|
+
* and the type the function takes. Each attribute must be declared: a
|
|
57
|
+
* `subject:<name>` in `ngdpbase.access.subject-attributes` (`id` always, `aal`
|
|
58
|
+
* as shipped), or a `resource:<name>` declared on the resource type the policy names (the
|
|
59
|
+
* `page` type when it names a page, or that add-on's type when it names only
|
|
60
|
+
* that type, #1823), or an `environment:<name>` in `ngdpbase.access.environment-attributes`. The old
|
|
61
|
+
* shape (`attribute` with `equals` and the like) is a problem that shows the
|
|
62
|
+
* new one. A condition with a problem never holds: an allow with it does not
|
|
63
|
+
* apply and a deny with it does, as for a missing attribute.
|
|
64
|
+
*/
|
|
65
|
+
export declare function conditionProblems(condition: unknown, pageAttributes: Record<string, {
|
|
66
|
+
type?: string;
|
|
67
|
+
}>, subjectAttributes?: Record<string, DeclaredSubjectAttribute>, environmentAttributes?: Record<string, DeclaredEnvironmentAttribute>, resourceTypeLabel?: string): string[];
|
|
68
|
+
/**
|
|
69
|
+
* Is the condition true, false or unknown (#2255, #2261)? `true` or `false`,
|
|
70
|
+
* or `undefined` when it cannot be told because an attribute it reads is
|
|
71
|
+
* missing, or an argument lacks the datatype its function takes; the caller
|
|
72
|
+
* fails closed on that. Each node is judged on its own: a missing attribute
|
|
73
|
+
* makes its comparison unknown, a true branch decides `or`, a false branch
|
|
74
|
+
* decides `and`, and `not` of unknown is unknown.
|
|
75
|
+
*/
|
|
76
|
+
export declare function conditionHolds(condition: PolicyCondition | undefined, read: AttributeReader | undefined, depth?: number): Promise<boolean | undefined>;
|
|
29
77
|
/**
|
|
30
78
|
* How each policy resource type matches (#1504). The TYPES are declared in
|
|
31
79
|
* configuration, `ngdpbase.access.resource-types`, and read through
|
|
@@ -40,7 +88,31 @@ export declare const RESOURCE_MATCHERS: Record<string, (pattern: string, pageNam
|
|
|
40
88
|
* PolicyValidator accepts: a type with no matcher here would be a policy that
|
|
41
89
|
* grants nothing.
|
|
42
90
|
*/
|
|
43
|
-
export declare const SUBJECT_MATCHERS: Record<string, (value: string, userContext: UserContext | undefined) => boolean>;
|
|
91
|
+
export declare const SUBJECT_MATCHERS: Record<string, (value: string | undefined, userContext: UserContext | undefined) => boolean>;
|
|
92
|
+
/**
|
|
93
|
+
* The subject types that take no `value` (#2261), for the validator. A value
|
|
94
|
+
* on one is refused rather than ignored.
|
|
95
|
+
*/
|
|
96
|
+
export declare const VALUELESS_SUBJECT_TYPES: readonly string[];
|
|
97
|
+
/**
|
|
98
|
+
* Which resource attributes a policy's condition may read (#1823).
|
|
99
|
+
*
|
|
100
|
+
* A policy that names exactly one add-on type (no page matcher) uses that
|
|
101
|
+
* type's attributes. A policy on a core type, including `system-category`,
|
|
102
|
+
* still reads the `page` attributes: those conditions are about the page.
|
|
103
|
+
*/
|
|
104
|
+
export declare function conditionAttributeSource(resources: readonly {
|
|
105
|
+
type?: string;
|
|
106
|
+
}[] | undefined, types: Record<string, {
|
|
107
|
+
attributes?: Record<string, {
|
|
108
|
+
type?: string;
|
|
109
|
+
}>;
|
|
110
|
+
}> | null): {
|
|
111
|
+
attributes: Record<string, {
|
|
112
|
+
type?: string;
|
|
113
|
+
}>;
|
|
114
|
+
label: string;
|
|
115
|
+
};
|
|
44
116
|
/**
|
|
45
117
|
* The resource types configuration declares (#1504), for the evaluator and the
|
|
46
118
|
* validator alike. When the key is not set at all — a configuration older than
|
|
@@ -56,14 +128,19 @@ interface EvaluationResult {
|
|
|
56
128
|
allowed: boolean;
|
|
57
129
|
reason: string;
|
|
58
130
|
policyName: string | null;
|
|
131
|
+
/** The deciding policies' ids (#2255): the denies that matched, else the allows. Empty when none matched. */
|
|
132
|
+
policyIds: string[];
|
|
133
|
+
/** Allows that matched subject, resource and action but whose condition was false or unknown (#2288). Absent when none. */
|
|
134
|
+
conditionNotMet?: string[];
|
|
59
135
|
}
|
|
60
136
|
/**
|
|
61
137
|
* PolicyEvaluator - Evaluates access policies against a given context.
|
|
62
138
|
*
|
|
63
139
|
* PolicyEvaluator mimics how JSPWiki uses Java's built-in security framework
|
|
64
140
|
* (java.security) to load and evaluate security policies from a policy file.
|
|
65
|
-
*
|
|
66
|
-
* decision
|
|
141
|
+
* Among the policies that match, a deny overrides any allow, the
|
|
142
|
+
* rule-combining algorithm `deny-overrides` (#2330), and no match is a deny (#2255). Each decision names the policies
|
|
143
|
+
* that decided it.
|
|
67
144
|
*
|
|
68
145
|
* @class PolicyEvaluator
|
|
69
146
|
* @extends BaseManager
|
|
@@ -85,6 +162,17 @@ interface EvaluationResult {
|
|
|
85
162
|
*/
|
|
86
163
|
declare class PolicyEvaluator extends BaseManager {
|
|
87
164
|
private configManager;
|
|
165
|
+
/** The headline of the access-policies item now up, so marking the last deny takes down this one and no other (#2355). */
|
|
166
|
+
private reportedReason;
|
|
167
|
+
/**
|
|
168
|
+
* Each condition checked and compiled, by the condition object configuration
|
|
169
|
+
* holds (#2279), kept while `ConfigurationManager.getRevision()` is
|
|
170
|
+
* `revision`. Any change to the configuration (a save, a reload, a reset, a
|
|
171
|
+
* restore, an add-on's runtime value) changes the revision, and the next
|
|
172
|
+
* decision starts again from nothing. The policies themselves are still read
|
|
173
|
+
* live for every decision; only a condition's compiled form is reused.
|
|
174
|
+
*/
|
|
175
|
+
private preparedConditions;
|
|
88
176
|
/**
|
|
89
177
|
* The policies in force NOW. Only the PDP interprets them (#1431 step 14b);
|
|
90
178
|
* this evaluator is the PDP's matching engine and asks it for the list, read
|
|
@@ -112,24 +200,73 @@ declare class PolicyEvaluator extends BaseManager {
|
|
|
112
200
|
*/
|
|
113
201
|
initialize(): Promise<void>;
|
|
114
202
|
/**
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
203
|
+
* Say at boot what a developer should look at in the policies after #2255,
|
|
204
|
+
* one warning each: stored policies the upgrade rewrote, policies it left
|
|
205
|
+
* that now decide differently (a deny) or reach pushed pages, and conditions
|
|
206
|
+
* that never hold. These are log lines only; categories no policy lets anyone
|
|
207
|
+
* change are an upgrade check (`upgradeChecks/uneditablePages.ts`).
|
|
208
|
+
*/
|
|
209
|
+
private reportPageWritePolicies;
|
|
210
|
+
/** The stored marks whose rule is still a deny in force (#2355). A mark for a rule since removed is not kept: the same rule added later must be shown again. */
|
|
211
|
+
private marksOfExistingDenies;
|
|
212
|
+
/** Save the marks without those of rules that are gone (#2355); nothing is written when none is. */
|
|
213
|
+
private dropMarksOfGoneRules;
|
|
214
|
+
/**
|
|
215
|
+
* An administrator marks a deny as checked (#2355). Kept as the rule's id and a fingerprint of
|
|
216
|
+
* its content in `ngdpbase.access.checked-denies`, written through ConfigurationManager with the
|
|
217
|
+
* person's context, which records the change. It hides the item and nothing else: no decision
|
|
218
|
+
* reads it. Answers `changed` when the rule is no longer what the page showed (nothing is
|
|
219
|
+
* saved) and `missing` when no deny has that id.
|
|
220
|
+
*/
|
|
221
|
+
markDenyChecked(ctx: ActorContext, id: string, fingerprint: string): Promise<'checked' | 'changed' | 'missing'>;
|
|
222
|
+
/**
|
|
223
|
+
* Evaluates all relevant policies to make an access decision (#2255).
|
|
123
224
|
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
* });
|
|
130
|
-
* console.log('Allowed:', result.allowed, 'Reason:', result.reason);
|
|
225
|
+
* Deny overrides allow (the rule-combining algorithm, #2330): if any matching
|
|
226
|
+
* deny applies, the answer is deny; otherwise any matching allow permits;
|
|
227
|
+
* otherwise no policy decided. A policy with a `condition` applies only when it holds;
|
|
228
|
+
* an unknown condition (a missing attribute) keeps an allow from applying
|
|
229
|
+
* and lets a deny apply, so a missing attribute fails closed.
|
|
131
230
|
*/
|
|
132
231
|
evaluateAccess(context: AccessContext): Promise<EvaluationResult>;
|
|
232
|
+
/**
|
|
233
|
+
* The policies with their conditions checked and compiled (#2279): a
|
|
234
|
+
* condition already compiled under the configuration in force is reused,
|
|
235
|
+
* and `prepare` runs only for the rest. With no configuration revision to
|
|
236
|
+
* key on, everything is prepared again.
|
|
237
|
+
*/
|
|
238
|
+
private prepared;
|
|
239
|
+
/**
|
|
240
|
+
* Checks and compiles each policy's condition (#2261). `prepared()` keeps
|
|
241
|
+
* the result until the configuration changes (#2279).
|
|
242
|
+
*/
|
|
243
|
+
private prepare;
|
|
244
|
+
/**
|
|
245
|
+
* Decide one add-on record type by id (#1823).
|
|
246
|
+
*
|
|
247
|
+
* Only policies that name this type are considered, and a policy with no
|
|
248
|
+
* resources does not match: a page grant cannot cover the type, and a
|
|
249
|
+
* blanket policy cannot either. The id is matched with the same globs as a
|
|
250
|
+
* page name, a leading dot included. A core type (`page`, `system-category`, `vault`,
|
|
251
|
+
* `shared-folder`) is not decided here.
|
|
252
|
+
*/
|
|
253
|
+
evaluateDeclaredResource(context: {
|
|
254
|
+
resourceType: string;
|
|
255
|
+
id: string;
|
|
256
|
+
action: string;
|
|
257
|
+
actions?: readonly string[];
|
|
258
|
+
userContext?: UserContext;
|
|
259
|
+
readAttribute?: AttributeReader;
|
|
260
|
+
}): Promise<EvaluationResult>;
|
|
261
|
+
/** True when a policy resource names this type and its pattern covers the id. No resources is not a match. */
|
|
262
|
+
private namesDeclaredType;
|
|
263
|
+
private resourceTypeMap;
|
|
264
|
+
/**
|
|
265
|
+
* Deny overrides allow, over policies that already match subject, resource
|
|
266
|
+
* and action (#2255). Every matching deny whose condition is true or
|
|
267
|
+
* unknown decides; failing that, every allow whose condition is true.
|
|
268
|
+
*/
|
|
269
|
+
private combine;
|
|
133
270
|
/**
|
|
134
271
|
* Checks if a single policy matches the given context.
|
|
135
272
|
*
|
|
@@ -189,12 +326,33 @@ declare class PolicyEvaluator extends BaseManager {
|
|
|
189
326
|
* `filter` shape, compiled once and applied to many resources.
|
|
190
327
|
*
|
|
191
328
|
* Policies that cannot match this subject or this action are dropped here,
|
|
192
|
-
* once; the predicate matches resources only
|
|
193
|
-
* `evaluateAccess`
|
|
194
|
-
* per call: a listing asks this ~18k
|
|
195
|
-
* `evaluateAccess` writes is right for one
|
|
329
|
+
* once; the predicate matches resources only and combines them exactly as
|
|
330
|
+
* `evaluateAccess` does (deny overrides allow, #2255), so a list and a
|
|
331
|
+
* single decision agree. No log line per call: a listing asks this ~18k
|
|
332
|
+
* times, and the INFO line `evaluateAccess` writes is right for one
|
|
333
|
+
* decision and wrong for a filter.
|
|
334
|
+
*/
|
|
335
|
+
compile(userContext: UserContext | undefined, action: string, actions?: readonly string[]): (pageName: string, attributes?: ResourceAttributes, readAttribute?: AttributeReader) => Promise<EvaluationResult>;
|
|
336
|
+
/** The attributes declared on the `page` resource type (#2255), for checking a condition. */
|
|
337
|
+
declaredPageAttributes(): Record<string, {
|
|
338
|
+
type?: string;
|
|
339
|
+
}>;
|
|
340
|
+
/** The subject attributes a condition may read (#2261): `id` always, and those declared in `ngdpbase.access.subject-attributes`. */
|
|
341
|
+
declaredSubjectAttributes(): Record<string, DeclaredSubjectAttribute>;
|
|
342
|
+
/** The environment attributes a condition may read (#2261): those declared in `ngdpbase.access.environment-attributes`. */
|
|
343
|
+
declaredEnvironmentAttributes(): Record<string, DeclaredEnvironmentAttribute>;
|
|
344
|
+
/**
|
|
345
|
+
* One line for each declared `schedule:` attribute whose schedule is not in
|
|
346
|
+
* `ngdpbase.schedules` (the attribute is missing and a condition on it fails
|
|
347
|
+
* closed) or has no rules (it reads as always open), for the boot warning.
|
|
196
348
|
*/
|
|
197
|
-
|
|
349
|
+
private scheduleProblems;
|
|
350
|
+
/** Each policy in force whose condition has a problem, with the problems (#2255): for the boot warning. */
|
|
351
|
+
conditionProblemsInForce(): Array<{
|
|
352
|
+
id: string;
|
|
353
|
+
effect: Policy['effect'];
|
|
354
|
+
problems: string[];
|
|
355
|
+
}>;
|
|
198
356
|
matchesResource(resources: PolicyResource[] | undefined, pageName: string, attributes?: ResourceAttributes): boolean;
|
|
199
357
|
/**
|
|
200
358
|
* Checks if the action matches the policy's actions.
|
|
@@ -219,8 +219,9 @@ export default class ShareManager extends BaseManager {
|
|
|
219
219
|
* True when a page must never appear in any share:
|
|
220
220
|
* - `private: true` (decision 1)
|
|
221
221
|
* - `owner-only` in user-keywords (decision 1)
|
|
222
|
-
* - `audience`
|
|
223
|
-
*
|
|
222
|
+
* - `audience` frontmatter (decision 3 — a share must not silently widen
|
|
223
|
+
* an author's chosen audience). A page's `access` field is not read
|
|
224
|
+
* since #2255.
|
|
224
225
|
*/
|
|
225
226
|
private isPageExcluded;
|
|
226
227
|
/** Prepare and lock everything a link to an encrypted vault covers. `ownerCtx` must hold the vault's key. */
|
|
@@ -5,6 +5,12 @@ export interface ThemeInfo {
|
|
|
5
5
|
author: string;
|
|
6
6
|
/** Optional Google Fonts (or other) stylesheet URLs to inject in <head> */
|
|
7
7
|
fonts?: string[];
|
|
8
|
+
/**
|
|
9
|
+
* Optional CSS filenames in this theme's css/ directory. Loaded after
|
|
10
|
+
* core.css so a site theme can adjust layout without editing the shared
|
|
11
|
+
* sheet. Basenames only; paths are rejected.
|
|
12
|
+
*/
|
|
13
|
+
stylesheets?: string[];
|
|
8
14
|
}
|
|
9
15
|
export interface ThemePaths {
|
|
10
16
|
/** Active theme name (folder name under themes/) */
|
|
@@ -23,6 +29,8 @@ export interface ThemePaths {
|
|
|
23
29
|
themeInfo: ThemeInfo | null;
|
|
24
30
|
/** Optional font stylesheet URLs from theme.json fonts[] */
|
|
25
31
|
fontUrls: string[];
|
|
32
|
+
/** Theme CSS files to load after core.css. Public URLs. */
|
|
33
|
+
themeStylesheets: string[];
|
|
26
34
|
}
|
|
27
35
|
/**
|
|
28
36
|
* Returns a cached ThemeManager for the given active theme + themes directory.
|
|
@@ -44,11 +52,22 @@ export declare class ThemeManager {
|
|
|
44
52
|
constructor(activeTheme: string, themesDir: string);
|
|
45
53
|
private loadThemeInfo;
|
|
46
54
|
private buildPaths;
|
|
55
|
+
/**
|
|
56
|
+
* Publish theme.json stylesheets[] as /themes/<theme>/css/<file>.
|
|
57
|
+
* Only a basename ending in .css that exists in that directory is kept,
|
|
58
|
+
* so a theme cannot point the browser at another path.
|
|
59
|
+
*/
|
|
60
|
+
private resolveThemeStylesheets;
|
|
47
61
|
/** Resolve variables.css path — falls back to empty placeholder if theme has no custom vars */
|
|
48
62
|
private resolveVariablesCssPath;
|
|
49
63
|
/** Resolve favicon path: prefer favicon.svg → favicon.png → public fallback */
|
|
50
64
|
private resolveFaviconPath;
|
|
51
|
-
/**
|
|
65
|
+
/**
|
|
66
|
+
* Resolve the header logo path: prefer logo-header.svg → logo-header.png →
|
|
67
|
+
* logo.svg → logo.png → favicon.svg → favicon.png → public fallback.
|
|
68
|
+
* logo-header.* lets a theme show a different copy in the header than the
|
|
69
|
+
* logo.* file that pages may link to.
|
|
70
|
+
*/
|
|
52
71
|
private resolveLogoPath;
|
|
53
72
|
get paths(): ThemePaths;
|
|
54
73
|
/** List all available themes (subdirs of themes/ that have a theme.json) */
|
|
@@ -19,6 +19,12 @@ export interface AgentTokenGrant {
|
|
|
19
19
|
id: string;
|
|
20
20
|
name: string;
|
|
21
21
|
scopes: string[];
|
|
22
|
+
/**
|
|
23
|
+
* The assurance level stored with the token when it was made (#2261): the
|
|
24
|
+
* level of the minting session at that moment, never higher. Absent on a
|
|
25
|
+
* token made before it was stored, which then has no `subject:aal`.
|
|
26
|
+
*/
|
|
27
|
+
aal?: 1 | 2 | 3;
|
|
22
28
|
}
|
|
23
29
|
/**
|
|
24
30
|
* A person acting for another under a proxy grant (#1762 slice 2), as a
|
|
@@ -112,6 +118,12 @@ export interface PermissionSubject {
|
|
|
112
118
|
* account's cap, since it is the actor who signs in (#1762).
|
|
113
119
|
*/
|
|
114
120
|
aalCap?: import('../providers/BaseAuthProvider.js').Aal;
|
|
121
|
+
/**
|
|
122
|
+
* Set by the bearer middleware on a subject authenticated by a JWT that
|
|
123
|
+
* records no sign-in level (Authentik, #2287): its `subject:aal` is missing,
|
|
124
|
+
* not AAL 1. Set from the verified result, never from a request field.
|
|
125
|
+
*/
|
|
126
|
+
bearerWithoutLevel?: true;
|
|
115
127
|
}
|
|
116
128
|
/**
|
|
117
129
|
* The subject of work with no request behind it (#631, #1212).
|
|
@@ -134,6 +146,8 @@ export interface JobSubject {
|
|
|
134
146
|
viaProxy?: ProxyClaim;
|
|
135
147
|
/** #1999: the scheduled job a run acts as (`JobContext.job`). */
|
|
136
148
|
job?: string;
|
|
149
|
+
/** #2261: the level stored with the job's request (`JobContext.aal`); absent when it stored none. */
|
|
150
|
+
grantedAal?: 1 | 2 | 3;
|
|
137
151
|
}
|
|
138
152
|
/**
|
|
139
153
|
* User creation input data
|
|
@@ -426,11 +440,11 @@ declare class UserManager extends BaseManager {
|
|
|
426
440
|
/**
|
|
427
441
|
* Create a user page for a new user.
|
|
428
442
|
*
|
|
429
|
-
* The page is
|
|
430
|
-
*
|
|
431
|
-
*
|
|
432
|
-
*
|
|
433
|
-
*
|
|
443
|
+
* The page is the new user's (#1462): they are its author. Authored by the
|
|
444
|
+
* admin who created the account — or by whoever ran self-registration —
|
|
445
|
+
* `author-lock` would leave the account's own owner unable to edit it.
|
|
446
|
+
* It is written by a system job through the write door (#1815), with the
|
|
447
|
+
* new user named as the one it is made for.
|
|
434
448
|
*
|
|
435
449
|
* @param {User} user - User object
|
|
436
450
|
* @param ctx - Who created the account, for the log line only
|
|
@@ -48,8 +48,10 @@ export declare const DEFAULT_SHARE_MAX_DAYS = 15;
|
|
|
48
48
|
* - `public`: a `storageLocation` without a vault; its pages can never be
|
|
49
49
|
* private.
|
|
50
50
|
* - `vault`: a `storageLocation.privatestore`; its pages may be private.
|
|
51
|
+
* - `shared-folder`: `storageLocation.sharedfolder: true` (#2255); its pages
|
|
52
|
+
* live in shared folders (the `shared` category).
|
|
51
53
|
*/
|
|
52
|
-
export type CategoryStored = 'none' | 'public' | 'vault';
|
|
54
|
+
export type CategoryStored = 'none' | 'public' | 'vault' | 'shared-folder';
|
|
53
55
|
/**
|
|
54
56
|
* Where an entry's pages are stored. The one rule every reader of "is this
|
|
55
57
|
* system-category stored here, and can it be private" goes through. A
|
|
@@ -39,7 +39,7 @@ export class AgentTokenAuthProvider {
|
|
|
39
39
|
return null;
|
|
40
40
|
return {
|
|
41
41
|
username: record.owner,
|
|
42
|
-
viaToken: { id: record.id, name: record.name, scopes: record.scopes }
|
|
42
|
+
viaToken: { id: record.id, name: record.name, scopes: record.scopes, ...(record.aal ? { aal: record.aal } : {}) }
|
|
43
43
|
};
|
|
44
44
|
}
|
|
45
45
|
}
|
|
@@ -74,6 +74,8 @@ export interface ViaToken {
|
|
|
74
74
|
name: string;
|
|
75
75
|
/** Scope ceiling this token may act within */
|
|
76
76
|
scopes: string[];
|
|
77
|
+
/** The assurance level stored with the token when it was made (#2261); absent on an older token. */
|
|
78
|
+
aal?: 1 | 2 | 3;
|
|
77
79
|
}
|
|
78
80
|
/**
|
|
79
81
|
* Returned by verify() on success.
|
|
@@ -21,6 +21,15 @@ declare class FileLoggingProvider extends BaseLoggingProvider {
|
|
|
21
21
|
*/
|
|
22
22
|
createTransports(config: LoggingProviderConfig): Transport[];
|
|
23
23
|
createFormat(): Logform.Format;
|
|
24
|
+
/** CR and LF as the visible two-character sequences `\r` and `\n`, so a value cannot start a line of its own (#2294). */
|
|
25
|
+
private static oneLine;
|
|
26
|
+
/**
|
|
27
|
+
* A stack keeps one frame per line, but its message portion (`Name: message`, which can span lines and can
|
|
28
|
+
* hold a caller-sent value) must not start a log line of its own (#2294). Only a line that begins with
|
|
29
|
+
* optional whitespace and `at ` starts a new output line; every other line is joined to the one before it
|
|
30
|
+
* with a visible `\n`.
|
|
31
|
+
*/
|
|
32
|
+
private static stackLines;
|
|
24
33
|
/**
|
|
25
34
|
* Render whatever a caller passed as the second argument to `logger.*`.
|
|
26
35
|
*
|
|
@@ -30,7 +39,9 @@ declare class FileLoggingProvider extends BaseLoggingProvider {
|
|
|
30
39
|
* line would be noise at best.
|
|
31
40
|
*
|
|
32
41
|
* A `stack` is emitted on its own lines because a one-line stack is
|
|
33
|
-
* unreadable, and reading the stack is the entire reason this exists.
|
|
42
|
+
* unreadable, and reading the stack is the entire reason this exists. Its
|
|
43
|
+
* frames keep their own lines; CR and LF in its message portion are escaped,
|
|
44
|
+
* as are those in the other keys and their string values.
|
|
34
45
|
*
|
|
35
46
|
* @param info - The winston info object for one log record
|
|
36
47
|
* @returns The rendered metadata, or an empty string when there is none
|
|
@@ -45,7 +45,17 @@ class FileLoggingProvider extends BaseLoggingProvider {
|
|
|
45
45
|
// #1461: private page titles never reach a log line or /admin/logs.
|
|
46
46
|
redactPrivateNamesFormat(), format.printf((info) => {
|
|
47
47
|
const ts = typeof info.timestamp === 'string' ? info.timestamp : JSON.stringify(info.timestamp);
|
|
48
|
-
|
|
48
|
+
// #2294: a caller-sent value (a page name) in the message could carry a CR or LF and start a log line of
|
|
49
|
+
// its own. Escaped here, once, for every transport and every call site; the escape is visible, not removed.
|
|
50
|
+
// Never throws: a logger that throws breaks its caller. Any non-string message (undefined, symbol, function,
|
|
51
|
+
// a circular object) is coerced with String(), and a formatting error falls back to a fixed marker.
|
|
52
|
+
let msg;
|
|
53
|
+
try {
|
|
54
|
+
msg = FileLoggingProvider.oneLine(typeof info.message === 'string' ? info.message : String(info.message));
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
msg = '[unprintable log message]';
|
|
58
|
+
}
|
|
49
59
|
// #1141: render the metadata too. This printf used to emit only
|
|
50
60
|
// timestamp/level/message, so the second argument of every
|
|
51
61
|
// `logger.error(msg, { error, stack })` call in the codebase was
|
|
@@ -57,6 +67,27 @@ class FileLoggingProvider extends BaseLoggingProvider {
|
|
|
57
67
|
return meta ? `${ts} [${info.level}]: ${msg} ${meta}` : `${ts} [${info.level}]: ${msg}`;
|
|
58
68
|
}));
|
|
59
69
|
}
|
|
70
|
+
/** CR and LF as the visible two-character sequences `\r` and `\n`, so a value cannot start a line of its own (#2294). */
|
|
71
|
+
static oneLine(text) {
|
|
72
|
+
return text.replace(/[\r\n]/g, (c) => (c === '\r' ? '\\r' : '\\n'));
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* A stack keeps one frame per line, but its message portion (`Name: message`, which can span lines and can
|
|
76
|
+
* hold a caller-sent value) must not start a log line of its own (#2294). Only a line that begins with
|
|
77
|
+
* optional whitespace and `at ` starts a new output line; every other line is joined to the one before it
|
|
78
|
+
* with a visible `\n`.
|
|
79
|
+
*/
|
|
80
|
+
static stackLines(stack) {
|
|
81
|
+
const out = [];
|
|
82
|
+
stack.split('\n').forEach((raw, i) => {
|
|
83
|
+
const line = FileLoggingProvider.oneLine(raw);
|
|
84
|
+
if (i === 0 || /^\s*at /.test(raw))
|
|
85
|
+
out.push(line);
|
|
86
|
+
else
|
|
87
|
+
out[out.length - 1] += `\\n${line}`;
|
|
88
|
+
});
|
|
89
|
+
return out.join('\n');
|
|
90
|
+
}
|
|
60
91
|
/**
|
|
61
92
|
* Render whatever a caller passed as the second argument to `logger.*`.
|
|
62
93
|
*
|
|
@@ -66,7 +97,9 @@ class FileLoggingProvider extends BaseLoggingProvider {
|
|
|
66
97
|
* line would be noise at best.
|
|
67
98
|
*
|
|
68
99
|
* A `stack` is emitted on its own lines because a one-line stack is
|
|
69
|
-
* unreadable, and reading the stack is the entire reason this exists.
|
|
100
|
+
* unreadable, and reading the stack is the entire reason this exists. Its
|
|
101
|
+
* frames keep their own lines; CR and LF in its message portion are escaped,
|
|
102
|
+
* as are those in the other keys and their string values.
|
|
70
103
|
*
|
|
71
104
|
* @param info - The winston info object for one log record
|
|
72
105
|
* @returns The rendered metadata, or an empty string when there is none
|
|
@@ -82,10 +115,10 @@ class FileLoggingProvider extends BaseLoggingProvider {
|
|
|
82
115
|
if (value === undefined)
|
|
83
116
|
continue;
|
|
84
117
|
if (key === 'stack' && typeof value === 'string') {
|
|
85
|
-
stack = value;
|
|
118
|
+
stack = FileLoggingProvider.stackLines(value);
|
|
86
119
|
continue;
|
|
87
120
|
}
|
|
88
|
-
parts.push(`${key}=${typeof value === 'string' ? value : JSON.stringify(value)}`);
|
|
121
|
+
parts.push(`${FileLoggingProvider.oneLine(key)}=${typeof value === 'string' ? FileLoggingProvider.oneLine(value) : JSON.stringify(value)}`);
|
|
89
122
|
}
|
|
90
123
|
const inline = parts.length > 0 ? parts.join(' ') : '';
|
|
91
124
|
if (stack) {
|