@memberjunction/storage 6.2.0-edge.4 → 6.2.0-edge.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/FileStorageEngine.d.ts +45 -1
  2. package/dist/FileStorageEngine.d.ts.map +1 -1
  3. package/dist/FileStorageEngine.js +72 -4
  4. package/dist/FileStorageEngine.js.map +1 -1
  5. package/dist/StorageAccessEvaluator.d.ts +196 -0
  6. package/dist/StorageAccessEvaluator.d.ts.map +1 -0
  7. package/dist/StorageAccessEvaluator.js +435 -0
  8. package/dist/StorageAccessEvaluator.js.map +1 -0
  9. package/dist/config.d.ts +22 -10
  10. package/dist/config.d.ts.map +1 -1
  11. package/dist/config.js +3 -0
  12. package/dist/config.js.map +1 -1
  13. package/dist/drivers/AWSFileStorage.d.ts +8 -0
  14. package/dist/drivers/AWSFileStorage.d.ts.map +1 -1
  15. package/dist/drivers/AWSFileStorage.js +11 -0
  16. package/dist/drivers/AWSFileStorage.js.map +1 -1
  17. package/dist/drivers/AzureFileStorage.d.ts +9 -0
  18. package/dist/drivers/AzureFileStorage.d.ts.map +1 -1
  19. package/dist/drivers/AzureFileStorage.js +22 -24
  20. package/dist/drivers/AzureFileStorage.js.map +1 -1
  21. package/dist/drivers/GoogleDriveFileStorage.d.ts +49 -2
  22. package/dist/drivers/GoogleDriveFileStorage.d.ts.map +1 -1
  23. package/dist/drivers/GoogleDriveFileStorage.js +80 -16
  24. package/dist/drivers/GoogleDriveFileStorage.js.map +1 -1
  25. package/dist/generic/FileStorageBase.d.ts +17 -1
  26. package/dist/generic/FileStorageBase.d.ts.map +1 -1
  27. package/dist/generic/FileStorageBase.js +18 -0
  28. package/dist/generic/FileStorageBase.js.map +1 -1
  29. package/dist/generic/ObjectKeys.d.ts +61 -0
  30. package/dist/generic/ObjectKeys.d.ts.map +1 -0
  31. package/dist/generic/ObjectKeys.js +82 -0
  32. package/dist/generic/ObjectKeys.js.map +1 -0
  33. package/dist/index.d.ts +2 -0
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +2 -0
  36. package/dist/index.js.map +1 -1
  37. package/package.json +6 -6
  38. package/readme.md +74 -0
@@ -1,7 +1,8 @@
1
1
  import { IMetadataProvider, UserInfo } from '@memberjunction/core';
2
2
  import { BaseSingleton } from '@memberjunction/global';
3
- import { FileStorageEngineBase, StorageAccountWithProvider, MJFileStorageAccountEntity, MJFileStorageProviderEntity } from '@memberjunction/core-entities';
3
+ import { FileStorageEngineBase, StorageAccountWithProvider, MJFileEntity, MJFileStorageAccountEntity, MJFileStorageProviderEntity } from '@memberjunction/core-entities';
4
4
  import { FileStorageBase } from './generic/FileStorageBase.js';
5
+ import { StorageAccountAccess } from './StorageAccessEvaluator.js';
5
6
  /**
6
7
  * Options for uploading a file to MJ Storage.
7
8
  */
@@ -51,6 +52,17 @@ export interface UploadFileResult {
51
52
  /** The storage provider that was used */
52
53
  Provider: MJFileStorageProviderEntity;
53
54
  }
