@webda/core 4.0.0-beta.4 → 4.0.0-beta.6

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 (69) hide show
  1. package/lib/application/application.d.ts.map +1 -1
  2. package/lib/application/application.js +12 -1
  3. package/lib/application/application.js.map +1 -1
  4. package/lib/bin/cli.d.ts +11 -0
  5. package/lib/bin/cli.d.ts.map +1 -1
  6. package/lib/bin/cli.js +26 -6
  7. package/lib/bin/cli.js.map +1 -1
  8. package/lib/core/core.d.ts +3 -2
  9. package/lib/core/core.d.ts.map +1 -1
  10. package/lib/core/core.js +15 -17
  11. package/lib/core/core.js.map +1 -1
  12. package/lib/core/operations.d.ts.map +1 -1
  13. package/lib/core/operations.js +13 -11
  14. package/lib/core/operations.js.map +1 -1
  15. package/lib/deployers/packager.d.ts +38 -0
  16. package/lib/deployers/packager.d.ts.map +1 -1
  17. package/lib/deployers/packager.js +70 -18
  18. package/lib/deployers/packager.js.map +1 -1
  19. package/lib/deployers/packager.service.d.ts +33 -0
  20. package/lib/deployers/packager.service.d.ts.map +1 -0
  21. package/lib/deployers/packager.service.js +112 -0
  22. package/lib/deployers/packager.service.js.map +1 -0
  23. package/lib/index.d.ts +4 -2
  24. package/lib/index.d.ts.map +1 -1
  25. package/lib/index.js +3 -1
  26. package/lib/index.js.map +1 -1
  27. package/lib/models/aclmodel.d.ts +32 -5
  28. package/lib/models/aclmodel.d.ts.map +1 -1
  29. package/lib/models/aclmodel.js +34 -9
  30. package/lib/models/aclmodel.js.map +1 -1
  31. package/lib/models/ownermodel.model.d.ts +25 -3
  32. package/lib/models/ownermodel.model.d.ts.map +1 -1
  33. package/lib/models/ownermodel.model.js +44 -9
  34. package/lib/models/ownermodel.model.js.map +1 -1
  35. package/lib/models/permissions.d.ts +247 -0
  36. package/lib/models/permissions.d.ts.map +1 -0
  37. package/lib/models/permissions.js +522 -0
  38. package/lib/models/permissions.js.map +1 -0
  39. package/lib/models/rolemodel.model.d.ts.map +1 -1
  40. package/lib/models/rolemodel.model.js +1 -2
  41. package/lib/models/rolemodel.model.js.map +1 -1
  42. package/lib/models/user.model.d.ts +12 -0
  43. package/lib/models/user.model.d.ts.map +1 -1
  44. package/lib/models/user.model.js +16 -0
  45. package/lib/models/user.model.js.map +1 -1
  46. package/lib/rest/restoperationstransport.service.d.ts.map +1 -1
  47. package/lib/rest/restoperationstransport.service.js +7 -5
  48. package/lib/rest/restoperationstransport.service.js.map +1 -1
  49. package/lib/services/audit.model.d.ts +2 -2
  50. package/lib/services/audit.model.d.ts.map +1 -1
  51. package/lib/services/audit.model.js +20 -7
  52. package/lib/services/audit.model.js.map +1 -1
  53. package/lib/services/binary.service.d.ts +42 -4
  54. package/lib/services/binary.service.d.ts.map +1 -1
  55. package/lib/services/binary.service.js +33 -13
  56. package/lib/services/binary.service.js.map +1 -1
  57. package/lib/services/domainservice.service.d.ts +74 -3
  58. package/lib/services/domainservice.service.d.ts.map +1 -1
  59. package/lib/services/domainservice.service.js +234 -57
  60. package/lib/services/domainservice.service.js.map +1 -1
  61. package/lib/services/mailer.service.d.ts.map +1 -1
  62. package/lib/services/mailer.service.js +1 -0
  63. package/lib/services/mailer.service.js.map +1 -1
  64. package/lib/stores/store.d.ts +20 -1
  65. package/lib/stores/store.d.ts.map +1 -1
  66. package/lib/stores/store.js +29 -1
  67. package/lib/stores/store.js.map +1 -1
  68. package/package.json +20 -17
  69. package/webda.module.json +92 -24
