@enbox/dwn-sdk-js 0.4.17 → 0.4.18

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 (77) hide show
  1. package/dist/browser.mjs +1 -1
  2. package/dist/browser.mjs.map +4 -4
  3. package/dist/esm/generated/precompiled-validators.js +349 -198
  4. package/dist/esm/generated/precompiled-validators.js.map +1 -1
  5. package/dist/esm/src/handlers/records-collection.js +200 -0
  6. package/dist/esm/src/handlers/records-collection.js.map +1 -0
  7. package/dist/esm/src/handlers/records-count.js +19 -196
  8. package/dist/esm/src/handlers/records-count.js.map +1 -1
  9. package/dist/esm/src/handlers/records-query.js +19 -376
  10. package/dist/esm/src/handlers/records-query.js.map +1 -1
  11. package/dist/esm/src/handlers/records-subscribe.js +21 -341
  12. package/dist/esm/src/handlers/records-subscribe.js.map +1 -1
  13. package/dist/esm/src/interfaces/records-count.js +1 -1
  14. package/dist/esm/src/interfaces/records-count.js.map +1 -1
  15. package/dist/esm/src/interfaces/records-query.js +1 -1
  16. package/dist/esm/src/interfaces/records-query.js.map +1 -1
  17. package/dist/esm/src/interfaces/records-subscribe.js +3 -1
  18. package/dist/esm/src/interfaces/records-subscribe.js.map +1 -1
  19. package/dist/esm/src/store/index-level.js +84 -32
  20. package/dist/esm/src/store/index-level.js.map +1 -1
  21. package/dist/esm/src/store/message-store-level.js +45 -11
  22. package/dist/esm/src/store/message-store-level.js.map +1 -1
  23. package/dist/esm/src/utils/record-limit-occupancy.js +5 -2
  24. package/dist/esm/src/utils/record-limit-occupancy.js.map +1 -1
  25. package/dist/esm/src/utils/records.js +14 -47
  26. package/dist/esm/src/utils/records.js.map +1 -1
  27. package/dist/esm/tests/features/records-nested-query-scope.spec.js +15 -1
  28. package/dist/esm/tests/features/records-nested-query-scope.spec.js.map +1 -1
  29. package/dist/esm/tests/features/records-record-limit.spec.js +116 -0
  30. package/dist/esm/tests/features/records-record-limit.spec.js.map +1 -1
  31. package/dist/esm/tests/handlers/records-count.spec.js +52 -1
  32. package/dist/esm/tests/handlers/records-count.spec.js.map +1 -1
  33. package/dist/esm/tests/handlers/records-subscribe.spec.js +76 -1
  34. package/dist/esm/tests/handlers/records-subscribe.spec.js.map +1 -1
  35. package/dist/esm/tests/store/index-level.spec.js +95 -1
  36. package/dist/esm/tests/store/index-level.spec.js.map +1 -1
  37. package/dist/esm/tests/store/message-store-level.spec.js +70 -1
  38. package/dist/esm/tests/store/message-store-level.spec.js.map +1 -1
  39. package/dist/types/generated/precompiled-validators.d.ts.map +1 -1
  40. package/dist/types/src/handlers/records-collection.d.ts +32 -0
  41. package/dist/types/src/handlers/records-collection.d.ts.map +1 -0
  42. package/dist/types/src/handlers/records-count.d.ts +0 -35
  43. package/dist/types/src/handlers/records-count.d.ts.map +1 -1
  44. package/dist/types/src/handlers/records-query.d.ts +0 -61
  45. package/dist/types/src/handlers/records-query.d.ts.map +1 -1
  46. package/dist/types/src/handlers/records-subscribe.d.ts +1 -37
  47. package/dist/types/src/handlers/records-subscribe.d.ts.map +1 -1
  48. package/dist/types/src/interfaces/records-subscribe.d.ts.map +1 -1
  49. package/dist/types/src/store/index-level.d.ts +27 -3
  50. package/dist/types/src/store/index-level.d.ts.map +1 -1
  51. package/dist/types/src/store/message-store-level.d.ts +1 -0
  52. package/dist/types/src/store/message-store-level.d.ts.map +1 -1
  53. package/dist/types/src/types/message-store.d.ts +6 -1
  54. package/dist/types/src/types/message-store.d.ts.map +1 -1
  55. package/dist/types/src/types/records-types.d.ts +1 -1
  56. package/dist/types/src/types/records-types.d.ts.map +1 -1
  57. package/dist/types/src/utils/record-limit-occupancy.d.ts.map +1 -1
  58. package/dist/types/src/utils/records.d.ts +6 -25
  59. package/dist/types/src/utils/records.d.ts.map +1 -1
  60. package/dist/types/tests/features/records-nested-query-scope.spec.d.ts.map +1 -1
  61. package/dist/types/tests/features/records-record-limit.spec.d.ts.map +1 -1
  62. package/dist/types/tests/handlers/records-count.spec.d.ts.map +1 -1
  63. package/dist/types/tests/handlers/records-subscribe.spec.d.ts.map +1 -1
  64. package/package.json +1 -1
  65. package/src/handlers/records-collection.ts +269 -0
  66. package/src/handlers/records-count.ts +21 -236
  67. package/src/handlers/records-query.ts +22 -447
  68. package/src/handlers/records-subscribe.ts +26 -404
  69. package/src/interfaces/records-count.ts +1 -1
  70. package/src/interfaces/records-query.ts +1 -1
  71. package/src/interfaces/records-subscribe.ts +5 -2
  72. package/src/store/index-level.ts +145 -37
  73. package/src/store/message-store-level.ts +46 -11
  74. package/src/types/message-store.ts +6 -1
  75. package/src/types/records-types.ts +1 -1
  76. package/src/utils/record-limit-occupancy.ts +5 -2
  77. package/src/utils/records.ts +17 -52
