@enbox/dwn-sdk-js 0.4.3 → 0.4.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 (204) hide show
  1. package/dist/browser.mjs +15 -15
  2. package/dist/browser.mjs.map +4 -4
  3. package/dist/esm/generated/precompiled-validators.js +5406 -2200
  4. package/dist/esm/generated/precompiled-validators.js.map +1 -1
  5. package/dist/esm/json-schemas/definitions.json +18 -0
  6. package/dist/esm/src/core/constants.js +3 -3
  7. package/dist/esm/src/core/constants.js.map +1 -1
  8. package/dist/esm/src/core/dwn-error.js +29 -1
  9. package/dist/esm/src/core/dwn-error.js.map +1 -1
  10. package/dist/esm/src/core/messages-grant-authorization.js +20 -0
  11. package/dist/esm/src/core/messages-grant-authorization.js.map +1 -1
  12. package/dist/esm/src/core/protocol-authorization-validation.js +80 -3
  13. package/dist/esm/src/core/protocol-authorization-validation.js.map +1 -1
  14. package/dist/esm/src/core/recording-validation-state-reader.js +5 -0
  15. package/dist/esm/src/core/recording-validation-state-reader.js.map +1 -1
  16. package/dist/esm/src/core/replication-apply.js +163 -7
  17. package/dist/esm/src/core/replication-apply.js.map +1 -1
  18. package/dist/esm/src/core/validation-state-reader.js +20 -0
  19. package/dist/esm/src/core/validation-state-reader.js.map +1 -1
  20. package/dist/esm/src/dwn.js +19 -2
  21. package/dist/esm/src/dwn.js.map +1 -1
  22. package/dist/esm/src/handlers/messages-query.js +3 -5
  23. package/dist/esm/src/handlers/messages-query.js.map +1 -1
  24. package/dist/esm/src/handlers/protocols-configure.js +10 -4
  25. package/dist/esm/src/handlers/protocols-configure.js.map +1 -1
  26. package/dist/esm/src/handlers/records-write.js +1 -1
  27. package/dist/esm/src/handlers/records-write.js.map +1 -1
  28. package/dist/esm/src/index.js +2 -1
  29. package/dist/esm/src/index.js.map +1 -1
  30. package/dist/esm/src/interfaces/protocols-configure.js +23 -10
  31. package/dist/esm/src/interfaces/protocols-configure.js.map +1 -1
  32. package/dist/esm/src/interfaces/records-write-signing.js +2 -8
  33. package/dist/esm/src/interfaces/records-write-signing.js.map +1 -1
  34. package/dist/esm/src/interfaces/records-write.js +43 -65
  35. package/dist/esm/src/interfaces/records-write.js.map +1 -1
  36. package/dist/esm/src/protocols/encryption.js +411 -0
  37. package/dist/esm/src/protocols/encryption.js.map +1 -0
  38. package/dist/esm/src/protocols/permission-grant.js +3 -3
  39. package/dist/esm/src/protocols/permission-grant.js.map +1 -1
  40. package/dist/esm/src/protocols/permissions.js +1 -0
  41. package/dist/esm/src/protocols/permissions.js.map +1 -1
  42. package/dist/esm/src/types/message-types.js.map +1 -1
  43. package/dist/esm/src/types/permission-types.js.map +1 -1
  44. package/dist/esm/src/types/protocols-types.js.map +1 -1
  45. package/dist/esm/src/utils/encryption.js +135 -187
  46. package/dist/esm/src/utils/encryption.js.map +1 -1
  47. package/dist/esm/src/utils/hd-key.js +0 -1
  48. package/dist/esm/src/utils/hd-key.js.map +1 -1
  49. package/dist/esm/src/utils/permission-scope.js +9 -6
  50. package/dist/esm/src/utils/permission-scope.js.map +1 -1
  51. package/dist/esm/src/utils/protocols.js +12 -9
  52. package/dist/esm/src/utils/protocols.js.map +1 -1
  53. package/dist/esm/src/utils/records.js +54 -56
  54. package/dist/esm/src/utils/records.js.map +1 -1
  55. package/dist/esm/src/utils/replication.js +27 -4
  56. package/dist/esm/src/utils/replication.js.map +1 -1
  57. package/dist/esm/tests/core/replication-apply.spec.js +141 -1
  58. package/dist/esm/tests/core/replication-apply.spec.js.map +1 -1
  59. package/dist/esm/tests/core/replication-replay-property.spec.js +1 -0
  60. package/dist/esm/tests/core/replication-replay-property.spec.js.map +1 -1
  61. package/dist/esm/tests/core/validation-read-closure.spec.js +111 -0
  62. package/dist/esm/tests/core/validation-read-closure.spec.js.map +1 -1
  63. package/dist/esm/tests/core/validation-state-reader.spec.js +89 -0
  64. package/dist/esm/tests/core/validation-state-reader.spec.js.map +1 -1
  65. package/dist/esm/tests/features/protocol-composition.spec.js +30 -31
  66. package/dist/esm/tests/features/protocol-composition.spec.js.map +1 -1
  67. package/dist/esm/tests/fuzz/encryption.fuzz.spec.js +29 -121
  68. package/dist/esm/tests/fuzz/encryption.fuzz.spec.js.map +1 -1
  69. package/dist/esm/tests/handlers/messages-query.spec.js +71 -3
  70. package/dist/esm/tests/handlers/messages-query.spec.js.map +1 -1
  71. package/dist/esm/tests/handlers/messages-read.spec.js +2 -2
  72. package/dist/esm/tests/handlers/messages-read.spec.js.map +1 -1
  73. package/dist/esm/tests/handlers/records-read.spec.js +9 -135
  74. package/dist/esm/tests/handlers/records-read.spec.js.map +1 -1
  75. package/dist/esm/tests/handlers/records-write.spec.js +279 -19
  76. package/dist/esm/tests/handlers/records-write.spec.js.map +1 -1
  77. package/dist/esm/tests/interfaces/protocols-configure.spec.js +17 -22
  78. package/dist/esm/tests/interfaces/protocols-configure.spec.js.map +1 -1
  79. package/dist/esm/tests/interfaces/records-write.spec.js +170 -150
  80. package/dist/esm/tests/interfaces/records-write.spec.js.map +1 -1
  81. package/dist/esm/tests/protocols/encryption.spec.js +914 -0
  82. package/dist/esm/tests/protocols/encryption.spec.js.map +1 -0
  83. package/dist/esm/tests/protocols/permission-grant.spec.js +55 -0
  84. package/dist/esm/tests/protocols/permission-grant.spec.js.map +1 -1
  85. package/dist/esm/tests/scenarios/end-to-end-tests.spec.js +100 -100
  86. package/dist/esm/tests/scenarios/end-to-end-tests.spec.js.map +1 -1
  87. package/dist/esm/tests/store/message-store-level.spec.js +20 -2
  88. package/dist/esm/tests/store/message-store-level.spec.js.map +1 -1
  89. package/dist/esm/tests/utils/encryption-callbacks.spec.js +88 -125
  90. package/dist/esm/tests/utils/encryption-callbacks.spec.js.map +1 -1
  91. package/dist/esm/tests/utils/encryption.spec.js +125 -255
  92. package/dist/esm/tests/utils/encryption.spec.js.map +1 -1
  93. package/dist/esm/tests/utils/permission-scope.spec.js +5 -1
  94. package/dist/esm/tests/utils/permission-scope.spec.js.map +1 -1
  95. package/dist/esm/tests/utils/records.spec.js +15 -5
  96. package/dist/esm/tests/utils/records.spec.js.map +1 -1
  97. package/dist/esm/tests/utils/test-data-generator.js +7 -44
  98. package/dist/esm/tests/utils/test-data-generator.js.map +1 -1
  99. package/dist/esm/tests/validation/json-schemas/encryption/grant-key.spec.js +63 -0
  100. package/dist/esm/tests/validation/json-schemas/encryption/grant-key.spec.js.map +1 -0
  101. package/dist/types/generated/precompiled-validators.d.ts +140 -92
  102. package/dist/types/generated/precompiled-validators.d.ts.map +1 -1
  103. package/dist/types/src/core/constants.d.ts +2 -2
  104. package/dist/types/src/core/constants.d.ts.map +1 -1
  105. package/dist/types/src/core/core-protocol.d.ts +1 -1
  106. package/dist/types/src/core/core-protocol.d.ts.map +1 -1
  107. package/dist/types/src/core/dwn-error.d.ts +29 -1
  108. package/dist/types/src/core/dwn-error.d.ts.map +1 -1
  109. package/dist/types/src/core/messages-grant-authorization.d.ts +2 -0
  110. package/dist/types/src/core/messages-grant-authorization.d.ts.map +1 -1
  111. package/dist/types/src/core/protocol-authorization-validation.d.ts +2 -2
  112. package/dist/types/src/core/protocol-authorization-validation.d.ts.map +1 -1
  113. package/dist/types/src/core/recording-validation-state-reader.d.ts +9 -0
  114. package/dist/types/src/core/recording-validation-state-reader.d.ts.map +1 -1
  115. package/dist/types/src/core/replication-apply.d.ts +4 -3
  116. package/dist/types/src/core/replication-apply.d.ts.map +1 -1
  117. package/dist/types/src/core/validation-state-reader.d.ts +9 -0
  118. package/dist/types/src/core/validation-state-reader.d.ts.map +1 -1
  119. package/dist/types/src/dwn.d.ts +1 -0
  120. package/dist/types/src/dwn.d.ts.map +1 -1
  121. package/dist/types/src/handlers/messages-query.d.ts.map +1 -1
  122. package/dist/types/src/handlers/protocols-configure.d.ts.map +1 -1
  123. package/dist/types/src/index.d.ts +6 -5
  124. package/dist/types/src/index.d.ts.map +1 -1
  125. package/dist/types/src/interfaces/protocols-configure.d.ts +1 -1
  126. package/dist/types/src/interfaces/protocols-configure.d.ts.map +1 -1
  127. package/dist/types/src/interfaces/records-write-signing.d.ts +4 -8
  128. package/dist/types/src/interfaces/records-write-signing.d.ts.map +1 -1
  129. package/dist/types/src/interfaces/records-write.d.ts +10 -26
  130. package/dist/types/src/interfaces/records-write.d.ts.map +1 -1
  131. package/dist/types/src/protocols/encryption.d.ts +43 -0
  132. package/dist/types/src/protocols/encryption.d.ts.map +1 -0
  133. package/dist/types/src/protocols/permission-grant.d.ts +3 -6
  134. package/dist/types/src/protocols/permission-grant.d.ts.map +1 -1
  135. package/dist/types/src/protocols/permissions.d.ts +2 -1
  136. package/dist/types/src/protocols/permissions.d.ts.map +1 -1
  137. package/dist/types/src/types/encryption-types.d.ts +5 -38
  138. package/dist/types/src/types/encryption-types.d.ts.map +1 -1
  139. package/dist/types/src/types/message-types.d.ts +0 -13
  140. package/dist/types/src/types/message-types.d.ts.map +1 -1
  141. package/dist/types/src/types/permission-types.d.ts +44 -9
  142. package/dist/types/src/types/permission-types.d.ts.map +1 -1
  143. package/dist/types/src/types/protocols-types.d.ts +9 -14
  144. package/dist/types/src/types/protocols-types.d.ts.map +1 -1
  145. package/dist/types/src/types/records-types.d.ts +3 -3
  146. package/dist/types/src/types/records-types.d.ts.map +1 -1
  147. package/dist/types/src/types/validation-state-reader.d.ts +12 -0
  148. package/dist/types/src/types/validation-state-reader.d.ts.map +1 -1
  149. package/dist/types/src/utils/encryption.d.ts +54 -145
  150. package/dist/types/src/utils/encryption.d.ts.map +1 -1
  151. package/dist/types/src/utils/hd-key.d.ts +1 -1
  152. package/dist/types/src/utils/hd-key.d.ts.map +1 -1
  153. package/dist/types/src/utils/permission-scope.d.ts +4 -3
  154. package/dist/types/src/utils/permission-scope.d.ts.map +1 -1
  155. package/dist/types/src/utils/protocols.d.ts +3 -5
  156. package/dist/types/src/utils/protocols.d.ts.map +1 -1
  157. package/dist/types/src/utils/records.d.ts +5 -13
  158. package/dist/types/src/utils/records.d.ts.map +1 -1
  159. package/dist/types/src/utils/replication.d.ts +3 -0
  160. package/dist/types/src/utils/replication.d.ts.map +1 -1
  161. package/dist/types/tests/features/protocol-composition.spec.d.ts.map +1 -1
  162. package/dist/types/tests/handlers/messages-query.spec.d.ts.map +1 -1
  163. package/dist/types/tests/handlers/records-read.spec.d.ts.map +1 -1
  164. package/dist/types/tests/handlers/records-write.spec.d.ts.map +1 -1
  165. package/dist/types/tests/protocols/encryption.spec.d.ts +2 -0
  166. package/dist/types/tests/protocols/encryption.spec.d.ts.map +1 -0
  167. package/dist/types/tests/scenarios/end-to-end-tests.spec.d.ts.map +1 -1
  168. package/dist/types/tests/utils/test-data-generator.d.ts +0 -5
  169. package/dist/types/tests/utils/test-data-generator.d.ts.map +1 -1
  170. package/dist/types/tests/validation/json-schemas/encryption/grant-key.spec.d.ts +2 -0
  171. package/dist/types/tests/validation/json-schemas/encryption/grant-key.spec.d.ts.map +1 -0
  172. package/package.json +3 -3
  173. package/src/core/constants.ts +3 -3
  174. package/src/core/core-protocol.ts +1 -1
  175. package/src/core/dwn-error.ts +29 -1
  176. package/src/core/messages-grant-authorization.ts +27 -0
  177. package/src/core/protocol-authorization-validation.ts +145 -6
  178. package/src/core/recording-validation-state-reader.ts +13 -0
  179. package/src/core/replication-apply.ts +222 -8
  180. package/src/core/validation-state-reader.ts +30 -0
  181. package/src/dwn.ts +24 -2
  182. package/src/handlers/messages-query.ts +6 -5
  183. package/src/handlers/protocols-configure.ts +19 -3
  184. package/src/handlers/records-write.ts +1 -1
  185. package/src/index.ts +15 -5
  186. package/src/interfaces/protocols-configure.ts +39 -12
  187. package/src/interfaces/records-write-signing.ts +5 -12
  188. package/src/interfaces/records-write.ts +75 -92
  189. package/src/protocols/encryption.ts +649 -0
  190. package/src/protocols/permission-grant.ts +4 -5
  191. package/src/protocols/permissions.ts +8 -6
  192. package/src/types/encryption-types.ts +9 -38
  193. package/src/types/message-types.ts +0 -13
  194. package/src/types/permission-types.ts +57 -9
  195. package/src/types/protocols-types.ts +9 -16
  196. package/src/types/records-types.ts +3 -3
  197. package/src/types/validation-state-reader.ts +13 -0
  198. package/src/utils/encryption.ts +213 -283
  199. package/src/utils/hd-key.ts +1 -1
  200. package/src/utils/permission-scope.ts +10 -6
  201. package/src/utils/protocols.ts +16 -15
  202. package/src/utils/records.ts +86 -71
  203. package/src/utils/replication.ts +30 -4
  204. package/dist/esm/tests/vectors/protocol-definitions/chat.json +0 -70