@@ -0,0 +1,522 @@
1
+ import { ComparisonExpression, LogicalExpression, QueryValidator } from "@webda/ql";
2
+ import { Model } from "@webda/models";
3
+ import { useLog } from "@webda/workout";
4
+ import { createHash } from "node:crypto";
5
+ import * as WebdaError from "../errors/errors.js";
6
+ import { useModel } from "../application/hooks.js";
7
+ import { useDynamicService, useModelMetadata } from "../core/hooks.js";
8
+ /**
9
+ * The CryptoService, resolved at call time (a static import would make a cycle through the operations module)
10
+ * @returns the CryptoService
11
+ */
12
+ function useCrypto() {
13
+ return useDynamicService("CryptoService");
14
+ }
15
+ /**
16
+ * The static `canAct(context, action, object?)` of one model class
17
+ *
18
+ * When the class defines none (a plain object in a unit test, a class built without `@webda/models`), the base
19
+ * {@link Model.canAct} semantics apply: delegate to the instance `canAct(context, action)`, otherwise deny.
20
+ * @param clazz - the model class
21
+ * @returns the static check, bound to its class
22
+ */
23
+ function staticCanActOf(clazz) {
24
+ if (typeof clazz?.canAct === "function") {
25
+ return (context, action, target) => clazz.canAct(context, action, target);
26
+ }
27
+ return (context, action, target) => Model.canAct(context, action, target);
28
+ }
29
+ /**
30
+ * The permission check of an object reached through a model class: the one framework entry point
31
+ *
32
+ * Stores are polymorphic: an object reached through a model class (the route or query class) may belong to a
33
+ * subclass with its own policy. The action is then allowed only when BOTH the reached class and the object's own
34
+ * class allow it, `ReachedModel.canAct(ctx, action, object)` first. When the two are the same class (or there is
35
+ * no object, as for a static action) the class is asked once.
36
+ * @param model - the model class the object is reached through, when known
37
+ * @param object - the object, if any
38
+ * @returns the check
39
+ */
40
+ function staticCanAct(model, object) {
41
+ const own = object !== undefined && object !== null ? object.constructor : undefined;
42
+ const reached = model ?? own;
43
+ const classes = [reached];
44
+ if (typeof model === "function" && own && own !== model && own !== Object) {
45
+ if (!(object instanceof model)) {
46
+ // A row of an unrelated class (a misconfigured shared repository): it is not an object of the reached model
47
+ return () => `not a ${model.name}`;
48
+ }
49
+ classes.push(own);
50
+ }
51
+ const checks = classes.map(staticCanActOf);
52
+ if (checks.length === 1) {
53
+ return checks[0];
54
+ }
55
+ return async (context, action, target) => {
56
+ for (const check of checks) {
57
+ const allowed = await check(context, action, target);
58
+ if (allowed !== true) {
59
+ return allowed;
60
+ }
61
+ }
62
+ return true;
63
+ };
64
+ }
65
+ /**
66
+ * Whether a model class defines a static `canAct` of its own (not the base one)
67
+ * @param model - the model class
68
+ * @returns true when the static form is overridden
69
+ */
70
+ export function hasStaticPermissionCheck(model) {
71
+ return typeof model?.canAct === "function" && model.canAct !== Model.canAct;
72
+ }
73
+ /**
74
+ * Whether a model class defines a permission check at all: a static `canAct` of its own (not the base one), or an
75
+ * instance `canAct`. A model with neither is refused on every transport. Subclasses with their own check do not
76
+ * open a class that has none: an object reached through a class must be allowed by that class too
77
+ * @param model - the model class
78
+ * @returns true when the model defines one of the two forms
79
+ */
80
+ export function hasModelPermissionCheck(model) {
81
+ return hasStaticPermissionCheck(model) || typeof model?.prototype?.canAct === "function";
82
+ }
83
+ /**
84
+ * Run a check, turning a thrown error into a refusal: an error must not answer differently from a refusal, or it
85
+ * would reveal that the object exists (non-HTTP errors are logged at WARN)
86
+ * @param check - the static canAct
87
+ * @param context - the caller context
88
+ * @param action - the action
89
+ * @param object - the object, if any
90
+ * @returns true when allowed, otherwise the refusal (a reason string or false)
91
+ */
92
+ async function askPermission(check, context, action, object) {
93
+ try {
94
+ const allowed = await check(context, action, object);
95
+ if (allowed === true) {
96
+ return true;
97
+ }
98
+ return allowed === false || allowed === undefined || allowed === null ? false : allowed;
99
+ }
100
+ catch (err) {
101
+ if (!(err instanceof WebdaError.HttpError)) {
102
+ useLog("WARN", `canAct('${action}') failed on ${object?.constructor?.name ?? "model"}`, err);
103
+ }
104
+ return err?.message ?? false;
105
+ }
106
+ }
107
+ /**
108
+ * Ask the model whether the current caller may perform `action` on an object
109
+ *
110
+ * The question goes through the static `canAct(context, action, object)` of the model class (see
111
+ * {@link Model.canAct}): the base implementation delegates to the object's instance `canAct`, and denies when there
112
+ * is none. `true` allows; anything else (`false`, a refusal reason string, `undefined`...) refuses, and so does a
113
+ * `canAct` that throws.
114
+ *
115
+ * @param object - the model instance (the new, unsaved object on create)
116
+ * @param context - the caller context
117
+ * @param action - the action name ("get", "create", "update", "delete", an action name or "attribute.action")
118
+ * @param model - the model class (defaults to the object's class)
119
+ * @returns true when allowed, otherwise the refusal (a reason string or false)
120
+ */
121
+ export async function getModelPermission(object, context, action, model) {
122
+ return askPermission(staticCanAct(model, object), context, action, object);
123
+ }
124
+ /**
125
+ * Whether the current caller may perform `action` on a model instance (see {@link checkModelPermission}); it never
126
+ * throws
127
+ * @param object - the model instance
128
+ * @param context - the caller context
129
+ * @param action - the action name
130
+ * @param model - the model class (defaults to the object's class)
131
+ * @returns true when allowed
132
+ */
133
+ export async function isModelActionAllowed(object, context, action, model) {
134
+ return (await getModelPermission(object, context, action, model)) === true;
135
+ }
136
+ /**
137
+ * Message of the NotFound error for a missing object, also used for an object the caller may not read
138
+ */
139
+ export const NOT_FOUND_MESSAGE = "Object not found";
140
+ /**
141
+ * Load an object for an action as the caller: a missing object and an object the caller may not read throw the same
142
+ * `NotFound("Object not found")`; a readable object whose action is refused throws `Forbidden`
143
+ * @param model - the model class
144
+ * @param key - the primary key
145
+ * @param context - the caller context
146
+ * @param action - the action ("get" to only read)
147
+ * @returns the object
148
+ */
149
+ export async function loadModelForAction(model, key, context, action) {
150
+ let object;
151
+ try {
152
+ object = await model.ref(key).get();
153
+ }
154
+ catch {
155
+ // Repositories throw when the object does not exist
156
+ }
157
+ if (!object || object.isDeleted?.()) {
158
+ throw new WebdaError.NotFound(NOT_FOUND_MESSAGE);
159
+ }
160
+ await checkModelPermission(object, context, action, model);
161
+ return object;
162
+ }
163
+ /**
164
+ * The parent relation (`ModelParent`) of a model, if any
165
+ * @param model - the model class
166
+ * @returns the parent attribute and model identifier
167
+ */
168
+ export function getParentRelation(model) {
169
+ try {
170
+ return useModelMetadata(model)?.Relations?.parent;
171
+ }
172
+ catch {
173
+ return undefined;
174
+ }
175
+ }
176
+ /**
177
+ * A child can only be attached to a parent the caller may read: a missing parent and an unreadable one throw the same
178
+ * `NotFound("Object not found")`
179
+ * @param model - the child model class
180
+ * @param parentId - the parent primary key
181
+ * @param context - the caller context
182
+ */
183
+ export async function checkModelParent(model, parentId, context) {
184
+ const parent = getParentRelation(model);
185
+ if (!parent || parentId === undefined || parentId === null || parentId === "") {
186
+ return;
187
+ }
188
+ let parentModel;
189
+ try {
190
+ parentModel = useModel(parent.model);
191
+ }
192
+ catch {
193
+ // Unknown parent model: treated as a missing parent
194
+ }
195
+ if (!parentModel) {
196
+ throw new WebdaError.NotFound(NOT_FOUND_MESSAGE);
197
+ }
198
+ await loadModelForAction(parentModel, parentId, context, "get");
199
+ }
200
+ /**
201
+ * When an update moves an object to another parent, the caller must be able to read the new parent
202
+ * @param model - the model class
203
+ * @param object - the stored object
204
+ * @param input - the sanitized update input
205
+ * @param context - the caller context
206
+ */
207
+ export async function checkModelReparent(model, object, input, context) {
208
+ const parent = getParentRelation(model);
209
+ const value = parent ? input?.[parent.attribute] : undefined;
210
+ if (value === undefined || value === null || String(value) === String(object?.[parent.attribute] ?? "")) {
211
+ return;
212
+ }
213
+ await checkModelParent(model, value, context);
214
+ }
215
+ /**
216
+ * Enforce a model's permission for an action on an object: the single check used by every client path (REST, gRPC,
217
+ * MCP, GraphQL and any transport dispatching operations)
218
+ *
219
+ * A caller who may not read the object (`canAct(ctx, "get", object)` refused) gets exactly the error of a missing
220
+ * object (`NotFound("Object not found")`), whatever the action, so a refusal never reveals that the key exists. A
221
+ * caller who may read the object but not perform the action gets a `Forbidden`. On `"create"` the object does not
222
+ * exist yet: a refusal is always a `Forbidden`.
223
+ *
224
+ * The refusal reason returned by `canAct` is logged, never sent to the client.
225
+ *
226
+ * @param object - the model instance
227
+ * @param context - the caller context
228
+ * @param action - the action name
229
+ * @param model - the model class (defaults to the object's class)
230
+ * @throws WebdaError.NotFound when the caller may not read the object
231
+ * @throws WebdaError.Forbidden when the caller may read the object but not perform the action
232
+ */
233
+ export async function checkModelPermission(object, context, action, model) {
234
+ const check = staticCanAct(model, object);
235
+ const allowed = await askPermission(check, context, action, object);
236
+ if (allowed === true) {
237
+ return;
238
+ }
239
+ useLog("DEBUG", `Permission refused for '${action}' on ${object?.constructor?.name ?? "object"}`, typeof allowed === "string" ? allowed : "");
240
+ if (action !== "create" && (action === "get" || (await askPermission(check, context, "get", object)) !== true)) {
241
+ throw new WebdaError.NotFound(NOT_FOUND_MESSAGE);
242
+ }
243
+ throw new WebdaError.Forbidden(`Action ${action} not allowed`);
244
+ }
245
+ /**
246
+ * Enforce a model's permission for a static (class-level) action: `canAct(context, action)` without object
247
+ *
248
+ * There is no object to hide, so a refusal is always a `Forbidden`.
249
+ * @param model - the model class
250
+ * @param context - the caller context
251
+ * @param action - the action name
252
+ * @throws WebdaError.Forbidden when refused
253
+ */
254
+ export async function checkStaticModelPermission(model, context, action) {
255
+ const allowed = await askPermission(staticCanAct(model), context, action, undefined);
256
+ if (allowed === true) {
257
+ return;
258
+ }
259
+ useLog("DEBUG", `Permission refused for static '${action}' on ${model?.name ?? "model"}`, typeof allowed === "string" ? allowed : "");
260
+ throw new WebdaError.Forbidden(`Action ${action} not allowed`);
261
+ }
262
+ /**
263
+ * Persist a new object with the repository `create`, which refuses an existing key (atomically in every bundled
264
+ * repository), instead of `save()`, which upserts
265
+ * @param object - the new model instance
266
+ * @returns the object
267
+ * @throws WebdaError.Conflict when an object with the same primary key exists
268
+ */
269
+ export async function createModel(object) {
270
+ try {
271
+ await object.getRepository().create(object);
272
+ }
273
+ catch (err) {
274
+ if (/^Already exists/.test(`${err?.message}`)) {
275
+ throw new WebdaError.Conflict("Object already exists");
276
+ }
277
+ throw err;
278
+ }
279
+ return object;
280
+ }
281
+ /**
282
+ * AND the model's permission query into a client query
283
+ *
284
+ * Both sides are parsed and combined on the expression tree, so a client `OR` keeps its precedence. The client
285
+ * ORDER BY, LIMIT and OFFSET are kept.
286
+ *
287
+ * @param query - the client query
288
+ * @param permission - the permission query, if any
289
+ * @returns the query to run
290
+ * @throws SyntaxError if the client query is invalid
291
+ */
292
+ export function mergePermissionQuery(query, permission) {
293
+ if (!permission?.query) {
294
+ return query;
295
+ }
296
+ return new QueryValidator(query ?? "").merge(permission.query, "AND").toString();
297
+ }
298
+ /**
299
+ * Highest LIMIT a client query can ask for: larger LIMITs are lowered to it
300
+ */
301
+ export const MAX_QUERY_LIMIT = 1000;
302
+ /**
303
+ * Rows a permission-filtered query scans to fill one page: ten times the page LIMIT, at least
304
+ * {@link MIN_SCANNED_ROWS}, at most {@link MAX_SCANNED_ROWS}
305
+ */
306
+ export const SCAN_FACTOR = 10;
307
+ /**
308
+ * Lower bound of the scan budget of a permission-filtered page
309
+ */
310
+ export const MIN_SCANNED_ROWS = 100;
311
+ /**
312
+ * Absolute bound of the scan budget of a permission-filtered page
313
+ */
314
+ export const MAX_SCANNED_ROWS = 10000;
315
+ /**
316
+ * Most store pages read to fill one page, whatever their size
317
+ */
318
+ export const MAX_REFILL_PAGES = 100;
319
+ /**
320
+ * Lifetime of a continuation token (one hour): paging has to resume within it
321
+ */
322
+ export const CONTINUATION_TOKEN_TTL_MS = 60 * 60 * 1000;
323
+ /**
324
+ * Refuse a client query that reads private (`__`-prefixed) fields, at any depth, in its filter or ORDER BY: a filter
325
+ * on a private field (a password hash...) would reveal its value through which rows match. The field list of a
326
+ * SELECT and the targets of an UPDATE SET are checked too.
327
+ * @param query - the parsed client query
328
+ * @throws WebdaError.BadRequest when a field path has a `__`-prefixed segment
329
+ */
330
+ export function assertNoPrivateFields(query) {
331
+ const isPrivate = (path) => path.some(segment => segment.startsWith("__"));
332
+ const visit = (expression) => {
333
+ if (expression instanceof LogicalExpression) {
334
+ expression.children.forEach(visit);
335
+ }
336
+ else if (expression instanceof ComparisonExpression && isPrivate(expression.attribute)) {
337
+ throw new WebdaError.BadRequest("Private fields cannot be queried");
338
+ }
339
+ };
340
+ visit(query.getExpression());
341
+ const parsed = query.getQuery();
342
+ if ([
343
+ ...(parsed.orderBy ?? []).map(o => o.field),
344
+ ...(parsed.fields ?? []),
345
+ ...(parsed.assignments ?? []).map(a => a.field)
346
+ ]
347
+ .map(field => field.split("."))
348
+ .some(isPrivate)) {
349
+ throw new WebdaError.BadRequest("Private fields cannot be queried");
350
+ }
351
+ }
352
+ /**
353
+ * Refuse what the Query operations do not run: DELETE and UPDATE statements, and SELECT field lists
354
+ *
355
+ * Statements are parsed by WebdaQL and run by the repositories (`deleteMany`, `updateMany`), never through the
356
+ * Query operations exposed to clients (REST, gRPC, MCP, GraphQL): those take a filter query only.
357
+ * @param query - the parsed client query
358
+ * @throws WebdaError.BadRequest for a DELETE or UPDATE statement, or a SELECT field list
359
+ */
360
+ export function assertFilterOnly(query) {
361
+ const { type, fields } = query.getQuery();
362
+ if (type === "DELETE" || type === "UPDATE") {
363
+ throw new WebdaError.BadRequest(`${type} statements are not accepted by queries`);
364
+ }
365
+ if (fields !== undefined) {
366
+ throw new WebdaError.BadRequest("SELECT field lists are not accepted by queries");
367
+ }
368
+ }
369
+ /**
370
+ * Type tag of a sealed continuation token, so no other ciphertext of the application can be sent as one
371
+ */
372
+ const TOKEN_TYPE = "webda-query-token";
373
+ /**
374
+ * @param binding - the token binding
375
+ * @returns the short hash of the query
376
+ */
377
+ function queryHash(binding) {
378
+ return createHash("sha256").update(binding.query).digest("base64url").substring(0, 32);
379
+ }
380
+ /**
381
+ * Seal a store continuation token: encrypted with the CryptoService (random IV, padded to 64 bytes) so its value
382
+ * cannot be read, compared or forged by the client; bound to the model, the query and the caller; and expiring
383
+ * after `ttl` ({@link CONTINUATION_TOKEN_TTL_MS})
384
+ * @param token - the store token
385
+ * @param binding - what the token is bound to
386
+ * @param ttl - lifetime in milliseconds
387
+ * @returns the opaque token
388
+ */
389
+ export async function sealContinuationToken(token, binding, ttl = CONTINUATION_TOKEN_TTL_MS) {
390
+ const payload = {
391
+ typ: TOKEN_TYPE,
392
+ t: token,
393
+ m: binding.model,
394
+ q: queryHash(binding),
395
+ u: binding.user,
396
+ exp: Date.now() + ttl,
397
+ p: ""
398
+ };
399
+ const base = JSON.stringify(payload).length;
400
+ return useCrypto().encrypt({ ...payload, p: "=".repeat((64 - (base % 64)) % 64) });
401
+ }
402
+ /**
403
+ * Open a token produced by {@link sealContinuationToken}
404
+ * @param token - the opaque token
405
+ * @param binding - what the token must be bound to
406
+ * @returns the store token
407
+ * @throws WebdaError.BadRequest when the token was not produced by this application for this model, query and
408
+ * caller, or has expired
409
+ */
410
+ export async function unsealContinuationToken(token, binding) {
411
+ let data;
412
+ try {
413
+ data = await useCrypto().decrypt(token);
414
+ }
415
+ catch {
416
+ // Invalid, forged or expired key
417
+ }
418
+ if (data?.typ === TOKEN_TYPE &&
419
+ typeof data.t === "string" &&
420
+ data.m === binding.model &&
421
+ data.q === queryHash(binding) &&
422
+ data.u === binding.user &&
423
+ typeof data.exp === "number" &&
424
+ data.exp > Date.now()) {
425
+ return data.t;
426
+ }
427
+ throw new WebdaError.BadRequest("Invalid continuation token");
428
+ }
429
+ /**
430
+ * @param model - the model class
431
+ * @returns its identifier, or its class name for classes registered without metadata
432
+ */
433
+ function modelIdentifier(model) {
434
+ try {
435
+ return useModelMetadata(model)?.Identifier ?? model?.name ?? "model";
436
+ }
437
+ catch {
438
+ return model?.name ?? "model";
439
+ }
440
+ }
441
+ /**
442
+ * Query a model as the caller
443
+ *
444
+ * - the client query may not read private (`__`) fields (400), and its LIMIT is lowered to {@link MAX_QUERY_LIMIT};
445
+ * - the client query is a filter: DELETE, UPDATE and SELECT field lists are refused (400, {@link assertFilterOnly});
446
+ * - a model defining neither `canAct` form refuses every row: the store is not asked;
447
+ * - the model's static `getPermissionQuery(context)` is ANDed into the query;
448
+ * - every result is checked with the static `canAct(context, "get", row)` and refused ones are dropped. Refused rows
449
+ * are replaced by continuing the scan (next store pages, asking only for the missing rows), within a budget of
450
+ * `SCAN_FACTOR` x LIMIT rows (between `MIN_SCANNED_ROWS` and `MAX_SCANNED_ROWS`) and {@link MAX_REFILL_PAGES}
451
+ * store pages. When the budget is spent, an empty page carries no token;
452
+ * - the continuation token is sealed ({@link sealContinuationToken}): a store token counting or naming rows
453
+ * (Postgres/Firestore offsets, Dynamo keys, memory offsets) would otherwise reveal hidden matches. It is bound to
454
+ * the model, the query and the caller, expires after {@link CONTINUATION_TOKEN_TTL_MS}, and is sent back as is in
455
+ * `OFFSET`; any other value is a 400.
456
+ *
457
+ * @param model - the model class
458
+ * @param query - the client query
459
+ * @param context - the caller context
460
+ * @returns the query results the caller may read
461
+ */
462
+ export async function queryModelWithPermissions(model, query, context) {
463
+ const client = new QueryValidator(query ?? "");
464
+ assertNoPrivateFields(client);
465
+ assertFilterOnly(client);
466
+ if (!hasModelPermissionCheck(model)) {
467
+ // Deny by default: no row can be read, the store is not even asked
468
+ return { results: [], continuationToken: undefined };
469
+ }
470
+ const limit = Math.min(client.getLimit(), MAX_QUERY_LIMIT);
471
+ const permission = typeof model.getPermissionQuery === "function" ? model.getPermissionQuery(context) : undefined;
472
+ const merged = new QueryValidator(mergePermissionQuery(query ?? "", permission));
473
+ // The query without its LIMIT and OFFSET: filter and ORDER BY
474
+ const orderBy = (merged.getQuery().orderBy ?? []).map(o => `${o.field} ${o.direction}`).join(", ");
475
+ const base = `${merged.getExpression().toString()}${orderBy ? ` ORDER BY ${orderBy}` : ""}`.trim();
476
+ const binding = {
477
+ model: modelIdentifier(model),
478
+ query: base,
479
+ user: context.getCurrentUserId() || "anonymous"
480
+ };
481
+ let offset = client.getOffset();
482
+ if (offset) {
483
+ offset = await unsealContinuationToken(offset, binding);
484
+ }
485
+ /**
486
+ * @param count - the LIMIT
487
+ * @param token - the store OFFSET
488
+ * @returns the query to send to the store
489
+ */
490
+ const page = (count, token) => new QueryValidator(base).merge(`LIMIT ${count}${token ? ` OFFSET ${JSON.stringify(token)}` : ""}`).toString();
491
+ const budget = Math.min(Math.max(limit * SCAN_FACTOR, MIN_SCANNED_ROWS), MAX_SCANNED_ROWS);
492
+ const results = [];
493
+ let scanned = 0;
494
+ let pages = 1;
495
+ let res = await model.query(page(limit, offset));
496
+ let token;
497
+ while (true) {
498
+ const rows = res.results ?? [];
499
+ scanned += rows.length;
500
+ // Each row is checked with the queried class and, for a subclass row, its own class too
501
+ const readable = await Promise.all(rows.map(async (r) => (await askPermission(staticCanAct(model, r), context, "get", r)) === true));
502
+ results.push(...rows.filter((_r, i) => readable[i]));
503
+ token = res.continuationToken;
504
+ if (!token || results.length >= limit) {
505
+ // Store exhausted, or page full
506
+ break;
507
+ }
508
+ if (scanned >= budget || pages >= MAX_REFILL_PAGES || rows.length === 0) {
509
+ // Budget spent, or a store that does not progress: a token on an empty page would only reveal hidden matches
510
+ token = results.length ? token : undefined;
511
+ break;
512
+ }
513
+ // Refill: continue after the last scanned row, asking only for the rows still missing
514
+ pages++;
515
+ res = await model.query(page(Math.min(limit - results.length, budget - scanned), token));
516
+ }
517
+ return {
518
+ results,
519
+ continuationToken: token ? await sealContinuationToken(String(token), binding) : undefined
520
+ };
521
+ }
522
+ //# sourceMappingURL=permissions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permissions.js","sourceRoot":"","sources":["../../src/models/permissions.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"rolemodel.model.d.ts","sourceRoot":"","sources":["../../src/models/rolemodel.model.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAIjE,8EAA8E;AAC9E,uBAAe,SAAU,SAAQ,KAAK;IACpC,QAAQ,CAAC,WAAW,IAAI;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;IAElD;;;OAGG;IACH,YAAY,IAAI,OAAO,CAEtB;IAED;;;;OAIG;IACG,QAAQ,CAAC,GAAG,EAAE,iBAAiB,gBAYpC;IAED;;;;;OAKG;IACG,MAAM,CAAC,OAAO,EAAE,iBAAiB,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,OAAO,CAAC,CAalF;CACF;AAED,OAAO,EAAE,SAAS,EAAE,CAAC"}
1
+ {"version":3,"file":"rolemodel.model.d.ts","sourceRoot":"","sources":["../../src/models/rolemodel.model.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAGjE,8EAA8E;AAC9E,uBAAe,SAAU,SAAQ,KAAK;IACpC,QAAQ,CAAC,WAAW,IAAI;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;IAElD;;;OAGG;IACH,YAAY,IAAI,OAAO,CAEtB;IAED;;;;OAIG;IACG,QAAQ,CAAC,GAAG,EAAE,iBAAiB,gBAYpC;IAED;;;;;OAKG;IACG,MAAM,CAAC,OAAO,EAAE,iBAAiB,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,OAAO,CAAC,CAalF;CACF;AAED,OAAO,EAAE,SAAS,EAAE,CAAC"}
@@ -1,6 +1,5 @@
1
1
  import { Model } from "@webda/models";
2
2
  import * as WebdaError from "../errors/errors.js";
3
- import { useContext } from "../contexts/execution.js";
4
3
  /** Model with role-based access control, mapping actions to required roles */
5
4
  class RoleModel extends Model {
6
5
  /**
@@ -42,7 +41,7 @@ class RoleModel extends Model {
42
41
  }
43
42
  return "No permission for this action defined";
44
43
  }
45
- const roles = await this.getRoles(useContext());
44
+ const roles = await this.getRoles(context);
46
45
  if (roles.indexOf(this.getRolesMap()[action]) >= 0) {
47
46
  return true;
48
47
  }
@@ -1 +1 @@
1
- {"version":3,"file":"rolemodel.model.js","sourceRoot":"","sources":["../../src/models/rolemodel.model.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAEtC,OAAO,KAAK,UAAU,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAEtD,8EAA8E;AAC9E,MAAe,SAAU,SAAQ,KAAK;IAGpC;;;OAGG;IACH,YAAY;QACV,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,QAAQ,CAAC,GAAsB;QACnC,IAAI,CAAC,GAAG,CAAC,gBAAgB,EAAE,EAAE,CAAC;YAC5B,MAAM,IAAI,UAAU,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QAC5C,CAAC;QACD,iCAAiC;QACjC,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC,KAAK,EAAE,CAAC;YAC3B,OAAO,GAAG,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC;QAChC,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,cAAc,EAAE,CAAC;QACxC,yBAAyB;QACzB,GAAG,CAAC,UAAU,EAAE,CAAC,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;QACzC,OAAO,GAAG,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC;IAChC,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,MAAM,CAAC,OAA0B,EAAE,MAAc;QACrD,sCAAsC;QACtC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC;YAChC,IAAI,IAAI,CAAC,YAAY,EAAE,EAAE,CAAC;gBACxB,OAAO,IAAI,CAAC;YACd,CAAC;YACD,OAAO,uCAAuC,CAAC;QACjD,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;QAChD,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;YACnD,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,eAAe,CAAC;IACzB,CAAC;CACF;AAED,OAAO,EAAE,SAAS,EAAE,CAAC"}
1
+ {"version":3,"file":"rolemodel.model.js","sourceRoot":"","sources":["../../src/models/rolemodel.model.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAEtC,OAAO,KAAK,UAAU,MAAM,qBAAqB,CAAC;AAElD,8EAA8E;AAC9E,MAAe,SAAU,SAAQ,KAAK;IAGpC;;;OAGG;IACH,YAAY;QACV,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,QAAQ,CAAC,GAAsB;QACnC,IAAI,CAAC,GAAG,CAAC,gBAAgB,EAAE,EAAE,CAAC;YAC5B,MAAM,IAAI,UAAU,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QAC5C,CAAC;QACD,iCAAiC;QACjC,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC,KAAK,EAAE,CAAC;YAC3B,OAAO,GAAG,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC;QAChC,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,cAAc,EAAE,CAAC;QACxC,yBAAyB;QACzB,GAAG,CAAC,UAAU,EAAE,CAAC,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;QACzC,OAAO,GAAG,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC;IAChC,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,MAAM,CAAC,OAA0B,EAAE,MAAc;QACrD,sCAAsC;QACtC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC;YAChC,IAAI,IAAI,CAAC,YAAY,EAAE,EAAE,CAAC;gBACxB,OAAO,IAAI,CAAC;YACd,CAAC;YACD,OAAO,uCAAuC,CAAC;QACjD,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAC3C,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;YACnD,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,eAAe,CAAC;IACzB,CAAC;CACF;AAED,OAAO,EAAE,SAAS,EAAE,CAAC"}
@@ -86,6 +86,18 @@ export declare class User extends UuidModel {
86
86
  * @returns the result string
87
87
  */
88
88
  getDisplayName(): string;
89
+ /**
90
+ * Store filter matching {@link User.canAct}: a caller only finds its own user, so users cannot be enumerated
91
+ *
92
+ * Subclasses inherit this filter even when they override `canAct` (it fails closed: it can only hide rows). A
93
+ * subclass whose `canAct` is more permissive overrides this method (returning `null` disables the store filter).
94
+ * @param context - the caller context
95
+ * @returns the permission query
96
+ */
97
+ static getPermissionQuery(context?: IOperationContext): null | {
98
+ partial: boolean;
99
+ query: string;
100
+ };
89
101
  /**
90
102
  * Only the user themselves can act on their own object
91
103
  * @param ctx - the operation context
@@ -1 +1 @@
1
- {"version":3,"file":"user.model.d.ts","sourceRoot":"","sources":["../../src/models/user.model.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAsB,MAAM,qBAAqB,CAAC;AACnE,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,WAAW,EAAE,KAAK,QAAQ,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE1G,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI,WAAW,CAAC,CAAC,CAAC,GAAG;IAC3C,KAAK,EAAE;QAAE,IAAI,EAAE,CAAC,CAAA;KAAE,CAAC;IACnB,MAAM,EAAE;QAAE,IAAI,EAAE,CAAC,CAAA;KAAE,CAAC;CACrB,CAAC;AACF;;;;GAIG;AACH,qBAAa,IAAK,SAAQ,SAAS;IACjC,CAAC,YAAY,CAAC,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC;IACjC;;OAEG;IACH,YAAY,IAAI,CAAC,EAAE,QAAQ,CAAC,IAAI,CAAC,EAShC;IAED;;OAEG;IACH,QAAQ,CAAC,EAAE,QAAQ,CAAC;IAEpB;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,KAAK;IASpB;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,MAAM;IASrB;;;;;OAKG;IACH,MAAM,CAAC,WAAW,CAAC,CAAC,SAAS,UAAU,EAAE,CAAC,SAAS,MAAM,GAAG,YAAY,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,CAKhH;IACD;;;;OAIG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;;OAIG;IACH,aAAa,IAAI,GAAG,CAOnB;IAED;;;OAGG;IACH,QAAQ,IAAI,MAAM,GAAG,SAAS,CAE7B;IAED;;;OAGG;IACH,SAAS,IAAI,MAAM,EAAE,CAEpB;IAED;;;OAGG;IACH,QAAQ,IAAI,MAAM,EAAE,CAEnB;IAED;;;OAGG;IACH,cAAc,IAAI,MAAM,CAEvB;IAED;;;;;OAKG;IACG,MAAM,CAAC,GAAG,EAAE,iBAAiB,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,OAAO,CAAC,CAK9E;IAED;;;OAGG;IACH,QAAQ,WAEP;IACD,SAAS,CAAC,kBAAkB,CAAC,OAAO,CAAC,EAAE,GAAG,GAAG,IAAI,CAiBhD;CACF"}
1
+ {"version":3,"file":"user.model.d.ts","sourceRoot":"","sources":["../../src/models/user.model.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAE5D,OAAO,EAAE,QAAQ,EAAsB,MAAM,qBAAqB,CAAC;AACnE,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,WAAW,EAAE,KAAK,QAAQ,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE1G,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI,WAAW,CAAC,CAAC,CAAC,GAAG;IAC3C,KAAK,EAAE;QAAE,IAAI,EAAE,CAAC,CAAA;KAAE,CAAC;IACnB,MAAM,EAAE;QAAE,IAAI,EAAE,CAAC,CAAA;KAAE,CAAC;CACrB,CAAC;AACF;;;;GAIG;AACH,qBAAa,IAAK,SAAQ,SAAS;IACjC,CAAC,YAAY,CAAC,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC;IACjC;;OAEG;IACH,YAAY,IAAI,CAAC,EAAE,QAAQ,CAAC,IAAI,CAAC,EAShC;IAED;;OAEG;IACH,QAAQ,CAAC,EAAE,QAAQ,CAAC;IAEpB;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,KAAK;IASpB;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,MAAM;IASrB;;;;;OAKG;IACH,MAAM,CAAC,WAAW,CAAC,CAAC,SAAS,UAAU,EAAE,CAAC,SAAS,MAAM,GAAG,YAAY,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,CAKhH;IACD;;;;OAIG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;;OAIG;IACH,aAAa,IAAI,GAAG,CAOnB;IAED;;;OAGG;IACH,QAAQ,IAAI,MAAM,GAAG,SAAS,CAE7B;IAED;;;OAGG;IACH,SAAS,IAAI,MAAM,EAAE,CAEpB;IAED;;;OAGG;IACH,QAAQ,IAAI,MAAM,EAAE,CAEnB;IAED;;;OAGG;IACH,cAAc,IAAI,MAAM,CAEvB;IAED;;;;;;;OAOG;IACH,MAAM,CAAC,kBAAkB,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,IAAI,GAAG;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAMjG;IAED;;;;;OAKG;IACG,MAAM,CAAC,GAAG,EAAE,iBAAiB,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,OAAO,CAAC,CAK9E;IAED;;;OAGG;IACH,QAAQ,WAEP;IACD,SAAS,CAAC,kBAAkB,CAAC,OAAO,CAAC,EAAE,GAAG,GAAG,IAAI,CAiBhD;CACF"}
@@ -1,4 +1,5 @@
1
1
  import { WEBDA_STORAGE } from "@webda/models";
2
+ import { bind } from "@webda/ql";
2
3
  import { Password, V3_PASSWORD_MAPPED } from "./password.model.js";
3
4
  import { UuidModel, WEBDA_EVENTS } from "@webda/models";
4
5
  /**
@@ -123,6 +124,21 @@ export class User extends UuidModel {
123
124
  getDisplayName() {
124
125
  return this.displayName;
125
126
  }
127
+ /**
128
+ * Store filter matching {@link User.canAct}: a caller only finds its own user, so users cannot be enumerated
129
+ *
130
+ * Subclasses inherit this filter even when they override `canAct` (it fails closed: it can only hide rows). A
131
+ * subclass whose `canAct` is more permissive overrides this method (returning `null` disables the store filter).
132
+ * @param context - the caller context
133
+ * @returns the permission query
134
+ */
135
+ static getPermissionQuery(context) {
136
+ if (!context) {
137
+ return null;
138
+ }
139
+ const userId = context.getCurrentUserId();
140
+ return { query: userId ? bind("uuid = ?", [userId]) : "FALSE", partial: false };
141
+ }
126
142
  /**
127
143
  * Only the user themselves can act on their own object
128
144
  * @param ctx - the operation context
@@ -1 +1 @@
1
- {"version":3,"file":"user.model.js","sourceRoot":"","sources":["../../src/models/user.model.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"user.model.js","sourceRoot":"","sources":["../../src/models/user.model.ts"],"names":[],"mappings":"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"}