@@ -1,30 +1,11 @@
1
- import type { Filter, PaginationCursor } from '../types/query-types.js';
2
- import type { GenericMessage, MessageSort } from '../types/message-types.js';
1
+ import type { RecordsCollectionVisibility } from './records-collection.js';
3
2
  import type { HandlerDependencies, MethodHandler } from '../types/method-handler.js';
4
- import type { RecordsQueryMessage, RecordsQueryReply, RecordsQueryReplyEntry } from '../types/records-types.js';
3
+ import type { RecordsQueryMessage, RecordsQueryReply } from '../types/records-types.js';
5
4
 
6
5
  import { attachInitialWrites } from '../utils/initial-write-attachment.js';
7
- import { authenticate } from '../core/auth.js';
8
- import { DateSort } from '../types/records-types.js';
9
- import { EncryptionControl } from '../core/encryption-control.js';
10
- import { Message } from '../core/message.js';
11
6
  import { messageReplyFromError } from '../core/message-reply.js';
12
- import { ProtocolAuthorization } from '../core/protocol-authorization.js';
13
- import { Records } from '../utils/records.js';
14
- import { RecordsGrantAuthorization } from '../core/records-grant-authorization.js';
15
7
  import { RecordsQuery } from '../interfaces/records-query.js';
16
- import { SortDirection } from '../types/query-types.js';
17
- import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
18
- import { queryRecordsWithRecordLimitOccupancy, resolveRecordLimitOccupancy } from '../utils/record-limit-occupancy.js';
19
-
20
- type RecordsQueryProjectionInput = {
21
- tenant: string;
22
- recordsQuery: RecordsQuery;
23
- requester: string | undefined;
24
- filters: Filter[];
25
- messageSort: MessageSort;
26
- pagination?: { cursor?: PaginationCursor; limit?: number };
27
- };
8
+ import { queryVisibleRecordsPage, resolveRecordsCollectionVisibility } from './records-collection.js';
28
9
 