@@ -20,6 +20,22 @@ export enum DwnErrorCode {
20
20
  ComputeCidCodecNotSupported = 'ComputeCidCodecNotSupported',
21
21
  ComputeCidMultihashNotSupported = 'ComputeCidMultihashNotSupported',
22
22
  Ed25519InvalidJwk = 'Ed25519InvalidJwk',
23
+ EncryptionProtocolValidateAudienceEpochEncrypted = 'EncryptionProtocolValidateAudienceEpochEncrypted',
24
+ EncryptionProtocolValidateAudienceEpochKeyIdMismatch = 'EncryptionProtocolValidateAudienceEpochKeyIdMismatch',
25
+ EncryptionProtocolValidateAudienceEpochMissing = 'EncryptionProtocolValidateAudienceEpochMissing',
26
+ EncryptionProtocolValidateAudienceKeyRecipientMissing = 'EncryptionProtocolValidateAudienceKeyRecipientMissing',
27
+ EncryptionProtocolValidateAudienceKeyRoleRecordMissing = 'EncryptionProtocolValidateAudienceKeyRoleRecordMissing',
28
+ EncryptionProtocolValidateAudienceMissingRequiredTag = 'EncryptionProtocolValidateAudienceMissingRequiredTag',
29
+ EncryptionProtocolValidateAudienceTagsMismatch = 'EncryptionProtocolValidateAudienceTagsMismatch',
30
+ EncryptionProtocolValidateAudienceWriterUnauthorized = 'EncryptionProtocolValidateAudienceWriterUnauthorized',
31
+ EncryptionProtocolValidateEncryptedDeliveryMissingEncryption = 'EncryptionProtocolValidateEncryptedDeliveryMissingEncryption',
32
+ EncryptionProtocolValidateGrantKeyAuthorMismatch = 'EncryptionProtocolValidateGrantKeyAuthorMismatch',
33
+ EncryptionProtocolValidateGrantKeyGrantScopeMismatch = 'EncryptionProtocolValidateGrantKeyGrantScopeMismatch',
34
+ EncryptionProtocolValidateGrantKeyMissingRequiredTag = 'EncryptionProtocolValidateGrantKeyMissingRequiredTag',
35
+ EncryptionProtocolValidateGrantKeyRecipientMismatch = 'EncryptionProtocolValidateGrantKeyRecipientMismatch',
36
+ EncryptionProtocolValidateRoleAudienceContextInvalid = 'EncryptionProtocolValidateRoleAudienceContextInvalid',
37
+ EncryptionProtocolValidateRoleAudienceInvalid = 'EncryptionProtocolValidateRoleAudienceInvalid',
38
+ EncryptionProtocolValidateSchemaUnexpectedRecord = 'EncryptionProtocolValidateSchemaUnexpectedRecord',
23
39
  EventLogNotOpenError = 'EventLogNotOpenError',
24
40
  EventLogProgressGap = 'EventLogProgressGap',
25
41
  MessagesGrantAuthorizationMismatchedProtocol = 'MessagesGrantAuthorizationMismatchedProtocol',
@@ -101,6 +117,10 @@ export enum DwnErrorCode {
101
117
  ProtocolAuthorizationInitialWriteRevalidationNotInitial = 'ProtocolAuthorizationInitialWriteRevalidationNotInitial',
102
118
  ProtocolAuthorizationDuplicateRoleRecipient = 'ProtocolAuthorizationDuplicateRoleRecipient',
103
119
  ProtocolAuthorizationEncryptionRequired = 'ProtocolAuthorizationEncryptionRequired',
120
+ ProtocolAuthorizationEncryptionKeyAgreementMissing = 'ProtocolAuthorizationEncryptionKeyAgreementMissing',
121
+ ProtocolAuthorizationEncryptionProtocolPathEntryMissing = 'ProtocolAuthorizationEncryptionProtocolPathEntryMissing',
122
+ ProtocolAuthorizationEncryptionRoleAudienceEntryMissing = 'ProtocolAuthorizationEncryptionRoleAudienceEntryMissing',
123
+ ProtocolAuthorizationEncryptionRoleAudienceEpochMissing = 'ProtocolAuthorizationEncryptionRoleAudienceEpochMissing',
104
124
  ProtocolAuthorizationImmutableRecord = 'ProtocolAuthorizationImmutableRecord',
105
125
  ProtocolAuthorizationInvalidSchema = 'ProtocolAuthorizationInvalidSchema',
106
126
  ProtocolAuthorizationInvalidType = 'ProtocolAuthorizationInvalidType',
@@ -142,6 +162,10 @@ export enum DwnErrorCode {
142
162
  ProtocolsConfigureInvalidActionUpdateWithoutCreate = 'ProtocolsConfigureInvalidActionUpdateWithoutCreate',
143
163
  ProtocolsConfigureInvalidCrossProtocolOf = 'ProtocolsConfigureInvalidCrossProtocolOf',
144
164
  ProtocolsConfigureInvalidCrossProtocolRole = 'ProtocolsConfigureInvalidCrossProtocolRole',
165
+ ProtocolsConfigureInvalidEncryptedAnyoneRead = 'ProtocolsConfigureInvalidEncryptedAnyoneRead',
166
+ ProtocolsConfigureInvalidEncryptedRoleMissingKeyAgreement = 'ProtocolsConfigureInvalidEncryptedRoleMissingKeyAgreement',
167
+ ProtocolsConfigureMissingEncryptedPathKeyAgreement = 'ProtocolsConfigureMissingEncryptedPathKeyAgreement',
168
+ ProtocolsConfigureMissingTopLevelKeyAgreement = 'ProtocolsConfigureMissingTopLevelKeyAgreement',
145
169
  ProtocolsConfigureInvalidRecipientOfAction = 'ProtocolsConfigureInvalidRecipientOfAction',
146
170
  ProtocolsConfigureInvalidRuleSetRecordType = 'ProtocolsConfigureInvalidRuleSetRecordType',
147
171
  ProtocolsConfigureInvalidTagSchema = 'ProtocolsConfigureInvalidTagSchema',
@@ -158,6 +182,7 @@ export enum DwnErrorCode {
158
182
  RecordsAuthorDelegatedGrantGrantedToAndOwnerSignatureMismatch = 'RecordsAuthorDelegatedGrantGrantedToAndOwnerSignatureMismatch',
159
183
  RecordsAuthorDelegatedGrantNotADelegatedGrant = 'RecordsAuthorDelegatedGrantNotADelegatedGrant',
160
184
  RecordsDecryptNoMatchingKeyEncryptedFound = 'RecordsDecryptNoMatchingKeyEncryptedFound',
185
+ RecordsDecryptUnsupportedKeyDerivationScheme = 'RecordsDecryptUnsupportedKeyDerivationScheme',
161
186
  RecordsCountFilterMissingRequiredProperties = 'RecordsCountFilterMissingRequiredProperties',
162
187
  RecordsCountNestedProtocolPathContextIdInvalid = 'RecordsCountNestedProtocolPathContextIdInvalid',
163
188
 
@@ -194,6 +219,7 @@ export enum DwnErrorCode {
194
219
  RecordsWriteCreateMissingSigner = 'RecordsWriteCreateMissingSigner',
195
220
  RecordsWriteCreateDataAndDataCidMutuallyExclusive = 'RecordsWriteCreateDataAndDataCidMutuallyExclusive',
196
221
  RecordsWriteCreateDataCidAndDataSizeMutuallyInclusive = 'RecordsWriteCreateDataCidAndDataSizeMutuallyInclusive',
222
+ RecordsWriteCreateEncryptionAndEncryptionInputMutuallyExclusive = 'RecordsWriteCreateEncryptionAndEncryptionInputMutuallyExclusive',
197
223
  RecordsWriteCreateMissingProtocol = 'RecordsWriteCreateMissingProtocol',
198
224
  RecordsWriteDataCidMismatch = 'RecordsWriteDataCidMismatch',
199
225
  RecordsWriteDataSizeMismatch = 'RecordsWriteDataSizeMismatch',
@@ -204,7 +230,6 @@ export enum DwnErrorCode {
204
230
  RecordsWriteMissingSigner = 'RecordsWriteMissingSigner',
205
231
  RecordsWriteMissingDataInPrevious = 'RecordsWriteMissingDataInPrevious',
206
232
  RecordsWriteMissingEncodedDataInPrevious = 'RecordsWriteMissingEncodedDataInPrevious',
207
- RecordsWriteMissingEncryption = 'RecordsWriteMissingEncryption',
208
233
 
209
234
  RecordsWriteNotAllowedAfterDelete = 'RecordsWriteNotAllowedAfterDelete',
210
235
  RecordsWriteOwnerAndTenantMismatch = 'RecordsWriteOwnerAndTenantMismatch',
@@ -214,7 +239,10 @@ export enum DwnErrorCode {
214
239
  RecordsWriteValidateIntegrityContextIdMismatch = 'RecordsWriteValidateIntegrityContextIdMismatch',
215
240
  RecordsWriteValidateIntegrityContextIdNotInSignerSignaturePayload = 'RecordsWriteValidateIntegrityContextIdNotInSignerSignaturePayload',
216
241
  RecordsWriteValidateIntegrityDateCreatedMismatch = 'RecordsWriteValidateIntegrityDateCreatedMismatch',
242
+ RecordsWriteValidateIntegrityEncryptionCidMissing = 'RecordsWriteValidateIntegrityEncryptionCidMissing',
217
243
  RecordsWriteValidateIntegrityEncryptionCidMismatch = 'RecordsWriteValidateIntegrityEncryptionCidMismatch',
244
+ RecordsWriteValidateIntegrityEncryptionEphemeralPublicKeyInvalid = 'RecordsWriteValidateIntegrityEncryptionEphemeralPublicKeyInvalid',
245
+ RecordsWriteValidateIntegrityEncryptionInitializationVectorInvalid = 'RecordsWriteValidateIntegrityEncryptionInitializationVectorInvalid',
218
246
  RecordsWriteValidateIntegrityRecordIdUnauthorized = 'RecordsWriteValidateIntegrityRecordIdUnauthorized',
219
247
  SchemaValidatorAdditionalPropertyNotAllowed = 'SchemaValidatorAdditionalPropertyNotAllowed',
220
248
  SchemaValidatorFailure = 'SchemaValidatorFailure',
@@ -8,6 +8,7 @@ import type { DataEncodedRecordsWriteMessage, RecordsDeleteMessage, RecordsWrite
8
8
  import type { MessagesQueryMessage, MessagesReadMessage, MessagesSubscribeMessage } from '../types/messages-types.js';
9
9
 
10
10
  import { DwnInterfaceName } from '../enums/dwn-interface-method.js';
11
+ import { EncryptionProtocol } from '../protocols/encryption.js';
11
12
  import { GrantAuthorization } from './grant-authorization.js';
12
13
  import { PermissionScopeMatcher } from '../utils/permission-scope.js';
13
14
  import { PermissionsProtocol } from '../protocols/permissions.js';
@@ -240,6 +241,10 @@ export class MessagesGrantAuthorization {
240
241
  );
241
242
  }
242
243
 
244
+ if (recordsWriteMessage.descriptor.protocol === EncryptionProtocol.uri) {
245
+ return MessagesGrantAuthorization.isEncryptionRecordScopeAuthorized(recordsWriteMessage, incomingScope);
246
+ }
247
+
243
248
  return PermissionScopeMatcher.matches(incomingScope, MessagesGrantAuthorization.getRecordsScopeTarget(recordsWriteMessage));
244
249
  }
245
250
 
@@ -263,6 +268,23 @@ export class MessagesGrantAuthorization {
263
268
  && PermissionScopeMatcher.matches(incomingScope, permissionScope);
264
269
  }
265
270
 
271
+ private static isEncryptionRecordScopeAuthorized(
272
+ recordsWriteMessage: RecordsWriteMessage,
273
+ incomingScope: MessagesPermissionScope,
274
+ ): boolean {
275
+ const tags = recordsWriteMessage.descriptor.tags;
276
+ const protocol = tags?.protocol;
277
+ if (typeof protocol !== 'string') {
278
+ return false;
279
+ }
280
+
281
+ return PermissionScopeMatcher.matches(incomingScope, {
282
+ protocol,
283
+ protocolPath : MessagesGrantAuthorization.getStringTag(recordsWriteMessage, 'protocolPath'),
284
+ contextId : MessagesGrantAuthorization.getStringTag(recordsWriteMessage, 'contextId'),
285
+ });
286
+ }
287
+
266
288
  private static isProtocolsConfigureScopeAuthorized(
267
289
  protocolsConfigureMessage: ProtocolsConfigureMessage,
268
290
  incomingScope: MessagesPermissionScope
@@ -291,6 +313,11 @@ export class MessagesGrantAuthorization {
291
313
  return { protocol, protocolPath, contextId };
292
314
  }
293
315
 
316
+ private static getStringTag(recordsWriteMessage: RecordsWriteMessage, tag: string): string | undefined {
317
+ const value = recordsWriteMessage.descriptor.tags?.[tag];
318
+ return typeof value === 'string' ? value : undefined;
319
+ }
320
+
294
321
  private static isSubtreeScope(scope: MessagesPermissionScope): boolean {
295
322
  return scope.protocolPath !== undefined || scope.contextId !== undefined;
296
323
  }
@@ -1,14 +1,16 @@
1
1
  import type { RecordsWrite } from '../interfaces/records-write.js';
2
2
  import type { RecordsWriteMessage } from '../types/records-types.js';
3
+ import type { RoleAudienceKeyEncryption } from '../utils/encryption.js';
3
4
  import type { ValidationStateReader } from '../types/validation-state-reader.js';
4
- import type { ProtocolDefinition, ProtocolRuleSet, ProtocolType, ProtocolTypes } from '../types/protocols-types.js';
5
-
6
- import { ProtocolRecordLimitStrategy } from '../types/protocols-types.js';
5
+ import type { ProtocolActionRule, ProtocolDefinition, ProtocolRuleSet, ProtocolType, ProtocolTypes } from '../types/protocols-types.js';
7
6
 
7
+ import { KeyDerivationScheme } from '../utils/hd-key.js';
8
8
  import { Records } from '../utils/records.js';
9
9
  import { validateProtocolTags } from '../utils/protocol-tags.js';
10
10
  import { DwnError, DwnErrorCode } from './dwn-error.js';
11
- import { getTypeName, parseCrossProtocolRef } from '../utils/protocols.js';
11
+ import { Encryption, ROLE_AUDIENCE_DERIVATION_SCHEME } from '../utils/encryption.js';
12
+ import { getRuleSetAtPath, getTypeName, parseCrossProtocolRef } from '../utils/protocols.js';
13
+ import { ProtocolAction, ProtocolRecordLimitStrategy } from '../types/protocols-types.js';
12
14
 
13
15
  /**
14
16
  * Verifies the `protocolPath` declared in the given message matches the path of actual record chain.
@@ -170,7 +172,14 @@ export async function verifyTypeWithComposition(
170
172
  tenant, declaredProtocolPath, protocolDefinition, validationStateReader, protocolDefinitionTimestamp
171
173
  );
172
174
 
173
- verifyType(inboundMessage, protocolTypes, declaredTypeName);
175
+ const protocolType = verifyType(inboundMessage, protocolTypes, declaredTypeName);
176
+ await verifyProtocolPathEncryptionIfNeeded(
177
+ tenant,
178
+ inboundMessage,
179
+ protocolDefinition,
180
+ protocolType,
181
+ validationStateReader,
182
+ );
174
183
  }
175
184
 
176
185
  /**
@@ -216,7 +225,7 @@ export function verifyType(
216
225
  inboundMessage: RecordsWriteMessage,
217
226
  protocolTypes: ProtocolTypes,
218
227
  typeName?: string,
219
- ): void {
228
+ ): ProtocolType {
220
229
  const declaredTypeName = typeName ?? getTypeName(inboundMessage.descriptor.protocolPath);
221
230
  const typeNames = Object.keys(protocolTypes);
222
231
 
@@ -254,6 +263,136 @@ export function verifyType(
254
263
  `type '${declaredTypeName}' requires encryption but message has no encryption metadata`
255
264
  );
256
265
  }
266
+
267
+ return protocolType;
268
+ }
269
+
270
+ async function verifyProtocolPathEncryptionIfNeeded(
271
+ tenant: string,
272
+ inboundMessage: RecordsWriteMessage,
273
+ protocolDefinition: ProtocolDefinition,
274
+ protocolType: ProtocolType,
275
+ validationStateReader: ValidationStateReader,
276
+ ): Promise<void> {
277
+ if (protocolType.encryptionRequired !== true) {
278
+ return;
279
+ }
280
+
281
+ const ruleSet = getRuleSetAtPath(inboundMessage.descriptor.protocolPath, protocolDefinition.structure);
282
+ if (ruleSet?.$keyAgreement?.publicKeyJwk === undefined) {
283
+ throw new DwnError(
284
+ DwnErrorCode.ProtocolAuthorizationEncryptionKeyAgreementMissing,
285
+ `encrypted protocol path '${inboundMessage.descriptor.protocolPath}' has no $keyAgreement`
286
+ );
287
+ }
288
+
289
+ const publicKeyJwk = ruleSet.$keyAgreement.publicKeyJwk;
290
+ const keyId = await Encryption.getKeyId(publicKeyJwk);
291
+ const hasProtocolPathEntry = inboundMessage.encryption!.keyEncryption.some((entry): boolean =>
292
+ entry.derivationScheme === KeyDerivationScheme.ProtocolPath && entry.keyId === keyId
293
+ );
294
+
295
+ if (!hasProtocolPathEntry) {
296
+ throw new DwnError(
297
+ DwnErrorCode.ProtocolAuthorizationEncryptionProtocolPathEntryMissing,
298
+ `encrypted record is missing a protocolPath keyEncryption entry for '${inboundMessage.descriptor.protocolPath}'`
299
+ );
300
+ }
301
+
302
+ await verifyRoleAudienceEncryptionIfNeeded(tenant, inboundMessage, protocolDefinition, ruleSet, validationStateReader);
303
+ }
304
+
305
+ async function verifyRoleAudienceEncryptionIfNeeded(
306
+ tenant: string,
307
+ inboundMessage: RecordsWriteMessage,
308
+ protocolDefinition: ProtocolDefinition,
309
+ ruleSet: ProtocolRuleSet,
310
+ validationStateReader: ValidationStateReader,
311
+ ): Promise<void> {
312
+ const readRoleRules = (ruleSet.$actions ?? []).filter((actionRule): boolean =>
313
+ actionRule.role !== undefined && actionRule.can.includes(ProtocolAction.Read)
314
+ );
315
+
316
+ for (const actionRule of readRoleRules) {
317
+ const roleAudience = resolveRoleAudience(actionRule, inboundMessage, protocolDefinition);
318
+ if (roleAudience === undefined) {
319
+ continue;
320
+ }
321
+
322
+ const matchingEntry = inboundMessage.encryption!.keyEncryption.find((entry): entry is RoleAudienceKeyEncryption =>
323
+ entry.derivationScheme === ROLE_AUDIENCE_DERIVATION_SCHEME &&
324
+ entry.protocol === roleAudience.protocol &&
325
+ entry.role === roleAudience.role
326
+ );
327
+
328
+ if (matchingEntry === undefined) {
329
+ throw new DwnError(
330
+ DwnErrorCode.ProtocolAuthorizationEncryptionRoleAudienceEntryMissing,
331
+ `encrypted record is missing a roleAudience keyEncryption entry for role '${roleAudience.role}'`
332
+ );
333
+ }
334
+
335
+ const matchingEpochs = await validationStateReader.queryAudienceEpochs({
336
+ tenant,
337
+ protocol : roleAudience.protocol,
338
+ contextId : roleAudience.contextId,
339
+ role : roleAudience.role,
340
+ epoch : matchingEntry.epoch,
341
+ keyId : matchingEntry.keyId,
342
+ });
343
+
344
+ if (matchingEpochs.length === 0) {
345
+ throw new DwnError(
346
+ DwnErrorCode.ProtocolAuthorizationEncryptionRoleAudienceEpochMissing,
347
+ `encrypted record references a missing audienceEpoch for role '${roleAudience.role}'`
348
+ );
349
+ }
350
+ }
351
+ }
352
+
353
+ function resolveRoleAudience(
354
+ actionRule: ProtocolActionRule,
355
+ inboundMessage: RecordsWriteMessage,
356
+ protocolDefinition: ProtocolDefinition,
357
+ ): { protocol: string; role: string; contextId: string } | undefined {
358
+ const roleRef = actionRule.role;
359
+ if (roleRef === undefined) {
360
+ return undefined;
361
+ }
362
+
363
+ const parsed = parseCrossProtocolRef(roleRef);
364
+ const protocol = parsed === undefined
365
+ ? inboundMessage.descriptor.protocol
366
+ : protocolDefinition.uses?.[parsed.alias];
367
+ const role = parsed === undefined ? roleRef : parsed.protocolPath;
368
+ if (protocol === undefined) {
369
+ return undefined;
370
+ }
371
+
372
+ const contextId = getRoleAudienceContextId(inboundMessage, role);
373
+ return contextId === undefined ? undefined : { protocol, role, contextId };
374
+ }
375
+
376
+ function getRoleAudienceContextId(
377
+ inboundMessage: RecordsWriteMessage,
378
+ rolePath: string,
379
+ ): string | undefined {
380
+ const parentDepth = rolePath.split('/').length - 1;
381
+ if (parentDepth === 0) {
382
+ return '';
383
+ }
384
+
385
+ const contextId = inboundMessage.contextId;
386
+ if (typeof contextId !== 'string') {
387
+ return undefined;
388
+ }
389
+
390
+ const contextSegments = contextId.split('/');
391
+ if (contextSegments.length < parentDepth) {
392
+ return undefined;
393
+ }
394
+
395
+ return contextSegments.slice(0, parentDepth).join('/');
257
396
  }
258
397
 
259
398
  /**
@@ -87,6 +87,19 @@ export class RecordingValidationStateReader implements ValidationStateReader {
87
87
  return this.inner.queryLatestRoleRecords(input);
88
88
  }
89
89
 
90
+ /** @inheritdoc */
91
+ public async queryAudienceEpochs(input: {
92
+ tenant: string;
93
+ protocol: string;
94
+ contextId: string;
95
+ role: string;
96
+ epoch: number;
97
+ keyId?: string;
98
+ }): Promise<RecordsWriteMessage[]> {
99
+ this.recordedReads.push({ method: 'queryAudienceEpochs' });
100
+ return this.inner.queryAudienceEpochs(input);
101
+ }
102
+
90
103
  /** @inheritdoc */
91
104
  public async fetchGrant(tenant: string, permissionGrantId: string): Promise<PermissionGrant> {
92
105
  this.recordedReads.push({ method: 'fetchGrant' });
@@ -5,7 +5,9 @@ import type { ValidationStateReader } from '../types/validation-state-reader.js'
5
5
 
6
6
  import { DwnErrorCode } from './dwn-error.js';
7
7
  import { Encoder } from '../utils/encoder.js';
8
+ import { EncryptionProtocol } from '../protocols/encryption.js';
8
9
  import { Message } from './message.js';
10
+ import { ROLE_AUDIENCE_DERIVATION_SCHEME } from '../utils/encryption.js';
9
11
  import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
10
12
  import { isCrossProtocolRef, parseCrossProtocolRef } from '../utils/protocols.js';
11
13
 
@@ -40,6 +42,14 @@ export type ReplicationApplyResultContext = {
40
42
  missingAncestorRecordIds?: string[];
41
43
  };
42
44
 
45
+ type AudienceDependencyTags = {
46
+ protocol: string;
47
+ contextId: string;
48
+ role: string;
49
+ epoch: number;
50
+ keyId: string;
51
+ };
52
+
43
53
  export type DependencyRef =
44
54
  | { type: 'Protocol'; protocol: string; messageCid?: string; terminal?: boolean }
45
55
  | { type: 'InitialWrite'; recordId: string; protocol?: string; messageCid?: string; terminal?: boolean }
@@ -47,7 +57,14 @@ export type DependencyRef =
47
57
  | { type: 'Ancestor'; recordId: string; protocol?: string; messageCid?: string; terminal?: boolean }
48
58
  | { type: 'Role'; protocol: string; protocolPath: string; recipient: string; contextPrefix?: string; messageCid?: string; terminal?: boolean }
49
59
  | { type: 'Grant'; permissionGrantId: string; messageCid?: string; terminal?: boolean }
50
- | { type: 'KeyDelivery'; protocol: string; contextId: string; messageCid?: string; terminal?: boolean }
60
+ | {
61
+ type: 'EncryptionProtocol';
62
+ protocolPath: 'audienceEpoch' | 'audienceKey' | 'grantKey';
63
+ tags?: Record<string, string | number>;
64
+ recipient?: string;
65
+ messageCid?: string;
66
+ terminal?: boolean;
67
+ }
51
68
  | { type: 'CrossProtocolRef'; protocol: string; recordId: string; messageCid?: string; terminal?: boolean }
52
69
  | { type: 'RecordData'; recordId: string; dataCid: string; protocol?: string; messageCid?: string; terminal?: boolean };
53
70
 
@@ -180,7 +197,14 @@ function dependencyRefsFromStatus(
180
197
  case DwnErrorCode.GrantAuthorizationGrantMissing:
181
198
  return toRefList(grantDependencyFromMessage(message));
182
199
  case DwnErrorCode.ProtocolAuthorizationMatchingRoleRecordNotFound:
200
+ case DwnErrorCode.EncryptionProtocolValidateAudienceWriterUnauthorized:
183
201
  return toRefList(roleDependencyFromMessage(message, context));
202
+ case DwnErrorCode.EncryptionProtocolValidateAudienceEpochMissing:
203
+ return toRefList(encryptionProtocolDependencyFromMessage(message, EncryptionProtocol.audienceEpochPath));
204
+ case DwnErrorCode.ProtocolAuthorizationEncryptionRoleAudienceEpochMissing:
205
+ return toRefList(encryptionProtocolDependencyFromRoleAudienceEntry(message, detail));
206
+ case DwnErrorCode.EncryptionProtocolValidateAudienceKeyRoleRecordMissing:
207
+ return toRefList(roleDependencyFromEncryptionAudienceRecipient(message));
184
208
  case DwnErrorCode.RecordsWriteMissingDataInPrevious:
185
209
  case DwnErrorCode.RecordsWriteMissingEncodedDataInPrevious:
186
210
  return toRefList(recordDataDependencyFromMessage(message));
@@ -214,7 +238,7 @@ function protocolDependencyFromMessage(message: GenericMessage, detail: string):
214
238
  return { type: 'Protocol', protocol: composedProtocol };
215
239
  }
216
240
 
217
- const protocol = (message.descriptor as Record<string, unknown>).protocol;
241
+ const protocol = dependencyProtocolFromMessage(message);
218
242
  return typeof protocol === 'string' ? { type: 'Protocol', protocol } : undefined;
219
243
  }
220
244
 
@@ -235,7 +259,7 @@ function parentDependenciesFromMessage(
235
259
  return [];
236
260
  }
237
261
 
238
- const protocol = (message.descriptor as Record<string, unknown>).protocol;
262
+ const protocol = dependencyProtocolFromMessage(message);
239
263
  const protocolProperty = typeof protocol === 'string' ? { protocol } : {};
240
264
  const ancestorRefs = (context.missingAncestorRecordIds ?? [])
241
265
  .filter((recordId): boolean => recordId !== parentRef.recordId)
@@ -248,9 +272,8 @@ function parentDependencyFromMessage(
248
272
  message: GenericMessage,
249
273
  detail: string,
250
274
  ): Extract<DependencyRef, { type: 'Parent' }> | undefined {
251
- const descriptor = message.descriptor as Record<string, unknown>;
252
275
  const parentId = parentRecordIdFromMessage(message, detail);
253
- const protocol = /in protocol '([^']+)'/.exec(detail)?.[1] ?? descriptor.protocol;
276
+ const protocol = /in protocol '([^']+)'/.exec(detail)?.[1] ?? dependencyProtocolFromMessage(message);
254
277
 
255
278
  if (parentId === undefined || typeof protocol !== 'string') {
256
279
  return undefined;
@@ -278,7 +301,7 @@ function ancestorDependenciesFromMessage(
278
301
  detail: string,
279
302
  context: ReplicationApplyResultContext,
280
303
  ): DependencyRef[] {
281
- const protocol = (message.descriptor as Record<string, unknown>).protocol;
304
+ const protocol = dependencyProtocolFromMessage(message);
282
305
  const protocolProperty = typeof protocol === 'string' ? { protocol } : {};
283
306
 
284
307
  const batchedRecordIds = context.missingAncestorRecordIds;
@@ -303,7 +326,7 @@ function initialWriteDependencyFromMessage(message: GenericMessage): DependencyR
303
326
  return undefined;
304
327
  }
305
328
 
306
- const protocol = (message.descriptor as Record<string, unknown>).protocol;
329
+ const protocol = dependencyProtocolFromMessage(message);
307
330
  return {
308
331
  type : 'InitialWrite',
309
332
  recordId : message.recordId,
@@ -312,6 +335,14 @@ function initialWriteDependencyFromMessage(message: GenericMessage): DependencyR
312
335
  }
313
336
 
314
337
  function grantDependencyFromMessage(message: GenericMessage): DependencyRef | undefined {
338
+ if (isEncryptionProtocolMessage(message)) {
339
+ const tags = (message.descriptor as Record<string, unknown>).tags;
340
+ const grantId = isRecordObject(tags) ? tags.grantId : undefined;
341
+ if (typeof grantId === 'string') {
342
+ return { type: 'Grant', permissionGrantId: grantId };
343
+ }
344
+ }
345
+
315
346
  const descriptorGrantId = (message.descriptor as Record<string, unknown>).permissionGrantId;
316
347
  if (typeof descriptorGrantId === 'string') {
317
348
  return { type: 'Grant', permissionGrantId: descriptorGrantId };
@@ -330,7 +361,7 @@ function recordDataDependencyFromMessage(message: GenericMessage): DependencyRef
330
361
 
331
362
  const descriptor = message.descriptor as Record<string, unknown>;
332
363
  const dataCid = descriptor.dataCid;
333
- const protocol = descriptor.protocol;
364
+ const protocol = dependencyProtocolFromMessage(message);
334
365
  return typeof dataCid === 'string'
335
366
  ? {
336
367
  type : 'RecordData',
@@ -342,6 +373,11 @@ function recordDataDependencyFromMessage(message: GenericMessage): DependencyRef
342
373
  }
343
374
 
344
375
  function roleDependencyFromMessage(message: GenericMessage, context: ReplicationApplyResultContext): DependencyRef | undefined {
376
+ const encryptionRoleDependency = roleDependencyFromEncryptionAudienceWriter(message, context);
377
+ if (encryptionRoleDependency !== undefined) {
378
+ return encryptionRoleDependency;
379
+ }
380
+
345
381
  const descriptor = message.descriptor as Record<string, unknown>;
346
382
  const filter = descriptor.filter as Record<string, unknown> | undefined;
347
383
  const protocol = descriptor.protocol ?? filter?.protocol;
@@ -383,6 +419,184 @@ function roleDependencyFromMessage(message: GenericMessage, context: Replication
383
419
  };
384
420
  }
385
421
 
422
+ function encryptionProtocolDependencyFromMessage(
423
+ message: GenericMessage,
424
+ protocolPath: Extract<DependencyRef, { type: 'EncryptionProtocol' }>['protocolPath'],
425
+ ): DependencyRef | undefined {
426
+ const tags = encryptionAudienceTagsFromMessage(message);
427
+ return tags === undefined
428
+ ? undefined
429
+ : { type: 'EncryptionProtocol', protocolPath, tags };
430
+ }
431
+
432
+ function encryptionProtocolDependencyFromRoleAudienceEntry(
433
+ message: GenericMessage,
434
+ detail: string,
435
+ ): DependencyRef | undefined {
436
+ const descriptor = message.descriptor as Record<string, unknown>;
437
+ const messageContextId = (message as { contextId?: unknown }).contextId;
438
+ const contextId = typeof messageContextId === 'string' ? messageContextId : descriptor.contextId;
439
+ const keyEncryption = (message as {
440
+ encryption?: {
441
+ keyEncryption?: Record<string, unknown>[];
442
+ };
443
+ }).encryption?.keyEncryption;
444
+ if (typeof contextId !== 'string' || !Array.isArray(keyEncryption)) {
445
+ return undefined;
446
+ }
447
+
448
+ const missingRole = /role '([^']+)'/.exec(detail)?.[1];
449
+ const entry = keyEncryption.find((candidate): boolean =>
450
+ candidate.derivationScheme === ROLE_AUDIENCE_DERIVATION_SCHEME &&
451
+ typeof candidate.protocol === 'string' &&
452
+ typeof candidate.role === 'string' &&
453
+ (missingRole === undefined || candidate.role === missingRole) &&
454
+ typeof candidate.epoch === 'number' &&
455
+ typeof candidate.keyId === 'string'
456
+ );
457
+ if (entry === undefined) {
458
+ return undefined;
459
+ }
460
+
461
+ const role = entry.role as string;
462
+ const audienceContextId = roleAudienceContextId(role, contextId);
463
+ if (audienceContextId === undefined) {
464
+ return undefined;
465
+ }
466
+
467
+ return {
468
+ type : 'EncryptionProtocol',
469
+ protocolPath : EncryptionProtocol.audienceEpochPath,
470
+ tags : {
471
+ protocol : entry.protocol as string,
472
+ contextId : audienceContextId,
473
+ role,
474
+ epoch : entry.epoch as number,
475
+ keyId : entry.keyId as string,
476
+ },
477
+ };
478
+ }
479
+
480
+ function roleDependencyFromEncryptionAudienceRecipient(message: GenericMessage): DependencyRef | undefined {
481
+ const tags = encryptionAudienceTagsFromMessage(message);
482
+ const recipient = (message.descriptor as Record<string, unknown>).recipient;
483
+ if (tags === undefined || typeof recipient !== 'string') {
484
+ return undefined;
485
+ }
486
+
487
+ return {
488
+ type : 'Role',
489
+ protocol : tags.protocol,
490
+ protocolPath : tags.role,
491
+ recipient,
492
+ ...(tags.contextId === '' ? {} : { contextPrefix: tags.contextId }),
493
+ };
494
+ }
495
+
496
+ function roleDependencyFromEncryptionAudienceWriter(
497
+ message: GenericMessage,
498
+ context: ReplicationApplyResultContext,
499
+ ): DependencyRef | undefined {
500
+ const tags = encryptionAudienceTagsFromMessage(message);
501
+ const protocolRole = getSignaturePayload(message)?.protocolRole;
502
+ const recipient = Message.getAuthor(message);
503
+ if (tags === undefined || typeof protocolRole !== 'string' || recipient === undefined) {
504
+ return undefined;
505
+ }
506
+
507
+ let roleProtocol = tags.protocol;
508
+ let roleProtocolPath = protocolRole;
509
+ if (isCrossProtocolRef(protocolRole)) {
510
+ const parsed = parseCrossProtocolRef(protocolRole);
511
+ const referencedProtocol = parsed === undefined ? undefined : context.protocolDefinition?.uses?.[parsed.alias];
512
+ if (parsed === undefined || referencedProtocol === undefined) {
513
+ return undefined;
514
+ }
515
+
516
+ roleProtocol = referencedProtocol;
517
+ roleProtocolPath = parsed.protocolPath;
518
+ }
519
+
520
+ const contextPrefix = roleContextPrefix(roleProtocolPath, tags.contextId);
521
+ return {
522
+ type : 'Role',
523
+ protocol : roleProtocol,
524
+ protocolPath : roleProtocolPath,
525
+ recipient,
526
+ ...(contextPrefix === undefined ? {} : { contextPrefix }),
527
+ };
528
+ }
529
+
530
+ function encryptionAudienceTagsFromMessage(message: GenericMessage): AudienceDependencyTags | undefined {
531
+ if (!isEncryptionProtocolMessage(message)) {
532
+ return undefined;
533
+ }
534
+
535
+ const tags = (message.descriptor as Record<string, unknown>).tags;
536
+ if (!isRecordObject(tags)) {
537
+ return undefined;
538
+ }
539
+
540
+ const { protocol, contextId, role, epoch, keyId } = tags;
541
+ if (
542
+ typeof protocol !== 'string' ||
543
+ typeof contextId !== 'string' ||
544
+ typeof role !== 'string' ||
545
+ typeof epoch !== 'number' ||
546
+ typeof keyId !== 'string'
547
+ ) {
548
+ return undefined;
549
+ }
550
+
551
+ return { protocol, contextId, role, epoch, keyId };
552
+ }
553
+
554
+ function dependencyProtocolFromMessage(message: GenericMessage): string | undefined {
555
+ if (isEncryptionProtocolMessage(message)) {
556
+ const tags = (message.descriptor as Record<string, unknown>).tags;
557
+ const protocol = isRecordObject(tags) ? tags.protocol : undefined;
558
+ return typeof protocol === 'string' ? protocol : undefined;
559
+ }
560
+
561
+ const descriptor = message.descriptor as Record<string, unknown>;
562
+ const filter = descriptor.filter as Record<string, unknown> | undefined;
563
+ const protocol = descriptor.protocol ?? filter?.protocol;
564
+ return typeof protocol === 'string' ? protocol : undefined;
565
+ }
566
+
567
+ function isEncryptionProtocolMessage(message: GenericMessage): boolean {
568
+ const descriptor = message.descriptor as Record<string, unknown>;
569
+ return descriptor.interface === DwnInterfaceName.Records &&
570
+ descriptor.protocol === EncryptionProtocol.uri;
571
+ }
572
+
573
+ function roleContextPrefix(rolePath: string, contextId: string): string | undefined {
574
+ const roleSegments = rolePath.split('/').length - 1;
575
+ if (roleSegments === 0 || contextId === '') {
576
+ return undefined;
577
+ }
578
+
579
+ return contextId.split('/').slice(0, roleSegments).join('/');
580
+ }
581
+
582
+ function roleAudienceContextId(rolePath: string, contextId: string): string | undefined {
583
+ const roleSegments = rolePath.split('/').length - 1;
584
+ if (roleSegments === 0) {
585
+ return '';
586
+ }
587
+
588
+ const contextSegments = contextId.split('/');
589
+ if (contextSegments.length < roleSegments) {
590
+ return undefined;
591
+ }
592
+
593
+ return contextSegments.slice(0, roleSegments).join('/');
594
+ }
595
+
596
+ function isRecordObject(value: unknown): value is Record<string, unknown> {
597
+ return typeof value === 'object' && value !== null;
598
+ }
599
+
386
600
  function isRecordsWrite(message: GenericMessage): message is GenericMessage & { recordId: string } {
387
601
  return message.descriptor.interface === DwnInterfaceName.Records &&
388
602
  message.descriptor.method === DwnMethodName.Write &&