mindoodb 0.0.85 → 0.0.88
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 +6 -2
- package/README.md +6 -4
- package/dist/appendonlystores/network/ClientNetworkContentAddressedStore.d.ts.map +1 -1
- package/dist/appendonlystores/network/ClientNetworkContentAddressedStore.js +2 -1
- package/dist/appendonlystores/network/ClientNetworkContentAddressedStore.js.map +1 -1
- package/dist/appendonlystores/network/ServerNetworkContentAddressedStore.d.ts +151 -12
- package/dist/appendonlystores/network/ServerNetworkContentAddressedStore.d.ts.map +1 -1
- package/dist/appendonlystores/network/ServerNetworkContentAddressedStore.js +340 -24
- package/dist/appendonlystores/network/ServerNetworkContentAddressedStore.js.map +1 -1
- package/dist/browser/index.mjs +14 -0
- package/dist/cloudflare/DurableObjectSql.d.ts +56 -0
- package/dist/cloudflare/DurableObjectSql.d.ts.map +1 -0
- package/dist/cloudflare/DurableObjectSql.js +180 -0
- package/dist/cloudflare/DurableObjectSql.js.map +1 -0
- package/dist/cloudflare/MindooDatabaseObject.d.ts +86 -0
- package/dist/cloudflare/MindooDatabaseObject.d.ts.map +1 -0
- package/dist/cloudflare/MindooDatabaseObject.js +614 -0
- package/dist/cloudflare/MindooDatabaseObject.js.map +1 -0
- package/dist/cloudflare/MindooServerObject.d.ts +63 -0
- package/dist/cloudflare/MindooServerObject.d.ts.map +1 -0
- package/dist/cloudflare/MindooServerObject.js +521 -0
- package/dist/cloudflare/MindooServerObject.js.map +1 -0
- package/dist/cloudflare/WorkersCryptoAdapter.d.ts +7 -0
- package/dist/cloudflare/WorkersCryptoAdapter.d.ts.map +1 -0
- package/dist/cloudflare/WorkersCryptoAdapter.js +14 -0
- package/dist/cloudflare/WorkersCryptoAdapter.js.map +1 -0
- package/dist/cloudflare/host.d.ts +49 -0
- package/dist/cloudflare/host.d.ts.map +1 -0
- package/dist/cloudflare/host.js +104 -0
- package/dist/cloudflare/host.js.map +1 -0
- package/dist/cloudflare/http.d.ts +91 -0
- package/dist/cloudflare/http.d.ts.map +1 -0
- package/dist/cloudflare/http.js +266 -0
- package/dist/cloudflare/http.js.map +1 -0
- package/dist/cloudflare/index.d.ts +12 -0
- package/dist/cloudflare/index.d.ts.map +1 -0
- package/dist/cloudflare/index.js +20 -0
- package/dist/cloudflare/index.js.map +1 -0
- package/dist/cloudflare/storeRpc.d.ts +22 -0
- package/dist/cloudflare/storeRpc.d.ts.map +1 -0
- package/dist/cloudflare/storeRpc.js +85 -0
- package/dist/cloudflare/storeRpc.js.map +1 -0
- package/dist/cloudflare/types.d.ts +101 -0
- package/dist/cloudflare/types.d.ts.map +1 -0
- package/dist/cloudflare/types.js +10 -0
- package/dist/cloudflare/types.js.map +1 -0
- package/dist/cloudflare/worker.d.ts +25 -0
- package/dist/cloudflare/worker.d.ts.map +1 -0
- package/dist/cloudflare/worker.js +170 -0
- package/dist/cloudflare/worker.js.map +1 -0
- package/dist/core/BaseMindooDB.d.ts +95 -10
- package/dist/core/BaseMindooDB.d.ts.map +1 -1
- package/dist/core/BaseMindooDB.js +441 -98
- package/dist/core/BaseMindooDB.js.map +1 -1
- package/dist/core/BaseMindooTenant.d.ts +43 -0
- package/dist/core/BaseMindooTenant.d.ts.map +1 -1
- package/dist/core/BaseMindooTenant.js +157 -6
- package/dist/core/BaseMindooTenant.js.map +1 -1
- package/dist/core/BaseMindooTenantDirectory.d.ts +103 -0
- package/dist/core/BaseMindooTenantDirectory.d.ts.map +1 -1
- package/dist/core/BaseMindooTenantDirectory.js +371 -8
- package/dist/core/BaseMindooTenantDirectory.js.map +1 -1
- package/dist/core/BaseMindooTenantFactory.d.ts.map +1 -1
- package/dist/core/BaseMindooTenantFactory.js +2 -1
- package/dist/core/BaseMindooTenantFactory.js.map +1 -1
- package/dist/core/ChangeDocDraft.d.ts +133 -0
- package/dist/core/ChangeDocDraft.d.ts.map +1 -0
- package/dist/core/ChangeDocDraft.js +492 -0
- package/dist/core/ChangeDocDraft.js.map +1 -0
- package/dist/core/MindooDBServerAdmin.d.ts.map +1 -1
- package/dist/core/MindooDBServerAdmin.js +2 -1
- package/dist/core/MindooDBServerAdmin.js.map +1 -1
- package/dist/core/accesscontrol/directoryProjection.d.ts.map +1 -1
- package/dist/core/accesscontrol/directoryProjection.js +19 -0
- package/dist/core/accesscontrol/directoryProjection.js.map +1 -1
- package/dist/core/accesscontrol/evaluate.d.ts +14 -0
- package/dist/core/accesscontrol/evaluate.d.ts.map +1 -1
- package/dist/core/accesscontrol/evaluate.js +42 -1
- package/dist/core/accesscontrol/evaluate.js.map +1 -1
- package/dist/core/accesscontrol/types.d.ts +88 -4
- package/dist/core/accesscontrol/types.d.ts.map +1 -1
- package/dist/core/accesscontrol/types.js +114 -1
- package/dist/core/accesscontrol/types.js.map +1 -1
- package/dist/core/appendonlystores/network/AuthenticationService.d.ts +14 -0
- package/dist/core/appendonlystores/network/AuthenticationService.d.ts.map +1 -1
- package/dist/core/appendonlystores/network/AuthenticationService.js +27 -7
- package/dist/core/appendonlystores/network/AuthenticationService.js.map +1 -1
- package/dist/core/appendonlystores/network/IrohNetworkTransport.d.ts.map +1 -1
- package/dist/core/appendonlystores/network/IrohNetworkTransport.js +12 -0
- package/dist/core/appendonlystores/network/IrohNetworkTransport.js.map +1 -1
- package/dist/core/appendonlystores/network/IrohStreamIO.d.ts.map +1 -1
- package/dist/core/appendonlystores/network/IrohStreamIO.js +3 -23
- package/dist/core/appendonlystores/network/IrohStreamIO.js.map +1 -1
- package/dist/core/appendonlystores/rpc/RpcContentAddressedStore.d.ts +6 -0
- package/dist/core/appendonlystores/rpc/RpcContentAddressedStore.d.ts.map +1 -1
- package/dist/core/appendonlystores/rpc/RpcContentAddressedStore.js +20 -1
- package/dist/core/appendonlystores/rpc/RpcContentAddressedStore.js.map +1 -1
- package/dist/core/appendonlystores/rpc/storeRpcCodec.d.ts.map +1 -1
- package/dist/core/appendonlystores/rpc/storeRpcCodec.js +3 -23
- package/dist/core/appendonlystores/rpc/storeRpcCodec.js.map +1 -1
- package/dist/core/appendonlystores/sqlite/SqliteContentAddressedStore.d.ts +7 -0
- package/dist/core/appendonlystores/sqlite/SqliteContentAddressedStore.d.ts.map +1 -1
- package/dist/core/appendonlystores/sqlite/SqliteContentAddressedStore.js +39 -30
- package/dist/core/appendonlystores/sqlite/SqliteContentAddressedStore.js.map +1 -1
- package/dist/core/appendonlystores/sqlite/SqliteDriver.d.ts +37 -1
- package/dist/core/appendonlystores/sqlite/SqliteDriver.d.ts.map +1 -1
- package/dist/core/appendonlystores/sqlite/SqliteDriver.js +99 -40
- package/dist/core/appendonlystores/sqlite/SqliteDriver.js.map +1 -1
- package/dist/core/appendonlystores/syncStores.d.ts.map +1 -1
- package/dist/core/appendonlystores/syncStores.js +25 -5
- package/dist/core/appendonlystores/syncStores.js.map +1 -1
- package/dist/core/appendonlystores/types.d.ts +7 -1
- package/dist/core/appendonlystores/types.d.ts.map +1 -1
- package/dist/core/appendonlystores/types.js +1 -0
- package/dist/core/appendonlystores/types.js.map +1 -1
- package/dist/core/builtinDbInvariants.d.ts +49 -0
- package/dist/core/builtinDbInvariants.d.ts.map +1 -1
- package/dist/core/builtinDbInvariants.js +86 -1
- package/dist/core/builtinDbInvariants.js.map +1 -1
- package/dist/core/crypto/AuthChallenge.d.ts +68 -0
- package/dist/core/crypto/AuthChallenge.d.ts.map +1 -0
- package/dist/core/crypto/AuthChallenge.js +118 -0
- package/dist/core/crypto/AuthChallenge.js.map +1 -0
- package/dist/core/crypto/DomainStatement.d.ts +5 -3
- package/dist/core/crypto/DomainStatement.d.ts.map +1 -1
- package/dist/core/crypto/DomainStatement.js +5 -3
- package/dist/core/crypto/DomainStatement.js.map +1 -1
- package/dist/core/crypto/encryptedFields.d.ts +11 -0
- package/dist/core/crypto/encryptedFields.d.ts.map +1 -1
- package/dist/core/crypto/encryptedFields.js +18 -0
- package/dist/core/crypto/encryptedFields.js.map +1 -1
- package/dist/core/expressions/evaluateExpression.d.ts +8 -0
- package/dist/core/expressions/evaluateExpression.d.ts.map +1 -1
- package/dist/core/expressions/evaluateExpression.js +29 -4
- package/dist/core/expressions/evaluateExpression.js.map +1 -1
- package/dist/core/expressions/metadata.js +4 -4
- package/dist/core/expressions/metadata.js.map +1 -1
- package/dist/core/index.d.ts +3 -3
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +17 -6
- package/dist/core/index.js.map +1 -1
- package/dist/core/query/executeQuery.d.ts.map +1 -1
- package/dist/core/query/executeQuery.js +5 -1
- package/dist/core/query/executeQuery.js.map +1 -1
- package/dist/core/query/executeQueryInclude.d.ts.map +1 -1
- package/dist/core/query/executeQueryInclude.js +2 -0
- package/dist/core/query/executeQueryInclude.js.map +1 -1
- package/dist/core/query/queryView.d.ts.map +1 -1
- package/dist/core/query/queryView.js +5 -1
- package/dist/core/query/queryView.js.map +1 -1
- package/dist/core/types.d.ts +204 -10
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/core/uri/MindooURI.d.ts.map +1 -1
- package/dist/core/uri/MindooURI.js +3 -24
- package/dist/core/uri/MindooURI.js.map +1 -1
- package/dist/core/userkeys/index.d.ts +1 -0
- package/dist/core/userkeys/index.d.ts.map +1 -1
- package/dist/core/userkeys/index.js +5 -1
- package/dist/core/userkeys/index.js.map +1 -1
- package/dist/core/userkeys/sealedValues.d.ts +54 -0
- package/dist/core/userkeys/sealedValues.d.ts.map +1 -0
- package/dist/core/userkeys/sealedValues.js +67 -0
- package/dist/core/userkeys/sealedValues.js.map +1 -0
- package/dist/core/utils/base64.d.ts +17 -0
- package/dist/core/utils/base64.d.ts.map +1 -0
- package/dist/core/utils/base64.js +54 -0
- package/dist/core/utils/base64.js.map +1 -0
- package/dist/core/utils/dynamicImportInterop.d.ts +10 -0
- package/dist/core/utils/dynamicImportInterop.d.ts.map +1 -0
- package/dist/core/utils/dynamicImportInterop.js +22 -0
- package/dist/core/utils/dynamicImportInterop.js.map +1 -0
- package/dist/core/utils/idGeneration.d.ts.map +1 -1
- package/dist/core/utils/idGeneration.js +14 -3
- package/dist/core/utils/idGeneration.js.map +1 -1
- package/dist/node/appendonlystores/BasicOnDiskContentAddressedStore.d.ts.map +1 -1
- package/dist/node/appendonlystores/BasicOnDiskContentAddressedStore.js +7 -0
- package/dist/node/appendonlystores/BasicOnDiskContentAddressedStore.js.map +1 -1
- package/dist/node/server/FsServerDataStore.d.ts +23 -0
- package/dist/node/server/FsServerDataStore.d.ts.map +1 -0
- package/dist/node/server/FsServerDataStore.js +59 -0
- package/dist/node/server/FsServerDataStore.js.map +1 -0
- package/dist/node/server/IrohServerEndpoint.d.ts +1 -1
- package/dist/node/server/IrohServerEndpoint.d.ts.map +1 -1
- package/dist/node/server/IrohServerRpc.d.ts +5 -5
- package/dist/node/server/IrohServerRpc.d.ts.map +1 -1
- package/dist/node/server/IrohServerRpc.js +1 -1
- package/dist/node/server/IrohServerRpc.js.map +1 -1
- package/dist/node/server/MindooDBServer.d.ts +29 -150
- package/dist/node/server/MindooDBServer.d.ts.map +1 -1
- package/dist/node/server/MindooDBServer.js +160 -1573
- package/dist/node/server/MindooDBServer.js.map +1 -1
- package/dist/node/server/PurgedDocRegistry.d.ts +4 -27
- package/dist/node/server/PurgedDocRegistry.d.ts.map +1 -1
- package/dist/node/server/PurgedDocRegistry.js +6 -83
- package/dist/node/server/PurgedDocRegistry.js.map +1 -1
- package/dist/node/server/StoreFactory.d.ts +1 -1
- package/dist/node/server/StoreFactory.d.ts.map +1 -1
- package/dist/node/server/TenantManager.d.ts +16 -284
- package/dist/node/server/TenantManager.d.ts.map +1 -1
- package/dist/node/server/TenantManager.js +35 -1168
- package/dist/node/server/TenantManager.js.map +1 -1
- package/dist/node/server/add-to-network.js +1 -1
- package/dist/node/server/add-to-network.js.map +1 -1
- package/dist/node/server/config.d.ts +11 -15
- package/dist/node/server/config.d.ts.map +1 -1
- package/dist/node/server/config.js +30 -245
- package/dist/node/server/config.js.map +1 -1
- package/dist/node/server/expressAdapter.d.ts +23 -0
- package/dist/node/server/expressAdapter.d.ts.map +1 -0
- package/dist/node/server/expressAdapter.js +108 -0
- package/dist/node/server/expressAdapter.js.map +1 -0
- package/dist/node/server/nativeIrohStreamIO.d.ts +1 -1
- package/dist/node/server/nativeIrohStreamIO.d.ts.map +1 -1
- package/dist/node/server/peer/FileClusterAuditStorage.d.ts +16 -0
- package/dist/node/server/peer/FileClusterAuditStorage.d.ts.map +1 -0
- package/dist/node/server/peer/FileClusterAuditStorage.js +39 -0
- package/dist/node/server/peer/FileClusterAuditStorage.js.map +1 -0
- package/dist/node/server/peer/IrohPeerLink.d.ts +1 -1
- package/dist/node/server/peer/IrohPeerLink.d.ts.map +1 -1
- package/dist/node/server/peer/routes.d.ts +10 -44
- package/dist/node/server/peer/routes.d.ts.map +1 -1
- package/dist/node/server/peer/routes.js +33 -275
- package/dist/node/server/peer/routes.js.map +1 -1
- package/dist/node/server/resolveServerPassword.js +1 -1
- package/dist/node/server/resolveServerPassword.js.map +1 -1
- package/dist/node/server/server.js +1 -1
- package/dist/node/server/server.js.map +1 -1
- package/dist/node/server/serverinit.js +1 -1
- package/dist/node/server/serverinit.js.map +1 -1
- package/dist/server/CapabilityMatcher.d.ts +60 -0
- package/dist/server/CapabilityMatcher.d.ts.map +1 -0
- package/dist/server/CapabilityMatcher.js +138 -0
- package/dist/server/CapabilityMatcher.js.map +1 -0
- package/dist/server/DeviceDiscoveryService.d.ts +36 -0
- package/dist/server/DeviceDiscoveryService.d.ts.map +1 -0
- package/dist/server/DeviceDiscoveryService.js +164 -0
- package/dist/server/DeviceDiscoveryService.js.map +1 -0
- package/dist/server/PurgedDocRegistry.d.ts +35 -0
- package/dist/server/PurgedDocRegistry.d.ts.map +1 -0
- package/dist/server/PurgedDocRegistry.js +90 -0
- package/dist/server/PurgedDocRegistry.js.map +1 -0
- package/dist/server/ServerDataStore.d.ts +67 -0
- package/dist/server/ServerDataStore.d.ts.map +1 -0
- package/dist/server/ServerDataStore.js +88 -0
- package/dist/server/ServerDataStore.js.map +1 -0
- package/dist/server/SyncEventBus.d.ts +39 -0
- package/dist/server/SyncEventBus.d.ts.map +1 -0
- package/dist/server/SyncEventBus.js +41 -0
- package/dist/server/SyncEventBus.js.map +1 -0
- package/dist/server/SystemAdminAuth.d.ts +82 -0
- package/dist/server/SystemAdminAuth.d.ts.map +1 -0
- package/dist/server/SystemAdminAuth.js +227 -0
- package/dist/server/SystemAdminAuth.js.map +1 -0
- package/dist/server/TenantManager.d.ts +366 -0
- package/dist/server/TenantManager.d.ts.map +1 -0
- package/dist/server/TenantManager.js +1416 -0
- package/dist/server/TenantManager.js.map +1 -0
- package/dist/server/http/MindooDBServerCore.d.ts +313 -0
- package/dist/server/http/MindooDBServerCore.d.ts.map +1 -0
- package/dist/server/http/MindooDBServerCore.js +1410 -0
- package/dist/server/http/MindooDBServerCore.js.map +1 -0
- package/dist/server/http/types.d.ts +89 -0
- package/dist/server/http/types.d.ts.map +1 -0
- package/dist/server/http/types.js +29 -0
- package/dist/server/http/types.js.map +1 -0
- package/dist/server/index.d.ts +32 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +76 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/peer/ClusterAuditLog.d.ts +71 -0
- package/dist/server/peer/ClusterAuditLog.d.ts.map +1 -0
- package/dist/server/peer/ClusterAuditLog.js +81 -0
- package/dist/server/peer/ClusterAuditLog.js.map +1 -0
- package/dist/server/peer/ClusterJobRunner.d.ts +43 -0
- package/dist/server/peer/ClusterJobRunner.d.ts.map +1 -0
- package/dist/server/peer/ClusterJobRunner.js +119 -0
- package/dist/server/peer/ClusterJobRunner.js.map +1 -0
- package/dist/server/peer/ClusterManager.d.ts +149 -0
- package/dist/server/peer/ClusterManager.d.ts.map +1 -0
- package/dist/server/peer/ClusterManager.js +292 -0
- package/dist/server/peer/ClusterManager.js.map +1 -0
- package/dist/server/peer/PeerAuthService.d.ts +69 -0
- package/dist/server/peer/PeerAuthService.d.ts.map +1 -0
- package/dist/server/peer/PeerAuthService.js +207 -0
- package/dist/server/peer/PeerAuthService.js.map +1 -0
- package/dist/server/peer/PeerReplicator.d.ts +303 -0
- package/dist/server/peer/PeerReplicator.d.ts.map +1 -0
- package/dist/server/peer/PeerReplicator.js +1072 -0
- package/dist/server/peer/PeerReplicator.js.map +1 -0
- package/dist/server/peer/clusterHttp.d.ts +113 -0
- package/dist/server/peer/clusterHttp.d.ts.map +1 -0
- package/dist/server/peer/clusterHttp.js +290 -0
- package/dist/server/peer/clusterHttp.js.map +1 -0
- package/dist/server/peer/types.d.ts +244 -0
- package/dist/server/peer/types.d.ts.map +1 -0
- package/dist/server/peer/types.js +189 -0
- package/dist/server/peer/types.js.map +1 -0
- package/dist/server/rateLimits.d.ts +119 -0
- package/dist/server/rateLimits.d.ts.map +1 -0
- package/dist/server/rateLimits.js +159 -0
- package/dist/server/rateLimits.js.map +1 -0
- package/dist/server/serverConfig.d.ts +37 -0
- package/dist/server/serverConfig.d.ts.map +1 -0
- package/dist/server/serverConfig.js +251 -0
- package/dist/server/serverConfig.js.map +1 -0
- package/dist/server/timestampProxy.d.ts +129 -0
- package/dist/server/timestampProxy.d.ts.map +1 -0
- package/dist/server/timestampProxy.js +361 -0
- package/dist/server/timestampProxy.js.map +1 -0
- package/dist/server/types.d.ts +267 -0
- package/dist/server/types.d.ts.map +1 -0
- package/dist/server/types.js +56 -0
- package/dist/server/types.js.map +1 -0
- package/dist/server/validation.d.ts +43 -0
- package/dist/server/validation.d.ts.map +1 -0
- package/dist/server/validation.js +104 -0
- package/dist/server/validation.js.map +1 -0
- package/package.json +9 -1
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Rate-limit resolution shared by the server's limiter tiers.
|
|
4
|
+
*
|
|
5
|
+
* Kept out of {@link MindooDBServer} so the interaction between the global net
|
|
6
|
+
* and the per-route tiers is testable on its own: it is the part that is easy
|
|
7
|
+
* to get wrong, and getting it wrong is silent — a global cap below a tier cap
|
|
8
|
+
* simply replaces that tier, and the tier's configuration stops meaning
|
|
9
|
+
* anything.
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.PEER_RATE_LIMIT = exports.DEVICE_DISCOVERY_RATE_LIMIT = exports.DEFAULT_SYSTEM_RATE_LIMIT_MAX = exports.DEFAULT_SYSTEM_RATE_LIMIT_WINDOW_MS = exports.TIMESTAMP_DAILY_WINDOW_MS = exports.DEFAULT_TIMESTAMP_DAILY_LIMIT_MAX = exports.DEFAULT_TIMESTAMP_RATE_LIMIT_MAX = exports.DEFAULT_TIMESTAMP_RATE_LIMIT_WINDOW_MS = exports.GLOBAL_RATE_LIMIT_TIER_HEADROOM = exports.DEFAULT_GLOBAL_RATE_LIMIT_WINDOW_MS = exports.DEFAULT_SYNC_RATE_LIMIT_MAX = exports.DEFAULT_SYNC_RATE_LIMIT_WINDOW_MS = exports.DEFAULT_AUTH_RATE_LIMIT_MAX = exports.DEFAULT_AUTH_RATE_LIMIT_WINDOW_MS = void 0;
|
|
13
|
+
exports.resolveGlobalRateLimit = resolveGlobalRateLimit;
|
|
14
|
+
exports.buildSyncRateLimitKey = buildSyncRateLimitKey;
|
|
15
|
+
exports.resolveServerRateLimits = resolveServerRateLimits;
|
|
16
|
+
exports.buildAuthRateLimitKey = buildAuthRateLimitKey;
|
|
17
|
+
exports.buildTimestampRateLimitKey = buildTimestampRateLimitKey;
|
|
18
|
+
/**
|
|
19
|
+
* Resolve the global limiter against the tiers it is supposed to back up.
|
|
20
|
+
*
|
|
21
|
+
* Without an explicit `rateLimits.global`, the ceiling is derived from the
|
|
22
|
+
* tiers so the net catches only traffic no tier claims. An explicit value is
|
|
23
|
+
* honoured — an operator may want a hard cap — but reported as shadowing so
|
|
24
|
+
* the caller can say so at startup instead of leaving it to be discovered as
|
|
25
|
+
* mysterious 429s.
|
|
26
|
+
*/
|
|
27
|
+
function resolveGlobalRateLimit(configured, tiers) {
|
|
28
|
+
const windowMs = configured?.windowMs ?? tiers.defaultWindowMs;
|
|
29
|
+
// Tier windows need not match the global one; compare rates, not raw maxima.
|
|
30
|
+
const perWindow = (tier) => Math.ceil((tier.max / tier.windowMs) * windowMs);
|
|
31
|
+
const tierFloor = perWindow(tiers.sync) + perWindow(tiers.auth) + tiers.headroom;
|
|
32
|
+
if (configured?.max === undefined) {
|
|
33
|
+
return { windowMs, max: tierFloor, tierFloor, shadowsTiers: false };
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
windowMs,
|
|
37
|
+
max: configured.max,
|
|
38
|
+
tierFloor,
|
|
39
|
+
shadowsTiers: configured.max < tierFloor,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Bucket key for the sync tier.
|
|
44
|
+
*
|
|
45
|
+
* The principal is what makes this usable behind a NAT or a CDN: keyed on the
|
|
46
|
+
* address alone, one client opening several databases spends everyone else's
|
|
47
|
+
* budget. The address stays in the key so that callers we could not
|
|
48
|
+
* authenticate still get separated per source rather than sharing one
|
|
49
|
+
* "anonymous" bucket.
|
|
50
|
+
*/
|
|
51
|
+
function buildSyncRateLimitKey(tenantId, principal, ip) {
|
|
52
|
+
return `sync:${tenantId ?? "unknown"}:${principal ?? "anonymous"}:${ip ?? "unknown"}`;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Rate-limit defaults. Auth and sync have separate tiers because a single
|
|
56
|
+
* challenge/authenticate handshake is two requests; with multiple tenants,
|
|
57
|
+
* store kinds, and token renewals the auth budget exhausts quickly if set
|
|
58
|
+
* too low. These can be overridden in config.json under `rateLimits.auth`
|
|
59
|
+
* and `rateLimits.sync`.
|
|
60
|
+
*/
|
|
61
|
+
exports.DEFAULT_AUTH_RATE_LIMIT_WINDOW_MS = 60000;
|
|
62
|
+
exports.DEFAULT_AUTH_RATE_LIMIT_MAX = 120;
|
|
63
|
+
exports.DEFAULT_SYNC_RATE_LIMIT_WINDOW_MS = 60000;
|
|
64
|
+
/**
|
|
65
|
+
* Sync is keyed per authenticated principal, and a client legitimately opens
|
|
66
|
+
* several databases at once: a host like Teacher's Desk reads six, and a cold
|
|
67
|
+
* pass over one of them costs a few hundred batched requests. A budget sized
|
|
68
|
+
* for a single database turns that normal open into a throttled one.
|
|
69
|
+
*/
|
|
70
|
+
exports.DEFAULT_SYNC_RATE_LIMIT_MAX = 3000;
|
|
71
|
+
/**
|
|
72
|
+
* The global limiter is a coarse net for unauthenticated floods and unknown
|
|
73
|
+
* routes; the per-tier limiters are the real budgets. It runs first, so a
|
|
74
|
+
* global max below a tier max silently replaces that tier — the sync budget
|
|
75
|
+
* was unreachable while this was a hardcoded 500. The default is therefore
|
|
76
|
+
* derived from the tiers, and an override that would shadow one is honoured
|
|
77
|
+
* but flagged at startup rather than quietly applied.
|
|
78
|
+
*/
|
|
79
|
+
exports.DEFAULT_GLOBAL_RATE_LIMIT_WINDOW_MS = 60000;
|
|
80
|
+
exports.GLOBAL_RATE_LIMIT_TIER_HEADROOM = 500;
|
|
81
|
+
/**
|
|
82
|
+
* Timestamping gets its own budget rather than sharing the sync one. Sync is
|
|
83
|
+
* chatty and high-volume; sealing a document is a deliberate, rare user action.
|
|
84
|
+
* Sharing a bucket would let ordinary sync traffic starve the seal endpoint, and
|
|
85
|
+
* a runaway seal loop degrade sync.
|
|
86
|
+
*
|
|
87
|
+
* The daily cap matters more than the burst cap: proxying collapses every user
|
|
88
|
+
* onto the server's IP, so one tenant can exhaust an upstream's per-IP allowance
|
|
89
|
+
* (open-tsa.eu publishes 60/minute) and lock out everyone else on this server.
|
|
90
|
+
*/
|
|
91
|
+
exports.DEFAULT_TIMESTAMP_RATE_LIMIT_WINDOW_MS = 60000;
|
|
92
|
+
exports.DEFAULT_TIMESTAMP_RATE_LIMIT_MAX = 10;
|
|
93
|
+
exports.DEFAULT_TIMESTAMP_DAILY_LIMIT_MAX = 500;
|
|
94
|
+
exports.TIMESTAMP_DAILY_WINDOW_MS = 24 * 60 * 60 * 1000;
|
|
95
|
+
/** `/system/*` admin routes: aggressive per-IP throttle. */
|
|
96
|
+
exports.DEFAULT_SYSTEM_RATE_LIMIT_WINDOW_MS = 60000;
|
|
97
|
+
exports.DEFAULT_SYSTEM_RATE_LIMIT_MAX = 30;
|
|
98
|
+
/** Device discovery scans every local tenant per request. */
|
|
99
|
+
exports.DEVICE_DISCOVERY_RATE_LIMIT = { windowMs: 60000, max: 10 };
|
|
100
|
+
/** Server-to-server peer routes; replication must not crawl. */
|
|
101
|
+
exports.PEER_RATE_LIMIT = { windowMs: 60000, max: 600 };
|
|
102
|
+
function resolveServerRateLimits(rateLimits) {
|
|
103
|
+
const auth = {
|
|
104
|
+
windowMs: rateLimits?.auth?.windowMs ?? exports.DEFAULT_AUTH_RATE_LIMIT_WINDOW_MS,
|
|
105
|
+
max: rateLimits?.auth?.max ?? exports.DEFAULT_AUTH_RATE_LIMIT_MAX,
|
|
106
|
+
};
|
|
107
|
+
const sync = {
|
|
108
|
+
windowMs: rateLimits?.sync?.windowMs ?? exports.DEFAULT_SYNC_RATE_LIMIT_WINDOW_MS,
|
|
109
|
+
max: rateLimits?.sync?.max ?? exports.DEFAULT_SYNC_RATE_LIMIT_MAX,
|
|
110
|
+
};
|
|
111
|
+
const timestamps = rateLimits?.timestamps;
|
|
112
|
+
return {
|
|
113
|
+
global: resolveGlobalRateLimit(rateLimits?.global, {
|
|
114
|
+
sync,
|
|
115
|
+
auth,
|
|
116
|
+
defaultWindowMs: exports.DEFAULT_GLOBAL_RATE_LIMIT_WINDOW_MS,
|
|
117
|
+
headroom: exports.GLOBAL_RATE_LIMIT_TIER_HEADROOM,
|
|
118
|
+
}),
|
|
119
|
+
auth,
|
|
120
|
+
sync,
|
|
121
|
+
timestamp: {
|
|
122
|
+
windowMs: timestamps?.windowMs ?? exports.DEFAULT_TIMESTAMP_RATE_LIMIT_WINDOW_MS,
|
|
123
|
+
max: timestamps?.max ?? exports.DEFAULT_TIMESTAMP_RATE_LIMIT_MAX,
|
|
124
|
+
dailyMax: timestamps?.dailyMax ?? exports.DEFAULT_TIMESTAMP_DAILY_LIMIT_MAX,
|
|
125
|
+
},
|
|
126
|
+
system: {
|
|
127
|
+
windowMs: rateLimits?.system?.windowMs ?? exports.DEFAULT_SYSTEM_RATE_LIMIT_WINDOW_MS,
|
|
128
|
+
max: rateLimits?.system?.max ?? exports.DEFAULT_SYSTEM_RATE_LIMIT_MAX,
|
|
129
|
+
},
|
|
130
|
+
device: exports.DEVICE_DISCOVERY_RATE_LIMIT,
|
|
131
|
+
peer: exports.PEER_RATE_LIMIT,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Composite key for the auth tier. Challenge requests include the username so
|
|
136
|
+
* that brute-forcing one account doesn't block legitimate users on the same
|
|
137
|
+
* IP. Authenticate requests omit username because the challenge token is
|
|
138
|
+
* already scoped to a single principal.
|
|
139
|
+
*/
|
|
140
|
+
function buildAuthRateLimitKey(scope, phase, tenantId, clientIp, body) {
|
|
141
|
+
const tenant = scope === "tenant" ? tenantId ?? "-" : "system";
|
|
142
|
+
if (phase === "challenge") {
|
|
143
|
+
// Bucket by username when supplied, otherwise by the signing public key a
|
|
144
|
+
// key-based client identifies with, so key-based clients still get a
|
|
145
|
+
// stable per-principal bucket instead of all sharing "-".
|
|
146
|
+
const principal = typeof body?.username === "string" && body.username.trim()
|
|
147
|
+
? body.username.trim().toLowerCase()
|
|
148
|
+
: typeof body?.signingPublicKey === "string" && body.signingPublicKey.trim()
|
|
149
|
+
? body.signingPublicKey.trim()
|
|
150
|
+
: "-";
|
|
151
|
+
return `${scope}:${tenant}:${phase}:${clientIp}:${principal}`;
|
|
152
|
+
}
|
|
153
|
+
return `${scope}:${tenant}:${phase}:${clientIp}`;
|
|
154
|
+
}
|
|
155
|
+
/** Bucket key of the timestamp tiers: tenant + principal + IP. */
|
|
156
|
+
function buildTimestampRateLimitKey(tier, tenantId, principal, clientIp) {
|
|
157
|
+
return `timestamp:${tier}:${tenantId ?? "unknown"}:${principal ?? "anonymous"}:${clientIp}`;
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=rateLimits.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rateLimits.js","sourceRoot":"","sources":["../../src/server/rateLimits.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Platform-neutral part of the server config: the `config.json` schema
|
|
3
|
+
* validator and the capability helpers. File access lives in the host
|
|
4
|
+
* (`node/server/config.ts` for Node).
|
|
5
|
+
*/
|
|
6
|
+
import type { ServerConfig, SystemAdminPrincipal } from "./types";
|
|
7
|
+
export interface ConfigBackupInfo {
|
|
8
|
+
file: string;
|
|
9
|
+
createdAt: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function isTenantCreationCapabilityRule(ruleKey: string): boolean;
|
|
12
|
+
export declare function isWildcardSystemAdminPrincipal(principal: SystemAdminPrincipal): boolean;
|
|
13
|
+
export declare function hasTenantCreationWildcardPrincipal(config: ServerConfig): boolean;
|
|
14
|
+
export declare function validateServerConfig(raw: unknown, filePath: string): ServerConfig;
|
|
15
|
+
export declare function isConfigBackupFilename(fileName: string): boolean;
|
|
16
|
+
export declare function parseConfigBackupTimestamp(fileName: string): string | null;
|
|
17
|
+
/**
|
|
18
|
+
* Where a host keeps `config.json` and its backups. `PUT /system/config`
|
|
19
|
+
* goes through this so the handler does not care whether the config is a
|
|
20
|
+
* file (Node) or a stored document (serverless hosts).
|
|
21
|
+
*/
|
|
22
|
+
export interface ServerConfigRepository {
|
|
23
|
+
listBackups(): ConfigBackupInfo[];
|
|
24
|
+
/** Throws `Config backup not found: <file>` / `Invalid config backup filename: <file>`. */
|
|
25
|
+
loadBackup(backupFile: string): ServerConfig;
|
|
26
|
+
/**
|
|
27
|
+
* Back up the current config (when there is one) and persist `config`.
|
|
28
|
+
* Returns the backup file name, or null when there was nothing to back up.
|
|
29
|
+
*/
|
|
30
|
+
replace(config: ServerConfig): string | null;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Extract all unique system admin principals from the capabilities config.
|
|
34
|
+
* Each principal is identified by (username, publicsignkey).
|
|
35
|
+
*/
|
|
36
|
+
export declare function extractAllPrincipals(config: ServerConfig): SystemAdminPrincipal[];
|
|
37
|
+
//# sourceMappingURL=serverConfig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serverConfig.d.ts","sourceRoot":"","sources":["../../src/server/serverConfig.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAGV,YAAY,EAGZ,oBAAoB,EAErB,MAAM,SAAS,CAAC;AAGjB,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAKD,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAcvE;AAED,wBAAgB,8BAA8B,CAC5C,SAAS,EAAE,oBAAoB,GAC9B,OAAO,CAET;AAED,wBAAgB,kCAAkC,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAKhF;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,YAAY,CAqDjF;AAyOD,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEhE;AAED,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAU1E;AAED;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACrC,WAAW,IAAI,gBAAgB,EAAE,CAAC;IAClC,2FAA2F;IAC3F,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,YAAY,CAAC;IAC7C;;;OAGG;IACH,OAAO,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,GAAG,IAAI,CAAC;CAC9C;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,YAAY,GACnB,oBAAoB,EAAE,CAexB"}
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Platform-neutral part of the server config: the `config.json` schema
|
|
4
|
+
* validator and the capability helpers. File access lives in the host
|
|
5
|
+
* (`node/server/config.ts` for Node).
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.isTenantCreationCapabilityRule = isTenantCreationCapabilityRule;
|
|
9
|
+
exports.isWildcardSystemAdminPrincipal = isWildcardSystemAdminPrincipal;
|
|
10
|
+
exports.hasTenantCreationWildcardPrincipal = hasTenantCreationWildcardPrincipal;
|
|
11
|
+
exports.validateServerConfig = validateServerConfig;
|
|
12
|
+
exports.isConfigBackupFilename = isConfigBackupFilename;
|
|
13
|
+
exports.parseConfigBackupTimestamp = parseConfigBackupTimestamp;
|
|
14
|
+
exports.extractAllPrincipals = extractAllPrincipals;
|
|
15
|
+
const types_1 = require("./peer/types");
|
|
16
|
+
const CONFIG_BACKUP_FILENAME_RE = /^config\.(\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}(?:\.\d{3})?Z)\.json$/;
|
|
17
|
+
function isTenantCreationCapabilityRule(ruleKey) {
|
|
18
|
+
const colonIdx = ruleKey.indexOf(":");
|
|
19
|
+
if (colonIdx === -1) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
const method = ruleKey.substring(0, colonIdx).toUpperCase();
|
|
23
|
+
const pathPattern = ruleKey.substring(colonIdx + 1);
|
|
24
|
+
// Segment-exact: tenant creation targets exactly one segment under
|
|
25
|
+
// `/system/tenants/` (the tenant id, which may itself be a `*` pattern). A
|
|
26
|
+
// prefix test would let a wildcard `*` principal be configured on an existing
|
|
27
|
+
// tenant's sub-resource, an over-grant (audit #6).
|
|
28
|
+
return method === "POST" && /^\/system\/tenants\/[^/]+\/?$/.test(pathPattern);
|
|
29
|
+
}
|
|
30
|
+
function isWildcardSystemAdminPrincipal(principal) {
|
|
31
|
+
return principal.username === "*" && principal.publicsignkey === "*";
|
|
32
|
+
}
|
|
33
|
+
function hasTenantCreationWildcardPrincipal(config) {
|
|
34
|
+
return Object.entries(config.capabilities).some(([ruleKey, principals]) => isTenantCreationCapabilityRule(ruleKey) &&
|
|
35
|
+
principals.some((principal) => isWildcardSystemAdminPrincipal(principal)));
|
|
36
|
+
}
|
|
37
|
+
function validateServerConfig(raw, filePath) {
|
|
38
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
39
|
+
throw new Error(`config.json at ${filePath} must be a JSON object`);
|
|
40
|
+
}
|
|
41
|
+
const obj = raw;
|
|
42
|
+
if (!obj.capabilities || typeof obj.capabilities !== "object" || Array.isArray(obj.capabilities)) {
|
|
43
|
+
throw new Error(`config.json at ${filePath} must have a "capabilities" object`);
|
|
44
|
+
}
|
|
45
|
+
const capabilities = {};
|
|
46
|
+
for (const [ruleKey, principals] of Object.entries(obj.capabilities)) {
|
|
47
|
+
validateCapabilityRule(ruleKey, filePath);
|
|
48
|
+
if (!Array.isArray(principals)) {
|
|
49
|
+
throw new Error(`config.json: capability rule "${ruleKey}" must map to an array of principals`);
|
|
50
|
+
}
|
|
51
|
+
capabilities[ruleKey] = principals.map((p, i) => validatePrincipal(p, ruleKey, i, filePath));
|
|
52
|
+
}
|
|
53
|
+
const rateLimits = validateRateLimits(obj.rateLimits, filePath);
|
|
54
|
+
const config = rateLimits ? { capabilities, rateLimits } : { capabilities };
|
|
55
|
+
const cluster = validateCluster(obj.cluster, filePath);
|
|
56
|
+
if (cluster) {
|
|
57
|
+
config.cluster = cluster;
|
|
58
|
+
}
|
|
59
|
+
const iroh = validateIroh(obj.iroh, filePath);
|
|
60
|
+
if (iroh) {
|
|
61
|
+
config.iroh = iroh;
|
|
62
|
+
}
|
|
63
|
+
const principalCount = Object.values(capabilities).reduce((sum, arr) => sum + arr.length, 0);
|
|
64
|
+
console.log(`[Config] Loaded config.json from ${filePath}: ${Object.keys(capabilities).length} capability rule(s), ${principalCount} principal entry/entries`);
|
|
65
|
+
return config;
|
|
66
|
+
}
|
|
67
|
+
function validateCluster(raw, filePath) {
|
|
68
|
+
if (raw === undefined) {
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
72
|
+
throw new Error(`config.json at ${filePath}: "cluster" must be an object`);
|
|
73
|
+
}
|
|
74
|
+
const obj = raw;
|
|
75
|
+
const cluster = {};
|
|
76
|
+
if (obj.autoSync !== undefined) {
|
|
77
|
+
if (typeof obj.autoSync !== "boolean") {
|
|
78
|
+
throw new Error(`config.json at ${filePath}: "cluster.autoSync" must be a boolean`);
|
|
79
|
+
}
|
|
80
|
+
cluster.autoSync = obj.autoSync;
|
|
81
|
+
}
|
|
82
|
+
if (obj.role !== undefined) {
|
|
83
|
+
if (!(0, types_1.isPeerRole)(obj.role)) {
|
|
84
|
+
throw new Error(`config.json at ${filePath}: "cluster.role" must be "peer", "hub" or "spoke"`);
|
|
85
|
+
}
|
|
86
|
+
cluster.role = obj.role;
|
|
87
|
+
}
|
|
88
|
+
return Object.keys(cluster).length > 0 ? cluster : undefined;
|
|
89
|
+
}
|
|
90
|
+
function validateIroh(raw, filePath) {
|
|
91
|
+
if (raw === undefined) {
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
95
|
+
throw new Error(`config.json at ${filePath}: "iroh" must be an object`);
|
|
96
|
+
}
|
|
97
|
+
const obj = raw;
|
|
98
|
+
if (obj.enabled !== undefined && typeof obj.enabled !== "boolean") {
|
|
99
|
+
throw new Error(`config.json at ${filePath}: "iroh.enabled" must be a boolean`);
|
|
100
|
+
}
|
|
101
|
+
if (obj.secretKeyPath !== undefined) {
|
|
102
|
+
if (typeof obj.secretKeyPath !== "string" || !obj.secretKeyPath.trim()) {
|
|
103
|
+
throw new Error(`config.json at ${filePath}: "iroh.secretKeyPath" must be a non-empty string`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
const iroh = {
|
|
107
|
+
enabled: obj.enabled === true,
|
|
108
|
+
};
|
|
109
|
+
if (typeof obj.secretKeyPath === "string") {
|
|
110
|
+
iroh.secretKeyPath = obj.secretKeyPath.trim();
|
|
111
|
+
}
|
|
112
|
+
return iroh;
|
|
113
|
+
}
|
|
114
|
+
function validateRateLimits(raw, filePath) {
|
|
115
|
+
if (raw === undefined) {
|
|
116
|
+
return undefined;
|
|
117
|
+
}
|
|
118
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
119
|
+
throw new Error(`config.json at ${filePath}: "rateLimits" must be an object`);
|
|
120
|
+
}
|
|
121
|
+
const obj = raw;
|
|
122
|
+
const auth = validateRateLimitConfig(obj.auth, "auth", filePath);
|
|
123
|
+
const sync = validateRateLimitConfig(obj.sync, "sync", filePath);
|
|
124
|
+
const timestamps = validateTimestampRateLimitConfig(obj.timestamps, filePath);
|
|
125
|
+
const global = validateRateLimitConfig(obj.global, "global", filePath);
|
|
126
|
+
const system = validateRateLimitConfig(obj.system, "system", filePath);
|
|
127
|
+
const rateLimits = {};
|
|
128
|
+
if (system) {
|
|
129
|
+
rateLimits.system = system;
|
|
130
|
+
}
|
|
131
|
+
if (auth) {
|
|
132
|
+
rateLimits.auth = auth;
|
|
133
|
+
}
|
|
134
|
+
if (sync) {
|
|
135
|
+
rateLimits.sync = sync;
|
|
136
|
+
}
|
|
137
|
+
if (timestamps) {
|
|
138
|
+
rateLimits.timestamps = timestamps;
|
|
139
|
+
}
|
|
140
|
+
if (global) {
|
|
141
|
+
rateLimits.global = global;
|
|
142
|
+
}
|
|
143
|
+
return Object.keys(rateLimits).length > 0 ? rateLimits : {};
|
|
144
|
+
}
|
|
145
|
+
function validateRateLimitConfig(raw, name, filePath) {
|
|
146
|
+
if (raw === undefined) {
|
|
147
|
+
return undefined;
|
|
148
|
+
}
|
|
149
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
150
|
+
throw new Error(`config.json at ${filePath}: "rateLimits.${name}" must be an object`);
|
|
151
|
+
}
|
|
152
|
+
const obj = raw;
|
|
153
|
+
const config = {};
|
|
154
|
+
if (obj.windowMs !== undefined) {
|
|
155
|
+
config.windowMs = validatePositiveInteger(obj.windowMs, `rateLimits.${name}.windowMs`, filePath);
|
|
156
|
+
}
|
|
157
|
+
if (obj.max !== undefined) {
|
|
158
|
+
config.max = validatePositiveInteger(obj.max, `rateLimits.${name}.max`, filePath);
|
|
159
|
+
}
|
|
160
|
+
return Object.keys(config).length > 0 ? config : {};
|
|
161
|
+
}
|
|
162
|
+
function validateTimestampRateLimitConfig(raw, filePath) {
|
|
163
|
+
const base = validateRateLimitConfig(raw, "timestamps", filePath);
|
|
164
|
+
if (!base) {
|
|
165
|
+
return undefined;
|
|
166
|
+
}
|
|
167
|
+
const obj = raw;
|
|
168
|
+
const config = { ...base };
|
|
169
|
+
if (obj.dailyMax !== undefined) {
|
|
170
|
+
config.dailyMax = validatePositiveInteger(obj.dailyMax, "rateLimits.timestamps.dailyMax", filePath);
|
|
171
|
+
}
|
|
172
|
+
return config;
|
|
173
|
+
}
|
|
174
|
+
function validatePositiveInteger(raw, fieldName, filePath) {
|
|
175
|
+
if (!Number.isInteger(raw) || raw <= 0) {
|
|
176
|
+
throw new Error(`config.json at ${filePath}: "${fieldName}" must be a positive integer`);
|
|
177
|
+
}
|
|
178
|
+
return raw;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Validate a capability rule key has the format `METHOD:PATH`.
|
|
182
|
+
*/
|
|
183
|
+
function validateCapabilityRule(rule, filePath) {
|
|
184
|
+
const colonIdx = rule.indexOf(":");
|
|
185
|
+
if (colonIdx === -1) {
|
|
186
|
+
throw new Error(`config.json at ${filePath}: invalid capability rule "${rule}" — expected "METHOD:PATH" format`);
|
|
187
|
+
}
|
|
188
|
+
const method = rule.substring(0, colonIdx).toUpperCase();
|
|
189
|
+
const pathPattern = rule.substring(colonIdx + 1);
|
|
190
|
+
const validMethods = ["ALL", "GET", "POST", "PUT", "DELETE", "PATCH"];
|
|
191
|
+
if (!validMethods.includes(method)) {
|
|
192
|
+
throw new Error(`config.json at ${filePath}: invalid method "${method}" in rule "${rule}" — expected one of ${validMethods.join(", ")}`);
|
|
193
|
+
}
|
|
194
|
+
if (!pathPattern.startsWith("/")) {
|
|
195
|
+
throw new Error(`config.json at ${filePath}: path pattern in rule "${rule}" must start with "/"`);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
function validatePrincipal(raw, ruleKey, index, filePath) {
|
|
199
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
200
|
+
throw new Error(`config.json at ${filePath}: principal #${index} in rule "${ruleKey}" must be an object`);
|
|
201
|
+
}
|
|
202
|
+
const obj = raw;
|
|
203
|
+
if (typeof obj.username !== "string" || obj.username.length === 0) {
|
|
204
|
+
throw new Error(`config.json at ${filePath}: principal #${index} in rule "${ruleKey}" must have a non-empty "username" string`);
|
|
205
|
+
}
|
|
206
|
+
if (typeof obj.publicsignkey !== "string" || obj.publicsignkey.length === 0) {
|
|
207
|
+
throw new Error(`config.json at ${filePath}: principal #${index} in rule "${ruleKey}" must have a non-empty "publicsignkey" string`);
|
|
208
|
+
}
|
|
209
|
+
const hasWildcardField = obj.username === "*" || obj.publicsignkey === "*";
|
|
210
|
+
if (hasWildcardField) {
|
|
211
|
+
if (obj.username !== "*" || obj.publicsignkey !== "*") {
|
|
212
|
+
throw new Error(`config.json at ${filePath}: principal #${index} in rule "${ruleKey}" must use "*" for both "username" and "publicsignkey"`);
|
|
213
|
+
}
|
|
214
|
+
if (!isTenantCreationCapabilityRule(ruleKey)) {
|
|
215
|
+
throw new Error(`config.json at ${filePath}: wildcard principal "*" is only allowed for POST:/system/tenants/... rules`);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return {
|
|
219
|
+
username: obj.username,
|
|
220
|
+
publicsignkey: obj.publicsignkey,
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
function isConfigBackupFilename(fileName) {
|
|
224
|
+
return CONFIG_BACKUP_FILENAME_RE.test(fileName);
|
|
225
|
+
}
|
|
226
|
+
function parseConfigBackupTimestamp(fileName) {
|
|
227
|
+
const match = CONFIG_BACKUP_FILENAME_RE.exec(fileName);
|
|
228
|
+
if (!match) {
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
return match[1].replace(/^(\d{4}-\d{2}-\d{2}T\d{2})-(\d{2})-(\d{2}(?:\.\d{3})?Z)$/, "$1:$2:$3");
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Extract all unique system admin principals from the capabilities config.
|
|
235
|
+
* Each principal is identified by (username, publicsignkey).
|
|
236
|
+
*/
|
|
237
|
+
function extractAllPrincipals(config) {
|
|
238
|
+
const seen = new Set();
|
|
239
|
+
const result = [];
|
|
240
|
+
for (const principals of Object.values(config.capabilities)) {
|
|
241
|
+
for (const p of principals) {
|
|
242
|
+
const key = `${p.username.toLowerCase()}\0${p.publicsignkey}`;
|
|
243
|
+
if (!seen.has(key)) {
|
|
244
|
+
seen.add(key);
|
|
245
|
+
result.push(p);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return result;
|
|
250
|
+
}
|
|
251
|
+
//# sourceMappingURL=serverConfig.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serverConfig.js","sourceRoot":"","sources":["../../src/server/serverConfig.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;AAqBH,wEAcC;AAED,wEAIC;AAED,gFAKC;AAED,oDAqDC;AAyOD,wDAEC;AAED,gEAUC;AAsBD,oDAiBC;AA1XD,wCAA0C;AAO1C,MAAM,yBAAyB,GAC7B,oEAAoE,CAAC;AAEvE,SAAgB,8BAA8B,CAAC,OAAe;IAC5D,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACtC,IAAI,QAAQ,KAAK,CAAC,CAAC,EAAE,CAAC;QACpB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;IAC5D,MAAM,WAAW,GAAG,OAAO,CAAC,SAAS,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC;IAEpD,mEAAmE;IACnE,2EAA2E;IAC3E,8EAA8E;IAC9E,mDAAmD;IACnD,OAAO,MAAM,KAAK,MAAM,IAAI,+BAA+B,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;AAChF,CAAC;AAED,SAAgB,8BAA8B,CAC5C,SAA+B;IAE/B,OAAO,SAAS,CAAC,QAAQ,KAAK,GAAG,IAAI,SAAS,CAAC,aAAa,KAAK,GAAG,CAAC;AACvE,CAAC;AAED,SAAgB,kCAAkC,CAAC,MAAoB;IACrE,OAAO,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,UAAU,CAAC,EAAE,EAAE,CACxE,8BAA8B,CAAC,OAAO,CAAC;QACvC,UAAU,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,8BAA8B,CAAC,SAAS,CAAC,CAAC,CAC1E,CAAC;AACJ,CAAC;AAED,SAAgB,oBAAoB,CAAC,GAAY,EAAE,QAAgB;IACjE,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAClE,MAAM,IAAI,KAAK,CAAC,kBAAkB,QAAQ,wBAAwB,CAAC,CAAC;IACtE,CAAC;IAED,MAAM,GAAG,GAAG,GAA8B,CAAC;IAE3C,IAAI,CAAC,GAAG,CAAC,YAAY,IAAI,OAAO,GAAG,CAAC,YAAY,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC;QACjG,MAAM,IAAI,KAAK,CACb,kBAAkB,QAAQ,oCAAoC,CAC/D,CAAC;IACJ,CAAC;IAED,MAAM,YAAY,GAA2C,EAAE,CAAC;IAEhE,KAAK,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,IAAI,MAAM,CAAC,OAAO,CAChD,GAAG,CAAC,YAAuC,CAC5C,EAAE,CAAC;QACF,sBAAsB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QAE1C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CACb,iCAAiC,OAAO,sCAAsC,CAC/E,CAAC;QACJ,CAAC;QAED,YAAY,CAAC,OAAO,CAAC,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAC9C,iBAAiB,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,QAAQ,CAAC,CAC3C,CAAC;IACJ,CAAC;IAED,MAAM,UAAU,GAAG,kBAAkB,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IAChE,MAAM,MAAM,GAAiB,UAAU,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC;IAE1F,MAAM,OAAO,GAAG,eAAe,CAAC,GAAG,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IACvD,IAAI,OAAO,EAAE,CAAC;QACZ,MAAM,CAAC,OAAO,GAAG,OAAO,CAAC;IAC3B,CAAC;IAED,MAAM,IAAI,GAAG,YAAY,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAC9C,IAAI,IAAI,EAAE,CAAC;QACT,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC;IACrB,CAAC;IAED,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,MAAM,CACvD,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,GAAG,GAAG,CAAC,MAAM,EAC9B,CAAC,CACF,CAAC;IACF,OAAO,CAAC,GAAG,CACT,oCAAoC,QAAQ,KAAK,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,MAAM,wBAAwB,cAAc,0BAA0B,CAClJ,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,eAAe,CAAC,GAAY,EAAE,QAAgB;IACrD,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACtB,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAClE,MAAM,IAAI,KAAK,CAAC,kBAAkB,QAAQ,+BAA+B,CAAC,CAAC;IAC7E,CAAC;IAED,MAAM,GAAG,GAAG,GAA8B,CAAC;IAC3C,MAAM,OAAO,GAAwB,EAAE,CAAC;IAExC,IAAI,GAAG,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC/B,IAAI,OAAO,GAAG,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;YACtC,MAAM,IAAI,KAAK,CAAC,kBAAkB,QAAQ,wCAAwC,CAAC,CAAC;QACtF,CAAC;QACD,OAAO,CAAC,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC;IAClC,CAAC;IACD,IAAI,GAAG,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC3B,IAAI,CAAC,IAAA,kBAAU,EAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CACb,kBAAkB,QAAQ,mDAAmD,CAC9E,CAAC;QACJ,CAAC;QACD,OAAO,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC;IAC1B,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;AAC/D,CAAC;AAED,SAAS,YAAY,CAAC,GAAY,EAAE,QAAgB;IAClD,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACtB,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAClE,MAAM,IAAI,KAAK,CAAC,kBAAkB,QAAQ,4BAA4B,CAAC,CAAC;IAC1E,CAAC;IACD,MAAM,GAAG,GAAG,GAA8B,CAAC;IAC3C,IAAI,GAAG,CAAC,OAAO,KAAK,SAAS,IAAI,OAAO,GAAG,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QAClE,MAAM,IAAI,KAAK,CAAC,kBAAkB,QAAQ,oCAAoC,CAAC,CAAC;IAClF,CAAC;IACD,IAAI,GAAG,CAAC,aAAa,KAAK,SAAS,EAAE,CAAC;QACpC,IAAI,OAAO,GAAG,CAAC,aAAa,KAAK,QAAQ,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,EAAE,EAAE,CAAC;YACvE,MAAM,IAAI,KAAK,CAAC,kBAAkB,QAAQ,mDAAmD,CAAC,CAAC;QACjG,CAAC;IACH,CAAC;IACD,MAAM,IAAI,GAAqB;QAC7B,OAAO,EAAE,GAAG,CAAC,OAAO,KAAK,IAAI;KAC9B,CAAC;IACF,IAAI,OAAO,GAAG,CAAC,aAAa,KAAK,QAAQ,EAAE,CAAC;QAC1C,IAAI,CAAC,aAAa,GAAG,GAAG,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC;IAChD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,kBAAkB,CACzB,GAAY,EACZ,QAAgB;IAEhB,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACtB,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAClE,MAAM,IAAI,KAAK,CAAC,kBAAkB,QAAQ,kCAAkC,CAAC,CAAC;IAChF,CAAC;IAED,MAAM,GAAG,GAAG,GAA8B,CAAC;IAC3C,MAAM,IAAI,GAAG,uBAAuB,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IACjE,MAAM,IAAI,GAAG,uBAAuB,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IACjE,MAAM,UAAU,GAAG,gCAAgC,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IAC9E,MAAM,MAAM,GAAG,uBAAuB,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;IACvE,MAAM,MAAM,GAAG,uBAAuB,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAEvE,MAAM,UAAU,GAA2B,EAAE,CAAC;IAC9C,IAAI,MAAM,EAAE,CAAC;QACX,UAAU,CAAC,MAAM,GAAG,MAAM,CAAC;IAC7B,CAAC;IACD,IAAI,IAAI,EAAE,CAAC;QACT,UAAU,CAAC,IAAI,GAAG,IAAI,CAAC;IACzB,CAAC;IACD,IAAI,IAAI,EAAE,CAAC;QACT,UAAU,CAAC,IAAI,GAAG,IAAI,CAAC;IACzB,CAAC;IACD,IAAI,UAAU,EAAE,CAAC;QACf,UAAU,CAAC,UAAU,GAAG,UAAU,CAAC;IACrC,CAAC;IACD,IAAI,MAAM,EAAE,CAAC;QACX,UAAU,CAAC,MAAM,GAAG,MAAM,CAAC;IAC7B,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;AAC9D,CAAC;AAED,SAAS,uBAAuB,CAC9B,GAAY,EACZ,IAAY,EACZ,QAAgB;IAEhB,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACtB,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAClE,MAAM,IAAI,KAAK,CAAC,kBAAkB,QAAQ,iBAAiB,IAAI,qBAAqB,CAAC,CAAC;IACxF,CAAC;IAED,MAAM,GAAG,GAAG,GAA8B,CAAC;IAC3C,MAAM,MAAM,GAAoB,EAAE,CAAC;IAEnC,IAAI,GAAG,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC/B,MAAM,CAAC,QAAQ,GAAG,uBAAuB,CACvC,GAAG,CAAC,QAAQ,EACZ,cAAc,IAAI,WAAW,EAC7B,QAAQ,CACT,CAAC;IACJ,CAAC;IACD,IAAI,GAAG,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;QAC1B,MAAM,CAAC,GAAG,GAAG,uBAAuB,CAClC,GAAG,CAAC,GAAG,EACP,cAAc,IAAI,MAAM,EACxB,QAAQ,CACT,CAAC;IACJ,CAAC;IAED,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;AACtD,CAAC;AAED,SAAS,gCAAgC,CACvC,GAAY,EACZ,QAAgB;IAEhB,MAAM,IAAI,GAAG,uBAAuB,CAAC,GAAG,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC;IAClE,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,GAAG,GAAG,GAA8B,CAAC;IAC3C,MAAM,MAAM,GAA6B,EAAE,GAAG,IAAI,EAAE,CAAC;IACrD,IAAI,GAAG,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC/B,MAAM,CAAC,QAAQ,GAAG,uBAAuB,CACvC,GAAG,CAAC,QAAQ,EACZ,gCAAgC,EAChC,QAAQ,CACT,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,uBAAuB,CAC9B,GAAY,EACZ,SAAiB,EACjB,QAAgB;IAEhB,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,IAAK,GAAc,IAAI,CAAC,EAAE,CAAC;QACnD,MAAM,IAAI,KAAK,CACb,kBAAkB,QAAQ,MAAM,SAAS,8BAA8B,CACxE,CAAC;IACJ,CAAC;IACD,OAAO,GAAa,CAAC;AACvB,CAAC;AAED;;GAEG;AACH,SAAS,sBAAsB,CAAC,IAAY,EAAE,QAAgB;IAC5D,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACnC,IAAI,QAAQ,KAAK,CAAC,CAAC,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CACb,kBAAkB,QAAQ,8BAA8B,IAAI,mCAAmC,CAChG,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;IACzD,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC;IAEjD,MAAM,YAAY,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IACtE,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CACb,kBAAkB,QAAQ,qBAAqB,MAAM,cAAc,IAAI,uBAAuB,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACxH,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CACb,kBAAkB,QAAQ,2BAA2B,IAAI,uBAAuB,CACjF,CAAC;IACJ,CAAC;AACH,CAAC;AAED,SAAS,iBAAiB,CACxB,GAAY,EACZ,OAAe,EACf,KAAa,EACb,QAAgB;IAEhB,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAClE,MAAM,IAAI,KAAK,CACb,kBAAkB,QAAQ,gBAAgB,KAAK,aAAa,OAAO,qBAAqB,CACzF,CAAC;IACJ,CAAC;IAED,MAAM,GAAG,GAAG,GAA8B,CAAC;IAE3C,IAAI,OAAO,GAAG,CAAC,QAAQ,KAAK,QAAQ,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAClE,MAAM,IAAI,KAAK,CACb,kBAAkB,QAAQ,gBAAgB,KAAK,aAAa,OAAO,2CAA2C,CAC/G,CAAC;IACJ,CAAC;IAED,IAAI,OAAO,GAAG,CAAC,aAAa,KAAK,QAAQ,IAAI,GAAG,CAAC,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5E,MAAM,IAAI,KAAK,CACb,kBAAkB,QAAQ,gBAAgB,KAAK,aAAa,OAAO,gDAAgD,CACpH,CAAC;IACJ,CAAC;IAED,MAAM,gBAAgB,GAAG,GAAG,CAAC,QAAQ,KAAK,GAAG,IAAI,GAAG,CAAC,aAAa,KAAK,GAAG,CAAC;IAC3E,IAAI,gBAAgB,EAAE,CAAC;QACrB,IAAI,GAAG,CAAC,QAAQ,KAAK,GAAG,IAAI,GAAG,CAAC,aAAa,KAAK,GAAG,EAAE,CAAC;YACtD,MAAM,IAAI,KAAK,CACb,kBAAkB,QAAQ,gBAAgB,KAAK,aAAa,OAAO,wDAAwD,CAC5H,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,8BAA8B,CAAC,OAAO,CAAC,EAAE,CAAC;YAC7C,MAAM,IAAI,KAAK,CACb,kBAAkB,QAAQ,6EAA6E,CACxG,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO;QACL,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,aAAa,EAAE,GAAG,CAAC,aAAa;KACjC,CAAC;AACJ,CAAC;AAED,SAAgB,sBAAsB,CAAC,QAAgB;IACrD,OAAO,yBAAyB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAClD,CAAC;AAED,SAAgB,0BAA0B,CAAC,QAAgB;IACzD,MAAM,KAAK,GAAG,yBAAyB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACvD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CACrB,0DAA0D,EAC1D,UAAU,CACX,CAAC;AACJ,CAAC;AAkBD;;;GAGG;AACH,SAAgB,oBAAoB,CAClC,MAAoB;IAEpB,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,MAAM,GAA2B,EAAE,CAAC;IAE1C,KAAK,MAAM,UAAU,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC;QAC5D,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;YAC3B,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,QAAQ,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,aAAa,EAAE,CAAC;YAC9D,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBACnB,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBACd,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACjB,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RFC 3161 timestamp proxy.
|
|
3
|
+
*
|
|
4
|
+
* Sealing a document (see the TeamSketchbook seal feature) needs a third-party
|
|
5
|
+
* attested time: the client hashes its own signature and asks a Time-Stamping
|
|
6
|
+
* Authority to sign that hash together with the TSA's clock reading.
|
|
7
|
+
*
|
|
8
|
+
* Most public TSAs cannot be called from a browser — they are http-only or send
|
|
9
|
+
* no CORS headers — so the server offers an authenticated proxy. It forwards
|
|
10
|
+
* opaque DER bytes and never parses them; the *client* verifies the returned
|
|
11
|
+
* token (messageImprint equality and chain to a trusted root), which is what
|
|
12
|
+
* makes a hostile or buggy proxy a denial-of-service risk rather than a forgery
|
|
13
|
+
* risk.
|
|
14
|
+
*
|
|
15
|
+
* SSRF is the hazard a forwarding endpoint always carries, so target URLs come
|
|
16
|
+
* only from server-side env config. A client may name a provider `id`; it can
|
|
17
|
+
* never supply a URL.
|
|
18
|
+
*/
|
|
19
|
+
/** Content type mandated by RFC 3161 §3.4 for a request. */
|
|
20
|
+
export declare const TIMESTAMP_QUERY_CONTENT_TYPE = "application/timestamp-query";
|
|
21
|
+
/** Content type mandated by RFC 3161 §3.4 for a response. */
|
|
22
|
+
export declare const TIMESTAMP_REPLY_CONTENT_TYPE = "application/timestamp-reply";
|
|
23
|
+
/**
|
|
24
|
+
* A TimeStampReq is a hash plus a little ASN.1 framing — a few hundred bytes at
|
|
25
|
+
* most. Anything larger is either a bug or an attempt to use us as an upload
|
|
26
|
+
* relay.
|
|
27
|
+
*/
|
|
28
|
+
export declare const MAX_TIMESTAMP_REQUEST_BYTES: number;
|
|
29
|
+
/**
|
|
30
|
+
* A TimeStampResp carries the token and the TSA certificate chain. Real tokens
|
|
31
|
+
* run 2–8 KB; the cap bounds memory when an upstream misbehaves.
|
|
32
|
+
*/
|
|
33
|
+
export declare const MAX_TIMESTAMP_RESPONSE_BYTES: number;
|
|
34
|
+
/** Per-provider timeout. Failover to the next provider is preferable to waiting. */
|
|
35
|
+
export declare const DEFAULT_TIMESTAMP_TIMEOUT_MS = 10000;
|
|
36
|
+
/** A configured upstream TSA, including the URL that never leaves the server. */
|
|
37
|
+
export interface TsaProviderConfig {
|
|
38
|
+
id: string;
|
|
39
|
+
name: string;
|
|
40
|
+
url: string;
|
|
41
|
+
/** TSA policy OID to request, when the provider publishes one. */
|
|
42
|
+
policyOid?: string;
|
|
43
|
+
/** eIDAS-qualified (or equivalent national-scheme) trust service. */
|
|
44
|
+
qualified: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Whether the token chains to a root that ships in common trust stores. When
|
|
47
|
+
* false the verifier must be handed the chain explicitly — the evidence
|
|
48
|
+
* bundle does that anyway, but it changes what third-party tooling can check
|
|
49
|
+
* unaided.
|
|
50
|
+
*/
|
|
51
|
+
rootInPublicTrustStores: boolean;
|
|
52
|
+
}
|
|
53
|
+
/** The provider description advertised to clients — deliberately without `url`. */
|
|
54
|
+
export type PublicTsaProvider = Omit<TsaProviderConfig, "url">;
|
|
55
|
+
/**
|
|
56
|
+
* Providers a client can name by id without the operator writing a URL.
|
|
57
|
+
*
|
|
58
|
+
* Terms of use differ and are the operator's call, which is why nothing here is
|
|
59
|
+
* enabled by default:
|
|
60
|
+
* - `aimoda` and `opentsa` state that general production use is fine;
|
|
61
|
+
* - `freetsa` is a community service with no usage restriction;
|
|
62
|
+
* - the DigiCert/Sectigo endpoints are provided for their own certificate
|
|
63
|
+
* customers' code signing, so using them as general infrastructure is not
|
|
64
|
+
* clearly permitted — they are listed for completeness, not recommended.
|
|
65
|
+
*/
|
|
66
|
+
export declare const BUILT_IN_TSA_PROVIDERS: Readonly<Record<string, TsaProviderConfig>>;
|
|
67
|
+
export interface ParseTsaProvidersOptions {
|
|
68
|
+
/** Permit http and loopback/private targets (local development, self-hosted TSA on the same box). */
|
|
69
|
+
allowInsecureUrls?: boolean;
|
|
70
|
+
/** Sink for configuration warnings; defaults to `console.warn`. */
|
|
71
|
+
warn?: (message: string) => void;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Parse `MINDOODB_TSA_PROVIDERS`.
|
|
75
|
+
*
|
|
76
|
+
* Comma-separated entries, each either a built-in id (`aimoda`) or a custom
|
|
77
|
+
* `id=url` pair (`inhouse=https://tsa.corp.example/tsr`). A trailing `!` on an
|
|
78
|
+
* entry marks it qualified, and `+` marks its root as publicly trusted:
|
|
79
|
+
*
|
|
80
|
+
* MINDOODB_TSA_PROVIDERS="aimoda,opentsa,belgium=http://tsa.belgium.be/connect!+"
|
|
81
|
+
*
|
|
82
|
+
* Unset or empty disables the proxy entirely. That is the safe default: a
|
|
83
|
+
* forwarding endpoint is outbound network access the operator should opt into,
|
|
84
|
+
* and Haven can still reach the browser-callable TSA directly without it.
|
|
85
|
+
*/
|
|
86
|
+
export declare function parseTsaProviders(raw: string | undefined, options?: ParseTsaProvidersOptions): TsaProviderConfig[];
|
|
87
|
+
/** Drop the URL before a provider list is handed to a client. */
|
|
88
|
+
export declare function toPublicTsaProviders(providers: TsaProviderConfig[]): PublicTsaProvider[];
|
|
89
|
+
export declare class TimestampProxyError extends Error {
|
|
90
|
+
readonly status: number;
|
|
91
|
+
/** Per-provider failures, for logging and for a client that wants to retry elsewhere. */
|
|
92
|
+
readonly attempts: TimestampAttempt[];
|
|
93
|
+
constructor(message: string, status: number,
|
|
94
|
+
/** Per-provider failures, for logging and for a client that wants to retry elsewhere. */
|
|
95
|
+
attempts?: TimestampAttempt[]);
|
|
96
|
+
}
|
|
97
|
+
export interface TimestampAttempt {
|
|
98
|
+
providerId: string;
|
|
99
|
+
ok: boolean;
|
|
100
|
+
error?: string;
|
|
101
|
+
httpStatus?: number;
|
|
102
|
+
durationMs: number;
|
|
103
|
+
}
|
|
104
|
+
export interface TimestampProxyResult {
|
|
105
|
+
providerId: string;
|
|
106
|
+
providerName: string;
|
|
107
|
+
/** Raw DER TimeStampResp. The caller does not interpret it. */
|
|
108
|
+
response: Uint8Array;
|
|
109
|
+
attempts: TimestampAttempt[];
|
|
110
|
+
}
|
|
111
|
+
export interface RequestTimestampOptions {
|
|
112
|
+
providers: TsaProviderConfig[];
|
|
113
|
+
/** DER-encoded TimeStampReq. */
|
|
114
|
+
request: Uint8Array;
|
|
115
|
+
/** Try this provider first; others remain as failover. */
|
|
116
|
+
preferredProviderId?: string;
|
|
117
|
+
timeoutMs?: number;
|
|
118
|
+
maxResponseBytes?: number;
|
|
119
|
+
fetchImpl?: typeof fetch;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* POST the request to each provider in turn, returning the first DER answer.
|
|
123
|
+
*
|
|
124
|
+
* Failover is per-provider and the reason for each failure is preserved: an
|
|
125
|
+
* operator debugging "sealing stopped working" needs to see that provider A
|
|
126
|
+
* timed out and provider B answered 403, not a single opaque 502.
|
|
127
|
+
*/
|
|
128
|
+
export declare function requestTimestampToken(options: RequestTimestampOptions): Promise<TimestampProxyResult>;
|
|
129
|
+
//# sourceMappingURL=timestampProxy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timestampProxy.d.ts","sourceRoot":"","sources":["../../src/server/timestampProxy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,4DAA4D;AAC5D,eAAO,MAAM,4BAA4B,gCAAgC,CAAC;AAC1E,6DAA6D;AAC7D,eAAO,MAAM,4BAA4B,gCAAgC,CAAC;AAE1E;;;;GAIG;AACH,eAAO,MAAM,2BAA2B,QAAW,CAAC;AACpD;;;GAGG;AACH,eAAO,MAAM,4BAA4B,QAAa,CAAC;AACvD,oFAAoF;AACpF,eAAO,MAAM,4BAA4B,QAAS,CAAC;AAEnD,iFAAiF;AACjF,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,kEAAkE;IAClE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qEAAqE;IACrE,SAAS,EAAE,OAAO,CAAC;IACnB;;;;;OAKG;IACH,uBAAuB,EAAE,OAAO,CAAC;CAClC;AAED,mFAAmF;AACnF,MAAM,MAAM,iBAAiB,GAAG,IAAI,CAAC,iBAAiB,EAAE,KAAK,CAAC,CAAC;AAE/D;;;;;;;;;;GAUG;AACH,eAAO,MAAM,sBAAsB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CA2C7E,CAAC;AAKH,MAAM,WAAW,wBAAwB;IACvC,qGAAqG;IACrG,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,mEAAmE;IACnE,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,OAAO,GAAE,wBAA6B,GACrC,iBAAiB,EAAE,CA8ErB;AAED,iEAAiE;AACjE,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,iBAAiB,EAAE,GAAG,iBAAiB,EAAE,CAExF;AAED,qBAAa,mBAAoB,SAAQ,KAAK;IAG1C,QAAQ,CAAC,MAAM,EAAE,MAAM;IACvB,yFAAyF;IACzF,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,EAAE;gBAHrC,OAAO,EAAE,MAAM,EACN,MAAM,EAAE,MAAM;IACvB,yFAAyF;IAChF,QAAQ,GAAE,gBAAgB,EAAO;CAK7C;AAED,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,EAAE,EAAE,OAAO,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,+DAA+D;IAC/D,QAAQ,EAAE,UAAU,CAAC;IACrB,QAAQ,EAAE,gBAAgB,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE,iBAAiB,EAAE,CAAC;IAC/B,gCAAgC;IAChC,OAAO,EAAE,UAAU,CAAC;IACpB,0DAA0D;IAC1D,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AA4ED;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,oBAAoB,CAAC,CAgG/B"}
|