29
10
  export class RecordsQueryHandler implements MethodHandler {
30
11
 
@@ -37,442 +18,36 @@ export class RecordsQueryHandler implements MethodHandler {
37
18
  let recordsQuery: RecordsQuery;
38
19
  try {
39
20
  recordsQuery = await RecordsQuery.parse(message);
40
- } catch (e) {
41
- return messageReplyFromError(e, 400);
42
- }
43
-
44
- let recordsWrites: RecordsQueryReplyEntry[];
45
- let cursor: PaginationCursor | undefined;
46
- const requester = Message.getRequester(recordsQuery.message);
47
- // if this is an anonymous query and the filter supports published records, query only published records
48
- if (Records.filterIncludesPublishedRecords(recordsQuery.message.descriptor.filter) && recordsQuery.author === undefined) {
49
- const results = await this.fetchPublishedRecords(tenant, recordsQuery, requester);
50
- recordsWrites = results.messages as RecordsQueryReplyEntry[];
51
- cursor = results.cursor;
52
- } else {
53
- // authentication and authorization
54
- try {
55
- await authenticate(message.authorization!, this.deps.didResolver);
56
-
57
- await RecordsQueryHandler.authorizeRecordsQuery(tenant, recordsQuery, this.deps);
58
- } catch (e) {
59
- return messageReplyFromError(e, 401);
60
- }
61
-
62
- if (recordsQuery.author === tenant) {
63
- const results = requester === tenant
64
- ? await this.fetchRecordsAsOwner(tenant, recordsQuery)
65
- : await this.fetchRecordsAsOwnerDelegate(tenant, recordsQuery, requester);
66
- recordsWrites = results.messages as RecordsQueryReplyEntry[];
67
- cursor = results.cursor;
68
- } else {
69
- const results = await this.fetchRecordsAsNonOwner(tenant, recordsQuery, requester);
70
- recordsWrites = results.messages as RecordsQueryReplyEntry[];
71
- cursor = results.cursor;
72
- }
73
- }
74
-
75
- // attach the retained initial write to every entry that is not itself an initial write
76
- const completeRecordsWrites = await attachInitialWrites({
77
- messageStore : this.deps.messageStore,
78
- tenant,
79
- recordsWrites,
80
- operationName : 'RecordsQuery',
81
- });
82
-
83
- return {
84
- status : { code: 200, detail: 'OK' },
85
- entries : completeRecordsWrites,
86
- cursor
87
- };
88
- }
89
-
90
- /**
91
- * Convert an incoming DateSort to a sort type accepted by MessageStore
92
- * Defaults to 'dateCreated' in Descending order if no sort is supplied.
93
- *
94
- * @param dateSort the optional DateSort from the RecordsQuery message descriptor.
95
- * @returns {MessageSort} for MessageStore sorting.
96
- */
97
- private convertDateSort(dateSort?: DateSort): MessageSort {
98
- switch (dateSort) {
99
- case DateSort.CreatedAscending:
100
- return { dateCreated: SortDirection.Ascending };
101
- case DateSort.CreatedDescending:
102
- return { dateCreated: SortDirection.Descending };
103
- case DateSort.PublishedAscending:
104
- return { datePublished: SortDirection.Ascending };
105
- case DateSort.PublishedDescending:
106
- return { datePublished: SortDirection.Descending };
107
- case DateSort.UpdatedAscending:
108
- return { messageTimestamp: SortDirection.Ascending };
109
- case DateSort.UpdatedDescending:
110
- return { messageTimestamp: SortDirection.Descending };
111
- default:
112
- return { dateCreated: SortDirection.Ascending };
21
+ } catch (error) {
22
+ return messageReplyFromError(error, 400);
113
23
  }
114
- }
115
24
 
116
- /**
117
- * Fetches the records as the owner of the DWN with no additional filtering.
118
- */
119
- private async fetchRecordsAsOwner(
120
- tenant: string,
121
- recordsQuery: RecordsQuery
122
- ): Promise<{ messages: GenericMessage[], cursor?: PaginationCursor }> {
123
- const { dateSort, filter, pagination } = recordsQuery.message.descriptor;
124
- // fetch all published records matching the query
125
- const queryFilter = {
126
- ...Records.convertFilter(filter, dateSort),
127
- interface : DwnInterfaceName.Records,
128
- method : DwnMethodName.Write,
129
- isLatestBaseState : true
130
- };
131
-
132
- const messageSort = this.convertDateSort(dateSort);
133
- return this.queryRecordsWithVisibleControlFiltering({
134
- tenant,
135
- recordsQuery,
136
- requester : tenant,
137
- filters : [queryFilter],
138
- messageSort,
139
- pagination,
140
- });
141
- }
142
-
143
- private async fetchRecordsAsOwnerDelegate(
144
- tenant: string,
145
- recordsQuery: RecordsQuery,
146
- requester: string | undefined,
147
- ): Promise<{ messages: GenericMessage[], cursor?: PaginationCursor }> {
148
- const { dateSort, filter, pagination } = recordsQuery.message.descriptor;
149
- const queryFilter = {
150
- ...Records.convertFilter(filter, dateSort),
151
- interface : DwnInterfaceName.Records,
152
- method : DwnMethodName.Write,
153
- isLatestBaseState : true
154
- };
155
-
156
- const messageSort = this.convertDateSort(dateSort);
157
- return this.queryRecordsWithVisibleControlFiltering({
158
- tenant,
159
- recordsQuery,
160
- requester,
161
- filters: [queryFilter],
162
- messageSort,
163
- pagination,
164
- });
165
- }
166
-
167
- /**
168
- * Fetches the records as a non-owner.
169
- *
170
- * Filters can support returning both published and unpublished records,
171
- * as well as explicitly only published or only unpublished records.
172
- *
173
- * A) BOTH published and unpublished:
174
- * 1. published records; and
175
- * 2. unpublished records intended for the query author (where `recipient` is the query author); and
176
- * 3. unpublished records authorized by a protocol rule.
177
- *
178
- * B) PUBLISHED:
179
- * 1. only published records;
180
- *
181
- * C) UNPUBLISHED:
182
- * 1. unpublished records intended for the query author (where `recipient` is the query author); and
183
- * 2. unpublished records authorized by a protocol rule.
184
- *
185
- */
186
- private async fetchRecordsAsNonOwner(
187
- tenant: string,
188
- recordsQuery: RecordsQuery,
189
- requester: string | undefined,
190
- ): Promise<{ messages: GenericMessage[], cursor?: PaginationCursor }> {
191
- const { dateSort, pagination, filter } = recordsQuery.message.descriptor;
192
- const filters = [];
193
- if (Records.filterIncludesPublishedRecords(filter)) {
194
- filters.push(RecordsQueryHandler.buildPublishedRecordsFilter(recordsQuery));
195
- }
196
-
197
- if (Records.filterIncludesUnpublishedRecords(filter)) {
198
- if (EncryptionControl.isExactAudienceFilter(filter)) {
199
- filters.push(Records.buildUnpublishedControlRecordsFilter(filter, dateSort));
200
- }
201
-
202
- if (Records.shouldBuildUnpublishedAuthorFilter(filter, recordsQuery.author!)) {
203
- filters.push(RecordsQueryHandler.buildUnpublishedRecordsByQueryAuthorFilter(recordsQuery));
204
- }
205
-
206
- if (Records.shouldProtocolAuthorize(recordsQuery.signaturePayload!)) {
207
- filters.push(RecordsQueryHandler.buildUnpublishedProtocolAuthorizedRecordsFilter(recordsQuery));
208
- }
209
-
210
- if (Message.getPermissionGrantId(recordsQuery.signaturePayload!) !== undefined) {
211
- filters.push(RecordsQueryHandler.buildUnpublishedPermissionGrantAuthorizedRecordsFilter(recordsQuery));
212
- }
213
-
214
- if (Records.shouldBuildUnpublishedRecipientFilter(filter, recordsQuery.author!)) {
215
- filters.push(RecordsQueryHandler.buildUnpublishedRecordsForQueryAuthorFilter(recordsQuery));
216
- }
25
+ let visibility: RecordsCollectionVisibility;
26
+ try {
27
+ visibility = await resolveRecordsCollectionVisibility(tenant, recordsQuery, this.deps);
28
+ } catch (error) {
29
+ return messageReplyFromError(error, 401);
217
30
  }
218
31
 
219
- const messageSort = this.convertDateSort(dateSort);
220
- return this.queryRecordsWithVisibleControlFiltering({
32
+ const result = await queryVisibleRecordsPage({
33
+ deps : this.deps,
221
34
  tenant,
222
- recordsQuery,
223
- requester,
224
- filters,
225
- messageSort,
226
- pagination,
35
+ request : recordsQuery,
36
+ visibility,
227
37
  });
228
- }
229
38
 
230
- /**
231
- * Fetches only published records.
232
- */
233
- private async fetchPublishedRecords(
234
- tenant: string,
235
- recordsQuery: RecordsQuery,
236
- requester: string | undefined,
237
- ): Promise<{ messages: GenericMessage[], cursor?: PaginationCursor }> {
238
- const { dateSort, pagination } = recordsQuery.message.descriptor;
239
- const filter = RecordsQueryHandler.buildPublishedRecordsFilter(recordsQuery);
240
- const messageSort = this.convertDateSort(dateSort);
241
- return this.queryRecordsWithVisibleControlFiltering({
242
- tenant,
243
- recordsQuery,
244
- requester,
245
- filters: [filter],
246
- messageSort,
247
- pagination,
248
- });
249
- }
250
-
251
- private async queryRecordsWithVisibleControlFiltering(
252
- input: RecordsQueryProjectionInput
253
- ): Promise<{ messages: RecordsQueryReplyEntry[], cursor?: PaginationCursor }> {
254
- const {
255
- tenant, recordsQuery, requester, filters, messageSort, pagination
256
- } = input;
257
- const recordLimit = await resolveRecordLimitOccupancy({
258
- validationStateReader : this.deps.validationStateReader,
39
+ // Attach the retained initial write to every entry that is not itself an initial write.
40
+ const entries = await attachInitialWrites({
41
+ messageStore : this.deps.messageStore,
259
42
  tenant,
260
- recordsFilter : recordsQuery.message.descriptor.filter,
261
- messageTimestamp : recordsQuery.message.descriptor.messageTimestamp,
43
+ recordsWrites : result.messages,
44
+ operationName : 'RecordsQuery',
262
45
  });
263
- const controlFilters = Records.buildControlRecordsFilters(filters);
264
- const currentAudienceRecordIdCache = new Map<string, string | undefined>();
265
- if (controlFilters.length === 0) {
266
- const result = await queryRecordsWithRecordLimitOccupancy({
267
- messageStore: this.deps.messageStore,
268
- tenant,
269
- filters,
270
- recordLimit,
271
- messageSort,
272
- pagination,
273
- });
274
- return EncryptionControl.projectCurrentAudienceRecordPage({
275
- messageStore : this.deps.messageStore,
276
- tenant,
277
- filters,
278
- currentAudienceRecordIdCache,
279
- result : {
280
- messages : result.messages as RecordsQueryReplyEntry[],
281
- cursor : result.cursor,
282
- },
283
- });
284
- }
285
-
286
- if (pagination?.limit === undefined || pagination.limit <= 0) {
287
- const result = await queryRecordsWithRecordLimitOccupancy({
288
- messageStore: this.deps.messageStore,
289
- tenant,
290
- filters,
291
- recordLimit,
292
- messageSort,
293
- pagination,
294
- });
295
- const projectedResult = await EncryptionControl.projectCurrentAudienceRecordPage({
296
- messageStore : this.deps.messageStore,
297
- tenant,
298
- filters,
299
- currentAudienceRecordIdCache,
300
- result : {
301
- messages : result.messages as RecordsQueryReplyEntry[],
302
- cursor : result.cursor,
303
- },
304
- });
305
- return {
306
- messages : await this.filterControlRecordsForRequester(tenant, recordsQuery, requester, projectedResult.messages),
307
- cursor : projectedResult.cursor,
308
- };
309
- }
310
-
311
- const visibleMessages: RecordsQueryReplyEntry[] = [];
312
- let cursor = pagination.cursor;
313
- let nextCursor: PaginationCursor | undefined;
314
- // Keeps visible-page pagination stable until #1100 moves control visibility into indexed store filters.
315
- do {
316
- const remainingLimit = pagination.limit - visibleMessages.length;
317
- const result = await queryRecordsWithRecordLimitOccupancy({
318
- messageStore : this.deps.messageStore,
319
- tenant,
320
- filters,
321
- recordLimit,
322
- messageSort,
323
- pagination : { ...pagination, cursor, limit: remainingLimit },
324
- });
325
- const projectedResult = await EncryptionControl.projectCurrentAudienceRecordPage({
326
- messageStore : this.deps.messageStore,
327
- tenant,
328
- filters,
329
- currentAudienceRecordIdCache,
330
- result : {
331
- messages : result.messages as RecordsQueryReplyEntry[],
332
- cursor : result.cursor,
333
- },
334
- });
335
- const filteredMessages = await this.filterControlRecordsForRequester(
336
- tenant,
337
- recordsQuery,
338
- requester,
339
- projectedResult.messages,
340
- );
341
- visibleMessages.push(...filteredMessages);
342
- nextCursor = projectedResult.cursor;
343
- cursor = projectedResult.cursor;
344
- } while (visibleMessages.length < pagination.limit && cursor !== undefined);
345
-
346
- return { messages: visibleMessages, cursor: nextCursor };
347
- }
348
-
349
- private static buildPublishedRecordsFilter(recordsQuery: RecordsQuery): Filter {
350
- const { dateSort, filter } = recordsQuery.message.descriptor;
351
- // fetch all published records matching the query
352
- return {
353
- ...Records.convertFilter(filter, dateSort),
354
- interface : DwnInterfaceName.Records,
355
- method : DwnMethodName.Write,
356
- published : true,
357
- isLatestBaseState : true
358
- };
359
- }
360
-
361
- /**
362
- * Creates a filter for unpublished records that are intended for the query author (where `recipient` is the author).
363
- */
364
- private static buildUnpublishedRecordsForQueryAuthorFilter(recordsQuery: RecordsQuery): Filter {
365
- const { dateSort, filter } = recordsQuery.message.descriptor;
366
- // include records where recipient is query author
367
- return {
368
- ...Records.convertFilter(filter, dateSort),
369
- interface : DwnInterfaceName.Records,
370
- method : DwnMethodName.Write,
371
- recipient : recordsQuery.author!,
372
- isLatestBaseState : true,
373
- published : false
374
- };
375
- }
376
-
377
- /**
378
- * Creates a filter for unpublished records that are within the specified protocol.
379
- * Validation that `protocol` and other required protocol-related fields occurs before this method.
380
- */
381
- private static buildUnpublishedProtocolAuthorizedRecordsFilter(recordsQuery: RecordsQuery): Filter {
382
- const { dateSort, filter } = recordsQuery.message.descriptor;
383
- return {
384
- ...Records.convertFilter(filter, dateSort),
385
- interface : DwnInterfaceName.Records,
386
- method : DwnMethodName.Write,
387
- isLatestBaseState : true,
388
- published : false
389
- };
390
- }
391
-
392
- /**
393
- * Creates a filter for unpublished records authorized by a permission grant.
394
- */
395
- private static buildUnpublishedPermissionGrantAuthorizedRecordsFilter(recordsQuery: RecordsQuery): Filter {
396
- const { dateSort, filter } = recordsQuery.message.descriptor;
397
- return {
398
- ...Records.convertFilter(filter, dateSort),
399
- interface : DwnInterfaceName.Records,
400
- method : DwnMethodName.Write,
401
- isLatestBaseState : true,
402
- published : false
403
- };
404
- }
405
46
 
406
- /**
407
- * Creates a filter for only unpublished records where the author is the same as the query author.
408
- */
409
- private static buildUnpublishedRecordsByQueryAuthorFilter(recordsQuery: RecordsQuery): Filter {
410
- const { dateSort, filter } = recordsQuery.message.descriptor;
411
- // include records where author is the same as the query author
412
47
  return {
413
- ...Records.convertFilter(filter, dateSort),
414
- author : recordsQuery.author!,
415
- interface : DwnInterfaceName.Records,
416
- method : DwnMethodName.Write,
417
- isLatestBaseState : true,
418
- published : false
48
+ status : { code: 200, detail: 'OK' },
49
+ entries,
50
+ cursor : result.cursor,
419
51
  };
420
52
  }
421
-
422
- /**
423
- * @param messageStore Used to check if the grant has been revoked.
424
- */
425
- private static async authorizeRecordsQuery(
426
- tenant: string,
427
- recordsQuery: RecordsQuery,
428
- deps: HandlerDependencies,
429
- ): Promise<void> {
430
-
431
- if (Message.isSignedByAuthorDelegate(recordsQuery.message) &&
432
- !EncryptionControl.filterTargetsOnlyControlRecords(recordsQuery.message.descriptor.filter)) {
433
- await recordsQuery.authorizeDelegate(deps.validationStateReader);
434
- } else if (EncryptionControl.filterTargetsOnlyControlRecords(recordsQuery.message.descriptor.filter)) {
435
- await EncryptionControl.authorizeControlReadRequest({
436
- tenant,
437
- incomingMessage : recordsQuery.message,
438
- requester : Message.getRequester(recordsQuery.message),
439
- validationStateReader : deps.validationStateReader,
440
- });
441
- }
442
-
443
- const permissionGrantId = Message.getPermissionGrantId(recordsQuery.signaturePayload!);
444
- if (permissionGrantId !== undefined) {
445
- const permissionGrant = await deps.validationStateReader.fetchGrant(tenant, permissionGrantId);
446
- await RecordsGrantAuthorization.authorizeQueryOrSubscribe({
447
- incomingMessage : recordsQuery.message,
448
- expectedGrantor : tenant,
449
- expectedGrantee : recordsQuery.author!,
450
- permissionGrant,
451
- validationStateReader : deps.validationStateReader,
452
- });
453
- return;
454
- }
455
-
456
- // NOTE: not all RecordsQuery messages require protocol authorization even if the filter includes protocol-related fields,
457
- // this is because we dynamically filter out records that the caller is not authorized to see.
458
- // Currently only run protocol authorization if message deliberately invokes a protocol role.
459
- if (Records.shouldProtocolAuthorize(recordsQuery.signaturePayload!)) {
460
- await ProtocolAuthorization.authorizeQueryOrSubscribe(tenant, recordsQuery, deps.validationStateReader);
461
- }
462
- }
463
-
464
- private async filterControlRecordsForRequester(
465
- tenant: string,
466
- recordsQuery: RecordsQuery,
467
- requester: string | undefined,
468
- recordsWrites: RecordsQueryReplyEntry[],
469
- ): Promise<RecordsQueryReplyEntry[]> {
470
- return EncryptionControl.filterVisibleControlRecords({
471
- tenant,
472
- incomingMessage : recordsQuery.message,
473
- requester,
474
- recordsWriteMessages : recordsWrites,
475
- validationStateReader : this.deps.validationStateReader,
476
- });
477
- }
478
53
  }