@enbox/dwn-sdk-js 0.4.6 → 0.4.7
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/README.md +3 -1
- package/dist/browser.mjs +19 -78
- package/dist/browser.mjs.map +4 -4
- package/dist/esm/generated/precompiled-validators.js +1997 -1517
- package/dist/esm/generated/precompiled-validators.js.map +1 -1
- package/dist/esm/src/core/constants.js +50 -0
- package/dist/esm/src/core/constants.js.map +1 -1
- package/dist/esm/src/core/dwn-error.js +28 -11
- package/dist/esm/src/core/dwn-error.js.map +1 -1
- package/dist/esm/src/core/encryption-control.js +785 -0
- package/dist/esm/src/core/encryption-control.js.map +1 -0
- package/dist/esm/src/core/message.js +6 -0
- package/dist/esm/src/core/message.js.map +1 -1
- package/dist/esm/src/core/messages-grant-authorization.js +36 -5
- package/dist/esm/src/core/messages-grant-authorization.js.map +1 -1
- package/dist/esm/src/core/protocol-authorization-action.js +3 -12
- package/dist/esm/src/core/protocol-authorization-action.js.map +1 -1
- package/dist/esm/src/core/protocol-authorization-validation.js +31 -30
- package/dist/esm/src/core/protocol-authorization-validation.js.map +1 -1
- package/dist/esm/src/core/protocol-authorization.js +6 -0
- package/dist/esm/src/core/protocol-authorization.js.map +1 -1
- package/dist/esm/src/core/recording-validation-state-reader.js +3 -3
- package/dist/esm/src/core/recording-validation-state-reader.js.map +1 -1
- package/dist/esm/src/core/replication-apply.js +62 -108
- package/dist/esm/src/core/replication-apply.js.map +1 -1
- package/dist/esm/src/core/validation-state-reader.js +5 -6
- package/dist/esm/src/core/validation-state-reader.js.map +1 -1
- package/dist/esm/src/dwn.js +1 -2
- package/dist/esm/src/dwn.js.map +1 -1
- package/dist/esm/src/event-stream/event-emitter-wake-publisher.js +11 -11
- package/dist/esm/src/event-stream/event-emitter-wake-publisher.js.map +1 -1
- package/dist/esm/src/handlers/messages-query.js +6 -16
- package/dist/esm/src/handlers/messages-query.js.map +1 -1
- package/dist/esm/src/handlers/messages-read.js +4 -3
- package/dist/esm/src/handlers/messages-read.js.map +1 -1
- package/dist/esm/src/handlers/messages-subscribe.js +26 -30
- package/dist/esm/src/handlers/messages-subscribe.js.map +1 -1
- package/dist/esm/src/handlers/protocols-configure.js +6 -4
- package/dist/esm/src/handlers/protocols-configure.js.map +1 -1
- package/dist/esm/src/handlers/records-count.js +85 -10
- package/dist/esm/src/handlers/records-count.js.map +1 -1
- package/dist/esm/src/handlers/records-delete.js +11 -0
- package/dist/esm/src/handlers/records-delete.js.map +1 -1
- package/dist/esm/src/handlers/records-query.js +140 -18
- package/dist/esm/src/handlers/records-query.js.map +1 -1
- package/dist/esm/src/handlers/records-read.js +20 -4
- package/dist/esm/src/handlers/records-read.js.map +1 -1
- package/dist/esm/src/handlers/records-subscribe.js +127 -11
- package/dist/esm/src/handlers/records-subscribe.js.map +1 -1
- package/dist/esm/src/handlers/records-write.js +15 -0
- package/dist/esm/src/handlers/records-write.js.map +1 -1
- package/dist/esm/src/index.js +7 -10
- package/dist/esm/src/index.js.map +1 -1
- package/dist/esm/src/interfaces/protocols-configure.js +66 -9
- package/dist/esm/src/interfaces/protocols-configure.js.map +1 -1
- package/dist/esm/src/interfaces/records-write.js +43 -36
- package/dist/esm/src/interfaces/records-write.js.map +1 -1
- package/dist/esm/src/jose/algorithms/signing/ed25519.js +5 -5
- package/dist/esm/src/jose/algorithms/signing/ed25519.js.map +1 -1
- package/dist/esm/src/jose/jws/general/verifier.js +1 -1
- package/dist/esm/src/jose/jws/general/verifier.js.map +1 -1
- package/dist/esm/src/protocols/encryption.js +32 -274
- package/dist/esm/src/protocols/encryption.js.map +1 -1
- package/dist/esm/src/store/blockstore-level.js +14 -23
- package/dist/esm/src/store/blockstore-level.js.map +1 -1
- package/dist/esm/src/store/blockstore-mock.js +10 -27
- package/dist/esm/src/store/blockstore-mock.js.map +1 -1
- package/dist/esm/src/store/blockstore-utils.js +45 -0
- package/dist/esm/src/store/blockstore-utils.js.map +1 -0
- package/dist/esm/src/store/blockstore.js +2 -0
- package/dist/esm/src/store/blockstore.js.map +1 -0
- package/dist/esm/src/store/data-store-level.js +4 -12
- package/dist/esm/src/store/data-store-level.js.map +1 -1
- package/dist/esm/src/store/level.js +7 -0
- package/dist/esm/src/store/level.js.map +1 -0
- package/dist/esm/src/types/encryption-types.js +4 -1
- package/dist/esm/src/types/encryption-types.js.map +1 -1
- package/dist/esm/src/utils/data-stream.js +25 -0
- package/dist/esm/src/utils/data-stream.js.map +1 -1
- package/dist/esm/src/utils/encryption.js +107 -19
- package/dist/esm/src/utils/encryption.js.map +1 -1
- package/dist/esm/src/utils/grant-key-coverage.js +180 -0
- package/dist/esm/src/utils/grant-key-coverage.js.map +1 -0
- package/dist/esm/src/utils/hd-key.js +1 -2
- package/dist/esm/src/utils/hd-key.js.map +1 -1
- package/dist/esm/src/utils/jws.js +7 -1
- package/dist/esm/src/utils/jws.js.map +1 -1
- package/dist/esm/src/utils/memory-cache.js +29 -8
- package/dist/esm/src/utils/memory-cache.js.map +1 -1
- package/dist/esm/src/utils/protocols.js +27 -0
- package/dist/esm/src/utils/protocols.js.map +1 -1
- package/dist/esm/src/utils/record-limit-occupancy.js +23 -3
- package/dist/esm/src/utils/record-limit-occupancy.js.map +1 -1
- package/dist/esm/src/utils/records.js +29 -0
- package/dist/esm/src/utils/records.js.map +1 -1
- package/dist/esm/src/utils/secp256k1.js +12 -11
- package/dist/esm/src/utils/secp256k1.js.map +1 -1
- package/dist/esm/src/utils/secp256r1.js +12 -20
- package/dist/esm/src/utils/secp256r1.js.map +1 -1
- package/dist/esm/src/utils/time.js +103 -25
- package/dist/esm/src/utils/time.js.map +1 -1
- package/dist/esm/tests/core/constants.spec.js +35 -0
- package/dist/esm/tests/core/constants.spec.js.map +1 -0
- package/dist/esm/tests/core/encryption-control.spec.js +100 -0
- package/dist/esm/tests/core/encryption-control.spec.js.map +1 -0
- package/dist/esm/tests/core/message.spec.js +35 -0
- package/dist/esm/tests/core/message.spec.js.map +1 -1
- package/dist/esm/tests/core/protocol-authorization.spec.js +1 -1
- package/dist/esm/tests/core/protocol-authorization.spec.js.map +1 -1
- package/dist/esm/tests/core/replication-apply.spec.js +157 -74
- package/dist/esm/tests/core/replication-apply.spec.js.map +1 -1
- package/dist/esm/tests/core/replication-replay-property.spec.js +2 -1
- package/dist/esm/tests/core/replication-replay-property.spec.js.map +1 -1
- package/dist/esm/tests/core/validation-read-closure.spec.js +14 -28
- package/dist/esm/tests/core/validation-read-closure.spec.js.map +1 -1
- package/dist/esm/tests/core/validation-state-reader.spec.js +19 -23
- package/dist/esm/tests/core/validation-state-reader.spec.js.map +1 -1
- package/dist/esm/tests/dwn.spec.js +2 -1
- package/dist/esm/tests/dwn.spec.js.map +1 -1
- package/dist/esm/tests/event-emitter-wake-publisher.spec.js +51 -0
- package/dist/esm/tests/event-emitter-wake-publisher.spec.js.map +1 -0
- package/dist/esm/tests/features/protocol-composition.spec.js +1 -1
- package/dist/esm/tests/features/protocol-composition.spec.js.map +1 -1
- package/dist/esm/tests/features/records-record-limit.spec.js +1 -1
- package/dist/esm/tests/features/records-record-limit.spec.js.map +1 -1
- package/dist/esm/tests/fuzz/encryption.fuzz.spec.js +9 -1
- package/dist/esm/tests/fuzz/encryption.fuzz.spec.js.map +1 -1
- package/dist/esm/tests/fuzz/process-message.fuzz.spec.js +1 -1
- package/dist/esm/tests/fuzz/process-message.fuzz.spec.js.map +1 -1
- package/dist/esm/tests/fuzz/protocols-utils.fuzz.spec.js +29 -1
- package/dist/esm/tests/fuzz/protocols-utils.fuzz.spec.js.map +1 -1
- package/dist/esm/tests/fuzz/secp256k1.fuzz.spec.js +2 -2
- package/dist/esm/tests/fuzz/secp256k1.fuzz.spec.js.map +1 -1
- package/dist/esm/tests/fuzz/time.fuzz.spec.js +7 -1
- package/dist/esm/tests/fuzz/time.fuzz.spec.js.map +1 -1
- package/dist/esm/tests/handlers/messages-query.spec.js +123 -11
- package/dist/esm/tests/handlers/messages-query.spec.js.map +1 -1
- package/dist/esm/tests/handlers/messages-read.spec.js +95 -0
- package/dist/esm/tests/handlers/messages-read.spec.js.map +1 -1
- package/dist/esm/tests/handlers/messages-subscribe.spec.js +90 -0
- package/dist/esm/tests/handlers/messages-subscribe.spec.js.map +1 -1
- package/dist/esm/tests/handlers/protocols-configure.spec.js +66 -0
- package/dist/esm/tests/handlers/protocols-configure.spec.js.map +1 -1
- package/dist/esm/tests/handlers/records-count.spec.js +370 -0
- package/dist/esm/tests/handlers/records-count.spec.js.map +1 -1
- package/dist/esm/tests/handlers/records-delete.spec.js +70 -1
- package/dist/esm/tests/handlers/records-delete.spec.js.map +1 -1
- package/dist/esm/tests/handlers/records-query.spec.js +562 -1
- package/dist/esm/tests/handlers/records-query.spec.js.map +1 -1
- package/dist/esm/tests/handlers/records-read.spec.js +140 -2
- package/dist/esm/tests/handlers/records-read.spec.js.map +1 -1
- package/dist/esm/tests/handlers/records-subscribe.spec.js +241 -1
- package/dist/esm/tests/handlers/records-subscribe.spec.js.map +1 -1
- package/dist/esm/tests/handlers/records-write.spec.js +1187 -29
- package/dist/esm/tests/handlers/records-write.spec.js.map +1 -1
- package/dist/esm/tests/interfaces/protocols-configure.spec.js +290 -2
- package/dist/esm/tests/interfaces/protocols-configure.spec.js.map +1 -1
- package/dist/esm/tests/interfaces/records-write.spec.js +47 -5
- package/dist/esm/tests/interfaces/records-write.spec.js.map +1 -1
- package/dist/esm/tests/protocols/encryption.spec.js +116 -472
- package/dist/esm/tests/protocols/encryption.spec.js.map +1 -1
- package/dist/esm/tests/scenarios/end-to-end-tests.spec.js +13 -27
- package/dist/esm/tests/scenarios/end-to-end-tests.spec.js.map +1 -1
- package/dist/esm/tests/store/blockstore-level.spec.js +33 -10
- package/dist/esm/tests/store/blockstore-level.spec.js.map +1 -1
- package/dist/esm/tests/store/blockstore-mock.spec.js +31 -7
- package/dist/esm/tests/store/blockstore-mock.spec.js.map +1 -1
- package/dist/esm/tests/store/blockstore-utils.spec.js +115 -0
- package/dist/esm/tests/store/blockstore-utils.spec.js.map +1 -0
- package/dist/esm/tests/store/index-level.spec.js +3 -3
- package/dist/esm/tests/store/index-level.spec.js.map +1 -1
- package/dist/esm/tests/test-stores.js +2 -1
- package/dist/esm/tests/test-stores.js.map +1 -1
- package/dist/esm/tests/utils/cid.spec.js +15 -0
- package/dist/esm/tests/utils/cid.spec.js.map +1 -1
- package/dist/esm/tests/utils/data-stream.spec.js +30 -0
- package/dist/esm/tests/utils/data-stream.spec.js.map +1 -1
- package/dist/esm/tests/utils/encryption-control-test-utils.js +111 -0
- package/dist/esm/tests/utils/encryption-control-test-utils.js.map +1 -0
- package/dist/esm/tests/utils/encryption.spec.js +198 -5
- package/dist/esm/tests/utils/encryption.spec.js.map +1 -1
- package/dist/esm/tests/utils/grant-key-coverage.spec.js +262 -0
- package/dist/esm/tests/utils/grant-key-coverage.spec.js.map +1 -0
- package/dist/esm/tests/utils/memory-cache.spec.js +12 -0
- package/dist/esm/tests/utils/memory-cache.spec.js.map +1 -1
- package/dist/esm/tests/utils/secp256r1.spec.js +2 -2
- package/dist/esm/tests/utils/secp256r1.spec.js.map +1 -1
- package/dist/esm/tests/utils/test-data-generator.js +2 -1
- package/dist/esm/tests/utils/test-data-generator.js.map +1 -1
- package/dist/esm/tests/utils/test-validation-state-reader.js +1 -1
- package/dist/esm/tests/utils/test-validation-state-reader.js.map +1 -1
- package/dist/esm/tests/utils/time.spec.js +26 -0
- package/dist/esm/tests/utils/time.spec.js.map +1 -1
- package/dist/esm/tests/validation/json-schemas/encryption/audience.spec.js +45 -0
- package/dist/esm/tests/validation/json-schemas/encryption/audience.spec.js.map +1 -0
- package/dist/esm/tests/validation/json-schemas/encryption/delivery.spec.js +47 -0
- package/dist/esm/tests/validation/json-schemas/encryption/delivery.spec.js.map +1 -0
- package/dist/esm/tests/validation/json-schemas/protocols/protocols-configure.spec.js +152 -0
- package/dist/esm/tests/validation/json-schemas/protocols/protocols-configure.spec.js.map +1 -1
- package/dist/esm/tests/validation/json-schemas/records/records-write.spec.js +46 -1
- package/dist/esm/tests/validation/json-schemas/records/records-write.spec.js.map +1 -1
- package/dist/types/generated/precompiled-validators.d.ts +4 -4
- package/dist/types/generated/precompiled-validators.d.ts.map +1 -1
- package/dist/types/src/core/constants.d.ts +39 -0
- package/dist/types/src/core/constants.d.ts.map +1 -1
- package/dist/types/src/core/dwn-error.d.ts +28 -11
- package/dist/types/src/core/dwn-error.d.ts.map +1 -1
- package/dist/types/src/core/encryption-control.d.ts +128 -0
- package/dist/types/src/core/encryption-control.d.ts.map +1 -0
- package/dist/types/src/core/message.d.ts +4 -0
- package/dist/types/src/core/message.d.ts.map +1 -1
- package/dist/types/src/core/messages-grant-authorization.d.ts +11 -0
- package/dist/types/src/core/messages-grant-authorization.d.ts.map +1 -1
- package/dist/types/src/core/protocol-authorization-action.d.ts.map +1 -1
- package/dist/types/src/core/protocol-authorization-validation.d.ts.map +1 -1
- package/dist/types/src/core/protocol-authorization.d.ts.map +1 -1
- package/dist/types/src/core/recording-validation-state-reader.d.ts +2 -3
- package/dist/types/src/core/recording-validation-state-reader.d.ts.map +1 -1
- package/dist/types/src/core/replication-apply.d.ts +10 -1
- package/dist/types/src/core/replication-apply.d.ts.map +1 -1
- package/dist/types/src/core/validation-state-reader.d.ts +2 -3
- package/dist/types/src/core/validation-state-reader.d.ts.map +1 -1
- package/dist/types/src/dwn.d.ts.map +1 -1
- package/dist/types/src/event-stream/event-emitter-wake-publisher.d.ts +1 -1
- package/dist/types/src/event-stream/event-emitter-wake-publisher.d.ts.map +1 -1
- package/dist/types/src/handlers/messages-query.d.ts.map +1 -1
- package/dist/types/src/handlers/messages-read.d.ts.map +1 -1
- package/dist/types/src/handlers/messages-subscribe.d.ts.map +1 -1
- package/dist/types/src/handlers/protocols-configure.d.ts +1 -0
- package/dist/types/src/handlers/protocols-configure.d.ts.map +1 -1
- package/dist/types/src/handlers/records-count.d.ts +2 -0
- package/dist/types/src/handlers/records-count.d.ts.map +1 -1
- package/dist/types/src/handlers/records-delete.d.ts.map +1 -1
- package/dist/types/src/handlers/records-query.d.ts +3 -0
- package/dist/types/src/handlers/records-query.d.ts.map +1 -1
- package/dist/types/src/handlers/records-read.d.ts.map +1 -1
- package/dist/types/src/handlers/records-subscribe.d.ts +2 -0
- package/dist/types/src/handlers/records-subscribe.d.ts.map +1 -1
- package/dist/types/src/handlers/records-write.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +10 -17
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/interfaces/protocols-configure.d.ts +13 -1
- package/dist/types/src/interfaces/protocols-configure.d.ts.map +1 -1
- package/dist/types/src/interfaces/records-write.d.ts +5 -1
- package/dist/types/src/interfaces/records-write.d.ts.map +1 -1
- package/dist/types/src/jose/algorithms/signing/ed25519.d.ts.map +1 -1
- package/dist/types/src/protocols/encryption.d.ts +2 -19
- package/dist/types/src/protocols/encryption.d.ts.map +1 -1
- package/dist/types/src/store/blockstore-level.d.ts +11 -11
- package/dist/types/src/store/blockstore-level.d.ts.map +1 -1
- package/dist/types/src/store/blockstore-mock.d.ts +12 -12
- package/dist/types/src/store/blockstore-mock.d.ts.map +1 -1
- package/dist/types/src/store/blockstore-utils.d.ts +23 -0
- package/dist/types/src/store/blockstore-utils.d.ts.map +1 -0
- package/dist/types/src/store/blockstore.d.ts +3 -0
- package/dist/types/src/store/blockstore.d.ts.map +1 -0
- package/dist/types/src/store/data-store-level.d.ts.map +1 -1
- package/dist/types/src/store/level.d.ts +13 -0
- package/dist/types/src/store/level.d.ts.map +1 -0
- package/dist/types/src/types/cache.d.ts +2 -2
- package/dist/types/src/types/cache.d.ts.map +1 -1
- package/dist/types/src/types/encryption-types.d.ts +31 -2
- package/dist/types/src/types/encryption-types.d.ts.map +1 -1
- package/dist/types/src/types/validation-state-reader.d.ts +3 -5
- package/dist/types/src/types/validation-state-reader.d.ts.map +1 -1
- package/dist/types/src/utils/data-stream.d.ts +5 -0
- package/dist/types/src/utils/data-stream.d.ts.map +1 -1
- package/dist/types/src/utils/encryption.d.ts +53 -24
- package/dist/types/src/utils/encryption.d.ts.map +1 -1
- package/dist/types/src/utils/grant-key-coverage.d.ts +36 -0
- package/dist/types/src/utils/grant-key-coverage.d.ts.map +1 -0
- package/dist/types/src/utils/hd-key.d.ts.map +1 -1
- package/dist/types/src/utils/jws.d.ts.map +1 -1
- package/dist/types/src/utils/memory-cache.d.ts +4 -2
- package/dist/types/src/utils/memory-cache.d.ts.map +1 -1
- package/dist/types/src/utils/protocols.d.ts +11 -0
- package/dist/types/src/utils/protocols.d.ts.map +1 -1
- package/dist/types/src/utils/record-limit-occupancy.d.ts +7 -0
- package/dist/types/src/utils/record-limit-occupancy.d.ts.map +1 -1
- package/dist/types/src/utils/records.d.ts +2 -0
- package/dist/types/src/utils/records.d.ts.map +1 -1
- package/dist/types/src/utils/secp256k1.d.ts.map +1 -1
- package/dist/types/src/utils/secp256r1.d.ts.map +1 -1
- package/dist/types/src/utils/time.d.ts +21 -13
- package/dist/types/src/utils/time.d.ts.map +1 -1
- package/dist/types/tests/core/constants.spec.d.ts +2 -0
- package/dist/types/tests/core/constants.spec.d.ts.map +1 -0
- package/dist/types/tests/core/encryption-control.spec.d.ts +2 -0
- package/dist/types/tests/core/encryption-control.spec.d.ts.map +1 -0
- package/dist/types/tests/dwn.spec.d.ts.map +1 -1
- package/dist/types/tests/event-emitter-wake-publisher.spec.d.ts +2 -0
- package/dist/types/tests/event-emitter-wake-publisher.spec.d.ts.map +1 -0
- package/dist/types/tests/handlers/messages-query.spec.d.ts.map +1 -1
- package/dist/types/tests/handlers/messages-read.spec.d.ts.map +1 -1
- package/dist/types/tests/handlers/messages-subscribe.spec.d.ts.map +1 -1
- package/dist/types/tests/handlers/protocols-configure.spec.d.ts.map +1 -1
- package/dist/types/tests/handlers/records-count.spec.d.ts.map +1 -1
- package/dist/types/tests/handlers/records-delete.spec.d.ts.map +1 -1
- package/dist/types/tests/handlers/records-query.spec.d.ts.map +1 -1
- package/dist/types/tests/handlers/records-read.spec.d.ts.map +1 -1
- package/dist/types/tests/handlers/records-subscribe.spec.d.ts.map +1 -1
- package/dist/types/tests/handlers/records-write.spec.d.ts.map +1 -1
- package/dist/types/tests/scenarios/end-to-end-tests.spec.d.ts.map +1 -1
- package/dist/types/tests/store/blockstore-utils.spec.d.ts +2 -0
- package/dist/types/tests/store/blockstore-utils.spec.d.ts.map +1 -0
- package/dist/types/tests/test-stores.d.ts.map +1 -1
- package/dist/types/tests/utils/encryption-control-test-utils.d.ts +46 -0
- package/dist/types/tests/utils/encryption-control-test-utils.d.ts.map +1 -0
- package/dist/types/tests/utils/grant-key-coverage.spec.d.ts +2 -0
- package/dist/types/tests/utils/grant-key-coverage.spec.d.ts.map +1 -0
- package/dist/types/tests/utils/test-data-generator.d.ts.map +1 -1
- package/dist/types/tests/validation/json-schemas/encryption/audience.spec.d.ts +2 -0
- package/dist/types/tests/validation/json-schemas/encryption/audience.spec.d.ts.map +1 -0
- package/dist/types/tests/validation/json-schemas/encryption/delivery.spec.d.ts +2 -0
- package/dist/types/tests/validation/json-schemas/encryption/delivery.spec.d.ts.map +1 -0
- package/package.json +47 -28
- package/src/core/constants.ts +61 -0
- package/src/core/dwn-error.ts +28 -11
- package/src/core/encryption-control.ts +1249 -0
- package/src/core/message.ts +7 -0
- package/src/core/messages-grant-authorization.ts +60 -9
- package/src/core/protocol-authorization-action.ts +3 -13
- package/src/core/protocol-authorization-validation.ts +66 -46
- package/src/core/protocol-authorization.ts +7 -0
- package/src/core/recording-validation-state-reader.ts +4 -5
- package/src/core/replication-apply.ts +77 -133
- package/src/core/validation-state-reader.ts +6 -8
- package/src/dwn.ts +1 -2
- package/src/event-stream/event-emitter-wake-publisher.ts +10 -14
- package/src/handlers/messages-query.ts +6 -22
- package/src/handlers/messages-read.ts +4 -3
- package/src/handlers/messages-subscribe.ts +34 -30
- package/src/handlers/protocols-configure.ts +7 -4
- package/src/handlers/records-count.ts +111 -10
- package/src/handlers/records-delete.ts +15 -0
- package/src/handlers/records-query.ts +176 -20
- package/src/handlers/records-read.ts +19 -6
- package/src/handlers/records-subscribe.ts +158 -8
- package/src/handlers/records-write.ts +19 -0
- package/src/index.ts +48 -21
- package/src/interfaces/protocols-configure.ts +102 -11
- package/src/interfaces/records-write.ts +49 -43
- package/src/jose/algorithms/signing/ed25519.ts +7 -6
- package/src/jose/jws/general/verifier.ts +3 -3
- package/src/protocols/encryption.ts +50 -420
- package/src/store/blockstore-level.ts +33 -37
- package/src/store/blockstore-mock.ts +24 -38
- package/src/store/blockstore-utils.ts +85 -0
- package/src/store/blockstore.ts +8 -0
- package/src/store/data-store-level.ts +5 -12
- package/src/store/level.ts +19 -0
- package/src/types/cache.ts +3 -3
- package/src/types/encryption-types.ts +39 -2
- package/src/types/validation-state-reader.ts +3 -5
- package/src/utils/data-stream.ts +29 -1
- package/src/utils/encryption.ts +190 -60
- package/src/utils/grant-key-coverage.ts +303 -0
- package/src/utils/hd-key.ts +1 -2
- package/src/utils/jws.ts +8 -2
- package/src/utils/memory-cache.ts +42 -11
- package/src/utils/protocols.ts +32 -0
- package/src/utils/record-limit-occupancy.ts +34 -5
- package/src/utils/records.ts +36 -2
- package/src/utils/secp256k1.ts +12 -12
- package/src/utils/secp256r1.ts +12 -22
- package/src/utils/time.ts +145 -27
- package/dist/esm/tests/validation/json-schemas/encryption/audience-key.spec.js +0 -40
- package/dist/esm/tests/validation/json-schemas/encryption/audience-key.spec.js.map +0 -1
- package/dist/types/tests/validation/json-schemas/encryption/audience-key.spec.d.ts +0 -2
- package/dist/types/tests/validation/json-schemas/encryption/audience-key.spec.d.ts.map +0 -1
- package/src/types/mitt.d.ts +0 -28
|
@@ -3,13 +3,14 @@ import type { HandlerDependencies, MethodHandler } from '../types/method-handler
|
|
|
3
3
|
import type { RecordsCountMessage, RecordsCountReply } from '../types/records-types.js';
|
|
4
4
|
|
|
5
5
|
import { authenticate } from '../core/auth.js';
|
|
6
|
-
import {
|
|
6
|
+
import { EncryptionControl } from '../core/encryption-control.js';
|
|
7
7
|
import { Message } from '../core/message.js';
|
|
8
8
|
import { messageReplyFromError } from '../core/message-reply.js';
|
|
9
9
|
import { ProtocolAuthorization } from '../core/protocol-authorization.js';
|
|
10
10
|
import { Records } from '../utils/records.js';
|
|
11
11
|
import { RecordsCount } from '../interfaces/records-count.js';
|
|
12
12
|
import { RecordsGrantAuthorization } from '../core/records-grant-authorization.js';
|
|
13
|
+
import { countRecordsWithRecordLimitOccupancy, queryRecordsWithRecordLimitOccupancy } from '../utils/record-limit-occupancy.js';
|
|
13
14
|
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
|
|
14
15
|
|
|
15
16
|
export class RecordsCountHandler implements MethodHandler {
|
|
@@ -28,10 +29,11 @@ export class RecordsCountHandler implements MethodHandler {
|
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
let count: number;
|
|
32
|
+
const requester = Message.getRequester(recordsCount.message);
|
|
31
33
|
|
|
32
34
|
// if this is an anonymous count and the filter supports published records, count only published records
|
|
33
35
|
if (Records.filterIncludesPublishedRecords(recordsCount.message.descriptor.filter) && recordsCount.author === undefined) {
|
|
34
|
-
count = await this.countPublishedRecords(tenant, recordsCount);
|
|
36
|
+
count = await this.countPublishedRecords(tenant, recordsCount, requester);
|
|
35
37
|
} else {
|
|
36
38
|
// authentication and authorization
|
|
37
39
|
try {
|
|
@@ -42,10 +44,12 @@ export class RecordsCountHandler implements MethodHandler {
|
|
|
42
44
|
return messageReplyFromError(e, 401);
|
|
43
45
|
}
|
|
44
46
|
|
|
45
|
-
if (recordsCount.author === tenant) {
|
|
47
|
+
if (recordsCount.author === tenant && requester === tenant) {
|
|
46
48
|
count = await this.countRecordsAsOwner(tenant, recordsCount);
|
|
49
|
+
} else if (recordsCount.author === tenant) {
|
|
50
|
+
count = await this.countRecordsAsOwnerDelegate(tenant, recordsCount, requester);
|
|
47
51
|
} else {
|
|
48
|
-
count = await this.countRecordsAsNonOwner(tenant, recordsCount);
|
|
52
|
+
count = await this.countRecordsAsNonOwner(tenant, recordsCount, requester);
|
|
49
53
|
}
|
|
50
54
|
}
|
|
51
55
|
|
|
@@ -70,10 +74,30 @@ export class RecordsCountHandler implements MethodHandler {
|
|
|
70
74
|
return this.countProjectedRecords(tenant, recordsCount, [countFilter]);
|
|
71
75
|
}
|
|
72
76
|
|
|
77
|
+
private async countRecordsAsOwnerDelegate(
|
|
78
|
+
tenant: string,
|
|
79
|
+
recordsCount: RecordsCount,
|
|
80
|
+
requester: string | undefined,
|
|
81
|
+
): Promise<number> {
|
|
82
|
+
const { filter } = recordsCount.message.descriptor;
|
|
83
|
+
const countFilter = {
|
|
84
|
+
...Records.convertFilter(filter),
|
|
85
|
+
interface : DwnInterfaceName.Records,
|
|
86
|
+
method : DwnMethodName.Write,
|
|
87
|
+
isLatestBaseState : true
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
return this.countProjectedRecordsForRequester(tenant, recordsCount, requester, [countFilter]);
|
|
91
|
+
}
|
|
92
|
+
|
|
73
93
|
/**
|
|
74
94
|
* Counts records as a non-owner, applying the same filter logic as RecordsQuery.
|
|
75
95
|
*/
|
|
76
|
-
private async countRecordsAsNonOwner(
|
|
96
|
+
private async countRecordsAsNonOwner(
|
|
97
|
+
tenant: string,
|
|
98
|
+
recordsCount: RecordsCount,
|
|
99
|
+
requester: string | undefined,
|
|
100
|
+
): Promise<number> {
|
|
77
101
|
const { filter } = recordsCount.message.descriptor;
|
|
78
102
|
const filters: Filter[] = [];
|
|
79
103
|
|
|
@@ -82,6 +106,10 @@ export class RecordsCountHandler implements MethodHandler {
|
|
|
82
106
|
}
|
|
83
107
|
|
|
84
108
|
if (Records.filterIncludesUnpublishedRecords(filter)) {
|
|
109
|
+
if (EncryptionControl.isExactAudienceFilter(filter)) {
|
|
110
|
+
filters.push(Records.buildUnpublishedControlRecordsFilter(filter));
|
|
111
|
+
}
|
|
112
|
+
|
|
85
113
|
if (Records.shouldBuildUnpublishedAuthorFilter(filter, recordsCount.author!)) {
|
|
86
114
|
filters.push(RecordsCountHandler.buildUnpublishedRecordsByCountAuthorFilter(recordsCount));
|
|
87
115
|
}
|
|
@@ -99,25 +127,89 @@ export class RecordsCountHandler implements MethodHandler {
|
|
|
99
127
|
}
|
|
100
128
|
}
|
|
101
129
|
|
|
102
|
-
return this.
|
|
130
|
+
return this.countProjectedRecordsForRequester(tenant, recordsCount, requester, filters);
|
|
103
131
|
}
|
|
104
132
|
|
|
105
133
|
/**
|
|
106
134
|
* Counts only published records.
|
|
107
135
|
*/
|
|
108
|
-
private async countPublishedRecords(
|
|
136
|
+
private async countPublishedRecords(
|
|
137
|
+
tenant: string,
|
|
138
|
+
recordsCount: RecordsCount,
|
|
139
|
+
requester: string | undefined,
|
|
140
|
+
): Promise<number> {
|
|
109
141
|
const filter = RecordsCountHandler.buildPublishedRecordsFilter(recordsCount);
|
|
110
|
-
return this.
|
|
142
|
+
return this.countProjectedRecordsForRequester(tenant, recordsCount, requester, [filter]);
|
|
111
143
|
}
|
|
112
144
|
|
|
113
145
|
private async countProjectedRecords(tenant: string, recordsCount: RecordsCount, filters: Filter[]): Promise<number> {
|
|
114
|
-
|
|
146
|
+
const totalCount = await countRecordsWithRecordLimitOccupancy({
|
|
115
147
|
messageStore : this.deps.messageStore,
|
|
116
148
|
validationStateReader : this.deps.validationStateReader,
|
|
117
149
|
tenant,
|
|
118
150
|
filters,
|
|
119
151
|
messageTimestamp : recordsCount.message.descriptor.messageTimestamp,
|
|
120
152
|
});
|
|
153
|
+
|
|
154
|
+
const audienceFilters = EncryptionControl.buildAudienceRecordFilters(filters);
|
|
155
|
+
if (audienceFilters.length === 0) {
|
|
156
|
+
return totalCount;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const storedAudienceCount = await this.deps.messageStore.count(tenant, audienceFilters);
|
|
160
|
+
if (storedAudienceCount === 0) {
|
|
161
|
+
return totalCount;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const { messages } = await this.deps.messageStore.query(tenant, audienceFilters);
|
|
165
|
+
const projectedAudienceMessages = await EncryptionControl.projectCurrentAudienceRecords({
|
|
166
|
+
messageStore : this.deps.messageStore,
|
|
167
|
+
tenant,
|
|
168
|
+
recordsWriteMessages : messages.filter(Records.isRecordsWrite),
|
|
169
|
+
bypassFilters : audienceFilters,
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
return totalCount - storedAudienceCount + projectedAudienceMessages.length;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
private async countProjectedRecordsForRequester(
|
|
176
|
+
tenant: string,
|
|
177
|
+
recordsCount: RecordsCount,
|
|
178
|
+
requester: string | undefined,
|
|
179
|
+
filters: Filter[],
|
|
180
|
+
): Promise<number> {
|
|
181
|
+
const controlFilters = Records.buildControlRecordsFilters(filters);
|
|
182
|
+
if (controlFilters.length === 0) {
|
|
183
|
+
return this.countProjectedRecords(tenant, recordsCount, filters);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const totalCount = await this.countProjectedRecords(tenant, recordsCount, filters);
|
|
187
|
+
const controlCount = await this.countProjectedRecords(tenant, recordsCount, controlFilters);
|
|
188
|
+
if (controlCount === 0) {
|
|
189
|
+
return totalCount;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const { messages } = await queryRecordsWithRecordLimitOccupancy({
|
|
193
|
+
messageStore : this.deps.messageStore,
|
|
194
|
+
validationStateReader : this.deps.validationStateReader,
|
|
195
|
+
tenant,
|
|
196
|
+
filters : controlFilters,
|
|
197
|
+
messageTimestamp : recordsCount.message.descriptor.messageTimestamp,
|
|
198
|
+
});
|
|
199
|
+
const projectedMessages = await EncryptionControl.projectCurrentAudienceRecords({
|
|
200
|
+
messageStore : this.deps.messageStore,
|
|
201
|
+
tenant,
|
|
202
|
+
recordsWriteMessages : messages,
|
|
203
|
+
bypassFilters : controlFilters,
|
|
204
|
+
});
|
|
205
|
+
const visibleMessages = await EncryptionControl.filterVisibleControlRecords({
|
|
206
|
+
tenant,
|
|
207
|
+
incomingMessage : recordsCount.message,
|
|
208
|
+
requester,
|
|
209
|
+
recordsWriteMessages : projectedMessages,
|
|
210
|
+
validationStateReader : this.deps.validationStateReader,
|
|
211
|
+
});
|
|
212
|
+
return totalCount - controlCount + visibleMessages.length;
|
|
121
213
|
}
|
|
122
214
|
|
|
123
215
|
private static buildPublishedRecordsFilter(recordsCount: RecordsCount): Filter {
|
|
@@ -198,8 +290,16 @@ export class RecordsCountHandler implements MethodHandler {
|
|
|
198
290
|
deps: HandlerDependencies,
|
|
199
291
|
): Promise<void> {
|
|
200
292
|
|
|
201
|
-
if (Message.isSignedByAuthorDelegate(recordsCount.message)
|
|
293
|
+
if (Message.isSignedByAuthorDelegate(recordsCount.message) &&
|
|
294
|
+
!EncryptionControl.filterTargetsOnlyControlRecords(recordsCount.message.descriptor.filter)) {
|
|
202
295
|
await recordsCount.authorizeDelegate(deps.validationStateReader);
|
|
296
|
+
} else if (EncryptionControl.filterTargetsOnlyControlRecords(recordsCount.message.descriptor.filter)) {
|
|
297
|
+
await EncryptionControl.authorizeControlReadRequest({
|
|
298
|
+
tenant,
|
|
299
|
+
incomingMessage : recordsCount.message,
|
|
300
|
+
requester : Message.getRequester(recordsCount.message),
|
|
301
|
+
validationStateReader : deps.validationStateReader,
|
|
302
|
+
});
|
|
203
303
|
}
|
|
204
304
|
|
|
205
305
|
const permissionGrantId = Message.getPermissionGrantId(recordsCount.signaturePayload!);
|
|
@@ -222,4 +322,5 @@ export class RecordsCountHandler implements MethodHandler {
|
|
|
222
322
|
await ProtocolAuthorization.authorizeQueryOrSubscribe(tenant, recordsCount, deps.validationStateReader);
|
|
223
323
|
}
|
|
224
324
|
}
|
|
325
|
+
|
|
225
326
|
}
|
|
@@ -6,6 +6,7 @@ import type { HandlerDependencies, MethodHandler } from '../types/method-handler
|
|
|
6
6
|
|
|
7
7
|
import { authenticate } from '../core/auth.js';
|
|
8
8
|
import { DwnInterfaceName } from '../enums/dwn-interface-method.js';
|
|
9
|
+
import { EncryptionControl } from '../core/encryption-control.js';
|
|
9
10
|
import { Message } from '../core/message.js';
|
|
10
11
|
import { messageReplyFromError } from '../core/message-reply.js';
|
|
11
12
|
import { ProtocolAuthorization } from '../core/protocol-authorization.js';
|
|
@@ -13,6 +14,7 @@ import { Records } from '../utils/records.js';
|
|
|
13
14
|
import { RecordsDelete } from '../interfaces/records-delete.js';
|
|
14
15
|
import { RecordsGrantAuthorization } from '../core/records-grant-authorization.js';
|
|
15
16
|
import { ResumableTaskName } from '../core/resumable-task-manager.js';
|
|
17
|
+
import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
|
|
16
18
|
|
|
17
19
|
export class RecordsDeleteHandler implements MethodHandler {
|
|
18
20
|
|
|
@@ -71,6 +73,12 @@ export class RecordsDeleteHandler implements MethodHandler {
|
|
|
71
73
|
// but if the latest record state is a RecordsDelete (ie. when we are pruning a non-prune delete),
|
|
72
74
|
// we'd need to use the initial write because RecordsDelete does not contain the immutable properties needed for processing.
|
|
73
75
|
const initialWrite = await this.deps.validationStateReader.fetchInitialRecordsWrite(tenant, message.descriptor.recordId);
|
|
76
|
+
if (EncryptionControl.isControlMessage(initialWrite!.message)) {
|
|
77
|
+
throw new DwnError(
|
|
78
|
+
DwnErrorCode.EncryptionControlValidateUnexpectedRecord,
|
|
79
|
+
'encryption control records cannot be deleted.'
|
|
80
|
+
);
|
|
81
|
+
}
|
|
74
82
|
|
|
75
83
|
await this.authorizeRecordsDelete(
|
|
76
84
|
tenant,
|
|
@@ -79,6 +87,13 @@ export class RecordsDeleteHandler implements MethodHandler {
|
|
|
79
87
|
);
|
|
80
88
|
|
|
81
89
|
} catch (e) {
|
|
90
|
+
if (e instanceof DwnError) {
|
|
91
|
+
const statusCode = EncryptionControl.mapErrorToStatusCode(e.code);
|
|
92
|
+
if (statusCode !== undefined) {
|
|
93
|
+
return messageReplyFromError(e, statusCode);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
82
97
|
return messageReplyFromError(e, 401);
|
|
83
98
|
}
|
|
84
99
|
|
|
@@ -5,6 +5,7 @@ import type { RecordsQueryMessage, RecordsQueryReply, RecordsQueryReplyEntry } f
|
|
|
5
5
|
|
|
6
6
|
import { authenticate } from '../core/auth.js';
|
|
7
7
|
import { DateSort } from '../types/records-types.js';
|
|
8
|
+
import { EncryptionControl } from '../core/encryption-control.js';
|
|
8
9
|
import { Message } from '../core/message.js';
|
|
9
10
|
import { messageReplyFromError } from '../core/message-reply.js';
|
|
10
11
|
import { ProtocolAuthorization } from '../core/protocol-authorization.js';
|
|
@@ -33,9 +34,10 @@ export class RecordsQueryHandler implements MethodHandler {
|
|
|
33
34
|
|
|
34
35
|
let recordsWrites: RecordsQueryReplyEntry[];
|
|
35
36
|
let cursor: PaginationCursor | undefined;
|
|
37
|
+
const requester = Message.getRequester(recordsQuery.message);
|
|
36
38
|
// if this is an anonymous query and the filter supports published records, query only published records
|
|
37
39
|
if (Records.filterIncludesPublishedRecords(recordsQuery.message.descriptor.filter) && recordsQuery.author === undefined) {
|
|
38
|
-
const results = await this.fetchPublishedRecords(tenant, recordsQuery);
|
|
40
|
+
const results = await this.fetchPublishedRecords(tenant, recordsQuery, requester);
|
|
39
41
|
recordsWrites = results.messages as RecordsQueryReplyEntry[];
|
|
40
42
|
cursor = results.cursor;
|
|
41
43
|
} else {
|
|
@@ -49,11 +51,13 @@ export class RecordsQueryHandler implements MethodHandler {
|
|
|
49
51
|
}
|
|
50
52
|
|
|
51
53
|
if (recordsQuery.author === tenant) {
|
|
52
|
-
const results =
|
|
54
|
+
const results = requester === tenant
|
|
55
|
+
? await this.fetchRecordsAsOwner(tenant, recordsQuery)
|
|
56
|
+
: await this.fetchRecordsAsOwnerDelegate(tenant, recordsQuery, requester);
|
|
53
57
|
recordsWrites = results.messages as RecordsQueryReplyEntry[];
|
|
54
58
|
cursor = results.cursor;
|
|
55
59
|
} else {
|
|
56
|
-
const results = await this.fetchRecordsAsNonOwner(tenant, recordsQuery);
|
|
60
|
+
const results = await this.fetchRecordsAsNonOwner(tenant, recordsQuery, requester);
|
|
57
61
|
recordsWrites = results.messages as RecordsQueryReplyEntry[];
|
|
58
62
|
cursor = results.cursor;
|
|
59
63
|
}
|
|
@@ -122,14 +126,37 @@ export class RecordsQueryHandler implements MethodHandler {
|
|
|
122
126
|
};
|
|
123
127
|
|
|
124
128
|
const messageSort = this.convertDateSort(dateSort);
|
|
125
|
-
return
|
|
126
|
-
messageStore : this.deps.messageStore,
|
|
127
|
-
validationStateReader : this.deps.validationStateReader,
|
|
129
|
+
return this.queryRecordsWithVisibleControlFiltering({
|
|
128
130
|
tenant,
|
|
129
|
-
|
|
131
|
+
recordsQuery,
|
|
132
|
+
requester : tenant,
|
|
133
|
+
filters : [queryFilter],
|
|
134
|
+
messageSort,
|
|
135
|
+
pagination,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
private async fetchRecordsAsOwnerDelegate(
|
|
140
|
+
tenant: string,
|
|
141
|
+
recordsQuery: RecordsQuery,
|
|
142
|
+
requester: string | undefined,
|
|
143
|
+
): Promise<{ messages: GenericMessage[], cursor?: PaginationCursor }> {
|
|
144
|
+
const { dateSort, filter, pagination } = recordsQuery.message.descriptor;
|
|
145
|
+
const queryFilter = {
|
|
146
|
+
...Records.convertFilter(filter, dateSort),
|
|
147
|
+
interface : DwnInterfaceName.Records,
|
|
148
|
+
method : DwnMethodName.Write,
|
|
149
|
+
isLatestBaseState : true
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
const messageSort = this.convertDateSort(dateSort);
|
|
153
|
+
return this.queryRecordsWithVisibleControlFiltering({
|
|
154
|
+
tenant,
|
|
155
|
+
recordsQuery,
|
|
156
|
+
requester,
|
|
157
|
+
filters: [queryFilter],
|
|
130
158
|
messageSort,
|
|
131
159
|
pagination,
|
|
132
|
-
messageTimestamp : recordsQuery.message.descriptor.messageTimestamp,
|
|
133
160
|
});
|
|
134
161
|
}
|
|
135
162
|
|
|
@@ -153,7 +180,9 @@ export class RecordsQueryHandler implements MethodHandler {
|
|
|
153
180
|
*
|
|
154
181
|
*/
|
|
155
182
|
private async fetchRecordsAsNonOwner(
|
|
156
|
-
tenant: string,
|
|
183
|
+
tenant: string,
|
|
184
|
+
recordsQuery: RecordsQuery,
|
|
185
|
+
requester: string | undefined,
|
|
157
186
|
): Promise<{ messages: GenericMessage[], cursor?: PaginationCursor }> {
|
|
158
187
|
const { dateSort, pagination, filter } = recordsQuery.message.descriptor;
|
|
159
188
|
const filters = [];
|
|
@@ -162,6 +191,10 @@ export class RecordsQueryHandler implements MethodHandler {
|
|
|
162
191
|
}
|
|
163
192
|
|
|
164
193
|
if (Records.filterIncludesUnpublishedRecords(filter)) {
|
|
194
|
+
if (EncryptionControl.isExactAudienceFilter(filter)) {
|
|
195
|
+
filters.push(Records.buildUnpublishedControlRecordsFilter(filter, dateSort));
|
|
196
|
+
}
|
|
197
|
+
|
|
165
198
|
if (Records.shouldBuildUnpublishedAuthorFilter(filter, recordsQuery.author!)) {
|
|
166
199
|
filters.push(RecordsQueryHandler.buildUnpublishedRecordsByQueryAuthorFilter(recordsQuery));
|
|
167
200
|
}
|
|
@@ -180,14 +213,13 @@ export class RecordsQueryHandler implements MethodHandler {
|
|
|
180
213
|
}
|
|
181
214
|
|
|
182
215
|
const messageSort = this.convertDateSort(dateSort);
|
|
183
|
-
return
|
|
184
|
-
messageStore : this.deps.messageStore,
|
|
185
|
-
validationStateReader : this.deps.validationStateReader,
|
|
216
|
+
return this.queryRecordsWithVisibleControlFiltering({
|
|
186
217
|
tenant,
|
|
218
|
+
recordsQuery,
|
|
219
|
+
requester,
|
|
187
220
|
filters,
|
|
188
221
|
messageSort,
|
|
189
222
|
pagination,
|
|
190
|
-
messageTimestamp : recordsQuery.message.descriptor.messageTimestamp,
|
|
191
223
|
});
|
|
192
224
|
}
|
|
193
225
|
|
|
@@ -195,22 +227,123 @@ export class RecordsQueryHandler implements MethodHandler {
|
|
|
195
227
|
* Fetches only published records.
|
|
196
228
|
*/
|
|
197
229
|
private async fetchPublishedRecords(
|
|
198
|
-
tenant: string,
|
|
230
|
+
tenant: string,
|
|
231
|
+
recordsQuery: RecordsQuery,
|
|
232
|
+
requester: string | undefined,
|
|
199
233
|
): Promise<{ messages: GenericMessage[], cursor?: PaginationCursor }> {
|
|
200
234
|
const { dateSort, pagination } = recordsQuery.message.descriptor;
|
|
201
235
|
const filter = RecordsQueryHandler.buildPublishedRecordsFilter(recordsQuery);
|
|
202
236
|
const messageSort = this.convertDateSort(dateSort);
|
|
203
|
-
return
|
|
204
|
-
messageStore : this.deps.messageStore,
|
|
205
|
-
validationStateReader : this.deps.validationStateReader,
|
|
237
|
+
return this.queryRecordsWithVisibleControlFiltering({
|
|
206
238
|
tenant,
|
|
207
|
-
|
|
239
|
+
recordsQuery,
|
|
240
|
+
requester,
|
|
241
|
+
filters: [filter],
|
|
208
242
|
messageSort,
|
|
209
243
|
pagination,
|
|
210
|
-
messageTimestamp : recordsQuery.message.descriptor.messageTimestamp,
|
|
211
244
|
});
|
|
212
245
|
}
|
|
213
246
|
|
|
247
|
+
private async queryRecordsWithVisibleControlFiltering(input: {
|
|
248
|
+
tenant: string;
|
|
249
|
+
recordsQuery: RecordsQuery;
|
|
250
|
+
requester: string | undefined;
|
|
251
|
+
filters: Filter[];
|
|
252
|
+
messageSort: MessageSort;
|
|
253
|
+
pagination?: { cursor?: PaginationCursor; limit?: number };
|
|
254
|
+
}): Promise<{ messages: RecordsQueryReplyEntry[], cursor?: PaginationCursor }> {
|
|
255
|
+
const {
|
|
256
|
+
tenant, recordsQuery, requester, filters, messageSort, pagination
|
|
257
|
+
} = input;
|
|
258
|
+
const controlFilters = Records.buildControlRecordsFilters(filters);
|
|
259
|
+
const currentAudienceRecordIdCache = new Map<string, string | undefined>();
|
|
260
|
+
if (controlFilters.length === 0) {
|
|
261
|
+
const result = await queryRecordsWithRecordLimitOccupancy({
|
|
262
|
+
messageStore : this.deps.messageStore,
|
|
263
|
+
validationStateReader : this.deps.validationStateReader,
|
|
264
|
+
tenant,
|
|
265
|
+
filters,
|
|
266
|
+
messageSort,
|
|
267
|
+
pagination,
|
|
268
|
+
messageTimestamp : recordsQuery.message.descriptor.messageTimestamp,
|
|
269
|
+
});
|
|
270
|
+
return EncryptionControl.projectCurrentAudienceRecordPage({
|
|
271
|
+
messageStore : this.deps.messageStore,
|
|
272
|
+
tenant,
|
|
273
|
+
filters,
|
|
274
|
+
currentAudienceRecordIdCache,
|
|
275
|
+
result : {
|
|
276
|
+
messages : result.messages as RecordsQueryReplyEntry[],
|
|
277
|
+
cursor : result.cursor,
|
|
278
|
+
},
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (pagination?.limit === undefined || pagination.limit <= 0) {
|
|
283
|
+
const result = await queryRecordsWithRecordLimitOccupancy({
|
|
284
|
+
messageStore : this.deps.messageStore,
|
|
285
|
+
validationStateReader : this.deps.validationStateReader,
|
|
286
|
+
tenant,
|
|
287
|
+
filters,
|
|
288
|
+
messageSort,
|
|
289
|
+
pagination,
|
|
290
|
+
messageTimestamp : recordsQuery.message.descriptor.messageTimestamp,
|
|
291
|
+
});
|
|
292
|
+
const projectedResult = await EncryptionControl.projectCurrentAudienceRecordPage({
|
|
293
|
+
messageStore : this.deps.messageStore,
|
|
294
|
+
tenant,
|
|
295
|
+
filters,
|
|
296
|
+
currentAudienceRecordIdCache,
|
|
297
|
+
result : {
|
|
298
|
+
messages : result.messages as RecordsQueryReplyEntry[],
|
|
299
|
+
cursor : result.cursor,
|
|
300
|
+
},
|
|
301
|
+
});
|
|
302
|
+
return {
|
|
303
|
+
messages : await this.filterControlRecordsForRequester(tenant, recordsQuery, requester, projectedResult.messages),
|
|
304
|
+
cursor : projectedResult.cursor,
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
const visibleMessages: RecordsQueryReplyEntry[] = [];
|
|
309
|
+
let cursor = pagination.cursor;
|
|
310
|
+
let nextCursor: PaginationCursor | undefined;
|
|
311
|
+
// Keeps visible-page pagination stable until #1100 moves control visibility into indexed store filters.
|
|
312
|
+
do {
|
|
313
|
+
const remainingLimit = pagination.limit - visibleMessages.length;
|
|
314
|
+
const result = await queryRecordsWithRecordLimitOccupancy({
|
|
315
|
+
messageStore : this.deps.messageStore,
|
|
316
|
+
validationStateReader : this.deps.validationStateReader,
|
|
317
|
+
tenant,
|
|
318
|
+
filters,
|
|
319
|
+
messageSort,
|
|
320
|
+
pagination : { ...pagination, cursor, limit: remainingLimit },
|
|
321
|
+
messageTimestamp : recordsQuery.message.descriptor.messageTimestamp,
|
|
322
|
+
});
|
|
323
|
+
const projectedResult = await EncryptionControl.projectCurrentAudienceRecordPage({
|
|
324
|
+
messageStore : this.deps.messageStore,
|
|
325
|
+
tenant,
|
|
326
|
+
filters,
|
|
327
|
+
currentAudienceRecordIdCache,
|
|
328
|
+
result : {
|
|
329
|
+
messages : result.messages as RecordsQueryReplyEntry[],
|
|
330
|
+
cursor : result.cursor,
|
|
331
|
+
},
|
|
332
|
+
});
|
|
333
|
+
const filteredMessages = await this.filterControlRecordsForRequester(
|
|
334
|
+
tenant,
|
|
335
|
+
recordsQuery,
|
|
336
|
+
requester,
|
|
337
|
+
projectedResult.messages,
|
|
338
|
+
);
|
|
339
|
+
visibleMessages.push(...filteredMessages);
|
|
340
|
+
nextCursor = projectedResult.cursor;
|
|
341
|
+
cursor = projectedResult.cursor;
|
|
342
|
+
} while (visibleMessages.length < pagination.limit && cursor !== undefined);
|
|
343
|
+
|
|
344
|
+
return { messages: visibleMessages, cursor: nextCursor };
|
|
345
|
+
}
|
|
346
|
+
|
|
214
347
|
private static buildPublishedRecordsFilter(recordsQuery: RecordsQuery): Filter {
|
|
215
348
|
const { dateSort, filter } = recordsQuery.message.descriptor;
|
|
216
349
|
// fetch all published records matching the query
|
|
@@ -293,8 +426,16 @@ export class RecordsQueryHandler implements MethodHandler {
|
|
|
293
426
|
deps: HandlerDependencies,
|
|
294
427
|
): Promise<void> {
|
|
295
428
|
|
|
296
|
-
if (Message.isSignedByAuthorDelegate(recordsQuery.message)
|
|
429
|
+
if (Message.isSignedByAuthorDelegate(recordsQuery.message) &&
|
|
430
|
+
!EncryptionControl.filterTargetsOnlyControlRecords(recordsQuery.message.descriptor.filter)) {
|
|
297
431
|
await recordsQuery.authorizeDelegate(deps.validationStateReader);
|
|
432
|
+
} else if (EncryptionControl.filterTargetsOnlyControlRecords(recordsQuery.message.descriptor.filter)) {
|
|
433
|
+
await EncryptionControl.authorizeControlReadRequest({
|
|
434
|
+
tenant,
|
|
435
|
+
incomingMessage : recordsQuery.message,
|
|
436
|
+
requester : Message.getRequester(recordsQuery.message),
|
|
437
|
+
validationStateReader : deps.validationStateReader,
|
|
438
|
+
});
|
|
298
439
|
}
|
|
299
440
|
|
|
300
441
|
const permissionGrantId = Message.getPermissionGrantId(recordsQuery.signaturePayload!);
|
|
@@ -317,4 +458,19 @@ export class RecordsQueryHandler implements MethodHandler {
|
|
|
317
458
|
await ProtocolAuthorization.authorizeQueryOrSubscribe(tenant, recordsQuery, deps.validationStateReader);
|
|
318
459
|
}
|
|
319
460
|
}
|
|
461
|
+
|
|
462
|
+
private async filterControlRecordsForRequester(
|
|
463
|
+
tenant: string,
|
|
464
|
+
recordsQuery: RecordsQuery,
|
|
465
|
+
requester: string | undefined,
|
|
466
|
+
recordsWrites: RecordsQueryReplyEntry[],
|
|
467
|
+
): Promise<RecordsQueryReplyEntry[]> {
|
|
468
|
+
return EncryptionControl.filterVisibleControlRecords({
|
|
469
|
+
tenant,
|
|
470
|
+
incomingMessage : recordsQuery.message,
|
|
471
|
+
requester,
|
|
472
|
+
recordsWriteMessages : recordsWrites,
|
|
473
|
+
validationStateReader : this.deps.validationStateReader,
|
|
474
|
+
});
|
|
475
|
+
}
|
|
320
476
|
}
|
|
@@ -5,6 +5,7 @@ import type { RecordsDeleteMessage, RecordsQueryReplyEntry, RecordsReadMessage,
|
|
|
5
5
|
import { authenticate } from '../core/auth.js';
|
|
6
6
|
import { DataStream } from '../utils/data-stream.js';
|
|
7
7
|
import { Encoder } from '../utils/encoder.js';
|
|
8
|
+
import { EncryptionControl } from '../core/encryption-control.js';
|
|
8
9
|
import { isRecordLimitOccupant } from '../utils/record-limit-occupancy.js';
|
|
9
10
|
import { Message } from '../core/message.js';
|
|
10
11
|
import { messageReplyFromError } from '../core/message-reply.js';
|
|
@@ -178,14 +179,26 @@ export class RecordsReadHandler implements MethodHandler {
|
|
|
178
179
|
matchedRecordsWrite: RecordsWrite,
|
|
179
180
|
deps: HandlerDependencies,
|
|
180
181
|
): Promise<void> {
|
|
181
|
-
if (Message.isSignedByAuthorDelegate(recordsRead.message)) {
|
|
182
|
-
await recordsRead.authorizeDelegate(matchedRecordsWrite.message, deps.validationStateReader);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
182
|
const { descriptor } = matchedRecordsWrite.message;
|
|
186
183
|
|
|
187
|
-
|
|
188
|
-
|
|
184
|
+
if (EncryptionControl.isControlMessage(matchedRecordsWrite.message)) {
|
|
185
|
+
await EncryptionControl.authorizeControlReadRequest({
|
|
186
|
+
tenant,
|
|
187
|
+
incomingMessage : recordsRead.message,
|
|
188
|
+
requester : Message.getRequester(recordsRead.message),
|
|
189
|
+
validationStateReader : deps.validationStateReader,
|
|
190
|
+
});
|
|
191
|
+
await EncryptionControl.authorizeRead({
|
|
192
|
+
tenant,
|
|
193
|
+
incomingMessage : recordsRead.message,
|
|
194
|
+
requester : Message.getRequester(recordsRead.message),
|
|
195
|
+
recordsWriteMessage : matchedRecordsWrite.message,
|
|
196
|
+
validationStateReader : deps.validationStateReader,
|
|
197
|
+
});
|
|
198
|
+
} else if (Message.isSignedByAuthorDelegate(recordsRead.message)) {
|
|
199
|
+
await recordsRead.authorizeDelegate(matchedRecordsWrite.message, deps.validationStateReader);
|
|
200
|
+
} else if (recordsRead.author === tenant) {
|
|
201
|
+
// if author is the same as the target tenant, we can directly grant access
|
|
189
202
|
return;
|
|
190
203
|
} else if (descriptor.published === true) {
|
|
191
204
|
// authentication is not required for published data
|