55
+ /** Where an `MJ: Files` row says its bytes live — what {@link FileStorageEngine.ResolveFileObject} reads. */
56
+ export type StorageFileLocation = Pick<MJFileEntity, 'ProviderID' | 'ProviderKey' | 'Name'>;
57
+ /** The account, driver and object key that serve an `MJ: Files` row, as {@link FileStorageEngine.ResolveFileObject} returns them. */
58
+ export interface ResolvedFileObject {
59
+ /** The storage account the row's provider resolves to (the provider's first account). */
60
+ Account: MJFileStorageAccountEntity;
61
+ /** An initialized driver for that account. */
62
+ Driver: FileStorageBase;
63
+ /** The object key the row resolves to ({@link StorageObjectKeyOf}): `ProviderKey`, else `Name`. */
64
+ ObjectKey: string;
65
+ }
54
66
  /**
55
67
  * Server-side file storage engine providing high-level operations for uploading,
56
68
  * downloading, and managing files in MJ Storage.
@@ -166,12 +178,44 @@ export declare class FileStorageEngine extends BaseSingleton<FileStorageEngine>
166
178
  * - Decrypting credentials via the Credential Engine
167
179
  * - Setting up OAuth token refresh callbacks for providers like Box
168
180
  *
181
+ * **No permission check.** The driver cache is process-wide and this method does not ask whether `contextUser` may
182
+ * use the account. Code acting for a user must call {@link StorageAccessEvaluator.AssertAccountAccess} (or
183
+ * `AccessibleAccountIDs`) first — the MJServer storage routes, the File Storage core actions and the search lane do —
184
+ * and, going from an `MJ: Files` row to its object, should use {@link ResolveFileObject} instead.
185
+ *
169
186
  * @param accountId - The FileStorageAccount ID to get a driver for
170
187
  * @param contextUser - User context for credential decryption (used for on-demand init)
171
188
  * @returns An initialized, ready-to-use FileStorageBase driver
172
189
  * @throws Error if the account is not found or driver initialization fails
173
190
  */
174
191
  GetDriver(accountId: string, contextUser: UserInfo): Promise<FileStorageBase>;
