@enbox/dwn-sdk-js 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +352 -0
- package/dist/bundles/dwn.js +153 -0
- package/dist/cjs/index.js +36749 -0
- package/dist/cjs/package.json +1 -0
- package/dist/esm/generated/precompiled-validators.js +11973 -0
- package/dist/esm/generated/precompiled-validators.js.map +1 -0
- package/dist/esm/json-schemas/definitions.json +23 -0
- package/dist/esm/src/core/abstract-message.js +47 -0
- package/dist/esm/src/core/abstract-message.js.map +1 -0
- package/dist/esm/src/core/auth.js +39 -0
- package/dist/esm/src/core/auth.js.map +1 -0
- package/dist/esm/src/core/dwn-constant.js +10 -0
- package/dist/esm/src/core/dwn-constant.js.map +1 -0
- package/dist/esm/src/core/dwn-error.js +169 -0
- package/dist/esm/src/core/dwn-error.js.map +1 -0
- package/dist/esm/src/core/grant-authorization.js +97 -0
- package/dist/esm/src/core/grant-authorization.js.map +1 -0
- package/dist/esm/src/core/message-reply.js +5 -0
- package/dist/esm/src/core/message-reply.js.map +1 -0
- package/dist/esm/src/core/message.js +233 -0
- package/dist/esm/src/core/message.js.map +1 -0
- package/dist/esm/src/core/messages-grant-authorization.js +101 -0
- package/dist/esm/src/core/messages-grant-authorization.js.map +1 -0
- package/dist/esm/src/core/protocol-authorization.js +608 -0
- package/dist/esm/src/core/protocol-authorization.js.map +1 -0
- package/dist/esm/src/core/protocols-grant-authorization.js +66 -0
- package/dist/esm/src/core/protocols-grant-authorization.js.map +1 -0
- package/dist/esm/src/core/records-grant-authorization.js +132 -0
- package/dist/esm/src/core/records-grant-authorization.js.map +1 -0
- package/dist/esm/src/core/resumable-task-manager.js +109 -0
- package/dist/esm/src/core/resumable-task-manager.js.map +1 -0
- package/dist/esm/src/core/tenant-gate.js +20 -0
- package/dist/esm/src/core/tenant-gate.js.map +1 -0
- package/dist/esm/src/dwn.js +164 -0
- package/dist/esm/src/dwn.js.map +1 -0
- package/dist/esm/src/enums/dwn-interface-method.js +16 -0
- package/dist/esm/src/enums/dwn-interface-method.js.map +1 -0
- package/dist/esm/src/event-log/event-emitter-stream.js +60 -0
- package/dist/esm/src/event-log/event-emitter-stream.js.map +1 -0
- package/dist/esm/src/event-log/event-log-level.js +63 -0
- package/dist/esm/src/event-log/event-log-level.js.map +1 -0
- package/dist/esm/src/handlers/messages-query.js +71 -0
- package/dist/esm/src/handlers/messages-query.js.map +1 -0
- package/dist/esm/src/handlers/messages-read.js +102 -0
- package/dist/esm/src/handlers/messages-read.js.map +1 -0
- package/dist/esm/src/handlers/messages-subscribe.js +81 -0
- package/dist/esm/src/handlers/messages-subscribe.js.map +1 -0
- package/dist/esm/src/handlers/protocols-configure.js +133 -0
- package/dist/esm/src/handlers/protocols-configure.js.map +1 -0
- package/dist/esm/src/handlers/protocols-query.js +73 -0
- package/dist/esm/src/handlers/protocols-query.js.map +1 -0
- package/dist/esm/src/handlers/records-delete.js +107 -0
- package/dist/esm/src/handlers/records-delete.js.map +1 -0
- package/dist/esm/src/handlers/records-query.js +210 -0
- package/dist/esm/src/handlers/records-query.js.map +1 -0
- package/dist/esm/src/handlers/records-read.js +169 -0
- package/dist/esm/src/handlers/records-read.js.map +1 -0
- package/dist/esm/src/handlers/records-subscribe.js +172 -0
- package/dist/esm/src/handlers/records-subscribe.js.map +1 -0
- package/dist/esm/src/handlers/records-write.js +344 -0
- package/dist/esm/src/handlers/records-write.js.map +1 -0
- package/dist/esm/src/index.js +49 -0
- package/dist/esm/src/index.js.map +1 -0
- package/dist/esm/src/interfaces/messages-query.js +53 -0
- package/dist/esm/src/interfaces/messages-query.js.map +1 -0
- package/dist/esm/src/interfaces/messages-read.js +61 -0
- package/dist/esm/src/interfaces/messages-read.js.map +1 -0
- package/dist/esm/src/interfaces/messages-subscribe.js +58 -0
- package/dist/esm/src/interfaces/messages-subscribe.js.map +1 -0
- package/dist/esm/src/interfaces/protocols-configure.js +271 -0
- package/dist/esm/src/interfaces/protocols-configure.js.map +1 -0
- package/dist/esm/src/interfaces/protocols-query.js +84 -0
- package/dist/esm/src/interfaces/protocols-query.js.map +1 -0
- package/dist/esm/src/interfaces/records-delete.js +89 -0
- package/dist/esm/src/interfaces/records-delete.js.map +1 -0
- package/dist/esm/src/interfaces/records-query.js +104 -0
- package/dist/esm/src/interfaces/records-query.js.map +1 -0
- package/dist/esm/src/interfaces/records-read.js +84 -0
- package/dist/esm/src/interfaces/records-read.js.map +1 -0
- package/dist/esm/src/interfaces/records-subscribe.js +91 -0
- package/dist/esm/src/interfaces/records-subscribe.js.map +1 -0
- package/dist/esm/src/interfaces/records-write.js +795 -0
- package/dist/esm/src/interfaces/records-write.js.map +1 -0
- package/dist/esm/src/jose/algorithms/signing/ed25519.js +51 -0
- package/dist/esm/src/jose/algorithms/signing/ed25519.js.map +1 -0
- package/dist/esm/src/jose/algorithms/signing/signature-algorithms.js +20 -0
- package/dist/esm/src/jose/algorithms/signing/signature-algorithms.js.map +1 -0
- package/dist/esm/src/jose/jws/general/builder.js +47 -0
- package/dist/esm/src/jose/jws/general/builder.js.map +1 -0
- package/dist/esm/src/jose/jws/general/verifier.js +97 -0
- package/dist/esm/src/jose/jws/general/verifier.js.map +1 -0
- package/dist/esm/src/protocols/permission-grant.js +39 -0
- package/dist/esm/src/protocols/permission-grant.js.map +1 -0
- package/dist/esm/src/protocols/permission-request.js +35 -0
- package/dist/esm/src/protocols/permission-request.js.map +1 -0
- package/dist/esm/src/protocols/permissions.js +357 -0
- package/dist/esm/src/protocols/permissions.js.map +1 -0
- package/dist/esm/src/schema-validator.js +37 -0
- package/dist/esm/src/schema-validator.js.map +1 -0
- package/dist/esm/src/store/blockstore-level.js +187 -0
- package/dist/esm/src/store/blockstore-level.js.map +1 -0
- package/dist/esm/src/store/blockstore-mock.js +168 -0
- package/dist/esm/src/store/blockstore-mock.js.map +1 -0
- package/dist/esm/src/store/data-store-level.js +136 -0
- package/dist/esm/src/store/data-store-level.js.map +1 -0
- package/dist/esm/src/store/index-level.js +660 -0
- package/dist/esm/src/store/index-level.js.map +1 -0
- package/dist/esm/src/store/level-wrapper.js +305 -0
- package/dist/esm/src/store/level-wrapper.js.map +1 -0
- package/dist/esm/src/store/message-store-level.js +159 -0
- package/dist/esm/src/store/message-store-level.js.map +1 -0
- package/dist/esm/src/store/resumable-task-store-level.js +131 -0
- package/dist/esm/src/store/resumable-task-store-level.js.map +1 -0
- package/dist/esm/src/store/storage-controller.js +184 -0
- package/dist/esm/src/store/storage-controller.js.map +1 -0
- package/dist/esm/src/types/cache.js +2 -0
- package/dist/esm/src/types/cache.js.map +1 -0
- package/dist/esm/src/types/data-store.js +2 -0
- package/dist/esm/src/types/data-store.js.map +1 -0
- package/dist/esm/src/types/event-log.js +2 -0
- package/dist/esm/src/types/event-log.js.map +1 -0
- package/dist/esm/src/types/jose-types.js +2 -0
- package/dist/esm/src/types/jose-types.js.map +1 -0
- package/dist/esm/src/types/jws-types.js +2 -0
- package/dist/esm/src/types/jws-types.js.map +1 -0
- package/dist/esm/src/types/message-interface.js +2 -0
- package/dist/esm/src/types/message-interface.js.map +1 -0
- package/dist/esm/src/types/message-store.js +2 -0
- package/dist/esm/src/types/message-store.js.map +1 -0
- package/dist/esm/src/types/message-types.js +3 -0
- package/dist/esm/src/types/message-types.js.map +1 -0
- package/dist/esm/src/types/messages-types.js +2 -0
- package/dist/esm/src/types/messages-types.js.map +1 -0
- package/dist/esm/src/types/method-handler.js +2 -0
- package/dist/esm/src/types/method-handler.js.map +1 -0
- package/dist/esm/src/types/permission-types.js +6 -0
- package/dist/esm/src/types/permission-types.js.map +1 -0
- package/dist/esm/src/types/protocols-types.js +20 -0
- package/dist/esm/src/types/protocols-types.js.map +1 -0
- package/dist/esm/src/types/query-types.js +6 -0
- package/dist/esm/src/types/query-types.js.map +1 -0
- package/dist/esm/src/types/records-types.js +8 -0
- package/dist/esm/src/types/records-types.js.map +1 -0
- package/dist/esm/src/types/resumable-task-store.js +2 -0
- package/dist/esm/src/types/resumable-task-store.js.map +1 -0
- package/dist/esm/src/types/signer.js +2 -0
- package/dist/esm/src/types/signer.js.map +1 -0
- package/dist/esm/src/types/subscriptions.js +2 -0
- package/dist/esm/src/types/subscriptions.js.map +1 -0
- package/dist/esm/src/utils/abort.js +40 -0
- package/dist/esm/src/utils/abort.js.map +1 -0
- package/dist/esm/src/utils/array.js +72 -0
- package/dist/esm/src/utils/array.js.map +1 -0
- package/dist/esm/src/utils/cid.js +130 -0
- package/dist/esm/src/utils/cid.js.map +1 -0
- package/dist/esm/src/utils/data-stream.js +100 -0
- package/dist/esm/src/utils/data-stream.js.map +1 -0
- package/dist/esm/src/utils/encoder.js +45 -0
- package/dist/esm/src/utils/encoder.js.map +1 -0
- package/dist/esm/src/utils/encryption.js +128 -0
- package/dist/esm/src/utils/encryption.js.map +1 -0
- package/dist/esm/src/utils/filter.js +229 -0
- package/dist/esm/src/utils/filter.js.map +1 -0
- package/dist/esm/src/utils/hd-key.js +114 -0
- package/dist/esm/src/utils/hd-key.js.map +1 -0
- package/dist/esm/src/utils/jws.js +89 -0
- package/dist/esm/src/utils/jws.js.map +1 -0
- package/dist/esm/src/utils/memory-cache.js +41 -0
- package/dist/esm/src/utils/memory-cache.js.map +1 -0
- package/dist/esm/src/utils/messages.js +84 -0
- package/dist/esm/src/utils/messages.js.map +1 -0
- package/dist/esm/src/utils/object.js +40 -0
- package/dist/esm/src/utils/object.js.map +1 -0
- package/dist/esm/src/utils/private-key-signer.js +43 -0
- package/dist/esm/src/utils/private-key-signer.js.map +1 -0
- package/dist/esm/src/utils/protocols.js +51 -0
- package/dist/esm/src/utils/protocols.js.map +1 -0
- package/dist/esm/src/utils/records.js +454 -0
- package/dist/esm/src/utils/records.js.map +1 -0
- package/dist/esm/src/utils/secp256k1.js +166 -0
- package/dist/esm/src/utils/secp256k1.js.map +1 -0
- package/dist/esm/src/utils/secp256r1.js +120 -0
- package/dist/esm/src/utils/secp256r1.js.map +1 -0
- package/dist/esm/src/utils/string.js +16 -0
- package/dist/esm/src/utils/string.js.map +1 -0
- package/dist/esm/src/utils/time.js +85 -0
- package/dist/esm/src/utils/time.js.map +1 -0
- package/dist/esm/src/utils/url.js +62 -0
- package/dist/esm/src/utils/url.js.map +1 -0
- package/dist/esm/tests/core/auth.spec.js +22 -0
- package/dist/esm/tests/core/auth.spec.js.map +1 -0
- package/dist/esm/tests/core/message-reply.spec.js +16 -0
- package/dist/esm/tests/core/message-reply.spec.js.map +1 -0
- package/dist/esm/tests/core/message.spec.js +146 -0
- package/dist/esm/tests/core/message.spec.js.map +1 -0
- package/dist/esm/tests/core/protocol-authorization.spec.js +48 -0
- package/dist/esm/tests/core/protocol-authorization.spec.js.map +1 -0
- package/dist/esm/tests/dwn.spec.js +166 -0
- package/dist/esm/tests/dwn.spec.js.map +1 -0
- package/dist/esm/tests/event-log/event-emitter-stream.spec.js +78 -0
- package/dist/esm/tests/event-log/event-emitter-stream.spec.js.map +1 -0
- package/dist/esm/tests/event-log/event-log-level.spec.js +44 -0
- package/dist/esm/tests/event-log/event-log-level.spec.js.map +1 -0
- package/dist/esm/tests/event-log/event-log.spec.js +236 -0
- package/dist/esm/tests/event-log/event-log.spec.js.map +1 -0
- package/dist/esm/tests/event-log/event-stream.spec.js +125 -0
- package/dist/esm/tests/event-log/event-stream.spec.js.map +1 -0
- package/dist/esm/tests/features/author-delegated-grant.spec.js +1273 -0
- package/dist/esm/tests/features/author-delegated-grant.spec.js.map +1 -0
- package/dist/esm/tests/features/owner-delegated-grant.spec.js +584 -0
- package/dist/esm/tests/features/owner-delegated-grant.spec.js.map +1 -0
- package/dist/esm/tests/features/owner-signature.spec.js +192 -0
- package/dist/esm/tests/features/owner-signature.spec.js.map +1 -0
- package/dist/esm/tests/features/permissions.spec.js +815 -0
- package/dist/esm/tests/features/permissions.spec.js.map +1 -0
- package/dist/esm/tests/features/protocol-create-action.spec.js +248 -0
- package/dist/esm/tests/features/protocol-create-action.spec.js.map +1 -0
- package/dist/esm/tests/features/protocol-delete-action.spec.js +492 -0
- package/dist/esm/tests/features/protocol-delete-action.spec.js.map +1 -0
- package/dist/esm/tests/features/protocol-update-action.spec.js +572 -0
- package/dist/esm/tests/features/protocol-update-action.spec.js.map +1 -0
- package/dist/esm/tests/features/records-prune.spec.js +812 -0
- package/dist/esm/tests/features/records-prune.spec.js.map +1 -0
- package/dist/esm/tests/features/records-tags.spec.js +2516 -0
- package/dist/esm/tests/features/records-tags.spec.js.map +1 -0
- package/dist/esm/tests/features/resumable-tasks.spec.js +349 -0
- package/dist/esm/tests/features/resumable-tasks.spec.js.map +1 -0
- package/dist/esm/tests/handlers/messages-query.spec.js +349 -0
- package/dist/esm/tests/handlers/messages-query.spec.js.map +1 -0
- package/dist/esm/tests/handlers/messages-read.spec.js +647 -0
- package/dist/esm/tests/handlers/messages-read.spec.js.map +1 -0
- package/dist/esm/tests/handlers/messages-subscribe.spec.js +432 -0
- package/dist/esm/tests/handlers/messages-subscribe.spec.js.map +1 -0
- package/dist/esm/tests/handlers/protocols-configure.spec.js +608 -0
- package/dist/esm/tests/handlers/protocols-configure.spec.js.map +1 -0
- package/dist/esm/tests/handlers/protocols-query.spec.js +454 -0
- package/dist/esm/tests/handlers/protocols-query.spec.js.map +1 -0
- package/dist/esm/tests/handlers/records-delete.spec.js +662 -0
- package/dist/esm/tests/handlers/records-delete.spec.js.map +1 -0
- package/dist/esm/tests/handlers/records-query.spec.js +2695 -0
- package/dist/esm/tests/handlers/records-query.spec.js.map +1 -0
- package/dist/esm/tests/handlers/records-read.spec.js +1724 -0
- package/dist/esm/tests/handlers/records-read.spec.js.map +1 -0
- package/dist/esm/tests/handlers/records-subscribe.spec.js +684 -0
- package/dist/esm/tests/handlers/records-subscribe.spec.js.map +1 -0
- package/dist/esm/tests/handlers/records-write.spec.js +3637 -0
- package/dist/esm/tests/handlers/records-write.spec.js.map +1 -0
- package/dist/esm/tests/interfaces/messages-get.spec.js +78 -0
- package/dist/esm/tests/interfaces/messages-get.spec.js.map +1 -0
- package/dist/esm/tests/interfaces/messages-subscribe.spec.js +30 -0
- package/dist/esm/tests/interfaces/messages-subscribe.spec.js.map +1 -0
- package/dist/esm/tests/interfaces/messagess-query.spec.js +127 -0
- package/dist/esm/tests/interfaces/messagess-query.spec.js.map +1 -0
- package/dist/esm/tests/interfaces/protocols-configure.spec.js +489 -0
- package/dist/esm/tests/interfaces/protocols-configure.spec.js.map +1 -0
- package/dist/esm/tests/interfaces/protocols-query.spec.js +46 -0
- package/dist/esm/tests/interfaces/protocols-query.spec.js.map +1 -0
- package/dist/esm/tests/interfaces/records-delete.spec.js +39 -0
- package/dist/esm/tests/interfaces/records-delete.spec.js.map +1 -0
- package/dist/esm/tests/interfaces/records-query.spec.js +85 -0
- package/dist/esm/tests/interfaces/records-query.spec.js.map +1 -0
- package/dist/esm/tests/interfaces/records-read.spec.js +62 -0
- package/dist/esm/tests/interfaces/records-read.spec.js.map +1 -0
- package/dist/esm/tests/interfaces/records-subscribe.spec.js +72 -0
- package/dist/esm/tests/interfaces/records-subscribe.spec.js.map +1 -0
- package/dist/esm/tests/interfaces/records-write.spec.js +423 -0
- package/dist/esm/tests/interfaces/records-write.spec.js.map +1 -0
- package/dist/esm/tests/jose/jws/general.spec.js +243 -0
- package/dist/esm/tests/jose/jws/general.spec.js.map +1 -0
- package/dist/esm/tests/protocols/permission-request.spec.js +40 -0
- package/dist/esm/tests/protocols/permission-request.spec.js.map +1 -0
- package/dist/esm/tests/protocols/permissions.spec.js +123 -0
- package/dist/esm/tests/protocols/permissions.spec.js.map +1 -0
- package/dist/esm/tests/scenarios/aggregator.spec.js +670 -0
- package/dist/esm/tests/scenarios/aggregator.spec.js.map +1 -0
- package/dist/esm/tests/scenarios/deleted-record.spec.js +102 -0
- package/dist/esm/tests/scenarios/deleted-record.spec.js.map +1 -0
- package/dist/esm/tests/scenarios/end-to-end-tests.spec.js +220 -0
- package/dist/esm/tests/scenarios/end-to-end-tests.spec.js.map +1 -0
- package/dist/esm/tests/scenarios/messages-query.spec.js +395 -0
- package/dist/esm/tests/scenarios/messages-query.spec.js.map +1 -0
- package/dist/esm/tests/scenarios/nested-roles.spec.js +300 -0
- package/dist/esm/tests/scenarios/nested-roles.spec.js.map +1 -0
- package/dist/esm/tests/scenarios/subscriptions.spec.js +886 -0
- package/dist/esm/tests/scenarios/subscriptions.spec.js.map +1 -0
- package/dist/esm/tests/store/blockstore-mock.spec.js +192 -0
- package/dist/esm/tests/store/blockstore-mock.spec.js.map +1 -0
- package/dist/esm/tests/store/data-store-level.spec.js +146 -0
- package/dist/esm/tests/store/data-store-level.spec.js.map +1 -0
- package/dist/esm/tests/store/index-level.spec.js +1208 -0
- package/dist/esm/tests/store/index-level.spec.js.map +1 -0
- package/dist/esm/tests/store/message-store-level.spec.js +48 -0
- package/dist/esm/tests/store/message-store-level.spec.js.map +1 -0
- package/dist/esm/tests/store/message-store.spec.js +404 -0
- package/dist/esm/tests/store/message-store.spec.js.map +1 -0
- package/dist/esm/tests/store-dependent-tests.spec.js +5 -0
- package/dist/esm/tests/store-dependent-tests.spec.js.map +1 -0
- package/dist/esm/tests/test-event-stream.js +25 -0
- package/dist/esm/tests/test-event-stream.js.map +1 -0
- package/dist/esm/tests/test-stores.js +45 -0
- package/dist/esm/tests/test-stores.js.map +1 -0
- package/dist/esm/tests/test-suite.js +88 -0
- package/dist/esm/tests/test-suite.js.map +1 -0
- package/dist/esm/tests/utils/cid.spec.js +80 -0
- package/dist/esm/tests/utils/cid.spec.js.map +1 -0
- package/dist/esm/tests/utils/data-stream.spec.js +27 -0
- package/dist/esm/tests/utils/data-stream.spec.js.map +1 -0
- package/dist/esm/tests/utils/encryption.spec.js +148 -0
- package/dist/esm/tests/utils/encryption.spec.js.map +1 -0
- package/dist/esm/tests/utils/filters.spec.js +295 -0
- package/dist/esm/tests/utils/filters.spec.js.map +1 -0
- package/dist/esm/tests/utils/hd-key.spec.js +35 -0
- package/dist/esm/tests/utils/hd-key.spec.js.map +1 -0
- package/dist/esm/tests/utils/jws.spec.js +8 -0
- package/dist/esm/tests/utils/jws.spec.js.map +1 -0
- package/dist/esm/tests/utils/memory-cache.spec.js +35 -0
- package/dist/esm/tests/utils/memory-cache.spec.js.map +1 -0
- package/dist/esm/tests/utils/messages.spec.js +101 -0
- package/dist/esm/tests/utils/messages.spec.js.map +1 -0
- package/dist/esm/tests/utils/object.spec.js +36 -0
- package/dist/esm/tests/utils/object.spec.js.map +1 -0
- package/dist/esm/tests/utils/poller.js +49 -0
- package/dist/esm/tests/utils/poller.js.map +1 -0
- package/dist/esm/tests/utils/private-key-signer.spec.js +44 -0
- package/dist/esm/tests/utils/private-key-signer.spec.js.map +1 -0
- package/dist/esm/tests/utils/records.spec.js +53 -0
- package/dist/esm/tests/utils/records.spec.js.map +1 -0
- package/dist/esm/tests/utils/secp256k1.spec.js +50 -0
- package/dist/esm/tests/utils/secp256k1.spec.js.map +1 -0
- package/dist/esm/tests/utils/secp256r1.spec.js +56 -0
- package/dist/esm/tests/utils/secp256r1.spec.js.map +1 -0
- package/dist/esm/tests/utils/test-data-generator.js +643 -0
- package/dist/esm/tests/utils/test-data-generator.js.map +1 -0
- package/dist/esm/tests/utils/test-stub-generator.js +39 -0
- package/dist/esm/tests/utils/test-stub-generator.js.map +1 -0
- package/dist/esm/tests/utils/time.spec.js +64 -0
- package/dist/esm/tests/utils/time.spec.js.map +1 -0
- package/dist/esm/tests/utils/url.spec.js +43 -0
- package/dist/esm/tests/utils/url.spec.js.map +1 -0
- package/dist/esm/tests/validation/json-schemas/definitions.spec.js +33 -0
- package/dist/esm/tests/validation/json-schemas/definitions.spec.js.map +1 -0
- package/dist/esm/tests/validation/json-schemas/jwk/general-jwk.spec.js +50 -0
- package/dist/esm/tests/validation/json-schemas/jwk/general-jwk.spec.js.map +1 -0
- package/dist/esm/tests/validation/json-schemas/jwk/public-jwk.spec.js +36 -0
- package/dist/esm/tests/validation/json-schemas/jwk/public-jwk.spec.js.map +1 -0
- package/dist/esm/tests/validation/json-schemas/jwk-verification-method.spec.js +82 -0
- package/dist/esm/tests/validation/json-schemas/jwk-verification-method.spec.js.map +1 -0
- package/dist/esm/tests/validation/json-schemas/protocols/protocols-configure.spec.js +75 -0
- package/dist/esm/tests/validation/json-schemas/protocols/protocols-configure.spec.js.map +1 -0
- package/dist/esm/tests/validation/json-schemas/records/records-query.spec.js +148 -0
- package/dist/esm/tests/validation/json-schemas/records/records-query.spec.js.map +1 -0
- package/dist/esm/tests/validation/json-schemas/records/records-write.spec.js +421 -0
- package/dist/esm/tests/validation/json-schemas/records/records-write.spec.js.map +1 -0
- package/dist/esm/tests/vectors/protocol-definitions/anyone-collaborate.json +21 -0
- package/dist/esm/tests/vectors/protocol-definitions/author-can.json +33 -0
- package/dist/esm/tests/vectors/protocol-definitions/chat.json +70 -0
- package/dist/esm/tests/vectors/protocol-definitions/credential-issuance.json +41 -0
- package/dist/esm/tests/vectors/protocol-definitions/dex.json +58 -0
- package/dist/esm/tests/vectors/protocol-definitions/email.json +62 -0
- package/dist/esm/tests/vectors/protocol-definitions/free-for-all.json +45 -0
- package/dist/esm/tests/vectors/protocol-definitions/friend-role.json +48 -0
- package/dist/esm/tests/vectors/protocol-definitions/message.json +37 -0
- package/dist/esm/tests/vectors/protocol-definitions/minimal.json +10 -0
- package/dist/esm/tests/vectors/protocol-definitions/nested.json +31 -0
- package/dist/esm/tests/vectors/protocol-definitions/private-protocol.json +15 -0
- package/dist/esm/tests/vectors/protocol-definitions/recipient-can.json +33 -0
- package/dist/esm/tests/vectors/protocol-definitions/slack.json +242 -0
- package/dist/esm/tests/vectors/protocol-definitions/social-media.json +106 -0
- package/dist/esm/tests/vectors/protocol-definitions/thread-role.json +70 -0
- package/dist/types/generated/precompiled-validators.d.ts +597 -0
- package/dist/types/generated/precompiled-validators.d.ts.map +1 -0
- package/dist/types/src/core/abstract-message.d.ts +25 -0
- package/dist/types/src/core/abstract-message.d.ts.map +1 -0
- package/dist/types/src/core/auth.d.ts +9 -0
- package/dist/types/src/core/auth.d.ts.map +1 -0
- package/dist/types/src/core/dwn-constant.d.ts +10 -0
- package/dist/types/src/core/dwn-constant.d.ts.map +1 -0
- package/dist/types/src/core/dwn-error.d.ts +164 -0
- package/dist/types/src/core/dwn-error.d.ts.map +1 -0
- package/dist/types/src/core/grant-authorization.d.ts +43 -0
- package/dist/types/src/core/grant-authorization.d.ts.map +1 -0
- package/dist/types/src/core/message-reply.d.ts +32 -0
- package/dist/types/src/core/message-reply.d.ts.map +1 -0
- package/dist/types/src/core/message.d.ts +94 -0
- package/dist/types/src/core/message.d.ts.map +1 -0
- package/dist/types/src/core/messages-grant-authorization.d.ts +34 -0
- package/dist/types/src/core/messages-grant-authorization.d.ts.map +1 -0
- package/dist/types/src/core/protocol-authorization.d.ts +103 -0
- package/dist/types/src/core/protocol-authorization.d.ts.map +1 -0
- package/dist/types/src/core/protocols-grant-authorization.d.ts +31 -0
- package/dist/types/src/core/protocols-grant-authorization.d.ts.map +1 -0
- package/dist/types/src/core/records-grant-authorization.d.ts +60 -0
- package/dist/types/src/core/records-grant-authorization.d.ts.map +1 -0
- package/dist/types/src/core/resumable-task-manager.d.ts +43 -0
- package/dist/types/src/core/resumable-task-manager.d.ts.map +1 -0
- package/dist/types/src/core/tenant-gate.d.ts +29 -0
- package/dist/types/src/core/tenant-gate.d.ts.map +1 -0
- package/dist/types/src/dwn.d.ts +85 -0
- package/dist/types/src/dwn.d.ts.map +1 -0
- package/dist/types/src/enums/dwn-interface-method.d.ts +14 -0
- package/dist/types/src/enums/dwn-interface-method.d.ts.map +1 -0
- package/dist/types/src/event-log/event-emitter-stream.d.ts +23 -0
- package/dist/types/src/event-log/event-emitter-stream.d.ts.map +1 -0
- package/dist/types/src/event-log/event-log-level.d.ts +35 -0
- package/dist/types/src/event-log/event-log-level.d.ts.map +1 -0
- package/dist/types/src/handlers/messages-query.d.ts +17 -0
- package/dist/types/src/handlers/messages-query.d.ts.map +1 -0
- package/dist/types/src/handlers/messages-read.d.ts +22 -0
- package/dist/types/src/handlers/messages-read.d.ts.map +1 -0
- package/dist/types/src/handlers/messages-subscribe.d.ts +18 -0
- package/dist/types/src/handlers/messages-subscribe.d.ts.map +1 -0
- package/dist/types/src/handlers/protocols-configure.d.ts +24 -0
- package/dist/types/src/handlers/protocols-configure.d.ts.map +1 -0
- package/dist/types/src/handlers/protocols-query.d.ts +20 -0
- package/dist/types/src/handlers/protocols-query.d.ts.map +1 -0
- package/dist/types/src/handlers/records-delete.d.ts +23 -0
- package/dist/types/src/handlers/records-delete.d.ts.map +1 -0
- package/dist/types/src/handlers/records-query.d.ts +70 -0
- package/dist/types/src/handlers/records-query.d.ts.map +1 -0
- package/dist/types/src/handlers/records-read.d.ts +20 -0
- package/dist/types/src/handlers/records-read.d.ts.map +1 -0
- package/dist/types/src/handlers/records-subscribe.d.ts +62 -0
- package/dist/types/src/handlers/records-subscribe.d.ts.map +1 -0
- package/dist/types/src/handlers/records-write.d.ts +51 -0
- package/dist/types/src/handlers/records-write.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +63 -0
- package/dist/types/src/index.d.ts.map +1 -0
- package/dist/types/src/interfaces/messages-query.d.ts +16 -0
- package/dist/types/src/interfaces/messages-query.d.ts.map +1 -0
- package/dist/types/src/interfaces/messages-read.d.ts +20 -0
- package/dist/types/src/interfaces/messages-read.d.ts.map +1 -0
- package/dist/types/src/interfaces/messages-subscribe.d.ts +20 -0
- package/dist/types/src/interfaces/messages-subscribe.d.ts.map +1 -0
- package/dist/types/src/interfaces/protocols-configure.d.ts +40 -0
- package/dist/types/src/interfaces/protocols-configure.d.ts.map +1 -0
- package/dist/types/src/interfaces/protocols-query.d.ts +17 -0
- package/dist/types/src/interfaces/protocols-query.d.ts.map +1 -0
- package/dist/types/src/interfaces/records-delete.d.ts +34 -0
- package/dist/types/src/interfaces/records-delete.d.ts.map +1 -0
- package/dist/types/src/interfaces/records-query.d.ts +31 -0
- package/dist/types/src/interfaces/records-query.d.ts.map +1 -0
- package/dist/types/src/interfaces/records-read.d.ts +36 -0
- package/dist/types/src/interfaces/records-read.d.ts.map +1 -0
- package/dist/types/src/interfaces/records-subscribe.d.ts +27 -0
- package/dist/types/src/interfaces/records-subscribe.d.ts.map +1 -0
- package/dist/types/src/interfaces/records-write.d.ts +309 -0
- package/dist/types/src/interfaces/records-write.d.ts.map +1 -0
- package/dist/types/src/jose/algorithms/signing/ed25519.d.ts +3 -0
- package/dist/types/src/jose/algorithms/signing/ed25519.d.ts.map +1 -0
- package/dist/types/src/jose/algorithms/signing/signature-algorithms.d.ts +3 -0
- package/dist/types/src/jose/algorithms/signing/signature-algorithms.d.ts.map +1 -0
- package/dist/types/src/jose/jws/general/builder.d.ts +10 -0
- package/dist/types/src/jose/jws/general/builder.d.ts.map +1 -0
- package/dist/types/src/jose/jws/general/verifier.d.ts +32 -0
- package/dist/types/src/jose/jws/general/verifier.d.ts.map +1 -0
- package/dist/types/src/protocols/permission-grant.d.ts +50 -0
- package/dist/types/src/protocols/permission-grant.d.ts.map +1 -0
- package/dist/types/src/protocols/permission-request.d.ts +35 -0
- package/dist/types/src/protocols/permission-request.d.ts.map +1 -0
- package/dist/types/src/protocols/permissions.d.ts +150 -0
- package/dist/types/src/protocols/permissions.d.ts.map +1 -0
- package/dist/types/src/schema-validator.d.ts +8 -0
- package/dist/types/src/schema-validator.d.ts.map +1 -0
- package/dist/types/src/store/blockstore-level.d.ts +34 -0
- package/dist/types/src/store/blockstore-level.d.ts.map +1 -0
- package/dist/types/src/store/blockstore-mock.d.ts +27 -0
- package/dist/types/src/store/blockstore-mock.d.ts.map +1 -0
- package/dist/types/src/store/data-store-level.d.ts +34 -0
- package/dist/types/src/store/data-store-level.d.ts.map +1 -0
- package/dist/types/src/store/index-level.d.ts +171 -0
- package/dist/types/src/store/index-level.d.ts.map +1 -0
- package/dist/types/src/store/level-wrapper.d.ts +48 -0
- package/dist/types/src/store/level-wrapper.d.ts.map +1 -0
- package/dist/types/src/store/message-store-level.d.ts +46 -0
- package/dist/types/src/store/message-store-level.d.ts.map +1 -0
- package/dist/types/src/store/resumable-task-store-level.d.ts +28 -0
- package/dist/types/src/store/resumable-task-store-level.d.ts.map +1 -0
- package/dist/types/src/store/storage-controller.d.ts +46 -0
- package/dist/types/src/store/storage-controller.d.ts.map +1 -0
- package/dist/types/src/types/cache.d.ts +16 -0
- package/dist/types/src/types/cache.d.ts.map +1 -0
- package/dist/types/src/types/data-store.d.ts +57 -0
- package/dist/types/src/types/data-store.d.ts.map +1 -0
- package/dist/types/src/types/event-log.d.ts +52 -0
- package/dist/types/src/types/event-log.d.ts.map +1 -0
- package/dist/types/src/types/jose-types.d.ts +75 -0
- package/dist/types/src/types/jose-types.d.ts.map +1 -0
- package/dist/types/src/types/jws-types.d.ts +27 -0
- package/dist/types/src/types/jws-types.d.ts.map +1 -0
- package/dist/types/src/types/message-interface.d.ts +27 -0
- package/dist/types/src/types/message-interface.d.ts.map +1 -0
- package/dist/types/src/types/message-store.d.ts +42 -0
- package/dist/types/src/types/message-store.d.ts.map +1 -0
- package/dist/types/src/types/message-types.d.ts +116 -0
- package/dist/types/src/types/message-types.d.ts.map +1 -0
- package/dist/types/src/types/messages-types.d.ts +65 -0
- package/dist/types/src/types/messages-types.d.ts.map +1 -0
- package/dist/types/src/types/method-handler.d.ts +19 -0
- package/dist/types/src/types/method-handler.d.ts.map +1 -0
- package/dist/types/src/types/permission-types.d.ts +93 -0
- package/dist/types/src/types/permission-types.d.ts.map +1 -0
- package/dist/types/src/types/protocols-types.d.ts +154 -0
- package/dist/types/src/types/protocols-types.d.ts.map +1 -0
- package/dist/types/src/types/query-types.d.ts +66 -0
- package/dist/types/src/types/query-types.d.ts.map +1 -0
- package/dist/types/src/types/records-types.d.ts +230 -0
- package/dist/types/src/types/records-types.d.ts.map +1 -0
- package/dist/types/src/types/resumable-task-store.d.ts +89 -0
- package/dist/types/src/types/resumable-task-store.d.ts.map +1 -0
- package/dist/types/src/types/signer.d.ts +26 -0
- package/dist/types/src/types/signer.d.ts.map +1 -0
- package/dist/types/src/types/subscriptions.d.ts +30 -0
- package/dist/types/src/types/subscriptions.d.ts.map +1 -0
- package/dist/types/src/utils/abort.d.ts +5 -0
- package/dist/types/src/utils/abort.d.ts.map +1 -0
- package/dist/types/src/utils/array.d.ts +18 -0
- package/dist/types/src/utils/array.d.ts.map +1 -0
- package/dist/types/src/utils/cid.d.ts +30 -0
- package/dist/types/src/utils/cid.d.ts.map +1 -0
- package/dist/types/src/utils/data-stream.d.ts +31 -0
- package/dist/types/src/utils/data-stream.d.ts.map +1 -0
- package/dist/types/src/utils/encoder.d.ts +14 -0
- package/dist/types/src/utils/encoder.d.ts.map +1 -0
- package/dist/types/src/utils/encryption.d.ts +44 -0
- package/dist/types/src/utils/encryption.d.ts.map +1 -0
- package/dist/types/src/utils/filter.d.ts +60 -0
- package/dist/types/src/utils/filter.d.ts.map +1 -0
- package/dist/types/src/utils/hd-key.d.ts +54 -0
- package/dist/types/src/utils/hd-key.d.ts.map +1 -0
- package/dist/types/src/utils/jws.d.ts +39 -0
- package/dist/types/src/utils/jws.d.ts.map +1 -0
- package/dist/types/src/utils/memory-cache.d.ts +15 -0
- package/dist/types/src/utils/memory-cache.d.ts.map +1 -0
- package/dist/types/src/utils/messages.d.ts +27 -0
- package/dist/types/src/utils/messages.d.ts.map +1 -0
- package/dist/types/src/utils/object.d.ts +13 -0
- package/dist/types/src/utils/object.d.ts.map +1 -0
- package/dist/types/src/utils/private-key-signer.d.ts +34 -0
- package/dist/types/src/utils/private-key-signer.d.ts.map +1 -0
- package/dist/types/src/utils/protocols.d.ts +14 -0
- package/dist/types/src/utils/protocols.d.ts.map +1 -0
- package/dist/types/src/utils/records.d.ts +122 -0
- package/dist/types/src/utils/records.d.ts.map +1 -0
- package/dist/types/src/utils/secp256k1.d.ts +59 -0
- package/dist/types/src/utils/secp256k1.d.ts.map +1 -0
- package/dist/types/src/utils/secp256r1.d.ts +39 -0
- package/dist/types/src/utils/secp256r1.d.ts.map +1 -0
- package/dist/types/src/utils/string.d.ts +6 -0
- package/dist/types/src/utils/string.d.ts.map +1 -0
- package/dist/types/src/utils/time.d.ts +50 -0
- package/dist/types/src/utils/time.d.ts.map +1 -0
- package/dist/types/src/utils/url.d.ts +5 -0
- package/dist/types/src/utils/url.d.ts.map +1 -0
- package/dist/types/tests/core/auth.spec.d.ts +2 -0
- package/dist/types/tests/core/auth.spec.d.ts.map +1 -0
- package/dist/types/tests/core/message-reply.spec.d.ts +2 -0
- package/dist/types/tests/core/message-reply.spec.d.ts.map +1 -0
- package/dist/types/tests/core/message.spec.d.ts +2 -0
- package/dist/types/tests/core/message.spec.d.ts.map +1 -0
- package/dist/types/tests/core/protocol-authorization.spec.d.ts +2 -0
- package/dist/types/tests/core/protocol-authorization.spec.d.ts.map +1 -0
- package/dist/types/tests/dwn.spec.d.ts +2 -0
- package/dist/types/tests/dwn.spec.d.ts.map +1 -0
- package/dist/types/tests/event-log/event-emitter-stream.spec.d.ts +2 -0
- package/dist/types/tests/event-log/event-emitter-stream.spec.d.ts.map +1 -0
- package/dist/types/tests/event-log/event-log-level.spec.d.ts +2 -0
- package/dist/types/tests/event-log/event-log-level.spec.d.ts.map +1 -0
- package/dist/types/tests/event-log/event-log.spec.d.ts +2 -0
- package/dist/types/tests/event-log/event-log.spec.d.ts.map +1 -0
- package/dist/types/tests/event-log/event-stream.spec.d.ts +2 -0
- package/dist/types/tests/event-log/event-stream.spec.d.ts.map +1 -0
- package/dist/types/tests/features/author-delegated-grant.spec.d.ts +2 -0
- package/dist/types/tests/features/author-delegated-grant.spec.d.ts.map +1 -0
- package/dist/types/tests/features/owner-delegated-grant.spec.d.ts +2 -0
- package/dist/types/tests/features/owner-delegated-grant.spec.d.ts.map +1 -0
- package/dist/types/tests/features/owner-signature.spec.d.ts +2 -0
- package/dist/types/tests/features/owner-signature.spec.d.ts.map +1 -0
- package/dist/types/tests/features/permissions.spec.d.ts +2 -0
- package/dist/types/tests/features/permissions.spec.d.ts.map +1 -0
- package/dist/types/tests/features/protocol-create-action.spec.d.ts +2 -0
- package/dist/types/tests/features/protocol-create-action.spec.d.ts.map +1 -0
- package/dist/types/tests/features/protocol-delete-action.spec.d.ts +2 -0
- package/dist/types/tests/features/protocol-delete-action.spec.d.ts.map +1 -0
- package/dist/types/tests/features/protocol-update-action.spec.d.ts +2 -0
- package/dist/types/tests/features/protocol-update-action.spec.d.ts.map +1 -0
- package/dist/types/tests/features/records-prune.spec.d.ts +2 -0
- package/dist/types/tests/features/records-prune.spec.d.ts.map +1 -0
- package/dist/types/tests/features/records-tags.spec.d.ts +2 -0
- package/dist/types/tests/features/records-tags.spec.d.ts.map +1 -0
- package/dist/types/tests/features/resumable-tasks.spec.d.ts +2 -0
- package/dist/types/tests/features/resumable-tasks.spec.d.ts.map +1 -0
- package/dist/types/tests/handlers/messages-query.spec.d.ts +2 -0
- package/dist/types/tests/handlers/messages-query.spec.d.ts.map +1 -0
- package/dist/types/tests/handlers/messages-read.spec.d.ts +2 -0
- package/dist/types/tests/handlers/messages-read.spec.d.ts.map +1 -0
- package/dist/types/tests/handlers/messages-subscribe.spec.d.ts +2 -0
- package/dist/types/tests/handlers/messages-subscribe.spec.d.ts.map +1 -0
- package/dist/types/tests/handlers/protocols-configure.spec.d.ts +2 -0
- package/dist/types/tests/handlers/protocols-configure.spec.d.ts.map +1 -0
- package/dist/types/tests/handlers/protocols-query.spec.d.ts +2 -0
- package/dist/types/tests/handlers/protocols-query.spec.d.ts.map +1 -0
- package/dist/types/tests/handlers/records-delete.spec.d.ts +2 -0
- package/dist/types/tests/handlers/records-delete.spec.d.ts.map +1 -0
- package/dist/types/tests/handlers/records-query.spec.d.ts +2 -0
- package/dist/types/tests/handlers/records-query.spec.d.ts.map +1 -0
- package/dist/types/tests/handlers/records-read.spec.d.ts +2 -0
- package/dist/types/tests/handlers/records-read.spec.d.ts.map +1 -0
- package/dist/types/tests/handlers/records-subscribe.spec.d.ts +2 -0
- package/dist/types/tests/handlers/records-subscribe.spec.d.ts.map +1 -0
- package/dist/types/tests/handlers/records-write.spec.d.ts +2 -0
- package/dist/types/tests/handlers/records-write.spec.d.ts.map +1 -0
- package/dist/types/tests/interfaces/messages-get.spec.d.ts +2 -0
- package/dist/types/tests/interfaces/messages-get.spec.d.ts.map +1 -0
- package/dist/types/tests/interfaces/messages-subscribe.spec.d.ts +2 -0
- package/dist/types/tests/interfaces/messages-subscribe.spec.d.ts.map +1 -0
- package/dist/types/tests/interfaces/messagess-query.spec.d.ts +2 -0
- package/dist/types/tests/interfaces/messagess-query.spec.d.ts.map +1 -0
- package/dist/types/tests/interfaces/protocols-configure.spec.d.ts +2 -0
- package/dist/types/tests/interfaces/protocols-configure.spec.d.ts.map +1 -0
- package/dist/types/tests/interfaces/protocols-query.spec.d.ts +2 -0
- package/dist/types/tests/interfaces/protocols-query.spec.d.ts.map +1 -0
- package/dist/types/tests/interfaces/records-delete.spec.d.ts +2 -0
- package/dist/types/tests/interfaces/records-delete.spec.d.ts.map +1 -0
- package/dist/types/tests/interfaces/records-query.spec.d.ts +2 -0
- package/dist/types/tests/interfaces/records-query.spec.d.ts.map +1 -0
- package/dist/types/tests/interfaces/records-read.spec.d.ts +2 -0
- package/dist/types/tests/interfaces/records-read.spec.d.ts.map +1 -0
- package/dist/types/tests/interfaces/records-subscribe.spec.d.ts +2 -0
- package/dist/types/tests/interfaces/records-subscribe.spec.d.ts.map +1 -0
- package/dist/types/tests/interfaces/records-write.spec.d.ts +2 -0
- package/dist/types/tests/interfaces/records-write.spec.d.ts.map +1 -0
- package/dist/types/tests/jose/jws/general.spec.d.ts +2 -0
- package/dist/types/tests/jose/jws/general.spec.d.ts.map +1 -0
- package/dist/types/tests/protocols/permission-request.spec.d.ts +2 -0
- package/dist/types/tests/protocols/permission-request.spec.d.ts.map +1 -0
- package/dist/types/tests/protocols/permissions.spec.d.ts +2 -0
- package/dist/types/tests/protocols/permissions.spec.d.ts.map +1 -0
- package/dist/types/tests/scenarios/aggregator.spec.d.ts +2 -0
- package/dist/types/tests/scenarios/aggregator.spec.d.ts.map +1 -0
- package/dist/types/tests/scenarios/deleted-record.spec.d.ts +2 -0
- package/dist/types/tests/scenarios/deleted-record.spec.d.ts.map +1 -0
- package/dist/types/tests/scenarios/end-to-end-tests.spec.d.ts +2 -0
- package/dist/types/tests/scenarios/end-to-end-tests.spec.d.ts.map +1 -0
- package/dist/types/tests/scenarios/messages-query.spec.d.ts +2 -0
- package/dist/types/tests/scenarios/messages-query.spec.d.ts.map +1 -0
- package/dist/types/tests/scenarios/nested-roles.spec.d.ts +2 -0
- package/dist/types/tests/scenarios/nested-roles.spec.d.ts.map +1 -0
- package/dist/types/tests/scenarios/subscriptions.spec.d.ts +2 -0
- package/dist/types/tests/scenarios/subscriptions.spec.d.ts.map +1 -0
- package/dist/types/tests/store/blockstore-mock.spec.d.ts +2 -0
- package/dist/types/tests/store/blockstore-mock.spec.d.ts.map +1 -0
- package/dist/types/tests/store/data-store-level.spec.d.ts +2 -0
- package/dist/types/tests/store/data-store-level.spec.d.ts.map +1 -0
- package/dist/types/tests/store/index-level.spec.d.ts +2 -0
- package/dist/types/tests/store/index-level.spec.d.ts.map +1 -0
- package/dist/types/tests/store/message-store-level.spec.d.ts +2 -0
- package/dist/types/tests/store/message-store-level.spec.d.ts.map +1 -0
- package/dist/types/tests/store/message-store.spec.d.ts +2 -0
- package/dist/types/tests/store/message-store.spec.d.ts.map +1 -0
- package/dist/types/tests/store-dependent-tests.spec.d.ts +2 -0
- package/dist/types/tests/store-dependent-tests.spec.d.ts.map +1 -0
- package/dist/types/tests/test-event-stream.d.ts +22 -0
- package/dist/types/tests/test-event-stream.d.ts.map +1 -0
- package/dist/types/tests/test-stores.d.ts +33 -0
- package/dist/types/tests/test-stores.d.ts.map +1 -0
- package/dist/types/tests/test-suite.d.ts +18 -0
- package/dist/types/tests/test-suite.d.ts.map +1 -0
- package/dist/types/tests/utils/cid.spec.d.ts +2 -0
- package/dist/types/tests/utils/cid.spec.d.ts.map +1 -0
- package/dist/types/tests/utils/data-stream.spec.d.ts +2 -0
- package/dist/types/tests/utils/data-stream.spec.d.ts.map +1 -0
- package/dist/types/tests/utils/encryption.spec.d.ts +2 -0
- package/dist/types/tests/utils/encryption.spec.d.ts.map +1 -0
- package/dist/types/tests/utils/filters.spec.d.ts +2 -0
- package/dist/types/tests/utils/filters.spec.d.ts.map +1 -0
- package/dist/types/tests/utils/hd-key.spec.d.ts +2 -0
- package/dist/types/tests/utils/hd-key.spec.d.ts.map +1 -0
- package/dist/types/tests/utils/jws.spec.d.ts +2 -0
- package/dist/types/tests/utils/jws.spec.d.ts.map +1 -0
- package/dist/types/tests/utils/memory-cache.spec.d.ts +2 -0
- package/dist/types/tests/utils/memory-cache.spec.d.ts.map +1 -0
- package/dist/types/tests/utils/messages.spec.d.ts +2 -0
- package/dist/types/tests/utils/messages.spec.d.ts.map +1 -0
- package/dist/types/tests/utils/object.spec.d.ts +2 -0
- package/dist/types/tests/utils/object.spec.d.ts.map +1 -0
- package/dist/types/tests/utils/poller.d.ts +21 -0
- package/dist/types/tests/utils/poller.d.ts.map +1 -0
- package/dist/types/tests/utils/private-key-signer.spec.d.ts +2 -0
- package/dist/types/tests/utils/private-key-signer.spec.d.ts.map +1 -0
- package/dist/types/tests/utils/records.spec.d.ts +2 -0
- package/dist/types/tests/utils/records.spec.d.ts.map +1 -0
- package/dist/types/tests/utils/secp256k1.spec.d.ts +2 -0
- package/dist/types/tests/utils/secp256k1.spec.d.ts.map +1 -0
- package/dist/types/tests/utils/secp256r1.spec.d.ts +2 -0
- package/dist/types/tests/utils/secp256r1.spec.d.ts.map +1 -0
- package/dist/types/tests/utils/test-data-generator.d.ts +342 -0
- package/dist/types/tests/utils/test-data-generator.d.ts.map +1 -0
- package/dist/types/tests/utils/test-stub-generator.d.ts +16 -0
- package/dist/types/tests/utils/test-stub-generator.d.ts.map +1 -0
- package/dist/types/tests/utils/time.spec.d.ts +2 -0
- package/dist/types/tests/utils/time.spec.d.ts.map +1 -0
- package/dist/types/tests/utils/url.spec.d.ts +2 -0
- package/dist/types/tests/utils/url.spec.d.ts.map +1 -0
- package/dist/types/tests/validation/json-schemas/definitions.spec.d.ts +2 -0
- package/dist/types/tests/validation/json-schemas/definitions.spec.d.ts.map +1 -0
- package/dist/types/tests/validation/json-schemas/jwk/general-jwk.spec.d.ts +2 -0
- package/dist/types/tests/validation/json-schemas/jwk/general-jwk.spec.d.ts.map +1 -0
- package/dist/types/tests/validation/json-schemas/jwk/public-jwk.spec.d.ts +2 -0
- package/dist/types/tests/validation/json-schemas/jwk/public-jwk.spec.d.ts.map +1 -0
- package/dist/types/tests/validation/json-schemas/jwk-verification-method.spec.d.ts +2 -0
- package/dist/types/tests/validation/json-schemas/jwk-verification-method.spec.d.ts.map +1 -0
- package/dist/types/tests/validation/json-schemas/protocols/protocols-configure.spec.d.ts +2 -0
- package/dist/types/tests/validation/json-schemas/protocols/protocols-configure.spec.d.ts.map +1 -0
- package/dist/types/tests/validation/json-schemas/records/records-query.spec.d.ts +2 -0
- package/dist/types/tests/validation/json-schemas/records/records-query.spec.d.ts.map +1 -0
- package/dist/types/tests/validation/json-schemas/records/records-write.spec.d.ts +2 -0
- package/dist/types/tests/validation/json-schemas/records/records-write.spec.d.ts.map +1 -0
- package/package.json +167 -0
- package/src/core/abstract-message.ts +62 -0
- package/src/core/auth.ts +36 -0
- package/src/core/dwn-constant.ts +9 -0
- package/src/core/dwn-error.ts +167 -0
- package/src/core/grant-authorization.ts +148 -0
- package/src/core/message-reply.ts +41 -0
- package/src/core/message.ts +259 -0
- package/src/core/messages-grant-authorization.ts +134 -0
- package/src/core/protocol-authorization.ts +903 -0
- package/src/core/protocols-grant-authorization.ts +88 -0
- package/src/core/records-grant-authorization.ts +197 -0
- package/src/core/resumable-task-manager.ts +114 -0
- package/src/core/tenant-gate.ts +33 -0
- package/src/dwn.ts +264 -0
- package/src/enums/dwn-interface-method.ts +14 -0
- package/src/event-log/event-emitter-stream.ts +69 -0
- package/src/event-log/event-log-level.ts +72 -0
- package/src/handlers/messages-query.ts +67 -0
- package/src/handlers/messages-read.ts +103 -0
- package/src/handlers/messages-subscribe.ts +89 -0
- package/src/handlers/protocols-configure.ts +137 -0
- package/src/handlers/protocols-query.ts +82 -0
- package/src/handlers/records-delete.ts +124 -0
- package/src/handlers/records-query.ts +262 -0
- package/src/handlers/records-read.ts +187 -0
- package/src/handlers/records-subscribe.ts +218 -0
- package/src/handlers/records-write.ts +404 -0
- package/src/index.ts +67 -0
- package/src/interfaces/messages-query.ts +60 -0
- package/src/interfaces/messages-read.ts +63 -0
- package/src/interfaces/messages-subscribe.ts +64 -0
- package/src/interfaces/protocols-configure.ts +340 -0
- package/src/interfaces/protocols-query.ts +96 -0
- package/src/interfaces/records-delete.ts +117 -0
- package/src/interfaces/records-query.ts +131 -0
- package/src/interfaces/records-read.ts +100 -0
- package/src/interfaces/records-subscribe.ts +104 -0
- package/src/interfaces/records-write.ts +1072 -0
- package/src/jose/algorithms/signing/ed25519.ts +58 -0
- package/src/jose/algorithms/signing/signature-algorithms.ts +22 -0
- package/src/jose/jws/general/builder.ts +48 -0
- package/src/jose/jws/general/verifier.ts +112 -0
- package/src/protocols/permission-grant.ts +86 -0
- package/src/protocols/permission-request.ts +63 -0
- package/src/protocols/permissions.ts +508 -0
- package/src/schema-validator.ts +46 -0
- package/src/store/blockstore-level.ts +113 -0
- package/src/store/blockstore-mock.ts +80 -0
- package/src/store/data-store-level.ts +120 -0
- package/src/store/index-level.ts +691 -0
- package/src/store/level-wrapper.ts +272 -0
- package/src/store/message-store-level.ts +195 -0
- package/src/store/resumable-task-store-level.ts +120 -0
- package/src/store/storage-controller.ts +240 -0
- package/src/types/cache.ts +16 -0
- package/src/types/data-store.ts +64 -0
- package/src/types/event-log.ts +52 -0
- package/src/types/jose-types.ts +76 -0
- package/src/types/jws-types.ts +28 -0
- package/src/types/message-interface.ts +30 -0
- package/src/types/message-store.ts +57 -0
- package/src/types/message-types.ts +132 -0
- package/src/types/messages-types.ts +77 -0
- package/src/types/method-handler.ts +19 -0
- package/src/types/permission-types.ts +110 -0
- package/src/types/protocols-types.ts +177 -0
- package/src/types/query-types.ts +61 -0
- package/src/types/records-types.ts +263 -0
- package/src/types/resumable-task-store.ts +96 -0
- package/src/types/signer.ts +27 -0
- package/src/types/subscriptions.ts +34 -0
- package/src/utils/abort.ts +31 -0
- package/src/utils/array.ts +39 -0
- package/src/utils/cid.ts +101 -0
- package/src/utils/data-stream.ts +99 -0
- package/src/utils/encoder.ts +54 -0
- package/src/utils/encryption.ts +145 -0
- package/src/utils/filter.ts +245 -0
- package/src/utils/hd-key.ts +126 -0
- package/src/utils/jws.ts +95 -0
- package/src/utils/memory-cache.ts +31 -0
- package/src/utils/messages.ts +109 -0
- package/src/utils/object.ts +43 -0
- package/src/utils/private-key-signer.ts +72 -0
- package/src/utils/protocols.ts +50 -0
- package/src/utils/records.ts +559 -0
- package/src/utils/secp256k1.ts +157 -0
- package/src/utils/secp256r1.ts +142 -0
- package/src/utils/string.ts +13 -0
- package/src/utils/time.ts +78 -0
- package/src/utils/url.ts +65 -0
|
@@ -0,0 +1,1724 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { DataStoreLevel, DwnConstant, MessageStoreLevel, PermissionsProtocol, Time } from '../../src/index.js';
|
|
11
|
+
import { DwnInterfaceName, DwnMethodName } from '../../src/index.js';
|
|
12
|
+
import chaiAsPromised from 'chai-as-promised';
|
|
13
|
+
import chatProtocolDefinition from '../vectors/protocol-definitions/chat.json' assert { type: 'json' };
|
|
14
|
+
import emailProtocolDefinition from '../vectors/protocol-definitions/email.json' assert { type: 'json' };
|
|
15
|
+
import friendRoleProtocolDefinition from '../vectors/protocol-definitions/friend-role.json' assert { type: 'json' };
|
|
16
|
+
import minimalProtocolDefinition from '../vectors/protocol-definitions/minimal.json' assert { type: 'json' };
|
|
17
|
+
import nestedProtocol from '../vectors/protocol-definitions/nested.json' assert { type: 'json' };
|
|
18
|
+
import sinon from 'sinon';
|
|
19
|
+
import socialMediaProtocolDefinition from '../vectors/protocol-definitions/social-media.json' assert { type: 'json' };
|
|
20
|
+
import threadRoleProtocolDefinition from '../vectors/protocol-definitions/thread-role.json' assert { type: 'json' };
|
|
21
|
+
import chai, { expect } from 'chai';
|
|
22
|
+
import { ArrayUtility } from '../../src/utils/array.js';
|
|
23
|
+
import { authenticate } from '../../src/core/auth.js';
|
|
24
|
+
import { DwnErrorCode } from '../../src/core/dwn-error.js';
|
|
25
|
+
import { Encryption } from '../../src/utils/encryption.js';
|
|
26
|
+
import { HdKey } from '../../src/utils/hd-key.js';
|
|
27
|
+
import { KeyDerivationScheme } from '../../src/utils/hd-key.js';
|
|
28
|
+
import { RecordsReadHandler } from '../../src/handlers/records-read.js';
|
|
29
|
+
import { TestDataGenerator } from '../utils/test-data-generator.js';
|
|
30
|
+
import { TestEventStream } from '../test-event-stream.js';
|
|
31
|
+
import { TestStores } from '../test-stores.js';
|
|
32
|
+
import { TestStubGenerator } from '../utils/test-stub-generator.js';
|
|
33
|
+
import { DataStream, Dwn, Jws, Protocols, ProtocolsConfigure, ProtocolsQuery, Records, RecordsDelete, RecordsRead, RecordsWrite, Secp256k1 } from '../../src/index.js';
|
|
34
|
+
import { DidKey, UniversalResolver } from '@enbox/dids';
|
|
35
|
+
chai.use(chaiAsPromised);
|
|
36
|
+
export function testRecordsReadHandler() {
|
|
37
|
+
describe('RecordsReadHandler.handle()', () => {
|
|
38
|
+
let didResolver;
|
|
39
|
+
let messageStore;
|
|
40
|
+
let dataStore;
|
|
41
|
+
let resumableTaskStore;
|
|
42
|
+
let eventLog;
|
|
43
|
+
let eventStream;
|
|
44
|
+
let dwn;
|
|
45
|
+
beforeEach(() => {
|
|
46
|
+
sinon.restore(); // wipe all previous stubs/spies/mocks/fakes
|
|
47
|
+
});
|
|
48
|
+
describe('functional tests', () => {
|
|
49
|
+
// important to follow the `before` and `after` pattern to initialize and clean the stores in tests
|
|
50
|
+
// so that different test suites can reuse the same backend store for testing
|
|
51
|
+
before(() => __awaiter(this, void 0, void 0, function* () {
|
|
52
|
+
didResolver = new UniversalResolver({ didResolvers: [DidKey] });
|
|
53
|
+
const stores = TestStores.get();
|
|
54
|
+
messageStore = stores.messageStore;
|
|
55
|
+
dataStore = stores.dataStore;
|
|
56
|
+
resumableTaskStore = stores.resumableTaskStore;
|
|
57
|
+
eventLog = stores.eventLog;
|
|
58
|
+
eventStream = TestEventStream.get();
|
|
59
|
+
dwn = yield Dwn.create({ didResolver, messageStore, dataStore, eventLog, eventStream, resumableTaskStore });
|
|
60
|
+
}));
|
|
61
|
+
beforeEach(() => __awaiter(this, void 0, void 0, function* () {
|
|
62
|
+
// clean up before each test rather than after so that a test does not depend on other tests to do the clean up
|
|
63
|
+
yield messageStore.clear();
|
|
64
|
+
yield dataStore.clear();
|
|
65
|
+
yield resumableTaskStore.clear();
|
|
66
|
+
yield eventLog.clear();
|
|
67
|
+
}));
|
|
68
|
+
after(() => __awaiter(this, void 0, void 0, function* () {
|
|
69
|
+
yield dwn.close();
|
|
70
|
+
}));
|
|
71
|
+
it('should allow tenant to RecordsRead their own record', () => __awaiter(this, void 0, void 0, function* () {
|
|
72
|
+
var _a, _b;
|
|
73
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
74
|
+
// insert data
|
|
75
|
+
const { message, dataStream, dataBytes } = yield TestDataGenerator.generateRecordsWrite({ author: alice });
|
|
76
|
+
const writeReply = yield dwn.processMessage(alice.did, message, { dataStream });
|
|
77
|
+
expect(writeReply.status.code).to.equal(202);
|
|
78
|
+
// testing RecordsRead
|
|
79
|
+
const recordsRead = yield RecordsRead.create({
|
|
80
|
+
filter: {
|
|
81
|
+
recordId: message.recordId,
|
|
82
|
+
},
|
|
83
|
+
signer: Jws.createSigner(alice)
|
|
84
|
+
});
|
|
85
|
+
const readReply = yield dwn.processMessage(alice.did, recordsRead.message);
|
|
86
|
+
expect(readReply.status.code).to.equal(200);
|
|
87
|
+
expect(readReply.entry.recordsWrite).to.exist;
|
|
88
|
+
expect((_a = readReply.entry.recordsWrite) === null || _a === void 0 ? void 0 : _a.authorization).to.deep.equal(message.authorization);
|
|
89
|
+
expect((_b = readReply.entry.recordsWrite) === null || _b === void 0 ? void 0 : _b.descriptor).to.deep.equal(message.descriptor);
|
|
90
|
+
const dataFetched = yield DataStream.toBytes(readReply.entry.data);
|
|
91
|
+
expect(ArrayUtility.byteArraysEqual(dataFetched, dataBytes)).to.be.true;
|
|
92
|
+
}));
|
|
93
|
+
it('should not allow non-tenant to RecordsRead a record', () => __awaiter(this, void 0, void 0, function* () {
|
|
94
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
95
|
+
// insert data
|
|
96
|
+
const { message, dataStream } = yield TestDataGenerator.generateRecordsWrite({ author: alice });
|
|
97
|
+
const writeReply = yield dwn.processMessage(alice.did, message, { dataStream });
|
|
98
|
+
expect(writeReply.status.code).to.equal(202);
|
|
99
|
+
// testing RecordsRead
|
|
100
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
101
|
+
const recordsRead = yield RecordsRead.create({
|
|
102
|
+
filter: {
|
|
103
|
+
recordId: message.recordId,
|
|
104
|
+
},
|
|
105
|
+
signer: Jws.createSigner(bob)
|
|
106
|
+
});
|
|
107
|
+
const readReply = yield dwn.processMessage(alice.did, recordsRead.message);
|
|
108
|
+
expect(readReply.status.code).to.equal(401);
|
|
109
|
+
}));
|
|
110
|
+
it('should allow reading of data that is published without `authorization`', () => __awaiter(this, void 0, void 0, function* () {
|
|
111
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
112
|
+
// insert public data
|
|
113
|
+
const { message, dataStream, dataBytes } = yield TestDataGenerator.generateRecordsWrite({ author: alice, published: true });
|
|
114
|
+
const writeReply = yield dwn.processMessage(alice.did, message, { dataStream });
|
|
115
|
+
expect(writeReply.status.code).to.equal(202);
|
|
116
|
+
// testing public RecordsRead
|
|
117
|
+
const recordsRead = yield RecordsRead.create({
|
|
118
|
+
filter: {
|
|
119
|
+
recordId: message.recordId
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
expect(recordsRead.author).to.be.undefined; // making sure no author/authorization is created
|
|
123
|
+
const readReply = yield dwn.processMessage(alice.did, recordsRead.message);
|
|
124
|
+
expect(readReply.status.code).to.equal(200);
|
|
125
|
+
const dataFetched = yield DataStream.toBytes(readReply.entry.data);
|
|
126
|
+
expect(ArrayUtility.byteArraysEqual(dataFetched, dataBytes)).to.be.true;
|
|
127
|
+
}));
|
|
128
|
+
it('should allow an authenticated user to RecordRead data that is published', () => __awaiter(this, void 0, void 0, function* () {
|
|
129
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
130
|
+
// insert public data
|
|
131
|
+
const { message, dataStream, dataBytes } = yield TestDataGenerator.generateRecordsWrite({ author: alice, published: true });
|
|
132
|
+
const writeReply = yield dwn.processMessage(alice.did, message, { dataStream });
|
|
133
|
+
expect(writeReply.status.code).to.equal(202);
|
|
134
|
+
// testing public RecordsRead
|
|
135
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
136
|
+
const recordsRead = yield RecordsRead.create({
|
|
137
|
+
filter: {
|
|
138
|
+
recordId: message.recordId,
|
|
139
|
+
},
|
|
140
|
+
signer: Jws.createSigner(bob)
|
|
141
|
+
});
|
|
142
|
+
const readReply = yield dwn.processMessage(alice.did, recordsRead.message);
|
|
143
|
+
expect(readReply.status.code).to.equal(200);
|
|
144
|
+
const dataFetched = yield DataStream.toBytes(readReply.entry.data);
|
|
145
|
+
expect(ArrayUtility.byteArraysEqual(dataFetched, dataBytes)).to.be.true;
|
|
146
|
+
}));
|
|
147
|
+
it('should allow a non-tenant to read RecordsRead data they have received', () => __awaiter(this, void 0, void 0, function* () {
|
|
148
|
+
var _a;
|
|
149
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
150
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
151
|
+
// Alice inserts data with Bob as recipient
|
|
152
|
+
const { message, dataStream, dataBytes } = yield TestDataGenerator.generateRecordsWrite({
|
|
153
|
+
author: alice,
|
|
154
|
+
recipient: bob.did,
|
|
155
|
+
});
|
|
156
|
+
const writeReply = yield dwn.processMessage(alice.did, message, { dataStream });
|
|
157
|
+
expect(writeReply.status.code).to.equal(202);
|
|
158
|
+
// Bob reads the data that Alice sent him
|
|
159
|
+
const recordsRead = yield RecordsRead.create({
|
|
160
|
+
filter: {
|
|
161
|
+
recordId: message.recordId,
|
|
162
|
+
},
|
|
163
|
+
signer: Jws.createSigner(bob)
|
|
164
|
+
});
|
|
165
|
+
const readReply = yield dwn.processMessage(alice.did, recordsRead.message);
|
|
166
|
+
expect(readReply.status.code).to.equal(200);
|
|
167
|
+
expect(readReply.entry.recordsWrite).to.exist;
|
|
168
|
+
expect((_a = readReply.entry.recordsWrite) === null || _a === void 0 ? void 0 : _a.descriptor).to.exist;
|
|
169
|
+
const dataFetched = yield DataStream.toBytes(readReply.entry.data);
|
|
170
|
+
expect(ArrayUtility.byteArraysEqual(dataFetched, dataBytes)).to.be.true;
|
|
171
|
+
}));
|
|
172
|
+
it('should return 400 when fetching initial write for a deleted record fails', () => __awaiter(this, void 0, void 0, function* () {
|
|
173
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
174
|
+
// Write a record
|
|
175
|
+
const { message: writeMessage, dataStream } = yield TestDataGenerator.generateRecordsWrite({ author: alice });
|
|
176
|
+
const writeReply = yield dwn.processMessage(alice.did, writeMessage, { dataStream });
|
|
177
|
+
expect(writeReply.status.code).to.equal(202);
|
|
178
|
+
// Delete the record
|
|
179
|
+
const recordsDelete = yield RecordsDelete.create({
|
|
180
|
+
signer: Jws.createSigner(alice),
|
|
181
|
+
recordId: writeMessage.recordId
|
|
182
|
+
});
|
|
183
|
+
const deleteReply = yield dwn.processMessage(alice.did, recordsDelete.message);
|
|
184
|
+
expect(deleteReply.status.code).to.equal(202);
|
|
185
|
+
// Stub the messageStore.query method to simulate failure in fetching initial write
|
|
186
|
+
const queryStub = sinon.stub(dwn['messageStore'], 'query');
|
|
187
|
+
queryStub.onFirstCall().resolves({ messages: [recordsDelete.message] });
|
|
188
|
+
queryStub.onSecondCall().resolves({ messages: [] }); // Simulate no initial write found
|
|
189
|
+
// Attempt to read the deleted record
|
|
190
|
+
const recordsRead = yield RecordsRead.create({
|
|
191
|
+
filter: { recordId: writeMessage.recordId },
|
|
192
|
+
signer: Jws.createSigner(alice)
|
|
193
|
+
});
|
|
194
|
+
const readReply = yield dwn.processMessage(alice.did, recordsRead.message);
|
|
195
|
+
// Verify the response
|
|
196
|
+
expect(readReply.status.code).to.equal(400);
|
|
197
|
+
expect(readReply.status.detail).to.contain(DwnErrorCode.RecordsReadInitialWriteNotFound);
|
|
198
|
+
// Restore the original messageStore.query method
|
|
199
|
+
queryStub.restore();
|
|
200
|
+
}));
|
|
201
|
+
it('should return 401 when a non-author attempts to read the initial write of a deleted record', () => __awaiter(this, void 0, void 0, function* () {
|
|
202
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
203
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
204
|
+
const carol = yield TestDataGenerator.generateDidKeyPersona();
|
|
205
|
+
// Alice installs a protocol that allows anyone to write
|
|
206
|
+
const protocolDefinition = {
|
|
207
|
+
published: true,
|
|
208
|
+
protocol: 'https://example.com/foo',
|
|
209
|
+
types: {
|
|
210
|
+
foo: {}
|
|
211
|
+
},
|
|
212
|
+
structure: {
|
|
213
|
+
foo: {
|
|
214
|
+
$actions: [{
|
|
215
|
+
who: 'anyone',
|
|
216
|
+
can: ['create', 'delete']
|
|
217
|
+
}]
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
const configureProtocol = yield TestDataGenerator.generateProtocolsConfigure({
|
|
222
|
+
author: alice,
|
|
223
|
+
protocolDefinition: protocolDefinition,
|
|
224
|
+
});
|
|
225
|
+
const configureProtocolReply = yield dwn.processMessage(alice.did, configureProtocol.message);
|
|
226
|
+
expect(configureProtocolReply.status.code).to.equal(202);
|
|
227
|
+
// Bob writes a record to Alice's DWN
|
|
228
|
+
const { message: writeMessage, dataStream } = yield TestDataGenerator.generateRecordsWrite({
|
|
229
|
+
author: bob,
|
|
230
|
+
protocol: protocolDefinition.protocol,
|
|
231
|
+
protocolPath: 'foo'
|
|
232
|
+
});
|
|
233
|
+
const writeReply = yield dwn.processMessage(alice.did, writeMessage, { dataStream });
|
|
234
|
+
expect(writeReply.status.code).to.equal(202);
|
|
235
|
+
// Bob deletes the record
|
|
236
|
+
const recordsDelete = yield RecordsDelete.create({
|
|
237
|
+
signer: Jws.createSigner(bob),
|
|
238
|
+
recordId: writeMessage.recordId
|
|
239
|
+
});
|
|
240
|
+
const deleteReply = yield dwn.processMessage(alice.did, recordsDelete.message);
|
|
241
|
+
expect(deleteReply.status.code).to.equal(202);
|
|
242
|
+
// Carol attempts to read the deleted record
|
|
243
|
+
const recordsRead = yield RecordsRead.create({
|
|
244
|
+
filter: { recordId: writeMessage.recordId },
|
|
245
|
+
signer: Jws.createSigner(carol)
|
|
246
|
+
});
|
|
247
|
+
const readReply = yield dwn.processMessage(alice.did, recordsRead.message);
|
|
248
|
+
// Verify the response
|
|
249
|
+
expect(readReply.status.code).to.equal(401);
|
|
250
|
+
expect(readReply.status.detail).to.contain(DwnErrorCode.ProtocolAuthorizationActionNotAllowed);
|
|
251
|
+
}));
|
|
252
|
+
it('should allow a non-tenant to read RecordsRead data they have authored', () => __awaiter(this, void 0, void 0, function* () {
|
|
253
|
+
var _a;
|
|
254
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
255
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
256
|
+
const carol = yield TestDataGenerator.generateDidKeyPersona();
|
|
257
|
+
// Alice installs a protocol that allows anyone to write foo record
|
|
258
|
+
const protocolDefinition = {
|
|
259
|
+
published: true,
|
|
260
|
+
protocol: 'https://example.com/foo',
|
|
261
|
+
types: {
|
|
262
|
+
foo: {}
|
|
263
|
+
},
|
|
264
|
+
structure: {
|
|
265
|
+
foo: {
|
|
266
|
+
$actions: [{
|
|
267
|
+
who: 'anyone',
|
|
268
|
+
can: ['create']
|
|
269
|
+
}]
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
const configureProtocol = yield TestDataGenerator.generateProtocolsConfigure({
|
|
274
|
+
author: alice,
|
|
275
|
+
protocolDefinition: protocolDefinition,
|
|
276
|
+
});
|
|
277
|
+
const configureProtocolReply = yield dwn.processMessage(alice.did, configureProtocol.message);
|
|
278
|
+
expect(configureProtocolReply.status.code).to.equal(202);
|
|
279
|
+
// Bob writes a foo record to Alice's DWN
|
|
280
|
+
const { message, dataStream, dataBytes } = yield TestDataGenerator.generateRecordsWrite({
|
|
281
|
+
author: bob,
|
|
282
|
+
protocol: protocolDefinition.protocol,
|
|
283
|
+
protocolPath: 'foo',
|
|
284
|
+
});
|
|
285
|
+
const writeReply = yield dwn.processMessage(alice.did, message, { dataStream });
|
|
286
|
+
expect(writeReply.status.code).to.equal(202);
|
|
287
|
+
// Bob reads the record he sent to Alice from Alice's DWN
|
|
288
|
+
const recordsRead = yield RecordsRead.create({
|
|
289
|
+
filter: {
|
|
290
|
+
recordId: message.recordId,
|
|
291
|
+
},
|
|
292
|
+
signer: Jws.createSigner(bob)
|
|
293
|
+
});
|
|
294
|
+
const readReply = yield dwn.processMessage(alice.did, recordsRead.message);
|
|
295
|
+
expect(readReply.status.code).to.equal(200);
|
|
296
|
+
expect(readReply.entry.recordsWrite).to.exist;
|
|
297
|
+
expect((_a = readReply.entry.recordsWrite) === null || _a === void 0 ? void 0 : _a.descriptor).to.exist;
|
|
298
|
+
const dataFetched = yield DataStream.toBytes(readReply.entry.data);
|
|
299
|
+
expect(ArrayUtility.byteArraysEqual(dataFetched, dataBytes)).to.be.true;
|
|
300
|
+
// carol attempts to read Bob's record
|
|
301
|
+
const carolRecordsRead = yield RecordsRead.create({
|
|
302
|
+
filter: {
|
|
303
|
+
recordId: message.recordId,
|
|
304
|
+
},
|
|
305
|
+
signer: Jws.createSigner(carol)
|
|
306
|
+
});
|
|
307
|
+
const carolReadReply = yield dwn.processMessage(alice.did, carolRecordsRead.message);
|
|
308
|
+
expect(carolReadReply.status.code).to.equal(401);
|
|
309
|
+
}));
|
|
310
|
+
it('should include `initialWrite` property if RecordsWrite is not initial write', () => __awaiter(this, void 0, void 0, function* () {
|
|
311
|
+
var _a;
|
|
312
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
313
|
+
const write = yield TestDataGenerator.generateRecordsWrite({ author: alice, published: false });
|
|
314
|
+
const writeReply = yield dwn.processMessage(alice.did, write.message, { dataStream: write.dataStream });
|
|
315
|
+
expect(writeReply.status.code).to.equal(202);
|
|
316
|
+
// write an update to the record
|
|
317
|
+
const write2 = yield RecordsWrite.createFrom({ recordsWriteMessage: write.message, published: true, signer: Jws.createSigner(alice) });
|
|
318
|
+
const write2Reply = yield dwn.processMessage(alice.did, write2.message);
|
|
319
|
+
expect(write2Reply.status.code).to.equal(202);
|
|
320
|
+
// make sure result returned now has `initialWrite` property
|
|
321
|
+
const messageData = yield RecordsRead.create({ filter: { recordId: write.message.recordId }, signer: Jws.createSigner(alice) });
|
|
322
|
+
const reply = yield dwn.processMessage(alice.did, messageData.message);
|
|
323
|
+
expect(reply.status.code).to.equal(200);
|
|
324
|
+
expect(reply.entry.initialWrite).to.exist;
|
|
325
|
+
expect((_a = reply.entry.initialWrite) === null || _a === void 0 ? void 0 : _a.recordId).to.equal(write.message.recordId);
|
|
326
|
+
}));
|
|
327
|
+
describe('protocol based reads', () => {
|
|
328
|
+
it('should allow read with allow-anyone rule', () => __awaiter(this, void 0, void 0, function* () {
|
|
329
|
+
// scenario: Alice writes an image to her DWN, then Bob reads the image because he is "anyone".
|
|
330
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
331
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
332
|
+
const protocolDefinition = socialMediaProtocolDefinition;
|
|
333
|
+
// Install social-media protocol on Alice's DWN
|
|
334
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
335
|
+
author: alice,
|
|
336
|
+
protocolDefinition
|
|
337
|
+
});
|
|
338
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
339
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
340
|
+
// Alice writes image to her DWN
|
|
341
|
+
const encodedImage = new TextEncoder().encode('cafe-aesthetic.jpg');
|
|
342
|
+
const imageRecordsWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
343
|
+
author: alice,
|
|
344
|
+
protocol: protocolDefinition.protocol,
|
|
345
|
+
protocolPath: 'image', // this comes from `types` in protocol definition
|
|
346
|
+
schema: protocolDefinition.types.image.schema,
|
|
347
|
+
dataFormat: 'image/jpeg',
|
|
348
|
+
data: encodedImage,
|
|
349
|
+
recipient: alice.did
|
|
350
|
+
});
|
|
351
|
+
const imageReply = yield dwn.processMessage(alice.did, imageRecordsWrite.message, { dataStream: imageRecordsWrite.dataStream });
|
|
352
|
+
expect(imageReply.status.code).to.equal(202);
|
|
353
|
+
// Bob (anyone) reads the image that Alice wrote
|
|
354
|
+
const imageRecordsRead = yield RecordsRead.create({
|
|
355
|
+
filter: {
|
|
356
|
+
recordId: imageRecordsWrite.message.recordId,
|
|
357
|
+
},
|
|
358
|
+
signer: Jws.createSigner(bob)
|
|
359
|
+
});
|
|
360
|
+
const imageReadReply = yield dwn.processMessage(alice.did, imageRecordsRead.message);
|
|
361
|
+
expect(imageReadReply.status.code).to.equal(200);
|
|
362
|
+
}));
|
|
363
|
+
it('should not allow anonymous reads when there is no allow-anyone rule', () => __awaiter(this, void 0, void 0, function* () {
|
|
364
|
+
// scenario: Alice's writes a record to a protocol. An anonymous read his Alice's DWN and is rejected
|
|
365
|
+
// because there is not an allow-anyone rule.
|
|
366
|
+
const alice = yield TestDataGenerator.generatePersona();
|
|
367
|
+
const protocolDefinition = emailProtocolDefinition;
|
|
368
|
+
TestStubGenerator.stubDidResolver(didResolver, [alice]);
|
|
369
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
370
|
+
author: alice,
|
|
371
|
+
protocolDefinition
|
|
372
|
+
});
|
|
373
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
374
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
375
|
+
// Alice writes a message to the minimal protocol
|
|
376
|
+
const recordsWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
377
|
+
author: alice,
|
|
378
|
+
protocol: protocolDefinition.protocol,
|
|
379
|
+
protocolPath: 'email',
|
|
380
|
+
schema: protocolDefinition.types.email.schema,
|
|
381
|
+
dataFormat: protocolDefinition.types.email.dataFormats[0],
|
|
382
|
+
data: new TextEncoder().encode('foo')
|
|
383
|
+
});
|
|
384
|
+
const recordsWriteReply = yield dwn.processMessage(alice.did, recordsWrite.message, { dataStream: recordsWrite.dataStream });
|
|
385
|
+
expect(recordsWriteReply.status.code).to.equal(202);
|
|
386
|
+
// Anonymous tries and fails to read Alice's message
|
|
387
|
+
const recordsRead = yield RecordsRead.create({
|
|
388
|
+
filter: {
|
|
389
|
+
recordId: recordsWrite.message.recordId,
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
const recordsReadReply = yield dwn.processMessage(alice.did, recordsRead.message);
|
|
393
|
+
expect(recordsReadReply.status.code).to.equal(401);
|
|
394
|
+
expect(recordsReadReply.status.detail).to.contain(DwnErrorCode.ProtocolAuthorizationActionNotAllowed);
|
|
395
|
+
}));
|
|
396
|
+
describe('recipient rules', () => {
|
|
397
|
+
it('should allow read with ancestor recipient rule', () => __awaiter(this, void 0, void 0, function* () {
|
|
398
|
+
// scenario: Alice sends an email to Bob, then Bob reads the email.
|
|
399
|
+
// ImposterBob tries and fails to read the email.
|
|
400
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
401
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
402
|
+
const imposterBob = yield TestDataGenerator.generateDidKeyPersona();
|
|
403
|
+
const protocolDefinition = emailProtocolDefinition;
|
|
404
|
+
// Install email protocol on Alice's DWN
|
|
405
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
406
|
+
author: alice,
|
|
407
|
+
protocolDefinition,
|
|
408
|
+
});
|
|
409
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
410
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
411
|
+
// Alice writes an email with Bob as recipient
|
|
412
|
+
const encodedEmail = new TextEncoder().encode('Dear Bob, hello!');
|
|
413
|
+
const emailRecordsWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
414
|
+
author: alice,
|
|
415
|
+
protocol: protocolDefinition.protocol,
|
|
416
|
+
protocolPath: 'email', // this comes from `types` in protocol definition
|
|
417
|
+
schema: protocolDefinition.types.email.schema,
|
|
418
|
+
dataFormat: protocolDefinition.types.email.dataFormats[0],
|
|
419
|
+
data: encodedEmail,
|
|
420
|
+
recipient: bob.did
|
|
421
|
+
});
|
|
422
|
+
const imageReply = yield dwn.processMessage(alice.did, emailRecordsWrite.message, { dataStream: emailRecordsWrite.dataStream });
|
|
423
|
+
expect(imageReply.status.code).to.equal(202);
|
|
424
|
+
// Bob reads Alice's email
|
|
425
|
+
const bobRecordsRead = yield RecordsRead.create({
|
|
426
|
+
filter: {
|
|
427
|
+
recordId: emailRecordsWrite.message.recordId,
|
|
428
|
+
},
|
|
429
|
+
signer: Jws.createSigner(bob)
|
|
430
|
+
});
|
|
431
|
+
const bobReadReply = yield dwn.processMessage(alice.did, bobRecordsRead.message);
|
|
432
|
+
expect(bobReadReply.status.code).to.equal(200);
|
|
433
|
+
// ImposterBob is not able to read Alice's email
|
|
434
|
+
const imposterRecordsRead = yield RecordsRead.create({
|
|
435
|
+
filter: {
|
|
436
|
+
recordId: emailRecordsWrite.message.recordId,
|
|
437
|
+
},
|
|
438
|
+
signer: Jws.createSigner(imposterBob)
|
|
439
|
+
});
|
|
440
|
+
const imposterReadReply = yield dwn.processMessage(alice.did, imposterRecordsRead.message);
|
|
441
|
+
expect(imposterReadReply.status.code).to.equal(401);
|
|
442
|
+
expect(imposterReadReply.status.detail).to.include(DwnErrorCode.ProtocolAuthorizationActionNotAllowed);
|
|
443
|
+
}));
|
|
444
|
+
});
|
|
445
|
+
describe('author action rules', () => {
|
|
446
|
+
it('should allow read with ancestor author rule', () => __awaiter(this, void 0, void 0, function* () {
|
|
447
|
+
// scenario: Bob sends an email to Alice, then Bob reads the email.
|
|
448
|
+
// ImposterBob tries and fails to read the email.
|
|
449
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
450
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
451
|
+
const imposterBob = yield TestDataGenerator.generateDidKeyPersona();
|
|
452
|
+
const protocolDefinition = emailProtocolDefinition;
|
|
453
|
+
// Install email protocol on Alice's DWN
|
|
454
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
455
|
+
author: alice,
|
|
456
|
+
protocolDefinition
|
|
457
|
+
});
|
|
458
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
459
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
460
|
+
// Alice writes an email with Bob as recipient
|
|
461
|
+
const encodedEmail = new TextEncoder().encode('Dear Alice, hello!');
|
|
462
|
+
const emailRecordsWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
463
|
+
author: bob,
|
|
464
|
+
protocol: protocolDefinition.protocol,
|
|
465
|
+
protocolPath: 'email', // this comes from `types` in protocol definition
|
|
466
|
+
schema: protocolDefinition.types.email.schema,
|
|
467
|
+
dataFormat: protocolDefinition.types.email.dataFormats[0],
|
|
468
|
+
data: encodedEmail,
|
|
469
|
+
recipient: alice.did
|
|
470
|
+
});
|
|
471
|
+
const imageReply = yield dwn.processMessage(alice.did, emailRecordsWrite.message, { dataStream: emailRecordsWrite.dataStream });
|
|
472
|
+
expect(imageReply.status.code).to.equal(202);
|
|
473
|
+
// Bob reads the email he just sent
|
|
474
|
+
const bobRecordsRead = yield RecordsRead.create({
|
|
475
|
+
filter: {
|
|
476
|
+
recordId: emailRecordsWrite.message.recordId,
|
|
477
|
+
},
|
|
478
|
+
signer: Jws.createSigner(bob)
|
|
479
|
+
});
|
|
480
|
+
const bobReadReply = yield dwn.processMessage(alice.did, bobRecordsRead.message);
|
|
481
|
+
expect(bobReadReply.status.code).to.equal(200);
|
|
482
|
+
// ImposterBob is not able to read the email
|
|
483
|
+
const imposterRecordsRead = yield RecordsRead.create({
|
|
484
|
+
filter: {
|
|
485
|
+
recordId: emailRecordsWrite.message.recordId,
|
|
486
|
+
},
|
|
487
|
+
signer: Jws.createSigner(imposterBob)
|
|
488
|
+
});
|
|
489
|
+
const imposterReadReply = yield dwn.processMessage(alice.did, imposterRecordsRead.message);
|
|
490
|
+
expect(imposterReadReply.status.code).to.equal(401);
|
|
491
|
+
expect(imposterReadReply.status.detail).to.include(DwnErrorCode.ProtocolAuthorizationActionNotAllowed);
|
|
492
|
+
}));
|
|
493
|
+
});
|
|
494
|
+
describe('filter based reads', () => {
|
|
495
|
+
it('should return a filter based read if there is only a single result', () => __awaiter(this, void 0, void 0, function* () {
|
|
496
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
497
|
+
const protocolDefinition = Object.assign({}, nestedProtocol);
|
|
498
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
499
|
+
author: alice,
|
|
500
|
+
protocolDefinition
|
|
501
|
+
});
|
|
502
|
+
const protocolConfigReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
503
|
+
expect(protocolConfigReply.status.code).to.equal(202);
|
|
504
|
+
const foo1Write = yield TestDataGenerator.generateRecordsWrite({
|
|
505
|
+
author: alice,
|
|
506
|
+
protocol: protocolDefinition.protocol,
|
|
507
|
+
protocolPath: 'foo',
|
|
508
|
+
schema: protocolDefinition.types.foo.schema,
|
|
509
|
+
dataFormat: protocolDefinition.types.foo.dataFormats[0],
|
|
510
|
+
data: new TextEncoder().encode('foo'),
|
|
511
|
+
recipient: alice.did
|
|
512
|
+
});
|
|
513
|
+
const foo1WriteReply = yield dwn.processMessage(alice.did, foo1Write.message, { dataStream: foo1Write.dataStream });
|
|
514
|
+
expect(foo1WriteReply.status.code).to.equal(202);
|
|
515
|
+
const fooPathRead = yield RecordsRead.create({
|
|
516
|
+
filter: {
|
|
517
|
+
protocol: protocolDefinition.protocol,
|
|
518
|
+
protocolPath: 'foo',
|
|
519
|
+
},
|
|
520
|
+
signer: Jws.createSigner(alice),
|
|
521
|
+
});
|
|
522
|
+
const fooPathReply = yield dwn.processMessage(alice.did, fooPathRead.message);
|
|
523
|
+
expect(fooPathReply.status.code).to.equal(200);
|
|
524
|
+
expect(fooPathReply.entry.recordsWrite.recordId).to.equal(foo1Write.message.recordId);
|
|
525
|
+
}));
|
|
526
|
+
it('should throw if requested filter has more than a single result', () => __awaiter(this, void 0, void 0, function* () {
|
|
527
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
528
|
+
const protocolDefinition = Object.assign({}, nestedProtocol);
|
|
529
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
530
|
+
author: alice,
|
|
531
|
+
protocolDefinition
|
|
532
|
+
});
|
|
533
|
+
const protocolConfigReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
534
|
+
expect(protocolConfigReply.status.code).to.equal(202);
|
|
535
|
+
const foo1Write = yield TestDataGenerator.generateRecordsWrite({
|
|
536
|
+
author: alice,
|
|
537
|
+
protocol: protocolDefinition.protocol,
|
|
538
|
+
protocolPath: 'foo',
|
|
539
|
+
schema: protocolDefinition.types.foo.schema,
|
|
540
|
+
dataFormat: protocolDefinition.types.foo.dataFormats[0],
|
|
541
|
+
data: new TextEncoder().encode('foo'),
|
|
542
|
+
recipient: alice.did
|
|
543
|
+
});
|
|
544
|
+
const foo1WriteReply = yield dwn.processMessage(alice.did, foo1Write.message, { dataStream: foo1Write.dataStream });
|
|
545
|
+
expect(foo1WriteReply.status.code).to.equal(202);
|
|
546
|
+
const foo2Write = yield TestDataGenerator.generateRecordsWrite({
|
|
547
|
+
author: alice,
|
|
548
|
+
protocol: protocolDefinition.protocol,
|
|
549
|
+
protocolPath: 'foo',
|
|
550
|
+
schema: protocolDefinition.types.foo.schema,
|
|
551
|
+
dataFormat: protocolDefinition.types.foo.dataFormats[0],
|
|
552
|
+
data: new TextEncoder().encode('foo'),
|
|
553
|
+
recipient: alice.did
|
|
554
|
+
});
|
|
555
|
+
const foo2WriteReply = yield dwn.processMessage(alice.did, foo2Write.message, { dataStream: foo2Write.dataStream });
|
|
556
|
+
expect(foo2WriteReply.status.code).to.equal(202);
|
|
557
|
+
// Since there are two 'foo' records, this should fail.
|
|
558
|
+
const fooPathRead = yield RecordsRead.create({
|
|
559
|
+
filter: {
|
|
560
|
+
protocol: protocolDefinition.protocol,
|
|
561
|
+
protocolPath: 'foo',
|
|
562
|
+
},
|
|
563
|
+
signer: Jws.createSigner(alice),
|
|
564
|
+
});
|
|
565
|
+
const fooPathReply = yield dwn.processMessage(alice.did, fooPathRead.message);
|
|
566
|
+
expect(fooPathReply.status.code).to.equal(400);
|
|
567
|
+
expect(fooPathReply.status.detail).to.contain(DwnErrorCode.RecordsReadReturnedMultiple);
|
|
568
|
+
}));
|
|
569
|
+
});
|
|
570
|
+
describe('protocolRole based reads', () => {
|
|
571
|
+
it('uses a root-level role to authorize a read', () => __awaiter(this, void 0, void 0, function* () {
|
|
572
|
+
// scenario: Alice writes a chat message writes a chat message. Bob invokes his
|
|
573
|
+
// friend role in order to read the chat message.
|
|
574
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
575
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
576
|
+
const protocolDefinition = friendRoleProtocolDefinition;
|
|
577
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
578
|
+
author: alice,
|
|
579
|
+
protocolDefinition
|
|
580
|
+
});
|
|
581
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
582
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
583
|
+
// Alice writes a 'friend' root-level role record with Bob as recipient
|
|
584
|
+
const friendRoleRecord = yield TestDataGenerator.generateRecordsWrite({
|
|
585
|
+
author: alice,
|
|
586
|
+
recipient: bob.did,
|
|
587
|
+
protocol: protocolDefinition.protocol,
|
|
588
|
+
protocolPath: 'friend',
|
|
589
|
+
data: new TextEncoder().encode('Bob is my friend'),
|
|
590
|
+
});
|
|
591
|
+
const friendRoleReply = yield dwn.processMessage(alice.did, friendRoleRecord.message, { dataStream: friendRoleRecord.dataStream });
|
|
592
|
+
expect(friendRoleReply.status.code).to.equal(202);
|
|
593
|
+
// Alice writes a 'chat' record
|
|
594
|
+
const chatRecord = yield TestDataGenerator.generateRecordsWrite({
|
|
595
|
+
author: alice,
|
|
596
|
+
recipient: alice.did,
|
|
597
|
+
protocol: protocolDefinition.protocol,
|
|
598
|
+
protocolPath: 'chat',
|
|
599
|
+
data: new TextEncoder().encode('Bob can read this cuz he is my friend'),
|
|
600
|
+
});
|
|
601
|
+
const chatReply = yield dwn.processMessage(alice.did, chatRecord.message, { dataStream: chatRecord.dataStream });
|
|
602
|
+
expect(chatReply.status.code).to.equal(202);
|
|
603
|
+
// Bob reads Alice's chat record
|
|
604
|
+
const readChatRecord = yield RecordsRead.create({
|
|
605
|
+
signer: Jws.createSigner(bob),
|
|
606
|
+
filter: {
|
|
607
|
+
recordId: chatRecord.message.recordId,
|
|
608
|
+
},
|
|
609
|
+
protocolRole: 'friend'
|
|
610
|
+
});
|
|
611
|
+
const chatReadReply = yield dwn.processMessage(alice.did, readChatRecord.message);
|
|
612
|
+
expect(chatReadReply.status.code).to.equal(200);
|
|
613
|
+
}));
|
|
614
|
+
it('rejects root-level role authorized reads if the protocolRole is not a valid protocol path to an active role record', () => __awaiter(this, void 0, void 0, function* () {
|
|
615
|
+
// scenario: Alice writes a chat message writes a chat message. Bob tries to invoke the 'chat' role,
|
|
616
|
+
// but 'chat' is not a role.
|
|
617
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
618
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
619
|
+
const protocolDefinition = friendRoleProtocolDefinition;
|
|
620
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
621
|
+
author: alice,
|
|
622
|
+
protocolDefinition
|
|
623
|
+
});
|
|
624
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
625
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
626
|
+
// Alice writes a 'chat' record
|
|
627
|
+
const chatRecord = yield TestDataGenerator.generateRecordsWrite({
|
|
628
|
+
author: alice,
|
|
629
|
+
recipient: alice.did,
|
|
630
|
+
protocol: protocolDefinition.protocol,
|
|
631
|
+
protocolPath: 'chat',
|
|
632
|
+
data: new TextEncoder().encode('Blah blah blah'),
|
|
633
|
+
});
|
|
634
|
+
const chatReply = yield dwn.processMessage(alice.did, chatRecord.message, { dataStream: chatRecord.dataStream });
|
|
635
|
+
expect(chatReply.status.code).to.equal(202);
|
|
636
|
+
// Bob tries to invoke a 'chat' role but 'chat' is not a role
|
|
637
|
+
const readChatRecord = yield RecordsRead.create({
|
|
638
|
+
signer: Jws.createSigner(bob),
|
|
639
|
+
filter: {
|
|
640
|
+
recordId: chatRecord.message.recordId,
|
|
641
|
+
},
|
|
642
|
+
protocolRole: 'chat'
|
|
643
|
+
});
|
|
644
|
+
const chatReadReply = yield dwn.processMessage(alice.did, readChatRecord.message);
|
|
645
|
+
expect(chatReadReply.status.code).to.equal(401);
|
|
646
|
+
expect(chatReadReply.status.detail).to.contain(DwnErrorCode.ProtocolAuthorizationNotARole);
|
|
647
|
+
}));
|
|
648
|
+
it('rejects root-level role authorized reads if there is no active role for the recipient', () => __awaiter(this, void 0, void 0, function* () {
|
|
649
|
+
// scenario: Alice writes a chat message writes a chat message. Bob tries to invoke a role,
|
|
650
|
+
// but he has not been given one.
|
|
651
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
652
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
653
|
+
const protocolDefinition = friendRoleProtocolDefinition;
|
|
654
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
655
|
+
author: alice,
|
|
656
|
+
protocolDefinition
|
|
657
|
+
});
|
|
658
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
659
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
660
|
+
// Alice writes a 'chat' record
|
|
661
|
+
const chatRecord = yield TestDataGenerator.generateRecordsWrite({
|
|
662
|
+
author: alice,
|
|
663
|
+
recipient: alice.did,
|
|
664
|
+
protocol: protocolDefinition.protocol,
|
|
665
|
+
protocolPath: 'chat',
|
|
666
|
+
data: new TextEncoder().encode('Blah blah blah'),
|
|
667
|
+
});
|
|
668
|
+
const chatReply = yield dwn.processMessage(alice.did, chatRecord.message, { dataStream: chatRecord.dataStream });
|
|
669
|
+
expect(chatReply.status.code).to.equal(202);
|
|
670
|
+
// Bob tries to invoke a 'friend' role but he is not a 'friend'
|
|
671
|
+
const readChatRecord = yield RecordsRead.create({
|
|
672
|
+
signer: Jws.createSigner(bob),
|
|
673
|
+
filter: {
|
|
674
|
+
recordId: chatRecord.message.recordId,
|
|
675
|
+
},
|
|
676
|
+
protocolRole: 'friend',
|
|
677
|
+
});
|
|
678
|
+
const chatReadReply = yield dwn.processMessage(alice.did, readChatRecord.message);
|
|
679
|
+
expect(chatReadReply.status.code).to.equal(401);
|
|
680
|
+
expect(chatReadReply.status.detail).to.contain(DwnErrorCode.ProtocolAuthorizationMatchingRoleRecordNotFound);
|
|
681
|
+
}));
|
|
682
|
+
it('can authorize a read using a context role', () => __awaiter(this, void 0, void 0, function* () {
|
|
683
|
+
// scenario: Alice creates a thread and adds Bob to the 'thread/participant' role. Alice writes a chat message.
|
|
684
|
+
// Bob invokes the record to read in the chat message.
|
|
685
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
686
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
687
|
+
const protocolDefinition = threadRoleProtocolDefinition;
|
|
688
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
689
|
+
author: alice,
|
|
690
|
+
protocolDefinition
|
|
691
|
+
});
|
|
692
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
693
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
694
|
+
// Alice creates a thread
|
|
695
|
+
const threadRecord = yield TestDataGenerator.generateRecordsWrite({
|
|
696
|
+
author: alice,
|
|
697
|
+
protocol: protocolDefinition.protocol,
|
|
698
|
+
protocolPath: 'thread'
|
|
699
|
+
});
|
|
700
|
+
const threadRecordReply = yield dwn.processMessage(alice.did, threadRecord.message, { dataStream: threadRecord.dataStream });
|
|
701
|
+
expect(threadRecordReply.status.code).to.equal(202);
|
|
702
|
+
// Alice adds Bob as a 'thread/participant' in that thread
|
|
703
|
+
const participantRecord = yield TestDataGenerator.generateRecordsWrite({
|
|
704
|
+
author: alice,
|
|
705
|
+
recipient: bob.did,
|
|
706
|
+
protocol: protocolDefinition.protocol,
|
|
707
|
+
protocolPath: 'thread/participant',
|
|
708
|
+
parentContextId: threadRecord.message.contextId,
|
|
709
|
+
});
|
|
710
|
+
const participantRecordReply = yield dwn.processMessage(alice.did, participantRecord.message, { dataStream: participantRecord.dataStream });
|
|
711
|
+
expect(participantRecordReply.status.code).to.equal(202);
|
|
712
|
+
// Alice writes a chat message in the thread
|
|
713
|
+
const chatRecord = yield TestDataGenerator.generateRecordsWrite({
|
|
714
|
+
author: alice,
|
|
715
|
+
protocol: protocolDefinition.protocol,
|
|
716
|
+
protocolPath: 'thread/chat',
|
|
717
|
+
parentContextId: threadRecord.message.contextId,
|
|
718
|
+
});
|
|
719
|
+
const chatRecordReply = yield dwn.processMessage(alice.did, chatRecord.message, { dataStream: chatRecord.dataStream });
|
|
720
|
+
expect(chatRecordReply.status.code).to.equal(202);
|
|
721
|
+
// Bob is able to read his own 'participant' role
|
|
722
|
+
// He doesn't need to invoke the role because recipients of a record are always authorized to read it
|
|
723
|
+
const participantRead = yield RecordsRead.create({
|
|
724
|
+
signer: Jws.createSigner(bob),
|
|
725
|
+
filter: {
|
|
726
|
+
protocolPath: 'thread/participant',
|
|
727
|
+
recipient: bob.did,
|
|
728
|
+
contextId: threadRecord.message.contextId
|
|
729
|
+
},
|
|
730
|
+
});
|
|
731
|
+
const participantReadReply = yield dwn.processMessage(alice.did, participantRead.message);
|
|
732
|
+
expect(participantReadReply.status.code).to.equal(200);
|
|
733
|
+
// Bob is able to read the thread root record
|
|
734
|
+
const threadRead = yield RecordsRead.create({
|
|
735
|
+
signer: Jws.createSigner(bob),
|
|
736
|
+
filter: {
|
|
737
|
+
recordId: participantReadReply.entry.recordsWrite.descriptor.parentId,
|
|
738
|
+
},
|
|
739
|
+
protocolRole: 'thread/participant'
|
|
740
|
+
});
|
|
741
|
+
const threadReadReply = yield dwn.processMessage(alice.did, threadRead.message);
|
|
742
|
+
expect(threadReadReply.status.code).to.equal(200);
|
|
743
|
+
// Bob invokes his 'participant' role to read the chat message
|
|
744
|
+
const chatRead = yield RecordsRead.create({
|
|
745
|
+
signer: Jws.createSigner(bob),
|
|
746
|
+
filter: {
|
|
747
|
+
recordId: chatRecord.message.recordId,
|
|
748
|
+
},
|
|
749
|
+
protocolRole: 'thread/participant'
|
|
750
|
+
});
|
|
751
|
+
const chatReadReply = yield dwn.processMessage(alice.did, chatRead.message);
|
|
752
|
+
expect(chatReadReply.status.code).to.equal(200);
|
|
753
|
+
}));
|
|
754
|
+
it('should not allow context role to be invoked against a wrong context', () => __awaiter(this, void 0, void 0, function* () {
|
|
755
|
+
// scenario: Alice creates a thread and adds Bob as a participant. Alice creates another thread. Bob tries and fails to invoke his
|
|
756
|
+
// context role to write a chat in the second thread
|
|
757
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
758
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
759
|
+
const protocolDefinition = threadRoleProtocolDefinition;
|
|
760
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
761
|
+
author: alice,
|
|
762
|
+
protocolDefinition
|
|
763
|
+
});
|
|
764
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
765
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
766
|
+
// Alice creates a thread
|
|
767
|
+
const threadRecord1 = yield TestDataGenerator.generateRecordsWrite({
|
|
768
|
+
author: alice,
|
|
769
|
+
recipient: bob.did,
|
|
770
|
+
protocol: protocolDefinition.protocol,
|
|
771
|
+
protocolPath: 'thread'
|
|
772
|
+
});
|
|
773
|
+
const threadRecordReply1 = yield dwn.processMessage(alice.did, threadRecord1.message, { dataStream: threadRecord1.dataStream });
|
|
774
|
+
expect(threadRecordReply1.status.code).to.equal(202);
|
|
775
|
+
// Alice adds Bob as a 'thread/participant' in that thread
|
|
776
|
+
const participantRecord = yield TestDataGenerator.generateRecordsWrite({
|
|
777
|
+
author: alice,
|
|
778
|
+
recipient: bob.did,
|
|
779
|
+
protocol: protocolDefinition.protocol,
|
|
780
|
+
protocolPath: 'thread/participant',
|
|
781
|
+
parentContextId: threadRecord1.message.contextId,
|
|
782
|
+
});
|
|
783
|
+
const participantRecordReply = yield dwn.processMessage(alice.did, participantRecord.message, { dataStream: participantRecord.dataStream });
|
|
784
|
+
expect(participantRecordReply.status.code).to.equal(202);
|
|
785
|
+
// Alice creates a second thread
|
|
786
|
+
const threadRecord2 = yield TestDataGenerator.generateRecordsWrite({
|
|
787
|
+
author: alice,
|
|
788
|
+
recipient: bob.did,
|
|
789
|
+
protocol: protocolDefinition.protocol,
|
|
790
|
+
protocolPath: 'thread'
|
|
791
|
+
});
|
|
792
|
+
const threadRecordReply2 = yield dwn.processMessage(alice.did, threadRecord2.message, { dataStream: threadRecord2.dataStream });
|
|
793
|
+
expect(threadRecordReply2.status.code).to.equal(202);
|
|
794
|
+
// Alice writes a chat message in the thread
|
|
795
|
+
const chatRecord = yield TestDataGenerator.generateRecordsWrite({
|
|
796
|
+
author: alice,
|
|
797
|
+
protocol: protocolDefinition.protocol,
|
|
798
|
+
protocolPath: 'thread/chat',
|
|
799
|
+
parentContextId: threadRecord2.message.contextId,
|
|
800
|
+
});
|
|
801
|
+
const chatRecordReply = yield dwn.processMessage(alice.did, chatRecord.message, { dataStream: chatRecord.dataStream });
|
|
802
|
+
expect(chatRecordReply.status.code).to.equal(202);
|
|
803
|
+
// Bob invokes his 'participant' role to read the chat message
|
|
804
|
+
const chatRead = yield RecordsRead.create({
|
|
805
|
+
signer: Jws.createSigner(bob),
|
|
806
|
+
filter: {
|
|
807
|
+
recordId: chatRecord.message.recordId,
|
|
808
|
+
},
|
|
809
|
+
protocolRole: 'thread/participant'
|
|
810
|
+
});
|
|
811
|
+
const chatReadReply = yield dwn.processMessage(alice.did, chatRead.message);
|
|
812
|
+
expect(chatReadReply.status.code).to.equal(401);
|
|
813
|
+
expect(chatReadReply.status.detail).to.contain(DwnErrorCode.ProtocolAuthorizationMatchingRoleRecordNotFound);
|
|
814
|
+
}));
|
|
815
|
+
});
|
|
816
|
+
});
|
|
817
|
+
describe('grant based reads', () => {
|
|
818
|
+
it('rejects with 401 an external party attempts to RecordReads if grant has different DWN method scope', () => __awaiter(this, void 0, void 0, function* () {
|
|
819
|
+
// scenario: Alice grants Bob access to RecordsWrite, then Bob tries to invoke the grant with RecordsRead
|
|
820
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
821
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
822
|
+
// Alice writes a record which Bob will later try to read
|
|
823
|
+
const { recordsWrite, dataStream } = yield TestDataGenerator.generateRecordsWrite({
|
|
824
|
+
author: alice,
|
|
825
|
+
});
|
|
826
|
+
const recordsWriteReply = yield dwn.processMessage(alice.did, recordsWrite.message, { dataStream });
|
|
827
|
+
expect(recordsWriteReply.status.code).to.equal(202);
|
|
828
|
+
// Alice gives Bob a permission grant with scope RecordsRead
|
|
829
|
+
const permissionGrant = yield PermissionsProtocol.createGrant({
|
|
830
|
+
signer: Jws.createSigner(alice),
|
|
831
|
+
grantedTo: bob.did,
|
|
832
|
+
dateExpires: Time.createOffsetTimestamp({ seconds: 60 * 60 * 24 }), // 24 hours
|
|
833
|
+
scope: {
|
|
834
|
+
interface: DwnInterfaceName.Records,
|
|
835
|
+
method: DwnMethodName.Write,
|
|
836
|
+
protocol: 'http://example.com/protocol/test',
|
|
837
|
+
}
|
|
838
|
+
});
|
|
839
|
+
const grantDataStream = DataStream.fromBytes(permissionGrant.permissionGrantBytes);
|
|
840
|
+
const permissionGrantWriteReply = yield dwn.processMessage(alice.did, permissionGrant.recordsWrite.message, { dataStream: grantDataStream });
|
|
841
|
+
expect(permissionGrantWriteReply.status.code).to.equal(202);
|
|
842
|
+
// Bob tries to RecordsRead
|
|
843
|
+
const recordsRead = yield RecordsRead.create({
|
|
844
|
+
filter: {
|
|
845
|
+
recordId: recordsWrite.message.recordId,
|
|
846
|
+
},
|
|
847
|
+
signer: Jws.createSigner(bob),
|
|
848
|
+
permissionGrantId: permissionGrant.recordsWrite.message.recordId,
|
|
849
|
+
});
|
|
850
|
+
const recordsReadReply = yield dwn.processMessage(alice.did, recordsRead.message);
|
|
851
|
+
expect(recordsReadReply.status.code).to.equal(401);
|
|
852
|
+
expect(recordsReadReply.status.detail).to.contain(DwnErrorCode.GrantAuthorizationMethodMismatch);
|
|
853
|
+
}));
|
|
854
|
+
describe('protocol records', () => {
|
|
855
|
+
it('allows reads of protocol records with unrestricted grant scopes', () => __awaiter(this, void 0, void 0, function* () {
|
|
856
|
+
// scenario: Alice writes a protocol record. Alice gives Bob a grant to read all records in her DWN
|
|
857
|
+
// Bob invokes that grant to read the protocol record.
|
|
858
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
859
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
860
|
+
const protocolDefinition = minimalProtocolDefinition;
|
|
861
|
+
// Alice installs the protocol
|
|
862
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
863
|
+
author: alice,
|
|
864
|
+
protocolDefinition
|
|
865
|
+
});
|
|
866
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
867
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
868
|
+
// Alice writes a record which Bob will later try to read
|
|
869
|
+
const { recordsWrite, dataStream } = yield TestDataGenerator.generateRecordsWrite({
|
|
870
|
+
author: alice,
|
|
871
|
+
protocol: protocolDefinition.protocol,
|
|
872
|
+
protocolPath: 'foo',
|
|
873
|
+
});
|
|
874
|
+
const recordsWriteReply = yield dwn.processMessage(alice.did, recordsWrite.message, { dataStream });
|
|
875
|
+
expect(recordsWriteReply.status.code).to.equal(202);
|
|
876
|
+
// Alice gives Bob a permission grant with scope RecordsRead
|
|
877
|
+
const permissionGrant = yield PermissionsProtocol.createGrant({
|
|
878
|
+
signer: Jws.createSigner(alice),
|
|
879
|
+
grantedTo: bob.did,
|
|
880
|
+
dateExpires: Time.createOffsetTimestamp({ seconds: 60 * 60 * 24 }), // 24 hours
|
|
881
|
+
scope: {
|
|
882
|
+
interface: DwnInterfaceName.Records,
|
|
883
|
+
method: DwnMethodName.Read,
|
|
884
|
+
protocol: protocolDefinition.protocol,
|
|
885
|
+
}
|
|
886
|
+
});
|
|
887
|
+
const grantDataStream = DataStream.fromBytes(permissionGrant.permissionGrantBytes);
|
|
888
|
+
const permissionGrantWriteReply = yield dwn.processMessage(alice.did, permissionGrant.recordsWrite.message, { dataStream: grantDataStream });
|
|
889
|
+
expect(permissionGrantWriteReply.status.code).to.equal(202);
|
|
890
|
+
// Bob is unable to read the record without using the permission grant
|
|
891
|
+
const recordsReadWithoutGrant = yield RecordsRead.create({
|
|
892
|
+
filter: {
|
|
893
|
+
recordId: recordsWrite.message.recordId,
|
|
894
|
+
},
|
|
895
|
+
signer: Jws.createSigner(bob),
|
|
896
|
+
});
|
|
897
|
+
const recordsReadWithoutGrantReply = yield dwn.processMessage(alice.did, recordsReadWithoutGrant.message);
|
|
898
|
+
expect(recordsReadWithoutGrantReply.status.code).to.equal(401);
|
|
899
|
+
expect(recordsReadWithoutGrantReply.status.detail).to.contain(DwnErrorCode.ProtocolAuthorizationActionRulesNotFound);
|
|
900
|
+
// Bob is able to read the record when he uses the permission grant
|
|
901
|
+
const recordsReadWithGrant = yield RecordsRead.create({
|
|
902
|
+
filter: {
|
|
903
|
+
recordId: recordsWrite.message.recordId,
|
|
904
|
+
},
|
|
905
|
+
signer: Jws.createSigner(bob),
|
|
906
|
+
permissionGrantId: permissionGrant.recordsWrite.message.recordId,
|
|
907
|
+
});
|
|
908
|
+
const recordsReadWithGrantReply = yield dwn.processMessage(alice.did, recordsReadWithGrant.message);
|
|
909
|
+
expect(recordsReadWithGrantReply.status.code).to.equal(200);
|
|
910
|
+
}));
|
|
911
|
+
it('allows reads of protocol records with matching protocol grant scopes', () => __awaiter(this, void 0, void 0, function* () {
|
|
912
|
+
// scenario: Alice writes a protocol record. Alice gives Bob a grant to read all records in the protocol
|
|
913
|
+
// Bob invokes that grant to read the protocol record.
|
|
914
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
915
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
916
|
+
const protocolDefinition = minimalProtocolDefinition;
|
|
917
|
+
// Alice installs the protocol
|
|
918
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
919
|
+
author: alice,
|
|
920
|
+
protocolDefinition
|
|
921
|
+
});
|
|
922
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
923
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
924
|
+
// Alice writes a record which Bob will later try to read
|
|
925
|
+
const { recordsWrite, dataStream } = yield TestDataGenerator.generateRecordsWrite({
|
|
926
|
+
author: alice,
|
|
927
|
+
protocol: protocolDefinition.protocol,
|
|
928
|
+
protocolPath: 'foo',
|
|
929
|
+
});
|
|
930
|
+
const recordsWriteReply = yield dwn.processMessage(alice.did, recordsWrite.message, { dataStream });
|
|
931
|
+
expect(recordsWriteReply.status.code).to.equal(202);
|
|
932
|
+
// Alice gives Bob a permission grant with scope RecordsRead
|
|
933
|
+
const permissionGrant = yield PermissionsProtocol.createGrant({
|
|
934
|
+
signer: Jws.createSigner(alice),
|
|
935
|
+
grantedTo: bob.did,
|
|
936
|
+
dateExpires: Time.createOffsetTimestamp({ seconds: 60 * 60 * 24 }), // 24 hours
|
|
937
|
+
scope: {
|
|
938
|
+
interface: DwnInterfaceName.Records,
|
|
939
|
+
method: DwnMethodName.Read,
|
|
940
|
+
protocol: protocolDefinition.protocol,
|
|
941
|
+
}
|
|
942
|
+
});
|
|
943
|
+
const grantDataStream = DataStream.fromBytes(permissionGrant.permissionGrantBytes);
|
|
944
|
+
const permissionGrantWriteReply = yield dwn.processMessage(alice.did, permissionGrant.recordsWrite.message, { dataStream: grantDataStream });
|
|
945
|
+
expect(permissionGrantWriteReply.status.code).to.equal(202);
|
|
946
|
+
// Bob is unable to read the record without using the permission grant
|
|
947
|
+
const recordsReadWithoutGrant = yield RecordsRead.create({
|
|
948
|
+
filter: {
|
|
949
|
+
recordId: recordsWrite.message.recordId,
|
|
950
|
+
},
|
|
951
|
+
signer: Jws.createSigner(bob),
|
|
952
|
+
});
|
|
953
|
+
const recordsReadWithoutGrantReply = yield dwn.processMessage(alice.did, recordsReadWithoutGrant.message);
|
|
954
|
+
expect(recordsReadWithoutGrantReply.status.code).to.equal(401);
|
|
955
|
+
expect(recordsReadWithoutGrantReply.status.detail).to.contain(DwnErrorCode.ProtocolAuthorizationActionRulesNotFound);
|
|
956
|
+
// Bob is able to read the record when he uses the permission grant
|
|
957
|
+
const recordsReadWithGrant = yield RecordsRead.create({
|
|
958
|
+
filter: {
|
|
959
|
+
recordId: recordsWrite.message.recordId,
|
|
960
|
+
},
|
|
961
|
+
signer: Jws.createSigner(bob),
|
|
962
|
+
permissionGrantId: permissionGrant.recordsWrite.message.recordId,
|
|
963
|
+
});
|
|
964
|
+
const recordsReadWithGrantReply = yield dwn.processMessage(alice.did, recordsReadWithGrant.message);
|
|
965
|
+
expect(recordsReadWithGrantReply.status.code).to.equal(200);
|
|
966
|
+
}));
|
|
967
|
+
it('rejects reads of protocol records with mismatching protocol grant scopes', () => __awaiter(this, void 0, void 0, function* () {
|
|
968
|
+
// scenario: Alice writes a protocol record. Alice gives Bob a grant to read a different protocol
|
|
969
|
+
// Bob invokes that grant to read the protocol record, but fails.
|
|
970
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
971
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
972
|
+
const protocolDefinition = minimalProtocolDefinition;
|
|
973
|
+
// Alice installs the protocol
|
|
974
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
975
|
+
author: alice,
|
|
976
|
+
protocolDefinition
|
|
977
|
+
});
|
|
978
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
979
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
980
|
+
// Alice writes a record which Bob will later try to read
|
|
981
|
+
const { recordsWrite, dataStream } = yield TestDataGenerator.generateRecordsWrite({
|
|
982
|
+
author: alice,
|
|
983
|
+
protocol: protocolDefinition.protocol,
|
|
984
|
+
protocolPath: 'foo',
|
|
985
|
+
});
|
|
986
|
+
const recordsWriteReply = yield dwn.processMessage(alice.did, recordsWrite.message, { dataStream });
|
|
987
|
+
expect(recordsWriteReply.status.code).to.equal(202);
|
|
988
|
+
// Alice gives Bob a permission grant with scope RecordsRead
|
|
989
|
+
const permissionGrant = yield PermissionsProtocol.createGrant({
|
|
990
|
+
signer: Jws.createSigner(alice),
|
|
991
|
+
grantedTo: bob.did,
|
|
992
|
+
dateExpires: Time.createOffsetTimestamp({ seconds: 60 * 60 * 24 }), // 24 hours
|
|
993
|
+
scope: {
|
|
994
|
+
interface: DwnInterfaceName.Records,
|
|
995
|
+
method: DwnMethodName.Read,
|
|
996
|
+
protocol: 'a-different-protocol'
|
|
997
|
+
}
|
|
998
|
+
});
|
|
999
|
+
const grantDataStream = DataStream.fromBytes(permissionGrant.permissionGrantBytes);
|
|
1000
|
+
const permissionGrantWriteReply = yield dwn.processMessage(alice.did, permissionGrant.recordsWrite.message, { dataStream: grantDataStream });
|
|
1001
|
+
expect(permissionGrantWriteReply.status.code).to.equal(202);
|
|
1002
|
+
// Bob is unable to read the record using the mismatched permission grant
|
|
1003
|
+
const recordsReadWithoutGrant = yield RecordsRead.create({
|
|
1004
|
+
filter: {
|
|
1005
|
+
recordId: recordsWrite.message.recordId,
|
|
1006
|
+
},
|
|
1007
|
+
signer: Jws.createSigner(bob),
|
|
1008
|
+
permissionGrantId: permissionGrant.recordsWrite.message.recordId,
|
|
1009
|
+
});
|
|
1010
|
+
const recordsReadWithoutGrantReply = yield dwn.processMessage(alice.did, recordsReadWithoutGrant.message);
|
|
1011
|
+
expect(recordsReadWithoutGrantReply.status.code).to.equal(401);
|
|
1012
|
+
expect(recordsReadWithoutGrantReply.status.detail).to.contain(DwnErrorCode.RecordsGrantAuthorizationScopeProtocolMismatch);
|
|
1013
|
+
}));
|
|
1014
|
+
it('allows reads of records in the contextId specified in the grant', () => __awaiter(this, void 0, void 0, function* () {
|
|
1015
|
+
// scenario: Alice grants Bob access to RecordsRead records with a specific contextId.
|
|
1016
|
+
// Bob uses it to read a record in that context.
|
|
1017
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
1018
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
1019
|
+
const protocolDefinition = minimalProtocolDefinition;
|
|
1020
|
+
// Alice installs the protocol
|
|
1021
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
1022
|
+
author: alice,
|
|
1023
|
+
protocolDefinition
|
|
1024
|
+
});
|
|
1025
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
1026
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
1027
|
+
// Alice writes a record which Bob will later try to read
|
|
1028
|
+
const { recordsWrite, dataStream } = yield TestDataGenerator.generateRecordsWrite({
|
|
1029
|
+
author: alice,
|
|
1030
|
+
protocol: protocolDefinition.protocol,
|
|
1031
|
+
protocolPath: 'foo',
|
|
1032
|
+
});
|
|
1033
|
+
const recordsWriteReply = yield dwn.processMessage(alice.did, recordsWrite.message, { dataStream });
|
|
1034
|
+
expect(recordsWriteReply.status.code).to.equal(202);
|
|
1035
|
+
// Alice gives Bob a permission grant with scope RecordsRead
|
|
1036
|
+
const permissionGrant = yield PermissionsProtocol.createGrant({
|
|
1037
|
+
signer: Jws.createSigner(alice),
|
|
1038
|
+
grantedTo: bob.did,
|
|
1039
|
+
dateExpires: Time.createOffsetTimestamp({ seconds: 60 * 60 * 24 }), // 24 hours
|
|
1040
|
+
scope: {
|
|
1041
|
+
interface: DwnInterfaceName.Records,
|
|
1042
|
+
method: DwnMethodName.Read,
|
|
1043
|
+
protocol: protocolDefinition.protocol,
|
|
1044
|
+
contextId: recordsWrite.message.contextId,
|
|
1045
|
+
}
|
|
1046
|
+
});
|
|
1047
|
+
const grantDataStream = DataStream.fromBytes(permissionGrant.permissionGrantBytes);
|
|
1048
|
+
const permissionGrantWriteReply = yield dwn.processMessage(alice.did, permissionGrant.recordsWrite.message, { dataStream: grantDataStream });
|
|
1049
|
+
expect(permissionGrantWriteReply.status.code).to.equal(202);
|
|
1050
|
+
// Bob is unable to read the record using the mismatched permission grant
|
|
1051
|
+
const recordsReadWithoutGrant = yield RecordsRead.create({
|
|
1052
|
+
filter: {
|
|
1053
|
+
recordId: recordsWrite.message.recordId,
|
|
1054
|
+
},
|
|
1055
|
+
signer: Jws.createSigner(bob),
|
|
1056
|
+
permissionGrantId: permissionGrant.recordsWrite.message.recordId,
|
|
1057
|
+
});
|
|
1058
|
+
const recordsReadWithoutGrantReply = yield dwn.processMessage(alice.did, recordsReadWithoutGrant.message);
|
|
1059
|
+
expect(recordsReadWithoutGrantReply.status.code).to.equal(200);
|
|
1060
|
+
}));
|
|
1061
|
+
it('rejects reads of records in a different contextId than is specified in the grant', () => __awaiter(this, void 0, void 0, function* () {
|
|
1062
|
+
// scenario: Alice grants Bob access to RecordsRead records with a specific contextId.
|
|
1063
|
+
// Bob tries and fails to invoke the grant in order to read a record outside of the context.
|
|
1064
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
1065
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
1066
|
+
const protocolDefinition = minimalProtocolDefinition;
|
|
1067
|
+
// Alice installs the protocol
|
|
1068
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
1069
|
+
author: alice,
|
|
1070
|
+
protocolDefinition
|
|
1071
|
+
});
|
|
1072
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
1073
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
1074
|
+
// Alice writes a record which Bob will later try to read
|
|
1075
|
+
const { recordsWrite, dataStream } = yield TestDataGenerator.generateRecordsWrite({
|
|
1076
|
+
author: alice,
|
|
1077
|
+
protocol: protocolDefinition.protocol,
|
|
1078
|
+
protocolPath: 'foo',
|
|
1079
|
+
});
|
|
1080
|
+
const recordsWriteReply = yield dwn.processMessage(alice.did, recordsWrite.message, { dataStream });
|
|
1081
|
+
expect(recordsWriteReply.status.code).to.equal(202);
|
|
1082
|
+
// Alice gives Bob a permission grant with scope RecordsRead
|
|
1083
|
+
const permissionGrant = yield PermissionsProtocol.createGrant({
|
|
1084
|
+
signer: Jws.createSigner(alice),
|
|
1085
|
+
grantedTo: bob.did,
|
|
1086
|
+
dateExpires: Time.createOffsetTimestamp({ seconds: 60 * 60 * 24 }), // 24 hours
|
|
1087
|
+
scope: {
|
|
1088
|
+
interface: DwnInterfaceName.Records,
|
|
1089
|
+
method: DwnMethodName.Read,
|
|
1090
|
+
protocol: protocolDefinition.protocol,
|
|
1091
|
+
contextId: yield TestDataGenerator.randomCborSha256Cid(), // different contextId than what Bob will try to read
|
|
1092
|
+
}
|
|
1093
|
+
});
|
|
1094
|
+
const grantDataStream = DataStream.fromBytes(permissionGrant.permissionGrantBytes);
|
|
1095
|
+
const permissionGrantWriteReply = yield dwn.processMessage(alice.did, permissionGrant.recordsWrite.message, { dataStream: grantDataStream });
|
|
1096
|
+
expect(permissionGrantWriteReply.status.code).to.equal(202);
|
|
1097
|
+
// Bob is unable to read the record using the mismatched permission grant
|
|
1098
|
+
const recordsReadWithoutGrant = yield RecordsRead.create({
|
|
1099
|
+
filter: {
|
|
1100
|
+
recordId: recordsWrite.message.recordId,
|
|
1101
|
+
},
|
|
1102
|
+
signer: Jws.createSigner(bob),
|
|
1103
|
+
permissionGrantId: permissionGrant.recordsWrite.message.recordId,
|
|
1104
|
+
});
|
|
1105
|
+
const recordsReadWithoutGrantReply = yield dwn.processMessage(alice.did, recordsReadWithoutGrant.message);
|
|
1106
|
+
expect(recordsReadWithoutGrantReply.status.code).to.equal(401);
|
|
1107
|
+
expect(recordsReadWithoutGrantReply.status.detail).to.contain(DwnErrorCode.RecordsGrantAuthorizationScopeContextIdMismatch);
|
|
1108
|
+
}));
|
|
1109
|
+
it('allows reads of records in the protocolPath specified in the grant', () => __awaiter(this, void 0, void 0, function* () {
|
|
1110
|
+
// scenario: Alice grants Bob access to RecordsRead records with a specific protocolPath.
|
|
1111
|
+
// Bob uses it to read a record in that protocolPath.
|
|
1112
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
1113
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
1114
|
+
const protocolDefinition = minimalProtocolDefinition;
|
|
1115
|
+
// Alice installs the protocol
|
|
1116
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
1117
|
+
author: alice,
|
|
1118
|
+
protocolDefinition
|
|
1119
|
+
});
|
|
1120
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
1121
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
1122
|
+
// Alice writes a record which Bob will later try to read
|
|
1123
|
+
const { recordsWrite, dataStream } = yield TestDataGenerator.generateRecordsWrite({
|
|
1124
|
+
author: alice,
|
|
1125
|
+
protocol: protocolDefinition.protocol,
|
|
1126
|
+
protocolPath: 'foo',
|
|
1127
|
+
});
|
|
1128
|
+
const recordsWriteReply = yield dwn.processMessage(alice.did, recordsWrite.message, { dataStream });
|
|
1129
|
+
expect(recordsWriteReply.status.code).to.equal(202);
|
|
1130
|
+
// Alice gives Bob a permission grant with scope RecordsRead
|
|
1131
|
+
const permissionGrant = yield PermissionsProtocol.createGrant({
|
|
1132
|
+
signer: Jws.createSigner(alice),
|
|
1133
|
+
grantedTo: bob.did,
|
|
1134
|
+
dateExpires: Time.createOffsetTimestamp({ seconds: 60 * 60 * 24 }), // 24 hours
|
|
1135
|
+
scope: {
|
|
1136
|
+
interface: DwnInterfaceName.Records,
|
|
1137
|
+
method: DwnMethodName.Read,
|
|
1138
|
+
protocol: protocolDefinition.protocol,
|
|
1139
|
+
protocolPath: recordsWrite.message.descriptor.protocolPath,
|
|
1140
|
+
}
|
|
1141
|
+
});
|
|
1142
|
+
const grantDataStream = DataStream.fromBytes(permissionGrant.permissionGrantBytes);
|
|
1143
|
+
const permissionGrantWriteReply = yield dwn.processMessage(alice.did, permissionGrant.recordsWrite.message, { dataStream: grantDataStream });
|
|
1144
|
+
expect(permissionGrantWriteReply.status.code).to.equal(202);
|
|
1145
|
+
// Bob is unable to read the record using the mismatched permission grant
|
|
1146
|
+
const recordsReadWithoutGrant = yield RecordsRead.create({
|
|
1147
|
+
filter: {
|
|
1148
|
+
recordId: recordsWrite.message.recordId,
|
|
1149
|
+
},
|
|
1150
|
+
signer: Jws.createSigner(bob),
|
|
1151
|
+
permissionGrantId: permissionGrant.recordsWrite.message.recordId,
|
|
1152
|
+
});
|
|
1153
|
+
const recordsReadWithoutGrantReply = yield dwn.processMessage(alice.did, recordsReadWithoutGrant.message);
|
|
1154
|
+
expect(recordsReadWithoutGrantReply.status.code).to.equal(200);
|
|
1155
|
+
}));
|
|
1156
|
+
it('rejects reads of records in a different protocolPath than is specified in the grant', () => __awaiter(this, void 0, void 0, function* () {
|
|
1157
|
+
// scenario: Alice grants Bob access to RecordsRead records with a specific protocolPath.
|
|
1158
|
+
// Bob tries and fails to invoke the grant in order to read a record outside of the protocolPath.
|
|
1159
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
1160
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
1161
|
+
const protocolDefinition = minimalProtocolDefinition;
|
|
1162
|
+
// Alice installs the protocol
|
|
1163
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
1164
|
+
author: alice,
|
|
1165
|
+
protocolDefinition
|
|
1166
|
+
});
|
|
1167
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
1168
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
1169
|
+
// Alice writes a record which Bob will later try to read
|
|
1170
|
+
const { recordsWrite, dataStream } = yield TestDataGenerator.generateRecordsWrite({
|
|
1171
|
+
author: alice,
|
|
1172
|
+
protocol: protocolDefinition.protocol,
|
|
1173
|
+
protocolPath: 'foo',
|
|
1174
|
+
});
|
|
1175
|
+
const recordsWriteReply = yield dwn.processMessage(alice.did, recordsWrite.message, { dataStream });
|
|
1176
|
+
expect(recordsWriteReply.status.code).to.equal(202);
|
|
1177
|
+
// Alice gives Bob a permission grant with scope RecordsRead
|
|
1178
|
+
const permissionGrant = yield PermissionsProtocol.createGrant({
|
|
1179
|
+
signer: Jws.createSigner(alice),
|
|
1180
|
+
grantedTo: bob.did,
|
|
1181
|
+
dateExpires: Time.createOffsetTimestamp({ seconds: 60 * 60 * 24 }), // 24 hours
|
|
1182
|
+
scope: {
|
|
1183
|
+
interface: DwnInterfaceName.Records,
|
|
1184
|
+
method: DwnMethodName.Read,
|
|
1185
|
+
protocol: protocolDefinition.protocol,
|
|
1186
|
+
protocolPath: 'different-protocol-path', // different protocol path than what Bob will try to read
|
|
1187
|
+
}
|
|
1188
|
+
});
|
|
1189
|
+
const grantDataStream = DataStream.fromBytes(permissionGrant.permissionGrantBytes);
|
|
1190
|
+
const permissionGrantWriteReply = yield dwn.processMessage(alice.did, permissionGrant.recordsWrite.message, { dataStream: grantDataStream });
|
|
1191
|
+
expect(permissionGrantWriteReply.status.code).to.equal(202);
|
|
1192
|
+
// Bob is unable to read the record using the mismatched permission grant
|
|
1193
|
+
const recordsReadWithoutGrant = yield RecordsRead.create({
|
|
1194
|
+
filter: {
|
|
1195
|
+
recordId: recordsWrite.message.recordId,
|
|
1196
|
+
},
|
|
1197
|
+
signer: Jws.createSigner(bob),
|
|
1198
|
+
permissionGrantId: permissionGrant.recordsWrite.message.recordId,
|
|
1199
|
+
});
|
|
1200
|
+
const recordsReadWithoutGrantReply = yield dwn.processMessage(alice.did, recordsReadWithoutGrant.message);
|
|
1201
|
+
expect(recordsReadWithoutGrantReply.status.code).to.equal(401);
|
|
1202
|
+
expect(recordsReadWithoutGrantReply.status.detail).to.contain(DwnErrorCode.RecordsGrantAuthorizationScopeProtocolPathMismatch);
|
|
1203
|
+
}));
|
|
1204
|
+
});
|
|
1205
|
+
});
|
|
1206
|
+
it('should return 404 RecordRead if data does not exist', () => __awaiter(this, void 0, void 0, function* () {
|
|
1207
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
1208
|
+
const recordsRead = yield RecordsRead.create({
|
|
1209
|
+
filter: {
|
|
1210
|
+
recordId: `non-existent-record-id`,
|
|
1211
|
+
},
|
|
1212
|
+
signer: Jws.createSigner(alice)
|
|
1213
|
+
});
|
|
1214
|
+
const readReply = yield dwn.processMessage(alice.did, recordsRead.message);
|
|
1215
|
+
expect(readReply.status.code).to.equal(404);
|
|
1216
|
+
}));
|
|
1217
|
+
it('should return 404 RecordRead if data has been deleted', () => __awaiter(this, void 0, void 0, function* () {
|
|
1218
|
+
var _a;
|
|
1219
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
1220
|
+
// insert public data
|
|
1221
|
+
const { message, dataStream } = yield TestDataGenerator.generateRecordsWrite({ author: alice, published: true });
|
|
1222
|
+
const writeReply = yield dwn.processMessage(alice.did, message, { dataStream });
|
|
1223
|
+
expect(writeReply.status.code).to.equal(202);
|
|
1224
|
+
// ensure data is inserted
|
|
1225
|
+
const queryData = yield TestDataGenerator.generateRecordsQuery({
|
|
1226
|
+
author: alice,
|
|
1227
|
+
filter: { recordId: message.recordId }
|
|
1228
|
+
});
|
|
1229
|
+
const reply = yield dwn.processMessage(alice.did, queryData.message);
|
|
1230
|
+
expect(reply.status.code).to.equal(200);
|
|
1231
|
+
expect((_a = reply.entries) === null || _a === void 0 ? void 0 : _a.length).to.equal(1);
|
|
1232
|
+
// RecordsDelete
|
|
1233
|
+
const recordsDelete = yield RecordsDelete.create({
|
|
1234
|
+
recordId: message.recordId,
|
|
1235
|
+
signer: Jws.createSigner(alice)
|
|
1236
|
+
});
|
|
1237
|
+
const deleteReply = yield dwn.processMessage(alice.did, recordsDelete.message);
|
|
1238
|
+
expect(deleteReply.status.code).to.equal(202);
|
|
1239
|
+
// RecordsRead
|
|
1240
|
+
const recordsRead = yield RecordsRead.create({
|
|
1241
|
+
filter: {
|
|
1242
|
+
recordId: message.recordId,
|
|
1243
|
+
},
|
|
1244
|
+
signer: Jws.createSigner(alice)
|
|
1245
|
+
});
|
|
1246
|
+
const readReply = yield dwn.processMessage(alice.did, recordsRead.message);
|
|
1247
|
+
expect(readReply.status.code).to.equal(404);
|
|
1248
|
+
}));
|
|
1249
|
+
it('should return 404 underlying data store cannot locate the data when data is above threshold', () => __awaiter(this, void 0, void 0, function* () {
|
|
1250
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
1251
|
+
sinon.stub(dataStore, 'get').resolves(undefined);
|
|
1252
|
+
// insert data larger than the allowed amount in encodedData
|
|
1253
|
+
const { message, dataStream } = yield TestDataGenerator.generateRecordsWrite({
|
|
1254
|
+
author: alice,
|
|
1255
|
+
data: TestDataGenerator.randomBytes(DwnConstant.maxDataSizeAllowedToBeEncoded + 1)
|
|
1256
|
+
});
|
|
1257
|
+
const writeReply = yield dwn.processMessage(alice.did, message, { dataStream });
|
|
1258
|
+
expect(writeReply.status.code).to.equal(202);
|
|
1259
|
+
// testing RecordsRead
|
|
1260
|
+
const recordsRead = yield RecordsRead.create({
|
|
1261
|
+
filter: {
|
|
1262
|
+
recordId: message.recordId,
|
|
1263
|
+
},
|
|
1264
|
+
signer: Jws.createSigner(alice)
|
|
1265
|
+
});
|
|
1266
|
+
const readReply = yield dwn.processMessage(alice.did, recordsRead.message);
|
|
1267
|
+
expect(readReply.status.code).to.equal(404);
|
|
1268
|
+
}));
|
|
1269
|
+
describe('data from encodedData', () => {
|
|
1270
|
+
it('should not get data from DataStore if encodedData exists', () => __awaiter(this, void 0, void 0, function* () {
|
|
1271
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
1272
|
+
//since the data is at the threshold it will be returned from the messageStore in the `encodedData` field.
|
|
1273
|
+
const { message, dataStream, dataBytes } = yield TestDataGenerator.generateRecordsWrite({
|
|
1274
|
+
author: alice,
|
|
1275
|
+
data: TestDataGenerator.randomBytes(DwnConstant.maxDataSizeAllowedToBeEncoded)
|
|
1276
|
+
});
|
|
1277
|
+
const writeReply = yield dwn.processMessage(alice.did, message, { dataStream });
|
|
1278
|
+
expect(writeReply.status.code).to.equal(202);
|
|
1279
|
+
const recordRead = yield RecordsRead.create({
|
|
1280
|
+
filter: {
|
|
1281
|
+
recordId: message.recordId,
|
|
1282
|
+
},
|
|
1283
|
+
signer: Jws.createSigner(alice)
|
|
1284
|
+
});
|
|
1285
|
+
const dataStoreGet = sinon.spy(dataStore, 'get');
|
|
1286
|
+
const recordsReadResponse = yield dwn.processMessage(alice.did, recordRead.message);
|
|
1287
|
+
expect(recordsReadResponse.status.code).to.equal(200);
|
|
1288
|
+
expect(recordsReadResponse.entry.recordsWrite).to.exist;
|
|
1289
|
+
expect(recordsReadResponse.entry.data).to.exist;
|
|
1290
|
+
sinon.assert.notCalled(dataStoreGet);
|
|
1291
|
+
const readData = yield DataStream.toBytes(recordsReadResponse.entry.data);
|
|
1292
|
+
expect(readData).to.eql(dataBytes);
|
|
1293
|
+
}));
|
|
1294
|
+
it('should get data from DataStore if encodedData does not exist', () => __awaiter(this, void 0, void 0, function* () {
|
|
1295
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
1296
|
+
//since the data is over the threshold it will not be returned from the messageStore in the `encodedData` field.
|
|
1297
|
+
const { message, dataStream, dataBytes } = yield TestDataGenerator.generateRecordsWrite({
|
|
1298
|
+
author: alice,
|
|
1299
|
+
data: TestDataGenerator.randomBytes(DwnConstant.maxDataSizeAllowedToBeEncoded + 1)
|
|
1300
|
+
});
|
|
1301
|
+
const writeReply = yield dwn.processMessage(alice.did, message, { dataStream });
|
|
1302
|
+
expect(writeReply.status.code).to.equal(202);
|
|
1303
|
+
const recordRead = yield RecordsRead.create({
|
|
1304
|
+
filter: {
|
|
1305
|
+
recordId: message.recordId,
|
|
1306
|
+
},
|
|
1307
|
+
signer: Jws.createSigner(alice)
|
|
1308
|
+
});
|
|
1309
|
+
const dataStoreGet = sinon.spy(dataStore, 'get');
|
|
1310
|
+
const recordsReadResponse = yield dwn.processMessage(alice.did, recordRead.message);
|
|
1311
|
+
expect(recordsReadResponse.status.code).to.equal(200);
|
|
1312
|
+
expect(recordsReadResponse.entry.recordsWrite).to.exist;
|
|
1313
|
+
expect(recordsReadResponse.entry.data).to.exist;
|
|
1314
|
+
sinon.assert.calledOnce(dataStoreGet);
|
|
1315
|
+
const readData = yield DataStream.toBytes(recordsReadResponse.entry.data);
|
|
1316
|
+
expect(readData).to.eql(dataBytes);
|
|
1317
|
+
}));
|
|
1318
|
+
});
|
|
1319
|
+
describe('encryption scenarios', () => {
|
|
1320
|
+
it('should be able to decrypt flat-space schema-contained record with a correct derived key', () => __awaiter(this, void 0, void 0, function* () {
|
|
1321
|
+
// scenario: Alice writes into her own DWN an encrypted record and she is able to decrypt it
|
|
1322
|
+
const alice = yield TestDataGenerator.generatePersona();
|
|
1323
|
+
TestStubGenerator.stubDidResolver(didResolver, [alice]);
|
|
1324
|
+
// encrypt Alice's record
|
|
1325
|
+
const originalData = TestDataGenerator.randomBytes(1000);
|
|
1326
|
+
const originalDataStream = DataStream.fromBytes(originalData);
|
|
1327
|
+
const dataEncryptionInitializationVector = TestDataGenerator.randomBytes(16);
|
|
1328
|
+
const dataEncryptionKey = TestDataGenerator.randomBytes(32);
|
|
1329
|
+
const encryptedDataStream = yield Encryption.aes256CtrEncrypt(dataEncryptionKey, dataEncryptionInitializationVector, originalDataStream);
|
|
1330
|
+
const encryptedDataBytes = yield DataStream.toBytes(encryptedDataStream);
|
|
1331
|
+
// TODO: #450 - Should not require a root key to specify the derivation scheme (https://github.com/TBD54566975/dwn-sdk-js/issues/450)
|
|
1332
|
+
const rootPrivateKeyWithSchemasScheme = {
|
|
1333
|
+
rootKeyId: alice.keyId,
|
|
1334
|
+
derivationScheme: KeyDerivationScheme.Schemas,
|
|
1335
|
+
derivedPrivateKey: alice.keyPair.privateJwk
|
|
1336
|
+
};
|
|
1337
|
+
const schema = 'https://some-schema.com';
|
|
1338
|
+
const schemaDerivationPath = Records.constructKeyDerivationPathUsingSchemasScheme(schema);
|
|
1339
|
+
const schemaDerivedPrivateKey = yield HdKey.derivePrivateKey(rootPrivateKeyWithSchemasScheme, schemaDerivationPath);
|
|
1340
|
+
const schemaDerivedPublicKey = yield Secp256k1.getPublicJwk(schemaDerivedPrivateKey.derivedPrivateKey);
|
|
1341
|
+
const rootPrivateKeyWithDataFormatsScheme = {
|
|
1342
|
+
rootKeyId: alice.keyId,
|
|
1343
|
+
derivationScheme: KeyDerivationScheme.DataFormats,
|
|
1344
|
+
derivedPrivateKey: alice.keyPair.privateJwk
|
|
1345
|
+
};
|
|
1346
|
+
const dataFormat = 'some/format';
|
|
1347
|
+
const dataFormatDerivationPath = Records.constructKeyDerivationPathUsingDataFormatsScheme(schema, dataFormat);
|
|
1348
|
+
const dataFormatDerivedPublicKey = yield HdKey.derivePublicKey(rootPrivateKeyWithDataFormatsScheme, dataFormatDerivationPath);
|
|
1349
|
+
const encryptionInput = {
|
|
1350
|
+
initializationVector: dataEncryptionInitializationVector,
|
|
1351
|
+
key: dataEncryptionKey,
|
|
1352
|
+
keyEncryptionInputs: [{
|
|
1353
|
+
publicKeyId: alice.keyId, // reusing signing key for encryption purely as a convenience
|
|
1354
|
+
publicKey: schemaDerivedPublicKey,
|
|
1355
|
+
derivationScheme: KeyDerivationScheme.Schemas
|
|
1356
|
+
},
|
|
1357
|
+
{
|
|
1358
|
+
publicKeyId: alice.keyId, // reusing signing key for encryption purely as a convenience
|
|
1359
|
+
publicKey: dataFormatDerivedPublicKey,
|
|
1360
|
+
derivationScheme: KeyDerivationScheme.DataFormats
|
|
1361
|
+
}]
|
|
1362
|
+
};
|
|
1363
|
+
const { message, dataStream } = yield TestDataGenerator.generateRecordsWrite({
|
|
1364
|
+
author: alice,
|
|
1365
|
+
schema,
|
|
1366
|
+
dataFormat,
|
|
1367
|
+
data: encryptedDataBytes,
|
|
1368
|
+
encryptionInput
|
|
1369
|
+
});
|
|
1370
|
+
const writeReply = yield dwn.processMessage(alice.did, message, { dataStream });
|
|
1371
|
+
expect(writeReply.status.code).to.equal(202);
|
|
1372
|
+
const recordsRead = yield RecordsRead.create({
|
|
1373
|
+
filter: {
|
|
1374
|
+
recordId: message.recordId,
|
|
1375
|
+
},
|
|
1376
|
+
signer: Jws.createSigner(alice)
|
|
1377
|
+
});
|
|
1378
|
+
// test able to derive correct key using `schemas` scheme from root key to decrypt the message
|
|
1379
|
+
const readReply = yield dwn.processMessage(alice.did, recordsRead.message);
|
|
1380
|
+
expect(readReply.status.code).to.equal(200);
|
|
1381
|
+
const recordsWriteMessage = readReply.entry.recordsWrite;
|
|
1382
|
+
const cipherStream = readReply.entry.data;
|
|
1383
|
+
const plaintextDataStream = yield Records.decrypt(recordsWriteMessage, schemaDerivedPrivateKey, cipherStream);
|
|
1384
|
+
const plaintextBytes = yield DataStream.toBytes(plaintextDataStream);
|
|
1385
|
+
expect(ArrayUtility.byteArraysEqual(plaintextBytes, originalData)).to.be.true;
|
|
1386
|
+
// test able to derive correct key using `dataFormat` scheme from root key to decrypt the message
|
|
1387
|
+
const readReply2 = yield dwn.processMessage(alice.did, recordsRead.message); // send the same read message to get a new cipher stream
|
|
1388
|
+
expect(readReply2.status.code).to.equal(200);
|
|
1389
|
+
const cipherStream2 = readReply2.entry.data;
|
|
1390
|
+
const plaintextDataStream2 = yield Records.decrypt(recordsWriteMessage, rootPrivateKeyWithDataFormatsScheme, cipherStream2);
|
|
1391
|
+
const plaintextBytes2 = yield DataStream.toBytes(plaintextDataStream2);
|
|
1392
|
+
expect(ArrayUtility.byteArraysEqual(plaintextBytes2, originalData)).to.be.true;
|
|
1393
|
+
// test unable to decrypt the message if dataFormat-derived key is derived without taking `schema` as input to derivation path
|
|
1394
|
+
const readReply3 = yield dwn.processMessage(alice.did, recordsRead.message); // process the same read message to get a new cipher stream
|
|
1395
|
+
expect(readReply3.status.code).to.equal(200);
|
|
1396
|
+
const cipherStream3 = readReply3.entry.data;
|
|
1397
|
+
const invalidDerivationPath = [KeyDerivationScheme.DataFormats, message.descriptor.dataFormat];
|
|
1398
|
+
const inValidDescendantPrivateKey = yield HdKey.derivePrivateKey(rootPrivateKeyWithDataFormatsScheme, invalidDerivationPath);
|
|
1399
|
+
yield expect(Records.decrypt(recordsWriteMessage, inValidDescendantPrivateKey, cipherStream3)).to.be.rejectedWith(DwnErrorCode.RecordsInvalidAncestorKeyDerivationSegment);
|
|
1400
|
+
}));
|
|
1401
|
+
it('should be able to decrypt flat-space schema-less record with the correct derived key', () => __awaiter(this, void 0, void 0, function* () {
|
|
1402
|
+
// scenario: Alice writes into her own DWN an encrypted record and she is able to decrypt it
|
|
1403
|
+
const alice = yield TestDataGenerator.generatePersona();
|
|
1404
|
+
TestStubGenerator.stubDidResolver(didResolver, [alice]);
|
|
1405
|
+
// encrypt Alice's record
|
|
1406
|
+
const originalData = TestDataGenerator.randomBytes(1000);
|
|
1407
|
+
const originalDataStream = DataStream.fromBytes(originalData);
|
|
1408
|
+
const dataEncryptionInitializationVector = TestDataGenerator.randomBytes(16);
|
|
1409
|
+
const dataEncryptionKey = TestDataGenerator.randomBytes(32);
|
|
1410
|
+
const encryptedDataStream = yield Encryption.aes256CtrEncrypt(dataEncryptionKey, dataEncryptionInitializationVector, originalDataStream);
|
|
1411
|
+
const encryptedDataBytes = yield DataStream.toBytes(encryptedDataStream);
|
|
1412
|
+
// TODO: #450 - Should not require a root key to specify the derivation scheme (https://github.com/TBD54566975/dwn-sdk-js/issues/450)
|
|
1413
|
+
const rootPrivateKeyWithDataFormatsScheme = {
|
|
1414
|
+
rootKeyId: alice.keyId,
|
|
1415
|
+
derivationScheme: KeyDerivationScheme.DataFormats,
|
|
1416
|
+
derivedPrivateKey: alice.keyPair.privateJwk
|
|
1417
|
+
};
|
|
1418
|
+
const dataFormat = `image/jpg`;
|
|
1419
|
+
const dataFormatDerivationPath = Records.constructKeyDerivationPathUsingDataFormatsScheme(undefined, dataFormat);
|
|
1420
|
+
const dataFormatDerivedPublicKey = yield HdKey.derivePublicKey(rootPrivateKeyWithDataFormatsScheme, dataFormatDerivationPath);
|
|
1421
|
+
const encryptionInput = {
|
|
1422
|
+
initializationVector: dataEncryptionInitializationVector,
|
|
1423
|
+
key: dataEncryptionKey,
|
|
1424
|
+
keyEncryptionInputs: [{
|
|
1425
|
+
publicKeyId: alice.keyId, // reusing signing key for encryption purely as a convenience
|
|
1426
|
+
publicKey: dataFormatDerivedPublicKey,
|
|
1427
|
+
derivationScheme: KeyDerivationScheme.DataFormats
|
|
1428
|
+
}]
|
|
1429
|
+
};
|
|
1430
|
+
const recordsWrite = yield RecordsWrite.create({
|
|
1431
|
+
signer: Jws.createSigner(alice),
|
|
1432
|
+
dataFormat,
|
|
1433
|
+
data: encryptedDataBytes,
|
|
1434
|
+
encryptionInput
|
|
1435
|
+
});
|
|
1436
|
+
const dataStream = DataStream.fromBytes(encryptedDataBytes);
|
|
1437
|
+
const writeReply = yield dwn.processMessage(alice.did, recordsWrite.message, { dataStream });
|
|
1438
|
+
expect(writeReply.status.code).to.equal(202);
|
|
1439
|
+
const recordsRead = yield RecordsRead.create({
|
|
1440
|
+
filter: {
|
|
1441
|
+
recordId: recordsWrite.message.recordId,
|
|
1442
|
+
},
|
|
1443
|
+
signer: Jws.createSigner(alice)
|
|
1444
|
+
});
|
|
1445
|
+
// test able to derive correct key using `dataFormat` scheme from root key to decrypt the message
|
|
1446
|
+
const readReply = yield dwn.processMessage(alice.did, recordsRead.message); // send the same read message to get a new cipher stream
|
|
1447
|
+
expect(readReply.status.code).to.equal(200);
|
|
1448
|
+
const cipherStream = readReply.entry.data;
|
|
1449
|
+
const recordsWriteMessage = readReply.entry.recordsWrite;
|
|
1450
|
+
const plaintextDataStream = yield Records.decrypt(recordsWriteMessage, rootPrivateKeyWithDataFormatsScheme, cipherStream);
|
|
1451
|
+
const plaintextBytes = yield DataStream.toBytes(plaintextDataStream);
|
|
1452
|
+
expect(ArrayUtility.byteArraysEqual(plaintextBytes, originalData)).to.be.true;
|
|
1453
|
+
}));
|
|
1454
|
+
it('should only be able to decrypt record with a correct derived private key - `protocol-context` derivation scheme', () => __awaiter(this, void 0, void 0, function* () {
|
|
1455
|
+
// scenario: Bob initiated an encrypted chat thread with Alice,
|
|
1456
|
+
// bob is able to decrypt subsequent messages from Alice using the `protocol-context` derived private key
|
|
1457
|
+
// creating Alice and Bob persona and setting up a stub DID resolver
|
|
1458
|
+
const alice = yield TestDataGenerator.generatePersona();
|
|
1459
|
+
const bob = yield TestDataGenerator.generatePersona();
|
|
1460
|
+
TestStubGenerator.stubDidResolver(didResolver, [alice, bob]);
|
|
1461
|
+
// Alice configures chat protocol with encryption
|
|
1462
|
+
const protocolDefinition = chatProtocolDefinition;
|
|
1463
|
+
const protocolDefinitionForAlice = yield Protocols.deriveAndInjectPublicEncryptionKeys(protocolDefinition, alice.keyId, alice.keyPair.privateJwk);
|
|
1464
|
+
const protocolsConfigureForAlice = yield TestDataGenerator.generateProtocolsConfigure({
|
|
1465
|
+
author: alice,
|
|
1466
|
+
protocolDefinition: protocolDefinitionForAlice
|
|
1467
|
+
});
|
|
1468
|
+
const protocolsConfigureForAliceReply = yield dwn.processMessage(alice.did, protocolsConfigureForAlice.message);
|
|
1469
|
+
expect(protocolsConfigureForAliceReply.status.code).to.equal(202);
|
|
1470
|
+
// Bob configures chat protocol with encryption
|
|
1471
|
+
const protocolDefinitionForBob = yield Protocols.deriveAndInjectPublicEncryptionKeys(protocolDefinition, bob.keyId, bob.keyPair.privateJwk);
|
|
1472
|
+
const protocolsConfigureForBob = yield TestDataGenerator.generateProtocolsConfigure({
|
|
1473
|
+
author: bob,
|
|
1474
|
+
protocolDefinition: protocolDefinitionForBob
|
|
1475
|
+
});
|
|
1476
|
+
const protocolsConfigureReply = yield dwn.processMessage(bob.did, protocolsConfigureForBob.message);
|
|
1477
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
1478
|
+
// Bob queries for Alice's chat protocol definition
|
|
1479
|
+
const protocolsQuery = yield ProtocolsQuery.create({
|
|
1480
|
+
filter: { protocol: chatProtocolDefinition.protocol }
|
|
1481
|
+
});
|
|
1482
|
+
const protocolsQueryReply = yield dwn.processMessage(alice.did, protocolsQuery.message);
|
|
1483
|
+
const protocolsConfigureMessageReceived = protocolsQueryReply.entries[0];
|
|
1484
|
+
// Bob verifies that the chat protocol definition is authored by Alice
|
|
1485
|
+
yield authenticate(protocolsConfigureMessageReceived.authorization, didResolver);
|
|
1486
|
+
const protocolsConfigureFetched = yield ProtocolsConfigure.parse(protocolsConfigureMessageReceived);
|
|
1487
|
+
expect(protocolsConfigureFetched.author).to.equal(alice.did);
|
|
1488
|
+
// Bob creates an initiating a chat thread RecordsWrite
|
|
1489
|
+
const plaintextMessageToAlice = TestDataGenerator.randomBytes(100);
|
|
1490
|
+
const { message: threadMessage, dataStream, recordsWrite, encryptedDataBytes, encryptionInput } = yield TestDataGenerator.generateProtocolEncryptedRecordsWrite({
|
|
1491
|
+
plaintextBytes: plaintextMessageToAlice,
|
|
1492
|
+
author: bob,
|
|
1493
|
+
protocolDefinition: protocolsConfigureForAlice.message.descriptor.definition,
|
|
1494
|
+
protocolPath: 'thread',
|
|
1495
|
+
encryptSymmetricKeyWithProtocolPathDerivedKey: true,
|
|
1496
|
+
encryptSymmetricKeyWithProtocolContextDerivedKey: true
|
|
1497
|
+
});
|
|
1498
|
+
// Bob writes the encrypted chat thread to Alice's DWN
|
|
1499
|
+
const bobToAliceWriteReply = yield dwn.processMessage(alice.did, threadMessage, { dataStream });
|
|
1500
|
+
expect(bobToAliceWriteReply.status.code).to.equal(202);
|
|
1501
|
+
// Bob also needs to write the same encrypted chat thread to his own DWN
|
|
1502
|
+
// Opportunity here to create a much nicer utility method for this entire block
|
|
1503
|
+
const bobToBobRecordsWrite = yield RecordsWrite.createFrom({
|
|
1504
|
+
recordsWriteMessage: recordsWrite.message,
|
|
1505
|
+
messageTimestamp: recordsWrite.message.descriptor.messageTimestamp
|
|
1506
|
+
});
|
|
1507
|
+
const bobRootPrivateKey = {
|
|
1508
|
+
rootKeyId: bob.keyId,
|
|
1509
|
+
derivationScheme: KeyDerivationScheme.ProtocolContext,
|
|
1510
|
+
derivedPrivateKey: bob.keyPair.privateJwk
|
|
1511
|
+
};
|
|
1512
|
+
const protocolPathDerivationPath = Records.constructKeyDerivationPathUsingProtocolPathScheme(recordsWrite.message.descriptor);
|
|
1513
|
+
const protocolPathDerivedPublicJwkForBobsDwn = yield HdKey.derivePublicKey(bobRootPrivateKey, protocolPathDerivationPath);
|
|
1514
|
+
const protocolPathDerivedKeyEncryptionInputForBobsDwn = {
|
|
1515
|
+
publicKeyId: bob.keyId, // reusing signing key for encryption purely as a convenience
|
|
1516
|
+
publicKey: protocolPathDerivedPublicJwkForBobsDwn,
|
|
1517
|
+
derivationScheme: KeyDerivationScheme.ProtocolPath
|
|
1518
|
+
};
|
|
1519
|
+
const encryptionInputForBobsDwn = encryptionInput;
|
|
1520
|
+
const indexOfKeyEncryptionInputToReplace = encryptionInputForBobsDwn.keyEncryptionInputs.findIndex(input => input.derivationScheme === KeyDerivationScheme.ProtocolPath);
|
|
1521
|
+
encryptionInputForBobsDwn.keyEncryptionInputs[indexOfKeyEncryptionInputToReplace] = protocolPathDerivedKeyEncryptionInputForBobsDwn;
|
|
1522
|
+
yield bobToBobRecordsWrite.encryptSymmetricEncryptionKey(encryptionInputForBobsDwn);
|
|
1523
|
+
yield bobToBobRecordsWrite.sign({ signer: Jws.createSigner(bob) });
|
|
1524
|
+
const dataStreamForBobsDwn = DataStream.fromBytes(encryptedDataBytes);
|
|
1525
|
+
const bobToBobWriteReply = yield dwn.processMessage(bob.did, bobToBobRecordsWrite.message, { dataStream: dataStreamForBobsDwn });
|
|
1526
|
+
expect(bobToBobWriteReply.status.code).to.equal(202);
|
|
1527
|
+
// NOTE: we know Alice is able to decrypt the message using protocol-path derived key through other tests, so we won't verify it again
|
|
1528
|
+
// test that anyone with the protocol-context derived private key is able to decrypt the message
|
|
1529
|
+
const recordsRead = yield RecordsRead.create({
|
|
1530
|
+
filter: {
|
|
1531
|
+
recordId: threadMessage.recordId,
|
|
1532
|
+
},
|
|
1533
|
+
signer: Jws.createSigner(alice)
|
|
1534
|
+
});
|
|
1535
|
+
const readReply = yield dwn.processMessage(alice.did, recordsRead.message);
|
|
1536
|
+
expect(readReply.status.code).to.equal(200);
|
|
1537
|
+
const fetchedRecordsWrite = readReply.entry.recordsWrite;
|
|
1538
|
+
const cipherStream = readReply.entry.data;
|
|
1539
|
+
const derivationPathFromReadContext = Records.constructKeyDerivationPathUsingProtocolContextScheme(fetchedRecordsWrite.contextId);
|
|
1540
|
+
const protocolContextDerivedPrivateJwk = yield HdKey.derivePrivateKey(bobRootPrivateKey, derivationPathFromReadContext);
|
|
1541
|
+
const plaintextDataStream = yield Records.decrypt(fetchedRecordsWrite, protocolContextDerivedPrivateJwk, cipherStream);
|
|
1542
|
+
const plaintextBytes = yield DataStream.toBytes(plaintextDataStream);
|
|
1543
|
+
expect(ArrayUtility.byteArraysEqual(plaintextBytes, plaintextMessageToAlice)).to.be.true;
|
|
1544
|
+
// verify that Alice is able to send an encrypted message using the protocol-context derived public key and Bob is able to decrypt it
|
|
1545
|
+
// NOTE: we will skip verification of Bob's protocol configuration because we have test the such scenario above as well as in other tests
|
|
1546
|
+
const { derivedPublicKey: protocolContextDerivedPublicJwkReturned, rootKeyId: protocolContextDerivingRootKeyIdReturned } = fetchedRecordsWrite.encryption.keyEncryption.find(encryptedKey => encryptedKey.derivationScheme === KeyDerivationScheme.ProtocolContext);
|
|
1547
|
+
const plaintextMessageToBob = TestDataGenerator.randomBytes(100);
|
|
1548
|
+
const recordsWriteToBob = yield TestDataGenerator.generateProtocolEncryptedRecordsWrite({
|
|
1549
|
+
plaintextBytes: plaintextMessageToBob,
|
|
1550
|
+
author: alice,
|
|
1551
|
+
protocolDefinition: protocolsConfigureForBob.message.descriptor.definition,
|
|
1552
|
+
protocolPath: 'thread/message',
|
|
1553
|
+
protocolParentContextId: fetchedRecordsWrite.contextId,
|
|
1554
|
+
protocolContextDerivingRootKeyId: protocolContextDerivingRootKeyIdReturned,
|
|
1555
|
+
protocolContextDerivedPublicJwk: protocolContextDerivedPublicJwkReturned,
|
|
1556
|
+
encryptSymmetricKeyWithProtocolPathDerivedKey: true,
|
|
1557
|
+
encryptSymmetricKeyWithProtocolContextDerivedKey: true
|
|
1558
|
+
});
|
|
1559
|
+
// Alice sends the message to Bob
|
|
1560
|
+
const aliceWriteReply = yield dwn.processMessage(bob.did, recordsWriteToBob.message, { dataStream: recordsWriteToBob.dataStream });
|
|
1561
|
+
expect(aliceWriteReply.status.code).to.equal(202);
|
|
1562
|
+
// test that Bob is able to read and decrypt Alice's message
|
|
1563
|
+
const recordsReadByBob = yield RecordsRead.create({
|
|
1564
|
+
filter: {
|
|
1565
|
+
recordId: recordsWriteToBob.message.recordId,
|
|
1566
|
+
},
|
|
1567
|
+
signer: Jws.createSigner(bob)
|
|
1568
|
+
});
|
|
1569
|
+
const readByBobReply = yield dwn.processMessage(bob.did, recordsReadByBob.message);
|
|
1570
|
+
expect(readByBobReply.status.code).to.equal(200);
|
|
1571
|
+
const fetchedRecordsWrite2 = readByBobReply.entry.recordsWrite;
|
|
1572
|
+
const cipherStream2 = readByBobReply.entry.data;
|
|
1573
|
+
const plaintextDataStream2 = yield Records.decrypt(fetchedRecordsWrite2, protocolContextDerivedPrivateJwk, cipherStream2);
|
|
1574
|
+
const plaintextBytes2 = yield DataStream.toBytes(plaintextDataStream2);
|
|
1575
|
+
expect(ArrayUtility.byteArraysEqual(plaintextBytes2, plaintextMessageToBob)).to.be.true;
|
|
1576
|
+
}));
|
|
1577
|
+
it('should only be able to decrypt record with a correct derived private key - `protocols` derivation scheme', () => __awaiter(this, void 0, void 0, function* () {
|
|
1578
|
+
// scenario: Bob writes into Alice's DWN an encrypted "email", alice is able to decrypt it
|
|
1579
|
+
var _a;
|
|
1580
|
+
// creating Alice and Bob persona and setting up a stub DID resolver
|
|
1581
|
+
const alice = yield TestDataGenerator.generatePersona();
|
|
1582
|
+
const bob = yield TestDataGenerator.generatePersona();
|
|
1583
|
+
TestStubGenerator.stubDidResolver(didResolver, [alice, bob]);
|
|
1584
|
+
// Alice configures email protocol with encryption
|
|
1585
|
+
const protocolDefinition = emailProtocolDefinition;
|
|
1586
|
+
const encryptedProtocolDefinition = yield Protocols.deriveAndInjectPublicEncryptionKeys(protocolDefinition, alice.keyId, alice.keyPair.privateJwk);
|
|
1587
|
+
const protocolsConfigure = yield TestDataGenerator.generateProtocolsConfigure({
|
|
1588
|
+
author: alice,
|
|
1589
|
+
protocolDefinition: encryptedProtocolDefinition
|
|
1590
|
+
});
|
|
1591
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfigure.message);
|
|
1592
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
1593
|
+
// Bob queries for Alice's email protocol definition
|
|
1594
|
+
const protocolsQuery = yield ProtocolsQuery.create({
|
|
1595
|
+
filter: { protocol: emailProtocolDefinition.protocol }
|
|
1596
|
+
});
|
|
1597
|
+
const protocolsQueryReply = yield dwn.processMessage(alice.did, protocolsQuery.message);
|
|
1598
|
+
const protocolsConfigureMessageReceived = protocolsQueryReply.entries[0];
|
|
1599
|
+
// Bob verifies that the email protocol definition is authored by Alice
|
|
1600
|
+
yield authenticate(protocolsConfigureMessageReceived.authorization, didResolver);
|
|
1601
|
+
const protocolsConfigureFetched = yield ProtocolsConfigure.parse(protocolsConfigureMessageReceived);
|
|
1602
|
+
expect(protocolsConfigureFetched.author).to.equal(alice.did);
|
|
1603
|
+
// Bob encrypts his email to Alice with a randomly generated symmetric key
|
|
1604
|
+
const bobMessageBytes = TestDataGenerator.randomBytes(100);
|
|
1605
|
+
const bobMessageStream = DataStream.fromBytes(bobMessageBytes);
|
|
1606
|
+
const dataEncryptionInitializationVector = TestDataGenerator.randomBytes(16);
|
|
1607
|
+
const dataEncryptionKey = TestDataGenerator.randomBytes(32);
|
|
1608
|
+
const bobMessageEncryptedStream = yield Encryption.aes256CtrEncrypt(dataEncryptionKey, dataEncryptionInitializationVector, bobMessageStream);
|
|
1609
|
+
const bobMessageEncryptedBytes = yield DataStream.toBytes(bobMessageEncryptedStream);
|
|
1610
|
+
// Bob generates an encrypted RecordsWrite,
|
|
1611
|
+
// the public encryption key designated by Alice is used to encrypt the symmetric key Bob generated above
|
|
1612
|
+
const publicJwk = (_a = protocolsConfigureFetched.message.descriptor.definition.structure.email.$encryption) === null || _a === void 0 ? void 0 : _a.publicKeyJwk;
|
|
1613
|
+
expect(publicJwk).to.not.be.undefined;
|
|
1614
|
+
const encryptionInput = {
|
|
1615
|
+
initializationVector: dataEncryptionInitializationVector,
|
|
1616
|
+
key: dataEncryptionKey,
|
|
1617
|
+
keyEncryptionInputs: [{
|
|
1618
|
+
publicKeyId: alice.keyId, // reusing signing key for encryption purely as a convenience
|
|
1619
|
+
publicKey: publicJwk,
|
|
1620
|
+
derivationScheme: KeyDerivationScheme.ProtocolPath
|
|
1621
|
+
}]
|
|
1622
|
+
};
|
|
1623
|
+
const { message, dataStream } = yield TestDataGenerator.generateRecordsWrite({
|
|
1624
|
+
author: bob,
|
|
1625
|
+
protocol: protocolDefinition.protocol,
|
|
1626
|
+
protocolPath: 'email', // this comes from `types` in protocol definition
|
|
1627
|
+
schema: protocolDefinition.types.email.schema,
|
|
1628
|
+
dataFormat: protocolDefinition.types.email.dataFormats[0],
|
|
1629
|
+
data: bobMessageEncryptedBytes,
|
|
1630
|
+
encryptionInput
|
|
1631
|
+
});
|
|
1632
|
+
// Bob writes the encrypted email to Alice's DWN
|
|
1633
|
+
const bobWriteReply = yield dwn.processMessage(alice.did, message, { dataStream });
|
|
1634
|
+
expect(bobWriteReply.status.code).to.equal(202);
|
|
1635
|
+
// Alice reads the encrypted email
|
|
1636
|
+
// assume Alice already made query to get the `recordId` of the email
|
|
1637
|
+
const recordsRead = yield RecordsRead.create({
|
|
1638
|
+
filter: {
|
|
1639
|
+
recordId: message.recordId,
|
|
1640
|
+
},
|
|
1641
|
+
signer: Jws.createSigner(alice)
|
|
1642
|
+
});
|
|
1643
|
+
const readReply = yield dwn.processMessage(alice.did, recordsRead.message);
|
|
1644
|
+
expect(readReply.status.code).to.equal(200);
|
|
1645
|
+
// test that Alice is able decrypt the encrypted email from Bob using the root key
|
|
1646
|
+
const rootPrivateKey = {
|
|
1647
|
+
rootKeyId: alice.keyId,
|
|
1648
|
+
derivationScheme: KeyDerivationScheme.ProtocolPath,
|
|
1649
|
+
derivedPrivateKey: alice.keyPair.privateJwk
|
|
1650
|
+
};
|
|
1651
|
+
const fetchedRecordsWrite = readReply.entry.recordsWrite;
|
|
1652
|
+
const cipherStream = readReply.entry.data;
|
|
1653
|
+
const plaintextDataStream = yield Records.decrypt(fetchedRecordsWrite, rootPrivateKey, cipherStream);
|
|
1654
|
+
const plaintextBytes = yield DataStream.toBytes(plaintextDataStream);
|
|
1655
|
+
expect(ArrayUtility.byteArraysEqual(plaintextBytes, bobMessageBytes)).to.be.true;
|
|
1656
|
+
// test that a correct derived key is able decrypt the encrypted email from Bob
|
|
1657
|
+
const readReply2 = yield dwn.processMessage(alice.did, recordsRead.message);
|
|
1658
|
+
expect(readReply2.status.code).to.equal(200);
|
|
1659
|
+
const relativeDescendantDerivationPath = Records.constructKeyDerivationPath(KeyDerivationScheme.ProtocolPath, fetchedRecordsWrite);
|
|
1660
|
+
const derivedPrivateKey = yield HdKey.derivePrivateKey(rootPrivateKey, relativeDescendantDerivationPath);
|
|
1661
|
+
const fetchedRecordsWrite2 = readReply2.entry.recordsWrite;
|
|
1662
|
+
const cipherStream2 = readReply2.entry.data;
|
|
1663
|
+
const plaintextDataStream2 = yield Records.decrypt(fetchedRecordsWrite2, derivedPrivateKey, cipherStream2);
|
|
1664
|
+
const plaintextBytes2 = yield DataStream.toBytes(plaintextDataStream2);
|
|
1665
|
+
expect(ArrayUtility.byteArraysEqual(plaintextBytes2, bobMessageBytes)).to.be.true;
|
|
1666
|
+
// test unable to decrypt the message if derived key has an unexpected path
|
|
1667
|
+
const invalidDerivationPath = [KeyDerivationScheme.ProtocolPath, protocolDefinition.protocol, 'invalidContextId'];
|
|
1668
|
+
const inValidDescendantPrivateKey = yield HdKey.derivePrivateKey(rootPrivateKey, invalidDerivationPath);
|
|
1669
|
+
yield expect(Records.decrypt(fetchedRecordsWrite, inValidDescendantPrivateKey, cipherStream)).to.be.rejectedWith(DwnErrorCode.RecordsInvalidAncestorKeyDerivationSegment);
|
|
1670
|
+
// test unable to decrypt the message if no derivation scheme used by the message matches the scheme used by the given private key
|
|
1671
|
+
const privateKeyWithMismatchingDerivationScheme = {
|
|
1672
|
+
rootKeyId: alice.keyId,
|
|
1673
|
+
derivationScheme: 'scheme-that-is-not-protocol-context',
|
|
1674
|
+
derivedPrivateKey: alice.keyPair.privateJwk
|
|
1675
|
+
};
|
|
1676
|
+
yield expect(Records.decrypt(fetchedRecordsWrite, privateKeyWithMismatchingDerivationScheme, cipherStream)).to.be.rejectedWith(DwnErrorCode.RecordsDecryptNoMatchingKeyEncryptedFound);
|
|
1677
|
+
// test unable to decrypt the message if public key ID does not match the derived private key
|
|
1678
|
+
const privateKeyWithMismatchingKeyId = {
|
|
1679
|
+
rootKeyId: 'mismatchingKeyId',
|
|
1680
|
+
derivationScheme: KeyDerivationScheme.ProtocolPath,
|
|
1681
|
+
derivedPrivateKey: alice.keyPair.privateJwk
|
|
1682
|
+
};
|
|
1683
|
+
yield expect(Records.decrypt(fetchedRecordsWrite, privateKeyWithMismatchingKeyId, cipherStream)).to.be.rejectedWith(DwnErrorCode.RecordsDecryptNoMatchingKeyEncryptedFound);
|
|
1684
|
+
}));
|
|
1685
|
+
});
|
|
1686
|
+
});
|
|
1687
|
+
it('should return 401 if signature check fails', () => __awaiter(this, void 0, void 0, function* () {
|
|
1688
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
1689
|
+
const recordsRead = yield RecordsRead.create({
|
|
1690
|
+
filter: {
|
|
1691
|
+
recordId: 'any-id',
|
|
1692
|
+
},
|
|
1693
|
+
signer: Jws.createSigner(alice)
|
|
1694
|
+
});
|
|
1695
|
+
// setting up a stub did resolver & message store
|
|
1696
|
+
// intentionally not supplying the public key so a different public key is generated to simulate invalid signature
|
|
1697
|
+
const mismatchingPersona = yield TestDataGenerator.generatePersona({ did: alice.did, keyId: alice.keyId });
|
|
1698
|
+
const didResolver = TestStubGenerator.createDidResolverStub(mismatchingPersona);
|
|
1699
|
+
const messageStoreStub = sinon.createStubInstance(MessageStoreLevel);
|
|
1700
|
+
const dataStoreStub = sinon.createStubInstance(DataStoreLevel);
|
|
1701
|
+
const recordsReadHandler = new RecordsReadHandler(didResolver, messageStoreStub, dataStoreStub);
|
|
1702
|
+
const reply = yield recordsReadHandler.handle({ tenant: alice.did, message: recordsRead.message });
|
|
1703
|
+
expect(reply.status.code).to.equal(401);
|
|
1704
|
+
}));
|
|
1705
|
+
it('should return 400 if fail parsing the message', () => __awaiter(this, void 0, void 0, function* () {
|
|
1706
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
1707
|
+
const recordsRead = yield RecordsRead.create({
|
|
1708
|
+
filter: {
|
|
1709
|
+
recordId: 'any-id',
|
|
1710
|
+
},
|
|
1711
|
+
signer: Jws.createSigner(alice)
|
|
1712
|
+
});
|
|
1713
|
+
// setting up a stub method resolver & message store
|
|
1714
|
+
const messageStoreStub = sinon.createStubInstance(MessageStoreLevel);
|
|
1715
|
+
const dataStoreStub = sinon.createStubInstance(DataStoreLevel);
|
|
1716
|
+
const recordsReadHandler = new RecordsReadHandler(didResolver, messageStoreStub, dataStoreStub);
|
|
1717
|
+
// stub the `parse()` function to throw an error
|
|
1718
|
+
sinon.stub(RecordsRead, 'parse').throws('anyError');
|
|
1719
|
+
const reply = yield recordsReadHandler.handle({ tenant: alice.did, message: recordsRead.message });
|
|
1720
|
+
expect(reply.status.code).to.equal(400);
|
|
1721
|
+
}));
|
|
1722
|
+
});
|
|
1723
|
+
}
|
|
1724
|
+
//# sourceMappingURL=records-read.spec.js.map
|