@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,3637 @@
|
|
|
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 anyoneCollaborateProtocolDefinition from '../vectors/protocol-definitions/anyone-collaborate.json' assert { type: 'json' };
|
|
11
|
+
import authorCanProtocolDefinition from '../vectors/protocol-definitions/author-can.json' assert { type: 'json' };
|
|
12
|
+
import chaiAsPromised from 'chai-as-promised';
|
|
13
|
+
import credentialIssuanceProtocolDefinition from '../vectors/protocol-definitions/credential-issuance.json' assert { type: 'json' };
|
|
14
|
+
import dexProtocolDefinition from '../vectors/protocol-definitions/dex.json' assert { type: 'json' };
|
|
15
|
+
import emailProtocolDefinition from '../vectors/protocol-definitions/email.json' assert { type: 'json' };
|
|
16
|
+
import friendRoleProtocolDefinition from '../vectors/protocol-definitions/friend-role.json' assert { type: 'json' };
|
|
17
|
+
import messageProtocolDefinition from '../vectors/protocol-definitions/message.json' assert { type: 'json' };
|
|
18
|
+
import minimalProtocolDefinition from '../vectors/protocol-definitions/minimal.json' assert { type: 'json' };
|
|
19
|
+
import nestedProtocol from '../vectors/protocol-definitions/nested.json' assert { type: 'json' };
|
|
20
|
+
import privateProtocol from '../vectors/protocol-definitions/private-protocol.json' assert { type: 'json' };
|
|
21
|
+
import recipientCanProtocol from '../vectors/protocol-definitions/recipient-can.json' assert { type: 'json' };
|
|
22
|
+
import sinon from 'sinon';
|
|
23
|
+
import socialMediaProtocolDefinition from '../vectors/protocol-definitions/social-media.json' assert { type: 'json' };
|
|
24
|
+
import threadRoleProtocolDefinition from '../vectors/protocol-definitions/thread-role.json' assert { type: 'json' };
|
|
25
|
+
import chai, { expect } from 'chai';
|
|
26
|
+
import { ArrayUtility } from '../../src/utils/array.js';
|
|
27
|
+
import { base64url } from 'multiformats/bases/base64';
|
|
28
|
+
import { Cid } from '../../src/utils/cid.js';
|
|
29
|
+
import { DataStream } from '../../src/utils/data-stream.js';
|
|
30
|
+
import { Dwn } from '../../src/dwn.js';
|
|
31
|
+
import { Encoder } from '../../src/utils/encoder.js';
|
|
32
|
+
import { GeneralJwsBuilder } from '../../src/jose/jws/general/builder.js';
|
|
33
|
+
import { Jws } from '../../src/utils/jws.js';
|
|
34
|
+
import { Message } from '../../src/core/message.js';
|
|
35
|
+
import { PermissionConditionPublication } from '../../src/types/permission-types.js';
|
|
36
|
+
import { RecordsRead } from '../../src/interfaces/records-read.js';
|
|
37
|
+
import { RecordsWrite } from '../../src/interfaces/records-write.js';
|
|
38
|
+
import { RecordsWriteHandler } from '../../src/handlers/records-write.js';
|
|
39
|
+
import { TestDataGenerator } from '../utils/test-data-generator.js';
|
|
40
|
+
import { TestEventStream } from '../test-event-stream.js';
|
|
41
|
+
import { TestStores } from '../test-stores.js';
|
|
42
|
+
import { TestStubGenerator } from '../utils/test-stub-generator.js';
|
|
43
|
+
import { Time } from '../../src/utils/time.js';
|
|
44
|
+
import { DwnError, DwnErrorCode } from '../../src/core/dwn-error.js';
|
|
45
|
+
import { DataStoreLevel, DwnConstant, DwnInterfaceName, DwnMethodName, KeyDerivationScheme, MessageStoreLevel, PermissionsProtocol, RecordsDelete, RecordsQuery } from '../../src/index.js';
|
|
46
|
+
import { DidKey, UniversalResolver } from '@enbox/dids';
|
|
47
|
+
import { Encryption, EncryptionAlgorithm } from '../../src/utils/encryption.js';
|
|
48
|
+
chai.use(chaiAsPromised);
|
|
49
|
+
export function testRecordsWriteHandler() {
|
|
50
|
+
describe('RecordsWriteHandler.handle()', () => __awaiter(this, void 0, void 0, function* () {
|
|
51
|
+
let didResolver;
|
|
52
|
+
let messageStore;
|
|
53
|
+
let dataStore;
|
|
54
|
+
let resumableTaskStore;
|
|
55
|
+
let eventLog;
|
|
56
|
+
let eventStream;
|
|
57
|
+
let dwn;
|
|
58
|
+
beforeEach(() => {
|
|
59
|
+
sinon.restore();
|
|
60
|
+
});
|
|
61
|
+
describe('functional tests', () => {
|
|
62
|
+
// important to follow the `before` and `after` pattern to initialize and clean the stores in tests
|
|
63
|
+
// so that different test suites can reuse the same backend store for testing
|
|
64
|
+
before(() => __awaiter(this, void 0, void 0, function* () {
|
|
65
|
+
didResolver = new UniversalResolver({ didResolvers: [DidKey] });
|
|
66
|
+
const stores = TestStores.get();
|
|
67
|
+
messageStore = stores.messageStore;
|
|
68
|
+
dataStore = stores.dataStore;
|
|
69
|
+
resumableTaskStore = stores.resumableTaskStore;
|
|
70
|
+
eventLog = stores.eventLog;
|
|
71
|
+
eventStream = TestEventStream.get();
|
|
72
|
+
dwn = yield Dwn.create({ didResolver, messageStore, dataStore, eventLog, eventStream, resumableTaskStore });
|
|
73
|
+
}));
|
|
74
|
+
beforeEach(() => __awaiter(this, void 0, void 0, function* () {
|
|
75
|
+
// clean up before each test rather than after so that a test does not depend on other tests to do the clean up
|
|
76
|
+
yield messageStore.clear();
|
|
77
|
+
yield dataStore.clear();
|
|
78
|
+
yield resumableTaskStore.clear();
|
|
79
|
+
yield eventLog.clear();
|
|
80
|
+
}));
|
|
81
|
+
after(() => __awaiter(this, void 0, void 0, function* () {
|
|
82
|
+
yield dwn.close();
|
|
83
|
+
}));
|
|
84
|
+
it('should call preProcessingForCoreRecordsWrite after authorization and before storage', () => __awaiter(this, void 0, void 0, function* () {
|
|
85
|
+
// We create spy or stub for authorization, preProcessingForCoreRecordsWrite and processMessageWithDataStream methods
|
|
86
|
+
// When we trigger a failure for `preProcessingForCoreRecordsWrite`, we expect the `processMessageWithDataStream` method to not be called
|
|
87
|
+
const authorizationSpy = sinon.spy(RecordsWriteHandler, 'authorizeRecordsWrite');
|
|
88
|
+
const processDataStreamSpy = sinon.spy(RecordsWriteHandler.prototype, 'processMessageWithDataStream');
|
|
89
|
+
const preProcessingForCoreRecordsWriteSpy = sinon.stub(RecordsWriteHandler.prototype, 'preProcessingForCoreRecordsWrite')
|
|
90
|
+
.throws(new DwnError(DwnErrorCode.PermissionsProtocolValidateScopeProtocolMismatch, 'Some Error'));
|
|
91
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
92
|
+
const { message, dataStream } = yield TestDataGenerator.generateRecordsWrite({ author: alice });
|
|
93
|
+
const reply = yield dwn.processMessage(alice.did, message, { dataStream });
|
|
94
|
+
expect(reply.status.code).to.equal(400);
|
|
95
|
+
// expect that authorization and preProcessingForCoreRecordsWrite are both called once
|
|
96
|
+
expect(authorizationSpy.calledOnce).to.be.true;
|
|
97
|
+
expect(preProcessingForCoreRecordsWriteSpy.calledOnce).to.be.true;
|
|
98
|
+
// expect that processMessageWithDataStream is NOT called since preProcessingForCoreRecordsWrite failed before reaching it
|
|
99
|
+
expect(processDataStreamSpy.called).to.be.false;
|
|
100
|
+
}));
|
|
101
|
+
it('should only be able to overwrite existing record if new record has a later `messageTimestamp` value', () => __awaiter(this, void 0, void 0, function* () {
|
|
102
|
+
var _a, _b, _c;
|
|
103
|
+
// write a message into DB
|
|
104
|
+
const author = yield TestDataGenerator.generateDidKeyPersona();
|
|
105
|
+
const data1 = new TextEncoder().encode('data1');
|
|
106
|
+
const recordsWriteMessageData = yield TestDataGenerator.generateRecordsWrite({ author, data: data1 });
|
|
107
|
+
const tenant = author.did;
|
|
108
|
+
const recordsWriteReply = yield dwn.processMessage(tenant, recordsWriteMessageData.message, { dataStream: recordsWriteMessageData.dataStream });
|
|
109
|
+
expect(recordsWriteReply.status.code).to.equal(202);
|
|
110
|
+
const recordId = recordsWriteMessageData.message.recordId;
|
|
111
|
+
const recordsQueryMessageData = yield TestDataGenerator.generateRecordsQuery({
|
|
112
|
+
author,
|
|
113
|
+
filter: { recordId }
|
|
114
|
+
});
|
|
115
|
+
// verify the message written can be queried
|
|
116
|
+
const recordsQueryReply = yield dwn.processMessage(tenant, recordsQueryMessageData.message);
|
|
117
|
+
expect(recordsQueryReply.status.code).to.equal(200);
|
|
118
|
+
expect((_a = recordsQueryReply.entries) === null || _a === void 0 ? void 0 : _a.length).to.equal(1);
|
|
119
|
+
expect(recordsQueryReply.entries[0].encodedData).to.equal(base64url.baseEncode(data1));
|
|
120
|
+
// generate and write a new RecordsWrite to overwrite the existing record
|
|
121
|
+
// a new RecordsWrite by default will have a later `messageTimestamp`
|
|
122
|
+
const newDataBytes = Encoder.stringToBytes('new data');
|
|
123
|
+
const newDataEncoded = Encoder.bytesToBase64Url(newDataBytes);
|
|
124
|
+
const newRecordsWrite = yield TestDataGenerator.generateFromRecordsWrite({
|
|
125
|
+
author,
|
|
126
|
+
existingWrite: recordsWriteMessageData.recordsWrite,
|
|
127
|
+
data: newDataBytes
|
|
128
|
+
});
|
|
129
|
+
// sanity check that old data and new data are different
|
|
130
|
+
expect(newDataEncoded).to.not.equal(Encoder.bytesToBase64Url(recordsWriteMessageData.dataBytes));
|
|
131
|
+
const newRecordsWriteReply = yield dwn.processMessage(tenant, newRecordsWrite.message, { dataStream: newRecordsWrite.dataStream });
|
|
132
|
+
expect(newRecordsWriteReply.status.code).to.equal(202);
|
|
133
|
+
// verify new record has overwritten the existing record
|
|
134
|
+
const newRecordsQueryReply = yield dwn.processMessage(tenant, recordsQueryMessageData.message);
|
|
135
|
+
expect(newRecordsQueryReply.status.code).to.equal(200);
|
|
136
|
+
expect((_b = newRecordsQueryReply.entries) === null || _b === void 0 ? void 0 : _b.length).to.equal(1);
|
|
137
|
+
expect(newRecordsQueryReply.entries[0].encodedData).to.equal(newDataEncoded);
|
|
138
|
+
// try to write the older message to store again and verify that it is not accepted
|
|
139
|
+
const thirdRecordsWriteReply = yield dwn.processMessage(tenant, recordsWriteMessageData.message, { dataStream: recordsWriteMessageData.dataStream });
|
|
140
|
+
expect(thirdRecordsWriteReply.status.code).to.equal(409); // expecting to fail
|
|
141
|
+
// expecting unchanged
|
|
142
|
+
const thirdRecordsQueryReply = yield dwn.processMessage(tenant, recordsQueryMessageData.message);
|
|
143
|
+
expect(thirdRecordsQueryReply.status.code).to.equal(200);
|
|
144
|
+
expect((_c = thirdRecordsQueryReply.entries) === null || _c === void 0 ? void 0 : _c.length).to.equal(1);
|
|
145
|
+
expect(thirdRecordsQueryReply.entries[0].encodedData).to.equal(newDataEncoded);
|
|
146
|
+
}));
|
|
147
|
+
it('should only be able to overwrite existing record if new message CID is larger when `messageTimestamp` value is the same', () => __awaiter(this, void 0, void 0, function* () {
|
|
148
|
+
var _a, _b, _c;
|
|
149
|
+
// start by writing an originating message
|
|
150
|
+
const author = yield TestDataGenerator.generatePersona();
|
|
151
|
+
const tenant = author.did;
|
|
152
|
+
const originatingMessageData = yield TestDataGenerator.generateRecordsWrite({
|
|
153
|
+
author,
|
|
154
|
+
data: Encoder.stringToBytes('unused')
|
|
155
|
+
});
|
|
156
|
+
// setting up a stub DID resolver
|
|
157
|
+
TestStubGenerator.stubDidResolver(didResolver, [author]);
|
|
158
|
+
const originatingMessageWriteReply = yield dwn.processMessage(tenant, originatingMessageData.message, { dataStream: originatingMessageData.dataStream });
|
|
159
|
+
expect(originatingMessageWriteReply.status.code).to.equal(202);
|
|
160
|
+
// generate two new RecordsWrite messages with the same `messageTimestamp` value
|
|
161
|
+
const dateModified = Time.getCurrentTimestamp();
|
|
162
|
+
const recordsWrite1 = yield TestDataGenerator.generateFromRecordsWrite({
|
|
163
|
+
author,
|
|
164
|
+
existingWrite: originatingMessageData.recordsWrite,
|
|
165
|
+
messageTimestamp: dateModified
|
|
166
|
+
});
|
|
167
|
+
const recordsWrite2 = yield TestDataGenerator.generateFromRecordsWrite({
|
|
168
|
+
author,
|
|
169
|
+
existingWrite: originatingMessageData.recordsWrite,
|
|
170
|
+
messageTimestamp: dateModified
|
|
171
|
+
});
|
|
172
|
+
// determine the lexicographical order of the two messages
|
|
173
|
+
const message1Cid = yield Message.getCid(recordsWrite1.message);
|
|
174
|
+
const message2Cid = yield Message.getCid(recordsWrite2.message);
|
|
175
|
+
let newerWrite;
|
|
176
|
+
let olderWrite;
|
|
177
|
+
if (message1Cid > message2Cid) {
|
|
178
|
+
newerWrite = recordsWrite1;
|
|
179
|
+
olderWrite = recordsWrite2;
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
newerWrite = recordsWrite2;
|
|
183
|
+
olderWrite = recordsWrite1;
|
|
184
|
+
}
|
|
185
|
+
// write the message with the smaller lexicographical message CID first
|
|
186
|
+
const recordsWriteReply = yield dwn.processMessage(tenant, olderWrite.message, { dataStream: olderWrite.dataStream });
|
|
187
|
+
expect(recordsWriteReply.status.code).to.equal(202);
|
|
188
|
+
// query to fetch the record
|
|
189
|
+
const recordsQueryMessageData = yield TestDataGenerator.generateRecordsQuery({
|
|
190
|
+
author,
|
|
191
|
+
filter: { recordId: originatingMessageData.message.recordId }
|
|
192
|
+
});
|
|
193
|
+
// verify the data is written
|
|
194
|
+
const recordsQueryReply = yield dwn.processMessage(tenant, recordsQueryMessageData.message);
|
|
195
|
+
expect(recordsQueryReply.status.code).to.equal(200);
|
|
196
|
+
expect((_a = recordsQueryReply.entries) === null || _a === void 0 ? void 0 : _a.length).to.equal(1);
|
|
197
|
+
expect(recordsQueryReply.entries[0].descriptor.dataCid)
|
|
198
|
+
.to.equal(olderWrite.message.descriptor.dataCid);
|
|
199
|
+
// attempt to write the message with larger lexicographical message CID
|
|
200
|
+
const newRecordsWriteReply = yield dwn.processMessage(tenant, newerWrite.message, { dataStream: newerWrite.dataStream });
|
|
201
|
+
expect(newRecordsWriteReply.status.code).to.equal(202);
|
|
202
|
+
// verify new record has overwritten the existing record
|
|
203
|
+
const newRecordsQueryReply = yield dwn.processMessage(tenant, recordsQueryMessageData.message);
|
|
204
|
+
expect(newRecordsQueryReply.status.code).to.equal(200);
|
|
205
|
+
expect((_b = newRecordsQueryReply.entries) === null || _b === void 0 ? void 0 : _b.length).to.equal(1);
|
|
206
|
+
expect(newRecordsQueryReply.entries[0].descriptor.dataCid)
|
|
207
|
+
.to.equal(newerWrite.message.descriptor.dataCid);
|
|
208
|
+
// try to write the message with smaller lexicographical message CID again
|
|
209
|
+
const thirdRecordsWriteReply = yield dwn.processMessage(tenant, olderWrite.message, { dataStream: DataStream.fromBytes(olderWrite.dataBytes) } // need to create data stream again since it's already used above
|
|
210
|
+
);
|
|
211
|
+
expect(thirdRecordsWriteReply.status.code).to.equal(409); // expecting to fail
|
|
212
|
+
// verify the message in store is still the one with larger lexicographical message CID
|
|
213
|
+
const thirdRecordsQueryReply = yield dwn.processMessage(tenant, recordsQueryMessageData.message);
|
|
214
|
+
expect(thirdRecordsQueryReply.status.code).to.equal(200);
|
|
215
|
+
expect((_c = thirdRecordsQueryReply.entries) === null || _c === void 0 ? void 0 : _c.length).to.equal(1);
|
|
216
|
+
expect(thirdRecordsQueryReply.entries[0].descriptor.dataCid)
|
|
217
|
+
.to.equal(newerWrite.message.descriptor.dataCid); // expecting unchanged
|
|
218
|
+
}));
|
|
219
|
+
it('#690 - should allow data format of a flat-space record to be updated to any value', () => __awaiter(this, void 0, void 0, function* () {
|
|
220
|
+
var _a;
|
|
221
|
+
const initialWriteData = yield TestDataGenerator.generateRecordsWrite();
|
|
222
|
+
const tenant = initialWriteData.author.did;
|
|
223
|
+
TestStubGenerator.stubDidResolver(didResolver, [initialWriteData.author]);
|
|
224
|
+
const initialWriteReply = yield dwn.processMessage(tenant, initialWriteData.message, { dataStream: initialWriteData.dataStream });
|
|
225
|
+
expect(initialWriteReply.status.code).to.equal(202);
|
|
226
|
+
const newDataFormat = 'any-new-data-format';
|
|
227
|
+
const newDataBytes = TestDataGenerator.randomBytes(100);
|
|
228
|
+
const updateWrite = yield RecordsWrite.createFrom({
|
|
229
|
+
recordsWriteMessage: initialWriteData.message,
|
|
230
|
+
dataFormat: newDataFormat,
|
|
231
|
+
signer: Jws.createSigner(initialWriteData.author),
|
|
232
|
+
data: newDataBytes
|
|
233
|
+
});
|
|
234
|
+
const newDataStream = DataStream.fromBytes(newDataBytes);
|
|
235
|
+
const updateReply = yield dwn.processMessage(tenant, updateWrite.message, { dataStream: newDataStream });
|
|
236
|
+
expect(updateReply.status.code).to.equal(202);
|
|
237
|
+
// verify the data format of the record is updated
|
|
238
|
+
const recordsRead = yield RecordsRead.create({
|
|
239
|
+
filter: { recordId: initialWriteData.message.recordId },
|
|
240
|
+
signer: Jws.createSigner(initialWriteData.author),
|
|
241
|
+
});
|
|
242
|
+
const recordsReadReply = yield dwn.processMessage(tenant, recordsRead.message);
|
|
243
|
+
expect(recordsReadReply.status.code).to.equal(200);
|
|
244
|
+
expect((_a = recordsReadReply.entry.recordsWrite) === null || _a === void 0 ? void 0 : _a.descriptor.dataFormat).to.equal(newDataFormat);
|
|
245
|
+
}));
|
|
246
|
+
it('should not allow changes to immutable properties', () => __awaiter(this, void 0, void 0, function* () {
|
|
247
|
+
const initialWriteData = yield TestDataGenerator.generateRecordsWrite();
|
|
248
|
+
const tenant = initialWriteData.author.did;
|
|
249
|
+
TestStubGenerator.stubDidResolver(didResolver, [initialWriteData.author]);
|
|
250
|
+
const initialWriteReply = yield dwn.processMessage(tenant, initialWriteData.message, { dataStream: initialWriteData.dataStream });
|
|
251
|
+
expect(initialWriteReply.status.code).to.equal(202);
|
|
252
|
+
const recordId = initialWriteData.message.recordId;
|
|
253
|
+
const dateCreated = initialWriteData.message.descriptor.dateCreated;
|
|
254
|
+
const schema = initialWriteData.message.descriptor.schema;
|
|
255
|
+
// dateCreated test
|
|
256
|
+
let childMessageData = yield TestDataGenerator.generateRecordsWrite({
|
|
257
|
+
author: initialWriteData.author,
|
|
258
|
+
recordId,
|
|
259
|
+
schema,
|
|
260
|
+
dateCreated: Time.getCurrentTimestamp(), // should not be allowed to be modified
|
|
261
|
+
dataFormat: initialWriteData.message.descriptor.dataFormat
|
|
262
|
+
});
|
|
263
|
+
let reply = yield dwn.processMessage(tenant, childMessageData.message, { dataStream: childMessageData.dataStream });
|
|
264
|
+
expect(reply.status.code).to.equal(400);
|
|
265
|
+
expect(reply.status.detail).to.contain('dateCreated is an immutable property');
|
|
266
|
+
// schema test
|
|
267
|
+
childMessageData = yield TestDataGenerator.generateRecordsWrite({
|
|
268
|
+
author: initialWriteData.author,
|
|
269
|
+
recordId,
|
|
270
|
+
schema: 'should-not-allowed-to-be-modified',
|
|
271
|
+
dateCreated,
|
|
272
|
+
dataFormat: initialWriteData.message.descriptor.dataFormat
|
|
273
|
+
});
|
|
274
|
+
reply = yield dwn.processMessage(tenant, childMessageData.message, { dataStream: childMessageData.dataStream });
|
|
275
|
+
expect(reply.status.code).to.equal(400);
|
|
276
|
+
expect(reply.status.detail).to.contain('schema is an immutable property');
|
|
277
|
+
}));
|
|
278
|
+
it('should inherit data from previous RecordsWrite given a matching dataCid and dataSize and no dataStream', () => __awaiter(this, void 0, void 0, function* () {
|
|
279
|
+
const { message, author, dataStream, dataBytes } = yield TestDataGenerator.generateRecordsWrite({
|
|
280
|
+
published: false
|
|
281
|
+
});
|
|
282
|
+
const tenant = author.did;
|
|
283
|
+
TestStubGenerator.stubDidResolver(didResolver, [author]);
|
|
284
|
+
const initialWriteReply = yield dwn.processMessage(tenant, message, { dataStream });
|
|
285
|
+
expect(initialWriteReply.status.code).to.equal(202);
|
|
286
|
+
const write2 = yield RecordsWrite.createFrom({
|
|
287
|
+
recordsWriteMessage: message,
|
|
288
|
+
published: true,
|
|
289
|
+
signer: Jws.createSigner(author),
|
|
290
|
+
});
|
|
291
|
+
const writeUpdateReply = yield dwn.processMessage(tenant, write2.message);
|
|
292
|
+
expect(writeUpdateReply.status.code).to.equal(202);
|
|
293
|
+
const readMessage = yield RecordsRead.create({
|
|
294
|
+
filter: {
|
|
295
|
+
recordId: message.recordId,
|
|
296
|
+
}
|
|
297
|
+
});
|
|
298
|
+
const readMessageReply = yield dwn.processMessage(tenant, readMessage.message);
|
|
299
|
+
expect(readMessageReply.status.code).to.equal(200);
|
|
300
|
+
expect(readMessageReply.entry.recordsWrite).to.exist;
|
|
301
|
+
const data = yield DataStream.toBytes(readMessageReply.entry.data);
|
|
302
|
+
expect(data).to.eql(dataBytes);
|
|
303
|
+
}));
|
|
304
|
+
it('should allow an initial `RecordsWrite` to be written without supplying data', () => __awaiter(this, void 0, void 0, function* () {
|
|
305
|
+
//scenario: you have an initial write without the data and a subsequent write with data to be able to write.
|
|
306
|
+
// the DWN should accept an initial write without data, however prevent the user from querying for it until it's updated.
|
|
307
|
+
var _a, _b;
|
|
308
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
309
|
+
const { recordsWrite } = yield TestDataGenerator.generateRecordsWrite({ author: alice });
|
|
310
|
+
// simulate synchronize of pruned initial `RecordsWrite`
|
|
311
|
+
const reply = yield dwn.processMessage(alice.did, recordsWrite.message);
|
|
312
|
+
expect(reply.status.code).to.equal(204);
|
|
313
|
+
// verify `RecordsWrite` inserted is not returned with a query
|
|
314
|
+
const recordsQueryMessageData = yield TestDataGenerator.generateRecordsQuery({
|
|
315
|
+
author: alice,
|
|
316
|
+
filter: { recordId: recordsWrite.message.recordId }
|
|
317
|
+
});
|
|
318
|
+
const recordsQueryReply = yield dwn.processMessage(alice.did, recordsQueryMessageData.message);
|
|
319
|
+
expect(recordsQueryReply.status.code).to.equal(200);
|
|
320
|
+
expect((_a = recordsQueryReply.entries) === null || _a === void 0 ? void 0 : _a.length).to.equal(0);
|
|
321
|
+
// generate and write a new `RecordsWrite` to overwrite the existing record
|
|
322
|
+
const newDataBytes = Encoder.stringToBytes('new data');
|
|
323
|
+
const newDataEncoded = Encoder.bytesToBase64Url(newDataBytes);
|
|
324
|
+
const newRecordsWrite = yield TestDataGenerator.generateFromRecordsWrite({
|
|
325
|
+
author: alice,
|
|
326
|
+
existingWrite: recordsWrite,
|
|
327
|
+
data: newDataBytes
|
|
328
|
+
});
|
|
329
|
+
const newRecordsWriteReply = yield dwn.processMessage(alice.did, newRecordsWrite.message, { dataStream: newRecordsWrite.dataStream });
|
|
330
|
+
expect(newRecordsWriteReply.status.code).to.equal(202);
|
|
331
|
+
// verify new `RecordsWrite` has overwritten the existing record with new data
|
|
332
|
+
const newRecordsQueryReply = yield dwn.processMessage(alice.did, recordsQueryMessageData.message);
|
|
333
|
+
expect(newRecordsQueryReply.status.code).to.equal(200);
|
|
334
|
+
expect((_b = newRecordsQueryReply.entries) === null || _b === void 0 ? void 0 : _b.length).to.equal(1);
|
|
335
|
+
expect(newRecordsQueryReply.entries[0].encodedData).to.equal(newDataEncoded);
|
|
336
|
+
}));
|
|
337
|
+
it('should not allow non-initial writes to be written without supplying data', () => __awaiter(this, void 0, void 0, function* () {
|
|
338
|
+
//scenario: you have an initial write without the data and a subsequent write with data to be able to write.
|
|
339
|
+
// the DWN should accept an initial write without data, however prevent the user from querying for it until it's updated.
|
|
340
|
+
var _a, _b;
|
|
341
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
342
|
+
// write a record into the dwn
|
|
343
|
+
const { recordsWrite, dataStream, dataBytes } = yield TestDataGenerator.generateRecordsWrite({ author: alice });
|
|
344
|
+
const reply = yield dwn.processMessage(alice.did, recordsWrite.message, { dataStream });
|
|
345
|
+
expect(reply.status.code).to.equal(202);
|
|
346
|
+
// verify `RecordsWrite` inserted can be queried
|
|
347
|
+
const recordsQueryMessageData = yield TestDataGenerator.generateRecordsQuery({
|
|
348
|
+
author: alice,
|
|
349
|
+
filter: { recordId: recordsWrite.message.recordId }
|
|
350
|
+
});
|
|
351
|
+
const recordsQueryReply = yield dwn.processMessage(alice.did, recordsQueryMessageData.message);
|
|
352
|
+
expect(recordsQueryReply.status.code).to.equal(200);
|
|
353
|
+
expect((_a = recordsQueryReply.entries) === null || _a === void 0 ? void 0 : _a.length).to.equal(1);
|
|
354
|
+
// generate and write a new `RecordsWrite` to overwrite the existing record
|
|
355
|
+
const newDataBytes = Encoder.stringToBytes('new data');
|
|
356
|
+
const newRecordsWrite = yield TestDataGenerator.generateFromRecordsWrite({
|
|
357
|
+
author: alice,
|
|
358
|
+
existingWrite: recordsWrite,
|
|
359
|
+
data: newDataBytes
|
|
360
|
+
});
|
|
361
|
+
// records write should be rejected.
|
|
362
|
+
const newRecordsWriteReply = yield dwn.processMessage(alice.did, newRecordsWrite.message);
|
|
363
|
+
expect(newRecordsWriteReply.status.code).to.equal(400);
|
|
364
|
+
expect(newRecordsWriteReply.status.detail).to.contain(DwnErrorCode.RecordsWriteDataCidMismatch);
|
|
365
|
+
// verify the original `RecordsWrite` and data are still available
|
|
366
|
+
const newRecordsQueryReply = yield dwn.processMessage(alice.did, recordsQueryMessageData.message);
|
|
367
|
+
expect(newRecordsQueryReply.status.code).to.equal(200);
|
|
368
|
+
expect((_b = newRecordsQueryReply.entries) === null || _b === void 0 ? void 0 : _b.length).to.equal(1);
|
|
369
|
+
const originalEncodedData = Encoder.bytesToBase64Url(dataBytes);
|
|
370
|
+
expect(newRecordsQueryReply.entries[0].encodedData).to.equal(originalEncodedData);
|
|
371
|
+
}));
|
|
372
|
+
describe('should inherit data from previous RecordsWrite given a matching dataCid and dataSize and no dataStream', () => {
|
|
373
|
+
it('with data above the threshold for encodedData', () => __awaiter(this, void 0, void 0, function* () {
|
|
374
|
+
const { message, author, dataStream, dataBytes } = yield TestDataGenerator.generateRecordsWrite({
|
|
375
|
+
data: TestDataGenerator.randomBytes(DwnConstant.maxDataSizeAllowedToBeEncoded + 1),
|
|
376
|
+
published: false
|
|
377
|
+
});
|
|
378
|
+
const tenant = author.did;
|
|
379
|
+
TestStubGenerator.stubDidResolver(didResolver, [author]);
|
|
380
|
+
const initialWriteReply = yield dwn.processMessage(tenant, message, { dataStream });
|
|
381
|
+
expect(initialWriteReply.status.code).to.equal(202);
|
|
382
|
+
const write2 = yield RecordsWrite.createFrom({
|
|
383
|
+
recordsWriteMessage: message,
|
|
384
|
+
published: true,
|
|
385
|
+
signer: Jws.createSigner(author),
|
|
386
|
+
});
|
|
387
|
+
const writeUpdateReply = yield dwn.processMessage(tenant, write2.message);
|
|
388
|
+
expect(writeUpdateReply.status.code).to.equal(202);
|
|
389
|
+
const readMessage = yield RecordsRead.create({
|
|
390
|
+
filter: {
|
|
391
|
+
recordId: message.recordId,
|
|
392
|
+
}
|
|
393
|
+
});
|
|
394
|
+
const readMessageReply = yield dwn.processMessage(tenant, readMessage.message);
|
|
395
|
+
expect(readMessageReply.status.code).to.equal(200);
|
|
396
|
+
expect(readMessageReply.entry.recordsWrite).to.exist;
|
|
397
|
+
const data = yield DataStream.toBytes(readMessageReply.entry.data);
|
|
398
|
+
expect(data).to.eql(dataBytes);
|
|
399
|
+
}));
|
|
400
|
+
it('with data equal to or below the threshold for encodedData', () => __awaiter(this, void 0, void 0, function* () {
|
|
401
|
+
const { message, author, dataStream, dataBytes } = yield TestDataGenerator.generateRecordsWrite({
|
|
402
|
+
data: TestDataGenerator.randomBytes(DwnConstant.maxDataSizeAllowedToBeEncoded),
|
|
403
|
+
published: false
|
|
404
|
+
});
|
|
405
|
+
const tenant = author.did;
|
|
406
|
+
TestStubGenerator.stubDidResolver(didResolver, [author]);
|
|
407
|
+
const initialWriteReply = yield dwn.processMessage(tenant, message, { dataStream });
|
|
408
|
+
expect(initialWriteReply.status.code).to.equal(202);
|
|
409
|
+
const write2 = yield RecordsWrite.createFrom({
|
|
410
|
+
recordsWriteMessage: message,
|
|
411
|
+
published: true,
|
|
412
|
+
signer: Jws.createSigner(author),
|
|
413
|
+
});
|
|
414
|
+
const writeUpdateReply = yield dwn.processMessage(tenant, write2.message);
|
|
415
|
+
expect(writeUpdateReply.status.code).to.equal(202);
|
|
416
|
+
const readMessage = yield RecordsRead.create({
|
|
417
|
+
filter: {
|
|
418
|
+
recordId: message.recordId,
|
|
419
|
+
}
|
|
420
|
+
});
|
|
421
|
+
const readMessageReply = yield dwn.processMessage(tenant, readMessage.message);
|
|
422
|
+
expect(readMessageReply.status.code).to.equal(200);
|
|
423
|
+
expect(readMessageReply.entry.recordsWrite).to.exist;
|
|
424
|
+
const data = yield DataStream.toBytes(readMessageReply.entry.data);
|
|
425
|
+
expect(data).to.eql(dataBytes);
|
|
426
|
+
}));
|
|
427
|
+
});
|
|
428
|
+
describe('should return 400 if actual data size mismatches with `dataSize` in descriptor', () => {
|
|
429
|
+
it('with dataStream and `dataSize` larger than encodedData threshold', () => __awaiter(this, void 0, void 0, function* () {
|
|
430
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
431
|
+
const { message, dataStream } = yield TestDataGenerator.generateRecordsWrite({
|
|
432
|
+
author: alice,
|
|
433
|
+
data: TestDataGenerator.randomBytes(DwnConstant.maxDataSizeAllowedToBeEncoded + 1)
|
|
434
|
+
});
|
|
435
|
+
// replace the dataSize to simulate mismatch, will need to generate `recordId` and `authorization` property again
|
|
436
|
+
message.descriptor.dataSize = DwnConstant.maxDataSizeAllowedToBeEncoded + 100;
|
|
437
|
+
const descriptorCid = yield Cid.computeCid(message.descriptor);
|
|
438
|
+
const recordId = yield RecordsWrite.getEntryId(alice.did, message.descriptor);
|
|
439
|
+
const signer = Jws.createSigner(alice);
|
|
440
|
+
const signature = yield RecordsWrite.createSignerSignature({
|
|
441
|
+
recordId,
|
|
442
|
+
contextId: message.contextId,
|
|
443
|
+
descriptorCid,
|
|
444
|
+
attestation: message.attestation,
|
|
445
|
+
encryption: message.encryption,
|
|
446
|
+
signer
|
|
447
|
+
});
|
|
448
|
+
message.recordId = recordId;
|
|
449
|
+
message.authorization = { signature };
|
|
450
|
+
const reply = yield dwn.processMessage(alice.did, message, { dataStream });
|
|
451
|
+
expect(reply.status.code).to.equal(400);
|
|
452
|
+
expect(reply.status.detail).to.contain(DwnErrorCode.RecordsWriteDataSizeMismatch);
|
|
453
|
+
}));
|
|
454
|
+
it('with only `dataSize` larger than encodedData threshold', () => __awaiter(this, void 0, void 0, function* () {
|
|
455
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
456
|
+
const { message, dataStream } = yield TestDataGenerator.generateRecordsWrite({
|
|
457
|
+
author: alice,
|
|
458
|
+
data: TestDataGenerator.randomBytes(DwnConstant.maxDataSizeAllowedToBeEncoded)
|
|
459
|
+
});
|
|
460
|
+
// replace the dataSize to simulate mismatch, will need to generate `recordId` and `authorization` property again
|
|
461
|
+
message.descriptor.dataSize = DwnConstant.maxDataSizeAllowedToBeEncoded + 100;
|
|
462
|
+
const descriptorCid = yield Cid.computeCid(message.descriptor);
|
|
463
|
+
const recordId = yield RecordsWrite.getEntryId(alice.did, message.descriptor);
|
|
464
|
+
const signer = Jws.createSigner(alice);
|
|
465
|
+
const signature = yield RecordsWrite.createSignerSignature({
|
|
466
|
+
recordId,
|
|
467
|
+
contextId: message.contextId,
|
|
468
|
+
descriptorCid,
|
|
469
|
+
attestation: message.attestation,
|
|
470
|
+
encryption: message.encryption,
|
|
471
|
+
signer
|
|
472
|
+
});
|
|
473
|
+
message.recordId = recordId;
|
|
474
|
+
message.authorization = { signature };
|
|
475
|
+
const reply = yield dwn.processMessage(alice.did, message, { dataStream });
|
|
476
|
+
expect(reply.status.code).to.equal(400);
|
|
477
|
+
expect(reply.status.detail).to.contain(DwnErrorCode.RecordsWriteDataSizeMismatch);
|
|
478
|
+
}));
|
|
479
|
+
it('with only dataStream larger than encodedData threshold', () => __awaiter(this, void 0, void 0, function* () {
|
|
480
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
481
|
+
const { message, dataStream } = yield TestDataGenerator.generateRecordsWrite({
|
|
482
|
+
author: alice,
|
|
483
|
+
data: TestDataGenerator.randomBytes(DwnConstant.maxDataSizeAllowedToBeEncoded + 1)
|
|
484
|
+
});
|
|
485
|
+
// replace the dataSize to simulate mismatch, will need to generate `recordId` and `authorization` property again
|
|
486
|
+
message.descriptor.dataSize = 1;
|
|
487
|
+
const descriptorCid = yield Cid.computeCid(message.descriptor);
|
|
488
|
+
const recordId = yield RecordsWrite.getEntryId(alice.did, message.descriptor);
|
|
489
|
+
const signer = Jws.createSigner(alice);
|
|
490
|
+
const signature = yield RecordsWrite.createSignerSignature({
|
|
491
|
+
recordId,
|
|
492
|
+
contextId: message.contextId,
|
|
493
|
+
descriptorCid,
|
|
494
|
+
attestation: message.attestation,
|
|
495
|
+
encryption: message.encryption,
|
|
496
|
+
signer
|
|
497
|
+
});
|
|
498
|
+
message.recordId = recordId;
|
|
499
|
+
message.authorization = { signature };
|
|
500
|
+
const reply = yield dwn.processMessage(alice.did, message, { dataStream });
|
|
501
|
+
expect(reply.status.code).to.equal(400);
|
|
502
|
+
expect(reply.status.detail).to.contain(DwnErrorCode.RecordsWriteDataSizeMismatch);
|
|
503
|
+
}));
|
|
504
|
+
it('with both `dataSize` and dataStream below than encodedData threshold', () => __awaiter(this, void 0, void 0, function* () {
|
|
505
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
506
|
+
const { message, dataStream } = yield TestDataGenerator.generateRecordsWrite({
|
|
507
|
+
author: alice
|
|
508
|
+
});
|
|
509
|
+
// replace the dataSize to simulate mismatch, will need to generate `recordId` and `authorization` property again
|
|
510
|
+
message.descriptor.dataSize = 1;
|
|
511
|
+
const descriptorCid = yield Cid.computeCid(message.descriptor);
|
|
512
|
+
const recordId = yield RecordsWrite.getEntryId(alice.did, message.descriptor);
|
|
513
|
+
const signer = Jws.createSigner(alice);
|
|
514
|
+
const signature = yield RecordsWrite.createSignerSignature({
|
|
515
|
+
recordId,
|
|
516
|
+
contextId: message.contextId,
|
|
517
|
+
descriptorCid,
|
|
518
|
+
attestation: message.attestation,
|
|
519
|
+
encryption: message.encryption,
|
|
520
|
+
signer
|
|
521
|
+
});
|
|
522
|
+
message.recordId = recordId;
|
|
523
|
+
message.authorization = { signature };
|
|
524
|
+
const reply = yield dwn.processMessage(alice.did, message, { dataStream });
|
|
525
|
+
expect(reply.status.code).to.equal(400);
|
|
526
|
+
expect(reply.status.detail).to.contain(DwnErrorCode.RecordsWriteDataSizeMismatch);
|
|
527
|
+
}));
|
|
528
|
+
});
|
|
529
|
+
it('should return 400 for data CID mismatch with both dataStream and `dataSize` larger than encodedData threshold', () => __awaiter(this, void 0, void 0, function* () {
|
|
530
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
531
|
+
const { message } = yield TestDataGenerator.generateRecordsWrite({
|
|
532
|
+
author: alice,
|
|
533
|
+
data: TestDataGenerator.randomBytes(DwnConstant.maxDataSizeAllowedToBeEncoded + 1)
|
|
534
|
+
});
|
|
535
|
+
const dataStream = DataStream.fromBytes(TestDataGenerator.randomBytes(DwnConstant.maxDataSizeAllowedToBeEncoded + 1)); // mismatch data stream
|
|
536
|
+
const reply = yield dwn.processMessage(alice.did, message, { dataStream });
|
|
537
|
+
expect(reply.status.code).to.equal(400);
|
|
538
|
+
expect(reply.status.detail).to.contain(DwnErrorCode.RecordsWriteDataCidMismatch);
|
|
539
|
+
}));
|
|
540
|
+
it('should return 400 for data CID mismatch with `dataSize` larger than encodedData threshold', () => __awaiter(this, void 0, void 0, function* () {
|
|
541
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
542
|
+
const { message } = yield TestDataGenerator.generateRecordsWrite({
|
|
543
|
+
author: alice,
|
|
544
|
+
data: TestDataGenerator.randomBytes(DwnConstant.maxDataSizeAllowedToBeEncoded + 1)
|
|
545
|
+
});
|
|
546
|
+
const dataStream = DataStream.fromBytes(TestDataGenerator.randomBytes(DwnConstant.maxDataSizeAllowedToBeEncoded)); // mismatch data stream
|
|
547
|
+
const reply = yield dwn.processMessage(alice.did, message, { dataStream });
|
|
548
|
+
expect(reply.status.code).to.equal(400);
|
|
549
|
+
expect(reply.status.detail).to.contain(DwnErrorCode.RecordsWriteDataCidMismatch);
|
|
550
|
+
}));
|
|
551
|
+
it('should return 400 for data CID mismatch with dataStream larger than encodedData threshold', () => __awaiter(this, void 0, void 0, function* () {
|
|
552
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
553
|
+
const { message } = yield TestDataGenerator.generateRecordsWrite({
|
|
554
|
+
author: alice,
|
|
555
|
+
data: TestDataGenerator.randomBytes(DwnConstant.maxDataSizeAllowedToBeEncoded)
|
|
556
|
+
});
|
|
557
|
+
const dataStream = DataStream.fromBytes(TestDataGenerator.randomBytes(DwnConstant.maxDataSizeAllowedToBeEncoded + 1)); // mismatch data stream
|
|
558
|
+
const reply = yield dwn.processMessage(alice.did, message, { dataStream });
|
|
559
|
+
expect(reply.status.code).to.equal(400);
|
|
560
|
+
expect(reply.status.detail).to.contain(DwnErrorCode.RecordsWriteDataCidMismatch);
|
|
561
|
+
}));
|
|
562
|
+
it('should return 400 for data CID mismatch with both dataStream and `dataSize` below than encodedData threshold', () => __awaiter(this, void 0, void 0, function* () {
|
|
563
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
564
|
+
const { message } = yield TestDataGenerator.generateRecordsWrite({
|
|
565
|
+
author: alice,
|
|
566
|
+
data: TestDataGenerator.randomBytes(DwnConstant.maxDataSizeAllowedToBeEncoded)
|
|
567
|
+
});
|
|
568
|
+
const dataStream = DataStream.fromBytes(TestDataGenerator.randomBytes(DwnConstant.maxDataSizeAllowedToBeEncoded)); // mismatch data stream
|
|
569
|
+
const reply = yield dwn.processMessage(alice.did, message, { dataStream });
|
|
570
|
+
expect(reply.status.code).to.equal(400);
|
|
571
|
+
expect(reply.status.detail).to.contain(DwnErrorCode.RecordsWriteDataCidMismatch);
|
|
572
|
+
}));
|
|
573
|
+
it('#359 - should not allow access of data by referencing a different`dataCid` in "modify" `RecordsWrite` with large data', () => __awaiter(this, void 0, void 0, function* () {
|
|
574
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
575
|
+
// alice writes a record
|
|
576
|
+
const dataString = TestDataGenerator.randomString(DwnConstant.maxDataSizeAllowedToBeEncoded + 1);
|
|
577
|
+
const dataSize = dataString.length;
|
|
578
|
+
const data = Encoder.stringToBytes(dataString);
|
|
579
|
+
const dataCid = yield Cid.computeDagPbCidFromBytes(data);
|
|
580
|
+
const write1 = yield TestDataGenerator.generateRecordsWrite({
|
|
581
|
+
author: alice,
|
|
582
|
+
data,
|
|
583
|
+
});
|
|
584
|
+
const write1Reply = yield dwn.processMessage(alice.did, write1.message, { dataStream: write1.dataStream });
|
|
585
|
+
expect(write1Reply.status.code).to.equal(202);
|
|
586
|
+
// alice writes another record (which will be modified later)
|
|
587
|
+
const write2 = yield TestDataGenerator.generateRecordsWrite({ author: alice });
|
|
588
|
+
const write2Reply = yield dwn.processMessage(alice.did, write2.message, { dataStream: write2.dataStream });
|
|
589
|
+
expect(write2Reply.status.code).to.equal(202);
|
|
590
|
+
// modify write2 by referencing the `dataCid` in write1 (which should not be allowed)
|
|
591
|
+
const write2Change = yield TestDataGenerator.generateRecordsWrite({
|
|
592
|
+
author: alice,
|
|
593
|
+
recipient: write2.message.descriptor.recipient,
|
|
594
|
+
recordId: write2.message.recordId,
|
|
595
|
+
dateCreated: write2.message.descriptor.dateCreated,
|
|
596
|
+
protocolPath: write2.message.descriptor.protocolPath,
|
|
597
|
+
schema: write2.message.descriptor.schema,
|
|
598
|
+
dataFormat: write2.message.descriptor.dataFormat,
|
|
599
|
+
// unauthorized reference to data in write1
|
|
600
|
+
dataCid,
|
|
601
|
+
dataSize
|
|
602
|
+
});
|
|
603
|
+
const write2ChangeReply = yield dwn.processMessage(alice.did, write2Change.message);
|
|
604
|
+
expect(write2ChangeReply.status.code).to.equal(400); // should be disallowed
|
|
605
|
+
expect(write2ChangeReply.status.detail).to.contain(DwnErrorCode.RecordsWriteDataCidMismatch);
|
|
606
|
+
// further sanity test to make sure the change is not written, ie. write2 still has the original data
|
|
607
|
+
const read = yield RecordsRead.create({
|
|
608
|
+
filter: {
|
|
609
|
+
recordId: write2.message.recordId,
|
|
610
|
+
},
|
|
611
|
+
signer: Jws.createSigner(alice)
|
|
612
|
+
});
|
|
613
|
+
const readReply = yield dwn.processMessage(alice.did, read.message);
|
|
614
|
+
expect(readReply.status.code).to.equal(200);
|
|
615
|
+
const readDataBytes = yield DataStream.toBytes(readReply.entry.data);
|
|
616
|
+
expect(ArrayUtility.byteArraysEqual(readDataBytes, write2.dataBytes)).to.be.true;
|
|
617
|
+
}));
|
|
618
|
+
it('#359 - should not allow access of data by referencing a different`dataCid` in "modify" `RecordsWrite`', () => __awaiter(this, void 0, void 0, function* () {
|
|
619
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
620
|
+
// alice writes a record
|
|
621
|
+
const dataString = TestDataGenerator.randomString(DwnConstant.maxDataSizeAllowedToBeEncoded);
|
|
622
|
+
const dataSize = dataString.length;
|
|
623
|
+
const data = Encoder.stringToBytes(dataString);
|
|
624
|
+
const dataCid = yield Cid.computeDagPbCidFromBytes(data);
|
|
625
|
+
const write1 = yield TestDataGenerator.generateRecordsWrite({
|
|
626
|
+
author: alice,
|
|
627
|
+
data,
|
|
628
|
+
});
|
|
629
|
+
const write1Reply = yield dwn.processMessage(alice.did, write1.message, { dataStream: write1.dataStream });
|
|
630
|
+
expect(write1Reply.status.code).to.equal(202);
|
|
631
|
+
// alice writes another record (which will be modified later)
|
|
632
|
+
const write2 = yield TestDataGenerator.generateRecordsWrite({ author: alice });
|
|
633
|
+
const write2Reply = yield dwn.processMessage(alice.did, write2.message, { dataStream: write2.dataStream });
|
|
634
|
+
expect(write2Reply.status.code).to.equal(202);
|
|
635
|
+
// modify write2 by referencing the `dataCid` in write1 (which should not be allowed)
|
|
636
|
+
const write2Change = yield TestDataGenerator.generateRecordsWrite({
|
|
637
|
+
author: alice,
|
|
638
|
+
recipient: write2.message.descriptor.recipient,
|
|
639
|
+
recordId: write2.message.recordId,
|
|
640
|
+
dateCreated: write2.message.descriptor.dateCreated,
|
|
641
|
+
protocolPath: write2.message.descriptor.protocolPath,
|
|
642
|
+
schema: write2.message.descriptor.schema,
|
|
643
|
+
dataFormat: write2.message.descriptor.dataFormat,
|
|
644
|
+
// unauthorized reference to data in write1
|
|
645
|
+
dataCid,
|
|
646
|
+
dataSize
|
|
647
|
+
});
|
|
648
|
+
const write2ChangeReply = yield dwn.processMessage(alice.did, write2Change.message);
|
|
649
|
+
expect(write2ChangeReply.status.code).to.equal(400); // should be disallowed
|
|
650
|
+
expect(write2ChangeReply.status.detail).to.contain(DwnErrorCode.RecordsWriteDataCidMismatch);
|
|
651
|
+
// further sanity test to make sure the change is not written, ie. write2 still has the original data
|
|
652
|
+
const read = yield RecordsRead.create({
|
|
653
|
+
filter: {
|
|
654
|
+
recordId: write2.message.recordId,
|
|
655
|
+
},
|
|
656
|
+
signer: Jws.createSigner(alice)
|
|
657
|
+
});
|
|
658
|
+
const readReply = yield dwn.processMessage(alice.did, read.message);
|
|
659
|
+
expect(readReply.status.code).to.equal(200);
|
|
660
|
+
const readDataBytes = yield DataStream.toBytes(readReply.entry.data);
|
|
661
|
+
expect(ArrayUtility.byteArraysEqual(readDataBytes, write2.dataBytes)).to.be.true;
|
|
662
|
+
}));
|
|
663
|
+
describe('initial write & subsequent write tests', () => {
|
|
664
|
+
describe('createFrom()', () => {
|
|
665
|
+
it('should accept a published RecordsWrite using createFrom() without specifying `data` or `datePublished`', () => __awaiter(this, void 0, void 0, function* () {
|
|
666
|
+
var _a;
|
|
667
|
+
const data = Encoder.stringToBytes('test');
|
|
668
|
+
const encodedData = Encoder.bytesToBase64Url(data);
|
|
669
|
+
// new record
|
|
670
|
+
const { message, author, recordsWrite, dataStream } = yield TestDataGenerator.generateRecordsWrite({
|
|
671
|
+
published: false,
|
|
672
|
+
data,
|
|
673
|
+
});
|
|
674
|
+
const tenant = author.did;
|
|
675
|
+
// setting up a stub DID resolver
|
|
676
|
+
TestStubGenerator.stubDidResolver(didResolver, [author]);
|
|
677
|
+
const reply = yield dwn.processMessage(tenant, message, { dataStream });
|
|
678
|
+
expect(reply.status.code).to.equal(202);
|
|
679
|
+
// changing the `published` property
|
|
680
|
+
const newWrite = yield RecordsWrite.createFrom({
|
|
681
|
+
recordsWriteMessage: recordsWrite.message,
|
|
682
|
+
published: true,
|
|
683
|
+
signer: Jws.createSigner(author)
|
|
684
|
+
});
|
|
685
|
+
const newWriteReply = yield dwn.processMessage(tenant, newWrite.message);
|
|
686
|
+
expect(newWriteReply.status.code).to.equal(202);
|
|
687
|
+
// verify the new record state can be queried
|
|
688
|
+
const recordsQueryMessageData = yield TestDataGenerator.generateRecordsQuery({
|
|
689
|
+
author,
|
|
690
|
+
filter: { recordId: message.recordId }
|
|
691
|
+
});
|
|
692
|
+
const recordsQueryReply = yield dwn.processMessage(tenant, recordsQueryMessageData.message);
|
|
693
|
+
expect(recordsQueryReply.status.code).to.equal(200);
|
|
694
|
+
expect((_a = recordsQueryReply.entries) === null || _a === void 0 ? void 0 : _a.length).to.equal(1);
|
|
695
|
+
expect(recordsQueryReply.entries[0].descriptor.published).to.equal(true);
|
|
696
|
+
// very importantly verify the original data is still returned
|
|
697
|
+
expect(recordsQueryReply.entries[0].encodedData).to.equal(encodedData);
|
|
698
|
+
}));
|
|
699
|
+
it('should inherit parent published state when using createFrom() to create RecordsWrite', () => __awaiter(this, void 0, void 0, function* () {
|
|
700
|
+
var _a;
|
|
701
|
+
const { message, author, recordsWrite, dataStream } = yield TestDataGenerator.generateRecordsWrite({
|
|
702
|
+
published: true
|
|
703
|
+
});
|
|
704
|
+
const tenant = author.did;
|
|
705
|
+
// setting up a stub DID resolver
|
|
706
|
+
TestStubGenerator.stubDidResolver(didResolver, [author]);
|
|
707
|
+
const reply = yield dwn.processMessage(tenant, message, { dataStream });
|
|
708
|
+
expect(reply.status.code).to.equal(202);
|
|
709
|
+
const newData = Encoder.stringToBytes('new data');
|
|
710
|
+
const newWrite = yield RecordsWrite.createFrom({
|
|
711
|
+
recordsWriteMessage: recordsWrite.message,
|
|
712
|
+
data: newData,
|
|
713
|
+
signer: Jws.createSigner(author)
|
|
714
|
+
});
|
|
715
|
+
const newWriteReply = yield dwn.processMessage(tenant, newWrite.message, { dataStream: DataStream.fromBytes(newData) });
|
|
716
|
+
expect(newWriteReply.status.code).to.equal(202);
|
|
717
|
+
// verify the new record state can be queried
|
|
718
|
+
const recordsQueryMessageData = yield TestDataGenerator.generateRecordsQuery({
|
|
719
|
+
author,
|
|
720
|
+
filter: { recordId: message.recordId }
|
|
721
|
+
});
|
|
722
|
+
const recordsQueryReply = yield dwn.processMessage(tenant, recordsQueryMessageData.message);
|
|
723
|
+
expect(recordsQueryReply.status.code).to.equal(200);
|
|
724
|
+
expect((_a = recordsQueryReply.entries) === null || _a === void 0 ? void 0 : _a.length).to.equal(1);
|
|
725
|
+
const recordsWriteReturned = recordsQueryReply.entries[0];
|
|
726
|
+
expect(recordsWriteReturned.encodedData).to.equal(Encoder.bytesToBase64Url(newData));
|
|
727
|
+
expect(recordsWriteReturned.descriptor.published).to.equal(true);
|
|
728
|
+
expect(recordsWriteReturned.descriptor.datePublished).to.equal(message.descriptor.datePublished);
|
|
729
|
+
}));
|
|
730
|
+
});
|
|
731
|
+
it('should fail with 400 if modifying a record but its initial write cannot be found in DB', () => __awaiter(this, void 0, void 0, function* () {
|
|
732
|
+
const recordId = yield TestDataGenerator.randomCborSha256Cid();
|
|
733
|
+
const { message, author, dataStream } = yield TestDataGenerator.generateRecordsWrite({
|
|
734
|
+
recordId,
|
|
735
|
+
data: Encoder.stringToBytes('anything') // simulating modification of a message
|
|
736
|
+
});
|
|
737
|
+
const tenant = author.did;
|
|
738
|
+
TestStubGenerator.stubDidResolver(didResolver, [author]);
|
|
739
|
+
const reply = yield dwn.processMessage(tenant, message, { dataStream });
|
|
740
|
+
expect(reply.status.code).to.equal(400);
|
|
741
|
+
expect(reply.status.detail).to.contain(DwnErrorCode.RecordsWriteGetInitialWriteNotFound);
|
|
742
|
+
}));
|
|
743
|
+
it('should return 400 if `dateCreated` and `messageTimestamp` are not the same in an initial write', () => __awaiter(this, void 0, void 0, function* () {
|
|
744
|
+
const { author, message, dataStream } = yield TestDataGenerator.generateRecordsWrite({
|
|
745
|
+
dateCreated: '2023-01-10T10:20:30.405060Z',
|
|
746
|
+
messageTimestamp: Time.getCurrentTimestamp() // this always generate a different timestamp
|
|
747
|
+
});
|
|
748
|
+
const tenant = author.did;
|
|
749
|
+
TestStubGenerator.stubDidResolver(didResolver, [author]);
|
|
750
|
+
const reply = yield dwn.processMessage(tenant, message, { dataStream });
|
|
751
|
+
expect(reply.status.code).to.equal(400);
|
|
752
|
+
expect(reply.status.detail).to.contain('must match dateCreated');
|
|
753
|
+
}));
|
|
754
|
+
it('should return 400 if `contextId` in an initial protocol-base write mismatches with the expected deterministic `contextId`', () => __awaiter(this, void 0, void 0, function* () {
|
|
755
|
+
// generate a message with protocol so that computed contextId is also computed and included in message
|
|
756
|
+
const { message, dataStream, author } = yield TestDataGenerator.generateRecordsWrite({ protocol: 'http://any.value', protocolPath: 'any/value' });
|
|
757
|
+
message.contextId = yield TestDataGenerator.randomCborSha256Cid(); // make contextId mismatch from computed value
|
|
758
|
+
TestStubGenerator.stubDidResolver(didResolver, [author]);
|
|
759
|
+
const reply = yield dwn.processMessage('unused-tenant-DID', message, { dataStream });
|
|
760
|
+
expect(reply.status.code).to.equal(400);
|
|
761
|
+
expect(reply.status.detail).to.contain('does not match deterministic contextId');
|
|
762
|
+
}));
|
|
763
|
+
describe('event log', () => {
|
|
764
|
+
it('should add an event to the event log on initial write', () => __awaiter(this, void 0, void 0, function* () {
|
|
765
|
+
const { message, author, dataStream } = yield TestDataGenerator.generateRecordsWrite();
|
|
766
|
+
TestStubGenerator.stubDidResolver(didResolver, [author]);
|
|
767
|
+
const reply = yield dwn.processMessage(author.did, message, { dataStream });
|
|
768
|
+
expect(reply.status.code).to.equal(202);
|
|
769
|
+
const { events } = yield eventLog.getEvents(author.did);
|
|
770
|
+
expect(events.length).to.equal(1);
|
|
771
|
+
const messageCid = yield Message.getCid(message);
|
|
772
|
+
expect(events[0]).to.equal(messageCid);
|
|
773
|
+
}));
|
|
774
|
+
it('should only keep first write and latest write when subsequent writes happen', () => __awaiter(this, void 0, void 0, function* () {
|
|
775
|
+
const { message, author, dataStream, recordsWrite } = yield TestDataGenerator.generateRecordsWrite();
|
|
776
|
+
TestStubGenerator.stubDidResolver(didResolver, [author]);
|
|
777
|
+
const reply = yield dwn.processMessage(author.did, message, { dataStream });
|
|
778
|
+
expect(reply.status.code).to.equal(202);
|
|
779
|
+
const newWrite = yield RecordsWrite.createFrom({
|
|
780
|
+
recordsWriteMessage: recordsWrite.message,
|
|
781
|
+
published: true,
|
|
782
|
+
signer: Jws.createSigner(author)
|
|
783
|
+
});
|
|
784
|
+
const newWriteReply = yield dwn.processMessage(author.did, newWrite.message);
|
|
785
|
+
expect(newWriteReply.status.code).to.equal(202);
|
|
786
|
+
const newestWrite = yield RecordsWrite.createFrom({
|
|
787
|
+
recordsWriteMessage: recordsWrite.message,
|
|
788
|
+
published: true,
|
|
789
|
+
signer: Jws.createSigner(author)
|
|
790
|
+
});
|
|
791
|
+
const newestWriteReply = yield dwn.processMessage(author.did, newestWrite.message);
|
|
792
|
+
expect(newestWriteReply.status.code).to.equal(202);
|
|
793
|
+
const { events } = yield eventLog.getEvents(author.did);
|
|
794
|
+
expect(events.length).to.equal(2);
|
|
795
|
+
const deletedMessageCid = yield Message.getCid(newWrite.message);
|
|
796
|
+
for (const messageCid of events) {
|
|
797
|
+
if (messageCid === deletedMessageCid) {
|
|
798
|
+
expect.fail(`${messageCid} should not exist`);
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
}));
|
|
802
|
+
});
|
|
803
|
+
});
|
|
804
|
+
describe('protocol based writes', () => {
|
|
805
|
+
it('should allow write with allow-anyone rule', () => __awaiter(this, void 0, void 0, function* () {
|
|
806
|
+
// scenario: Bob writes into Alice's DWN given Alice's "email" protocol allow-anyone rule
|
|
807
|
+
var _a;
|
|
808
|
+
// write a protocol definition with an allow-anyone rule
|
|
809
|
+
const protocolDefinition = emailProtocolDefinition;
|
|
810
|
+
const alice = yield TestDataGenerator.generatePersona();
|
|
811
|
+
const bob = yield TestDataGenerator.generatePersona();
|
|
812
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
813
|
+
author: alice,
|
|
814
|
+
protocolDefinition
|
|
815
|
+
});
|
|
816
|
+
// setting up a stub DID resolver
|
|
817
|
+
TestStubGenerator.stubDidResolver(didResolver, [alice, bob]);
|
|
818
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
819
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
820
|
+
// generate a `RecordsWrite` message from bob
|
|
821
|
+
const bobData = Encoder.stringToBytes('data from bob');
|
|
822
|
+
const emailFromBob = yield TestDataGenerator.generateRecordsWrite({
|
|
823
|
+
author: bob,
|
|
824
|
+
protocol: protocolDefinition.protocol,
|
|
825
|
+
protocolPath: 'email',
|
|
826
|
+
schema: protocolDefinition.types.email.schema,
|
|
827
|
+
dataFormat: protocolDefinition.types.email.dataFormats[0],
|
|
828
|
+
data: bobData
|
|
829
|
+
});
|
|
830
|
+
const bobWriteReply = yield dwn.processMessage(alice.did, emailFromBob.message, { dataStream: emailFromBob.dataStream });
|
|
831
|
+
expect(bobWriteReply.status.code).to.equal(202);
|
|
832
|
+
// verify bob's message got written to the DB
|
|
833
|
+
const messageDataForQueryingBobsWrite = yield TestDataGenerator.generateRecordsQuery({
|
|
834
|
+
author: alice,
|
|
835
|
+
filter: { recordId: emailFromBob.message.recordId }
|
|
836
|
+
});
|
|
837
|
+
const bobRecordsQueryReply = yield dwn.processMessage(alice.did, messageDataForQueryingBobsWrite.message);
|
|
838
|
+
expect(bobRecordsQueryReply.status.code).to.equal(200);
|
|
839
|
+
expect((_a = bobRecordsQueryReply.entries) === null || _a === void 0 ? void 0 : _a.length).to.equal(1);
|
|
840
|
+
expect(bobRecordsQueryReply.entries[0].encodedData).to.equal(Encoder.bytesToBase64Url(bobData));
|
|
841
|
+
}));
|
|
842
|
+
it('should allow co-update with allow-anyone rule', () => __awaiter(this, void 0, void 0, function* () {
|
|
843
|
+
// scenario: Alice creates a record on her DWN, and Bob (anyone) is able to update it. Bob is not able to
|
|
844
|
+
// create a record.
|
|
845
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
846
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
847
|
+
const protocolDefinition = anyoneCollaborateProtocolDefinition;
|
|
848
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
849
|
+
author: alice,
|
|
850
|
+
protocolDefinition
|
|
851
|
+
});
|
|
852
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
853
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
854
|
+
// Alice creates a doc
|
|
855
|
+
const docRecord = yield TestDataGenerator.generateRecordsWrite({
|
|
856
|
+
author: alice,
|
|
857
|
+
recipient: alice.did,
|
|
858
|
+
protocol: protocolDefinition.protocol,
|
|
859
|
+
protocolPath: 'doc'
|
|
860
|
+
});
|
|
861
|
+
const docRecordsReply = yield dwn.processMessage(alice.did, docRecord.message, { dataStream: docRecord.dataStream });
|
|
862
|
+
expect(docRecordsReply.status.code).to.equal(202);
|
|
863
|
+
// Bob updates Alice's doc
|
|
864
|
+
const bobsData = yield TestDataGenerator.randomBytes(10);
|
|
865
|
+
const docUpdateRecord = yield TestDataGenerator.generateFromRecordsWrite({
|
|
866
|
+
author: bob,
|
|
867
|
+
existingWrite: docRecord.recordsWrite,
|
|
868
|
+
data: bobsData
|
|
869
|
+
});
|
|
870
|
+
const docUpdateRecordsReply = yield dwn.processMessage(alice.did, docUpdateRecord.message, { dataStream: docUpdateRecord.dataStream });
|
|
871
|
+
expect(docUpdateRecordsReply.status.code).to.equal(202);
|
|
872
|
+
// Bob tries and fails to create a new record
|
|
873
|
+
const bobDocRecord = yield TestDataGenerator.generateRecordsWrite({
|
|
874
|
+
author: bob,
|
|
875
|
+
recipient: bob.did,
|
|
876
|
+
protocol: protocolDefinition.protocol,
|
|
877
|
+
protocolPath: 'doc'
|
|
878
|
+
});
|
|
879
|
+
const bobDocRecordsReply = yield dwn.processMessage(alice.did, bobDocRecord.message, { dataStream: bobDocRecord.dataStream });
|
|
880
|
+
expect(bobDocRecordsReply.status.code).to.equal(401);
|
|
881
|
+
expect(bobDocRecordsReply.status.detail).to.contain(DwnErrorCode.ProtocolAuthorizationActionNotAllowed);
|
|
882
|
+
}));
|
|
883
|
+
describe('recipient rules', () => {
|
|
884
|
+
it('should allow write with ancestor recipient rule', () => __awaiter(this, void 0, void 0, function* () {
|
|
885
|
+
// scenario: VC issuer writes into Alice's DWN an asynchronous credential response upon receiving Alice's credential application
|
|
886
|
+
// Carol tries to write a credential response but is rejected
|
|
887
|
+
var _a;
|
|
888
|
+
const protocolDefinition = credentialIssuanceProtocolDefinition;
|
|
889
|
+
const credentialApplicationSchema = protocolDefinition.types.credentialApplication.schema;
|
|
890
|
+
const credentialResponseSchema = protocolDefinition.types.credentialResponse.schema;
|
|
891
|
+
const alice = yield TestDataGenerator.generatePersona();
|
|
892
|
+
const vcIssuer = yield TestDataGenerator.generatePersona();
|
|
893
|
+
const carol = yield TestDataGenerator.generatePersona();
|
|
894
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
895
|
+
author: alice,
|
|
896
|
+
protocolDefinition
|
|
897
|
+
});
|
|
898
|
+
// setting up a stub DID resolver
|
|
899
|
+
TestStubGenerator.stubDidResolver(didResolver, [alice, vcIssuer, carol]);
|
|
900
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
901
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
902
|
+
// write a credential application to Alice's DWN to simulate that she has sent a credential application to a VC issuer
|
|
903
|
+
const encodedCredentialApplication = new TextEncoder().encode('credential application data');
|
|
904
|
+
const credentialApplication = yield TestDataGenerator.generateRecordsWrite({
|
|
905
|
+
author: alice,
|
|
906
|
+
recipient: vcIssuer.did,
|
|
907
|
+
protocol: protocolDefinition.protocol,
|
|
908
|
+
protocolPath: 'credentialApplication', // this comes from `types` in protocol definition
|
|
909
|
+
schema: credentialApplicationSchema,
|
|
910
|
+
dataFormat: protocolDefinition.types.credentialApplication.dataFormats[0],
|
|
911
|
+
data: encodedCredentialApplication
|
|
912
|
+
});
|
|
913
|
+
const credentialApplicationReply = yield dwn.processMessage(alice.did, credentialApplication.message, { dataStream: credentialApplication.dataStream });
|
|
914
|
+
expect(credentialApplicationReply.status.code).to.equal(202);
|
|
915
|
+
// generate a credential application response message from VC issuer
|
|
916
|
+
const encodedCredentialResponse = new TextEncoder().encode('credential response data');
|
|
917
|
+
const credentialResponse = yield TestDataGenerator.generateRecordsWrite({
|
|
918
|
+
author: vcIssuer,
|
|
919
|
+
recipient: alice.did,
|
|
920
|
+
protocol: protocolDefinition.protocol,
|
|
921
|
+
protocolPath: 'credentialApplication/credentialResponse', // this comes from `types` in protocol definition
|
|
922
|
+
parentContextId: credentialApplication.message.contextId,
|
|
923
|
+
schema: credentialResponseSchema,
|
|
924
|
+
dataFormat: protocolDefinition.types.credentialResponse.dataFormats[0],
|
|
925
|
+
data: encodedCredentialResponse
|
|
926
|
+
});
|
|
927
|
+
const credentialResponseReply = yield dwn.processMessage(alice.did, credentialResponse.message, { dataStream: credentialResponse.dataStream });
|
|
928
|
+
expect(credentialResponseReply.status.code).to.equal(202);
|
|
929
|
+
// verify VC issuer's message got written to the DB
|
|
930
|
+
const messageDataForQueryingCredentialResponse = yield TestDataGenerator.generateRecordsQuery({
|
|
931
|
+
author: alice,
|
|
932
|
+
filter: { recordId: credentialResponse.message.recordId }
|
|
933
|
+
});
|
|
934
|
+
const applicationResponseQueryReply = yield dwn.processMessage(alice.did, messageDataForQueryingCredentialResponse.message);
|
|
935
|
+
expect(applicationResponseQueryReply.status.code).to.equal(200);
|
|
936
|
+
expect((_a = applicationResponseQueryReply.entries) === null || _a === void 0 ? void 0 : _a.length).to.equal(1);
|
|
937
|
+
expect(applicationResponseQueryReply.entries[0].encodedData)
|
|
938
|
+
.to.equal(base64url.baseEncode(encodedCredentialResponse));
|
|
939
|
+
}));
|
|
940
|
+
it('should allow co-update with ancestor recipient rule', () => __awaiter(this, void 0, void 0, function* () {
|
|
941
|
+
// scenario: Alice creates a post with Bob as recipient. Alice adds a `post/tag` to the post. Bob is able to update
|
|
942
|
+
// the `post/tag` because he is recipient of the post. Bob is not able to create a new `post/tag`.
|
|
943
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
944
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
945
|
+
const protocolDefinition = recipientCanProtocol;
|
|
946
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
947
|
+
author: alice,
|
|
948
|
+
protocolDefinition
|
|
949
|
+
});
|
|
950
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
951
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
952
|
+
// Alice creates a post with Bob as recipient
|
|
953
|
+
const docRecord = yield TestDataGenerator.generateRecordsWrite({
|
|
954
|
+
author: alice,
|
|
955
|
+
recipient: bob.did,
|
|
956
|
+
protocol: protocolDefinition.protocol,
|
|
957
|
+
protocolPath: 'post'
|
|
958
|
+
});
|
|
959
|
+
const docRecordsReply = yield dwn.processMessage(alice.did, docRecord.message, { dataStream: docRecord.dataStream });
|
|
960
|
+
expect(docRecordsReply.status.code).to.equal(202);
|
|
961
|
+
// Alice creates a post/tag
|
|
962
|
+
const tagRecord = yield TestDataGenerator.generateRecordsWrite({
|
|
963
|
+
author: alice,
|
|
964
|
+
recipient: alice.did,
|
|
965
|
+
protocol: protocolDefinition.protocol,
|
|
966
|
+
protocolPath: 'post/tag',
|
|
967
|
+
parentContextId: docRecord.message.contextId,
|
|
968
|
+
});
|
|
969
|
+
const tagRecordsReply = yield dwn.processMessage(alice.did, tagRecord.message, { dataStream: tagRecord.dataStream });
|
|
970
|
+
expect(tagRecordsReply.status.code).to.equal(202);
|
|
971
|
+
// Bob updates Alice's post
|
|
972
|
+
const bobsData = yield TestDataGenerator.randomBytes(10);
|
|
973
|
+
const tagUpdateRecord = yield TestDataGenerator.generateFromRecordsWrite({
|
|
974
|
+
author: bob,
|
|
975
|
+
existingWrite: tagRecord.recordsWrite,
|
|
976
|
+
data: bobsData
|
|
977
|
+
});
|
|
978
|
+
const tagUpdateRecordsReply = yield dwn.processMessage(alice.did, tagUpdateRecord.message, { dataStream: tagUpdateRecord.dataStream });
|
|
979
|
+
expect(tagUpdateRecordsReply.status.code).to.equal(202);
|
|
980
|
+
// Bob tries and fails to create a new record
|
|
981
|
+
const bobTagRecord = yield TestDataGenerator.generateRecordsWrite({
|
|
982
|
+
author: bob,
|
|
983
|
+
recipient: bob.did,
|
|
984
|
+
protocol: protocolDefinition.protocol,
|
|
985
|
+
protocolPath: 'post/tag',
|
|
986
|
+
parentContextId: docRecord.message.contextId,
|
|
987
|
+
});
|
|
988
|
+
const bobTagRecordsReply = yield dwn.processMessage(alice.did, bobTagRecord.message, { dataStream: bobTagRecord.dataStream });
|
|
989
|
+
expect(bobTagRecordsReply.status.code).to.equal(401);
|
|
990
|
+
expect(bobTagRecordsReply.status.detail).to.contain(DwnErrorCode.ProtocolAuthorizationActionNotAllowed);
|
|
991
|
+
}));
|
|
992
|
+
it('should allow co-update with direct recipient rule', () => __awaiter(this, void 0, void 0, function* () {
|
|
993
|
+
// scenario:
|
|
994
|
+
// Alice creates a 'post' with Bob as recipient.
|
|
995
|
+
// Bob is able to update the 'post' because he was recipient of it.
|
|
996
|
+
// Carol is not able to update it.
|
|
997
|
+
const protocolDefinition = recipientCanProtocol;
|
|
998
|
+
const alice = yield TestDataGenerator.generatePersona();
|
|
999
|
+
const bob = yield TestDataGenerator.generatePersona();
|
|
1000
|
+
const carol = yield TestDataGenerator.generatePersona();
|
|
1001
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
1002
|
+
author: alice,
|
|
1003
|
+
protocolDefinition
|
|
1004
|
+
});
|
|
1005
|
+
// setting up a stub DID resolver
|
|
1006
|
+
TestStubGenerator.stubDidResolver(didResolver, [alice, bob, carol]);
|
|
1007
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
1008
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
1009
|
+
// Alice creates a 'post' with Bob as recipient
|
|
1010
|
+
const recordsWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
1011
|
+
author: alice,
|
|
1012
|
+
recipient: bob.did,
|
|
1013
|
+
protocol: protocolDefinition.protocol,
|
|
1014
|
+
protocolPath: 'post',
|
|
1015
|
+
});
|
|
1016
|
+
const recordsWriteReply = yield dwn.processMessage(alice.did, recordsWrite.message, { dataStream: recordsWrite.dataStream });
|
|
1017
|
+
expect(recordsWriteReply.status.code).to.eq(202);
|
|
1018
|
+
// Carol is unable to update the 'post'
|
|
1019
|
+
const carolRecordsWrite = yield TestDataGenerator.generateFromRecordsWrite({
|
|
1020
|
+
author: carol,
|
|
1021
|
+
existingWrite: recordsWrite.recordsWrite
|
|
1022
|
+
});
|
|
1023
|
+
const carolRecordsWriteReply = yield dwn.processMessage(alice.did, carolRecordsWrite.message);
|
|
1024
|
+
expect(carolRecordsWriteReply.status.code).to.eq(401);
|
|
1025
|
+
expect(carolRecordsWriteReply.status.detail).to.contain(DwnErrorCode.ProtocolAuthorizationActionNotAllowed);
|
|
1026
|
+
// Bob is able to update the post
|
|
1027
|
+
const bobRecordsWrite = yield TestDataGenerator.generateFromRecordsWrite({
|
|
1028
|
+
author: bob,
|
|
1029
|
+
existingWrite: recordsWrite.recordsWrite,
|
|
1030
|
+
});
|
|
1031
|
+
const bobRecordsWriteReply = yield dwn.processMessage(alice.did, bobRecordsWrite.message, { dataStream: bobRecordsWrite.dataStream });
|
|
1032
|
+
expect(bobRecordsWriteReply.status.code).to.eq(202);
|
|
1033
|
+
}));
|
|
1034
|
+
});
|
|
1035
|
+
describe('author action rules', () => {
|
|
1036
|
+
it('allow author to write with ancestor author rule and block non-authors', () => __awaiter(this, void 0, void 0, function* () {
|
|
1037
|
+
var _a;
|
|
1038
|
+
// scenario: Alice posts an image on the social media protocol to Bob's, then she adds a caption
|
|
1039
|
+
// AliceImposter attempts to post add a caption to Alice's image, but is blocked
|
|
1040
|
+
const protocolDefinition = socialMediaProtocolDefinition;
|
|
1041
|
+
const alice = yield TestDataGenerator.generatePersona();
|
|
1042
|
+
const aliceImposter = yield TestDataGenerator.generatePersona();
|
|
1043
|
+
const bob = yield TestDataGenerator.generatePersona();
|
|
1044
|
+
// setting up a stub DID resolver
|
|
1045
|
+
TestStubGenerator.stubDidResolver(didResolver, [alice, aliceImposter, bob]);
|
|
1046
|
+
// Install social-media protocol
|
|
1047
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
1048
|
+
author: bob,
|
|
1049
|
+
protocolDefinition
|
|
1050
|
+
});
|
|
1051
|
+
const protocolsConfigureReply = yield dwn.processMessage(bob.did, protocolsConfig.message);
|
|
1052
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
1053
|
+
// Alice writes image to bob's DWN
|
|
1054
|
+
const encodedImage = new TextEncoder().encode('cafe-aesthetic.jpg');
|
|
1055
|
+
const imageRecordsWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
1056
|
+
author: alice,
|
|
1057
|
+
protocol: protocolDefinition.protocol,
|
|
1058
|
+
protocolPath: 'image', // this comes from `types` in protocol definition
|
|
1059
|
+
schema: protocolDefinition.types.image.schema,
|
|
1060
|
+
dataFormat: protocolDefinition.types.image.dataFormats[0],
|
|
1061
|
+
data: encodedImage
|
|
1062
|
+
});
|
|
1063
|
+
const imageReply = yield dwn.processMessage(bob.did, imageRecordsWrite.message, { dataStream: imageRecordsWrite.dataStream });
|
|
1064
|
+
expect(imageReply.status.code).to.equal(202);
|
|
1065
|
+
// AliceImposter attempts and fails to caption Alice's image
|
|
1066
|
+
const encodedCaptionImposter = new TextEncoder().encode('bad vibes! >:(');
|
|
1067
|
+
const captionImposter = yield TestDataGenerator.generateRecordsWrite({
|
|
1068
|
+
author: aliceImposter,
|
|
1069
|
+
protocol: protocolDefinition.protocol,
|
|
1070
|
+
protocolPath: 'image/caption', // this comes from `types` in protocol definition
|
|
1071
|
+
schema: protocolDefinition.types.caption.schema,
|
|
1072
|
+
dataFormat: protocolDefinition.types.caption.dataFormats[0],
|
|
1073
|
+
parentContextId: imageRecordsWrite.recordsWrite.message.contextId,
|
|
1074
|
+
data: encodedCaptionImposter
|
|
1075
|
+
});
|
|
1076
|
+
const captionReply = yield dwn.processMessage(bob.did, captionImposter.message, { dataStream: captionImposter.dataStream });
|
|
1077
|
+
expect(captionReply.status.code).to.equal(401);
|
|
1078
|
+
expect(captionReply.status.detail).to.contain(DwnErrorCode.ProtocolAuthorizationActionNotAllowed);
|
|
1079
|
+
// Alice is able to add a caption to her image
|
|
1080
|
+
const encodedCaption = new TextEncoder().encode('coffee and work vibes!');
|
|
1081
|
+
const captionRecordsWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
1082
|
+
author: alice,
|
|
1083
|
+
protocol: protocolDefinition.protocol,
|
|
1084
|
+
protocolPath: 'image/caption',
|
|
1085
|
+
schema: protocolDefinition.types.caption.schema,
|
|
1086
|
+
dataFormat: protocolDefinition.types.caption.dataFormats[0],
|
|
1087
|
+
parentContextId: imageRecordsWrite.recordsWrite.message.contextId,
|
|
1088
|
+
data: encodedCaption
|
|
1089
|
+
});
|
|
1090
|
+
const captionResponse = yield dwn.processMessage(bob.did, captionRecordsWrite.message, { dataStream: captionRecordsWrite.dataStream });
|
|
1091
|
+
expect(captionResponse.status.code).to.equal(202);
|
|
1092
|
+
// Verify Alice's caption got written to the DB
|
|
1093
|
+
const messageDataForQueryingCaptionResponse = yield TestDataGenerator.generateRecordsQuery({
|
|
1094
|
+
author: alice,
|
|
1095
|
+
filter: { recordId: captionRecordsWrite.message.recordId }
|
|
1096
|
+
});
|
|
1097
|
+
const applicationResponseQueryReply = yield dwn.processMessage(bob.did, messageDataForQueryingCaptionResponse.message);
|
|
1098
|
+
expect(applicationResponseQueryReply.status.code).to.equal(200);
|
|
1099
|
+
expect((_a = applicationResponseQueryReply.entries) === null || _a === void 0 ? void 0 : _a.length).to.equal(1);
|
|
1100
|
+
expect(applicationResponseQueryReply.entries[0].encodedData)
|
|
1101
|
+
.to.equal(base64url.baseEncode(encodedCaption));
|
|
1102
|
+
}));
|
|
1103
|
+
it('should allow co-update with ancestor author rule', () => __awaiter(this, void 0, void 0, function* () {
|
|
1104
|
+
// scenario: Bob authors a post on Alice's DWN. Alice adds a comment to the post. Bob is able to update the comment,
|
|
1105
|
+
// since he authored the post.
|
|
1106
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
1107
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
1108
|
+
const protocolDefinition = authorCanProtocolDefinition;
|
|
1109
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
1110
|
+
author: alice,
|
|
1111
|
+
protocolDefinition
|
|
1112
|
+
});
|
|
1113
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
1114
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
1115
|
+
// Bob creates a post
|
|
1116
|
+
const postRecord = yield TestDataGenerator.generateRecordsWrite({
|
|
1117
|
+
author: bob,
|
|
1118
|
+
recipient: bob.did,
|
|
1119
|
+
protocol: protocolDefinition.protocol,
|
|
1120
|
+
protocolPath: 'post'
|
|
1121
|
+
});
|
|
1122
|
+
const postRecordsReply = yield dwn.processMessage(alice.did, postRecord.message, { dataStream: postRecord.dataStream });
|
|
1123
|
+
expect(postRecordsReply.status.code).to.equal(202);
|
|
1124
|
+
// Alice creates a post/comment
|
|
1125
|
+
const commentRecord = yield TestDataGenerator.generateRecordsWrite({
|
|
1126
|
+
author: alice,
|
|
1127
|
+
recipient: alice.did,
|
|
1128
|
+
protocol: protocolDefinition.protocol,
|
|
1129
|
+
protocolPath: 'post/comment',
|
|
1130
|
+
parentContextId: postRecord.message.contextId,
|
|
1131
|
+
});
|
|
1132
|
+
const commentRecordsReply = yield dwn.processMessage(alice.did, commentRecord.message, { dataStream: commentRecord.dataStream });
|
|
1133
|
+
expect(commentRecordsReply.status.code).to.equal(202);
|
|
1134
|
+
// Bob updates Alice's comment
|
|
1135
|
+
const bobsData = yield TestDataGenerator.randomBytes(10);
|
|
1136
|
+
const postUpdateRecord = yield TestDataGenerator.generateFromRecordsWrite({
|
|
1137
|
+
author: alice,
|
|
1138
|
+
existingWrite: commentRecord.recordsWrite,
|
|
1139
|
+
data: bobsData
|
|
1140
|
+
});
|
|
1141
|
+
const commentUpdateRecordsReply = yield dwn.processMessage(alice.did, postUpdateRecord.message, { dataStream: postUpdateRecord.dataStream });
|
|
1142
|
+
expect(commentUpdateRecordsReply.status.code).to.equal(202);
|
|
1143
|
+
// Bob tries and fails to create a new comment
|
|
1144
|
+
const bobPostRecord = yield TestDataGenerator.generateRecordsWrite({
|
|
1145
|
+
author: bob,
|
|
1146
|
+
recipient: bob.did,
|
|
1147
|
+
protocol: protocolDefinition.protocol,
|
|
1148
|
+
protocolPath: 'post/comment',
|
|
1149
|
+
parentContextId: postRecord.message.contextId,
|
|
1150
|
+
});
|
|
1151
|
+
const bobPostRecordsReply = yield dwn.processMessage(alice.did, bobPostRecord.message, { dataStream: bobPostRecord.dataStream });
|
|
1152
|
+
expect(bobPostRecordsReply.status.code).to.equal(401);
|
|
1153
|
+
expect(bobPostRecordsReply.status.detail).to.contain(DwnErrorCode.ProtocolAuthorizationActionNotAllowed);
|
|
1154
|
+
}));
|
|
1155
|
+
});
|
|
1156
|
+
describe('role rules', () => {
|
|
1157
|
+
describe('write root-level role records', () => {
|
|
1158
|
+
it('allows a root-level role record with unique recipient to be created and updated', () => __awaiter(this, void 0, void 0, function* () {
|
|
1159
|
+
// scenario: Alice adds Bob to the 'friend' role. Then she updates the 'friend' record.
|
|
1160
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
1161
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
1162
|
+
const protocolDefinition = friendRoleProtocolDefinition;
|
|
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 'friend' root-level role record with Bob as recipient
|
|
1170
|
+
const friendRoleRecord = yield TestDataGenerator.generateRecordsWrite({
|
|
1171
|
+
author: alice,
|
|
1172
|
+
recipient: bob.did,
|
|
1173
|
+
protocol: protocolDefinition.protocol,
|
|
1174
|
+
protocolPath: 'friend',
|
|
1175
|
+
data: new TextEncoder().encode('Bob is my friend'),
|
|
1176
|
+
});
|
|
1177
|
+
const friendRoleReply = yield dwn.processMessage(alice.did, friendRoleRecord.message, { dataStream: friendRoleRecord.dataStream });
|
|
1178
|
+
expect(friendRoleReply.status.code).to.equal(202);
|
|
1179
|
+
// Alice updates Bob's 'friend' record
|
|
1180
|
+
const updateFriendRecord = yield TestDataGenerator.generateFromRecordsWrite({
|
|
1181
|
+
author: alice,
|
|
1182
|
+
existingWrite: friendRoleRecord.recordsWrite,
|
|
1183
|
+
});
|
|
1184
|
+
const updateFriendReply = yield dwn.processMessage(alice.did, updateFriendRecord.message, { dataStream: updateFriendRecord.dataStream });
|
|
1185
|
+
expect(updateFriendReply.status.code).to.equal(202);
|
|
1186
|
+
}));
|
|
1187
|
+
it('should reject role RecordsWrite if recipient is undefined', () => __awaiter(this, void 0, void 0, function* () {
|
|
1188
|
+
// scenario: Alice writes a root-level role record with no recipient and it is rejected
|
|
1189
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
1190
|
+
const protocolDefinition = friendRoleProtocolDefinition;
|
|
1191
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
1192
|
+
author: alice,
|
|
1193
|
+
protocolDefinition
|
|
1194
|
+
});
|
|
1195
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
1196
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
1197
|
+
// Alice writes a 'friend' root-level role record with no recipient
|
|
1198
|
+
const friendRoleRecord = yield TestDataGenerator.generateRecordsWrite({
|
|
1199
|
+
author: alice,
|
|
1200
|
+
protocol: protocolDefinition.protocol,
|
|
1201
|
+
protocolPath: 'friend',
|
|
1202
|
+
data: new TextEncoder().encode('Bob is my friend'),
|
|
1203
|
+
});
|
|
1204
|
+
const friendRoleReply = yield dwn.processMessage(alice.did, friendRoleRecord.message, { dataStream: friendRoleRecord.dataStream });
|
|
1205
|
+
expect(friendRoleReply.status.code).to.equal(400);
|
|
1206
|
+
expect(friendRoleReply.status.detail).to.contain(DwnErrorCode.ProtocolAuthorizationRoleMissingRecipient);
|
|
1207
|
+
}));
|
|
1208
|
+
it('should allow a new root-level role record to be created for the same recipient if their old one was deleted', () => __awaiter(this, void 0, void 0, function* () {
|
|
1209
|
+
// scenario: Alice adds Bob to the 'friend' role, then deletes the role. Alice writes a new record adding Bob as a 'friend' again.
|
|
1210
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
1211
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
1212
|
+
const protocolDefinition = friendRoleProtocolDefinition;
|
|
1213
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
1214
|
+
author: alice,
|
|
1215
|
+
protocolDefinition
|
|
1216
|
+
});
|
|
1217
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
1218
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
1219
|
+
// Alice writes a 'friend' root-level role record with Bob as recipient
|
|
1220
|
+
const friendRoleRecord = yield TestDataGenerator.generateRecordsWrite({
|
|
1221
|
+
author: alice,
|
|
1222
|
+
recipient: bob.did,
|
|
1223
|
+
protocol: protocolDefinition.protocol,
|
|
1224
|
+
protocolPath: 'friend',
|
|
1225
|
+
data: new TextEncoder().encode('Bob is my friend'),
|
|
1226
|
+
});
|
|
1227
|
+
const friendRoleReply = yield dwn.processMessage(alice.did, friendRoleRecord.message, { dataStream: friendRoleRecord.dataStream });
|
|
1228
|
+
expect(friendRoleReply.status.code).to.equal(202);
|
|
1229
|
+
// Alice deletes Bob's 'friend' role record
|
|
1230
|
+
const deleteFriend = yield TestDataGenerator.generateRecordsDelete({
|
|
1231
|
+
author: alice,
|
|
1232
|
+
recordId: friendRoleRecord.message.recordId,
|
|
1233
|
+
});
|
|
1234
|
+
const deleteFriendReply = yield dwn.processMessage(alice.did, deleteFriend.message);
|
|
1235
|
+
expect(deleteFriendReply.status.code).to.equal(202);
|
|
1236
|
+
// Alice writes a new record adding Bob as a 'friend' again
|
|
1237
|
+
const duplicateFriendRecord = yield TestDataGenerator.generateRecordsWrite({
|
|
1238
|
+
author: alice,
|
|
1239
|
+
recipient: bob.did,
|
|
1240
|
+
protocol: protocolDefinition.protocol,
|
|
1241
|
+
protocolPath: 'friend',
|
|
1242
|
+
data: new TextEncoder().encode('Bob is still my friend'),
|
|
1243
|
+
});
|
|
1244
|
+
const duplicateFriendReply = yield dwn.processMessage(alice.did, duplicateFriendRecord.message, { dataStream: duplicateFriendRecord.dataStream });
|
|
1245
|
+
expect(duplicateFriendReply.status.code).to.equal(202);
|
|
1246
|
+
}));
|
|
1247
|
+
});
|
|
1248
|
+
describe('write context role records', () => {
|
|
1249
|
+
it('can authorized a create or update RecordsWrite using the invoked a context role', () => __awaiter(this, void 0, void 0, function* () {
|
|
1250
|
+
// scenario: Alice creates a thread and adds Bob to the 'thread/participant' role. Then she updates Bob's role record.
|
|
1251
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
1252
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
1253
|
+
const protocolDefinition = threadRoleProtocolDefinition;
|
|
1254
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
1255
|
+
author: alice,
|
|
1256
|
+
protocolDefinition
|
|
1257
|
+
});
|
|
1258
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
1259
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
1260
|
+
// Alice creates a thread
|
|
1261
|
+
const threadRecord = yield TestDataGenerator.generateRecordsWrite({
|
|
1262
|
+
author: alice,
|
|
1263
|
+
recipient: bob.did,
|
|
1264
|
+
protocol: protocolDefinition.protocol,
|
|
1265
|
+
protocolPath: 'thread'
|
|
1266
|
+
});
|
|
1267
|
+
const threadRecordReply = yield dwn.processMessage(alice.did, threadRecord.message, { dataStream: threadRecord.dataStream });
|
|
1268
|
+
expect(threadRecordReply.status.code).to.equal(202);
|
|
1269
|
+
// Alice adds Bob as a 'thread/participant' in that thread
|
|
1270
|
+
const participantRecord = yield TestDataGenerator.generateRecordsWrite({
|
|
1271
|
+
author: alice,
|
|
1272
|
+
recipient: bob.did,
|
|
1273
|
+
protocol: protocolDefinition.protocol,
|
|
1274
|
+
protocolPath: 'thread/participant',
|
|
1275
|
+
parentContextId: threadRecord.message.contextId,
|
|
1276
|
+
});
|
|
1277
|
+
const participantRecordReply = yield dwn.processMessage(alice.did, participantRecord.message, { dataStream: participantRecord.dataStream });
|
|
1278
|
+
expect(participantRecordReply.status.code).to.equal(202);
|
|
1279
|
+
// Alice updates Bob's role record
|
|
1280
|
+
const participantUpdateRecord = yield TestDataGenerator.generateFromRecordsWrite({
|
|
1281
|
+
author: alice,
|
|
1282
|
+
existingWrite: participantRecord.recordsWrite,
|
|
1283
|
+
});
|
|
1284
|
+
const participantUpdateRecordReply = yield dwn.processMessage(alice.did, participantUpdateRecord.message, { dataStream: participantUpdateRecord.dataStream });
|
|
1285
|
+
expect(participantUpdateRecordReply.status.code).to.equal(202);
|
|
1286
|
+
}));
|
|
1287
|
+
it('can create the same role under different contexts', () => __awaiter(this, void 0, void 0, function* () {
|
|
1288
|
+
// scenario: Alice creates a thread and adds Bob to the 'thread/participant' role. Alice repeats the steps with a new thread.
|
|
1289
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
1290
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
1291
|
+
const protocolDefinition = threadRoleProtocolDefinition;
|
|
1292
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
1293
|
+
author: alice,
|
|
1294
|
+
protocolDefinition
|
|
1295
|
+
});
|
|
1296
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
1297
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
1298
|
+
// Alice creates the first thread
|
|
1299
|
+
const threadRecord1 = yield TestDataGenerator.generateRecordsWrite({
|
|
1300
|
+
author: alice,
|
|
1301
|
+
recipient: bob.did,
|
|
1302
|
+
protocol: protocolDefinition.protocol,
|
|
1303
|
+
protocolPath: 'thread'
|
|
1304
|
+
});
|
|
1305
|
+
const threadRecordReply1 = yield dwn.processMessage(alice.did, threadRecord1.message, { dataStream: threadRecord1.dataStream });
|
|
1306
|
+
expect(threadRecordReply1.status.code).to.equal(202);
|
|
1307
|
+
// Alice adds Bob as a 'thread/participant' to the first thread
|
|
1308
|
+
const participantRecord1 = yield TestDataGenerator.generateRecordsWrite({
|
|
1309
|
+
author: alice,
|
|
1310
|
+
recipient: bob.did,
|
|
1311
|
+
protocol: protocolDefinition.protocol,
|
|
1312
|
+
protocolPath: 'thread/participant',
|
|
1313
|
+
parentContextId: threadRecord1.message.contextId,
|
|
1314
|
+
});
|
|
1315
|
+
const participantRecordReply1 = yield dwn.processMessage(alice.did, participantRecord1.message, { dataStream: participantRecord1.dataStream });
|
|
1316
|
+
expect(participantRecordReply1.status.code).to.equal(202);
|
|
1317
|
+
// Alice creates a second thread
|
|
1318
|
+
const threadRecord2 = yield TestDataGenerator.generateRecordsWrite({
|
|
1319
|
+
author: alice,
|
|
1320
|
+
recipient: bob.did,
|
|
1321
|
+
protocol: protocolDefinition.protocol,
|
|
1322
|
+
protocolPath: 'thread'
|
|
1323
|
+
});
|
|
1324
|
+
const threadRecordReply2 = yield dwn.processMessage(alice.did, threadRecord2.message, { dataStream: threadRecord2.dataStream });
|
|
1325
|
+
expect(threadRecordReply2.status.code).to.equal(202);
|
|
1326
|
+
// Alice adds Bob as a 'thread/participant' to the second thread
|
|
1327
|
+
const participantRecord2 = yield TestDataGenerator.generateRecordsWrite({
|
|
1328
|
+
author: alice,
|
|
1329
|
+
recipient: bob.did,
|
|
1330
|
+
protocol: protocolDefinition.protocol,
|
|
1331
|
+
protocolPath: 'thread/participant',
|
|
1332
|
+
parentContextId: threadRecord2.message.contextId,
|
|
1333
|
+
});
|
|
1334
|
+
const participantRecordReply2 = yield dwn.processMessage(alice.did, participantRecord2.message, { dataStream: participantRecord2.dataStream });
|
|
1335
|
+
expect(participantRecordReply2.status.code).to.equal(202);
|
|
1336
|
+
}));
|
|
1337
|
+
it('rejects writes to a $role record if there already exists one in the same context', () => __awaiter(this, void 0, void 0, function* () {
|
|
1338
|
+
// scenario: Alice creates a thread and adds Bob to the 'thread/participant' role. She adds Bob to the role second time and fails
|
|
1339
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
1340
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
1341
|
+
const protocolDefinition = threadRoleProtocolDefinition;
|
|
1342
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
1343
|
+
author: alice,
|
|
1344
|
+
protocolDefinition
|
|
1345
|
+
});
|
|
1346
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
1347
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
1348
|
+
// Alice creates the first thread
|
|
1349
|
+
const threadRecord = yield TestDataGenerator.generateRecordsWrite({
|
|
1350
|
+
author: alice,
|
|
1351
|
+
recipient: bob.did,
|
|
1352
|
+
protocol: protocolDefinition.protocol,
|
|
1353
|
+
protocolPath: 'thread'
|
|
1354
|
+
});
|
|
1355
|
+
const threadRecordReply = yield dwn.processMessage(alice.did, threadRecord.message, { dataStream: threadRecord.dataStream });
|
|
1356
|
+
expect(threadRecordReply.status.code).to.equal(202);
|
|
1357
|
+
// Alice adds Bob as a 'thread/participant' to the thread
|
|
1358
|
+
const participantRecord1 = yield TestDataGenerator.generateRecordsWrite({
|
|
1359
|
+
author: alice,
|
|
1360
|
+
recipient: bob.did,
|
|
1361
|
+
protocol: protocolDefinition.protocol,
|
|
1362
|
+
protocolPath: 'thread/participant',
|
|
1363
|
+
parentContextId: threadRecord.message.contextId,
|
|
1364
|
+
});
|
|
1365
|
+
const participantRecordReply1 = yield dwn.processMessage(alice.did, participantRecord1.message, { dataStream: participantRecord1.dataStream });
|
|
1366
|
+
expect(participantRecordReply1.status.code).to.equal(202);
|
|
1367
|
+
// Alice adds Bob as a 'thread/participant' again to the same thread
|
|
1368
|
+
const participantRecord2 = yield TestDataGenerator.generateRecordsWrite({
|
|
1369
|
+
author: alice,
|
|
1370
|
+
recipient: bob.did,
|
|
1371
|
+
protocol: protocolDefinition.protocol,
|
|
1372
|
+
protocolPath: 'thread/participant',
|
|
1373
|
+
parentContextId: threadRecord.message.contextId,
|
|
1374
|
+
});
|
|
1375
|
+
const participantRecordReply2 = yield dwn.processMessage(alice.did, participantRecord2.message, { dataStream: participantRecord2.dataStream });
|
|
1376
|
+
expect(participantRecordReply2.status.code).to.equal(400);
|
|
1377
|
+
expect(participantRecordReply2.status.detail).to.contain(DwnErrorCode.ProtocolAuthorizationDuplicateRoleRecipient);
|
|
1378
|
+
}));
|
|
1379
|
+
it('allows a new context role record to be created for the same recipient in the same context if their old one was deleted', () => __awaiter(this, void 0, void 0, function* () {
|
|
1380
|
+
// scenario: Alice creates a thread and adds Bob to the 'thread/participant' role. She deletes the role and then adds a new one.
|
|
1381
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
1382
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
1383
|
+
const protocolDefinition = threadRoleProtocolDefinition;
|
|
1384
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
1385
|
+
author: alice,
|
|
1386
|
+
protocolDefinition
|
|
1387
|
+
});
|
|
1388
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
1389
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
1390
|
+
// Alice creates the first thread
|
|
1391
|
+
const threadRecord = yield TestDataGenerator.generateRecordsWrite({
|
|
1392
|
+
author: alice,
|
|
1393
|
+
recipient: bob.did,
|
|
1394
|
+
protocol: protocolDefinition.protocol,
|
|
1395
|
+
protocolPath: 'thread'
|
|
1396
|
+
});
|
|
1397
|
+
const threadRecordReply = yield dwn.processMessage(alice.did, threadRecord.message, { dataStream: threadRecord.dataStream });
|
|
1398
|
+
expect(threadRecordReply.status.code).to.equal(202);
|
|
1399
|
+
// Alice adds Bob as a 'thread/participant' to the thread
|
|
1400
|
+
const participantRecord1 = yield TestDataGenerator.generateRecordsWrite({
|
|
1401
|
+
author: alice,
|
|
1402
|
+
recipient: bob.did,
|
|
1403
|
+
protocol: protocolDefinition.protocol,
|
|
1404
|
+
protocolPath: 'thread/participant',
|
|
1405
|
+
parentContextId: threadRecord.message.contextId,
|
|
1406
|
+
});
|
|
1407
|
+
const participantRecordReply1 = yield dwn.processMessage(alice.did, participantRecord1.message, { dataStream: participantRecord1.dataStream });
|
|
1408
|
+
expect(participantRecordReply1.status.code).to.equal(202);
|
|
1409
|
+
// Alice deletes the participant record
|
|
1410
|
+
const participantDelete = yield TestDataGenerator.generateRecordsDelete({
|
|
1411
|
+
author: alice,
|
|
1412
|
+
recordId: participantRecord1.message.recordId,
|
|
1413
|
+
});
|
|
1414
|
+
const participantDeleteReply = yield dwn.processMessage(alice.did, participantDelete.message);
|
|
1415
|
+
expect(participantDeleteReply.status.code).to.equal(202);
|
|
1416
|
+
// Alice creates a new 'thread/participant' record
|
|
1417
|
+
const participantRecord2 = yield TestDataGenerator.generateRecordsWrite({
|
|
1418
|
+
author: alice,
|
|
1419
|
+
recipient: bob.did,
|
|
1420
|
+
protocol: protocolDefinition.protocol,
|
|
1421
|
+
protocolPath: 'thread/participant',
|
|
1422
|
+
parentContextId: threadRecord.message.contextId,
|
|
1423
|
+
});
|
|
1424
|
+
const participantRecordReply2 = yield dwn.processMessage(alice.did, participantRecord2.message, { dataStream: participantRecord2.dataStream });
|
|
1425
|
+
expect(participantRecordReply2.status.code).to.equal(202);
|
|
1426
|
+
}));
|
|
1427
|
+
});
|
|
1428
|
+
describe('role based writes', () => {
|
|
1429
|
+
it('uses a root-level role to authorize a write', () => __awaiter(this, void 0, void 0, function* () {
|
|
1430
|
+
// scenario: Alice gives Bob a friend role. Bob invokes his
|
|
1431
|
+
// friend role in order to write a chat message
|
|
1432
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
1433
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
1434
|
+
const protocolDefinition = friendRoleProtocolDefinition;
|
|
1435
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
1436
|
+
author: alice,
|
|
1437
|
+
protocolDefinition
|
|
1438
|
+
});
|
|
1439
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
1440
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
1441
|
+
// Alice writes a 'friend' $root-level role record with Bob as recipient
|
|
1442
|
+
const friendRoleRecord = yield TestDataGenerator.generateRecordsWrite({
|
|
1443
|
+
author: alice,
|
|
1444
|
+
recipient: bob.did,
|
|
1445
|
+
protocol: protocolDefinition.protocol,
|
|
1446
|
+
protocolPath: 'friend',
|
|
1447
|
+
data: new TextEncoder().encode('Bob is my friend'),
|
|
1448
|
+
});
|
|
1449
|
+
const friendRoleReply = yield dwn.processMessage(alice.did, friendRoleRecord.message, { dataStream: friendRoleRecord.dataStream });
|
|
1450
|
+
expect(friendRoleReply.status.code).to.equal(202);
|
|
1451
|
+
// Bob writes a 'chat' record
|
|
1452
|
+
const chatRecord = yield TestDataGenerator.generateRecordsWrite({
|
|
1453
|
+
author: bob,
|
|
1454
|
+
recipient: alice.did,
|
|
1455
|
+
protocol: protocolDefinition.protocol,
|
|
1456
|
+
protocolPath: 'chat',
|
|
1457
|
+
data: new TextEncoder().encode('Bob can write this cuz he is Alices friend'),
|
|
1458
|
+
protocolRole: 'friend'
|
|
1459
|
+
});
|
|
1460
|
+
const chatReply = yield dwn.processMessage(alice.did, chatRecord.message, { dataStream: chatRecord.dataStream });
|
|
1461
|
+
expect(chatReply.status.code).to.equal(202);
|
|
1462
|
+
}));
|
|
1463
|
+
it('uses a root-level role to authorize a co-update', () => __awaiter(this, void 0, void 0, function* () {
|
|
1464
|
+
// scenario: Alice gives Bob a admin role. Bob invokes his
|
|
1465
|
+
// admin role in order to update a chat message that Alice wrote
|
|
1466
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
1467
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
1468
|
+
const protocolDefinition = friendRoleProtocolDefinition;
|
|
1469
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
1470
|
+
author: alice,
|
|
1471
|
+
protocolDefinition
|
|
1472
|
+
});
|
|
1473
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
1474
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
1475
|
+
// Alice writes a 'admin' root-level role record with Bob as recipient
|
|
1476
|
+
const friendRoleRecord = yield TestDataGenerator.generateRecordsWrite({
|
|
1477
|
+
author: alice,
|
|
1478
|
+
recipient: bob.did,
|
|
1479
|
+
protocol: protocolDefinition.protocol,
|
|
1480
|
+
protocolPath: 'admin',
|
|
1481
|
+
data: new TextEncoder().encode('Bob is my friend'),
|
|
1482
|
+
});
|
|
1483
|
+
const friendRoleReply = yield dwn.processMessage(alice.did, friendRoleRecord.message, { dataStream: friendRoleRecord.dataStream });
|
|
1484
|
+
expect(friendRoleReply.status.code).to.equal(202);
|
|
1485
|
+
// Alice creates a 'chat' record
|
|
1486
|
+
const chatRecord = yield TestDataGenerator.generateRecordsWrite({
|
|
1487
|
+
author: alice,
|
|
1488
|
+
recipient: alice.did,
|
|
1489
|
+
protocol: protocolDefinition.protocol,
|
|
1490
|
+
protocolPath: 'chat',
|
|
1491
|
+
data: new TextEncoder().encode('Bob can write this cuz he is Alices friend'),
|
|
1492
|
+
});
|
|
1493
|
+
const chatReply = yield dwn.processMessage(alice.did, chatRecord.message, { dataStream: chatRecord.dataStream });
|
|
1494
|
+
expect(chatReply.status.code).to.equal(202);
|
|
1495
|
+
// Bob invokes his admin role to update the 'chat' record
|
|
1496
|
+
const chatUpdateRecord = yield TestDataGenerator.generateFromRecordsWrite({
|
|
1497
|
+
author: bob,
|
|
1498
|
+
existingWrite: chatRecord.recordsWrite,
|
|
1499
|
+
protocolRole: 'admin',
|
|
1500
|
+
});
|
|
1501
|
+
const chatUpdateReply = yield dwn.processMessage(alice.did, chatUpdateRecord.message, { dataStream: chatUpdateRecord.dataStream });
|
|
1502
|
+
expect(chatUpdateReply.status.code).to.equal(202);
|
|
1503
|
+
}));
|
|
1504
|
+
it('rejects root-level role authorized writes if the protocolRole is not a valid protocol path to an active role record', () => __awaiter(this, void 0, void 0, function* () {
|
|
1505
|
+
// scenario: Bob tries to invoke the 'chat' role to write to Alice's DWN, but 'chat' is not a role.
|
|
1506
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
1507
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
1508
|
+
const protocolDefinition = friendRoleProtocolDefinition;
|
|
1509
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
1510
|
+
author: alice,
|
|
1511
|
+
protocolDefinition
|
|
1512
|
+
});
|
|
1513
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
1514
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
1515
|
+
// Alice writes a 'chat' record with Bob as recipient
|
|
1516
|
+
const chatRecord = yield TestDataGenerator.generateRecordsWrite({
|
|
1517
|
+
author: alice,
|
|
1518
|
+
recipient: bob.did,
|
|
1519
|
+
protocol: protocolDefinition.protocol,
|
|
1520
|
+
protocolPath: 'chat',
|
|
1521
|
+
data: new TextEncoder().encode('Blah blah blah'),
|
|
1522
|
+
});
|
|
1523
|
+
const chatReply = yield dwn.processMessage(alice.did, chatRecord.message, { dataStream: chatRecord.dataStream });
|
|
1524
|
+
expect(chatReply.status.code).to.equal(202);
|
|
1525
|
+
// Bob tries to invoke a 'chat' role but 'chat' is not a role
|
|
1526
|
+
const writeChatRecord = yield TestDataGenerator.generateRecordsWrite({
|
|
1527
|
+
author: bob,
|
|
1528
|
+
recipient: bob.did,
|
|
1529
|
+
protocol: protocolDefinition.protocol,
|
|
1530
|
+
protocolPath: 'chat',
|
|
1531
|
+
data: new TextEncoder().encode('Blah blah blah'),
|
|
1532
|
+
protocolRole: 'chat',
|
|
1533
|
+
});
|
|
1534
|
+
const chatReadReply = yield dwn.processMessage(alice.did, writeChatRecord.message, { dataStream: writeChatRecord.dataStream });
|
|
1535
|
+
expect(chatReadReply.status.code).to.equal(401);
|
|
1536
|
+
expect(chatReadReply.status.detail).to.contain(DwnErrorCode.ProtocolAuthorizationNotARole);
|
|
1537
|
+
}));
|
|
1538
|
+
it('rejects root-level role authorized writes if there is no active role for the recipient', () => __awaiter(this, void 0, void 0, function* () {
|
|
1539
|
+
// scenario: Bob tries to invoke a role to write, but he has not been given one.
|
|
1540
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
1541
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
1542
|
+
const protocolDefinition = friendRoleProtocolDefinition;
|
|
1543
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
1544
|
+
author: alice,
|
|
1545
|
+
protocolDefinition
|
|
1546
|
+
});
|
|
1547
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
1548
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
1549
|
+
// Bob writes a 'chat' record invoking a friend role that he does not have
|
|
1550
|
+
const chatRecord = yield TestDataGenerator.generateRecordsWrite({
|
|
1551
|
+
author: bob,
|
|
1552
|
+
recipient: bob.did,
|
|
1553
|
+
protocol: protocolDefinition.protocol,
|
|
1554
|
+
protocolPath: 'chat',
|
|
1555
|
+
data: new TextEncoder().encode('Blah blah blah'),
|
|
1556
|
+
protocolRole: 'friend'
|
|
1557
|
+
});
|
|
1558
|
+
const chatReply = yield dwn.processMessage(alice.did, chatRecord.message, { dataStream: chatRecord.dataStream });
|
|
1559
|
+
expect(chatReply.status.code).to.equal(401);
|
|
1560
|
+
expect(chatReply.status.detail).to.contain(DwnErrorCode.ProtocolAuthorizationMatchingRoleRecordNotFound);
|
|
1561
|
+
}));
|
|
1562
|
+
it('uses a context role to authorize a write', () => __awaiter(this, void 0, void 0, function* () {
|
|
1563
|
+
// scenario: Alice creates a thread and adds Bob to the 'thread/participant' role. Bob invokes the record to write in the thread
|
|
1564
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
1565
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
1566
|
+
const protocolDefinition = threadRoleProtocolDefinition;
|
|
1567
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
1568
|
+
author: alice,
|
|
1569
|
+
protocolDefinition
|
|
1570
|
+
});
|
|
1571
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
1572
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
1573
|
+
// Alice creates a thread
|
|
1574
|
+
const threadRecord = yield TestDataGenerator.generateRecordsWrite({
|
|
1575
|
+
author: alice,
|
|
1576
|
+
recipient: bob.did,
|
|
1577
|
+
protocol: protocolDefinition.protocol,
|
|
1578
|
+
protocolPath: 'thread'
|
|
1579
|
+
});
|
|
1580
|
+
const threadRecordReply = yield dwn.processMessage(alice.did, threadRecord.message, { dataStream: threadRecord.dataStream });
|
|
1581
|
+
expect(threadRecordReply.status.code).to.equal(202);
|
|
1582
|
+
// Alice adds Bob as a 'thread/participant' in that thread
|
|
1583
|
+
const participantRecord = yield TestDataGenerator.generateRecordsWrite({
|
|
1584
|
+
author: alice,
|
|
1585
|
+
recipient: bob.did,
|
|
1586
|
+
protocol: protocolDefinition.protocol,
|
|
1587
|
+
protocolPath: 'thread/participant',
|
|
1588
|
+
parentContextId: threadRecord.message.contextId,
|
|
1589
|
+
});
|
|
1590
|
+
const participantRecordReply = yield dwn.processMessage(alice.did, participantRecord.message, { dataStream: participantRecord.dataStream });
|
|
1591
|
+
expect(participantRecordReply.status.code).to.equal(202);
|
|
1592
|
+
// Bob invokes the role to write to the thread
|
|
1593
|
+
const chatRecord = yield TestDataGenerator.generateRecordsWrite({
|
|
1594
|
+
author: bob,
|
|
1595
|
+
protocol: protocolDefinition.protocol,
|
|
1596
|
+
protocolPath: 'thread/chat',
|
|
1597
|
+
parentContextId: threadRecord.message.contextId,
|
|
1598
|
+
protocolRole: 'thread/participant'
|
|
1599
|
+
});
|
|
1600
|
+
const chatRecordReply = yield dwn.processMessage(alice.did, chatRecord.message, { dataStream: chatRecord.dataStream });
|
|
1601
|
+
expect(chatRecordReply.status.code).to.equal(202);
|
|
1602
|
+
}));
|
|
1603
|
+
it('uses a context role to authorize a co-update', () => __awaiter(this, void 0, void 0, function* () {
|
|
1604
|
+
// scenario: Alice creates a thread and adds Bob to the 'thread/admin' role.
|
|
1605
|
+
// Bob invokes the record to write in the thread
|
|
1606
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
1607
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
1608
|
+
const protocolDefinition = threadRoleProtocolDefinition;
|
|
1609
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
1610
|
+
author: alice,
|
|
1611
|
+
protocolDefinition
|
|
1612
|
+
});
|
|
1613
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
1614
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
1615
|
+
// Alice creates a thread
|
|
1616
|
+
const threadRecord = yield TestDataGenerator.generateRecordsWrite({
|
|
1617
|
+
author: alice,
|
|
1618
|
+
recipient: bob.did,
|
|
1619
|
+
protocol: protocolDefinition.protocol,
|
|
1620
|
+
protocolPath: 'thread'
|
|
1621
|
+
});
|
|
1622
|
+
const threadRecordReply = yield dwn.processMessage(alice.did, threadRecord.message, { dataStream: threadRecord.dataStream });
|
|
1623
|
+
expect(threadRecordReply.status.code).to.equal(202);
|
|
1624
|
+
// Alice adds Bob as a 'thread/participant' in that thread
|
|
1625
|
+
const participantRecord = yield TestDataGenerator.generateRecordsWrite({
|
|
1626
|
+
author: alice,
|
|
1627
|
+
recipient: bob.did,
|
|
1628
|
+
protocol: protocolDefinition.protocol,
|
|
1629
|
+
protocolPath: 'thread/admin',
|
|
1630
|
+
parentContextId: threadRecord.message.contextId,
|
|
1631
|
+
});
|
|
1632
|
+
const participantRecordReply = yield dwn.processMessage(alice.did, participantRecord.message, { dataStream: participantRecord.dataStream });
|
|
1633
|
+
expect(participantRecordReply.status.code).to.equal(202);
|
|
1634
|
+
// Alice writes a chat message in the thread
|
|
1635
|
+
const chatRecord = yield TestDataGenerator.generateRecordsWrite({
|
|
1636
|
+
author: alice,
|
|
1637
|
+
protocol: protocolDefinition.protocol,
|
|
1638
|
+
protocolPath: 'thread/chat',
|
|
1639
|
+
parentContextId: threadRecord.message.contextId,
|
|
1640
|
+
});
|
|
1641
|
+
const chatRecordReply = yield dwn.processMessage(alice.did, chatRecord.message, { dataStream: chatRecord.dataStream });
|
|
1642
|
+
expect(chatRecordReply.status.code).to.equal(202);
|
|
1643
|
+
// Bob invokes his admin role to co-update the chat message
|
|
1644
|
+
const chatCoUpdateRecord = yield TestDataGenerator.generateFromRecordsWrite({
|
|
1645
|
+
author: bob,
|
|
1646
|
+
existingWrite: chatRecord.recordsWrite,
|
|
1647
|
+
protocolRole: 'thread/admin',
|
|
1648
|
+
});
|
|
1649
|
+
const chatUpdateRecordReply = yield dwn.processMessage(alice.did, chatCoUpdateRecord.message, { dataStream: chatCoUpdateRecord.dataStream });
|
|
1650
|
+
expect(chatUpdateRecordReply.status.code).to.equal(202);
|
|
1651
|
+
}));
|
|
1652
|
+
it('rejects context role authorized writes if the protocolRole is not a valid protocol path to an active role record', () => __awaiter(this, void 0, void 0, function* () {
|
|
1653
|
+
// scenario: Alice creates a thread and adds Bob as a participant. ALice creates another thread. Bob tries and fails to invoke his
|
|
1654
|
+
// contextRole to write a chat in the second thread
|
|
1655
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
1656
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
1657
|
+
const protocolDefinition = threadRoleProtocolDefinition;
|
|
1658
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
1659
|
+
author: alice,
|
|
1660
|
+
protocolDefinition
|
|
1661
|
+
});
|
|
1662
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
1663
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
1664
|
+
// Alice creates a thread
|
|
1665
|
+
const threadRecord1 = yield TestDataGenerator.generateRecordsWrite({
|
|
1666
|
+
author: alice,
|
|
1667
|
+
recipient: bob.did,
|
|
1668
|
+
protocol: protocolDefinition.protocol,
|
|
1669
|
+
protocolPath: 'thread'
|
|
1670
|
+
});
|
|
1671
|
+
const threadRecordReply1 = yield dwn.processMessage(alice.did, threadRecord1.message, { dataStream: threadRecord1.dataStream });
|
|
1672
|
+
expect(threadRecordReply1.status.code).to.equal(202);
|
|
1673
|
+
// Alice adds Bob as a 'thread/participant' in that thread
|
|
1674
|
+
const participantRecord = yield TestDataGenerator.generateRecordsWrite({
|
|
1675
|
+
author: alice,
|
|
1676
|
+
recipient: bob.did,
|
|
1677
|
+
protocol: protocolDefinition.protocol,
|
|
1678
|
+
protocolPath: 'thread/participant',
|
|
1679
|
+
parentContextId: threadRecord1.message.contextId,
|
|
1680
|
+
});
|
|
1681
|
+
const participantRecordReply = yield dwn.processMessage(alice.did, participantRecord.message, { dataStream: participantRecord.dataStream });
|
|
1682
|
+
expect(participantRecordReply.status.code).to.equal(202);
|
|
1683
|
+
// Alice creates a second thread
|
|
1684
|
+
const threadRecord2 = yield TestDataGenerator.generateRecordsWrite({
|
|
1685
|
+
author: alice,
|
|
1686
|
+
recipient: bob.did,
|
|
1687
|
+
protocol: protocolDefinition.protocol,
|
|
1688
|
+
protocolPath: 'thread'
|
|
1689
|
+
});
|
|
1690
|
+
const threadRecordReply2 = yield dwn.processMessage(alice.did, threadRecord2.message, { dataStream: threadRecord2.dataStream });
|
|
1691
|
+
expect(threadRecordReply2.status.code).to.equal(202);
|
|
1692
|
+
// Bob invokes his role to try to write to the second thread
|
|
1693
|
+
const chatRecord = yield TestDataGenerator.generateRecordsWrite({
|
|
1694
|
+
author: bob,
|
|
1695
|
+
protocol: protocolDefinition.protocol,
|
|
1696
|
+
protocolPath: 'thread/chat',
|
|
1697
|
+
parentContextId: threadRecord2.message.contextId,
|
|
1698
|
+
protocolRole: 'thread/participant'
|
|
1699
|
+
});
|
|
1700
|
+
const chatRecordReply = yield dwn.processMessage(alice.did, chatRecord.message, { dataStream: chatRecord.dataStream });
|
|
1701
|
+
expect(chatRecordReply.status.code).to.equal(401);
|
|
1702
|
+
expect(chatRecordReply.status.detail).to.contain(DwnErrorCode.ProtocolAuthorizationMatchingRoleRecordNotFound);
|
|
1703
|
+
}));
|
|
1704
|
+
it('rejects attempts to invoke an invalid path as a protocolRole', () => __awaiter(this, void 0, void 0, function* () {
|
|
1705
|
+
// scenario: Bob tries to invoke 'notARealPath' as a protocolRole and fails
|
|
1706
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
1707
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
1708
|
+
const protocolDefinition = threadRoleProtocolDefinition;
|
|
1709
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
1710
|
+
author: alice,
|
|
1711
|
+
protocolDefinition
|
|
1712
|
+
});
|
|
1713
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
1714
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
1715
|
+
// Bob invokes a fake protocolRole to write
|
|
1716
|
+
const fakeRoleInvocation = yield TestDataGenerator.generateRecordsWrite({
|
|
1717
|
+
author: bob,
|
|
1718
|
+
recipient: alice.did,
|
|
1719
|
+
protocol: protocolDefinition.protocol,
|
|
1720
|
+
protocolPath: 'thread',
|
|
1721
|
+
protocolRole: 'notARealPath',
|
|
1722
|
+
});
|
|
1723
|
+
const fakeRoleInvocationReply = yield dwn.processMessage(alice.did, fakeRoleInvocation.message, { dataStream: fakeRoleInvocation.dataStream });
|
|
1724
|
+
expect(fakeRoleInvocationReply.status.code).to.equal(401);
|
|
1725
|
+
expect(fakeRoleInvocationReply.status.detail).to.contain(DwnErrorCode.ProtocolAuthorizationNotARole);
|
|
1726
|
+
}));
|
|
1727
|
+
});
|
|
1728
|
+
});
|
|
1729
|
+
it('should allow updating records by the initial author', () => __awaiter(this, void 0, void 0, function* () {
|
|
1730
|
+
// scenario: Bob writes into Alice's DWN given Alice's "message" protocol allow-anyone rule, then modifies the message
|
|
1731
|
+
var _a, _b;
|
|
1732
|
+
// write a protocol definition with an allow-anyone rule
|
|
1733
|
+
const protocolDefinition = messageProtocolDefinition;
|
|
1734
|
+
const protocol = protocolDefinition.protocol;
|
|
1735
|
+
const alice = yield TestDataGenerator.generatePersona();
|
|
1736
|
+
const bob = yield TestDataGenerator.generatePersona();
|
|
1737
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
1738
|
+
author: alice,
|
|
1739
|
+
protocolDefinition
|
|
1740
|
+
});
|
|
1741
|
+
// setting up a stub DID resolver
|
|
1742
|
+
TestStubGenerator.stubDidResolver(didResolver, [alice, bob]);
|
|
1743
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
1744
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
1745
|
+
// generate a `RecordsWrite` message from bob
|
|
1746
|
+
const bobData = new TextEncoder().encode('message from bob');
|
|
1747
|
+
const messageFromBob = yield TestDataGenerator.generateRecordsWrite({
|
|
1748
|
+
author: bob,
|
|
1749
|
+
protocol,
|
|
1750
|
+
protocolPath: 'message', // this comes from `types` in protocol definition
|
|
1751
|
+
schema: protocolDefinition.types.message.schema,
|
|
1752
|
+
dataFormat: protocolDefinition.types.message.dataFormats[0],
|
|
1753
|
+
data: bobData
|
|
1754
|
+
});
|
|
1755
|
+
const bobWriteReply = yield dwn.processMessage(alice.did, messageFromBob.message, { dataStream: messageFromBob.dataStream });
|
|
1756
|
+
expect(bobWriteReply.status.code).to.equal(202);
|
|
1757
|
+
// verify bob's message got written to the DB
|
|
1758
|
+
const messageDataForQueryingBobsWrite = yield TestDataGenerator.generateRecordsQuery({
|
|
1759
|
+
author: alice,
|
|
1760
|
+
filter: { recordId: messageFromBob.message.recordId }
|
|
1761
|
+
});
|
|
1762
|
+
const bobRecordsQueryReply = yield dwn.processMessage(alice.did, messageDataForQueryingBobsWrite.message);
|
|
1763
|
+
expect(bobRecordsQueryReply.status.code).to.equal(200);
|
|
1764
|
+
expect((_a = bobRecordsQueryReply.entries) === null || _a === void 0 ? void 0 : _a.length).to.equal(1);
|
|
1765
|
+
expect(bobRecordsQueryReply.entries[0].encodedData).to.equal(base64url.baseEncode(bobData));
|
|
1766
|
+
// generate a new message from bob updating the existing message
|
|
1767
|
+
const updatedMessageBytes = Encoder.stringToBytes('updated message from bob');
|
|
1768
|
+
const updatedMessageFromBob = yield TestDataGenerator.generateFromRecordsWrite({
|
|
1769
|
+
author: bob,
|
|
1770
|
+
existingWrite: messageFromBob.recordsWrite,
|
|
1771
|
+
data: updatedMessageBytes
|
|
1772
|
+
});
|
|
1773
|
+
const newWriteReply = yield dwn.processMessage(alice.did, updatedMessageFromBob.message, { dataStream: updatedMessageFromBob.dataStream });
|
|
1774
|
+
expect(newWriteReply.status.code).to.equal(202);
|
|
1775
|
+
// verify bob's message got written to the DB
|
|
1776
|
+
const newRecordQueryReply = yield dwn.processMessage(alice.did, messageDataForQueryingBobsWrite.message);
|
|
1777
|
+
expect(newRecordQueryReply.status.code).to.equal(200);
|
|
1778
|
+
expect((_b = newRecordQueryReply.entries) === null || _b === void 0 ? void 0 : _b.length).to.equal(1);
|
|
1779
|
+
expect(newRecordQueryReply.entries[0].encodedData).to.equal(Encoder.bytesToBase64Url(updatedMessageBytes));
|
|
1780
|
+
}));
|
|
1781
|
+
it('should disallow overwriting existing records by a different author if author is not authorized to `co-update`', () => __awaiter(this, void 0, void 0, function* () {
|
|
1782
|
+
// scenario: Bob writes into Alice's DWN given Alice's "message" protocol, Carol then attempts to modify the existing message
|
|
1783
|
+
var _a;
|
|
1784
|
+
// write a protocol definition with an allow-anyone rule
|
|
1785
|
+
const protocolDefinition = messageProtocolDefinition;
|
|
1786
|
+
const protocol = protocolDefinition.protocol;
|
|
1787
|
+
const alice = yield TestDataGenerator.generatePersona();
|
|
1788
|
+
const bob = yield TestDataGenerator.generatePersona();
|
|
1789
|
+
const carol = yield TestDataGenerator.generatePersona();
|
|
1790
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
1791
|
+
author: alice,
|
|
1792
|
+
protocolDefinition
|
|
1793
|
+
});
|
|
1794
|
+
// setting up a stub DID resolver
|
|
1795
|
+
TestStubGenerator.stubDidResolver(didResolver, [alice, bob, carol]);
|
|
1796
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
1797
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
1798
|
+
// generate a `RecordsWrite` message from bob
|
|
1799
|
+
const bobData = new TextEncoder().encode('data from bob');
|
|
1800
|
+
const messageFromBob = yield TestDataGenerator.generateRecordsWrite({
|
|
1801
|
+
author: bob,
|
|
1802
|
+
protocol,
|
|
1803
|
+
protocolPath: 'message', // this comes from `types` in protocol definition
|
|
1804
|
+
schema: protocolDefinition.types.message.schema,
|
|
1805
|
+
dataFormat: protocolDefinition.types.message.dataFormats[0],
|
|
1806
|
+
data: bobData
|
|
1807
|
+
});
|
|
1808
|
+
const bobWriteReply = yield dwn.processMessage(alice.did, messageFromBob.message, { dataStream: messageFromBob.dataStream });
|
|
1809
|
+
expect(bobWriteReply.status.code).to.equal(202);
|
|
1810
|
+
// verify bob's message got written to the DB
|
|
1811
|
+
const messageDataForQueryingBobsWrite = yield TestDataGenerator.generateRecordsQuery({
|
|
1812
|
+
author: alice,
|
|
1813
|
+
filter: { recordId: messageFromBob.message.recordId }
|
|
1814
|
+
});
|
|
1815
|
+
const bobRecordsQueryReply = yield dwn.processMessage(alice.did, messageDataForQueryingBobsWrite.message);
|
|
1816
|
+
expect(bobRecordsQueryReply.status.code).to.equal(200);
|
|
1817
|
+
expect((_a = bobRecordsQueryReply.entries) === null || _a === void 0 ? void 0 : _a.length).to.equal(1);
|
|
1818
|
+
expect(bobRecordsQueryReply.entries[0].encodedData).to.equal(base64url.baseEncode(bobData));
|
|
1819
|
+
// generate a new message from carol updating the existing message, which should not be allowed/accepted
|
|
1820
|
+
const modifiedMessageData = new TextEncoder().encode('modified message by carol');
|
|
1821
|
+
const modifiedMessageFromCarol = yield TestDataGenerator.generateRecordsWrite({
|
|
1822
|
+
author: carol,
|
|
1823
|
+
protocol,
|
|
1824
|
+
protocolPath: 'message', // this comes from `types` in protocol definition
|
|
1825
|
+
schema: protocolDefinition.types.message.schema,
|
|
1826
|
+
dataFormat: protocolDefinition.types.message.dataFormats[0],
|
|
1827
|
+
data: modifiedMessageData,
|
|
1828
|
+
recordId: messageFromBob.message.recordId,
|
|
1829
|
+
});
|
|
1830
|
+
const carolWriteReply = yield dwn.processMessage(alice.did, modifiedMessageFromCarol.message, { dataStream: modifiedMessageFromCarol.dataStream });
|
|
1831
|
+
expect(carolWriteReply.status.code).to.equal(401);
|
|
1832
|
+
expect(carolWriteReply.status.detail).to.contain(DwnErrorCode.ProtocolAuthorizationActionNotAllowed);
|
|
1833
|
+
}));
|
|
1834
|
+
it('should not allow to change immutable recipient', () => __awaiter(this, void 0, void 0, function* () {
|
|
1835
|
+
// scenario: Bob writes into Alice's DWN given Alice's "message" protocol allow-anyone rule, then tries to modify immutable recipient
|
|
1836
|
+
var _a;
|
|
1837
|
+
// NOTE: no need to test the same for parent, protocol, and contextId
|
|
1838
|
+
// because changing them will result in other error conditions
|
|
1839
|
+
// write a protocol definition with an allow-anyone rule
|
|
1840
|
+
const protocolDefinition = messageProtocolDefinition;
|
|
1841
|
+
const protocol = protocolDefinition.protocol;
|
|
1842
|
+
const alice = yield TestDataGenerator.generatePersona();
|
|
1843
|
+
const bob = yield TestDataGenerator.generatePersona();
|
|
1844
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
1845
|
+
author: alice,
|
|
1846
|
+
protocolDefinition
|
|
1847
|
+
});
|
|
1848
|
+
// setting up a stub DID resolver
|
|
1849
|
+
TestStubGenerator.stubDidResolver(didResolver, [alice, bob]);
|
|
1850
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
1851
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
1852
|
+
// generate a `RecordsWrite` message from bob
|
|
1853
|
+
const bobData = new TextEncoder().encode('message from bob');
|
|
1854
|
+
const messageFromBob = yield TestDataGenerator.generateRecordsWrite({
|
|
1855
|
+
author: bob,
|
|
1856
|
+
protocol,
|
|
1857
|
+
protocolPath: 'message', // this comes from `types` in protocol definition
|
|
1858
|
+
schema: protocolDefinition.types.message.schema,
|
|
1859
|
+
dataFormat: protocolDefinition.types.message.dataFormats[0],
|
|
1860
|
+
data: bobData
|
|
1861
|
+
});
|
|
1862
|
+
const bobWriteReply = yield dwn.processMessage(alice.did, messageFromBob.message, { dataStream: messageFromBob.dataStream });
|
|
1863
|
+
expect(bobWriteReply.status.code).to.equal(202);
|
|
1864
|
+
// verify bob's message got written to the DB
|
|
1865
|
+
const messageDataForQueryingBobsWrite = yield TestDataGenerator.generateRecordsQuery({
|
|
1866
|
+
author: alice,
|
|
1867
|
+
filter: { recordId: messageFromBob.message.recordId }
|
|
1868
|
+
});
|
|
1869
|
+
const bobRecordsQueryReply = yield dwn.processMessage(alice.did, messageDataForQueryingBobsWrite.message);
|
|
1870
|
+
expect(bobRecordsQueryReply.status.code).to.equal(200);
|
|
1871
|
+
expect((_a = bobRecordsQueryReply.entries) === null || _a === void 0 ? void 0 : _a.length).to.equal(1);
|
|
1872
|
+
expect(bobRecordsQueryReply.entries[0].encodedData).to.equal(base64url.baseEncode(bobData));
|
|
1873
|
+
// generate a new message from bob changing immutable recipient
|
|
1874
|
+
const updatedMessageFromBob = yield TestDataGenerator.generateRecordsWrite({
|
|
1875
|
+
author: bob,
|
|
1876
|
+
dateCreated: messageFromBob.message.descriptor.dateCreated,
|
|
1877
|
+
protocol,
|
|
1878
|
+
protocolPath: 'message', // this comes from `types` in protocol definition
|
|
1879
|
+
schema: protocolDefinition.types.message.schema,
|
|
1880
|
+
dataFormat: protocolDefinition.types.message.dataFormats[0],
|
|
1881
|
+
data: bobData,
|
|
1882
|
+
recordId: messageFromBob.message.recordId,
|
|
1883
|
+
recipient: bob.did // this immutable property was Alice's DID initially
|
|
1884
|
+
});
|
|
1885
|
+
const newWriteReply = yield dwn.processMessage(alice.did, updatedMessageFromBob.message, { dataStream: updatedMessageFromBob.dataStream });
|
|
1886
|
+
expect(newWriteReply.status.code).to.equal(400);
|
|
1887
|
+
expect(newWriteReply.status.detail).to.contain('recipient is an immutable property');
|
|
1888
|
+
}));
|
|
1889
|
+
it('should block unauthorized write with recipient rule', () => __awaiter(this, void 0, void 0, function* () {
|
|
1890
|
+
// scenario: fake VC issuer attempts write into Alice's DWN a credential response
|
|
1891
|
+
// upon learning the ID of Alice's credential application to actual issuer
|
|
1892
|
+
const protocolDefinition = credentialIssuanceProtocolDefinition;
|
|
1893
|
+
const protocol = protocolDefinition.protocol;
|
|
1894
|
+
const credentialApplicationSchema = protocolDefinition.types.credentialApplication.schema;
|
|
1895
|
+
const credentialResponseSchema = protocolDefinition.types.credentialResponse.schema;
|
|
1896
|
+
const alice = yield TestDataGenerator.generatePersona();
|
|
1897
|
+
const fakeVcIssuer = yield TestDataGenerator.generatePersona();
|
|
1898
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
1899
|
+
author: alice,
|
|
1900
|
+
protocolDefinition
|
|
1901
|
+
});
|
|
1902
|
+
// setting up a stub DID resolver
|
|
1903
|
+
TestStubGenerator.stubDidResolver(didResolver, [alice, fakeVcIssuer]);
|
|
1904
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
1905
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
1906
|
+
// write a credential application to Alice's DWN to simulate that she has sent a credential application to a VC issuer
|
|
1907
|
+
const vcIssuer = yield TestDataGenerator.generatePersona();
|
|
1908
|
+
const encodedCredentialApplication = new TextEncoder().encode('credential application data');
|
|
1909
|
+
const credentialApplication = yield TestDataGenerator.generateRecordsWrite({
|
|
1910
|
+
author: alice,
|
|
1911
|
+
recipient: vcIssuer.did,
|
|
1912
|
+
protocol,
|
|
1913
|
+
protocolPath: 'credentialApplication', // this comes from `types` in protocol definition
|
|
1914
|
+
schema: credentialApplicationSchema,
|
|
1915
|
+
dataFormat: protocolDefinition.types.credentialApplication.dataFormats[0],
|
|
1916
|
+
data: encodedCredentialApplication
|
|
1917
|
+
});
|
|
1918
|
+
const credentialApplicationContextId = yield credentialApplication.recordsWrite.getEntryId();
|
|
1919
|
+
const credentialApplicationReply = yield dwn.processMessage(alice.did, credentialApplication.message, { dataStream: credentialApplication.dataStream });
|
|
1920
|
+
expect(credentialApplicationReply.status.code).to.equal(202);
|
|
1921
|
+
// generate a credential application response message from a fake VC issuer
|
|
1922
|
+
const encodedCredentialResponse = new TextEncoder().encode('credential response data');
|
|
1923
|
+
const credentialResponse = yield TestDataGenerator.generateRecordsWrite({
|
|
1924
|
+
author: fakeVcIssuer,
|
|
1925
|
+
recipient: alice.did,
|
|
1926
|
+
protocol,
|
|
1927
|
+
protocolPath: 'credentialApplication/credentialResponse', // this comes from `types` in protocol definition
|
|
1928
|
+
parentContextId: credentialApplicationContextId,
|
|
1929
|
+
schema: credentialResponseSchema,
|
|
1930
|
+
dataFormat: protocolDefinition.types.credentialResponse.dataFormats[0],
|
|
1931
|
+
data: encodedCredentialResponse
|
|
1932
|
+
});
|
|
1933
|
+
const credentialResponseReply = yield dwn.processMessage(alice.did, credentialResponse.message, { dataStream: credentialResponse.dataStream });
|
|
1934
|
+
expect(credentialResponseReply.status.code).to.equal(401);
|
|
1935
|
+
expect(credentialResponseReply.status.detail).to.contain(DwnErrorCode.ProtocolAuthorizationActionNotAllowed);
|
|
1936
|
+
}));
|
|
1937
|
+
it('should fail authorization if protocol definition cannot be found for a protocol-based RecordsWrite', () => __awaiter(this, void 0, void 0, function* () {
|
|
1938
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
1939
|
+
const protocol = 'nonExistentProtocol';
|
|
1940
|
+
const data = Encoder.stringToBytes('any data');
|
|
1941
|
+
const credentialApplication = yield TestDataGenerator.generateRecordsWrite({
|
|
1942
|
+
author: alice,
|
|
1943
|
+
recipient: alice.did,
|
|
1944
|
+
protocol,
|
|
1945
|
+
protocolPath: 'credentialApplication/credentialResponse', // this comes from `types` in protocol definition
|
|
1946
|
+
data
|
|
1947
|
+
});
|
|
1948
|
+
const reply = yield dwn.processMessage(alice.did, credentialApplication.message, { dataStream: credentialApplication.dataStream });
|
|
1949
|
+
expect(reply.status.code).to.equal(400);
|
|
1950
|
+
expect(reply.status.detail).to.contain('unable to find protocol definition');
|
|
1951
|
+
}));
|
|
1952
|
+
it('should fail authorization if record schema is incorrect for a protocol-based RecordsWrite', () => __awaiter(this, void 0, void 0, function* () {
|
|
1953
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
1954
|
+
const protocolDefinition = credentialIssuanceProtocolDefinition;
|
|
1955
|
+
const protocol = protocolDefinition.protocol;
|
|
1956
|
+
const protocolConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
1957
|
+
author: alice,
|
|
1958
|
+
protocolDefinition
|
|
1959
|
+
});
|
|
1960
|
+
const protocolConfigureReply = yield dwn.processMessage(alice.did, protocolConfig.message);
|
|
1961
|
+
expect(protocolConfigureReply.status.code).to.equal(202);
|
|
1962
|
+
const data = Encoder.stringToBytes('any data');
|
|
1963
|
+
const credentialApplication = yield TestDataGenerator.generateRecordsWrite({
|
|
1964
|
+
author: alice,
|
|
1965
|
+
recipient: alice.did,
|
|
1966
|
+
protocol,
|
|
1967
|
+
protocolPath: 'credentialApplication', // this comes from `types` in protocol definition
|
|
1968
|
+
schema: 'unexpectedSchema',
|
|
1969
|
+
data
|
|
1970
|
+
});
|
|
1971
|
+
const reply = yield dwn.processMessage(alice.did, credentialApplication.message, { dataStream: credentialApplication.dataStream });
|
|
1972
|
+
expect(reply.status.code).to.equal(400);
|
|
1973
|
+
expect(reply.status.detail).to.contain(DwnErrorCode.ProtocolAuthorizationInvalidSchema);
|
|
1974
|
+
}));
|
|
1975
|
+
it('should fail authorization if given `protocolPath` contains an invalid record type', () => __awaiter(this, void 0, void 0, function* () {
|
|
1976
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
1977
|
+
const protocolDefinition = credentialIssuanceProtocolDefinition;
|
|
1978
|
+
const protocol = protocolDefinition.protocol;
|
|
1979
|
+
const protocolConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
1980
|
+
author: alice,
|
|
1981
|
+
protocolDefinition
|
|
1982
|
+
});
|
|
1983
|
+
const protocolConfigureReply = yield dwn.processMessage(alice.did, protocolConfig.message);
|
|
1984
|
+
expect(protocolConfigureReply.status.code).to.equal(202);
|
|
1985
|
+
const data = Encoder.stringToBytes('any data');
|
|
1986
|
+
const credentialApplication = yield TestDataGenerator.generateRecordsWrite({
|
|
1987
|
+
author: alice,
|
|
1988
|
+
recipient: alice.did,
|
|
1989
|
+
protocol,
|
|
1990
|
+
protocolPath: 'invalidType',
|
|
1991
|
+
data
|
|
1992
|
+
});
|
|
1993
|
+
const reply = yield dwn.processMessage(alice.did, credentialApplication.message, { dataStream: credentialApplication.dataStream });
|
|
1994
|
+
expect(reply.status.code).to.equal(400);
|
|
1995
|
+
expect(reply.status.detail).to.contain(DwnErrorCode.ProtocolAuthorizationInvalidType);
|
|
1996
|
+
}));
|
|
1997
|
+
it('should fail authorization if given `protocolPath` is mismatching with actual path', () => __awaiter(this, void 0, void 0, function* () {
|
|
1998
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
1999
|
+
const protocolDefinition = credentialIssuanceProtocolDefinition;
|
|
2000
|
+
const protocol = protocolDefinition.protocol;
|
|
2001
|
+
const protocolConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
2002
|
+
author: alice,
|
|
2003
|
+
protocolDefinition,
|
|
2004
|
+
});
|
|
2005
|
+
const protocolConfigureReply = yield dwn.processMessage(alice.did, protocolConfig.message);
|
|
2006
|
+
expect(protocolConfigureReply.status.code).to.equal(202);
|
|
2007
|
+
const data = Encoder.stringToBytes('any data');
|
|
2008
|
+
const credentialApplication = yield TestDataGenerator.generateRecordsWrite({
|
|
2009
|
+
author: alice,
|
|
2010
|
+
recipient: alice.did,
|
|
2011
|
+
protocol,
|
|
2012
|
+
protocolPath: 'credentialApplication/credentialResponse', // incorrect path. correct path is `credentialResponse` because this record has no parent
|
|
2013
|
+
schema: protocolDefinition.types.credentialResponse.schema,
|
|
2014
|
+
data
|
|
2015
|
+
});
|
|
2016
|
+
const reply = yield dwn.processMessage(alice.did, credentialApplication.message, { dataStream: credentialApplication.dataStream });
|
|
2017
|
+
expect(reply.status.code).to.equal(400);
|
|
2018
|
+
expect(reply.status.detail).to.contain(DwnErrorCode.ProtocolAuthorizationParentlessIncorrectProtocolPath);
|
|
2019
|
+
expect(reply.status.detail).to.contain('is not valid for records with no parent');
|
|
2020
|
+
}));
|
|
2021
|
+
it('#690 - should only allow data format of a protocol-space record to be updated to any value allowed by the protocol configuration', () => __awaiter(this, void 0, void 0, function* () {
|
|
2022
|
+
var _a;
|
|
2023
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
2024
|
+
const protocolDefinition = socialMediaProtocolDefinition;
|
|
2025
|
+
const protocol = protocolDefinition.protocol;
|
|
2026
|
+
const protocolConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
2027
|
+
author: alice,
|
|
2028
|
+
protocolDefinition: protocolDefinition,
|
|
2029
|
+
});
|
|
2030
|
+
const protocolConfigureReply = yield dwn.processMessage(alice.did, protocolConfig.message);
|
|
2031
|
+
expect(protocolConfigureReply.status.code).to.equal(202);
|
|
2032
|
+
// write image record
|
|
2033
|
+
const data = TestDataGenerator.randomBytes(100);
|
|
2034
|
+
const imageRecordsWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
2035
|
+
author: alice,
|
|
2036
|
+
recipient: alice.did,
|
|
2037
|
+
protocol,
|
|
2038
|
+
protocolPath: 'image',
|
|
2039
|
+
schema: protocolDefinition.types.image.schema,
|
|
2040
|
+
dataFormat: protocolDefinition.types.image.dataFormats[0],
|
|
2041
|
+
data
|
|
2042
|
+
});
|
|
2043
|
+
const writeReply = yield dwn.processMessage(alice.did, imageRecordsWrite.message, { dataStream: imageRecordsWrite.dataStream });
|
|
2044
|
+
expect(writeReply.status.code).to.equal(202);
|
|
2045
|
+
// update the image to a not-allowed data format
|
|
2046
|
+
const newDataBytes = TestDataGenerator.randomBytes(100);
|
|
2047
|
+
const notAllowedUpdateWrite = yield RecordsWrite.createFrom({
|
|
2048
|
+
recordsWriteMessage: imageRecordsWrite.message,
|
|
2049
|
+
dataFormat: `not-allowed-data-format`,
|
|
2050
|
+
signer: Jws.createSigner(alice),
|
|
2051
|
+
data: newDataBytes
|
|
2052
|
+
});
|
|
2053
|
+
const newDataStream = DataStream.fromBytes(newDataBytes);
|
|
2054
|
+
const notAllowedUpdateWriteReply = yield dwn.processMessage(alice.did, notAllowedUpdateWrite.message, { dataStream: newDataStream });
|
|
2055
|
+
expect(notAllowedUpdateWriteReply.status.code).to.equal(400);
|
|
2056
|
+
expect(notAllowedUpdateWriteReply.status.detail).to.contain(DwnErrorCode.ProtocolAuthorizationIncorrectDataFormat);
|
|
2057
|
+
// update the image to a different allowed dataFormat
|
|
2058
|
+
const updateWrite = yield RecordsWrite.createFrom({
|
|
2059
|
+
recordsWriteMessage: imageRecordsWrite.message,
|
|
2060
|
+
dataFormat: protocolDefinition.types.image.dataFormats[1],
|
|
2061
|
+
signer: Jws.createSigner(alice),
|
|
2062
|
+
data: newDataBytes
|
|
2063
|
+
});
|
|
2064
|
+
const updateReply = yield dwn.processMessage(alice.did, updateWrite.message, { dataStream: newDataStream });
|
|
2065
|
+
expect(updateReply.status.code).to.equal(202);
|
|
2066
|
+
// verify the data format of the record is updated
|
|
2067
|
+
const recordsRead = yield RecordsRead.create({
|
|
2068
|
+
filter: { recordId: imageRecordsWrite.message.recordId },
|
|
2069
|
+
signer: Jws.createSigner(alice),
|
|
2070
|
+
});
|
|
2071
|
+
const recordsReadReply = yield dwn.processMessage(alice.did, recordsRead.message);
|
|
2072
|
+
expect(recordsReadReply.status.code).to.equal(200);
|
|
2073
|
+
expect((_a = recordsReadReply.entry.recordsWrite) === null || _a === void 0 ? void 0 : _a.descriptor.dataFormat).to.equal(protocolDefinition.types.image.dataFormats[1]);
|
|
2074
|
+
}));
|
|
2075
|
+
it('#690 - should allow any data format for a record if protocol definition does not explicitly specify the list of allowed data formats', () => __awaiter(this, void 0, void 0, function* () {
|
|
2076
|
+
var _a;
|
|
2077
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
2078
|
+
const protocolDefinition = minimalProtocolDefinition;
|
|
2079
|
+
const protocol = protocolDefinition.protocol;
|
|
2080
|
+
const protocolConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
2081
|
+
author: alice,
|
|
2082
|
+
protocolDefinition: protocolDefinition,
|
|
2083
|
+
});
|
|
2084
|
+
const protocolConfigureReply = yield dwn.processMessage(alice.did, protocolConfig.message);
|
|
2085
|
+
expect(protocolConfigureReply.status.code).to.equal(202);
|
|
2086
|
+
// write image record
|
|
2087
|
+
const data = TestDataGenerator.randomBytes(100);
|
|
2088
|
+
const imageRecordsWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
2089
|
+
author: alice,
|
|
2090
|
+
recipient: alice.did,
|
|
2091
|
+
protocol,
|
|
2092
|
+
protocolPath: 'foo',
|
|
2093
|
+
schema: 'any-schema',
|
|
2094
|
+
dataFormat: 'any-data-format',
|
|
2095
|
+
data
|
|
2096
|
+
});
|
|
2097
|
+
const writeReply = yield dwn.processMessage(alice.did, imageRecordsWrite.message, { dataStream: imageRecordsWrite.dataStream });
|
|
2098
|
+
expect(writeReply.status.code).to.equal(202);
|
|
2099
|
+
// update the image to a different data format
|
|
2100
|
+
const newDataFormat = 'any-new-data-format';
|
|
2101
|
+
const newDataBytes = TestDataGenerator.randomBytes(100);
|
|
2102
|
+
const updateWrite = yield RecordsWrite.createFrom({
|
|
2103
|
+
recordsWriteMessage: imageRecordsWrite.message,
|
|
2104
|
+
dataFormat: newDataFormat,
|
|
2105
|
+
signer: Jws.createSigner(alice),
|
|
2106
|
+
data: newDataBytes
|
|
2107
|
+
});
|
|
2108
|
+
const newDataStream = DataStream.fromBytes(newDataBytes);
|
|
2109
|
+
const updateReply = yield dwn.processMessage(alice.did, updateWrite.message, { dataStream: newDataStream });
|
|
2110
|
+
expect(updateReply.status.code).to.equal(202);
|
|
2111
|
+
// verify the data format of the record is updated
|
|
2112
|
+
const recordsRead = yield RecordsRead.create({
|
|
2113
|
+
filter: { recordId: imageRecordsWrite.message.recordId },
|
|
2114
|
+
signer: Jws.createSigner(alice),
|
|
2115
|
+
});
|
|
2116
|
+
const recordsReadReply = yield dwn.processMessage(alice.did, recordsRead.message);
|
|
2117
|
+
expect(recordsReadReply.status.code).to.equal(200);
|
|
2118
|
+
expect((_a = recordsReadReply.entry.recordsWrite) === null || _a === void 0 ? void 0 : _a.descriptor.dataFormat).to.equal(newDataFormat);
|
|
2119
|
+
}));
|
|
2120
|
+
it('should fail authorization if record schema is not allowed at the hierarchical level attempted for the RecordsWrite', () => __awaiter(this, void 0, void 0, function* () {
|
|
2121
|
+
// scenario: Attempt writing of records at 3 levels in the hierarchy to cover all possible cases of missing rule sets
|
|
2122
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
2123
|
+
const protocolDefinition = credentialIssuanceProtocolDefinition;
|
|
2124
|
+
const protocol = protocolDefinition.protocol;
|
|
2125
|
+
const protocolConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
2126
|
+
author: alice,
|
|
2127
|
+
protocolDefinition
|
|
2128
|
+
});
|
|
2129
|
+
const credentialApplicationSchema = protocolDefinition.types.credentialApplication.schema;
|
|
2130
|
+
const credentialResponseSchema = protocolDefinition.types.credentialResponse.schema;
|
|
2131
|
+
const protocolConfigureReply = yield dwn.processMessage(alice.did, protocolConfig.message);
|
|
2132
|
+
expect(protocolConfigureReply.status.code).to.equal(202);
|
|
2133
|
+
// Try and fail to write a 'credentialResponse', which is not allowed at the top level of the record hierarchy
|
|
2134
|
+
const data = Encoder.stringToBytes('any data');
|
|
2135
|
+
const failedCredentialResponse = yield TestDataGenerator.generateRecordsWrite({
|
|
2136
|
+
author: alice,
|
|
2137
|
+
recipient: alice.did,
|
|
2138
|
+
protocol,
|
|
2139
|
+
protocolPath: 'credentialResponse',
|
|
2140
|
+
schema: credentialResponseSchema, // this is a known schema type, but not allowed for a protocol root record
|
|
2141
|
+
data
|
|
2142
|
+
});
|
|
2143
|
+
const failedCredentialResponseReply = yield dwn.processMessage(alice.did, failedCredentialResponse.message, { dataStream: failedCredentialResponse.dataStream });
|
|
2144
|
+
expect(failedCredentialResponseReply.status.code).to.equal(400);
|
|
2145
|
+
expect(failedCredentialResponseReply.status.detail).to.contain(DwnErrorCode.ProtocolAuthorizationMissingRuleSet);
|
|
2146
|
+
// Successfully write a 'credentialApplication' at the top level of the of the record hierarchy
|
|
2147
|
+
const credentialApplication = yield TestDataGenerator.generateRecordsWrite({
|
|
2148
|
+
author: alice,
|
|
2149
|
+
recipient: alice.did,
|
|
2150
|
+
protocol,
|
|
2151
|
+
protocolPath: 'credentialApplication', // allowed at root level
|
|
2152
|
+
schema: credentialApplicationSchema,
|
|
2153
|
+
data
|
|
2154
|
+
});
|
|
2155
|
+
const credentialApplicationReply = yield dwn.processMessage(alice.did, credentialApplication.message, { dataStream: credentialApplication.dataStream });
|
|
2156
|
+
expect(credentialApplicationReply.status.code).to.equal(202);
|
|
2157
|
+
// Try and fail to write another 'credentialApplication' below the first 'credentialApplication'
|
|
2158
|
+
const failedCredentialApplication = yield TestDataGenerator.generateRecordsWrite({
|
|
2159
|
+
author: alice,
|
|
2160
|
+
recipient: alice.did,
|
|
2161
|
+
protocol,
|
|
2162
|
+
protocolPath: 'credentialApplication/credentialApplication', // credentialApplications may not be nested below another credentialApplication
|
|
2163
|
+
schema: credentialApplicationSchema,
|
|
2164
|
+
parentContextId: credentialApplication.message.contextId,
|
|
2165
|
+
data
|
|
2166
|
+
});
|
|
2167
|
+
const failedCredentialApplicationReply2 = yield dwn.processMessage(alice.did, failedCredentialApplication.message, { dataStream: failedCredentialApplication.dataStream });
|
|
2168
|
+
expect(failedCredentialApplicationReply2.status.code).to.equal(400);
|
|
2169
|
+
expect(failedCredentialApplicationReply2.status.detail).to.contain(DwnErrorCode.ProtocolAuthorizationMissingRuleSet);
|
|
2170
|
+
// Successfully write a 'credentialResponse' below the 'credentialApplication'
|
|
2171
|
+
const credentialResponse = yield TestDataGenerator.generateRecordsWrite({
|
|
2172
|
+
author: alice,
|
|
2173
|
+
recipient: alice.did,
|
|
2174
|
+
protocol,
|
|
2175
|
+
protocolPath: 'credentialApplication/credentialResponse',
|
|
2176
|
+
schema: credentialResponseSchema,
|
|
2177
|
+
parentContextId: credentialApplication.message.contextId,
|
|
2178
|
+
data
|
|
2179
|
+
});
|
|
2180
|
+
const credentialResponseReply = yield dwn.processMessage(alice.did, credentialResponse.message, { dataStream: credentialResponse.dataStream });
|
|
2181
|
+
expect(credentialResponseReply.status.code).to.equal(202);
|
|
2182
|
+
// Try and fail to write a 'credentialApplication' below 'credentialApplication/credentialResponse'
|
|
2183
|
+
// Testing case where there is no rule set for any record type at the given level in the hierarchy
|
|
2184
|
+
const nestedCredentialApplication = yield TestDataGenerator.generateRecordsWrite({
|
|
2185
|
+
author: alice,
|
|
2186
|
+
recipient: alice.did,
|
|
2187
|
+
protocol,
|
|
2188
|
+
protocolPath: 'credentialApplication/credentialResponse/credentialApplication',
|
|
2189
|
+
schema: credentialApplicationSchema,
|
|
2190
|
+
parentContextId: credentialResponse.message.contextId,
|
|
2191
|
+
data
|
|
2192
|
+
});
|
|
2193
|
+
const nestedCredentialApplicationReply = yield dwn.processMessage(alice.did, nestedCredentialApplication.message, { dataStream: nestedCredentialApplication.dataStream });
|
|
2194
|
+
expect(nestedCredentialApplicationReply.status.code).to.equal(400);
|
|
2195
|
+
expect(nestedCredentialApplicationReply.status.detail).to.contain(DwnErrorCode.ProtocolAuthorizationMissingRuleSet);
|
|
2196
|
+
}));
|
|
2197
|
+
it('should only allow DWN owner to write if record does not have an action rule defined', () => __awaiter(this, void 0, void 0, function* () {
|
|
2198
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
2199
|
+
// write a protocol definition without an explicit action rule
|
|
2200
|
+
const protocolDefinition = privateProtocol;
|
|
2201
|
+
const protocol = protocolDefinition.protocol;
|
|
2202
|
+
const protocolConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
2203
|
+
author: alice,
|
|
2204
|
+
protocolDefinition
|
|
2205
|
+
});
|
|
2206
|
+
const protocolConfigureReply = yield dwn.processMessage(alice.did, protocolConfig.message);
|
|
2207
|
+
expect(protocolConfigureReply.status.code).to.equal(202);
|
|
2208
|
+
// test that Alice is allowed to write to her own DWN
|
|
2209
|
+
const data = Encoder.stringToBytes('any data');
|
|
2210
|
+
const aliceWriteMessageData = yield TestDataGenerator.generateRecordsWrite({
|
|
2211
|
+
author: alice,
|
|
2212
|
+
recipient: alice.did,
|
|
2213
|
+
protocol,
|
|
2214
|
+
protocolPath: 'privateNote', // this comes from `types`
|
|
2215
|
+
schema: protocolDefinition.types.privateNote.schema,
|
|
2216
|
+
dataFormat: protocolDefinition.types.privateNote.dataFormats[0],
|
|
2217
|
+
data
|
|
2218
|
+
});
|
|
2219
|
+
let reply = yield dwn.processMessage(alice.did, aliceWriteMessageData.message, { dataStream: aliceWriteMessageData.dataStream });
|
|
2220
|
+
expect(reply.status.code).to.equal(202);
|
|
2221
|
+
// test that Bob is not allowed to write to Alice's DWN
|
|
2222
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
2223
|
+
const bobWriteMessageData = yield TestDataGenerator.generateRecordsWrite({
|
|
2224
|
+
author: bob,
|
|
2225
|
+
recipient: alice.did,
|
|
2226
|
+
protocol,
|
|
2227
|
+
protocolPath: 'privateNote', // this comes from `types`
|
|
2228
|
+
schema: 'private-note',
|
|
2229
|
+
dataFormat: protocolDefinition.types.privateNote.dataFormats[0],
|
|
2230
|
+
data
|
|
2231
|
+
});
|
|
2232
|
+
reply = yield dwn.processMessage(alice.did, bobWriteMessageData.message, { dataStream: bobWriteMessageData.dataStream });
|
|
2233
|
+
expect(reply.status.code).to.equal(401);
|
|
2234
|
+
expect(reply.status.detail).to.contain(DwnErrorCode.ProtocolAuthorizationActionRulesNotFound);
|
|
2235
|
+
}));
|
|
2236
|
+
it('should look up recipient path with ancestor depth of 2+ (excluding self) in action rule correctly', () => __awaiter(this, void 0, void 0, function* () {
|
|
2237
|
+
// simulate a DEX protocol with at least 3 layers of message exchange: ask -> offer -> fulfillment
|
|
2238
|
+
// make sure recipient of offer can send fulfillment
|
|
2239
|
+
var _a;
|
|
2240
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
2241
|
+
const pfi = yield TestDataGenerator.generateDidKeyPersona();
|
|
2242
|
+
// write a DEX protocol definition
|
|
2243
|
+
const protocolDefinition = dexProtocolDefinition;
|
|
2244
|
+
const protocol = protocolDefinition.protocol;
|
|
2245
|
+
// write the DEX protocol in the PFI
|
|
2246
|
+
const protocolConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
2247
|
+
author: pfi,
|
|
2248
|
+
protocolDefinition: protocolDefinition
|
|
2249
|
+
});
|
|
2250
|
+
const protocolConfigureReply = yield dwn.processMessage(pfi.did, protocolConfig.message);
|
|
2251
|
+
expect(protocolConfigureReply.status.code).to.equal(202);
|
|
2252
|
+
// simulate Alice's ask and PFI's offer already occurred
|
|
2253
|
+
const data = Encoder.stringToBytes('irrelevant');
|
|
2254
|
+
const askMessageData = yield TestDataGenerator.generateRecordsWrite({
|
|
2255
|
+
author: alice,
|
|
2256
|
+
recipient: pfi.did,
|
|
2257
|
+
schema: protocolDefinition.types.ask.schema,
|
|
2258
|
+
protocol,
|
|
2259
|
+
protocolPath: 'ask',
|
|
2260
|
+
data
|
|
2261
|
+
});
|
|
2262
|
+
let reply = yield dwn.processMessage(pfi.did, askMessageData.message, { dataStream: askMessageData.dataStream });
|
|
2263
|
+
expect(reply.status.code).to.equal(202);
|
|
2264
|
+
const offerMessageData = yield TestDataGenerator.generateRecordsWrite({
|
|
2265
|
+
author: pfi,
|
|
2266
|
+
recipient: alice.did,
|
|
2267
|
+
schema: protocolDefinition.types.offer.schema,
|
|
2268
|
+
parentContextId: askMessageData.message.contextId,
|
|
2269
|
+
protocol,
|
|
2270
|
+
protocolPath: 'ask/offer',
|
|
2271
|
+
data
|
|
2272
|
+
});
|
|
2273
|
+
reply = yield dwn.processMessage(pfi.did, offerMessageData.message, { dataStream: offerMessageData.dataStream });
|
|
2274
|
+
expect(reply.status.code).to.equal(202);
|
|
2275
|
+
// the actual test: making sure fulfillment message is accepted
|
|
2276
|
+
const fulfillmentMessageData = yield TestDataGenerator.generateRecordsWrite({
|
|
2277
|
+
author: alice,
|
|
2278
|
+
recipient: pfi.did,
|
|
2279
|
+
schema: protocolDefinition.types.fulfillment.schema,
|
|
2280
|
+
parentContextId: offerMessageData.message.contextId,
|
|
2281
|
+
protocol,
|
|
2282
|
+
protocolPath: 'ask/offer/fulfillment',
|
|
2283
|
+
data
|
|
2284
|
+
});
|
|
2285
|
+
reply = yield dwn.processMessage(pfi.did, fulfillmentMessageData.message, { dataStream: fulfillmentMessageData.dataStream });
|
|
2286
|
+
expect(reply.status.code).to.equal(202);
|
|
2287
|
+
// verify the fulfillment message is stored
|
|
2288
|
+
const recordsQueryMessageData = yield TestDataGenerator.generateRecordsQuery({
|
|
2289
|
+
author: pfi,
|
|
2290
|
+
filter: { recordId: fulfillmentMessageData.message.recordId }
|
|
2291
|
+
});
|
|
2292
|
+
// verify the data is written
|
|
2293
|
+
const recordsQueryReply = yield dwn.processMessage(pfi.did, recordsQueryMessageData.message);
|
|
2294
|
+
expect(recordsQueryReply.status.code).to.equal(200);
|
|
2295
|
+
expect((_a = recordsQueryReply.entries) === null || _a === void 0 ? void 0 : _a.length).to.equal(1);
|
|
2296
|
+
expect(recordsQueryReply.entries[0].descriptor.dataCid).to.equal(fulfillmentMessageData.message.descriptor.dataCid);
|
|
2297
|
+
}));
|
|
2298
|
+
it('should fail authorization if incoming message contains `parentId` that leads to no record', () => __awaiter(this, void 0, void 0, function* () {
|
|
2299
|
+
// 1. DEX protocol with at least 3 layers of message exchange: ask -> offer -> fulfillment
|
|
2300
|
+
// 2. Alice sends an ask to a PFI
|
|
2301
|
+
// 3. Alice sends a fulfillment to an non-existent offer to the PFI
|
|
2302
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
2303
|
+
const pfi = yield TestDataGenerator.generateDidKeyPersona();
|
|
2304
|
+
// write a DEX protocol definition
|
|
2305
|
+
const protocolDefinition = dexProtocolDefinition;
|
|
2306
|
+
const protocol = protocolDefinition.protocol;
|
|
2307
|
+
// write the DEX protocol in the PFI
|
|
2308
|
+
const protocolConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
2309
|
+
author: pfi,
|
|
2310
|
+
protocolDefinition: protocolDefinition
|
|
2311
|
+
});
|
|
2312
|
+
const protocolConfigureReply = yield dwn.processMessage(pfi.did, protocolConfig.message);
|
|
2313
|
+
expect(protocolConfigureReply.status.code).to.equal(202);
|
|
2314
|
+
// simulate Alice's ask
|
|
2315
|
+
const data = Encoder.stringToBytes('irrelevant');
|
|
2316
|
+
const askMessageData = yield TestDataGenerator.generateRecordsWrite({
|
|
2317
|
+
author: alice,
|
|
2318
|
+
recipient: pfi.did,
|
|
2319
|
+
schema: protocolDefinition.types.ask.schema,
|
|
2320
|
+
protocol,
|
|
2321
|
+
protocolPath: 'ask',
|
|
2322
|
+
data
|
|
2323
|
+
});
|
|
2324
|
+
let reply = yield dwn.processMessage(pfi.did, askMessageData.message, { dataStream: askMessageData.dataStream });
|
|
2325
|
+
expect(reply.status.code).to.equal(202);
|
|
2326
|
+
// the actual test: making sure fulfillment message fails
|
|
2327
|
+
const fulfillmentMessageData = yield TestDataGenerator.generateRecordsWrite({
|
|
2328
|
+
author: alice,
|
|
2329
|
+
recipient: pfi.did,
|
|
2330
|
+
schema: protocolDefinition.types.fulfillment.schema,
|
|
2331
|
+
parentContextId: 'nonExistentId', // NOTE: this will point to a non-existent parent
|
|
2332
|
+
protocolPath: 'ask/offer/fulfillment',
|
|
2333
|
+
protocol,
|
|
2334
|
+
data
|
|
2335
|
+
});
|
|
2336
|
+
reply = yield dwn.processMessage(pfi.did, fulfillmentMessageData.message, { dataStream: fulfillmentMessageData.dataStream });
|
|
2337
|
+
expect(reply.status.code).to.equal(400);
|
|
2338
|
+
expect(reply.status.detail).to.contain(DwnErrorCode.ProtocolAuthorizationIncorrectProtocolPath);
|
|
2339
|
+
}));
|
|
2340
|
+
it('should 400 if expected CID of `encryption` mismatches the `encryptionCid` in `authorization`', () => __awaiter(this, void 0, void 0, function* () {
|
|
2341
|
+
const alice = yield TestDataGenerator.generatePersona();
|
|
2342
|
+
TestStubGenerator.stubDidResolver(didResolver, [alice]);
|
|
2343
|
+
// configure protocol
|
|
2344
|
+
const protocolDefinition = emailProtocolDefinition;
|
|
2345
|
+
const protocol = protocolDefinition.protocol;
|
|
2346
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
2347
|
+
author: alice,
|
|
2348
|
+
protocolDefinition
|
|
2349
|
+
});
|
|
2350
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
2351
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
2352
|
+
const bobMessageBytes = Encoder.stringToBytes('message from bob');
|
|
2353
|
+
const bobMessageStream = DataStream.fromBytes(bobMessageBytes);
|
|
2354
|
+
const dataEncryptionInitializationVector = TestDataGenerator.randomBytes(16);
|
|
2355
|
+
const dataEncryptionKey = TestDataGenerator.randomBytes(32);
|
|
2356
|
+
const bobMessageEncryptedStream = yield Encryption.aes256CtrEncrypt(dataEncryptionKey, dataEncryptionInitializationVector, bobMessageStream);
|
|
2357
|
+
const bobMessageEncryptedBytes = yield DataStream.toBytes(bobMessageEncryptedStream);
|
|
2358
|
+
const encryptionInput = {
|
|
2359
|
+
algorithm: EncryptionAlgorithm.Aes256Ctr,
|
|
2360
|
+
initializationVector: dataEncryptionInitializationVector,
|
|
2361
|
+
key: dataEncryptionKey,
|
|
2362
|
+
keyEncryptionInputs: [{
|
|
2363
|
+
publicKeyId: alice.keyId, // reusing signing key for encryption purely as a convenience
|
|
2364
|
+
publicKey: alice.keyPair.publicJwk,
|
|
2365
|
+
algorithm: EncryptionAlgorithm.EciesSecp256k1,
|
|
2366
|
+
derivationScheme: KeyDerivationScheme.ProtocolPath
|
|
2367
|
+
}]
|
|
2368
|
+
};
|
|
2369
|
+
const { message, dataStream } = yield TestDataGenerator.generateRecordsWrite({
|
|
2370
|
+
author: alice,
|
|
2371
|
+
protocol,
|
|
2372
|
+
protocolPath: 'email',
|
|
2373
|
+
schema: 'email',
|
|
2374
|
+
data: bobMessageEncryptedBytes,
|
|
2375
|
+
encryptionInput
|
|
2376
|
+
});
|
|
2377
|
+
// replace valid `encryption` property with a mismatching one
|
|
2378
|
+
message.encryption.initializationVector = Encoder.stringToBase64Url('any value which will result in a different CID');
|
|
2379
|
+
const recordsWriteHandler = new RecordsWriteHandler(didResolver, messageStore, dataStore, eventLog, eventStream);
|
|
2380
|
+
const writeReply = yield recordsWriteHandler.handle({ tenant: alice.did, message, dataStream: dataStream });
|
|
2381
|
+
expect(writeReply.status.code).to.equal(400);
|
|
2382
|
+
expect(writeReply.status.detail).to.contain(DwnErrorCode.RecordsWriteValidateIntegrityEncryptionCidMismatch);
|
|
2383
|
+
}));
|
|
2384
|
+
it('should return 400 if protocol is not normalized', () => __awaiter(this, void 0, void 0, function* () {
|
|
2385
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
2386
|
+
const protocolDefinition = emailProtocolDefinition;
|
|
2387
|
+
// write a message into DB
|
|
2388
|
+
const recordsWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
2389
|
+
author: alice,
|
|
2390
|
+
data: new TextEncoder().encode('data1'),
|
|
2391
|
+
protocol: 'example.com/',
|
|
2392
|
+
protocolPath: 'email', // from email protocol
|
|
2393
|
+
schema: protocolDefinition.types.email.schema
|
|
2394
|
+
});
|
|
2395
|
+
// overwrite protocol because #create auto-normalizes protocol
|
|
2396
|
+
recordsWrite.message.descriptor.protocol = 'example.com/';
|
|
2397
|
+
// Re-create auth because we altered the descriptor after signing
|
|
2398
|
+
const descriptorCid = yield Cid.computeCid(recordsWrite.message.descriptor);
|
|
2399
|
+
const attestation = yield RecordsWrite.createAttestation(descriptorCid);
|
|
2400
|
+
const signature = yield RecordsWrite.createSignerSignature({
|
|
2401
|
+
recordId: recordsWrite.message.recordId,
|
|
2402
|
+
contextId: recordsWrite.message.contextId,
|
|
2403
|
+
descriptorCid,
|
|
2404
|
+
attestation,
|
|
2405
|
+
encryption: recordsWrite.message.encryption,
|
|
2406
|
+
signer: Jws.createSigner(alice)
|
|
2407
|
+
});
|
|
2408
|
+
recordsWrite.message = Object.assign(Object.assign({}, recordsWrite.message), { attestation, authorization: { signature } });
|
|
2409
|
+
// Send records write message
|
|
2410
|
+
const reply = yield dwn.processMessage(alice.did, recordsWrite.message, { dataStream: recordsWrite.dataStream });
|
|
2411
|
+
expect(reply.status.code).to.equal(400);
|
|
2412
|
+
expect(reply.status.detail).to.contain(DwnErrorCode.UrlProtocolNotNormalized);
|
|
2413
|
+
}));
|
|
2414
|
+
it('#359 - should not allow access of data by referencing `dataCid` in protocol authorized `RecordsWrite`', () => __awaiter(this, void 0, void 0, function* () {
|
|
2415
|
+
var _a, _b, _c;
|
|
2416
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
2417
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
2418
|
+
// alice writes a private record
|
|
2419
|
+
const dataString = TestDataGenerator.randomString(DwnConstant.maxDataSizeAllowedToBeEncoded);
|
|
2420
|
+
const dataSize = dataString.length;
|
|
2421
|
+
const data = Encoder.stringToBytes(dataString);
|
|
2422
|
+
const dataCid = yield Cid.computeDagPbCidFromBytes(data);
|
|
2423
|
+
const { message, dataStream } = yield TestDataGenerator.generateRecordsWrite({
|
|
2424
|
+
author: alice,
|
|
2425
|
+
data,
|
|
2426
|
+
});
|
|
2427
|
+
const reply = yield dwn.processMessage(alice.did, message, { dataStream });
|
|
2428
|
+
expect(reply.status.code).to.equal(202);
|
|
2429
|
+
const protocolDefinition = socialMediaProtocolDefinition;
|
|
2430
|
+
const protocol = protocolDefinition.protocol;
|
|
2431
|
+
// alice has a social media protocol that allows anyone to write and read images
|
|
2432
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
2433
|
+
author: alice,
|
|
2434
|
+
protocolDefinition
|
|
2435
|
+
});
|
|
2436
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
2437
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
2438
|
+
// bob learns of metadata (ie. dataCid) of alice's secret data,
|
|
2439
|
+
// attempts to gain unauthorized access by writing to alice's DWN through open protocol referencing the dataCid without supplying the data
|
|
2440
|
+
// which he is allowed to do, the DWN will treat the operation as an initial-write or a record that has a later and different state.
|
|
2441
|
+
const imageRecordsWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
2442
|
+
author: bob,
|
|
2443
|
+
protocol,
|
|
2444
|
+
protocolPath: 'image',
|
|
2445
|
+
schema: protocolDefinition.types.image.schema,
|
|
2446
|
+
dataFormat: 'image/jpeg',
|
|
2447
|
+
dataCid, // bob learns of, and references alice's secrete data's CID
|
|
2448
|
+
dataSize,
|
|
2449
|
+
recipient: alice.did
|
|
2450
|
+
});
|
|
2451
|
+
const imageReply = yield dwn.processMessage(alice.did, imageRecordsWrite.message);
|
|
2452
|
+
expect(imageReply.status.code).to.equal(204); // allows write but is not readable or queryable
|
|
2453
|
+
// verify the record is not able to be read
|
|
2454
|
+
const bobRecordsReadData = yield RecordsRead.create({
|
|
2455
|
+
filter: {
|
|
2456
|
+
recordId: imageRecordsWrite.message.recordId,
|
|
2457
|
+
},
|
|
2458
|
+
signer: Jws.createSigner(bob)
|
|
2459
|
+
});
|
|
2460
|
+
const bobRecordsReadReply = yield dwn.processMessage(alice.did, bobRecordsReadData.message);
|
|
2461
|
+
expect(bobRecordsReadReply.status.code).to.equal(404);
|
|
2462
|
+
// verify the record is not part of a query
|
|
2463
|
+
const bobRecordsQuery = yield RecordsQuery.create({
|
|
2464
|
+
filter: {
|
|
2465
|
+
schema: protocolDefinition.types.image.schema,
|
|
2466
|
+
},
|
|
2467
|
+
signer: Jws.createSigner(bob)
|
|
2468
|
+
});
|
|
2469
|
+
const bobRecordsQueryReply = yield dwn.processMessage(alice.did, bobRecordsQuery.message);
|
|
2470
|
+
expect(bobRecordsQueryReply.status.code).to.equal(200);
|
|
2471
|
+
expect((_a = bobRecordsQueryReply.entries) === null || _a === void 0 ? void 0 : _a.length).to.equal(0);
|
|
2472
|
+
//further sanity query for specific recordId
|
|
2473
|
+
const bobRecordsQueryRecordId = yield RecordsQuery.create({
|
|
2474
|
+
filter: {
|
|
2475
|
+
recordId: imageRecordsWrite.message.recordId,
|
|
2476
|
+
},
|
|
2477
|
+
signer: Jws.createSigner(bob)
|
|
2478
|
+
});
|
|
2479
|
+
const bobRecordsQueryRecordIdReply = yield dwn.processMessage(alice.did, bobRecordsQueryRecordId.message);
|
|
2480
|
+
expect(bobRecordsQueryRecordIdReply.status.code).to.equal(200);
|
|
2481
|
+
expect((_b = bobRecordsQueryRecordIdReply.entries) === null || _b === void 0 ? void 0 : _b.length).to.equal(0);
|
|
2482
|
+
// attempt update recordsWrite without data, this will reject
|
|
2483
|
+
const updateRecord = yield RecordsWrite.createFrom({
|
|
2484
|
+
recordsWriteMessage: imageRecordsWrite.message,
|
|
2485
|
+
signer: Jws.createSigner(bob),
|
|
2486
|
+
published: true,
|
|
2487
|
+
});
|
|
2488
|
+
const updateRecordReply = yield dwn.processMessage(alice.did, updateRecord.message);
|
|
2489
|
+
expect(updateRecordReply.status.code).to.equal(400);
|
|
2490
|
+
expect(updateRecordReply.status.detail).to.include(DwnErrorCode.RecordsWriteMissingEncodedDataInPrevious);
|
|
2491
|
+
// sanity still can't query
|
|
2492
|
+
const bobRecordsQueryReply2 = yield dwn.processMessage(alice.did, bobRecordsQuery.message);
|
|
2493
|
+
expect(bobRecordsQueryReply2.status.code).to.equal(200);
|
|
2494
|
+
expect((_c = bobRecordsQueryReply2.entries) === null || _c === void 0 ? void 0 : _c.length).to.equal(0);
|
|
2495
|
+
}));
|
|
2496
|
+
it('#359 - should not allow access of data by referencing `dataCid` in protocol authorized `RecordsWrite` with large data', () => __awaiter(this, void 0, void 0, function* () {
|
|
2497
|
+
var _a, _b, _c;
|
|
2498
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
2499
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
2500
|
+
// alice writes a private record
|
|
2501
|
+
const dataString = TestDataGenerator.randomString(DwnConstant.maxDataSizeAllowedToBeEncoded + 1);
|
|
2502
|
+
const dataSize = dataString.length;
|
|
2503
|
+
const data = Encoder.stringToBytes(dataString);
|
|
2504
|
+
const dataCid = yield Cid.computeDagPbCidFromBytes(data);
|
|
2505
|
+
const { message, dataStream } = yield TestDataGenerator.generateRecordsWrite({
|
|
2506
|
+
author: alice,
|
|
2507
|
+
data,
|
|
2508
|
+
});
|
|
2509
|
+
const reply = yield dwn.processMessage(alice.did, message, { dataStream });
|
|
2510
|
+
expect(reply.status.code).to.equal(202);
|
|
2511
|
+
const protocolDefinition = socialMediaProtocolDefinition;
|
|
2512
|
+
const protocol = protocolDefinition.protocol;
|
|
2513
|
+
// alice has a social media protocol that allows anyone to write and read images
|
|
2514
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
2515
|
+
author: alice,
|
|
2516
|
+
protocolDefinition
|
|
2517
|
+
});
|
|
2518
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
2519
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
2520
|
+
// bob learns of metadata (ie. dataCid) of alice's secret data,
|
|
2521
|
+
// attempts to gain unauthorized access by writing to alice's DWN through open protocol referencing the dataCid without supplying the data
|
|
2522
|
+
// which he is allowed to do, the DWN will treat the operation as an initial-write or a record that has a later and different state.
|
|
2523
|
+
const imageRecordsWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
2524
|
+
author: bob,
|
|
2525
|
+
protocol,
|
|
2526
|
+
protocolPath: 'image',
|
|
2527
|
+
schema: protocolDefinition.types.image.schema,
|
|
2528
|
+
dataFormat: 'image/jpeg',
|
|
2529
|
+
dataCid, // bob learns of, and references alice's secrete data's CID
|
|
2530
|
+
dataSize,
|
|
2531
|
+
recipient: alice.did
|
|
2532
|
+
});
|
|
2533
|
+
const imageReply = yield dwn.processMessage(alice.did, imageRecordsWrite.message);
|
|
2534
|
+
expect(imageReply.status.code).to.equal(204); // allows write but is not readable or queryable
|
|
2535
|
+
// verify the record is not able to be read
|
|
2536
|
+
const bobRecordsReadData = yield RecordsRead.create({
|
|
2537
|
+
filter: {
|
|
2538
|
+
recordId: imageRecordsWrite.message.recordId,
|
|
2539
|
+
},
|
|
2540
|
+
signer: Jws.createSigner(bob)
|
|
2541
|
+
});
|
|
2542
|
+
const bobRecordsReadReply = yield dwn.processMessage(alice.did, bobRecordsReadData.message);
|
|
2543
|
+
expect(bobRecordsReadReply.status.code).to.equal(404);
|
|
2544
|
+
// verify the record is not part of a query
|
|
2545
|
+
const bobRecordsQuery = yield RecordsQuery.create({
|
|
2546
|
+
filter: {
|
|
2547
|
+
schema: protocolDefinition.types.image.schema,
|
|
2548
|
+
},
|
|
2549
|
+
signer: Jws.createSigner(bob)
|
|
2550
|
+
});
|
|
2551
|
+
const bobRecordsQueryReply = yield dwn.processMessage(alice.did, bobRecordsQuery.message);
|
|
2552
|
+
expect(bobRecordsQueryReply.status.code).to.equal(200);
|
|
2553
|
+
expect((_a = bobRecordsQueryReply.entries) === null || _a === void 0 ? void 0 : _a.length).to.equal(0);
|
|
2554
|
+
//further sanity query for specific recordId
|
|
2555
|
+
const bobRecordsQueryRecordId = yield RecordsQuery.create({
|
|
2556
|
+
filter: {
|
|
2557
|
+
recordId: imageRecordsWrite.message.recordId,
|
|
2558
|
+
},
|
|
2559
|
+
signer: Jws.createSigner(bob)
|
|
2560
|
+
});
|
|
2561
|
+
const bobRecordsQueryRecordIdReply = yield dwn.processMessage(alice.did, bobRecordsQueryRecordId.message);
|
|
2562
|
+
expect(bobRecordsQueryRecordIdReply.status.code).to.equal(200);
|
|
2563
|
+
expect((_b = bobRecordsQueryRecordIdReply.entries) === null || _b === void 0 ? void 0 : _b.length).to.equal(0);
|
|
2564
|
+
// attempt update recordsWrite without data, this will reject
|
|
2565
|
+
const updateRecord = yield RecordsWrite.createFrom({
|
|
2566
|
+
recordsWriteMessage: imageRecordsWrite.message,
|
|
2567
|
+
signer: Jws.createSigner(bob),
|
|
2568
|
+
published: true,
|
|
2569
|
+
});
|
|
2570
|
+
const updateRecordReply = yield dwn.processMessage(alice.did, updateRecord.message);
|
|
2571
|
+
expect(updateRecordReply.status.code).to.equal(400);
|
|
2572
|
+
expect(updateRecordReply.status.detail).to.include(DwnErrorCode.RecordsWriteMissingDataInPrevious);
|
|
2573
|
+
// sanity still can't query
|
|
2574
|
+
const bobRecordsQueryReply2 = yield dwn.processMessage(alice.did, bobRecordsQuery.message);
|
|
2575
|
+
expect(bobRecordsQueryReply2.status.code).to.equal(200);
|
|
2576
|
+
expect((_c = bobRecordsQueryReply2.entries) === null || _c === void 0 ? void 0 : _c.length).to.equal(0);
|
|
2577
|
+
}));
|
|
2578
|
+
it('should allow record with or without schema if protocol does not require schema for a record type', () => __awaiter(this, void 0, void 0, function* () {
|
|
2579
|
+
// scenario: Alice's DWN has a protocol that allows anyone to write a record without schema
|
|
2580
|
+
var _a;
|
|
2581
|
+
// write a protocol definition that has a record type without schema
|
|
2582
|
+
const protocolDefinition = anyoneCollaborateProtocolDefinition;
|
|
2583
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
2584
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
2585
|
+
author: alice,
|
|
2586
|
+
protocolDefinition
|
|
2587
|
+
});
|
|
2588
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
2589
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
2590
|
+
// write a `RecordsWrite` message without schema
|
|
2591
|
+
const data = TestDataGenerator.randomBytes(100);
|
|
2592
|
+
const dataStream = DataStream.fromBytes(data);
|
|
2593
|
+
const docWrite = yield RecordsWrite.create({
|
|
2594
|
+
protocol: protocolDefinition.protocol,
|
|
2595
|
+
protocolPath: 'doc',
|
|
2596
|
+
dataFormat: 'application/octet-stream',
|
|
2597
|
+
data,
|
|
2598
|
+
signer: Jws.createSigner(alice)
|
|
2599
|
+
});
|
|
2600
|
+
const writeReply = yield dwn.processMessage(alice.did, docWrite.message, { dataStream });
|
|
2601
|
+
expect(writeReply.status.code).to.equal(202);
|
|
2602
|
+
// write a `RecordsWrite` message with schema
|
|
2603
|
+
const data2 = TestDataGenerator.randomBytes(100);
|
|
2604
|
+
const data2Stream = DataStream.fromBytes(data2);
|
|
2605
|
+
const doc2Write = yield RecordsWrite.create({
|
|
2606
|
+
protocol: protocolDefinition.protocol,
|
|
2607
|
+
protocolPath: 'doc',
|
|
2608
|
+
schema: TestDataGenerator.randomString(10),
|
|
2609
|
+
dataFormat: 'application/octet-stream',
|
|
2610
|
+
data: data2,
|
|
2611
|
+
signer: Jws.createSigner(alice)
|
|
2612
|
+
});
|
|
2613
|
+
const write2Reply = yield dwn.processMessage(alice.did, doc2Write.message, { dataStream: data2Stream });
|
|
2614
|
+
expect(write2Reply.status.code).to.equal(202);
|
|
2615
|
+
// verify messages got written to the DB
|
|
2616
|
+
const recordsQuery = yield RecordsQuery.create({
|
|
2617
|
+
filter: { protocolPath: 'doc' },
|
|
2618
|
+
signer: Jws.createSigner(alice)
|
|
2619
|
+
});
|
|
2620
|
+
const recordsReadReply = yield dwn.processMessage(alice.did, recordsQuery.message);
|
|
2621
|
+
expect(recordsReadReply.status.code).to.equal(200);
|
|
2622
|
+
expect((_a = recordsReadReply.entries) === null || _a === void 0 ? void 0 : _a.length).to.equal(2);
|
|
2623
|
+
}));
|
|
2624
|
+
it('should allow authorization if protocol message size is within min and max size', () => __awaiter(this, void 0, void 0, function* () {
|
|
2625
|
+
const alice = yield TestDataGenerator.generatePersona();
|
|
2626
|
+
TestStubGenerator.stubDidResolver(didResolver, [alice]);
|
|
2627
|
+
const protocolDefinition = {
|
|
2628
|
+
protocol: 'http://blob-size.xyz',
|
|
2629
|
+
published: true,
|
|
2630
|
+
types: {
|
|
2631
|
+
blob: {}
|
|
2632
|
+
},
|
|
2633
|
+
structure: {
|
|
2634
|
+
blob: {
|
|
2635
|
+
$size: {
|
|
2636
|
+
min: 1,
|
|
2637
|
+
max: 1000
|
|
2638
|
+
}
|
|
2639
|
+
}
|
|
2640
|
+
}
|
|
2641
|
+
};
|
|
2642
|
+
const protocol = protocolDefinition.protocol;
|
|
2643
|
+
const protocolConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
2644
|
+
author: alice,
|
|
2645
|
+
protocolDefinition,
|
|
2646
|
+
});
|
|
2647
|
+
const protocolConfigureReply = yield dwn.processMessage(alice.did, protocolConfig.message);
|
|
2648
|
+
expect(protocolConfigureReply.status.code).to.equal(202);
|
|
2649
|
+
// test min record size
|
|
2650
|
+
const data = TestDataGenerator.randomBytes(1);
|
|
2651
|
+
const testRecord = yield TestDataGenerator.generateRecordsWrite({
|
|
2652
|
+
author: alice,
|
|
2653
|
+
recipient: alice.did,
|
|
2654
|
+
protocol,
|
|
2655
|
+
protocolPath: 'blob',
|
|
2656
|
+
data
|
|
2657
|
+
});
|
|
2658
|
+
const reply = yield dwn.processMessage(alice.did, testRecord.message, { dataStream: testRecord.dataStream });
|
|
2659
|
+
expect(reply.status.code).to.equal(202);
|
|
2660
|
+
// test max record size
|
|
2661
|
+
const data2 = TestDataGenerator.randomBytes(1000);
|
|
2662
|
+
const testRecord2 = yield TestDataGenerator.generateRecordsWrite({
|
|
2663
|
+
author: alice,
|
|
2664
|
+
recipient: alice.did,
|
|
2665
|
+
protocol,
|
|
2666
|
+
protocolPath: 'blob',
|
|
2667
|
+
data: data2
|
|
2668
|
+
});
|
|
2669
|
+
const reply2 = yield dwn.processMessage(alice.did, testRecord2.message, { dataStream: testRecord2.dataStream });
|
|
2670
|
+
expect(reply2.status.code).to.equal(202);
|
|
2671
|
+
// test beyond max size
|
|
2672
|
+
const data3 = TestDataGenerator.randomBytes(1001);
|
|
2673
|
+
const testRecord3 = yield TestDataGenerator.generateRecordsWrite({
|
|
2674
|
+
author: alice,
|
|
2675
|
+
recipient: alice.did,
|
|
2676
|
+
protocol,
|
|
2677
|
+
protocolPath: 'blob',
|
|
2678
|
+
data: data3
|
|
2679
|
+
});
|
|
2680
|
+
const reply3 = yield dwn.processMessage(alice.did, testRecord3.message, { dataStream: testRecord3.dataStream });
|
|
2681
|
+
expect(reply3.status.code).to.equal(400);
|
|
2682
|
+
expect(reply3.status.detail).to.contain(DwnErrorCode.ProtocolAuthorizationMaxSizeInvalid);
|
|
2683
|
+
}));
|
|
2684
|
+
it('should fail authorization if protocol message size is less than specified minimum size', () => __awaiter(this, void 0, void 0, function* () {
|
|
2685
|
+
const alice = yield TestDataGenerator.generatePersona();
|
|
2686
|
+
TestStubGenerator.stubDidResolver(didResolver, [alice]);
|
|
2687
|
+
const protocolDefinition = {
|
|
2688
|
+
protocol: 'http://blob-size.xyz',
|
|
2689
|
+
published: true,
|
|
2690
|
+
types: {
|
|
2691
|
+
blob: {}
|
|
2692
|
+
},
|
|
2693
|
+
structure: {
|
|
2694
|
+
blob: {
|
|
2695
|
+
$size: {
|
|
2696
|
+
min: 1000
|
|
2697
|
+
}
|
|
2698
|
+
}
|
|
2699
|
+
}
|
|
2700
|
+
};
|
|
2701
|
+
const protocol = protocolDefinition.protocol;
|
|
2702
|
+
const protocolConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
2703
|
+
author: alice,
|
|
2704
|
+
protocolDefinition,
|
|
2705
|
+
});
|
|
2706
|
+
const protocolConfigureReply = yield dwn.processMessage(alice.did, protocolConfig.message);
|
|
2707
|
+
expect(protocolConfigureReply.status.code).to.equal(202);
|
|
2708
|
+
const data = TestDataGenerator.randomBytes(999);
|
|
2709
|
+
const testRecord = yield TestDataGenerator.generateRecordsWrite({
|
|
2710
|
+
author: alice,
|
|
2711
|
+
recipient: alice.did,
|
|
2712
|
+
protocol,
|
|
2713
|
+
protocolPath: 'blob',
|
|
2714
|
+
data
|
|
2715
|
+
});
|
|
2716
|
+
const reply = yield dwn.processMessage(alice.did, testRecord.message, { dataStream: testRecord.dataStream });
|
|
2717
|
+
expect(reply.status.code).to.equal(400);
|
|
2718
|
+
expect(reply.status.detail).to.contain(DwnErrorCode.ProtocolAuthorizationMinSizeInvalid);
|
|
2719
|
+
// test valid min record size
|
|
2720
|
+
const data2 = TestDataGenerator.randomBytes(1000);
|
|
2721
|
+
const testRecord2 = yield TestDataGenerator.generateRecordsWrite({
|
|
2722
|
+
author: alice,
|
|
2723
|
+
recipient: alice.did,
|
|
2724
|
+
protocol,
|
|
2725
|
+
protocolPath: 'blob',
|
|
2726
|
+
data: data2
|
|
2727
|
+
});
|
|
2728
|
+
const reply2 = yield dwn.processMessage(alice.did, testRecord2.message, { dataStream: testRecord2.dataStream });
|
|
2729
|
+
expect(reply2.status.code).to.equal(202);
|
|
2730
|
+
}));
|
|
2731
|
+
it('should fail authorization if protocol message size is more than specified maximum size', () => __awaiter(this, void 0, void 0, function* () {
|
|
2732
|
+
const alice = yield TestDataGenerator.generatePersona();
|
|
2733
|
+
TestStubGenerator.stubDidResolver(didResolver, [alice]);
|
|
2734
|
+
const protocolDefinition = {
|
|
2735
|
+
protocol: 'http://blob-size.xyz',
|
|
2736
|
+
published: true,
|
|
2737
|
+
types: {
|
|
2738
|
+
blob: {}
|
|
2739
|
+
},
|
|
2740
|
+
structure: {
|
|
2741
|
+
blob: {
|
|
2742
|
+
$size: {
|
|
2743
|
+
max: 1000
|
|
2744
|
+
}
|
|
2745
|
+
}
|
|
2746
|
+
}
|
|
2747
|
+
};
|
|
2748
|
+
const protocol = protocolDefinition.protocol;
|
|
2749
|
+
const protocolConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
2750
|
+
author: alice,
|
|
2751
|
+
protocolDefinition,
|
|
2752
|
+
});
|
|
2753
|
+
const protocolConfigureReply = yield dwn.processMessage(alice.did, protocolConfig.message);
|
|
2754
|
+
expect(protocolConfigureReply.status.code).to.equal(202);
|
|
2755
|
+
const data = TestDataGenerator.randomBytes(1001);
|
|
2756
|
+
const testRecord = yield TestDataGenerator.generateRecordsWrite({
|
|
2757
|
+
author: alice,
|
|
2758
|
+
recipient: alice.did,
|
|
2759
|
+
protocol,
|
|
2760
|
+
protocolPath: 'blob',
|
|
2761
|
+
data
|
|
2762
|
+
});
|
|
2763
|
+
const reply = yield dwn.processMessage(alice.did, testRecord.message, { dataStream: testRecord.dataStream });
|
|
2764
|
+
expect(reply.status.code).to.equal(400);
|
|
2765
|
+
expect(reply.status.detail).to.contain(DwnErrorCode.ProtocolAuthorizationMaxSizeInvalid);
|
|
2766
|
+
// test valid max record size
|
|
2767
|
+
const data2 = TestDataGenerator.randomBytes(1000);
|
|
2768
|
+
const testRecord2 = yield TestDataGenerator.generateRecordsWrite({
|
|
2769
|
+
author: alice,
|
|
2770
|
+
recipient: alice.did,
|
|
2771
|
+
protocol,
|
|
2772
|
+
protocolPath: 'blob',
|
|
2773
|
+
data: data2
|
|
2774
|
+
});
|
|
2775
|
+
const reply2 = yield dwn.processMessage(alice.did, testRecord2.message, { dataStream: testRecord2.dataStream });
|
|
2776
|
+
expect(reply2.status.code).to.equal(202);
|
|
2777
|
+
}));
|
|
2778
|
+
it('should fail if a write references a parent that has been deleted', () => __awaiter(this, void 0, void 0, function* () {
|
|
2779
|
+
// scenario:
|
|
2780
|
+
// 0. Alice installs a nested protocol foo -> bar -> baz
|
|
2781
|
+
// 1. Alice writes foo1
|
|
2782
|
+
// 2. Alice deletes foo1
|
|
2783
|
+
// 3. Alice tries to write a bar1 referencing the deleted foo and should fail
|
|
2784
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
2785
|
+
const protocolDefinition = nestedProtocol;
|
|
2786
|
+
// 0. Alice installs a nested protocol foo -> bar -> baz
|
|
2787
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
2788
|
+
author: alice,
|
|
2789
|
+
protocolDefinition
|
|
2790
|
+
});
|
|
2791
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
2792
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
2793
|
+
// 1. Alice writes foo1
|
|
2794
|
+
const fooOptions = {
|
|
2795
|
+
author: alice,
|
|
2796
|
+
protocol: nestedProtocol.protocol,
|
|
2797
|
+
protocolPath: 'foo',
|
|
2798
|
+
schema: nestedProtocol.types.foo.schema,
|
|
2799
|
+
dataFormat: nestedProtocol.types.foo.dataFormats[0],
|
|
2800
|
+
};
|
|
2801
|
+
const foo1 = yield TestDataGenerator.generateRecordsWrite(fooOptions);
|
|
2802
|
+
const foo1WriteResponse = yield dwn.processMessage(alice.did, foo1.message, { dataStream: foo1.dataStream });
|
|
2803
|
+
expect(foo1WriteResponse.status.code).equals(202);
|
|
2804
|
+
// 2. Alice deletes foo1
|
|
2805
|
+
const deleteFoo = yield TestDataGenerator.generateRecordsDelete({
|
|
2806
|
+
author: alice,
|
|
2807
|
+
recordId: foo1.message.recordId
|
|
2808
|
+
});
|
|
2809
|
+
const deleteFooReply = yield dwn.processMessage(alice.did, deleteFoo.message);
|
|
2810
|
+
expect(deleteFooReply.status.code).equals(202);
|
|
2811
|
+
// 3. Alice tries to write a bar1 referencing the deleted foo and should fail
|
|
2812
|
+
const barOptions = {
|
|
2813
|
+
author: alice,
|
|
2814
|
+
protocol: nestedProtocol.protocol,
|
|
2815
|
+
protocolPath: 'foo/bar',
|
|
2816
|
+
schema: nestedProtocol.types.bar.schema,
|
|
2817
|
+
dataFormat: nestedProtocol.types.bar.dataFormats[0],
|
|
2818
|
+
parentContextId: foo1.message.contextId
|
|
2819
|
+
};
|
|
2820
|
+
const bar1 = yield TestDataGenerator.generateRecordsWrite(barOptions);
|
|
2821
|
+
const bar1WriteResponse = yield dwn.processMessage(alice.did, bar1.message, { dataStream: bar1.dataStream });
|
|
2822
|
+
expect(bar1WriteResponse.status.code).equals(400);
|
|
2823
|
+
expect(bar1WriteResponse.status.detail).to.contain(DwnErrorCode.ProtocolAuthorizationIncorrectProtocolPath);
|
|
2824
|
+
}));
|
|
2825
|
+
it('should fail if a write references a mismatching parent that compared to the parent in the `contextId` ', () => __awaiter(this, void 0, void 0, function* () {
|
|
2826
|
+
// scenario:
|
|
2827
|
+
// 0. Alice installs a nested protocol foo -> bar -> baz
|
|
2828
|
+
// 1. Alice writes foo1
|
|
2829
|
+
// 2. Alice tries to write a bar1 referencing the foo1 in parentId, but contextId does not reference the same parent
|
|
2830
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
2831
|
+
const protocolDefinition = nestedProtocol;
|
|
2832
|
+
// 0. Alice installs a nested protocol foo -> bar -> baz
|
|
2833
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
2834
|
+
author: alice,
|
|
2835
|
+
protocolDefinition
|
|
2836
|
+
});
|
|
2837
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
2838
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
2839
|
+
// 1. Alice writes foo1
|
|
2840
|
+
const fooOptions = {
|
|
2841
|
+
author: alice,
|
|
2842
|
+
protocol: nestedProtocol.protocol,
|
|
2843
|
+
protocolPath: 'foo',
|
|
2844
|
+
schema: nestedProtocol.types.foo.schema,
|
|
2845
|
+
dataFormat: nestedProtocol.types.foo.dataFormats[0],
|
|
2846
|
+
};
|
|
2847
|
+
const foo1 = yield TestDataGenerator.generateRecordsWrite(fooOptions);
|
|
2848
|
+
const foo1WriteResponse = yield dwn.processMessage(alice.did, foo1.message, { dataStream: foo1.dataStream });
|
|
2849
|
+
expect(foo1WriteResponse.status.code).equals(202);
|
|
2850
|
+
// 2. Alice tries to write a bar1 referencing the foo1 in parentId, but contextId does not reference the same parent
|
|
2851
|
+
const barOptions = {
|
|
2852
|
+
author: alice,
|
|
2853
|
+
protocol: nestedProtocol.protocol,
|
|
2854
|
+
protocolPath: 'foo/bar',
|
|
2855
|
+
schema: nestedProtocol.types.bar.schema,
|
|
2856
|
+
dataFormat: nestedProtocol.types.bar.dataFormats[0],
|
|
2857
|
+
parentContextId: foo1.message.contextId
|
|
2858
|
+
};
|
|
2859
|
+
const bar1 = yield TestDataGenerator.generateRecordsWrite(barOptions);
|
|
2860
|
+
// replace the contextId with a different parent
|
|
2861
|
+
const contextIdSegments = bar1.message.contextId.split(`/`);
|
|
2862
|
+
contextIdSegments[1] = 'differentParent';
|
|
2863
|
+
bar1.message.contextId = contextIdSegments.join(`/`);
|
|
2864
|
+
// resign the message
|
|
2865
|
+
const recordId = yield RecordsWrite.getEntryId(alice.did, bar1.message.descriptor);
|
|
2866
|
+
const descriptorCid = yield Cid.computeCid(bar1.message.descriptor);
|
|
2867
|
+
const signature = yield RecordsWrite.createSignerSignature({
|
|
2868
|
+
recordId,
|
|
2869
|
+
contextId: bar1.message.contextId,
|
|
2870
|
+
descriptorCid,
|
|
2871
|
+
encryption: undefined,
|
|
2872
|
+
attestation: undefined,
|
|
2873
|
+
signer: Jws.createSigner(alice)
|
|
2874
|
+
});
|
|
2875
|
+
bar1.message.recordId = recordId;
|
|
2876
|
+
bar1.message.authorization = { signature };
|
|
2877
|
+
const bar1WriteResponse = yield dwn.processMessage(alice.did, bar1.message);
|
|
2878
|
+
expect(bar1WriteResponse.status.code).equals(400);
|
|
2879
|
+
expect(bar1WriteResponse.status.detail).to.contain(DwnErrorCode.ProtocolAuthorizationIncorrectContextId);
|
|
2880
|
+
}));
|
|
2881
|
+
});
|
|
2882
|
+
describe('grant based writes', () => {
|
|
2883
|
+
describe('protocol records', () => {
|
|
2884
|
+
it('allows writes of protocol records with matching protocol grant scopes', () => __awaiter(this, void 0, void 0, function* () {
|
|
2885
|
+
// scenario: Alice gives Bob a grant to read all records in the protocol
|
|
2886
|
+
// Bob invokes that grant to write a protocol record.
|
|
2887
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
2888
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
2889
|
+
const protocolDefinition = minimalProtocolDefinition;
|
|
2890
|
+
// Alice installs the protocol
|
|
2891
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
2892
|
+
author: alice,
|
|
2893
|
+
protocolDefinition
|
|
2894
|
+
});
|
|
2895
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
2896
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
2897
|
+
// Alice gives Bob a permission grant
|
|
2898
|
+
const permissionGrant = yield PermissionsProtocol.createGrant({
|
|
2899
|
+
signer: Jws.createSigner(alice),
|
|
2900
|
+
grantedTo: bob.did,
|
|
2901
|
+
dateExpires: Time.createOffsetTimestamp({ seconds: 60 * 60 * 24 }), // 24 hours
|
|
2902
|
+
scope: {
|
|
2903
|
+
interface: DwnInterfaceName.Records,
|
|
2904
|
+
method: DwnMethodName.Write,
|
|
2905
|
+
protocol: protocolDefinition.protocol,
|
|
2906
|
+
}
|
|
2907
|
+
});
|
|
2908
|
+
const grantDataStream = DataStream.fromBytes(permissionGrant.permissionGrantBytes);
|
|
2909
|
+
const permissionGrantWriteReply = yield dwn.processMessage(alice.did, permissionGrant.recordsWrite.message, { dataStream: grantDataStream });
|
|
2910
|
+
expect(permissionGrantWriteReply.status.code).to.equal(202);
|
|
2911
|
+
// Bob invokes the grant in order to write a record to the protocol
|
|
2912
|
+
const { recordsWrite, dataStream } = yield TestDataGenerator.generateRecordsWrite({
|
|
2913
|
+
author: bob,
|
|
2914
|
+
protocol: protocolDefinition.protocol,
|
|
2915
|
+
protocolPath: 'foo',
|
|
2916
|
+
permissionGrantId: permissionGrant.recordsWrite.message.recordId,
|
|
2917
|
+
});
|
|
2918
|
+
const recordsWriteReply = yield dwn.processMessage(alice.did, recordsWrite.message, { dataStream });
|
|
2919
|
+
expect(recordsWriteReply.status.code).to.equal(202);
|
|
2920
|
+
}));
|
|
2921
|
+
it('rejects writes of protocol records with mismatching protocol grant scopes', () => __awaiter(this, void 0, void 0, function* () {
|
|
2922
|
+
// scenario: Alice gives Bob a grant to write to a protocol. Bob tries and fails to
|
|
2923
|
+
// invoke the grant to write to another protocol.
|
|
2924
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
2925
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
2926
|
+
const protocolDefinition = minimalProtocolDefinition;
|
|
2927
|
+
// Alice installs the protocol
|
|
2928
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
2929
|
+
author: alice,
|
|
2930
|
+
protocolDefinition
|
|
2931
|
+
});
|
|
2932
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
2933
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
2934
|
+
// Alice gives Bob a permission grant with a different protocol than what Bob will try to write to
|
|
2935
|
+
const permissionGrant = yield PermissionsProtocol.createGrant({
|
|
2936
|
+
signer: Jws.createSigner(alice),
|
|
2937
|
+
grantedTo: bob.did,
|
|
2938
|
+
dateExpires: Time.createOffsetTimestamp({ seconds: 60 * 60 * 24 }), // 24 hours
|
|
2939
|
+
scope: {
|
|
2940
|
+
interface: DwnInterfaceName.Records,
|
|
2941
|
+
method: DwnMethodName.Write,
|
|
2942
|
+
protocol: 'some-other-protocol',
|
|
2943
|
+
}
|
|
2944
|
+
});
|
|
2945
|
+
const grantDataStream = DataStream.fromBytes(permissionGrant.permissionGrantBytes);
|
|
2946
|
+
const permissionGrantWriteReply = yield dwn.processMessage(alice.did, permissionGrant.recordsWrite.message, { dataStream: grantDataStream });
|
|
2947
|
+
expect(permissionGrantWriteReply.status.code).to.equal(202);
|
|
2948
|
+
// Bob invokes the grant, failing to write to a different protocol than the grant allows
|
|
2949
|
+
const { recordsWrite, dataStream } = yield TestDataGenerator.generateRecordsWrite({
|
|
2950
|
+
author: bob,
|
|
2951
|
+
protocol: protocolDefinition.protocol,
|
|
2952
|
+
protocolPath: 'foo',
|
|
2953
|
+
permissionGrantId: permissionGrant.recordsWrite.message.recordId,
|
|
2954
|
+
});
|
|
2955
|
+
const recordsWriteReply = yield dwn.processMessage(alice.did, recordsWrite.message, { dataStream });
|
|
2956
|
+
expect(recordsWriteReply.status.code).to.equal(401);
|
|
2957
|
+
expect(recordsWriteReply.status.detail).to.contain(DwnErrorCode.RecordsGrantAuthorizationScopeProtocolMismatch);
|
|
2958
|
+
}));
|
|
2959
|
+
it('allows writes of protocol records with matching contextId grant scopes', () => __awaiter(this, void 0, void 0, function* () {
|
|
2960
|
+
// scenario: Alice gives Bob a grant to write to a specific contextId.
|
|
2961
|
+
// Bob invokes that grant to write a record in the allowed contextId.
|
|
2962
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
2963
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
2964
|
+
const protocolDefinition = emailProtocolDefinition;
|
|
2965
|
+
// Alice installs the protocol
|
|
2966
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
2967
|
+
author: alice,
|
|
2968
|
+
protocolDefinition
|
|
2969
|
+
});
|
|
2970
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
2971
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
2972
|
+
// Alice creates the context that she will give Bob access to
|
|
2973
|
+
const alicesRecordsWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
2974
|
+
author: alice,
|
|
2975
|
+
data: new TextEncoder().encode('data1'),
|
|
2976
|
+
protocol: protocolDefinition.protocol,
|
|
2977
|
+
protocolPath: 'email',
|
|
2978
|
+
schema: protocolDefinition.types.email.schema,
|
|
2979
|
+
dataFormat: protocolDefinition.types.email.dataFormats[0],
|
|
2980
|
+
});
|
|
2981
|
+
const alicesRecordsWriteReply = yield dwn.processMessage(alice.did, alicesRecordsWrite.message, { dataStream: alicesRecordsWrite.dataStream });
|
|
2982
|
+
expect(alicesRecordsWriteReply.status.code).to.equal(202);
|
|
2983
|
+
// Alice gives Bob a permission grant
|
|
2984
|
+
const permissionGrant = yield PermissionsProtocol.createGrant({
|
|
2985
|
+
signer: Jws.createSigner(alice),
|
|
2986
|
+
grantedTo: bob.did,
|
|
2987
|
+
dateExpires: Time.createOffsetTimestamp({ seconds: 60 * 60 * 24 }), // 24 hours
|
|
2988
|
+
scope: {
|
|
2989
|
+
interface: DwnInterfaceName.Records,
|
|
2990
|
+
method: DwnMethodName.Write,
|
|
2991
|
+
protocol: protocolDefinition.protocol,
|
|
2992
|
+
contextId: alicesRecordsWrite.message.contextId,
|
|
2993
|
+
}
|
|
2994
|
+
});
|
|
2995
|
+
const grantDataStream = DataStream.fromBytes(permissionGrant.permissionGrantBytes);
|
|
2996
|
+
const permissionGrantWriteReply = yield dwn.processMessage(alice.did, permissionGrant.recordsWrite.message, { dataStream: grantDataStream });
|
|
2997
|
+
expect(permissionGrantWriteReply.status.code).to.equal(202);
|
|
2998
|
+
// Bob invokes the grant in order to write a record to the protocol
|
|
2999
|
+
const bobsRecordsWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
3000
|
+
author: bob,
|
|
3001
|
+
protocol: protocolDefinition.protocol,
|
|
3002
|
+
protocolPath: 'email/email',
|
|
3003
|
+
schema: protocolDefinition.types.email.schema,
|
|
3004
|
+
dataFormat: protocolDefinition.types.email.dataFormats[0],
|
|
3005
|
+
parentContextId: alicesRecordsWrite.message.contextId,
|
|
3006
|
+
permissionGrantId: permissionGrant.recordsWrite.message.recordId,
|
|
3007
|
+
});
|
|
3008
|
+
const bobsRecordsWriteReply = yield dwn.processMessage(alice.did, bobsRecordsWrite.message, { dataStream: bobsRecordsWrite.dataStream });
|
|
3009
|
+
expect(bobsRecordsWriteReply.status.code).to.equal(202);
|
|
3010
|
+
}));
|
|
3011
|
+
it('rejects writes of protocol records with mismatching contextId grant scopes', () => __awaiter(this, void 0, void 0, function* () {
|
|
3012
|
+
// scenario: Alice gives Bob a grant to write to a specific contextId. Bob tries and fails to
|
|
3013
|
+
// invoke the grant to write to another contextId.
|
|
3014
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
3015
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
3016
|
+
const protocolDefinition = emailProtocolDefinition;
|
|
3017
|
+
// Alice installs the protocol
|
|
3018
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
3019
|
+
author: alice,
|
|
3020
|
+
protocolDefinition
|
|
3021
|
+
});
|
|
3022
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
3023
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
3024
|
+
// Alice creates the context that she will give Bob access to
|
|
3025
|
+
const alicesRecordsWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
3026
|
+
author: alice,
|
|
3027
|
+
data: new TextEncoder().encode('data1'),
|
|
3028
|
+
protocol: protocolDefinition.protocol,
|
|
3029
|
+
protocolPath: 'email',
|
|
3030
|
+
schema: protocolDefinition.types.email.schema,
|
|
3031
|
+
dataFormat: protocolDefinition.types.email.dataFormats[0],
|
|
3032
|
+
});
|
|
3033
|
+
const alicesRecordsWriteReply = yield dwn.processMessage(alice.did, alicesRecordsWrite.message, { dataStream: alicesRecordsWrite.dataStream });
|
|
3034
|
+
expect(alicesRecordsWriteReply.status.code).to.equal(202);
|
|
3035
|
+
// Alice gives Bob a permission grant
|
|
3036
|
+
const permissionGrant = yield PermissionsProtocol.createGrant({
|
|
3037
|
+
signer: Jws.createSigner(alice),
|
|
3038
|
+
grantedTo: bob.did,
|
|
3039
|
+
dateExpires: Time.createOffsetTimestamp({ seconds: 60 * 60 * 24 }), // 24 hours
|
|
3040
|
+
scope: {
|
|
3041
|
+
interface: DwnInterfaceName.Records,
|
|
3042
|
+
method: DwnMethodName.Write,
|
|
3043
|
+
protocol: protocolDefinition.protocol,
|
|
3044
|
+
contextId: yield TestDataGenerator.randomCborSha256Cid(), // different contextId than what Bob will try to write to
|
|
3045
|
+
}
|
|
3046
|
+
});
|
|
3047
|
+
const grantDataStream = DataStream.fromBytes(permissionGrant.permissionGrantBytes);
|
|
3048
|
+
const permissionGrantWriteReply = yield dwn.processMessage(alice.did, permissionGrant.recordsWrite.message, { dataStream: grantDataStream });
|
|
3049
|
+
expect(permissionGrantWriteReply.status.code).to.equal(202);
|
|
3050
|
+
// Bob invokes the grant in order to write a record to the protocol
|
|
3051
|
+
const bobsRecordsWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
3052
|
+
author: bob,
|
|
3053
|
+
protocol: protocolDefinition.protocol,
|
|
3054
|
+
protocolPath: 'email/email',
|
|
3055
|
+
schema: protocolDefinition.types.email.schema,
|
|
3056
|
+
dataFormat: protocolDefinition.types.email.dataFormats[0],
|
|
3057
|
+
parentContextId: alicesRecordsWrite.message.contextId,
|
|
3058
|
+
permissionGrantId: permissionGrant.recordsWrite.message.recordId,
|
|
3059
|
+
});
|
|
3060
|
+
const bobsRecordsWriteReply = yield dwn.processMessage(alice.did, bobsRecordsWrite.message, { dataStream: bobsRecordsWrite.dataStream });
|
|
3061
|
+
expect(bobsRecordsWriteReply.status.code).to.equal(401);
|
|
3062
|
+
expect(bobsRecordsWriteReply.status.detail).to.contain(DwnErrorCode.RecordsGrantAuthorizationScopeContextIdMismatch);
|
|
3063
|
+
}));
|
|
3064
|
+
it('allows writes of protocol records with matching protocolPath grant scopes', () => __awaiter(this, void 0, void 0, function* () {
|
|
3065
|
+
// scenario: Alice gives Bob a grant to write to a specific protocolPath.
|
|
3066
|
+
// Bob invokes that grant to write a record in the allowed protocolPath.
|
|
3067
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
3068
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
3069
|
+
const protocolDefinition = minimalProtocolDefinition;
|
|
3070
|
+
// Alice installs the protocol
|
|
3071
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
3072
|
+
author: alice,
|
|
3073
|
+
protocolDefinition
|
|
3074
|
+
});
|
|
3075
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
3076
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
3077
|
+
// Alice gives Bob a permission grant
|
|
3078
|
+
const permissionGrant = yield PermissionsProtocol.createGrant({
|
|
3079
|
+
signer: Jws.createSigner(alice),
|
|
3080
|
+
grantedTo: bob.did,
|
|
3081
|
+
dateExpires: Time.createOffsetTimestamp({ seconds: 60 * 60 * 24 }), // 24 hours
|
|
3082
|
+
scope: {
|
|
3083
|
+
interface: DwnInterfaceName.Records,
|
|
3084
|
+
method: DwnMethodName.Write,
|
|
3085
|
+
protocol: protocolDefinition.protocol,
|
|
3086
|
+
protocolPath: 'foo',
|
|
3087
|
+
}
|
|
3088
|
+
});
|
|
3089
|
+
const grantDataStream = DataStream.fromBytes(permissionGrant.permissionGrantBytes);
|
|
3090
|
+
const permissionGrantWriteReply = yield dwn.processMessage(alice.did, permissionGrant.recordsWrite.message, { dataStream: grantDataStream });
|
|
3091
|
+
expect(permissionGrantWriteReply.status.code).to.equal(202);
|
|
3092
|
+
// Bob invokes the grant in order to write a record to the protocol
|
|
3093
|
+
const bobsRecordsWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
3094
|
+
author: bob,
|
|
3095
|
+
protocol: protocolDefinition.protocol,
|
|
3096
|
+
protocolPath: 'foo',
|
|
3097
|
+
permissionGrantId: permissionGrant.recordsWrite.message.recordId,
|
|
3098
|
+
});
|
|
3099
|
+
const bobsRecordsWriteReply = yield dwn.processMessage(alice.did, bobsRecordsWrite.message, { dataStream: bobsRecordsWrite.dataStream });
|
|
3100
|
+
expect(bobsRecordsWriteReply.status.code).to.equal(202);
|
|
3101
|
+
}));
|
|
3102
|
+
it('rejects writes of protocol records with mismatching protocolPath grant scopes', () => __awaiter(this, void 0, void 0, function* () {
|
|
3103
|
+
// scenario: Alice gives Bob a grant to write to a specific protocolPath. Bob tries and fails to
|
|
3104
|
+
// invoke the grant to write to another protocolPath.
|
|
3105
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
3106
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
3107
|
+
const protocolDefinition = minimalProtocolDefinition;
|
|
3108
|
+
// Alice installs the protocol
|
|
3109
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
3110
|
+
author: alice,
|
|
3111
|
+
protocolDefinition
|
|
3112
|
+
});
|
|
3113
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
3114
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
3115
|
+
// Alice gives Bob a permission grant
|
|
3116
|
+
const permissionGrant = yield PermissionsProtocol.createGrant({
|
|
3117
|
+
signer: Jws.createSigner(alice),
|
|
3118
|
+
grantedTo: bob.did,
|
|
3119
|
+
dateExpires: Time.createOffsetTimestamp({ seconds: 60 * 60 * 24 }), // 24 hours
|
|
3120
|
+
scope: {
|
|
3121
|
+
interface: DwnInterfaceName.Records,
|
|
3122
|
+
method: DwnMethodName.Write,
|
|
3123
|
+
protocol: protocolDefinition.protocol,
|
|
3124
|
+
protocolPath: 'some-other-protocol-path',
|
|
3125
|
+
}
|
|
3126
|
+
});
|
|
3127
|
+
const grantDataStream = DataStream.fromBytes(permissionGrant.permissionGrantBytes);
|
|
3128
|
+
const permissionGrantWriteReply = yield dwn.processMessage(alice.did, permissionGrant.recordsWrite.message, { dataStream: grantDataStream });
|
|
3129
|
+
expect(permissionGrantWriteReply.status.code).to.equal(202);
|
|
3130
|
+
// Bob invokes the grant in order to write a record to the protocol
|
|
3131
|
+
const bobsRecordsWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
3132
|
+
author: bob,
|
|
3133
|
+
protocol: protocolDefinition.protocol,
|
|
3134
|
+
protocolPath: 'foo',
|
|
3135
|
+
permissionGrantId: permissionGrant.recordsWrite.message.recordId,
|
|
3136
|
+
});
|
|
3137
|
+
const bobsRecordsWriteReply = yield dwn.processMessage(alice.did, bobsRecordsWrite.message, { dataStream: bobsRecordsWrite.dataStream });
|
|
3138
|
+
expect(bobsRecordsWriteReply.status.code).to.equal(401);
|
|
3139
|
+
expect(bobsRecordsWriteReply.status.detail).to.contain(DwnErrorCode.RecordsGrantAuthorizationScopeProtocolPathMismatch);
|
|
3140
|
+
}));
|
|
3141
|
+
});
|
|
3142
|
+
describe('grant condition published', () => {
|
|
3143
|
+
it('Rejects unpublished records if grant condition `published` === required', () => __awaiter(this, void 0, void 0, function* () {
|
|
3144
|
+
// scenario: Alice gives Bob a grant with condition `published` === required.
|
|
3145
|
+
// Bob is able to write a public record but not able to write an unpublished record.
|
|
3146
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
3147
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
3148
|
+
// Alice installs a protocol
|
|
3149
|
+
const protocolDefinition = minimalProtocolDefinition;
|
|
3150
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
3151
|
+
author: alice,
|
|
3152
|
+
protocolDefinition,
|
|
3153
|
+
});
|
|
3154
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
3155
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
3156
|
+
// Alice creates a grant for Bob with `published` === required
|
|
3157
|
+
const permissionGrant = yield PermissionsProtocol.createGrant({
|
|
3158
|
+
signer: Jws.createSigner(alice),
|
|
3159
|
+
grantedTo: bob.did,
|
|
3160
|
+
dateExpires: Time.createOffsetTimestamp({ seconds: 60 * 60 * 24 }), // 24 hours
|
|
3161
|
+
scope: {
|
|
3162
|
+
interface: DwnInterfaceName.Records,
|
|
3163
|
+
method: DwnMethodName.Write,
|
|
3164
|
+
protocol: protocolDefinition.protocol,
|
|
3165
|
+
},
|
|
3166
|
+
conditions: {
|
|
3167
|
+
publication: PermissionConditionPublication.Required,
|
|
3168
|
+
}
|
|
3169
|
+
});
|
|
3170
|
+
const grantDataStream = DataStream.fromBytes(permissionGrant.permissionGrantBytes);
|
|
3171
|
+
const permissionGrantWriteReply = yield dwn.processMessage(alice.did, permissionGrant.recordsWrite.message, { dataStream: grantDataStream });
|
|
3172
|
+
expect(permissionGrantWriteReply.status.code).to.equal(202);
|
|
3173
|
+
const permissionGrantId = permissionGrant.recordsWrite.message.recordId;
|
|
3174
|
+
// Bob is able to write a published record
|
|
3175
|
+
const publishedRecordsWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
3176
|
+
author: bob,
|
|
3177
|
+
protocol: protocolDefinition.protocol,
|
|
3178
|
+
protocolPath: 'foo',
|
|
3179
|
+
published: true,
|
|
3180
|
+
permissionGrantId
|
|
3181
|
+
});
|
|
3182
|
+
const publishedRecordsWriteReply = yield dwn.processMessage(alice.did, publishedRecordsWrite.message, { dataStream: publishedRecordsWrite.dataStream });
|
|
3183
|
+
expect(publishedRecordsWriteReply.status.code).to.equal(202);
|
|
3184
|
+
// Bob is not able to write an unpublished record
|
|
3185
|
+
const unpublishedRecordsWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
3186
|
+
author: bob,
|
|
3187
|
+
protocol: protocolDefinition.protocol,
|
|
3188
|
+
protocolPath: 'foo',
|
|
3189
|
+
published: false,
|
|
3190
|
+
permissionGrantId
|
|
3191
|
+
});
|
|
3192
|
+
const unpublishedRecordsWriteReply = yield dwn.processMessage(alice.did, unpublishedRecordsWrite.message, { dataStream: unpublishedRecordsWrite.dataStream });
|
|
3193
|
+
expect(unpublishedRecordsWriteReply.status.code).to.equal(401);
|
|
3194
|
+
expect(unpublishedRecordsWriteReply.status.detail).to.contain(DwnErrorCode.RecordsGrantAuthorizationConditionPublicationRequired);
|
|
3195
|
+
}));
|
|
3196
|
+
it('Rejects published records if grant condition `published` === prohibited', () => __awaiter(this, void 0, void 0, function* () {
|
|
3197
|
+
// scenario: Alice gives Bob a grant with condition `published` === prohibited.
|
|
3198
|
+
// Bob is able to write a unpublished record but not able to write a public record.
|
|
3199
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
3200
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
3201
|
+
// Alice installs a protocol
|
|
3202
|
+
const protocolDefinition = minimalProtocolDefinition;
|
|
3203
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
3204
|
+
author: alice,
|
|
3205
|
+
protocolDefinition,
|
|
3206
|
+
});
|
|
3207
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
3208
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
3209
|
+
// Alice creates a grant for Bob with `published` === prohibited
|
|
3210
|
+
const permissionGrant = yield PermissionsProtocol.createGrant({
|
|
3211
|
+
signer: Jws.createSigner(alice),
|
|
3212
|
+
grantedTo: bob.did,
|
|
3213
|
+
dateExpires: Time.createOffsetTimestamp({ seconds: 60 * 60 * 24 }), // 24 hours
|
|
3214
|
+
scope: {
|
|
3215
|
+
interface: DwnInterfaceName.Records,
|
|
3216
|
+
method: DwnMethodName.Write,
|
|
3217
|
+
protocol: protocolDefinition.protocol,
|
|
3218
|
+
},
|
|
3219
|
+
conditions: {
|
|
3220
|
+
publication: PermissionConditionPublication.Prohibited
|
|
3221
|
+
}
|
|
3222
|
+
});
|
|
3223
|
+
const grantDataStream = DataStream.fromBytes(permissionGrant.permissionGrantBytes);
|
|
3224
|
+
const permissionGrantWriteReply = yield dwn.processMessage(alice.did, permissionGrant.recordsWrite.message, { dataStream: grantDataStream });
|
|
3225
|
+
expect(permissionGrantWriteReply.status.code).to.equal(202);
|
|
3226
|
+
const permissionGrantId = permissionGrant.recordsWrite.message.recordId;
|
|
3227
|
+
// Bob not is able to write a published record
|
|
3228
|
+
const publishedRecordsWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
3229
|
+
author: bob,
|
|
3230
|
+
protocol: protocolDefinition.protocol,
|
|
3231
|
+
protocolPath: 'foo',
|
|
3232
|
+
published: true,
|
|
3233
|
+
permissionGrantId
|
|
3234
|
+
});
|
|
3235
|
+
const publishedRecordsWriteReply = yield dwn.processMessage(alice.did, publishedRecordsWrite.message, { dataStream: publishedRecordsWrite.dataStream });
|
|
3236
|
+
expect(publishedRecordsWriteReply.status.code).to.equal(401);
|
|
3237
|
+
expect(publishedRecordsWriteReply.status.detail).to.contain(DwnErrorCode.RecordsGrantAuthorizationConditionPublicationProhibited);
|
|
3238
|
+
// Bob is able to write an unpublished record
|
|
3239
|
+
const unpublishedRecordsWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
3240
|
+
author: bob,
|
|
3241
|
+
protocol: protocolDefinition.protocol,
|
|
3242
|
+
protocolPath: 'foo',
|
|
3243
|
+
published: false,
|
|
3244
|
+
permissionGrantId
|
|
3245
|
+
});
|
|
3246
|
+
const unpublishedRecordsWriteReply = yield dwn.processMessage(alice.did, unpublishedRecordsWrite.message, { dataStream: unpublishedRecordsWrite.dataStream });
|
|
3247
|
+
expect(unpublishedRecordsWriteReply.status.code).to.equal(202);
|
|
3248
|
+
}));
|
|
3249
|
+
it('Allows both published and unpublished records if grant condition `published` is undefined', () => __awaiter(this, void 0, void 0, function* () {
|
|
3250
|
+
// scenario: Alice gives Bob a grant without condition `published`.
|
|
3251
|
+
// Bob is able to write both an unpublished record and a published record.
|
|
3252
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
3253
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
3254
|
+
// Alice installs a protocol
|
|
3255
|
+
const protocolDefinition = minimalProtocolDefinition;
|
|
3256
|
+
const protocolsConfig = yield TestDataGenerator.generateProtocolsConfigure({
|
|
3257
|
+
author: alice,
|
|
3258
|
+
protocolDefinition,
|
|
3259
|
+
});
|
|
3260
|
+
const protocolsConfigureReply = yield dwn.processMessage(alice.did, protocolsConfig.message);
|
|
3261
|
+
expect(protocolsConfigureReply.status.code).to.equal(202);
|
|
3262
|
+
// Alice creates a grant for Bob with `published` === prohibited
|
|
3263
|
+
const permissionGrant = yield PermissionsProtocol.createGrant({
|
|
3264
|
+
signer: Jws.createSigner(alice),
|
|
3265
|
+
grantedTo: bob.did,
|
|
3266
|
+
dateExpires: Time.createOffsetTimestamp({ seconds: 60 * 60 * 24 }), // 24 hours
|
|
3267
|
+
scope: {
|
|
3268
|
+
interface: DwnInterfaceName.Records,
|
|
3269
|
+
method: DwnMethodName.Write,
|
|
3270
|
+
protocol: protocolDefinition.protocol,
|
|
3271
|
+
},
|
|
3272
|
+
conditions: {
|
|
3273
|
+
// publication: '', // intentionally undefined
|
|
3274
|
+
}
|
|
3275
|
+
});
|
|
3276
|
+
const grantDataStream = DataStream.fromBytes(permissionGrant.permissionGrantBytes);
|
|
3277
|
+
const permissionGrantWriteReply = yield dwn.processMessage(alice.did, permissionGrant.recordsWrite.message, { dataStream: grantDataStream });
|
|
3278
|
+
expect(permissionGrantWriteReply.status.code).to.equal(202);
|
|
3279
|
+
const permissionGrantId = permissionGrant.recordsWrite.message.recordId;
|
|
3280
|
+
// Bob is able to write a published record
|
|
3281
|
+
const publishedRecordsWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
3282
|
+
author: bob,
|
|
3283
|
+
protocol: protocolDefinition.protocol,
|
|
3284
|
+
protocolPath: 'foo',
|
|
3285
|
+
published: true,
|
|
3286
|
+
permissionGrantId
|
|
3287
|
+
});
|
|
3288
|
+
const publishedRecordsWriteReply = yield dwn.processMessage(alice.did, publishedRecordsWrite.message, { dataStream: publishedRecordsWrite.dataStream });
|
|
3289
|
+
expect(publishedRecordsWriteReply.status.code).to.equal(202);
|
|
3290
|
+
// Bob is able to write an unpublished record
|
|
3291
|
+
const unpublishedRecordsWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
3292
|
+
author: bob,
|
|
3293
|
+
protocol: protocolDefinition.protocol,
|
|
3294
|
+
protocolPath: 'foo',
|
|
3295
|
+
published: false,
|
|
3296
|
+
permissionGrantId
|
|
3297
|
+
});
|
|
3298
|
+
const unpublishedRecordsWriteReply = yield dwn.processMessage(alice.did, unpublishedRecordsWrite.message, { dataStream: unpublishedRecordsWrite.dataStream });
|
|
3299
|
+
expect(unpublishedRecordsWriteReply.status.code).to.equal(202);
|
|
3300
|
+
}));
|
|
3301
|
+
});
|
|
3302
|
+
});
|
|
3303
|
+
it('should return 400 if dataStream is not provided and dataStore does not contain dataCid', () => __awaiter(this, void 0, void 0, function* () {
|
|
3304
|
+
// scenario: A sync writes a pruned initial RecordsWrite, without a `dataStream`. Alice does another regular
|
|
3305
|
+
// RecordsWrite for the same record, referencing the same `dataCid` but omitting the `dataStream`.
|
|
3306
|
+
// Pruned RecordsWrite
|
|
3307
|
+
// Data large enough to use the DataStore
|
|
3308
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
3309
|
+
const data = TestDataGenerator.randomBytes(DwnConstant.maxDataSizeAllowedToBeEncoded + 1);
|
|
3310
|
+
const prunedRecordsWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
3311
|
+
author: alice,
|
|
3312
|
+
published: false,
|
|
3313
|
+
data,
|
|
3314
|
+
});
|
|
3315
|
+
const prunedRecordsWriteReply = yield dwn.processMessage(alice.did, prunedRecordsWrite.message);
|
|
3316
|
+
expect(prunedRecordsWriteReply.status.code).to.equal(204);
|
|
3317
|
+
// Update record to published, omitting dataStream
|
|
3318
|
+
const recordsWrite = yield TestDataGenerator.generateFromRecordsWrite({
|
|
3319
|
+
author: alice,
|
|
3320
|
+
existingWrite: prunedRecordsWrite.recordsWrite,
|
|
3321
|
+
published: true,
|
|
3322
|
+
data,
|
|
3323
|
+
});
|
|
3324
|
+
const recordsWriteReply = yield dwn.processMessage(alice.did, recordsWrite.message);
|
|
3325
|
+
expect(recordsWriteReply.status.code).to.equal(400);
|
|
3326
|
+
expect(recordsWriteReply.status.detail).to.contain(DwnErrorCode.RecordsWriteMissingDataInPrevious);
|
|
3327
|
+
}));
|
|
3328
|
+
it('should return 400 if dataStream is not provided and previous message does not contain encodedData', () => __awaiter(this, void 0, void 0, function* () {
|
|
3329
|
+
// scenario: A sync writes a pruned initial RecordsWrite, without a `dataStream`. Alice does another regular
|
|
3330
|
+
// RecordsWrite for the same record, referencing the same `dataCid` but omitting the `dataStream`.
|
|
3331
|
+
// Pruned RecordsWrite
|
|
3332
|
+
// Data that would be encoded within the message
|
|
3333
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
3334
|
+
const data = TestDataGenerator.randomBytes(DwnConstant.maxDataSizeAllowedToBeEncoded);
|
|
3335
|
+
const prunedRecordsWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
3336
|
+
author: alice,
|
|
3337
|
+
published: false,
|
|
3338
|
+
data,
|
|
3339
|
+
});
|
|
3340
|
+
const prunedRecordsWriteReply = yield dwn.processMessage(alice.did, prunedRecordsWrite.message);
|
|
3341
|
+
expect(prunedRecordsWriteReply.status.code).to.equal(204);
|
|
3342
|
+
// Update record to published, omitting dataStream
|
|
3343
|
+
const recordsWrite = yield TestDataGenerator.generateFromRecordsWrite({
|
|
3344
|
+
author: alice,
|
|
3345
|
+
existingWrite: prunedRecordsWrite.recordsWrite,
|
|
3346
|
+
published: true,
|
|
3347
|
+
data,
|
|
3348
|
+
});
|
|
3349
|
+
const recordsWriteReply = yield dwn.processMessage(alice.did, recordsWrite.message);
|
|
3350
|
+
expect(recordsWriteReply.status.code).to.equal(400);
|
|
3351
|
+
expect(recordsWriteReply.status.detail).to.contain(DwnErrorCode.RecordsWriteMissingEncodedDataInPrevious);
|
|
3352
|
+
}));
|
|
3353
|
+
it('should return 400 if attempting a write after a delete', () => __awaiter(this, void 0, void 0, function* () {
|
|
3354
|
+
const { message, author, dataStream } = yield TestDataGenerator.generateRecordsWrite({
|
|
3355
|
+
data: TestDataGenerator.randomBytes(DwnConstant.maxDataSizeAllowedToBeEncoded),
|
|
3356
|
+
published: false
|
|
3357
|
+
});
|
|
3358
|
+
const tenant = author.did;
|
|
3359
|
+
TestStubGenerator.stubDidResolver(didResolver, [author]);
|
|
3360
|
+
const initialWriteReply = yield dwn.processMessage(tenant, message, { dataStream });
|
|
3361
|
+
expect(initialWriteReply.status.code).to.equal(202);
|
|
3362
|
+
const recordsDelete = yield RecordsDelete.create({
|
|
3363
|
+
recordId: message.recordId,
|
|
3364
|
+
signer: Jws.createSigner(author),
|
|
3365
|
+
});
|
|
3366
|
+
const deleteReply = yield dwn.processMessage(tenant, recordsDelete.message);
|
|
3367
|
+
expect(deleteReply.status.code).to.equal(202);
|
|
3368
|
+
const newDataBytes = TestDataGenerator.randomBytes(100);
|
|
3369
|
+
const newInvalidWrite = yield RecordsWrite.createFrom({
|
|
3370
|
+
recordsWriteMessage: message,
|
|
3371
|
+
signer: Jws.createSigner(author),
|
|
3372
|
+
data: newDataBytes
|
|
3373
|
+
});
|
|
3374
|
+
const newInvalidWriteReply = yield dwn.processMessage(tenant, newInvalidWrite.message, { dataStream: DataStream.fromBytes(newDataBytes) });
|
|
3375
|
+
expect(newInvalidWriteReply.status.code).to.equal(400);
|
|
3376
|
+
expect(newInvalidWriteReply.status.detail).to.contain(DwnErrorCode.RecordsWriteNotAllowedAfterDelete);
|
|
3377
|
+
}));
|
|
3378
|
+
it('should not allow referencing data across tenants', () => __awaiter(this, void 0, void 0, function* () {
|
|
3379
|
+
var _a, _b, _c;
|
|
3380
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
3381
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
3382
|
+
const data = Encoder.stringToBytes('test');
|
|
3383
|
+
const dataCid = yield Cid.computeDagPbCidFromBytes(data);
|
|
3384
|
+
const encodedData = Encoder.bytesToBase64Url(data);
|
|
3385
|
+
// alice writes data to her DWN
|
|
3386
|
+
const aliceWriteData = yield TestDataGenerator.generateRecordsWrite({
|
|
3387
|
+
author: alice,
|
|
3388
|
+
data
|
|
3389
|
+
});
|
|
3390
|
+
const aliceWriteReply = yield dwn.processMessage(alice.did, aliceWriteData.message, { dataStream: aliceWriteData.dataStream });
|
|
3391
|
+
expect(aliceWriteReply.status.code).to.equal(202);
|
|
3392
|
+
const aliceQueryWriteAfterAliceWriteData = yield TestDataGenerator.generateRecordsQuery({
|
|
3393
|
+
author: alice,
|
|
3394
|
+
filter: { recordId: aliceWriteData.message.recordId }
|
|
3395
|
+
});
|
|
3396
|
+
const aliceQueryWriteAfterAliceWriteReply = yield dwn.processMessage(alice.did, aliceQueryWriteAfterAliceWriteData.message);
|
|
3397
|
+
expect(aliceQueryWriteAfterAliceWriteReply.status.code).to.equal(200);
|
|
3398
|
+
expect((_a = aliceQueryWriteAfterAliceWriteReply.entries) === null || _a === void 0 ? void 0 : _a.length).to.equal(1);
|
|
3399
|
+
expect(aliceQueryWriteAfterAliceWriteReply.entries[0].encodedData).to.equal(encodedData);
|
|
3400
|
+
// bob learns of the CID of data of alice and tries to gain unauthorized access by referencing it in his own DWN
|
|
3401
|
+
const bobWriteData = yield TestDataGenerator.generateRecordsWrite({
|
|
3402
|
+
author: bob,
|
|
3403
|
+
dataCid,
|
|
3404
|
+
dataSize: 4
|
|
3405
|
+
});
|
|
3406
|
+
const bobWriteReply = yield dwn.processMessage(bob.did, bobWriteData.message); // intentionally missing data stream
|
|
3407
|
+
expect(bobWriteReply.status.code).to.equal(204); // NOTE: allows write here but does not allow read or query later
|
|
3408
|
+
const aliceQueryWriteAfterBobWriteData = yield TestDataGenerator.generateRecordsQuery({
|
|
3409
|
+
author: alice,
|
|
3410
|
+
filter: { recordId: aliceWriteData.message.recordId }
|
|
3411
|
+
});
|
|
3412
|
+
const aliceQueryWriteAfterBobWriteReply = yield dwn.processMessage(alice.did, aliceQueryWriteAfterBobWriteData.message);
|
|
3413
|
+
expect(aliceQueryWriteAfterBobWriteReply.status.code).to.equal(200);
|
|
3414
|
+
expect((_b = aliceQueryWriteAfterBobWriteReply.entries) === null || _b === void 0 ? void 0 : _b.length).to.equal(1);
|
|
3415
|
+
expect(aliceQueryWriteAfterBobWriteReply.entries[0].encodedData).to.equal(encodedData);
|
|
3416
|
+
// verify that bob has not gained access to alice's data
|
|
3417
|
+
const bobQueryAfterBobWriteData = yield TestDataGenerator.generateRecordsQuery({
|
|
3418
|
+
author: bob,
|
|
3419
|
+
filter: { recordId: bobWriteData.message.recordId }
|
|
3420
|
+
});
|
|
3421
|
+
const bobQueryAfterBobWriteReply = yield dwn.processMessage(bob.did, bobQueryAfterBobWriteData.message);
|
|
3422
|
+
expect(bobQueryAfterBobWriteReply.status.code).to.equal(200);
|
|
3423
|
+
expect((_c = bobQueryAfterBobWriteReply.entries) === null || _c === void 0 ? void 0 : _c.length).to.equal(0);
|
|
3424
|
+
}));
|
|
3425
|
+
describe('encodedData threshold', () => __awaiter(this, void 0, void 0, function* () {
|
|
3426
|
+
it('should call cloneAndAddEncodedData if dataSize is less than or equal to the threshold', () => __awaiter(this, void 0, void 0, function* () {
|
|
3427
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
3428
|
+
const dataBytes = TestDataGenerator.randomBytes(DwnConstant.maxDataSizeAllowedToBeEncoded);
|
|
3429
|
+
const { message, dataStream } = yield TestDataGenerator.generateRecordsWrite({ author: alice, data: dataBytes });
|
|
3430
|
+
const processEncoded = sinon.spy(RecordsWriteHandler.prototype, 'cloneAndAddEncodedData');
|
|
3431
|
+
const writeMessage = yield dwn.processMessage(alice.did, message, { dataStream });
|
|
3432
|
+
expect(writeMessage.status.code).to.equal(202);
|
|
3433
|
+
sinon.assert.calledOnce(processEncoded);
|
|
3434
|
+
}));
|
|
3435
|
+
it('should not call cloneAndAddEncodedData if dataSize is greater than the threshold', () => __awaiter(this, void 0, void 0, function* () {
|
|
3436
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
3437
|
+
const dataBytes = TestDataGenerator.randomBytes(DwnConstant.maxDataSizeAllowedToBeEncoded + 1);
|
|
3438
|
+
const { message, dataStream } = yield TestDataGenerator.generateRecordsWrite({ author: alice, data: dataBytes });
|
|
3439
|
+
const processEncoded = sinon.spy(RecordsWriteHandler.prototype, 'cloneAndAddEncodedData');
|
|
3440
|
+
const writeMessage = yield dwn.processMessage(alice.did, message, { dataStream });
|
|
3441
|
+
expect(writeMessage.status.code).to.equal(202);
|
|
3442
|
+
sinon.assert.notCalled(processEncoded);
|
|
3443
|
+
}));
|
|
3444
|
+
it('should have encodedData field if dataSize is less than or equal to the threshold', () => __awaiter(this, void 0, void 0, function* () {
|
|
3445
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
3446
|
+
const dataBytes = TestDataGenerator.randomBytes(DwnConstant.maxDataSizeAllowedToBeEncoded);
|
|
3447
|
+
const { message, dataStream } = yield TestDataGenerator.generateRecordsWrite({ author: alice, data: dataBytes });
|
|
3448
|
+
const writeMessage = yield dwn.processMessage(alice.did, message, { dataStream });
|
|
3449
|
+
expect(writeMessage.status.code).to.equal(202);
|
|
3450
|
+
const messageCid = yield Message.getCid(message);
|
|
3451
|
+
const storedMessage = yield messageStore.get(alice.did, messageCid);
|
|
3452
|
+
expect(storedMessage.encodedData).to.exist.and.not.be.undefined;
|
|
3453
|
+
}));
|
|
3454
|
+
it('should not have encodedData field if dataSize greater than threshold', () => __awaiter(this, void 0, void 0, function* () {
|
|
3455
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
3456
|
+
const dataBytes = TestDataGenerator.randomBytes(DwnConstant.maxDataSizeAllowedToBeEncoded + 1);
|
|
3457
|
+
const { message, dataStream } = yield TestDataGenerator.generateRecordsWrite({ author: alice, data: dataBytes });
|
|
3458
|
+
const writeMessage = yield dwn.processMessage(alice.did, message, { dataStream });
|
|
3459
|
+
expect(writeMessage.status.code).to.equal(202);
|
|
3460
|
+
const messageCid = yield Message.getCid(message);
|
|
3461
|
+
const storedMessage = yield messageStore.get(alice.did, messageCid);
|
|
3462
|
+
expect(storedMessage.encodedData).to.not.exist;
|
|
3463
|
+
}));
|
|
3464
|
+
it('should retain original RecordsWrite message but without the encodedData if data is under threshold', () => __awaiter(this, void 0, void 0, function* () {
|
|
3465
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
3466
|
+
const dataBytes = TestDataGenerator.randomBytes(DwnConstant.maxDataSizeAllowedToBeEncoded);
|
|
3467
|
+
const { message, dataStream } = yield TestDataGenerator.generateRecordsWrite({ author: alice, data: dataBytes });
|
|
3468
|
+
const writeMessage = yield dwn.processMessage(alice.did, message, { dataStream });
|
|
3469
|
+
expect(writeMessage.status.code).to.equal(202);
|
|
3470
|
+
const messageCid = yield Message.getCid(message);
|
|
3471
|
+
const storedMessage = yield messageStore.get(alice.did, messageCid);
|
|
3472
|
+
expect(storedMessage.encodedData).to.exist.and.not.be.undefined;
|
|
3473
|
+
const updatedDataBytes = TestDataGenerator.randomBytes(DwnConstant.maxDataSizeAllowedToBeEncoded);
|
|
3474
|
+
const newWrite = yield RecordsWrite.createFrom({
|
|
3475
|
+
recordsWriteMessage: message,
|
|
3476
|
+
published: true,
|
|
3477
|
+
signer: Jws.createSigner(alice),
|
|
3478
|
+
data: updatedDataBytes,
|
|
3479
|
+
});
|
|
3480
|
+
const updateDataStream = DataStream.fromBytes(updatedDataBytes);
|
|
3481
|
+
const writeMessage2 = yield dwn.processMessage(alice.did, newWrite.message, { dataStream: updateDataStream });
|
|
3482
|
+
expect(writeMessage2.status.code).to.equal(202);
|
|
3483
|
+
const originalWrite = yield messageStore.get(alice.did, messageCid);
|
|
3484
|
+
expect(originalWrite.encodedData).to.not.exist;
|
|
3485
|
+
const newestWrite = yield messageStore.get(alice.did, yield Message.getCid(newWrite.message));
|
|
3486
|
+
expect(newestWrite.encodedData).to.exist.and.not.be.undefined;
|
|
3487
|
+
}));
|
|
3488
|
+
}));
|
|
3489
|
+
});
|
|
3490
|
+
describe('authorization validation tests', () => {
|
|
3491
|
+
it('should return 400 if `recordId` in payload of the message signature mismatches with `recordId` in the message', () => __awaiter(this, void 0, void 0, function* () {
|
|
3492
|
+
const { author, message, recordsWrite, dataStream } = yield TestDataGenerator.generateRecordsWrite();
|
|
3493
|
+
// replace signature with mismatching `recordId`, even though signature is still valid
|
|
3494
|
+
const signaturePayload = Object.assign({}, recordsWrite.signaturePayload);
|
|
3495
|
+
signaturePayload.recordId = yield TestDataGenerator.randomCborSha256Cid(); // make recordId mismatch in authorization payload
|
|
3496
|
+
const signaturePayloadBytes = Encoder.objectToBytes(signaturePayload);
|
|
3497
|
+
const signer = Jws.createSigner(author);
|
|
3498
|
+
const jwsBuilder = yield GeneralJwsBuilder.create(signaturePayloadBytes, [signer]);
|
|
3499
|
+
message.authorization = { signature: jwsBuilder.getJws() };
|
|
3500
|
+
const tenant = author.did;
|
|
3501
|
+
const didResolver = TestStubGenerator.createDidResolverStub(author);
|
|
3502
|
+
const messageStoreStub = sinon.createStubInstance(MessageStoreLevel);
|
|
3503
|
+
const dataStoreStub = sinon.createStubInstance(DataStoreLevel);
|
|
3504
|
+
const recordsWriteHandler = new RecordsWriteHandler(didResolver, messageStoreStub, dataStoreStub, eventLog, eventStream);
|
|
3505
|
+
const reply = yield recordsWriteHandler.handle({ tenant, message, dataStream: dataStream });
|
|
3506
|
+
expect(reply.status.code).to.equal(400);
|
|
3507
|
+
expect(reply.status.detail).to.contain('does not match recordId in authorization');
|
|
3508
|
+
}));
|
|
3509
|
+
it('should return 400 if `contextId` in payload of message signature mismatches with `contextId` in the message', () => __awaiter(this, void 0, void 0, function* () {
|
|
3510
|
+
// generate a message with protocol so that computed contextId is also computed and included in message
|
|
3511
|
+
const { author, message, recordsWrite, dataStream } = yield TestDataGenerator.generateRecordsWrite({ protocol: 'http://any.value', protocolPath: 'any/value' });
|
|
3512
|
+
// replace `authorization` with mismatching `contextId`, even though signature is still valid
|
|
3513
|
+
const signaturePayload = Object.assign({}, recordsWrite.signaturePayload);
|
|
3514
|
+
signaturePayload.contextId = yield TestDataGenerator.randomCborSha256Cid(); // make contextId mismatch in authorization payload
|
|
3515
|
+
const signaturePayloadBytes = Encoder.objectToBytes(signaturePayload);
|
|
3516
|
+
const signer = Jws.createSigner(author);
|
|
3517
|
+
const jwsBuilder = yield GeneralJwsBuilder.create(signaturePayloadBytes, [signer]);
|
|
3518
|
+
message.authorization = { signature: jwsBuilder.getJws() };
|
|
3519
|
+
const tenant = author.did;
|
|
3520
|
+
const didResolver = sinon.createStubInstance(UniversalResolver);
|
|
3521
|
+
const messageStoreStub = sinon.createStubInstance(MessageStoreLevel);
|
|
3522
|
+
const dataStoreStub = sinon.createStubInstance(DataStoreLevel);
|
|
3523
|
+
const recordsWriteHandler = new RecordsWriteHandler(didResolver, messageStoreStub, dataStoreStub, eventLog, eventStream);
|
|
3524
|
+
const reply = yield recordsWriteHandler.handle({ tenant, message, dataStream: dataStream });
|
|
3525
|
+
expect(reply.status.code).to.equal(400);
|
|
3526
|
+
expect(reply.status.detail).to.contain('does not match contextId in authorization');
|
|
3527
|
+
}));
|
|
3528
|
+
it('should return 401 if `authorization` signature check fails', () => __awaiter(this, void 0, void 0, function* () {
|
|
3529
|
+
const { author, message, dataStream } = yield TestDataGenerator.generateRecordsWrite();
|
|
3530
|
+
const tenant = author.did;
|
|
3531
|
+
// setting up a stub DID resolver & message store
|
|
3532
|
+
// intentionally not supplying the public key so a different public key is generated to simulate invalid signature
|
|
3533
|
+
const mismatchingPersona = yield TestDataGenerator.generatePersona({ did: author.did, keyId: author.keyId });
|
|
3534
|
+
const didResolver = TestStubGenerator.createDidResolverStub(mismatchingPersona);
|
|
3535
|
+
const messageStoreStub = sinon.createStubInstance(MessageStoreLevel);
|
|
3536
|
+
const dataStoreStub = sinon.createStubInstance(DataStoreLevel);
|
|
3537
|
+
const recordsWriteHandler = new RecordsWriteHandler(didResolver, messageStoreStub, dataStoreStub, eventLog, eventStream);
|
|
3538
|
+
const reply = yield recordsWriteHandler.handle({ tenant, message, dataStream: dataStream });
|
|
3539
|
+
expect(reply.status.code).to.equal(401);
|
|
3540
|
+
}));
|
|
3541
|
+
it('should return 401 if an unauthorized author is attempting write', () => __awaiter(this, void 0, void 0, function* () {
|
|
3542
|
+
const author = yield TestDataGenerator.generatePersona();
|
|
3543
|
+
const { message, dataStream } = yield TestDataGenerator.generateRecordsWrite({ author });
|
|
3544
|
+
// setting up a stub DID resolver & message store
|
|
3545
|
+
const didResolver = TestStubGenerator.createDidResolverStub(author);
|
|
3546
|
+
const messageStoreStub = sinon.createStubInstance(MessageStoreLevel);
|
|
3547
|
+
const dataStoreStub = sinon.createStubInstance(DataStoreLevel);
|
|
3548
|
+
const recordsWriteHandler = new RecordsWriteHandler(didResolver, messageStoreStub, dataStoreStub, eventLog, eventStream);
|
|
3549
|
+
const tenant = yield (yield TestDataGenerator.generatePersona()).did; // unauthorized tenant
|
|
3550
|
+
const reply = yield recordsWriteHandler.handle({ tenant, message, dataStream: dataStream });
|
|
3551
|
+
expect(reply.status.code).to.equal(401);
|
|
3552
|
+
}));
|
|
3553
|
+
});
|
|
3554
|
+
describe('attestation validation tests', () => {
|
|
3555
|
+
it('should fail with 400 if `attestation` payload contains properties other than `descriptorCid`', () => __awaiter(this, void 0, void 0, function* () {
|
|
3556
|
+
const { author, message, recordsWrite, dataStream } = yield TestDataGenerator.generateRecordsWrite();
|
|
3557
|
+
const tenant = author.did;
|
|
3558
|
+
const signer = Jws.createSigner(author);
|
|
3559
|
+
// replace `attestation` with one that has an additional property, but go the extra mile of making sure signature is valid
|
|
3560
|
+
const descriptorCid = recordsWrite.signaturePayload.descriptorCid;
|
|
3561
|
+
const attestationPayload = { descriptorCid, someAdditionalProperty: 'anyValue' }; // additional property is not allowed
|
|
3562
|
+
const attestationPayloadBytes = Encoder.objectToBytes(attestationPayload);
|
|
3563
|
+
const attestationBuilder = yield GeneralJwsBuilder.create(attestationPayloadBytes, [signer]);
|
|
3564
|
+
message.attestation = attestationBuilder.getJws();
|
|
3565
|
+
// recreate the `authorization` based on the new` attestationCid`
|
|
3566
|
+
const signaturePayload = Object.assign({}, recordsWrite.signaturePayload);
|
|
3567
|
+
signaturePayload.attestationCid = yield Cid.computeCid(attestationPayload);
|
|
3568
|
+
const signaturePayloadBytes = Encoder.objectToBytes(signaturePayload);
|
|
3569
|
+
const authorizationBuilder = yield GeneralJwsBuilder.create(signaturePayloadBytes, [signer]);
|
|
3570
|
+
message.authorization = { signature: authorizationBuilder.getJws() };
|
|
3571
|
+
const didResolver = TestStubGenerator.createDidResolverStub(author);
|
|
3572
|
+
const messageStoreStub = sinon.createStubInstance(MessageStoreLevel);
|
|
3573
|
+
const dataStoreStub = sinon.createStubInstance(DataStoreLevel);
|
|
3574
|
+
const recordsWriteHandler = new RecordsWriteHandler(didResolver, messageStoreStub, dataStoreStub, eventLog, eventStream);
|
|
3575
|
+
const reply = yield recordsWriteHandler.handle({ tenant, message, dataStream: dataStream });
|
|
3576
|
+
expect(reply.status.code).to.equal(400);
|
|
3577
|
+
expect(reply.status.detail).to.contain(`Only 'descriptorCid' is allowed in attestation payload`);
|
|
3578
|
+
}));
|
|
3579
|
+
it('should fail validation with 400 if more than 1 attester is given ', () => __awaiter(this, void 0, void 0, function* () {
|
|
3580
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
3581
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
3582
|
+
const { message, dataStream } = yield TestDataGenerator.generateRecordsWrite({ author: alice, attesters: [alice, bob] });
|
|
3583
|
+
const recordsWriteHandler = new RecordsWriteHandler(didResolver, messageStore, dataStore, eventLog, eventStream);
|
|
3584
|
+
const writeReply = yield recordsWriteHandler.handle({ tenant: alice.did, message, dataStream: dataStream });
|
|
3585
|
+
expect(writeReply.status.code).to.equal(400);
|
|
3586
|
+
expect(writeReply.status.detail).to.contain('implementation only supports 1 attester');
|
|
3587
|
+
}));
|
|
3588
|
+
it('should fail validation with 400 if the `attestation` does not include the correct `descriptorCid`', () => __awaiter(this, void 0, void 0, function* () {
|
|
3589
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
3590
|
+
const { message, dataStream } = yield TestDataGenerator.generateRecordsWrite({ author: alice, attesters: [alice] });
|
|
3591
|
+
// create another write and use its `attestation` value instead, that `attestation` will point to an entirely different `descriptorCid`
|
|
3592
|
+
const anotherWrite = yield TestDataGenerator.generateRecordsWrite({ attesters: [alice] });
|
|
3593
|
+
message.attestation = anotherWrite.message.attestation;
|
|
3594
|
+
const recordsWriteHandler = new RecordsWriteHandler(didResolver, messageStore, dataStore, eventLog, eventStream);
|
|
3595
|
+
const writeReply = yield recordsWriteHandler.handle({ tenant: alice.did, message, dataStream: dataStream });
|
|
3596
|
+
expect(writeReply.status.code).to.equal(400);
|
|
3597
|
+
expect(writeReply.status.detail).to.contain('does not match expected descriptorCid');
|
|
3598
|
+
}));
|
|
3599
|
+
it('should fail validation with 400 if expected CID of `attestation` mismatches the `attestationCid` in `authorization`', () => __awaiter(this, void 0, void 0, function* () {
|
|
3600
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
3601
|
+
const { message, dataStream } = yield TestDataGenerator.generateRecordsWrite({ author: alice, attesters: [alice] });
|
|
3602
|
+
// replace valid attestation (the one signed by `authorization` with another attestation to the same message (descriptorCid)
|
|
3603
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
3604
|
+
const descriptorCid = yield Cid.computeCid(message.descriptor);
|
|
3605
|
+
const attestationNotReferencedByAuthorization = yield RecordsWrite['createAttestation'](descriptorCid, Jws.createSigners([bob]));
|
|
3606
|
+
message.attestation = attestationNotReferencedByAuthorization;
|
|
3607
|
+
const recordsWriteHandler = new RecordsWriteHandler(didResolver, messageStore, dataStore, eventLog, eventStream);
|
|
3608
|
+
const writeReply = yield recordsWriteHandler.handle({ tenant: alice.did, message, dataStream: dataStream });
|
|
3609
|
+
expect(writeReply.status.code).to.equal(400);
|
|
3610
|
+
expect(writeReply.status.detail).to.contain('does not match attestationCid');
|
|
3611
|
+
}));
|
|
3612
|
+
});
|
|
3613
|
+
describe('unknown error', () => {
|
|
3614
|
+
it('should throw if `recordsWriteHandler.processMessageWithoutDataStream()` throws unknown error', () => __awaiter(this, void 0, void 0, function* () {
|
|
3615
|
+
// simulate an initial write to test non-data path, as initial writes without data are always accepted (bot not readable)
|
|
3616
|
+
// https://github.com/TBD54566975/dwn-sdk-js/issues/628
|
|
3617
|
+
const { author, message: initialWriteMessage, recordsWrite: initialWrite } = yield TestDataGenerator.generateRecordsWrite();
|
|
3618
|
+
yield Time.minimalSleep();
|
|
3619
|
+
const { message, dataStream } = yield TestDataGenerator.generateFromRecordsWrite({ author, existingWrite: initialWrite });
|
|
3620
|
+
const tenant = author.did;
|
|
3621
|
+
const didResolverStub = TestStubGenerator.createDidResolverStub(author);
|
|
3622
|
+
const messageStoreStub = sinon.createStubInstance(MessageStoreLevel);
|
|
3623
|
+
messageStoreStub.query.resolves({ messages: [initialWriteMessage] });
|
|
3624
|
+
const dataStoreStub = sinon.createStubInstance(DataStoreLevel);
|
|
3625
|
+
const recordsWriteHandler = new RecordsWriteHandler(didResolverStub, messageStoreStub, dataStoreStub, eventLog, eventStream);
|
|
3626
|
+
// simulate throwing unexpected error
|
|
3627
|
+
sinon.stub(recordsWriteHandler, 'processMessageWithoutDataStream').throws(new Error('an unknown error in recordsWriteHandler.processMessageWithoutDataStream()'));
|
|
3628
|
+
sinon.stub(recordsWriteHandler, 'processMessageWithDataStream').throws(new Error('an unknown error in recordsWriteHandler.processMessageWithDataStream()'));
|
|
3629
|
+
let handlerPromise = recordsWriteHandler.handle({ tenant, message, dataStream: dataStream }); // with data stream
|
|
3630
|
+
yield expect(handlerPromise).to.be.rejectedWith('an unknown error in recordsWriteHandler.processMessageWithDataStream()');
|
|
3631
|
+
handlerPromise = recordsWriteHandler.handle({ tenant, message }); // without data stream
|
|
3632
|
+
yield expect(handlerPromise).to.be.rejectedWith('an unknown error in recordsWriteHandler.processMessageWithoutDataStream()');
|
|
3633
|
+
}));
|
|
3634
|
+
});
|
|
3635
|
+
}));
|
|
3636
|
+
}
|
|
3637
|
+
//# sourceMappingURL=records-write.spec.js.map
|