192
+ /**
193
+ * Resolves an `MJ: Files` row to the account, driver and object key that serve its bytes — and refuses unless
194
+ * `contextUser` may use that account for `access` and may read every `MJ: Files` row that tracks the object.
195
+ *
196
+ * Every route that goes from a file ID to bytes or a URL uses this: the row names only a PROVIDER (and `ProviderKey`
197
+ * / `Name` are written by whoever saved the row), so without the account gate a row could reach an account the caller
198
+ * is refused, and without the tracked-file rule a second row could alias an object whose own row the caller cannot
199
+ * read. Load the row as the caller first — this decides storage access, not whether the caller may see the row.
200
+ *
201
+ * @param file - The row's storage location (`ProviderID`, `ProviderKey`, `Name`)
202
+ * @param contextUser - The caller the decision is for
203
+ * @param access - `Read` to download or sign a URL; `Write` to delete, rename or overwrite the object
204
+ * @param provider - The metadata provider to read permissions through; defaults to `Metadata.Provider`
205
+ * @returns The resolved object, or `null` when the row's provider has no storage account
206
+ * @throws StorageAccountAccessDeniedError when the account refuses `access`;
207
+ * TrackedFileAccessDeniedError when a row tracking the object is not readable by the caller
208
+ */
209
+ ResolveFileObject(file: StorageFileLocation, contextUser: UserInfo, access?: StorageAccountAccess, provider?: IMetadataProvider): Promise<ResolvedFileObject | null>;
210
+ /** The first storage account on `providerID`, refreshing the cache once when none is found; `null` when there is none. */
211
+ private firstAccountForProvider;
212
+ /**
213
+ * Reloads the shared account cache after a lookup missed, as the MJ system user. A forced `Config` loads as the user
214
+ * it is given, and `BaseEngine` empties a config that user cannot read (`MJ: File Storage Accounts`), so a restricted
215
+ * caller forcing the reload would blank the cache, and re-initialize every driver, for everyone. With no system user
216
+ * nothing is reloaded and the miss stands.
217
+ */
218
+ RefreshAfterMiss(provider?: IMetadataProvider): Promise<void>;
175
219
  /**
176
220
  * Uploads a file to MJ Storage and creates an `MJ: Files` entity record.
177
221
  *
@@ -1 +1 @@
1
- {"version":3,"file":"FileStorageEngine.d.ts","sourceRoot":"","sources":["../src/FileStorageEngine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAsB,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACvF,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EACH,qBAAqB,EACrB,0BAA0B,EAE1B,0BAA0B,EAC1B,2BAA2B,EAC9B,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAO5D;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAC9B,mCAAmC;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,qEAAqE;IACrE,QAAQ,EAAE,MAAM,CAAC;IACjB,sDAAsD;IACtD,QAAQ,EAAE,MAAM,CAAC;IACjB,2DAA2D;IAC3D,WAAW,EAAE,QAAQ,CAAC;IACtB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;OAEG;IACH,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC7B,4CAA4C;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,+DAA+D;IAC/D,WAAW,EAAE,MAAM,CAAC;IACpB,wCAAwC;IACxC,OAAO,EAAE,0BAA0B,CAAC;IACpC,yCAAyC;IACzC,QAAQ,EAAE,2BAA2B,CAAC;CACzC;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,qBAAa,iBAAkB,SAAQ,aAAa,CAAC,iBAAiB,CAAC;IAGnE,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,QAAQ,CAAkB;IAClC,OAAO,CAAC,eAAe,CAA8B;IACrD,OAAO,CAAC,YAAY,CAAuB;IAG3C,OAAO,CAAC,YAAY,CAA2C;IAE/D;;OAEG;IACH,WAAkB,QAAQ,IAAI,iBAAiB,CAE9C;IAMD,qDAAqD;IACrD,SAAS,KAAK,IAAI,IAAI,qBAAqB,CAE1C;IAED,sDAAsD;IACtD,IAAW,MAAM,IAAI,OAAO,CAE3B;IAID,+CAA+C;IAC/C,IAAW,QAAQ,IAAI,0BAA0B,EAAE,CAElD;IAED,gDAAgD;IAChD,IAAW,SAAS,IAAI,2BAA2B,EAAE,CAEpD;IAED,+EAA+E;IAC/E,IAAW,qBAAqB,IAAI,0BAA0B,EAAE,CAE/D;IAED,mDAAmD;IACnD,IAAW,kBAAkB,IAAI,OAAO,CAEvC;IAID,6CAA6C;IACtC,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,0BAA0B,GAAG,SAAS;IAIhF,8CAA8C;IACvC,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,2BAA2B,GAAG,SAAS;IAInF,kEAAkE;IAC3D,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,0BAA0B,GAAG,SAAS;IAI7E,gEAAgE;IACzD,uBAAuB,CAAC,UAAU,EAAE,MAAM,GAAG,0BAA0B,EAAE;IAIhF,sEAAsE;IAC/D,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,0BAA0B,GAAG,IAAI;IAQnF;;;;;OAKG;IACU,MAAM,CAAC,YAAY,CAAC,EAAE,OAAO,EAAE,WAAW,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBhH;;;;OAIG;YACW,SAAS;IAiBvB;;;;;OAKG;IACH,OAAO,CAAC,oBAAoB;IAU5B;;;;;;OAMG;IACU,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC;IAmChD;;;;;;;;;;OAUG;IACI,qBAAqB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,0BAA0B,GAAG,IAAI;IAWnF;;;;;;;;;;;;;;;;OAgBG;IACU,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,QAAQ,GAAG,OAAO,CAAC,eAAe,CAAC;IA6B1F;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACU,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC;CAyDjF"}
1
+ {"version":3,"file":"FileStorageEngine.d.ts","sourceRoot":"","sources":["../src/FileStorageEngine.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,9 @@
1
- import { LogError, Metadata } from '@memberjunction/core';
1
+ import { LogError, Metadata, WellKnownUserSource } from '@memberjunction/core';
2
2
  import { BaseSingleton } from '@memberjunction/global';
3
3
  import { FileStorageEngineBase } from '@memberjunction/core-entities';
4
+ import { StorageObjectKeyOf } from './generic/ObjectKeys.js';
4
5
  import { InitializeDriverWithAccountCredentials } from './util.js';
6
+ import { StorageAccessEvaluator } from './StorageAccessEvaluator.js';
5
7
  // ─────────────────────────────────────────────────────────────────────────────
6
8
  // Engine
7
9
  // ─────────────────────────────────────────────────────────────────────────────
@@ -230,6 +232,11 @@ export class FileStorageEngine extends BaseSingleton {
230
232
  * - Decrypting credentials via the Credential Engine
231
233
  * - Setting up OAuth token refresh callbacks for providers like Box
232
234
  *
235
+ * **No permission check.** The driver cache is process-wide and this method does not ask whether `contextUser` may
236
+ * use the account. Code acting for a user must call {@link StorageAccessEvaluator.AssertAccountAccess} (or
237
+ * `AccessibleAccountIDs`) first — the MJServer storage routes, the File Storage core actions and the search lane do —
238
+ * and, going from an `MJ: Files` row to its object, should use {@link ResolveFileObject} instead.
239
+ *
233
240
  * @param accountId - The FileStorageAccount ID to get a driver for
234
241
  * @param contextUser - User context for credential decryption (used for on-demand init)
235
242
  * @returns An initialized, ready-to-use FileStorageBase driver
@@ -244,7 +251,7 @@ export class FileStorageEngine extends BaseSingleton {
244
251
  // On-demand fallback: account wasn't in cache (failed init, added late, etc.)
245
252
  let resolved = this.Base.GetAccountWithProvider(accountId);
246
253
  if (!resolved) {
247
- await this.Config(true, contextUser);
254
+ await this.RefreshAfterMiss();
248
255
  resolved = this.Base.GetAccountWithProvider(accountId);
249
256
  }
250
257
  if (!resolved) {
@@ -259,6 +266,64 @@ export class FileStorageEngine extends BaseSingleton {
259
266
  this._driverCache.set(accountId, driver);
260
267
  return driver;
261
268
  }
269
+ /**
270
+ * Resolves an `MJ: Files` row to the account, driver and object key that serve its bytes — and refuses unless
271
+ * `contextUser` may use that account for `access` and may read every `MJ: Files` row that tracks the object.
272
+ *
273
+ * Every route that goes from a file ID to bytes or a URL uses this: the row names only a PROVIDER (and `ProviderKey`
274
+ * / `Name` are written by whoever saved the row), so without the account gate a row could reach an account the caller
275
+ * is refused, and without the tracked-file rule a second row could alias an object whose own row the caller cannot
276
+ * read. Load the row as the caller first — this decides storage access, not whether the caller may see the row.
277
+ *
278
+ * @param file - The row's storage location (`ProviderID`, `ProviderKey`, `Name`)
279
+ * @param contextUser - The caller the decision is for
280
+ * @param access - `Read` to download or sign a URL; `Write` to delete, rename or overwrite the object
281
+ * @param provider - The metadata provider to read permissions through; defaults to `Metadata.Provider`
282
+ * @returns The resolved object, or `null` when the row's provider has no storage account
283
+ * @throws StorageAccountAccessDeniedError when the account refuses `access`;
284
+ * TrackedFileAccessDeniedError when a row tracking the object is not readable by the caller
285
+ */
286
+ async ResolveFileObject(file, contextUser, access = 'Read', provider) {
287
+ const account = await this.firstAccountForProvider(file.ProviderID, contextUser, provider);
288
+ if (!account) {
289
+ return null;
290
+ }
291
+ const evaluator = StorageAccessEvaluator.Instance;
292
+ await evaluator.AssertAccountAccess(account.ID, contextUser, access, provider);
293
+ const driver = await this.GetDriver(account.ID, contextUser);
294
+ const objectKey = StorageObjectKeyOf(file);
295
+ await evaluator.AssertTrackedObjectsReadable(file.ProviderID, [objectKey], contextUser, provider, driver);
296
+ return { Account: account, Driver: driver, ObjectKey: objectKey };
297
+ }
298
+ /** The first storage account on `providerID`, refreshing the cache once when none is found; `null` when there is none. */
299
+ async firstAccountForProvider(providerID, contextUser, provider) {
300
+ await this.Config(false, contextUser, provider);
301
+ let accounts = this.Base.GetAccountsByProviderID(providerID);
302
+ if (accounts.length === 0) {
303
+ await this.RefreshAfterMiss(provider);
304
+ accounts = this.Base.GetAccountsByProviderID(providerID);
305
+ }
306
+ return accounts[0] ?? null;
307
+ }
308
+ /**
309
+ * Reloads the shared account cache after a lookup missed, as the MJ system user. A forced `Config` loads as the user
310
+ * it is given, and `BaseEngine` empties a config that user cannot read (`MJ: File Storage Accounts`), so a restricted
311
+ * caller forcing the reload would blank the cache, and re-initialize every driver, for everyone. With no system user
312
+ * nothing is reloaded and the miss stands.
313
+ */
314
+ async RefreshAfterMiss(provider) {
315
+ const md = provider ?? Metadata.Provider;
316
+ let systemUser = null;
317
+ try {
318
+ systemUser = await WellKnownUserSource.Instance.GetSystemUser(md);
319
+ }
320
+ catch (error) {
321
+ LogError(`FileStorageEngine: resolving the system user for a cache refresh failed: ${error instanceof Error ? error.message : String(error)}`);
322
+ }
323
+ if (systemUser) {
324
+ await this.Config(true, systemUser, md);
325
+ }
326
+ }
262
327
  /**
263
328
  * Uploads a file to MJ Storage and creates an `MJ: Files` entity record.
264
329
  *
@@ -292,8 +357,8 @@ export class FileStorageEngine extends BaseSingleton {
292
357
  // 1. Resolve storage account
293
358
  let resolved = this.ResolveStorageAccount(storageAccountId);
294
359
  if (!resolved) {
295
- // Attempt a forced refresh from database in case account was recently added or cache was stale
296
- await this.Config(true, contextUser, md);
360
+ // Attempt a refresh from the database in case the account was recently added or the cache was stale
361
+ await this.RefreshAfterMiss(md);
297
362
  resolved = this.ResolveStorageAccount(storageAccountId);
298
363
  }
299
364
  if (!resolved) {
@@ -306,6 +371,9 @@ export class FileStorageEngine extends BaseSingleton {
306
371
  const rawPrefix = options.pathPrefix ?? `artifacts/${new Date().toISOString().slice(0, 10)}/${crypto.randomUUID()}`;
307
372
  const cleanPrefix = rawPrefix.replace(/\.\./g, '').replace(/^[/\\]+/, '').replace(/[\x00-\x1f\x7f]/g, '').replace(/[/\\]+/g, '/').replace(/\/+$/, '') || 'artifacts';
308
373
  const storagePath = `${cleanPrefix}/${cleanFileName}`;
374
+ // Never overwrite an object that backs an `MJ: Files` row the caller cannot read (a caller-chosen pathPrefix can
375
+ // name one). The account gate is the caller's job — this method uploads to the account it is given.
376
+ await StorageAccessEvaluator.Instance.AssertTrackedObjectsReadable(resolved.provider.ID, [storagePath], contextUser, md, driver);
309
377
  const uploaded = await driver.PutObject(storagePath, content, mimeType);
310
378
  if (!uploaded) {
311
379
  throw new Error(`FileStorageEngine.UploadFile: PutObject returned false for path '${storagePath}'`);
@@ -1 +1 @@
1
- {"version":3,"file":"FileStorageEngine.js","sourceRoot":"","sources":["../src/FileStorageEngine.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"FileStorageEngine.js","sourceRoot":"","sources":["../src/FileStorageEngine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,196 @@
1
+ /**
2
+ * @fileoverview The one place MJ decides who may use a file storage account, and which tracked files in it a user may
3
+ * read.
4
+ *
5
+ * `MJ: File Storage Account Permissions` rows grant `CanRead` and/or `CanWrite` on a storage account to Everyone, to a
6
+ * Role, or to a single User. Every consumer of that model asks {@link StorageAccessEvaluator}: the storage GraphQL routes
7
+ * (MJServer `FileResolver`, `ArtifactFileResolver`), the File Storage core actions and the agent file handler, the
8
+ * search lane (`StorageSearchProvider`), the search engine's late permission filter, and every route that goes from an
9
+ * `MJ: Files` row to its object (through `FileStorageEngine.ResolveFileObject`).
10
+ *
11
+ * **Evaluated per call.** Nothing is snapshotted: each question reads the permission rows for exactly the accounts it
12
+ * names, so a grant or a revocation is seen by the next call, and the answer for one user never depends on which user
13
+ * happened to ask first. Reads set `IgnoreMaxRows`, so the entity's row cap can never drop an account's rows (which the
14
+ * zero-rows rule would read as "open") or a tracked file's row.
15
+ *
16
+ * **Read with an elevated identity, decided for the caller.** The permission rows are read as the MJ system user
17
+ * (resolved through `WellKnownUserSource`, the same way server-side `BaseEngine`s load). Reading them as the caller
18
+ * would turn "this user may not read the permission rows" into "this account has no rows", which the zero-rows rule
19
+ * below treats as open. When no elevated identity can be resolved, or any read fails, the answer is "no access"
20
+ * (fail closed).
21
+ *
22
+ * **The tracked-file rule.** An object that backs an `MJ: Files` row may be read, signed, listed, returned by search,
23
+ * overwritten, moved, copied or deleted only when the caller can read that row ({@link StorageAccessEvaluator.UnreadableTrackedObjectKeys}).
24
+ * Keys are compared through the account driver's `NormalizeObjectKey` and case-insensitively; a key whose meaning
25
+ * depends on the provider (`..`, `\`, `%2F`, ...) is refused outright (`IsSafeStorageObjectKey`).
26
+ *
27
+ * @module @memberjunction/storage
28
+ */
29
+ import { IMetadataProvider, UserInfo } from '@memberjunction/core';
30
+ import { BaseSingleton } from '@memberjunction/global';
31
+ import type { MJFileEntity, MJFileStorageAccountPermissionEntity } from '@memberjunction/core-entities';
32
+ import { StorageObjectKeyNormalizer } from './generic/ObjectKeys.js';
33
+ /** What a caller wants to do with a storage account: list/download/search (`Read`) or upload/delete/move/copy into it (`Write`). */
34
+ export type StorageAccountAccess = 'Read' | 'Write';
35
+ /** The fields of an `MJ: File Storage Account Permissions` row the access decision reads. */
36
+ export type StorageAccountPermissionRow = Pick<MJFileStorageAccountPermissionEntity, 'FileStorageAccountID' | 'Type' | 'UserID' | 'RoleID' | 'CanRead' | 'CanWrite'>;
37
+ /** The permission state of a set of accounts, as read by {@link StorageAccessEvaluator.LoadAccountPermissionState}. */
38
+ export interface StorageAccountPermissionState {
39
+ /** Normalized ({@link NormalizeUUID}) IDs of the requested accounts that exist. */
40
+ ExistingAccountIDs: Set<string>;
41
+ /** Every permission row for the requested accounts. */
42
+ Rows: StorageAccountPermissionRow[];
43
+ }
44
+ /**
45
+ * The refusal for a storage account the caller may not use. Deliberately the same for an account that does not exist, so a
46
+ * refusal never reveals whether an account ID is real.
47
+ */
48
+ export declare const STORAGE_ACCOUNT_ACCESS_DENIED_MESSAGE = "You do not have access to this storage account or it does not exist.";
49
+ /** The refusal for an object backed by an `MJ: Files` row the caller may not read — the wording `GetFileContents` uses. */
50
+ export declare const TRACKED_FILE_ACCESS_DENIED_MESSAGE = "You do not have access to this file or it does not exist.";
51
+ /** Thrown by {@link StorageAccessEvaluator.AssertAccountAccess} when the caller may not use a storage account. */
52
+ export declare class StorageAccountAccessDeniedError extends Error {
53
+ constructor(message?: string);
54
+ }
55
+ /**
56
+ * Thrown by {@link StorageAccessEvaluator.AssertTrackedObjectsReadable} when an object backs an `MJ: Files` row the caller
57
+ * may not read (or its key is one the checks refuse — see {@link IsSafeStorageObjectKey}). Carries
58
+ * {@link TRACKED_FILE_ACCESS_DENIED_MESSAGE}, the wording `GetFileContents` uses for a row it cannot load.
59
+ */
60
+ export declare class TrackedFileAccessDeniedError extends Error {
61
+ constructor(message?: string);
62
+ }
63
+ /** The `MJ: Files` columns needed to work out which object key a row backs. */
64
+ type TrackedFileRow = Pick<MJFileEntity, 'ID' | 'Name' | 'ProviderKey'>;
65
+ /**
66
+ * Decides storage-account access (`Read` / `Write`) and tracked-file read access for a user, per call. See the module
67
+ * documentation for the evaluation model.
68
+ *
69
+ * ```typescript
70
+ * const evaluator = StorageAccessEvaluator.Instance;
71
+ * await evaluator.AssertAccountAccess(accountId, contextUser, 'Write', provider); // throws when refused
72
+ * const readable = await evaluator.AccessibleAccountIDs(ids, contextUser, 'Read', provider);
73
+ * if (readable.has(NormalizeUUID(id))) { ... }
74
+ * ```
75
+ */
76
+ export declare class StorageAccessEvaluator extends BaseSingleton<StorageAccessEvaluator> {
77
+ /**
78
+ * **The current product rule: a storage account with NO `MJ: File Storage Account Permissions` rows is open to every
79
+ * authenticated user, for both Read and Write.** The admin UI documents it ("If no roles are selected, all authorized
80
+ * users have access"), and every account created before account permissions existed relies on it. Entity-level
81
+ * permissions on `MJ: Files` still apply on top.
82
+ *
83
+ * This is the ONLY place the rule lives. Flipping it to "no rows means closed" is a product decision that needs a data
84
+ * migration writing an explicit `Everyone` row (CanRead, and CanWrite where wanted) for every existing account without
85
+ * rows — otherwise every such account goes dark at deploy time.
86
+ */
87
+ private static readonly ACCOUNT_WITHOUT_PERMISSION_ROWS_IS_OPEN;
88
+ /** Returns the global singleton instance. */
89
+ static get Instance(): StorageAccessEvaluator;
90
+ /**
91
+ * The subset of `accountIDs` that `user` may use for `access`, as normalized ({@link NormalizeUUID}) IDs — compare with
92
+ * `NormalizeUUID(id)`. An ID that is not a UUID, names no account, or names an account the user may not use is left
93
+ * out; so is everything when the user cannot be evaluated or the permission read fails (fail closed).
94
+ *
95
+ * @param accountIDs - `MJ: File Storage Accounts` IDs to ask about (duplicates and casing are ignored)
96
+ * @param user - The user the decision is for
97
+ * @param access - `Read` checks `CanRead`; `Write` checks `CanWrite`
98
+ * @param provider - The metadata provider to read through; defaults to `Metadata.Provider`
99
+ */
100
+ AccessibleAccountIDs(accountIDs: string[], user: UserInfo, access: StorageAccountAccess, provider?: IMetadataProvider): Promise<Set<string>>;
101
+ /** Whether `user` may use storage account `accountID` for `access`. See {@link AccessibleAccountIDs}. */
102
+ UserCanAccessAccount(accountID: string, user: UserInfo, access: StorageAccountAccess, provider?: IMetadataProvider): Promise<boolean>;
103
+ /**
104
+ * Throws {@link StorageAccountAccessDeniedError} unless `user` may use storage account `accountID` for `access`. The
105
+ * error carries {@link STORAGE_ACCOUNT_ACCESS_DENIED_MESSAGE} whether the account is restricted or does not exist.
106
+ */
107
+ AssertAccountAccess(accountID: string, user: UserInfo, access: StorageAccountAccess, provider?: IMetadataProvider): Promise<void>;
108
+ /**
109
+ * The decision for ONE account, given all of its permission rows: open when it has none (the current product rule —
110
+ * see {@link ACCOUNT_WITHOUT_PERMISSION_ROWS_IS_OPEN}), otherwise granted when any row both allows `access`
111
+ * (`CanRead` / `CanWrite`) and applies to `user` (an `Everyone` row, a `Role` row for one of `user.UserRoles`, or a
112
+ * `User` row naming `user.ID`). A user that cannot be evaluated (no ID, or no `UserRoles` array) is refused.
113
+ */
114
+ GrantsAccess(rows: StorageAccountPermissionRow[], user: UserInfo, access: StorageAccountAccess): boolean;
115
+ /**
116
+ * Reads, with the elevated reader, which of `accountIDs` exist and every permission row they have. Returns `null` when
117
+ * the question could not be asked (no elevated reader, or a failed read) — callers fail closed.
118
+ * Protected so a host with its own permission store can supply the state; `accountIDs` arrive validated and normalized.
119
+ */
120
+ protected LoadAccountPermissionState(accountIDs: string[], provider?: IMetadataProvider): Promise<StorageAccountPermissionState | null>;
121
+ /**
122
+ * The identity the permission rows and the `MJ: Files` mapping are read with: the MJ system user for `provider`'s
123
+ * connection, or `null` when this process has none. Protected so a host can supply a different elevated reader.
124
+ */
125
+ protected ResolveElevatedReader(provider: IMetadataProvider): Promise<UserInfo | null>;
126
+ /**
127
+ * Which of `objectKeys` back an `MJ: Files` row that `user` may not read. An object is tracked when an `MJ: Files` row
128
+ * on the account's storage provider resolves to it the way the server resolves every row to an object — `ProviderKey`,
129
+ * or `Name` when `ProviderKey` is empty. The mapping is read with the elevated reader (so a row the user cannot see
130
+ * still counts as tracked); whether the user may read each row is then asked as the user, through `RunView` (entity
131
+ * permission and row-level security both apply, as they do for `Load`). Reads are batched and never truncated.
132
+ *
133
+ * **Matching.** The key a caller sends and the key a row stores are both put through `keyNormalizer` — pass the
134
+ * account's driver, whose `NormalizeObjectKey` knows how that driver spells one object several ways (S3's key prefix;
135
+ * leading, trailing and repeated `/` everywhere) — and compared case-insensitively. The lookup finds rows whose stored
136
+ * key is the canonical key with or without a leading or trailing `/`, or the caller's own spelling; a row stored in any
137
+ * other non-canonical spelling (a driver prefix written into `ProviderKey`, doubled slashes) is not found, and MJ's
138
+ * own writers store neither.
139
+ *
140
+ * **Refused keys.** A key {@link IsSafeStorageObjectKey} rejects (a `.`/`..` segment, a backslash, a
141
+ * meaning-changing percent encoding, a control character) is always returned: its meaning depends on the provider,
142
+ * so it is never compared.
143
+ *
144
+ * Untracked keys are never returned — they are governed by the account gate alone. `MJ: Files` rows are keyed by
145
+ * PROVIDER, not account, so a tracked row in another account on the same provider with the same key also counts: the
146
+ * error is always toward refusing. Fails closed — when the mapping cannot be read every key is returned, and when the
147
+ * user-side read fails every tracked key is.
148
+ *
149
+ * @param fileStorageProviderID - The `MJ: File Storage Providers` ID of the account the objects live in
150
+ * @param objectKeys - Object keys as the caller or the driver spells them (path and/or provider object ID)
151
+ * @param keyNormalizer - The account's canonicalizer (its driver); defaults to `NormalizeStorageObjectKey`
152
+ */
153
+ UnreadableTrackedObjectKeys(fileStorageProviderID: string, objectKeys: string[], user: UserInfo, provider?: IMetadataProvider, keyNormalizer?: StorageObjectKeyNormalizer): Promise<Set<string>>;
154
+ /**
155
+ * Throws {@link TrackedFileAccessDeniedError} when any of `objectKeys` backs an `MJ: Files` row `user` may not read
156
+ * (or is a key the checks refuse). See {@link UnreadableTrackedObjectKeys} for the rule.
157
+ */
158
+ AssertTrackedObjectsReadable(fileStorageProviderID: string, objectKeys: string[], user: UserInfo, provider?: IMetadataProvider, keyNormalizer?: StorageObjectKeyNormalizer): Promise<void>;
159
+ /**
160
+ * Reads, with the elevated reader, the `MJ: Files` rows on `fileStorageProviderID` whose stored object key
161
+ * ({@link StorageObjectKeyOf}: `ProviderKey`, else `Name`), lower-cased, is one of `lookupValues` (already lower-cased). Batched, never truncated.
162
+ * Returns `null` when the read could not be made. Protected so a host can change the mapping.
163
+ */
164
+ protected FindTrackedFiles(fileStorageProviderID: string, lookupValues: string[], provider: IMetadataProvider): Promise<TrackedFileRow[] | null>;
165
+ /** Whether a single permission row allows `access` and applies to `user`. */
166
+ private rowGrants;
167
+ /** A user can be evaluated only with an ID and a hydrated `UserRoles` array; anything less is refused. */
168
+ private canEvaluate;
169
+ /** Distinct, normalized, UUID-shaped IDs — anything else can name no account and is simply not asked about. */
170
+ private distinctValidAccountIDs;
171
+ /** {@link LoadAccountPermissionState}, with a throw turned into `null` (fail closed). */
172
+ private loadStateSafely;
173
+ /** Permission rows keyed by normalized account ID. */
174
+ private groupRowsByAccount;
175
+ /** The normalized account IDs in an accounts result. */
176
+ private accountIDsOf;
177
+ /** Narrows a row from the batched read to a permission row. */
178
+ private isPermissionRow;
179
+ /** Each safe key paired with its lower-cased canonical form; keys that canonicalize to the root (`''`) name no object. */
180
+ private canonicalKeys;
181
+ /**
182
+ * The lower-cased stored spellings the lookup matches for each key: the canonical key bare, with a leading `/`, with a
183
+ * trailing `/`, with both — and the caller's own spelling, so a row stored exactly as the caller spells it is found.
184
+ */
185
+ private lookupValues;
186
+ /** `items` in consecutive batches of {@link IN_LIST_BATCH_SIZE}. */
187
+ private batches;
188
+ /** The keys (as the caller spelled them) whose tracked rows include one the user may not read. */
189
+ private keysBehindUnreadableRows;
190
+ /** The canonical, lower-cased object key the server resolves an `MJ: Files` row to ({@link StorageObjectKeyOf}). */
191
+ private trackedKeyOf;
192
+ /** Which of `fileIDs` `user` may read, asked as the user (batched, never truncated); `null` when a read fails. */
193
+ private readableFileIDs;
194
+ }
195
+ export {};
196
+ //# sourceMappingURL=StorageAccessEvaluator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StorageAccessEvaluator.d.ts","sourceRoot":"","sources":["../src/StorageAccessEvaluator.ts"],"names":[],"mappings":"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"}