@jwilleke/ngdpbase-types 5.41.1 → 5.43.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.js +1 -1
- 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/managers/AddonsManager.d.ts +8 -28
- package/lib/src/managers/AgentTokenManager.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/ConfigurationManager.d.ts +15 -0
- package/lib/src/managers/ConsentManager.d.ts +15 -0
- package/lib/src/managers/ImportManager.d.ts +15 -0
- package/lib/src/managers/PageManager.d.ts +185 -23
- package/lib/src/managers/PolicyEvaluator.d.ts +99 -24
- package/lib/src/managers/ShareManager.d.ts +3 -2
- 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/BaseAttachmentProvider.d.ts +4 -0
- package/lib/src/providers/BaseAuditProvider.d.ts +492 -0
- package/lib/src/providers/BaseAuthProvider.d.ts +4 -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/security/PolicyDecisionPoint.d.ts +57 -1
- package/lib/src/security/PolicyInformationPoint.d.ts +86 -6
- package/lib/src/security/permissions.generated.d.ts +8 -0
- package/lib/src/types/Consent.d.ts +17 -4
- package/lib/src/types/Consent.js +11 -1
- package/lib/src/types/Page.d.ts +0 -7
- package/lib/src/types/Policy.d.ts +67 -6
- package/lib/src/types/Policy.js +6 -0
- package/lib/src/types/Provider.d.ts +18 -0
- package/lib/src/types/User.d.ts +6 -0
- package/lib/src/types/express.d.ts +22 -0
- package/lib/src/utils/addonPageSync.d.ts +0 -12
- package/lib/src/utils/auditChain.d.ts +83 -0
- 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/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/frontmatterAccess.d.ts +15 -24
- package/lib/src/utils/legacyStoreKeys.d.ts +16 -0
- package/lib/src/utils/pageWritePolicies.d.ts +55 -0
- package/lib/src/utils/permissionCatalog.d.ts +2 -0
- package/lib/src/utils/permissionCatalog.js +19 -0
- package/lib/src/utils/policyAttributes.d.ts +141 -0
- package/lib/src/utils/policyAttributes.js +219 -0
- package/lib/src/utils/postureRecord.d.ts +73 -0
- package/lib/src/utils/privateStoreAccess.d.ts +24 -4
- package/lib/src/utils/privateStoreAccess.js +19 -4
- 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/lib/src/utils/username.d.ts +13 -2
- package/lib/src/utils/username.js +18 -3
- package/package.json +5 -2
|
@@ -200,6 +200,21 @@ declare class ConfigurationManager extends BaseManager {
|
|
|
200
200
|
* @throws {Error} If default configuration file cannot be loaded
|
|
201
201
|
*/
|
|
202
202
|
private loadConfigurations;
|
|
203
|
+
/** What the #2255 page-write migration rewrote in memory, one sentence each; PolicyDecisionPoint reports it. */
|
|
204
|
+
pageWritePolicyMigration: string[];
|
|
205
|
+
/**
|
|
206
|
+
* #2255: before the merge, rewrite the custom layer's stored copies of the
|
|
207
|
+
* shipped role policies whose page writes moved to the category policies
|
|
208
|
+
* (`migrateStoredPageWritePolicies`). In memory only, like the other
|
|
209
|
+
* migrations here; one warning per policy changed.
|
|
210
|
+
*/
|
|
211
|
+
private migrateStoredPageWritePolicies;
|
|
212
|
+
/**
|
|
213
|
+
* #2246: `ngdpbase.stores.<kind>.owner|encrypt` in the custom config have
|
|
214
|
+
* been ignored since #1505. One warning per key, and one needs-attention
|
|
215
|
+
* entry naming them all. Nothing is changed, carried over or removed.
|
|
216
|
+
*/
|
|
217
|
+
private reportLegacyStoreKeys;
|
|
203
218
|
/**
|
|
204
219
|
* #642: One-shot migration shim. If the custom config sets either of the
|
|
205
220
|
* legacy keys `ngdpbase.base-url` or `ngdpbase.baseURL`, copy the value
|
|
@@ -95,6 +95,8 @@ declare class ConsentManager extends BaseManager {
|
|
|
95
95
|
* made on an earlier account of the same name is never theirs (#1937).
|
|
96
96
|
*/
|
|
97
97
|
private recordsOf;
|
|
98
|
+
/** The acceptances still standing: each `accept` line with no later `withdraw` of the same document, version and subject. */
|
|
99
|
+
private standingOf;
|
|
98
100
|
private accountOf;
|
|
99
101
|
/**
|
|
100
102
|
* The documents of `scope` that `username` has not accepted at their
|
|
@@ -134,6 +136,19 @@ declare class ConsentManager extends BaseManager {
|
|
|
134
136
|
* @returns The records written; empty when there was nothing to accept
|
|
135
137
|
*/
|
|
136
138
|
accept(ctx: ActorContext, scope: ConsentScope, seen: ConsentSeen[], how: string, subject?: string): Promise<ConsentRecord[]>;
|
|
139
|
+
/**
|
|
140
|
+
* Withdraw `username`'s acceptances in `scope` about `subject` (#1523 slice
|
|
141
|
+
* 1c, Q5: a remembered browser is withdrawn by removing it). Recorded first
|
|
142
|
+
* as `consent-withdraw` (on-failure refuse: nothing is withdrawn), then a
|
|
143
|
+
* `withdraw` line is appended for each acceptance, so the history keeps
|
|
144
|
+
* both. Called by the code that removed the thing the acceptance was
|
|
145
|
+
* about, which has already decided the caller may; nothing to withdraw is
|
|
146
|
+
* not an error.
|
|
147
|
+
*
|
|
148
|
+
* @param why Why, for the record: `removed`, `expired`, `password-changed`
|
|
149
|
+
* @returns The `withdraw` lines written
|
|
150
|
+
*/
|
|
151
|
+
withdraw(username: string, scope: ConsentScope, subject: string, ctx: ActorContext, why: string): Promise<ConsentRecord[]>;
|
|
137
152
|
/**
|
|
138
153
|
* The account `username` was deleted (`AuthManager.closeAccess`): its
|
|
139
154
|
* records go with it, after `consent-withdraw` names what it had accepted
|
|
@@ -312,6 +312,10 @@ declare class ImportManager extends BaseManager {
|
|
|
312
312
|
private readonly iceRuns;
|
|
313
313
|
/** ICE (#2171): a rechecking run's store, as fingerprint → id, read once per run and store; dropped when the run ends. */
|
|
314
314
|
private readonly storeHoldings;
|
|
315
|
+
/** ICE (#2188): what a run gives files back their ids with, by run and store; dropped when the run ends. */
|
|
316
|
+
private readonly storeRestoring;
|
|
317
|
+
/** ICE (#2171): the fingerprints of the files a rechecking run put back into a store, by run and store; dropped when the run ends. */
|
|
318
|
+
private readonly storeRestored;
|
|
315
319
|
/** ICE: work waiting for the background job, each with its own context: an import run or an export (#2120). */
|
|
316
320
|
private readonly iceQueue;
|
|
317
321
|
/** ICE: true while a background job is draining the queue. */
|
|
@@ -701,6 +705,17 @@ declare class ImportManager extends BaseManager {
|
|
|
701
705
|
* save door. Nothing here logs a page's or a file's name (#1461, #2110).
|
|
702
706
|
*/
|
|
703
707
|
private receiveTakeoutEntry;
|
|
708
|
+
/**
|
|
709
|
+
* Point every page of the user's store `store` that links a file by an id
|
|
710
|
+
* in `ids` at the file's id now (#2188), through the page door. Only an id
|
|
711
|
+
* no store of the user's holds is repointed: a link that opens their own
|
|
712
|
+
* file, say one that moved to another of their stores keeping its id, is
|
|
713
|
+
* left. An id held only by the shared pool or someone else's store is not
|
|
714
|
+
* the page's file, so it is repointed.
|
|
715
|
+
* A page that cannot be saved is passed over and named in `failed`; the
|
|
716
|
+
* rest are still done. Pages are named by uuid, never by title.
|
|
717
|
+
*/
|
|
718
|
+
private relinkStorePages;
|
|
704
719
|
/** A takeout's page into the store, as #1472 decided: see {@link privateStoreReceiver}. */
|
|
705
720
|
private saveTakeoutPage;
|
|
706
721
|
/**
|
|
@@ -97,6 +97,26 @@ export interface PageSaveOptions {
|
|
|
97
97
|
* doc says so.
|
|
98
98
|
*/
|
|
99
99
|
preserveEditor?: boolean;
|
|
100
|
+
/**
|
|
101
|
+
* The user a NEW page is made for, by a system job (#1815): they become its
|
|
102
|
+
* author and editor, where a create otherwise takes both from the acting
|
|
103
|
+
* context. For the pages the system makes on a user's behalf — the profile
|
|
104
|
+
* page at sign-up, the new profile page of a rename — so the job's
|
|
105
|
+
* `page-create`, granted in policy, decides the write, and the page is
|
|
106
|
+
* still the user's (author-lock leaves it to them). Refused from any context
|
|
107
|
+
* but the system principal's job, and refused for a page that already
|
|
108
|
+
* exists (`PageWriteRefusedError`, `page-create`): the job never edits
|
|
109
|
+
* that page instead.
|
|
110
|
+
*/
|
|
111
|
+
createdFor?: string;
|
|
112
|
+
/**
|
|
113
|
+
* The author of a page an add-on pushes (#2255): `addon:<slug>`. A new copy
|
|
114
|
+
* is authored by the add-on, and a copy seeded before #2255, authored by
|
|
115
|
+
* the system principal, is re-stamped with it. Taken only from the system
|
|
116
|
+
* principal's job and only in the `addon:<slug>` form; ignored otherwise.
|
|
117
|
+
* Any other author is kept, as on every edit.
|
|
118
|
+
*/
|
|
119
|
+
shippedAuthor?: string;
|
|
100
120
|
/**
|
|
101
121
|
* Request-level detail the manager cannot see, for the audit record (#1121).
|
|
102
122
|
*
|
|
@@ -199,11 +219,25 @@ export declare class PageAudienceRefusedError extends Error {
|
|
|
199
219
|
readonly pageName: string;
|
|
200
220
|
constructor(pageName: string);
|
|
201
221
|
}
|
|
222
|
+
/** The permission a page write is decided on (#1815). */
|
|
223
|
+
export type PageWriteAction = 'page-create' | 'page-edit' | 'page-delete' | 'page-rename';
|
|
224
|
+
/**
|
|
225
|
+
* A write refused by the write door (#1815): the context may not create,
|
|
226
|
+
* edit or delete this page, decided by policy, the page's own rules and the
|
|
227
|
+
* vault container rule. Nothing was written. Routes answer it with 403. The
|
|
228
|
+
* message names no page, so a private title never reaches a log (#2178).
|
|
229
|
+
*/
|
|
230
|
+
export declare class PageWriteRefusedError extends Error {
|
|
231
|
+
readonly pageName: string;
|
|
232
|
+
readonly action: PageWriteAction;
|
|
233
|
+
constructor(pageName: string, action: PageWriteAction);
|
|
234
|
+
}
|
|
202
235
|
export declare class PageContentValidationError extends Error {
|
|
203
236
|
readonly validationErrors: FilterValidationError[];
|
|
204
237
|
constructor(pageName: string, validationErrors: FilterValidationError[]);
|
|
205
238
|
}
|
|
206
239
|
import { type PageAction } from '../utils/pageUrl.js';
|
|
240
|
+
import { type VaultSealState } from '../utils/privateStoreMeta.js';
|
|
207
241
|
/** One vault page with data outside its vault (#1842), as the repair actions offer it. */
|
|
208
242
|
export interface VaultRepairItem {
|
|
209
243
|
owner: string;
|
|
@@ -261,6 +295,9 @@ export type VaultRepairResult = ({
|
|
|
261
295
|
/** The move of existing captures into the capture vault (#1505), recorded per vault it moved them out of. */
|
|
262
296
|
/** The refusal when someone without `admin-system` names a system-category (#1503, operator 2026-10-29). */
|
|
263
297
|
export declare const SYSTEM_CATEGORY_ADMIN_ONLY = "Only administrators can set a page's system category";
|
|
298
|
+
/** The system-category of a page in a shared folder (#2255): given when it is created there, by nothing else. */
|
|
299
|
+
export declare const SHARED_CATEGORY = "shared";
|
|
300
|
+
export declare const SHARED_CATEGORY_REFUSAL = "A page is in the shared system category only when it is created in a shared folder";
|
|
264
301
|
/** What a write may give a page as its system-category ({@link PageManager.systemCategoryForWrite}). */
|
|
265
302
|
export type SystemCategoryForWrite = {
|
|
266
303
|
ok: true;
|
|
@@ -327,6 +364,11 @@ export interface ShippedPageSource {
|
|
|
327
364
|
exclude?: (data: Record<string, unknown>) => string | undefined;
|
|
328
365
|
/** Metadata the source adds to every page it writes (e.g. `addon`, a default category) */
|
|
329
366
|
extraMetadata?: (data: Record<string, unknown>) => Record<string, unknown>;
|
|
367
|
+
/**
|
|
368
|
+
* The author of the pages it writes, for an add-on's (#2255): `addon:<slug>`
|
|
369
|
+
* (`SavePageOptions.shippedAuthor`). Absent, they are the system principal's.
|
|
370
|
+
*/
|
|
371
|
+
author?: string;
|
|
330
372
|
/**
|
|
331
373
|
* Called by the boot seed for a source page this site already holds, with the
|
|
332
374
|
* live page and the parsed source — the addon seed's metadata tidy-ups and
|
|
@@ -622,8 +664,10 @@ declare class PageManager extends BaseManager implements CatalogSource {
|
|
|
622
664
|
private readShippedSystemCategories;
|
|
623
665
|
/**
|
|
624
666
|
* Which system-category a write by `ctx` gives a page (#1503, operator
|
|
625
|
-
* 2026-10-29): only
|
|
626
|
-
* or changes one.
|
|
667
|
+
* 2026-10-29): only a holder of `page-categorize` (#2255; shipped to admin)
|
|
668
|
+
* sets or changes one. `shared` is set by nobody: a page created in a shared
|
|
669
|
+
* folder gets it at the write door (`savePage`), and a request naming it for
|
|
670
|
+
* any other page is refused, `page-categorize` or not. Anyone else's new page takes `fallback` (else the default
|
|
627
671
|
* system-category) and an existing page keeps its own (`current`); a request
|
|
628
672
|
* naming any other is refused, never rewritten. An administrator's request
|
|
629
673
|
* comes back as given (`undefined` when it names none), for the caller's own
|
|
@@ -644,16 +688,10 @@ declare class PageManager extends BaseManager implements CatalogSource {
|
|
|
644
688
|
* taken for a shipped one. Shipped pages are admin-only and never private.
|
|
645
689
|
*/
|
|
646
690
|
isShippedPageCopy(uuid: string): Promise<boolean>;
|
|
647
|
-
/**
|
|
648
|
-
* One-time access backfill for a live required page (#1411): a page with no
|
|
649
|
-
* `access` gets the default for its category, as a metadata-only save that
|
|
650
|
-
* keeps `lastModified`. A page that has any `access` — an operator's choice —
|
|
651
|
-
* is left alone.
|
|
652
|
-
*/
|
|
653
|
-
private backfillShippedPageAccess;
|
|
654
691
|
/**
|
|
655
692
|
* The source for the pages an addon ships (#1406). Pages it writes carry
|
|
656
|
-
* `addon
|
|
693
|
+
* `addon`, the add-on as author (`addon:<slug>`, #2255) and, when the source
|
|
694
|
+
* names none, the `addon` category (#931).
|
|
657
695
|
*
|
|
658
696
|
* @param addonName - The addon's name
|
|
659
697
|
* @param pagesDir - The addon's `pages/` folder
|
|
@@ -926,6 +964,82 @@ declare class PageManager extends BaseManager implements CatalogSource {
|
|
|
926
964
|
* @throws when `ctx` may not file into the page's folder
|
|
927
965
|
*/
|
|
928
966
|
private assertMayFileInSharedFolder;
|
|
967
|
+
/**
|
|
968
|
+
* May `ctx` edit or delete this existing page (#1815)? The page decision
|
|
969
|
+
* every route asks (`canUserAccessPage`), with the page's metadata, so the
|
|
970
|
+
* delegation ceilings, the vault container rule, author-lock, the page's own
|
|
971
|
+
* rules and policy all count, in that one evaluator. `record` false asks it
|
|
972
|
+
* as an affordance, which records nothing (#1668). Without a PIP nothing is
|
|
973
|
+
* writable.
|
|
974
|
+
*/
|
|
975
|
+
private mayChangeExisting;
|
|
976
|
+
/**
|
|
977
|
+
* May `ctx` create a page at `destination` (#1815)? In a vault, the
|
|
978
|
+
* container rule and then `page-create` with the vault (`permitsInVault`;
|
|
979
|
+
* a shared folder by its own permission). A public page, `page-create`
|
|
980
|
+
* asked of the PDP about the page (#2255: the PDP reads its attributes from
|
|
981
|
+
* the PIP). The same rule as `hasPermissionOn`.
|
|
982
|
+
*
|
|
983
|
+
* @returns `permit`, and the `policyIds` of the `page-create` decision when
|
|
984
|
+
* one was made (#2272); a vault page is decided by the container rule and
|
|
985
|
+
* `permitsInVault`, which name none.
|
|
986
|
+
*/
|
|
987
|
+
private decideCreateAt;
|
|
988
|
+
/**
|
|
989
|
+
* Where a save puts the page (#1815, decision 7): the private name the
|
|
990
|
+
* provider will store it under, or its public title. Read from the page's
|
|
991
|
+
* own `private` / `store` frontmatter, the rule the provider's placement
|
|
992
|
+
* follows: a private name stays private unless the save says
|
|
993
|
+
* `private: false`; a public title goes into a vault when it says
|
|
994
|
+
* `private: true`, the owner's and the store it names, else the vault the
|
|
995
|
+
* page is in now, else the default vault.
|
|
996
|
+
*
|
|
997
|
+
* @param owner - The username whose vault a public title would go into: the
|
|
998
|
+
* page's author (for a new page, whoever it is made by or for)
|
|
999
|
+
*/
|
|
1000
|
+
private writeDestination;
|
|
1001
|
+
/** The container a page name is in: its vault, or the public space. */
|
|
1002
|
+
private static containerOf;
|
|
1003
|
+
/**
|
|
1004
|
+
* The write door's decision for a save (#1815, operator 2026-11-04). An
|
|
1005
|
+
* existing page is edited only by a context the page decision lets edit it
|
|
1006
|
+
* ({@link mayChangeExisting}); a page arriving in a container it is not in
|
|
1007
|
+
* now — a new page, or a move into or out of a vault — is also created
|
|
1008
|
+
* there ({@link decideCreateAt}). Whatever route the write came by: the route's
|
|
1009
|
+
* own check is an early refusal, this is the one that counts.
|
|
1010
|
+
*
|
|
1011
|
+
* @throws PageWriteRefusedError when either is refused; nothing is written
|
|
1012
|
+
*/
|
|
1013
|
+
private assertMaySave;
|
|
1014
|
+
/**
|
|
1015
|
+
* Record a refused `page-create` as `authorization-deny` (#1815, security
|
|
1016
|
+
* review L1). The edit and delete refusals are recorded by the page
|
|
1017
|
+
* decision (`canUserAccessPage`); a create is decided by the PDP, which
|
|
1018
|
+
* records nothing, so the door records it here: core records every refusal.
|
|
1019
|
+
* Standard tier, `continue` on failure: the refusal stands either way.
|
|
1020
|
+
*
|
|
1021
|
+
* @param policyIds - The policies of the `page-create` decision that refused
|
|
1022
|
+
* (#2272). Only a refusal that decision made passes any; one no policy
|
|
1023
|
+
* decided (`createdFor` misuse) leaves the field off the record.
|
|
1024
|
+
* @param conditionNotMet - Allows of that decision that matched but whose condition was not met (#2288).
|
|
1025
|
+
*/
|
|
1026
|
+
private recordCreateRefusal;
|
|
1027
|
+
/** `shippedAuthor` when the system principal's job gives it in the `addon:<slug>` form (#2255); otherwise nothing. */
|
|
1028
|
+
private shippedAuthorFor;
|
|
1029
|
+
/** Is `ctx` a job of the system principal (#631) — the only context that may make a page for someone else (#1815)? */
|
|
1030
|
+
private isSystemJob;
|
|
1031
|
+
/** The username a page's stored author names (#2097), or null. */
|
|
1032
|
+
private authorUsername;
|
|
1033
|
+
/**
|
|
1034
|
+
* Would `ctx` be allowed to edit this page — asked only to decide what to
|
|
1035
|
+
* offer or report, never before writing it (#1815). The same decision as
|
|
1036
|
+
* the write door, as an affordance: it records nothing (#1668). Saving still
|
|
1037
|
+
* asks the door.
|
|
1038
|
+
*
|
|
1039
|
+
* @param identifier - Page UUID, title, slug or vault name
|
|
1040
|
+
* @param ctx - Whose question this is — never defaulted
|
|
1041
|
+
*/
|
|
1042
|
+
mayEditPage(identifier: string, ctx: ActorContext): Promise<boolean>;
|
|
929
1043
|
/**
|
|
930
1044
|
* Admin-override save (#689): the admin "Edit raw" textarea, split into
|
|
931
1045
|
* frontmatter and body and written through the door (#1462).
|
|
@@ -975,7 +1089,7 @@ declare class PageManager extends BaseManager implements CatalogSource {
|
|
|
975
1089
|
* What a page stores for the user `name` (#2097): `IdentityManager.storedReferenceOf`.
|
|
976
1090
|
*/
|
|
977
1091
|
private referenceTo;
|
|
978
|
-
/** `audience`
|
|
1092
|
+
/** The `audience` of a save, user entries as {@link referenceTo} stores them (#2097). */
|
|
979
1093
|
private convertAccessListsForSave;
|
|
980
1094
|
/**
|
|
981
1095
|
* The frontmatter a save writes, from the frontmatter it was given (#1462).
|
|
@@ -994,6 +1108,7 @@ declare class PageManager extends BaseManager implements CatalogSource {
|
|
|
994
1108
|
* @param actingUser - Who is writing this revision, from the context (#1164)
|
|
995
1109
|
* @param viaToken - The agent token this write came through (#946), if any
|
|
996
1110
|
* @param keepEditor - Leave the stored `editor` alone (`preserveEditor`, #1457)
|
|
1111
|
+
* @param shippedAuthor - An add-on page's author (`shippedAuthor`, #2255), already checked
|
|
997
1112
|
* @returns The frontmatter to hand the provider
|
|
998
1113
|
*/
|
|
999
1114
|
private normalizeSaveMetadata;
|
|
@@ -1009,7 +1124,9 @@ declare class PageManager extends BaseManager implements CatalogSource {
|
|
|
1009
1124
|
*
|
|
1010
1125
|
* `ctx` is mandatory and positional: the save acts as the caller's subject
|
|
1011
1126
|
* (#1179), a private-store write reaches that session's keys through it
|
|
1012
|
-
* (#1382), and the audit record names it.
|
|
1127
|
+
* (#1382), and the audit record names it. The write is decided here, for
|
|
1128
|
+
* that context, before anything is written (#1815): `page-edit` on the page
|
|
1129
|
+
* as it is, `page-create` where it is going when that is somewhere new. A caller forwards the context it
|
|
1013
1130
|
* was given — a request's subject, or the job's for boot and scheduled
|
|
1014
1131
|
* work — and never invents one.
|
|
1015
1132
|
*
|
|
@@ -1020,6 +1137,7 @@ declare class PageManager extends BaseManager implements CatalogSource {
|
|
|
1020
1137
|
* @param options - Validation and conflict-check opt-outs, `rawFrontmatter` (#689),
|
|
1021
1138
|
* `preserveLastModified`, `preserveEditor` (#1457), audit enrichment
|
|
1022
1139
|
* @returns Where the page landed, and what it was called before
|
|
1140
|
+
* @throws PageWriteRefusedError when `ctx` may not make this write
|
|
1023
1141
|
*
|
|
1024
1142
|
* @example
|
|
1025
1143
|
* await pageManager.savePage('New Page', '# Hello World', { 'user-keywords': ['tutorial'] }, req.userContext);
|
|
@@ -1110,6 +1228,26 @@ declare class PageManager extends BaseManager implements CatalogSource {
|
|
|
1110
1228
|
}>>;
|
|
1111
1229
|
/** The store ids the requester has of their own (#1387). */
|
|
1112
1230
|
listOwnStoreIds(ctx: ActorContext): Promise<string[]>;
|
|
1231
|
+
/**
|
|
1232
|
+
* The requester's own vaults, each with its pages and whether it is
|
|
1233
|
+
* encrypted (#2245), for `/my/vaults`.
|
|
1234
|
+
*
|
|
1235
|
+
* `state` is the vault's {@link VaultSealState} (#1834): `sealed` is
|
|
1236
|
+
* encrypted, `plain` is not, and `unopened` or `mismatch` is a vault whose
|
|
1237
|
+
* kind says it must be encrypted while its copy is not. `readable` is false
|
|
1238
|
+
* for a vault this context cannot open, such as a sealed vault still
|
|
1239
|
+
* locked: its pages are then unknown, not none.
|
|
1240
|
+
*/
|
|
1241
|
+
listOwnVaults(ctx: ActorContext): Promise<Array<{
|
|
1242
|
+
id: string;
|
|
1243
|
+
state: VaultSealState;
|
|
1244
|
+
readable: boolean;
|
|
1245
|
+
pages: Array<{
|
|
1246
|
+
name: string;
|
|
1247
|
+
title: string;
|
|
1248
|
+
uuid: string;
|
|
1249
|
+
}>;
|
|
1250
|
+
}>>;
|
|
1113
1251
|
listOwnDeletedPrivatePages(ctx: ActorContext): Promise<StoreDeletedEntry[]>;
|
|
1114
1252
|
/**
|
|
1115
1253
|
* Bring one of the requester's private pages back from its store's trash
|
|
@@ -1233,14 +1371,25 @@ declare class PageManager extends BaseManager implements CatalogSource {
|
|
|
1233
1371
|
* and the context names who put it there. Afterwards the page is taken out
|
|
1234
1372
|
* of every shared index, here and nowhere else (#1462).
|
|
1235
1373
|
*
|
|
1374
|
+
* The write door decides `page-delete` on the page first (#1815), and the
|
|
1375
|
+
* delete is recorded as `page-delete` before it happens.
|
|
1376
|
+
*
|
|
1236
1377
|
* @param identifier - Page UUID, title, or slug
|
|
1237
1378
|
* @param ctx - Who is acting (#1179)
|
|
1379
|
+
* @param options - `audit.skip` when the caller already recorded this
|
|
1380
|
+
* delete; `audit.ipAddress`, the request's address, for the record
|
|
1238
1381
|
* @returns True if deleted, false if not found
|
|
1382
|
+
* @throws PageWriteRefusedError when `ctx` may not delete the page
|
|
1239
1383
|
*
|
|
1240
1384
|
* @example
|
|
1241
1385
|
* const deleted = await pageManager.deletePage('Old Page', req.userContext);
|
|
1242
1386
|
*/
|
|
1243
|
-
deletePage(identifier: string, ctx: ActorContext
|
|
1387
|
+
deletePage(identifier: string, ctx: ActorContext, options?: {
|
|
1388
|
+
audit?: {
|
|
1389
|
+
skip?: boolean;
|
|
1390
|
+
ipAddress?: string;
|
|
1391
|
+
};
|
|
1392
|
+
}): Promise<boolean>;
|
|
1244
1393
|
/**
|
|
1245
1394
|
* Delete the pages a test made (#2008): every shared page carrying the
|
|
1246
1395
|
* `test-artifact` system keyword (#1355), and never a page without it.
|
|
@@ -1253,7 +1402,8 @@ declare class PageManager extends BaseManager implements CatalogSource {
|
|
|
1253
1402
|
* follow. One page's failure never stops the rest; it is reported.
|
|
1254
1403
|
*
|
|
1255
1404
|
* The caller decides who may ask: the sweep route asks `admin-system`, and
|
|
1256
|
-
* an account delete has already been decided as `user-delete
|
|
1405
|
+
* an account delete has already been decided as `user-delete` and sends a
|
|
1406
|
+
* system job (#1815). Each delete is still decided by `deletePage`. Private
|
|
1257
1407
|
* vault pages are not in the shared index, so they are not reached here.
|
|
1258
1408
|
*
|
|
1259
1409
|
* @param ctx - Who is acting; named in every record
|
|
@@ -1502,7 +1652,7 @@ declare class PageManager extends BaseManager implements CatalogSource {
|
|
|
1502
1652
|
private warnUnmatchableAddonAudience;
|
|
1503
1653
|
/**
|
|
1504
1654
|
* At startup, once add-ons have loaded (#1964): warn about every page whose
|
|
1505
|
-
* `audience`
|
|
1655
|
+
* `audience` names an add-on that can match nobody — unknown,
|
|
1506
1656
|
* not per-person, or not loaded.
|
|
1507
1657
|
*
|
|
1508
1658
|
* @returns Each page and slug warned about
|
|
@@ -1617,8 +1767,10 @@ declare class PageManager extends BaseManager implements CatalogSource {
|
|
|
1617
1767
|
*
|
|
1618
1768
|
* `pages/vaults/{user}/` and every store below it is owned by that user.
|
|
1619
1769
|
* Nobody else acts in it unless the owner delegated (a share the owner
|
|
1620
|
-
* issued, once the store's Share switch exists — #1388). No role reaches in
|
|
1621
|
-
*
|
|
1770
|
+
* issued, once the store's Share switch exists — #1388). No role reaches in
|
|
1771
|
+
* (security-posture P2: no `hasRole` as an allow); at a door, a holder of
|
|
1772
|
+
* `admin-system` may enter an unencrypted vault when
|
|
1773
|
+
* `ngdpbase.vaults.admin-access` is on (#2255), recorded each time.
|
|
1622
1774
|
*
|
|
1623
1775
|
* The owner is the one in the page's name (#1456), not frontmatter
|
|
1624
1776
|
* `author`, so reassigning `author` cannot move ownership (#711).
|
|
@@ -1629,7 +1781,7 @@ declare class PageManager extends BaseManager implements CatalogSource {
|
|
|
1629
1781
|
* - `false` — a private name, and the caller is neither — whether or not
|
|
1630
1782
|
* the page exists
|
|
1631
1783
|
*/
|
|
1632
|
-
checkPrivatePageAccess(wikiContext: WikiContext, pageNameOrUuid: string): Promise<boolean | null>;
|
|
1784
|
+
checkPrivatePageAccess(wikiContext: WikiContext, pageNameOrUuid: string, adminEntry?: 'record' | 'quiet' | 'none'): Promise<boolean | null>;
|
|
1633
1785
|
/**
|
|
1634
1786
|
* Owner and store of a private page, or `null` when the page is not private
|
|
1635
1787
|
* or does not exist (#1398). The owner owns the page and every attachment
|
|
@@ -1686,6 +1838,15 @@ declare class PageManager extends BaseManager implements CatalogSource {
|
|
|
1686
1838
|
* Best-effort: a failure is logged and never blocks start-up. An encrypted
|
|
1687
1839
|
* store is not readable here and is not touched — it migrates at its
|
|
1688
1840
|
* owner's unlock, through {@link migratePrivateLinks}.
|
|
1841
|
+
*
|
|
1842
|
+
* #1815 (operator, 2026-11-04, decision 2): the public pages are the system
|
|
1843
|
+
* principal's work; each user's vaults are a job on behalf of that user
|
|
1844
|
+
* ({@link jobContextForOwner}), through the write door like any write. The
|
|
1845
|
+
* vault container rule admits a job carrying its owner, and the owner's
|
|
1846
|
+
* rights in their own vaults come from policy, resolved when each write is
|
|
1847
|
+
* decided. The system principal is let into no vault. A shared folder is
|
|
1848
|
+
* not a user's and opens to no boot job (its key never reaches one), so it
|
|
1849
|
+
* is not visited.
|
|
1689
1850
|
*/
|
|
1690
1851
|
migratePrivateLinksAtBoot(): Promise<void>;
|
|
1691
1852
|
/**
|
|
@@ -1799,8 +1960,9 @@ declare class PageManager extends BaseManager implements CatalogSource {
|
|
|
1799
1960
|
* keeps its `lastModified` and `editor`, since nobody edited it. The audit
|
|
1800
1961
|
* record is a rename, from the old path to the new.
|
|
1801
1962
|
*
|
|
1802
|
-
* Access is
|
|
1803
|
-
*
|
|
1963
|
+
* Access is decided by the save it makes, as for every write (#1815): an
|
|
1964
|
+
* edit of the page where it is and a create in the vault it goes to. A
|
|
1965
|
+
* page is never moved out of an encrypted vault
|
|
1804
1966
|
* into one that is not, since that would write it in the clear.
|
|
1805
1967
|
*
|
|
1806
1968
|
* @param pageName - The page's private name, `vaults/{owner}/{vault}/{title}`
|
|
@@ -1823,7 +1985,7 @@ declare class PageManager extends BaseManager implements CatalogSource {
|
|
|
1823
1985
|
*
|
|
1824
1986
|
* @returns How many pages moved
|
|
1825
1987
|
*/
|
|
1826
|
-
moveCapturesToCaptureVault(ctx: ActorContext): Promise<number>;
|
|
1988
|
+
moveCapturesToCaptureVault(ctx: ActorContext, owner?: string): Promise<number>;
|
|
1827
1989
|
/**
|
|
1828
1990
|
* Move private pages made before #1505 into their system-category's own
|
|
1829
1991
|
* vault (#1507). Until then every private page went to its owner's default
|
|
@@ -1838,7 +2000,7 @@ declare class PageManager extends BaseManager implements CatalogSource {
|
|
|
1838
2000
|
*
|
|
1839
2001
|
* @returns How many pages moved
|
|
1840
2002
|
*/
|
|
1841
|
-
movePagesToCategoryVaults(ctx: ActorContext): Promise<number>;
|
|
2003
|
+
movePagesToCategoryVaults(ctx: ActorContext, owner?: string): Promise<number>;
|
|
1842
2004
|
/**
|
|
1843
2005
|
* Every private slug in the `vaults--…` form (#1507), once per vault. A
|
|
1844
2006
|
* private page's slug is made fresh on every save, so each page whose slug
|
|
@@ -1848,7 +2010,7 @@ declare class PageManager extends BaseManager implements CatalogSource {
|
|
|
1848
2010
|
*
|
|
1849
2011
|
* @returns How many pages were re-saved
|
|
1850
2012
|
*/
|
|
1851
|
-
migratePrivateSlugs(ctx: ActorContext): Promise<number>;
|
|
2013
|
+
migratePrivateSlugs(ctx: ActorContext, owner?: string): Promise<number>;
|
|
1852
2014
|
/**
|
|
1853
2015
|
* One pass of a vault move: every page in the vaults `ctx` can open is
|
|
1854
2016
|
* offered to `pick`, which names the vault it goes to (and any frontmatter
|
|
@@ -1,5 +1,6 @@
|
|
|
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 DeclaredSubjectAttribute } from '../utils/policyAttributes.js';
|
|
3
4
|
import { WikiEngine } from '../types/WikiEngine.js';
|
|
4
5
|
/**
|
|
5
6
|
* User context for policy evaluation
|
|
@@ -17,15 +18,55 @@ interface UserContext {
|
|
|
17
18
|
* PIP (#1504): today a page's `system-category`.
|
|
18
19
|
*/
|
|
19
20
|
export type ResourceAttributes = Record<string, unknown>;
|
|
21
|
+
/**
|
|
22
|
+
* Reads one attribute a condition names, `subject:id` or `resource:owner`
|
|
23
|
+
* (#2255). Supplied by the PDP from the PIP; `undefined` or `null` is a
|
|
24
|
+
* missing attribute. Asked only when a matching policy has a condition. A
|
|
25
|
+
* reader may be async (an identity is resolved through IdentityManager), and
|
|
26
|
+
* the evaluator awaits every read.
|
|
27
|
+
*/
|
|
28
|
+
export type AttributeReader = (name: string) => unknown | Promise<unknown>;
|
|
20
29
|
/**
|
|
21
30
|
* Access evaluation context
|
|
22
31
|
*/
|
|
23
32
|
interface AccessContext {
|
|
24
33
|
pageName: string;
|
|
34
|
+
/**
|
|
35
|
+
* The action asked. `actions` widens it: a policy granting any of them
|
|
36
|
+
* matches (#2255: a page write is `page-edit` or `pushed-pages-edit`).
|
|
37
|
+
*/
|
|
25
38
|
action: string;
|
|
39
|
+
actions?: readonly string[];
|
|
26
40
|
userContext?: UserContext;
|
|
27
41
|
attributes?: ResourceAttributes;
|
|
42
|
+
/** For a policy's `condition`; without one every condition is unknown. */
|
|
43
|
+
readAttribute?: AttributeReader;
|
|
28
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* What is wrong with a policy's condition, one sentence each (#2255, #2261);
|
|
47
|
+
* empty when it is fine. Each sentence says what is wrong, then what to
|
|
48
|
+
* change. A node is a comparison (`attribute` and one operator) or `any-of`,
|
|
49
|
+
* `all-of` or `not` over other conditions, nested at most
|
|
50
|
+
* {@link MAX_CONDITION_DEPTH} deep, at most {@link MAX_CONDITION_NODES} nodes
|
|
51
|
+
* in all, an `in` list of at most {@link MAX_IN_ITEMS} and an `any-of` or
|
|
52
|
+
* `all-of` of at most {@link MAX_GROUP_CHILDREN}. Each attribute a comparison names must be
|
|
53
|
+
* declared: a `subject:<name>` in `ngdpbase.access.subject-attributes`
|
|
54
|
+
* (`id` always, `aal` as shipped), or a `resource:<name>` declared on the `page`
|
|
55
|
+
* resource type. The types of the two sides must agree. A condition with a
|
|
56
|
+
* problem never holds: an allow with it does not apply and a deny with it
|
|
57
|
+
* does, as for a missing attribute.
|
|
58
|
+
*/
|
|
59
|
+
export declare function conditionProblems(condition: unknown, pageAttributes: Record<string, {
|
|
60
|
+
type?: string;
|
|
61
|
+
}>, subjectAttributes?: Record<string, DeclaredSubjectAttribute>): string[];
|
|
62
|
+
/**
|
|
63
|
+
* Is the condition true, false or unknown (#2255, #2261)? `true` or `false`,
|
|
64
|
+
* or `undefined` when it cannot be told because an attribute it reads is
|
|
65
|
+
* missing; the caller fails closed on that. Each node is judged on its own:
|
|
66
|
+
* a missing attribute makes its leaf unknown, a true branch decides `any-of`,
|
|
67
|
+
* a false branch decides `all-of`, and `not` of unknown is unknown.
|
|
68
|
+
*/
|
|
69
|
+
export declare function conditionHolds(condition: PolicyCondition | undefined, read: AttributeReader | undefined, depth?: number): Promise<boolean | undefined>;
|
|
29
70
|
/**
|
|
30
71
|
* How each policy resource type matches (#1504). The TYPES are declared in
|
|
31
72
|
* configuration, `ngdpbase.access.resource-types`, and read through
|
|
@@ -40,7 +81,12 @@ export declare const RESOURCE_MATCHERS: Record<string, (pattern: string, pageNam
|
|
|
40
81
|
* PolicyValidator accepts: a type with no matcher here would be a policy that
|
|
41
82
|
* grants nothing.
|
|
42
83
|
*/
|
|
43
|
-
export declare const SUBJECT_MATCHERS: Record<string, (value: string, userContext: UserContext | undefined) => boolean>;
|
|
84
|
+
export declare const SUBJECT_MATCHERS: Record<string, (value: string | undefined, userContext: UserContext | undefined) => boolean>;
|
|
85
|
+
/**
|
|
86
|
+
* The subject types that take no `value` (#2261), for the validator. A value
|
|
87
|
+
* on one is refused rather than ignored.
|
|
88
|
+
*/
|
|
89
|
+
export declare const VALUELESS_SUBJECT_TYPES: readonly string[];
|
|
44
90
|
/**
|
|
45
91
|
* The resource types configuration declares (#1504), for the evaluator and the
|
|
46
92
|
* validator alike. When the key is not set at all — a configuration older than
|
|
@@ -56,14 +102,19 @@ interface EvaluationResult {
|
|
|
56
102
|
allowed: boolean;
|
|
57
103
|
reason: string;
|
|
58
104
|
policyName: string | null;
|
|
105
|
+
/** The deciding policies' ids (#2255): the denies that matched, else the allows. Empty when none matched. */
|
|
106
|
+
policyIds: string[];
|
|
107
|
+
/** Allows that matched subject, resource and action but whose condition was false or unknown (#2288). Absent when none. */
|
|
108
|
+
conditionNotMet?: string[];
|
|
59
109
|
}
|
|
60
110
|
/**
|
|
61
111
|
* PolicyEvaluator - Evaluates access policies against a given context.
|
|
62
112
|
*
|
|
63
113
|
* PolicyEvaluator mimics how JSPWiki uses Java's built-in security framework
|
|
64
114
|
* (java.security) to load and evaluate security policies from a policy file.
|
|
65
|
-
*
|
|
66
|
-
* decision
|
|
115
|
+
* Among the policies that match, a deny overrides any allow whatever its
|
|
116
|
+
* priority, and no match is a deny (#2255). Each decision names the policies
|
|
117
|
+
* that decided it.
|
|
67
118
|
*
|
|
68
119
|
* @class PolicyEvaluator
|
|
69
120
|
* @extends BaseManager
|
|
@@ -112,24 +163,35 @@ declare class PolicyEvaluator extends BaseManager {
|
|
|
112
163
|
*/
|
|
113
164
|
initialize(): Promise<void>;
|
|
114
165
|
/**
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
|
|
122
|
-
|
|
166
|
+
* Say at boot what an administrator should look at in the policies after
|
|
167
|
+
* #2255, one warning each, and one needs-attention entry for them all:
|
|
168
|
+
* stored policies the upgrade rewrote, policies it left that now decide
|
|
169
|
+
* differently (a deny) or reach pushed pages, conditions that never hold,
|
|
170
|
+
* and stored categories no policy lets anyone change (their pages are
|
|
171
|
+
* changed by nobody, admin included).
|
|
172
|
+
*/
|
|
173
|
+
private reportPageWritePolicies;
|
|
174
|
+
/**
|
|
175
|
+
* Evaluates all relevant policies to make an access decision (#2255).
|
|
123
176
|
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
* });
|
|
130
|
-
* console.log('Allowed:', result.allowed, 'Reason:', result.reason);
|
|
177
|
+
* Deny overrides allow: if any matching deny applies, the answer is deny,
|
|
178
|
+
* whatever the priorities; otherwise any matching allow permits; otherwise
|
|
179
|
+
* no policy decided. A policy with a `condition` applies only when it holds;
|
|
180
|
+
* an unknown condition (a missing attribute) keeps an allow from applying
|
|
181
|
+
* and lets a deny apply, so a missing attribute fails closed.
|
|
131
182
|
*/
|
|
132
183
|
evaluateAccess(context: AccessContext): Promise<EvaluationResult>;
|
|
184
|
+
/**
|
|
185
|
+
* Checks and compiles each policy's condition (#2261). `compile()` does it
|
|
186
|
+
* once for a whole listing; a single decision does it for its few matches.
|
|
187
|
+
*/
|
|
188
|
+
private prepare;
|
|
189
|
+
/**
|
|
190
|
+
* Deny overrides allow, over policies that already match subject, resource
|
|
191
|
+
* and action (#2255). Every matching deny whose condition is true or
|
|
192
|
+
* unknown decides; failing that, every allow whose condition is true.
|
|
193
|
+
*/
|
|
194
|
+
private combine;
|
|
133
195
|
/**
|
|
134
196
|
* Checks if a single policy matches the given context.
|
|
135
197
|
*
|
|
@@ -189,12 +251,25 @@ declare class PolicyEvaluator extends BaseManager {
|
|
|
189
251
|
* `filter` shape, compiled once and applied to many resources.
|
|
190
252
|
*
|
|
191
253
|
* 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
|
|
254
|
+
* once; the predicate matches resources only and combines them exactly as
|
|
255
|
+
* `evaluateAccess` does (deny overrides allow, #2255), so a list and a
|
|
256
|
+
* single decision agree. No log line per call: a listing asks this ~18k
|
|
257
|
+
* times, and the INFO line `evaluateAccess` writes is right for one
|
|
258
|
+
* decision and wrong for a filter.
|
|
196
259
|
*/
|
|
197
|
-
compile(userContext: UserContext | undefined, action: string): (pageName: string, attributes?: ResourceAttributes) => EvaluationResult
|
|
260
|
+
compile(userContext: UserContext | undefined, action: string, actions?: readonly string[]): (pageName: string, attributes?: ResourceAttributes, readAttribute?: AttributeReader) => Promise<EvaluationResult>;
|
|
261
|
+
/** The attributes declared on the `page` resource type (#2255), for checking a condition. */
|
|
262
|
+
declaredPageAttributes(): Record<string, {
|
|
263
|
+
type?: string;
|
|
264
|
+
}>;
|
|
265
|
+
/** The subject attributes a condition may read (#2261): `id` always, and those declared in `ngdpbase.access.subject-attributes`. */
|
|
266
|
+
declaredSubjectAttributes(): Record<string, DeclaredSubjectAttribute>;
|
|
267
|
+
/** Each policy in force whose condition has a problem, with the problems (#2255): for the boot warning. */
|
|
268
|
+
conditionProblemsInForce(): Array<{
|
|
269
|
+
id: string;
|
|
270
|
+
effect: Policy['effect'];
|
|
271
|
+
problems: string[];
|
|
272
|
+
}>;
|
|
198
273
|
matchesResource(resources: PolicyResource[] | undefined, pageName: string, attributes?: ResourceAttributes): boolean;
|
|
199
274
|
/**
|
|
200
275
|
* 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. */
|