mindoodb 0.0.23 → 0.0.32
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-server.md +9 -1
- package/README.md +5 -3
- package/dist/appendonlystores/network/ClientNetworkContentAddressedStore.d.ts +1 -1
- package/dist/appendonlystores/network/ClientNetworkContentAddressedStore.d.ts.map +1 -1
- package/dist/appendonlystores/network/ClientNetworkContentAddressedStore.js +24 -5
- package/dist/appendonlystores/network/ClientNetworkContentAddressedStore.js.map +1 -1
- package/dist/appendonlystores/network/HttpTransport.d.ts +14 -2
- package/dist/appendonlystores/network/HttpTransport.d.ts.map +1 -1
- package/dist/appendonlystores/network/HttpTransport.js +124 -27
- package/dist/appendonlystores/network/HttpTransport.js.map +1 -1
- package/dist/appendonlystores/network/ServerNetworkContentAddressedStore.d.ts +159 -4
- package/dist/appendonlystores/network/ServerNetworkContentAddressedStore.d.ts.map +1 -1
- package/dist/appendonlystores/network/ServerNetworkContentAddressedStore.js +334 -25
- package/dist/appendonlystores/network/ServerNetworkContentAddressedStore.js.map +1 -1
- package/dist/browser/appendonlystores/IndexedDBContentAddressedStore.d.ts +9 -0
- package/dist/browser/appendonlystores/IndexedDBContentAddressedStore.d.ts.map +1 -1
- package/dist/browser/appendonlystores/IndexedDBContentAddressedStore.js +77 -5
- package/dist/browser/appendonlystores/IndexedDBContentAddressedStore.js.map +1 -1
- package/dist/browser/index.mjs +103 -0
- package/dist/core/BaseMindooDB.d.ts +697 -4
- package/dist/core/BaseMindooDB.d.ts.map +1 -1
- package/dist/core/BaseMindooDB.js +3273 -180
- package/dist/core/BaseMindooDB.js.map +1 -1
- package/dist/core/BaseMindooTenant.d.ts +192 -1
- package/dist/core/BaseMindooTenant.d.ts.map +1 -1
- package/dist/core/BaseMindooTenant.js +633 -88
- package/dist/core/BaseMindooTenant.js.map +1 -1
- package/dist/core/BaseMindooTenantDirectory.d.ts +770 -10
- package/dist/core/BaseMindooTenantDirectory.d.ts.map +1 -1
- package/dist/core/BaseMindooTenantDirectory.js +2715 -292
- package/dist/core/BaseMindooTenantDirectory.js.map +1 -1
- package/dist/core/BaseMindooTenantFactory.d.ts +2 -0
- package/dist/core/BaseMindooTenantFactory.d.ts.map +1 -1
- package/dist/core/BaseMindooTenantFactory.js +20 -0
- package/dist/core/BaseMindooTenantFactory.js.map +1 -1
- package/dist/core/accesscontrol/AccessDeniedError.d.ts +22 -0
- package/dist/core/accesscontrol/AccessDeniedError.d.ts.map +1 -0
- package/dist/core/accesscontrol/AccessDeniedError.js +28 -0
- package/dist/core/accesscontrol/AccessDeniedError.js.map +1 -0
- package/dist/core/accesscontrol/DirectoryStateNode.d.ts +220 -0
- package/dist/core/accesscontrol/DirectoryStateNode.d.ts.map +1 -0
- package/dist/core/accesscontrol/DirectoryStateNode.js +297 -0
- package/dist/core/accesscontrol/DirectoryStateNode.js.map +1 -0
- package/dist/core/accesscontrol/DirectoryTimeTravelIndex.d.ts +118 -0
- package/dist/core/accesscontrol/DirectoryTimeTravelIndex.d.ts.map +1 -0
- package/dist/core/accesscontrol/DirectoryTimeTravelIndex.js +173 -0
- package/dist/core/accesscontrol/DirectoryTimeTravelIndex.js.map +1 -0
- package/dist/core/accesscontrol/directoryProjection.d.ts +26 -0
- package/dist/core/accesscontrol/directoryProjection.d.ts.map +1 -0
- package/dist/core/accesscontrol/directoryProjection.js +174 -0
- package/dist/core/accesscontrol/directoryProjection.js.map +1 -0
- package/dist/core/accesscontrol/evaluate.d.ts +77 -0
- package/dist/core/accesscontrol/evaluate.d.ts.map +1 -0
- package/dist/core/accesscontrol/evaluate.js +206 -0
- package/dist/core/accesscontrol/evaluate.js.map +1 -0
- package/dist/core/accesscontrol/grantKeys.d.ts +113 -0
- package/dist/core/accesscontrol/grantKeys.d.ts.map +1 -0
- package/dist/core/accesscontrol/grantKeys.js +302 -0
- package/dist/core/accesscontrol/grantKeys.js.map +1 -0
- package/dist/core/accesscontrol/keyBagReconciler.d.ts +22 -0
- package/dist/core/accesscontrol/keyBagReconciler.d.ts.map +1 -0
- package/dist/core/accesscontrol/keyBagReconciler.js +3 -0
- package/dist/core/accesscontrol/keyBagReconciler.js.map +1 -0
- package/dist/core/accesscontrol/materializationGuard.d.ts +89 -0
- package/dist/core/accesscontrol/materializationGuard.d.ts.map +1 -0
- package/dist/core/accesscontrol/materializationGuard.js +69 -0
- package/dist/core/accesscontrol/materializationGuard.js.map +1 -0
- package/dist/core/accesscontrol/quarantine.d.ts +65 -0
- package/dist/core/accesscontrol/quarantine.d.ts.map +1 -0
- package/dist/core/accesscontrol/quarantine.js +79 -0
- package/dist/core/accesscontrol/quarantine.js.map +1 -0
- package/dist/core/accesscontrol/receiptValidation.d.ts +113 -0
- package/dist/core/accesscontrol/receiptValidation.d.ts.map +1 -0
- package/dist/core/accesscontrol/receiptValidation.js +142 -0
- package/dist/core/accesscontrol/receiptValidation.js.map +1 -0
- package/dist/core/accesscontrol/timestamp/Ed25519WitnessProvider.d.ts +31 -0
- package/dist/core/accesscontrol/timestamp/Ed25519WitnessProvider.d.ts.map +1 -0
- package/dist/core/accesscontrol/timestamp/Ed25519WitnessProvider.js +66 -0
- package/dist/core/accesscontrol/timestamp/Ed25519WitnessProvider.js.map +1 -0
- package/dist/core/accesscontrol/timestamp/TimestampProvider.d.ts +79 -0
- package/dist/core/accesscontrol/timestamp/TimestampProvider.d.ts.map +1 -0
- package/dist/core/accesscontrol/timestamp/TimestampProvider.js +22 -0
- package/dist/core/accesscontrol/timestamp/TimestampProvider.js.map +1 -0
- package/dist/core/accesscontrol/types.d.ts +825 -0
- package/dist/core/accesscontrol/types.d.ts.map +1 -0
- package/dist/core/accesscontrol/types.js +534 -0
- package/dist/core/accesscontrol/types.js.map +1 -0
- package/dist/core/appendonlystores/InMemoryContentAddressedStore.d.ts +9 -0
- package/dist/core/appendonlystores/InMemoryContentAddressedStore.d.ts.map +1 -1
- package/dist/core/appendonlystores/InMemoryContentAddressedStore.js +54 -0
- package/dist/core/appendonlystores/InMemoryContentAddressedStore.js.map +1 -1
- package/dist/core/appendonlystores/network/AuthenticationService.d.ts +38 -2
- package/dist/core/appendonlystores/network/AuthenticationService.d.ts.map +1 -1
- package/dist/core/appendonlystores/network/AuthenticationService.js +199 -26
- package/dist/core/appendonlystores/network/AuthenticationService.js.map +1 -1
- package/dist/core/appendonlystores/network/NetworkTransport.d.ts +17 -3
- package/dist/core/appendonlystores/network/NetworkTransport.d.ts.map +1 -1
- package/dist/core/appendonlystores/network/types.d.ts +58 -4
- package/dist/core/appendonlystores/network/types.d.ts.map +1 -1
- package/dist/core/appendonlystores/network/types.js +4 -0
- package/dist/core/appendonlystores/network/types.js.map +1 -1
- package/dist/core/appendonlystores/scanUtils.d.ts +27 -0
- package/dist/core/appendonlystores/scanUtils.d.ts.map +1 -0
- package/dist/core/appendonlystores/scanUtils.js +87 -0
- package/dist/core/appendonlystores/scanUtils.js.map +1 -0
- package/dist/core/appendonlystores/types.d.ts +23 -2
- package/dist/core/appendonlystores/types.d.ts.map +1 -1
- package/dist/core/cache/CacheManager.d.ts +13 -3
- package/dist/core/cache/CacheManager.d.ts.map +1 -1
- package/dist/core/cache/CacheManager.js +7 -4
- package/dist/core/cache/CacheManager.js.map +1 -1
- package/dist/core/crypto/EntrySignature.d.ts +137 -0
- package/dist/core/crypto/EntrySignature.d.ts.map +1 -0
- package/dist/core/crypto/EntrySignature.js +210 -0
- package/dist/core/crypto/EntrySignature.js.map +1 -0
- package/dist/core/crypto/MindooDocSigner.d.ts.map +1 -1
- package/dist/core/crypto/MindooDocSigner.js +6 -2
- package/dist/core/crypto/MindooDocSigner.js.map +1 -1
- package/dist/core/crypto/WitnessReceipt.d.ts +137 -0
- package/dist/core/crypto/WitnessReceipt.d.ts.map +1 -0
- package/dist/core/crypto/WitnessReceipt.js +182 -0
- package/dist/core/crypto/WitnessReceipt.js.map +1 -0
- package/dist/core/crypto/encryptedFields.d.ts +27 -0
- package/dist/core/crypto/encryptedFields.d.ts.map +1 -0
- package/dist/core/crypto/encryptedFields.js +58 -0
- package/dist/core/crypto/encryptedFields.js.map +1 -0
- package/dist/core/crypto/pbkdf2Iterations.d.ts +12 -0
- package/dist/core/crypto/pbkdf2Iterations.d.ts.map +1 -1
- package/dist/core/crypto/pbkdf2Iterations.js +23 -0
- package/dist/core/crypto/pbkdf2Iterations.js.map +1 -1
- package/dist/core/crypto/privateKeyEncryption.d.ts.map +1 -1
- package/dist/core/crypto/privateKeyEncryption.js +3 -1
- package/dist/core/crypto/privateKeyEncryption.js.map +1 -1
- package/dist/core/databaseIdValidation.d.ts +1 -1
- package/dist/core/databaseIdValidation.d.ts.map +1 -1
- package/dist/core/databaseIdValidation.js +4 -4
- package/dist/core/databaseIdValidation.js.map +1 -1
- package/dist/core/errors.d.ts +26 -0
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js +42 -1
- package/dist/core/errors.js.map +1 -1
- package/dist/core/expressions/builder.d.ts +102 -0
- package/dist/core/expressions/builder.d.ts.map +1 -0
- package/dist/core/expressions/builder.js +249 -0
- package/dist/core/expressions/builder.js.map +1 -0
- package/dist/core/expressions/evaluateExpression.d.ts +78 -0
- package/dist/core/expressions/evaluateExpression.d.ts.map +1 -0
- package/dist/core/expressions/evaluateExpression.js +386 -0
- package/dist/core/expressions/evaluateExpression.js.map +1 -0
- package/dist/core/expressions/formulaSource.d.ts +24 -0
- package/dist/core/expressions/formulaSource.d.ts.map +1 -0
- package/dist/core/expressions/formulaSource.js +765 -0
- package/dist/core/expressions/formulaSource.js.map +1 -0
- package/dist/core/expressions/index.d.ts +8 -0
- package/dist/core/expressions/index.d.ts.map +1 -0
- package/dist/core/expressions/index.js +46 -0
- package/dist/core/expressions/index.js.map +1 -0
- package/dist/core/expressions/metadata.d.ts +23 -0
- package/dist/core/expressions/metadata.d.ts.map +1 -0
- package/dist/core/expressions/metadata.js +191 -0
- package/dist/core/expressions/metadata.js.map +1 -0
- package/dist/core/expressions/types.d.ts +164 -0
- package/dist/core/expressions/types.d.ts.map +1 -0
- package/dist/core/expressions/types.js +3 -0
- package/dist/core/expressions/types.js.map +1 -0
- package/dist/core/extraction/types.d.ts +47 -0
- package/dist/core/extraction/types.d.ts.map +1 -0
- package/dist/core/extraction/types.js +42 -0
- package/dist/core/extraction/types.js.map +1 -0
- package/dist/core/index.d.ts +13 -3
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +113 -4
- package/dist/core/index.js.map +1 -1
- package/dist/core/indexing/createViewDataProvider.d.ts +84 -0
- package/dist/core/indexing/createViewDataProvider.d.ts.map +1 -0
- package/dist/core/indexing/createViewDataProvider.js +139 -0
- package/dist/core/indexing/createViewDataProvider.js.map +1 -0
- package/dist/core/indexing/fulltext/DocumentFullTextIndex.d.ts +180 -0
- package/dist/core/indexing/fulltext/DocumentFullTextIndex.d.ts.map +1 -0
- package/dist/core/indexing/fulltext/DocumentFullTextIndex.js +548 -0
- package/dist/core/indexing/fulltext/DocumentFullTextIndex.js.map +1 -0
- package/dist/core/indexing/fulltext/SearchEngineAdapter.d.ts +69 -0
- package/dist/core/indexing/fulltext/SearchEngineAdapter.d.ts.map +1 -0
- package/dist/core/indexing/fulltext/SearchEngineAdapter.js +183 -0
- package/dist/core/indexing/fulltext/SearchEngineAdapter.js.map +1 -0
- package/dist/core/indexing/fulltext/extractFulltextText.d.ts +34 -0
- package/dist/core/indexing/fulltext/extractFulltextText.d.ts.map +1 -0
- package/dist/core/indexing/fulltext/extractFulltextText.js +129 -0
- package/dist/core/indexing/fulltext/extractFulltextText.js.map +1 -0
- package/dist/core/indexing/fulltext/index.d.ts +5 -0
- package/dist/core/indexing/fulltext/index.d.ts.map +1 -0
- package/dist/core/indexing/fulltext/index.js +20 -0
- package/dist/core/indexing/fulltext/index.js.map +1 -0
- package/dist/core/indexing/fulltext/types.d.ts +168 -0
- package/dist/core/indexing/fulltext/types.d.ts.map +1 -0
- package/dist/core/indexing/fulltext/types.js +89 -0
- package/dist/core/indexing/fulltext/types.js.map +1 -0
- package/dist/core/indexing/summary/DocumentSummaryStore.d.ts +137 -0
- package/dist/core/indexing/summary/DocumentSummaryStore.d.ts.map +1 -0
- package/dist/core/indexing/summary/DocumentSummaryStore.js +438 -0
- package/dist/core/indexing/summary/DocumentSummaryStore.js.map +1 -0
- package/dist/core/indexing/summary/SummaryVirtualViewDataProvider.d.ts +72 -0
- package/dist/core/indexing/summary/SummaryVirtualViewDataProvider.d.ts.map +1 -0
- package/dist/core/indexing/summary/SummaryVirtualViewDataProvider.js +221 -0
- package/dist/core/indexing/summary/SummaryVirtualViewDataProvider.js.map +1 -0
- package/dist/core/indexing/summary/extractSummaryFields.d.ts +75 -0
- package/dist/core/indexing/summary/extractSummaryFields.d.ts.map +1 -0
- package/dist/core/indexing/summary/extractSummaryFields.js +266 -0
- package/dist/core/indexing/summary/extractSummaryFields.js.map +1 -0
- package/dist/core/indexing/summary/index.d.ts +5 -0
- package/dist/core/indexing/summary/index.d.ts.map +1 -0
- package/dist/core/indexing/summary/index.js +23 -0
- package/dist/core/indexing/summary/index.js.map +1 -0
- package/dist/core/indexing/summary/types.d.ts +119 -0
- package/dist/core/indexing/summary/types.d.ts.map +1 -0
- package/dist/core/indexing/summary/types.js +81 -0
- package/dist/core/indexing/summary/types.js.map +1 -0
- package/dist/core/indexing/virtualviews/IVirtualViewDataProvider.d.ts +47 -1
- package/dist/core/indexing/virtualviews/IVirtualViewDataProvider.d.ts.map +1 -1
- package/dist/core/indexing/virtualviews/MindooDBVirtualViewDataProvider.d.ts +24 -8
- package/dist/core/indexing/virtualviews/MindooDBVirtualViewDataProvider.d.ts.map +1 -1
- package/dist/core/indexing/virtualviews/MindooDBVirtualViewDataProvider.js +96 -41
- package/dist/core/indexing/virtualviews/MindooDBVirtualViewDataProvider.js.map +1 -1
- package/dist/core/indexing/virtualviews/ViewEntrySortKey.d.ts +2 -0
- package/dist/core/indexing/virtualviews/ViewEntrySortKey.d.ts.map +1 -1
- package/dist/core/indexing/virtualviews/ViewEntrySortKey.js +8 -3
- package/dist/core/indexing/virtualviews/ViewEntrySortKey.js.map +1 -1
- package/dist/core/indexing/virtualviews/VirtualView.d.ts +111 -5
- package/dist/core/indexing/virtualviews/VirtualView.d.ts.map +1 -1
- package/dist/core/indexing/virtualviews/VirtualView.js +266 -75
- package/dist/core/indexing/virtualviews/VirtualView.js.map +1 -1
- package/dist/core/indexing/virtualviews/VirtualViewColumn.d.ts +12 -0
- package/dist/core/indexing/virtualviews/VirtualViewColumn.d.ts.map +1 -1
- package/dist/core/indexing/virtualviews/VirtualViewColumn.js +1 -0
- package/dist/core/indexing/virtualviews/VirtualViewColumn.js.map +1 -1
- package/dist/core/indexing/virtualviews/VirtualViewEntryData.d.ts +12 -0
- package/dist/core/indexing/virtualviews/VirtualViewEntryData.d.ts.map +1 -1
- package/dist/core/indexing/virtualviews/VirtualViewEntryData.js +66 -5
- package/dist/core/indexing/virtualviews/VirtualViewEntryData.js.map +1 -1
- package/dist/core/indexing/virtualviews/VirtualViewFactory.d.ts +50 -6
- package/dist/core/indexing/virtualviews/VirtualViewFactory.d.ts.map +1 -1
- package/dist/core/indexing/virtualviews/VirtualViewFactory.js +54 -12
- package/dist/core/indexing/virtualviews/VirtualViewFactory.js.map +1 -1
- package/dist/core/indexing/virtualviews/index.d.ts +3 -3
- package/dist/core/indexing/virtualviews/index.d.ts.map +1 -1
- package/dist/core/indexing/virtualviews/index.js.map +1 -1
- package/dist/core/indexing/virtualviews/types.d.ts +6 -0
- package/dist/core/indexing/virtualviews/types.d.ts.map +1 -1
- package/dist/core/indexing/virtualviews/types.js +11 -3
- package/dist/core/indexing/virtualviews/types.js.map +1 -1
- package/dist/core/keys/KeyBag.d.ts +25 -0
- package/dist/core/keys/KeyBag.d.ts.map +1 -1
- package/dist/core/keys/KeyBag.js +37 -1
- package/dist/core/keys/KeyBag.js.map +1 -1
- package/dist/core/query/executeQuery.d.ts +18 -0
- package/dist/core/query/executeQuery.d.ts.map +1 -0
- package/dist/core/query/executeQuery.js +313 -0
- package/dist/core/query/executeQuery.js.map +1 -0
- package/dist/core/query/index.d.ts +5 -0
- package/dist/core/query/index.d.ts.map +1 -0
- package/dist/core/query/index.js +14 -0
- package/dist/core/query/index.js.map +1 -0
- package/dist/core/query/queryLive.d.ts +27 -0
- package/dist/core/query/queryLive.d.ts.map +1 -0
- package/dist/core/query/queryLive.js +104 -0
- package/dist/core/query/queryLive.js.map +1 -0
- package/dist/core/query/queryView.d.ts +156 -0
- package/dist/core/query/queryView.d.ts.map +1 -0
- package/dist/core/query/queryView.js +266 -0
- package/dist/core/query/queryView.js.map +1 -0
- package/dist/core/query/types.d.ts +121 -0
- package/dist/core/query/types.d.ts.map +1 -0
- package/dist/core/query/types.js +18 -0
- package/dist/core/query/types.js.map +1 -0
- package/dist/core/storeEntryTime.d.ts +57 -0
- package/dist/core/storeEntryTime.d.ts.map +1 -0
- package/dist/core/storeEntryTime.js +72 -0
- package/dist/core/storeEntryTime.js.map +1 -0
- package/dist/core/types.d.ts +1509 -39
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +13 -1
- package/dist/core/types.js.map +1 -1
- package/dist/core/uri/MindooURI.d.ts +53 -1
- package/dist/core/uri/MindooURI.d.ts.map +1 -1
- package/dist/core/uri/MindooURI.js +135 -0
- package/dist/core/uri/MindooURI.js.map +1 -1
- package/dist/core/utils/urlSafety.d.ts +46 -0
- package/dist/core/utils/urlSafety.d.ts.map +1 -0
- package/dist/core/utils/urlSafety.js +144 -0
- package/dist/core/utils/urlSafety.js.map +1 -0
- package/dist/node/appendonlystores/BasicOnDiskContentAddressedStore.d.ts +14 -0
- package/dist/node/appendonlystores/BasicOnDiskContentAddressedStore.d.ts.map +1 -1
- package/dist/node/appendonlystores/BasicOnDiskContentAddressedStore.js +95 -4
- package/dist/node/appendonlystores/BasicOnDiskContentAddressedStore.js.map +1 -1
- package/dist/node/server/CapabilityMatcher.d.ts +10 -0
- package/dist/node/server/CapabilityMatcher.d.ts.map +1 -1
- package/dist/node/server/CapabilityMatcher.js +14 -2
- package/dist/node/server/CapabilityMatcher.js.map +1 -1
- package/dist/node/server/MindooDBServer.d.ts.map +1 -1
- package/dist/node/server/MindooDBServer.js +117 -8
- package/dist/node/server/MindooDBServer.js.map +1 -1
- package/dist/node/server/PurgedDocRegistry.d.ts +32 -0
- package/dist/node/server/PurgedDocRegistry.d.ts.map +1 -0
- package/dist/node/server/PurgedDocRegistry.js +94 -0
- package/dist/node/server/PurgedDocRegistry.js.map +1 -0
- package/dist/node/server/ServerSync.d.ts.map +1 -1
- package/dist/node/server/ServerSync.js +5 -2
- package/dist/node/server/ServerSync.js.map +1 -1
- package/dist/node/server/SystemAdminAuth.d.ts +10 -0
- package/dist/node/server/SystemAdminAuth.d.ts.map +1 -1
- package/dist/node/server/SystemAdminAuth.js +25 -0
- package/dist/node/server/SystemAdminAuth.js.map +1 -1
- package/dist/node/server/TenantManager.d.ts +95 -1
- package/dist/node/server/TenantManager.d.ts.map +1 -1
- package/dist/node/server/TenantManager.js +382 -15
- package/dist/node/server/TenantManager.js.map +1 -1
- package/dist/node/server/config.d.ts.map +1 -1
- package/dist/node/server/config.js +5 -1
- package/dist/node/server/config.js.map +1 -1
- package/dist/node/server/types.d.ts +29 -3
- package/dist/node/server/types.d.ts.map +1 -1
- package/dist/node/server/types.js +12 -0
- package/dist/node/server/types.js.map +1 -1
- package/dist/node/server/validation.d.ts +6 -0
- package/dist/node/server/validation.d.ts.map +1 -1
- package/dist/node/server/validation.js +7 -1
- package/dist/node/server/validation.js.map +1 -1
- package/package.json +4 -3
- package/dist/appendonlystores/BasicOnDiskContentAddressedStoreFactory.d.ts +0 -8
- package/dist/appendonlystores/BasicOnDiskContentAddressedStoreFactory.d.ts.map +0 -1
- package/dist/appendonlystores/BasicOnDiskContentAddressedStoreFactory.js +0 -16
- package/dist/appendonlystores/BasicOnDiskContentAddressedStoreFactory.js.map +0 -1
- package/dist/core/appendonlystores/BasicOnDiskContentAddressedStore.d.ts +0 -68
- package/dist/core/appendonlystores/BasicOnDiskContentAddressedStore.d.ts.map +0 -1
- package/dist/core/appendonlystores/BasicOnDiskContentAddressedStore.js +0 -659
- package/dist/core/appendonlystores/BasicOnDiskContentAddressedStore.js.map +0 -1
- package/dist/node/attachments/writeAttachmentToFile.d.ts +0 -15
- package/dist/node/attachments/writeAttachmentToFile.d.ts.map +0 -1
- package/dist/node/attachments/writeAttachmentToFile.js +0 -73
- package/dist/node/attachments/writeAttachmentToFile.js.map +0 -1
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal (non-public) contract the tenant uses to drive the KeyBag import
|
|
3
|
+
* pass on its own directory (docs/accesscontrol.md §13).
|
|
4
|
+
*
|
|
5
|
+
* Deliberately NOT part of the public {@link MindooTenantDirectory} surface: the
|
|
6
|
+
* only reconcile entry point consumers see is
|
|
7
|
+
* `MindooTenant.reconcileKeyDistributionsForCurrentUser()`. The reconcile core
|
|
8
|
+
* sources its RSA-OAEP session key from the directory's own tenant, so no
|
|
9
|
+
* foreign decryption key is ever passed across an API boundary.
|
|
10
|
+
*/
|
|
11
|
+
export interface KeyBagReconciler {
|
|
12
|
+
/**
|
|
13
|
+
* Import the key versions pushed to `username` using the directory's OWN
|
|
14
|
+
* tenant session key, and remove pulled (revoked) ids. Returns the imported
|
|
15
|
+
* and removed key ids; both empty when the host is locked (no session key).
|
|
16
|
+
*/
|
|
17
|
+
reconcileImportedKeysForCurrentUser(username: string): Promise<{
|
|
18
|
+
imported: string[];
|
|
19
|
+
removed: string[];
|
|
20
|
+
}>;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=keyBagReconciler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keyBagReconciler.d.ts","sourceRoot":"","sources":["../../../src/core/accesscontrol/keyBagReconciler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;OAIG;IACH,mCAAmC,CACjC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;CACvD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keyBagReconciler.js","sourceRoot":"","sources":["../../../src/core/accesscontrol/keyBagReconciler.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { RuleType } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Pure helpers for client-side materialization defenses (docs/accesscontrol.md
|
|
4
|
+
* §10): mandatory snapshot head verification, op-type re-derivation, and the
|
|
5
|
+
* shape of the quarantine/audit log.
|
|
6
|
+
*
|
|
7
|
+
* Everything here is a pure function of its inputs so the materialization path
|
|
8
|
+
* stays deterministic across replicas — the property that makes "quarantine on
|
|
9
|
+
* receipt" safe under eventual consistency (§10).
|
|
10
|
+
*/
|
|
11
|
+
/** Why an entry was quarantined (for the audit log and tests). */
|
|
12
|
+
export type QuarantineReason = "tier2_denied" | "tier1_recheck_denied" | "snapshot_head_mismatch" | "snapshot_untrusted_head" | "op_type_mismatch" | "cascade_dependent" | "invalid_signature" | "invalid_witness_receipt" | "directory_unavailable";
|
|
13
|
+
/**
|
|
14
|
+
* One entry in the per-tenant quarantine/audit log (§10). Kept deliberately
|
|
15
|
+
* small and serializable so it can be surfaced in Haven's audit view and
|
|
16
|
+
* persisted alongside the store.
|
|
17
|
+
*/
|
|
18
|
+
export interface QuarantineRecord {
|
|
19
|
+
/** Store entry id that was quarantined. */
|
|
20
|
+
entryId: string;
|
|
21
|
+
/** Document the entry belonged to. */
|
|
22
|
+
docId: string;
|
|
23
|
+
/** Database id (sync context). */
|
|
24
|
+
dbid: string;
|
|
25
|
+
/** Signed operation type of the entry. */
|
|
26
|
+
entryType: string;
|
|
27
|
+
/** Why it was quarantined. */
|
|
28
|
+
reason: QuarantineReason;
|
|
29
|
+
/** Human-readable detail (e.g. the matched rule id / decision reason). */
|
|
30
|
+
detail: string;
|
|
31
|
+
/** Trusted time of the entry (`receivedAt ?? createdAt`). */
|
|
32
|
+
trustedTime: number;
|
|
33
|
+
/** When the quarantine decision was recorded locally (wall clock, audit only). */
|
|
34
|
+
recordedAt: number;
|
|
35
|
+
/** For cascades, the ancestor entry id that triggered this quarantine. */
|
|
36
|
+
causedByEntryId?: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Mandatory snapshot head verification (§10, "Snapshots"). A `doc_snapshot` is
|
|
40
|
+
* only trustworthy if the Automerge heads of the **decoded** snapshot exactly
|
|
41
|
+
* equal the covered dep heads declared in the store entry's
|
|
42
|
+
* `snapshotHeadHashes`. This prevents a snapshot from smuggling content the
|
|
43
|
+
* author was not allowed to write under the guise of a checkpoint.
|
|
44
|
+
*
|
|
45
|
+
* The comparison is order-independent (heads are a set) and exact (no missing
|
|
46
|
+
* or extra heads allowed).
|
|
47
|
+
*
|
|
48
|
+
* @param decodedHeads Automerge heads of the decoded snapshot document.
|
|
49
|
+
* @param declaredHeads `snapshotHeadHashes` from the signed store metadata.
|
|
50
|
+
* @returns true iff the two describe the identical set of heads.
|
|
51
|
+
*/
|
|
52
|
+
export declare function snapshotHeadsMatch(decodedHeads: readonly string[], declaredHeads: readonly string[] | undefined): boolean;
|
|
53
|
+
/** Inputs needed to re-derive an entry's operation type from its decoded change. */
|
|
54
|
+
export interface OpTypeDerivationInput {
|
|
55
|
+
/**
|
|
56
|
+
* Whether this change is the document's genesis change (no in-document
|
|
57
|
+
* Automerge parents). The first change of a document is a `doc_create`.
|
|
58
|
+
*/
|
|
59
|
+
isGenesis: boolean;
|
|
60
|
+
/** Whether the document was deleted in the `before` (pre-change) state. */
|
|
61
|
+
beforeDeleted: boolean;
|
|
62
|
+
/** Whether the document is deleted in the `after` (post-change) state. */
|
|
63
|
+
afterDeleted: boolean;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Re-derive the operation type from the decoded change + lifecycle transition,
|
|
67
|
+
* independent of the signed `entryType` (§10, defense in depth). Used to reject
|
|
68
|
+
* an entry whose signed `entryType` was relabeled (e.g. a `doc_delete` disguised
|
|
69
|
+
* as a `doc_change` to dodge a delete rule).
|
|
70
|
+
*
|
|
71
|
+
* Derivation:
|
|
72
|
+
* - genesis change → `doc_create`
|
|
73
|
+
* - not-deleted → deleted → `doc_delete`
|
|
74
|
+
* - deleted → not-deleted → `doc_undelete`
|
|
75
|
+
* - otherwise → `doc_change`
|
|
76
|
+
*
|
|
77
|
+
* `doc_snapshot` is not a data-change and is derived/validated separately
|
|
78
|
+
* (snapshot head match), so it is not produced here.
|
|
79
|
+
*/
|
|
80
|
+
export declare function deriveDataOpType(input: OpTypeDerivationInput): RuleType;
|
|
81
|
+
/**
|
|
82
|
+
* Whether a signed `entryType` is consistent with the type re-derived from the
|
|
83
|
+
* decoded change (§10). A `doc_create` and `doc_change` are *both* acceptable
|
|
84
|
+
* labels for a genesis-or-normal mutation only when they agree; delete and
|
|
85
|
+
* undelete must match exactly. We treat any disagreement as a mismatch (the
|
|
86
|
+
* safe, fail-closed choice).
|
|
87
|
+
*/
|
|
88
|
+
export declare function opTypeMatches(signedEntryType: string, derived: RuleType): boolean;
|
|
89
|
+
//# sourceMappingURL=materializationGuard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"materializationGuard.d.ts","sourceRoot":"","sources":["../../../src/core/accesscontrol/materializationGuard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC;;;;;;;;GAQG;AAEH,kEAAkE;AAClE,MAAM,MAAM,gBAAgB,GACxB,cAAc,GACd,sBAAsB,GACtB,wBAAwB,GACxB,yBAAyB,GACzB,kBAAkB,GAClB,mBAAmB,GACnB,mBAAmB,GACnB,yBAAyB,GAKzB,uBAAuB,CAAC;AAE5B;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,2CAA2C;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,0CAA0C;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,8BAA8B;IAC9B,MAAM,EAAE,gBAAgB,CAAC;IACzB,0EAA0E;IAC1E,MAAM,EAAE,MAAM,CAAC;IACf,6DAA6D;IAC7D,WAAW,EAAE,MAAM,CAAC;IACpB,kFAAkF;IAClF,UAAU,EAAE,MAAM,CAAC;IACnB,0EAA0E;IAC1E,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAChC,YAAY,EAAE,SAAS,MAAM,EAAE,EAC/B,aAAa,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,GAC3C,OAAO,CAYT;AAED,oFAAoF;AACpF,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,SAAS,EAAE,OAAO,CAAC;IACnB,2EAA2E;IAC3E,aAAa,EAAE,OAAO,CAAC;IACvB,0EAA0E;IAC1E,YAAY,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,qBAAqB,GAAG,QAAQ,CAKvE;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,eAAe,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,GAAG,OAAO,CAEjF"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.snapshotHeadsMatch = snapshotHeadsMatch;
|
|
4
|
+
exports.deriveDataOpType = deriveDataOpType;
|
|
5
|
+
exports.opTypeMatches = opTypeMatches;
|
|
6
|
+
/**
|
|
7
|
+
* Mandatory snapshot head verification (§10, "Snapshots"). A `doc_snapshot` is
|
|
8
|
+
* only trustworthy if the Automerge heads of the **decoded** snapshot exactly
|
|
9
|
+
* equal the covered dep heads declared in the store entry's
|
|
10
|
+
* `snapshotHeadHashes`. This prevents a snapshot from smuggling content the
|
|
11
|
+
* author was not allowed to write under the guise of a checkpoint.
|
|
12
|
+
*
|
|
13
|
+
* The comparison is order-independent (heads are a set) and exact (no missing
|
|
14
|
+
* or extra heads allowed).
|
|
15
|
+
*
|
|
16
|
+
* @param decodedHeads Automerge heads of the decoded snapshot document.
|
|
17
|
+
* @param declaredHeads `snapshotHeadHashes` from the signed store metadata.
|
|
18
|
+
* @returns true iff the two describe the identical set of heads.
|
|
19
|
+
*/
|
|
20
|
+
function snapshotHeadsMatch(decodedHeads, declaredHeads) {
|
|
21
|
+
const declared = declaredHeads ?? [];
|
|
22
|
+
if (decodedHeads.length !== declared.length)
|
|
23
|
+
return false;
|
|
24
|
+
const declaredSet = new Set(declared);
|
|
25
|
+
if (declaredSet.size !== declared.length) {
|
|
26
|
+
// Duplicate declared heads are malformed; require a clean set.
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
for (const head of decodedHeads) {
|
|
30
|
+
if (!declaredSet.has(head))
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Re-derive the operation type from the decoded change + lifecycle transition,
|
|
37
|
+
* independent of the signed `entryType` (§10, defense in depth). Used to reject
|
|
38
|
+
* an entry whose signed `entryType` was relabeled (e.g. a `doc_delete` disguised
|
|
39
|
+
* as a `doc_change` to dodge a delete rule).
|
|
40
|
+
*
|
|
41
|
+
* Derivation:
|
|
42
|
+
* - genesis change → `doc_create`
|
|
43
|
+
* - not-deleted → deleted → `doc_delete`
|
|
44
|
+
* - deleted → not-deleted → `doc_undelete`
|
|
45
|
+
* - otherwise → `doc_change`
|
|
46
|
+
*
|
|
47
|
+
* `doc_snapshot` is not a data-change and is derived/validated separately
|
|
48
|
+
* (snapshot head match), so it is not produced here.
|
|
49
|
+
*/
|
|
50
|
+
function deriveDataOpType(input) {
|
|
51
|
+
if (input.isGenesis)
|
|
52
|
+
return "doc_create";
|
|
53
|
+
if (!input.beforeDeleted && input.afterDeleted)
|
|
54
|
+
return "doc_delete";
|
|
55
|
+
if (input.beforeDeleted && !input.afterDeleted)
|
|
56
|
+
return "doc_undelete";
|
|
57
|
+
return "doc_change";
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Whether a signed `entryType` is consistent with the type re-derived from the
|
|
61
|
+
* decoded change (§10). A `doc_create` and `doc_change` are *both* acceptable
|
|
62
|
+
* labels for a genesis-or-normal mutation only when they agree; delete and
|
|
63
|
+
* undelete must match exactly. We treat any disagreement as a mismatch (the
|
|
64
|
+
* safe, fail-closed choice).
|
|
65
|
+
*/
|
|
66
|
+
function opTypeMatches(signedEntryType, derived) {
|
|
67
|
+
return signedEntryType === derived;
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=materializationGuard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"materializationGuard.js","sourceRoot":"","sources":["../../../src/core/accesscontrol/materializationGuard.ts"],"names":[],"mappings":";;AAoEA,gDAeC;AA8BD,4CAKC;AASD,sCAEC;AA3ED;;;;;;;;;;;;;GAaG;AACH,SAAgB,kBAAkB,CAChC,YAA+B,EAC/B,aAA4C;IAE5C,MAAM,QAAQ,GAAG,aAAa,IAAI,EAAE,CAAC;IACrC,IAAI,YAAY,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAC1D,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC;IACtC,IAAI,WAAW,CAAC,IAAI,KAAK,QAAQ,CAAC,MAAM,EAAE,CAAC;QACzC,+DAA+D;QAC/D,OAAO,KAAK,CAAC;IACf,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;QAChC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,OAAO,KAAK,CAAC;IAC3C,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAeD;;;;;;;;;;;;;;GAcG;AACH,SAAgB,gBAAgB,CAAC,KAA4B;IAC3D,IAAI,KAAK,CAAC,SAAS;QAAE,OAAO,YAAY,CAAC;IACzC,IAAI,CAAC,KAAK,CAAC,aAAa,IAAI,KAAK,CAAC,YAAY;QAAE,OAAO,YAAY,CAAC;IACpE,IAAI,KAAK,CAAC,aAAa,IAAI,CAAC,KAAK,CAAC,YAAY;QAAE,OAAO,cAAc,CAAC;IACtE,OAAO,YAAY,CAAC;AACtB,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,aAAa,CAAC,eAAuB,EAAE,OAAiB;IACtE,OAAO,eAAe,KAAK,OAAO,CAAC;AACrC,CAAC"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { QuarantineRecord } from "./materializationGuard";
|
|
2
|
+
/**
|
|
3
|
+
* Deterministic cascade-quarantine engine (docs/accesscontrol.md §10).
|
|
4
|
+
*
|
|
5
|
+
* When an entry is quarantined, every entry that causally depends on it
|
|
6
|
+
* (transitively, via Automerge change deps) must also be quarantined — a
|
|
7
|
+
* replica never materializes a change whose ancestor it rejected. The accepted
|
|
8
|
+
* set is therefore always a **causally-closed prefix**, identical across
|
|
9
|
+
* replicas that have synced to the same point.
|
|
10
|
+
*
|
|
11
|
+
* This module is a pure function of (entries, per-entry verdict): no I/O, no
|
|
12
|
+
* wall clock. The verdict callback supplies the Tier 2 / op-type / snapshot
|
|
13
|
+
* decision for an entry that has no quarantined ancestors; the cascade is
|
|
14
|
+
* handled here. Keeping it pure is what guarantees cross-replica convergence.
|
|
15
|
+
*/
|
|
16
|
+
/** Minimal entry shape the cascade engine needs. */
|
|
17
|
+
export interface QuarantineCandidate {
|
|
18
|
+
/** Store entry id. */
|
|
19
|
+
id: string;
|
|
20
|
+
/** Document id. */
|
|
21
|
+
docId: string;
|
|
22
|
+
/** Entry ids this entry causally depends on (Automerge deps, store ids). */
|
|
23
|
+
dependencyIds: string[];
|
|
24
|
+
/** Signed operation type. */
|
|
25
|
+
entryType: string;
|
|
26
|
+
/** Trusted time (`receivedAt ?? createdAt`); used only for stable ordering. */
|
|
27
|
+
trustedTime: number;
|
|
28
|
+
}
|
|
29
|
+
/** A verdict for a single entry whose ancestors were all accepted. */
|
|
30
|
+
export interface EntryVerdict {
|
|
31
|
+
/** Whether the entry is accepted (materialized). */
|
|
32
|
+
accepted: boolean;
|
|
33
|
+
/** When rejected, the audit record (without cascade bookkeeping). */
|
|
34
|
+
record?: Omit<QuarantineRecord, "recordedAt" | "causedByEntryId">;
|
|
35
|
+
}
|
|
36
|
+
/** Result of {@link computeAcceptedSet}. */
|
|
37
|
+
export interface AcceptedSetResult {
|
|
38
|
+
/** Ids that are accepted (and may be materialized), in input order. */
|
|
39
|
+
acceptedIds: string[];
|
|
40
|
+
/** Ids that are quarantined (direct violation or cascade). */
|
|
41
|
+
quarantinedIds: string[];
|
|
42
|
+
/** Audit records for every quarantined entry. */
|
|
43
|
+
records: QuarantineRecord[];
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Deterministic order for evaluation: ascending trusted time, then entry id as
|
|
47
|
+
* a stable tie-breaker. Mirrors the directory/materialization ordering so every
|
|
48
|
+
* replica evaluates entries in the same sequence (§10).
|
|
49
|
+
*/
|
|
50
|
+
export declare function sortForEvaluation<T extends QuarantineCandidate>(entries: readonly T[]): T[];
|
|
51
|
+
/**
|
|
52
|
+
* Compute the causally-closed accepted set and the quarantine records.
|
|
53
|
+
*
|
|
54
|
+
* Entries are evaluated in deterministic trusted-time order. An entry is
|
|
55
|
+
* quarantined if (a) any of its dependencies was quarantined (cascade), or
|
|
56
|
+
* (b) the verdict callback rejects it. Cascade quarantines reference the first
|
|
57
|
+
* quarantined ancestor that caused them, for the audit trail.
|
|
58
|
+
*
|
|
59
|
+
* @param entries The candidate entries (any order; sorted internally).
|
|
60
|
+
* @param verdictFor Decides an entry assuming its ancestors are all accepted.
|
|
61
|
+
* Only called for entries with no quarantined dependency.
|
|
62
|
+
* @param now Wall-clock timestamp for audit records (not used in any decision).
|
|
63
|
+
*/
|
|
64
|
+
export declare function computeAcceptedSet(entries: readonly QuarantineCandidate[], verdictFor: (entry: QuarantineCandidate) => EntryVerdict, now: number): AcceptedSetResult;
|
|
65
|
+
//# sourceMappingURL=quarantine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quarantine.d.ts","sourceRoot":"","sources":["../../../src/core/accesscontrol/quarantine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE1D;;;;;;;;;;;;;GAaG;AAEH,oDAAoD;AACpD,MAAM,WAAW,mBAAmB;IAClC,sBAAsB;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,mBAAmB;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,4EAA4E;IAC5E,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,6BAA6B;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,+EAA+E;IAC/E,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,sEAAsE;AACtE,MAAM,WAAW,YAAY;IAC3B,oDAAoD;IACpD,QAAQ,EAAE,OAAO,CAAC;IAClB,qEAAqE;IACrE,MAAM,CAAC,EAAE,IAAI,CAAC,gBAAgB,EAAE,YAAY,GAAG,iBAAiB,CAAC,CAAC;CACnE;AAED,4CAA4C;AAC5C,MAAM,WAAW,iBAAiB;IAChC,uEAAuE;IACvE,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,8DAA8D;IAC9D,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,iDAAiD;IACjD,OAAO,EAAE,gBAAgB,EAAE,CAAC;CAC7B;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,mBAAmB,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,GAAG,CAAC,EAAE,CAI3F;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,SAAS,mBAAmB,EAAE,EACvC,UAAU,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,YAAY,EACxD,GAAG,EAAE,MAAM,GACV,iBAAiB,CAuDnB"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sortForEvaluation = sortForEvaluation;
|
|
4
|
+
exports.computeAcceptedSet = computeAcceptedSet;
|
|
5
|
+
/**
|
|
6
|
+
* Deterministic order for evaluation: ascending trusted time, then entry id as
|
|
7
|
+
* a stable tie-breaker. Mirrors the directory/materialization ordering so every
|
|
8
|
+
* replica evaluates entries in the same sequence (§10).
|
|
9
|
+
*/
|
|
10
|
+
function sortForEvaluation(entries) {
|
|
11
|
+
return [...entries].sort((a, b) => a.trustedTime === b.trustedTime ? a.id.localeCompare(b.id) : a.trustedTime - b.trustedTime);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Compute the causally-closed accepted set and the quarantine records.
|
|
15
|
+
*
|
|
16
|
+
* Entries are evaluated in deterministic trusted-time order. An entry is
|
|
17
|
+
* quarantined if (a) any of its dependencies was quarantined (cascade), or
|
|
18
|
+
* (b) the verdict callback rejects it. Cascade quarantines reference the first
|
|
19
|
+
* quarantined ancestor that caused them, for the audit trail.
|
|
20
|
+
*
|
|
21
|
+
* @param entries The candidate entries (any order; sorted internally).
|
|
22
|
+
* @param verdictFor Decides an entry assuming its ancestors are all accepted.
|
|
23
|
+
* Only called for entries with no quarantined dependency.
|
|
24
|
+
* @param now Wall-clock timestamp for audit records (not used in any decision).
|
|
25
|
+
*/
|
|
26
|
+
function computeAcceptedSet(entries, verdictFor, now) {
|
|
27
|
+
const ordered = sortForEvaluation(entries);
|
|
28
|
+
const acceptedIds = [];
|
|
29
|
+
const quarantinedIds = [];
|
|
30
|
+
const records = [];
|
|
31
|
+
// entry id -> the quarantined-ancestor id that taints it (for cascades).
|
|
32
|
+
const taintedBy = new Map();
|
|
33
|
+
const quarantined = new Set();
|
|
34
|
+
for (const entry of ordered) {
|
|
35
|
+
// Cascade: if any dependency is quarantined, this entry is too (§10).
|
|
36
|
+
const taintingDep = entry.dependencyIds.find((dep) => quarantined.has(dep));
|
|
37
|
+
if (taintingDep) {
|
|
38
|
+
const rootCause = taintedBy.get(taintingDep) ?? taintingDep;
|
|
39
|
+
quarantined.add(entry.id);
|
|
40
|
+
quarantinedIds.push(entry.id);
|
|
41
|
+
taintedBy.set(entry.id, rootCause);
|
|
42
|
+
records.push({
|
|
43
|
+
entryId: entry.id,
|
|
44
|
+
docId: entry.docId,
|
|
45
|
+
dbid: "",
|
|
46
|
+
entryType: entry.entryType,
|
|
47
|
+
reason: "cascade_dependent",
|
|
48
|
+
detail: `causally depends on quarantined entry ${taintingDep}`,
|
|
49
|
+
trustedTime: entry.trustedTime,
|
|
50
|
+
recordedAt: now,
|
|
51
|
+
causedByEntryId: rootCause,
|
|
52
|
+
});
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
const verdict = verdictFor(entry);
|
|
56
|
+
if (verdict.accepted) {
|
|
57
|
+
acceptedIds.push(entry.id);
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
quarantined.add(entry.id);
|
|
61
|
+
quarantinedIds.push(entry.id);
|
|
62
|
+
taintedBy.set(entry.id, entry.id);
|
|
63
|
+
records.push({
|
|
64
|
+
recordedAt: now,
|
|
65
|
+
...(verdict.record ?? {
|
|
66
|
+
entryId: entry.id,
|
|
67
|
+
docId: entry.docId,
|
|
68
|
+
dbid: "",
|
|
69
|
+
entryType: entry.entryType,
|
|
70
|
+
reason: "tier2_denied",
|
|
71
|
+
detail: "rejected by access policy",
|
|
72
|
+
trustedTime: entry.trustedTime,
|
|
73
|
+
}),
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return { acceptedIds, quarantinedIds, records };
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=quarantine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quarantine.js","sourceRoot":"","sources":["../../../src/core/accesscontrol/quarantine.ts"],"names":[],"mappings":";;AAsDA,8CAIC;AAeD,gDA2DC;AAnFD;;;;GAIG;AACH,SAAgB,iBAAiB,CAAgC,OAAqB;IACpF,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAChC,CAAC,CAAC,WAAW,KAAK,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC,WAAW,CAC3F,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,SAAgB,kBAAkB,CAChC,OAAuC,EACvC,UAAwD,EACxD,GAAW;IAEX,MAAM,OAAO,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAC3C,MAAM,WAAW,GAAa,EAAE,CAAC;IACjC,MAAM,cAAc,GAAa,EAAE,CAAC;IACpC,MAAM,OAAO,GAAuB,EAAE,CAAC;IAEvC,yEAAyE;IACzE,MAAM,SAAS,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC5C,MAAM,WAAW,GAAG,IAAI,GAAG,EAAU,CAAC;IAEtC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,sEAAsE;QACtE,MAAM,WAAW,GAAG,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;QAC5E,IAAI,WAAW,EAAE,CAAC;YAChB,MAAM,SAAS,GAAG,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,WAAW,CAAC;YAC5D,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAC1B,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAC9B,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;YACnC,OAAO,CAAC,IAAI,CAAC;gBACX,OAAO,EAAE,KAAK,CAAC,EAAE;gBACjB,KAAK,EAAE,KAAK,CAAC,KAAK;gBAClB,IAAI,EAAE,EAAE;gBACR,SAAS,EAAE,KAAK,CAAC,SAAS;gBAC1B,MAAM,EAAE,mBAAmB;gBAC3B,MAAM,EAAE,yCAAyC,WAAW,EAAE;gBAC9D,WAAW,EAAE,KAAK,CAAC,WAAW;gBAC9B,UAAU,EAAE,GAAG;gBACf,eAAe,EAAE,SAAS;aAC3B,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QAED,MAAM,OAAO,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;QAClC,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YACrB,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC7B,CAAC;aAAM,CAAC;YACN,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAC1B,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAC9B,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC;YAClC,OAAO,CAAC,IAAI,CAAC;gBACX,UAAU,EAAE,GAAG;gBACf,GAAG,CAAC,OAAO,CAAC,MAAM,IAAI;oBACpB,OAAO,EAAE,KAAK,CAAC,EAAE;oBACjB,KAAK,EAAE,KAAK,CAAC,KAAK;oBAClB,IAAI,EAAE,EAAE;oBACR,SAAS,EAAE,KAAK,CAAC,SAAS;oBAC1B,MAAM,EAAE,cAAc;oBACtB,MAAM,EAAE,2BAA2B;oBACnC,WAAW,EAAE,KAAK,CAAC,WAAW;iBAC/B,CAAC;aACH,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,OAAO,EAAE,CAAC;AAClD,CAAC"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { StoreEntryMetadata } from "../types";
|
|
2
|
+
/**
|
|
3
|
+
* Receipt-time validation and the clock-skew guard (docs/accesscontrol.md §4,
|
|
4
|
+
* §5.4).
|
|
5
|
+
*
|
|
6
|
+
* A valid witness signature proves *who* signed and *what* it covers, but not
|
|
7
|
+
* that the `receivedAt` value is honest. A compromised witness could backdate
|
|
8
|
+
* `receivedAt` to slip an entry "before" a policy that would have denied it.
|
|
9
|
+
* Receivers therefore validate `receivedAt` in addition to the signature:
|
|
10
|
+
* per-witness monotonicity plus a wall-clock sanity check at receive time.
|
|
11
|
+
*/
|
|
12
|
+
/** Default tolerance for the client/server clock-skew guard (§4). */
|
|
13
|
+
export declare const DEFAULT_CLOCK_SKEW_TOLERANCE_MS: number;
|
|
14
|
+
/** How far in the past a `receivedAt` may be before it is *flagged* (not rejected). */
|
|
15
|
+
export declare const DEFAULT_IMPLAUSIBLE_PAST_MS: number;
|
|
16
|
+
/** Result of the clock-skew guard. */
|
|
17
|
+
export interface ClockSkewResult {
|
|
18
|
+
ok: boolean;
|
|
19
|
+
skewMs: number;
|
|
20
|
+
toleranceMs: number;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Compare the local wall clock to the server's reported time (from
|
|
24
|
+
* `/sync/.../capabilities`), aborting sync if they diverge beyond tolerance
|
|
25
|
+
* (§4). This bounds how wrong a `createdAt` (and therefore a trusted-time
|
|
26
|
+
* decision) can be when a client edits offline then syncs.
|
|
27
|
+
*/
|
|
28
|
+
export declare function checkClockSkew(localTimeMs: number, serverTimeMs: number, toleranceMs?: number): ClockSkewResult;
|
|
29
|
+
/** Capabilities a client reads from `GET /sync/.../capabilities` (§4, §12). */
|
|
30
|
+
export interface NegotiableCapabilities {
|
|
31
|
+
/** Server wall clock (ms epoch), used for the clock-skew guard. */
|
|
32
|
+
serverTime?: number;
|
|
33
|
+
/** Whether the server understands witness fields / access control v1. */
|
|
34
|
+
supportsAccessControlV1?: boolean;
|
|
35
|
+
}
|
|
36
|
+
/** Outcome of the pre-sync capability negotiation (§12). */
|
|
37
|
+
export interface SyncNegotiationResult {
|
|
38
|
+
/** Whether sync may proceed. */
|
|
39
|
+
ok: boolean;
|
|
40
|
+
/** Why sync was refused, when not ok. */
|
|
41
|
+
reason?: string;
|
|
42
|
+
/** The clock-skew measurement, when the server reported its time. */
|
|
43
|
+
clockSkew?: ClockSkewResult;
|
|
44
|
+
/** Whether the server enforces access control v1 (advisory for the client). */
|
|
45
|
+
accessControlAvailable: boolean;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Decide whether a client may proceed to sync, given the server's advertised
|
|
49
|
+
* capabilities (§12). Two gates:
|
|
50
|
+
*
|
|
51
|
+
* 1. **Clock-skew guard** (§4): if the server reported its time and the local
|
|
52
|
+
* clock diverges beyond tolerance, refuse — a wrong local clock would make
|
|
53
|
+
* `createdAt`-based trusted-time decisions unsafe.
|
|
54
|
+
* 2. **Strict mode** (§12): a per-tenant policy may refuse to sync against a
|
|
55
|
+
* server that does not understand witness fields / access control v1.
|
|
56
|
+
*
|
|
57
|
+
* Pure and deterministic so it is trivially testable; the transport layer is a
|
|
58
|
+
* thin consumer.
|
|
59
|
+
*/
|
|
60
|
+
export declare function negotiateSync(localTimeMs: number, capabilities: NegotiableCapabilities, options?: {
|
|
61
|
+
strictMode?: boolean;
|
|
62
|
+
skewToleranceMs?: number;
|
|
63
|
+
}): SyncNegotiationResult;
|
|
64
|
+
/** Outcome of validating a single entry's witness receipt. */
|
|
65
|
+
export interface ReceiptValidationResult {
|
|
66
|
+
/** Whether the receipt is acceptable (trusted witness, valid sig, sane time). */
|
|
67
|
+
ok: boolean;
|
|
68
|
+
/** Human-readable reason when not ok, or a flag note when ok-but-suspicious. */
|
|
69
|
+
reason?: string;
|
|
70
|
+
/** True when the entry carried no receipt at all (a local, not-yet-synced entry). */
|
|
71
|
+
noReceipt?: boolean;
|
|
72
|
+
/** True when the time looked implausibly old (accepted, but logged for audit). */
|
|
73
|
+
flaggedImplausiblePast?: boolean;
|
|
74
|
+
}
|
|
75
|
+
/** Inputs the validator needs that are not on the entry itself. */
|
|
76
|
+
export interface ReceiptValidationContext {
|
|
77
|
+
/** Database id the entry belongs to (bound into the receipt signature). */
|
|
78
|
+
dbid: string;
|
|
79
|
+
/** Currently-trusted witness public keys (from the directory-state node, §6.4). */
|
|
80
|
+
trustedWitnessKeys: Set<string>;
|
|
81
|
+
/** Receiver wall clock at receive time (ms epoch). */
|
|
82
|
+
nowMs: number;
|
|
83
|
+
/** Clock-skew tolerance for the far-future rejection. */
|
|
84
|
+
skewToleranceMs?: number;
|
|
85
|
+
/** How far in the past is "implausible" (flagged, not rejected). */
|
|
86
|
+
implausiblePastMs?: number;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Validates witness receipts on incoming entries (§5.4). One instance should be
|
|
90
|
+
* kept per store so per-witness `receivedAt` monotonicity is enforced across
|
|
91
|
+
* the entries accepted from each witness.
|
|
92
|
+
*/
|
|
93
|
+
export declare class WitnessReceiptValidator {
|
|
94
|
+
/** Last accepted `receivedAt` per witness key (monotonicity, §5.4). */
|
|
95
|
+
private lastSeenByWitness;
|
|
96
|
+
/** Seed the per-witness high-water marks (e.g. from persisted state). */
|
|
97
|
+
constructor(initialLastSeen?: Map<string, number>);
|
|
98
|
+
/** The last-seen `receivedAt` for a witness, or undefined if none yet. */
|
|
99
|
+
getLastSeen(witnessPublicKey: string): number | undefined;
|
|
100
|
+
/**
|
|
101
|
+
* Validate the witness receipt on an entry. Returns `{ ok: true, noReceipt:
|
|
102
|
+
* true }` for entries with no receipt (local, not-yet-synced). Throws no
|
|
103
|
+
* exceptions for invalid receipts — it returns `{ ok: false, reason }` so the
|
|
104
|
+
* caller can quarantine.
|
|
105
|
+
*/
|
|
106
|
+
validate(entry: StoreEntryMetadata, ctx: ReceiptValidationContext, subtle: SubtleCrypto): Promise<ReceiptValidationResult>;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* The trusted time of an entry for all access-control evaluation: `receivedAt`
|
|
110
|
+
* when present (witness-assigned), otherwise `createdAt` (local entry). §5.1.
|
|
111
|
+
*/
|
|
112
|
+
export declare function trustedTimeOf(entry: Pick<StoreEntryMetadata, "receivedAt" | "createdAt">): number;
|
|
113
|
+
//# sourceMappingURL=receiptValidation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"receiptValidation.d.ts","sourceRoot":"","sources":["../../../src/core/accesscontrol/receiptValidation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAG9C;;;;;;;;;GASG;AAEH,qEAAqE;AACrE,eAAO,MAAM,+BAA+B,QAAgB,CAAC;AAE7D,uFAAuF;AACvF,eAAO,MAAM,2BAA2B,QAA4B,CAAC;AAErE,sCAAsC;AACtC,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,WAAW,GAAE,MAAwC,GACpD,eAAe,CAGjB;AAED,+EAA+E;AAC/E,MAAM,WAAW,sBAAsB;IACrC,mEAAmE;IACnE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yEAAyE;IACzE,uBAAuB,CAAC,EAAE,OAAO,CAAC;CACnC;AAED,4DAA4D;AAC5D,MAAM,WAAW,qBAAqB;IACpC,gCAAgC;IAChC,EAAE,EAAE,OAAO,CAAC;IACZ,yCAAyC;IACzC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qEAAqE;IACrE,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,+EAA+E;IAC/E,sBAAsB,EAAE,OAAO,CAAC;CACjC;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAC3B,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,sBAAsB,EACpC,OAAO,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,OAAO,CAAC;IAAC,eAAe,CAAC,EAAE,MAAM,CAAA;CAAE,GAC3D,qBAAqB,CA0BvB;AAED,8DAA8D;AAC9D,MAAM,WAAW,uBAAuB;IACtC,iFAAiF;IACjF,EAAE,EAAE,OAAO,CAAC;IACZ,gFAAgF;IAChF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qFAAqF;IACrF,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,kFAAkF;IAClF,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAClC;AAED,mEAAmE;AACnE,MAAM,WAAW,wBAAwB;IACvC,2EAA2E;IAC3E,IAAI,EAAE,MAAM,CAAC;IACb,mFAAmF;IACnF,kBAAkB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAChC,sDAAsD;IACtD,KAAK,EAAE,MAAM,CAAC;IACd,yDAAyD;IACzD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,oEAAoE;IACpE,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;;GAIG;AACH,qBAAa,uBAAuB;IAClC,uEAAuE;IACvE,OAAO,CAAC,iBAAiB,CAA6B;IAEtD,yEAAyE;gBAC7D,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC;IAMjD,0EAA0E;IAC1E,WAAW,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAIzD;;;;;OAKG;IACG,QAAQ,CACZ,KAAK,EAAE,kBAAkB,EACzB,GAAG,EAAE,wBAAwB,EAC7B,MAAM,EAAE,YAAY,GACnB,OAAO,CAAC,uBAAuB,CAAC;CA+CpC;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,IAAI,CAAC,kBAAkB,EAAE,YAAY,GAAG,WAAW,CAAC,GAAG,MAAM,CAEjG"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WitnessReceiptValidator = exports.DEFAULT_IMPLAUSIBLE_PAST_MS = exports.DEFAULT_CLOCK_SKEW_TOLERANCE_MS = void 0;
|
|
4
|
+
exports.checkClockSkew = checkClockSkew;
|
|
5
|
+
exports.negotiateSync = negotiateSync;
|
|
6
|
+
exports.trustedTimeOf = trustedTimeOf;
|
|
7
|
+
const WitnessReceipt_1 = require("../crypto/WitnessReceipt");
|
|
8
|
+
/**
|
|
9
|
+
* Receipt-time validation and the clock-skew guard (docs/accesscontrol.md §4,
|
|
10
|
+
* §5.4).
|
|
11
|
+
*
|
|
12
|
+
* A valid witness signature proves *who* signed and *what* it covers, but not
|
|
13
|
+
* that the `receivedAt` value is honest. A compromised witness could backdate
|
|
14
|
+
* `receivedAt` to slip an entry "before" a policy that would have denied it.
|
|
15
|
+
* Receivers therefore validate `receivedAt` in addition to the signature:
|
|
16
|
+
* per-witness monotonicity plus a wall-clock sanity check at receive time.
|
|
17
|
+
*/
|
|
18
|
+
/** Default tolerance for the client/server clock-skew guard (§4). */
|
|
19
|
+
exports.DEFAULT_CLOCK_SKEW_TOLERANCE_MS = 5 * 60 * 1000; // 5 minutes
|
|
20
|
+
/** How far in the past a `receivedAt` may be before it is *flagged* (not rejected). */
|
|
21
|
+
exports.DEFAULT_IMPLAUSIBLE_PAST_MS = 365 * 24 * 60 * 60 * 1000; // ~1 year
|
|
22
|
+
/**
|
|
23
|
+
* Compare the local wall clock to the server's reported time (from
|
|
24
|
+
* `/sync/.../capabilities`), aborting sync if they diverge beyond tolerance
|
|
25
|
+
* (§4). This bounds how wrong a `createdAt` (and therefore a trusted-time
|
|
26
|
+
* decision) can be when a client edits offline then syncs.
|
|
27
|
+
*/
|
|
28
|
+
function checkClockSkew(localTimeMs, serverTimeMs, toleranceMs = exports.DEFAULT_CLOCK_SKEW_TOLERANCE_MS) {
|
|
29
|
+
const skewMs = Math.abs(localTimeMs - serverTimeMs);
|
|
30
|
+
return { ok: skewMs <= toleranceMs, skewMs, toleranceMs };
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Decide whether a client may proceed to sync, given the server's advertised
|
|
34
|
+
* capabilities (§12). Two gates:
|
|
35
|
+
*
|
|
36
|
+
* 1. **Clock-skew guard** (§4): if the server reported its time and the local
|
|
37
|
+
* clock diverges beyond tolerance, refuse — a wrong local clock would make
|
|
38
|
+
* `createdAt`-based trusted-time decisions unsafe.
|
|
39
|
+
* 2. **Strict mode** (§12): a per-tenant policy may refuse to sync against a
|
|
40
|
+
* server that does not understand witness fields / access control v1.
|
|
41
|
+
*
|
|
42
|
+
* Pure and deterministic so it is trivially testable; the transport layer is a
|
|
43
|
+
* thin consumer.
|
|
44
|
+
*/
|
|
45
|
+
function negotiateSync(localTimeMs, capabilities, options) {
|
|
46
|
+
const accessControlAvailable = capabilities.supportsAccessControlV1 === true;
|
|
47
|
+
let clockSkew;
|
|
48
|
+
if (typeof capabilities.serverTime === "number") {
|
|
49
|
+
clockSkew = checkClockSkew(localTimeMs, capabilities.serverTime, options?.skewToleranceMs);
|
|
50
|
+
if (!clockSkew.ok) {
|
|
51
|
+
return {
|
|
52
|
+
ok: false,
|
|
53
|
+
reason: `clock skew ${clockSkew.skewMs}ms exceeds tolerance ${clockSkew.toleranceMs}ms`,
|
|
54
|
+
clockSkew,
|
|
55
|
+
accessControlAvailable,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (options?.strictMode && !accessControlAvailable) {
|
|
60
|
+
return {
|
|
61
|
+
ok: false,
|
|
62
|
+
reason: "strict mode: server does not support access control v1",
|
|
63
|
+
clockSkew,
|
|
64
|
+
accessControlAvailable,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
return { ok: true, clockSkew, accessControlAvailable };
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Validates witness receipts on incoming entries (§5.4). One instance should be
|
|
71
|
+
* kept per store so per-witness `receivedAt` monotonicity is enforced across
|
|
72
|
+
* the entries accepted from each witness.
|
|
73
|
+
*/
|
|
74
|
+
class WitnessReceiptValidator {
|
|
75
|
+
/** Seed the per-witness high-water marks (e.g. from persisted state). */
|
|
76
|
+
constructor(initialLastSeen) {
|
|
77
|
+
/** Last accepted `receivedAt` per witness key (monotonicity, §5.4). */
|
|
78
|
+
this.lastSeenByWitness = new Map();
|
|
79
|
+
if (initialLastSeen) {
|
|
80
|
+
this.lastSeenByWitness = new Map(initialLastSeen);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/** The last-seen `receivedAt` for a witness, or undefined if none yet. */
|
|
84
|
+
getLastSeen(witnessPublicKey) {
|
|
85
|
+
return this.lastSeenByWitness.get(witnessPublicKey);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Validate the witness receipt on an entry. Returns `{ ok: true, noReceipt:
|
|
89
|
+
* true }` for entries with no receipt (local, not-yet-synced). Throws no
|
|
90
|
+
* exceptions for invalid receipts — it returns `{ ok: false, reason }` so the
|
|
91
|
+
* caller can quarantine.
|
|
92
|
+
*/
|
|
93
|
+
async validate(entry, ctx, subtle) {
|
|
94
|
+
const { receivedAt, receivedByPublicKey, receivedDateSignature } = entry;
|
|
95
|
+
// No receipt: a purely local entry. Nothing to validate here.
|
|
96
|
+
if (receivedAt === undefined || !receivedByPublicKey || !receivedDateSignature) {
|
|
97
|
+
return { ok: true, noReceipt: true };
|
|
98
|
+
}
|
|
99
|
+
// The witness must be currently trusted (§6.4).
|
|
100
|
+
if (!ctx.trustedWitnessKeys.has(receivedByPublicKey)) {
|
|
101
|
+
return { ok: false, reason: "receipt from an untrusted witness key" };
|
|
102
|
+
}
|
|
103
|
+
// Cryptographically verify the signature over the §5.2 layout.
|
|
104
|
+
const fields = (0, WitnessReceipt_1.witnessFieldsFromEntry)(entry, {
|
|
105
|
+
dbid: ctx.dbid,
|
|
106
|
+
receivedAt,
|
|
107
|
+
receivedByPublicKey,
|
|
108
|
+
});
|
|
109
|
+
const sigValid = await (0, WitnessReceipt_1.verifyWitnessReceipt)(fields, receivedDateSignature, receivedByPublicKey, subtle);
|
|
110
|
+
if (!sigValid) {
|
|
111
|
+
return { ok: false, reason: "invalid witness signature" };
|
|
112
|
+
}
|
|
113
|
+
// Per-witness monotonicity: a witness cannot rewind its own clock (§5.4).
|
|
114
|
+
const lastSeen = this.lastSeenByWitness.get(receivedByPublicKey);
|
|
115
|
+
if (lastSeen !== undefined && receivedAt < lastSeen) {
|
|
116
|
+
return {
|
|
117
|
+
ok: false,
|
|
118
|
+
reason: `non-monotonic receivedAt (${receivedAt} < last-seen ${lastSeen}) from witness`,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
// Wall-clock sanity at receive time (§5.4): reject far-future values.
|
|
122
|
+
const tolerance = ctx.skewToleranceMs ?? exports.DEFAULT_CLOCK_SKEW_TOLERANCE_MS;
|
|
123
|
+
if (receivedAt > ctx.nowMs + tolerance) {
|
|
124
|
+
return { ok: false, reason: "receivedAt is implausibly in the future" };
|
|
125
|
+
}
|
|
126
|
+
// Flag (but accept) implausibly old values for the audit log.
|
|
127
|
+
const implausiblePast = ctx.implausiblePastMs ?? exports.DEFAULT_IMPLAUSIBLE_PAST_MS;
|
|
128
|
+
const flaggedImplausiblePast = receivedAt < ctx.nowMs - implausiblePast;
|
|
129
|
+
// Accept and advance the monotonicity high-water mark.
|
|
130
|
+
this.lastSeenByWitness.set(receivedByPublicKey, receivedAt);
|
|
131
|
+
return { ok: true, flaggedImplausiblePast };
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
exports.WitnessReceiptValidator = WitnessReceiptValidator;
|
|
135
|
+
/**
|
|
136
|
+
* The trusted time of an entry for all access-control evaluation: `receivedAt`
|
|
137
|
+
* when present (witness-assigned), otherwise `createdAt` (local entry). §5.1.
|
|
138
|
+
*/
|
|
139
|
+
function trustedTimeOf(entry) {
|
|
140
|
+
return entry.receivedAt ?? entry.createdAt;
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=receiptValidation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"receiptValidation.js","sourceRoot":"","sources":["../../../src/core/accesscontrol/receiptValidation.ts"],"names":[],"mappings":"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"}
|