mindoodb 0.0.84 → 0.0.86
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 +1 -0
- package/README.md +6 -4
- package/dist/appendonlystores/network/ClientNetworkContentAddressedStore.d.ts +15 -0
- package/dist/appendonlystores/network/ClientNetworkContentAddressedStore.d.ts.map +1 -1
- package/dist/appendonlystores/network/ClientNetworkContentAddressedStore.js +75 -1
- package/dist/appendonlystores/network/ClientNetworkContentAddressedStore.js.map +1 -1
- package/dist/appendonlystores/network/HttpTransport.d.ts +9 -1
- package/dist/appendonlystores/network/HttpTransport.d.ts.map +1 -1
- package/dist/appendonlystores/network/HttpTransport.js +38 -10
- package/dist/appendonlystores/network/HttpTransport.js.map +1 -1
- 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 +43 -1
- package/dist/core/BaseMindooDB.d.ts.map +1 -1
- package/dist/core/BaseMindooDB.js +209 -87
- package/dist/core/BaseMindooDB.js.map +1 -1
- package/dist/core/BaseMindooTenant.d.ts +14 -0
- package/dist/core/BaseMindooTenant.d.ts.map +1 -1
- package/dist/core/BaseMindooTenant.js +46 -0
- package/dist/core/BaseMindooTenant.js.map +1 -1
- package/dist/core/BaseMindooTenantDirectory.d.ts +10 -0
- package/dist/core/BaseMindooTenantDirectory.d.ts.map +1 -1
- package/dist/core/BaseMindooTenantDirectory.js +79 -8
- package/dist/core/BaseMindooTenantDirectory.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/appendonlystores/InMemoryContentAddressedStore.d.ts.map +1 -1
- package/dist/core/appendonlystores/InMemoryContentAddressedStore.js +1 -0
- package/dist/core/appendonlystores/InMemoryContentAddressedStore.js.map +1 -1
- package/dist/core/appendonlystores/network/AuthenticationService.d.ts +8 -0
- package/dist/core/appendonlystores/network/AuthenticationService.d.ts.map +1 -1
- package/dist/core/appendonlystores/network/AuthenticationService.js +19 -0
- package/dist/core/appendonlystores/network/AuthenticationService.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/network/NetworkTransport.d.ts +7 -1
- package/dist/core/appendonlystores/network/NetworkTransport.d.ts.map +1 -1
- package/dist/core/appendonlystores/network/types.d.ts +23 -0
- package/dist/core/appendonlystores/network/types.d.ts.map +1 -1
- package/dist/core/appendonlystores/network/types.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.map +1 -1
- package/dist/core/appendonlystores/sqlite/SqliteContentAddressedStore.js +21 -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 +253 -168
- package/dist/core/appendonlystores/syncStores.js.map +1 -1
- package/dist/core/appendonlystores/types.d.ts +8 -0
- package/dist/core/appendonlystores/types.d.ts.map +1 -1
- package/dist/core/appendonlystores/types.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/types.d.ts +61 -2
- 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/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/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 +1 -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 -1568
- 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/compressionMiddleware.d.ts +14 -0
- package/dist/node/server/compressionMiddleware.d.ts.map +1 -1
- package/dist/node/server/compressionMiddleware.js +46 -3
- package/dist/node/server/compressionMiddleware.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 +165 -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 +228 -0
- package/dist/server/SystemAdminAuth.js.map +1 -0
- package/dist/server/TenantManager.d.ts +330 -0
- package/dist/server/TenantManager.d.ts.map +1 -0
- package/dist/server/TenantManager.js +1186 -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 +1403 -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 +208 -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 +1071 -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 @@
|
|
|
1
|
+
{"version":3,"file":"CapabilityMatcher.d.ts","sourceRoot":"","sources":["../../src/server/CapabilityMatcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAwB,MAAM,SAAS,CAAC;AASlE,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,KAAK,CAAe;gBAEhB,MAAM,EAAE,YAAY;IAKhC;;;;OAIG;IACH,MAAM,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI;IAKlC,OAAO,CAAC,WAAW;IAUnB;;;;OAIG;IACH,YAAY,CACV,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,GACpB,OAAO;IA2BV;;;OAGG;IACH,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO;IAuBjE,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,gBAAgB;IA0BxB,OAAO,CAAC,oBAAoB;IAI5B,OAAO,CAAC,uBAAuB;IAI/B;;;;;;;;OAQG;IACH,OAAO,CAAC,MAAM,CAAC,oBAAoB;IAInC;;;OAGG;IACH,OAAO,CAAC,WAAW;CAoBpB;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGrE"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Capability matching engine for system admin authorization.
|
|
4
|
+
*
|
|
5
|
+
* Parses `METHOD:PATHPATTERN` rules from config.json and checks whether
|
|
6
|
+
* a given (method, path, username, publicsignkey) tuple is authorized.
|
|
7
|
+
*
|
|
8
|
+
* Matching semantics:
|
|
9
|
+
* - Rule method `ALL` matches any HTTP method.
|
|
10
|
+
* - Path patterns use `*` as a wildcard that matches any remaining characters.
|
|
11
|
+
* - All matching rules are unioned; access is granted if *any* matching rule
|
|
12
|
+
* lists a principal with both the correct username AND publicsignkey.
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.CapabilityMatcher = void 0;
|
|
16
|
+
exports.parseSystemTenantItemPath = parseSystemTenantItemPath;
|
|
17
|
+
const serverConfig_1 = require("./serverConfig");
|
|
18
|
+
class CapabilityMatcher {
|
|
19
|
+
constructor(config) {
|
|
20
|
+
this.rules = [];
|
|
21
|
+
this.parseConfig(config);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Hot-swap the internal rules from a new config.
|
|
25
|
+
* Existing authorization decisions in-flight are unaffected;
|
|
26
|
+
* subsequent calls to `isAuthorized` / `principalExists` use the new rules.
|
|
27
|
+
*/
|
|
28
|
+
reload(config) {
|
|
29
|
+
this.rules = [];
|
|
30
|
+
this.parseConfig(config);
|
|
31
|
+
}
|
|
32
|
+
parseConfig(config) {
|
|
33
|
+
for (const [ruleKey, principals] of Object.entries(config.capabilities)) {
|
|
34
|
+
const colonIdx = ruleKey.indexOf(":");
|
|
35
|
+
const method = ruleKey.substring(0, colonIdx).toUpperCase();
|
|
36
|
+
const pathPattern = ruleKey.substring(colonIdx + 1);
|
|
37
|
+
this.rules.push({ method, pathPattern, principals });
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Check whether a request is authorized.
|
|
42
|
+
*
|
|
43
|
+
* @returns `true` if any matching capability rule lists the given principal.
|
|
44
|
+
*/
|
|
45
|
+
isAuthorized(httpMethod, httpPath, username, publicsignkey) {
|
|
46
|
+
const method = httpMethod.toUpperCase();
|
|
47
|
+
const normalizedUsername = username.toLowerCase();
|
|
48
|
+
for (const rule of this.rules) {
|
|
49
|
+
if (!this.methodMatches(rule.method, method))
|
|
50
|
+
continue;
|
|
51
|
+
if (!this.pathMatches(rule.pathPattern, httpPath))
|
|
52
|
+
continue;
|
|
53
|
+
for (const principal of rule.principals) {
|
|
54
|
+
if (this.principalMatches(rule, method, httpPath, principal, normalizedUsername, publicsignkey)) {
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Check whether a principal exists in *any* capability rule.
|
|
63
|
+
* Used during challenge generation to reject unknown principals early.
|
|
64
|
+
*/
|
|
65
|
+
principalExists(username, publicsignkey) {
|
|
66
|
+
const normalizedUsername = username.toLowerCase();
|
|
67
|
+
for (const rule of this.rules) {
|
|
68
|
+
for (const principal of rule.principals) {
|
|
69
|
+
if (this.principalMatches(rule, rule.method, rule.pathPattern, principal, normalizedUsername, publicsignkey)) {
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
methodMatches(ruleMethod, requestMethod) {
|
|
77
|
+
return ruleMethod === "ALL" || ruleMethod === requestMethod;
|
|
78
|
+
}
|
|
79
|
+
principalMatches(rule, requestMethod, requestPath, principal, normalizedUsername, publicsignkey) {
|
|
80
|
+
if (principal.username.toLowerCase() === normalizedUsername &&
|
|
81
|
+
principal.publicsignkey === publicsignkey) {
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
if ((0, serverConfig_1.isWildcardSystemAdminPrincipal)(principal) &&
|
|
85
|
+
this.isTenantCreationRule(rule.method, rule.pathPattern) &&
|
|
86
|
+
this.isTenantCreationRequest(requestMethod, requestPath)) {
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
isTenantCreationRule(method, pathPattern) {
|
|
92
|
+
return method === "POST" && CapabilityMatcher.isTenantCreationPath(pathPattern);
|
|
93
|
+
}
|
|
94
|
+
isTenantCreationRequest(method, path) {
|
|
95
|
+
return method === "POST" && CapabilityMatcher.isTenantCreationPath(path);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Tenant creation targets exactly one path segment under `/system/tenants/`
|
|
99
|
+
* (the new tenant id) — e.g. `/system/tenants/acme`. A prefix (`startsWith`)
|
|
100
|
+
* test over-grants the wildcard tenant-creation principal to sub-resources of
|
|
101
|
+
* an *existing* tenant, e.g. any future `/system/tenants/acme/<sub>` route
|
|
102
|
+
* (audit #6). Require a segment-exact
|
|
103
|
+
* match so the wildcard authorizes creation only. A trailing slash is allowed
|
|
104
|
+
* but no further path segment.
|
|
105
|
+
*/
|
|
106
|
+
static isTenantCreationPath(path) {
|
|
107
|
+
return parseSystemTenantItemPath(path) !== null;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Match a path pattern against a request path.
|
|
111
|
+
* `*` matches any remaining characters (greedy).
|
|
112
|
+
*/
|
|
113
|
+
pathMatches(pattern, requestPath) {
|
|
114
|
+
const starIdx = pattern.indexOf("*");
|
|
115
|
+
if (starIdx === -1) {
|
|
116
|
+
return pattern === requestPath;
|
|
117
|
+
}
|
|
118
|
+
const prefix = pattern.substring(0, starIdx);
|
|
119
|
+
const suffix = pattern.substring(starIdx + 1);
|
|
120
|
+
if (!requestPath.startsWith(prefix)) {
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
if (suffix.length === 0) {
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
return requestPath.endsWith(suffix);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
exports.CapabilityMatcher = CapabilityMatcher;
|
|
130
|
+
/**
|
|
131
|
+
* Parse `/system/tenants/:tenantId` (optional trailing slash, no sub-resource).
|
|
132
|
+
* Returns the tenant id segment or `null`.
|
|
133
|
+
*/
|
|
134
|
+
function parseSystemTenantItemPath(path) {
|
|
135
|
+
const match = /^\/system\/tenants\/([^/]+)\/?$/.exec(path);
|
|
136
|
+
return match ? match[1] : null;
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=CapabilityMatcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CapabilityMatcher.js","sourceRoot":"","sources":["../../src/server/CapabilityMatcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server-wide device discovery: prove possession of a device signing key,
|
|
3
|
+
* then scan all tenants for an active grant and deliver RSA-wrapped
|
|
4
|
+
* `$publicinfos` plus admin public keys and the per-device join bootstrap —
|
|
5
|
+
* no join-response URI required.
|
|
6
|
+
*/
|
|
7
|
+
import type { CryptoAdapter } from "../core/crypto/CryptoAdapter";
|
|
8
|
+
import type { DeviceTenantDelivery } from "../core/types";
|
|
9
|
+
import type { TenantManager } from "./TenantManager";
|
|
10
|
+
export type { DeviceTenantDelivery };
|
|
11
|
+
export interface DeviceDiscoverResult {
|
|
12
|
+
tenants: DeviceTenantDelivery[];
|
|
13
|
+
}
|
|
14
|
+
export declare class DeviceDiscoveryAuthError extends Error {
|
|
15
|
+
constructor(message: string);
|
|
16
|
+
}
|
|
17
|
+
export declare class DeviceDiscoveryService {
|
|
18
|
+
private readonly tenantManager;
|
|
19
|
+
private readonly cryptoAdapter;
|
|
20
|
+
private challenges;
|
|
21
|
+
constructor(tenantManager: TenantManager, cryptoAdapter: CryptoAdapter);
|
|
22
|
+
/**
|
|
23
|
+
* Issue a short-lived, single-use challenge bound to `signingPublicKey`.
|
|
24
|
+
* Does not require the key to be on any tenant yet (discovery finds that).
|
|
25
|
+
*/
|
|
26
|
+
createChallenge(signingPublicKey: string): string;
|
|
27
|
+
/**
|
|
28
|
+
* Verify the Ed25519 signature over the challenge, then scan every local
|
|
29
|
+
* tenant for an active grant containing this signing key. Matching tenants
|
|
30
|
+
* receive a delivery with RSA-wrapped `$publicinfos` (parallelized).
|
|
31
|
+
*/
|
|
32
|
+
discover(challenge: string, signature: Uint8Array): Promise<DeviceDiscoverResult>;
|
|
33
|
+
private verifySignature;
|
|
34
|
+
private cleanup;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=DeviceDiscoveryService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DeviceDiscoveryService.d.ts","sourceRoot":"","sources":["../../src/server/DeviceDiscoveryService.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAElE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAarD,YAAY,EAAE,oBAAoB,EAAE,CAAC;AAErC,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,oBAAoB,EAAE,CAAC;CACjC;AAED,qBAAa,wBAAyB,SAAQ,KAAK;gBACrC,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,sBAAsB;IAI/B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAJhC,OAAO,CAAC,UAAU,CAAsC;gBAGrC,aAAa,EAAE,aAAa,EAC5B,aAAa,EAAE,aAAa;IAG/C;;;OAGG;IACH,eAAe,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM;IAkBjD;;;;OAIG;IACG,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,GAAG,OAAO,CAAC,oBAAoB,CAAC;YA0GzE,eAAe;IAkC7B,OAAO,CAAC,OAAO;CAahB"}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Server-wide device discovery: prove possession of a device signing key,
|
|
4
|
+
* then scan all tenants for an active grant and deliver RSA-wrapped
|
|
5
|
+
* `$publicinfos` plus admin public keys and the per-device join bootstrap —
|
|
6
|
+
* no join-response URI required.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.DeviceDiscoveryService = exports.DeviceDiscoveryAuthError = void 0;
|
|
10
|
+
const idGeneration_1 = require("../core/utils/idGeneration");
|
|
11
|
+
const RSAEncryption_1 = require("../core/crypto/RSAEncryption");
|
|
12
|
+
const CHALLENGE_TTL_MS = 5 * 60 * 1000;
|
|
13
|
+
const MAX_CHALLENGES = 10000;
|
|
14
|
+
class DeviceDiscoveryAuthError extends Error {
|
|
15
|
+
constructor(message) {
|
|
16
|
+
super(message);
|
|
17
|
+
this.name = "DeviceDiscoveryAuthError";
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
exports.DeviceDiscoveryAuthError = DeviceDiscoveryAuthError;
|
|
21
|
+
class DeviceDiscoveryService {
|
|
22
|
+
constructor(tenantManager, cryptoAdapter) {
|
|
23
|
+
this.tenantManager = tenantManager;
|
|
24
|
+
this.cryptoAdapter = cryptoAdapter;
|
|
25
|
+
this.challenges = new Map();
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Issue a short-lived, single-use challenge bound to `signingPublicKey`.
|
|
29
|
+
* Does not require the key to be on any tenant yet (discovery finds that).
|
|
30
|
+
*/
|
|
31
|
+
createChallenge(signingPublicKey) {
|
|
32
|
+
const trimmed = signingPublicKey.trim();
|
|
33
|
+
if (!trimmed) {
|
|
34
|
+
throw new Error("signingPublicKey is required");
|
|
35
|
+
}
|
|
36
|
+
const challenge = (0, idGeneration_1.generateRandomUuid)();
|
|
37
|
+
const now = Date.now();
|
|
38
|
+
this.challenges.set(challenge, {
|
|
39
|
+
challenge,
|
|
40
|
+
signingPublicKey: trimmed,
|
|
41
|
+
createdAt: now,
|
|
42
|
+
expiresAt: now + CHALLENGE_TTL_MS,
|
|
43
|
+
used: false,
|
|
44
|
+
});
|
|
45
|
+
this.cleanup();
|
|
46
|
+
return challenge;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Verify the Ed25519 signature over the challenge, then scan every local
|
|
50
|
+
* tenant for an active grant containing this signing key. Matching tenants
|
|
51
|
+
* receive a delivery with RSA-wrapped `$publicinfos` (parallelized).
|
|
52
|
+
*/
|
|
53
|
+
async discover(challenge, signature) {
|
|
54
|
+
const authChallenge = this.challenges.get(challenge);
|
|
55
|
+
if (!authChallenge) {
|
|
56
|
+
throw new DeviceDiscoveryAuthError("Challenge not found or expired");
|
|
57
|
+
}
|
|
58
|
+
if (Date.now() > authChallenge.expiresAt) {
|
|
59
|
+
this.challenges.delete(challenge);
|
|
60
|
+
throw new DeviceDiscoveryAuthError("Challenge expired");
|
|
61
|
+
}
|
|
62
|
+
if (authChallenge.used) {
|
|
63
|
+
throw new DeviceDiscoveryAuthError("Challenge already used");
|
|
64
|
+
}
|
|
65
|
+
authChallenge.used = true;
|
|
66
|
+
const ok = await this.verifySignature(challenge, signature, authChallenge.signingPublicKey);
|
|
67
|
+
if (!ok) {
|
|
68
|
+
throw new DeviceDiscoveryAuthError("Invalid signature");
|
|
69
|
+
}
|
|
70
|
+
const signingPublicKey = authChallenge.signingPublicKey;
|
|
71
|
+
const tenantIds = this.tenantManager.listTenants();
|
|
72
|
+
const matches = [];
|
|
73
|
+
for (const tenantId of tenantIds) {
|
|
74
|
+
try {
|
|
75
|
+
const loaded = await this.tenantManager.getTenant(tenantId);
|
|
76
|
+
const lookup = await loaded.directory.getUserBySigningPublicKey(signingPublicKey);
|
|
77
|
+
if (!lookup?.encryptionPublicKey)
|
|
78
|
+
continue;
|
|
79
|
+
matches.push({
|
|
80
|
+
tenantId,
|
|
81
|
+
adminSigningPublicKey: loaded.context.config.adminSigningPublicKey,
|
|
82
|
+
adminEncryptionPublicKey: loaded.context.config.adminEncryptionPublicKey,
|
|
83
|
+
encryptionPublicKey: lookup.encryptionPublicKey,
|
|
84
|
+
username_hash: typeof lookup.username === "string" && /^[a-f0-9]{64}$/i.test(lookup.username)
|
|
85
|
+
? lookup.username
|
|
86
|
+
: undefined,
|
|
87
|
+
identity_hashes: lookup.identityHashes,
|
|
88
|
+
joinResponseWrapped: typeof lookup.joinResponseWrapped === "string" && lookup.joinResponseWrapped.trim()
|
|
89
|
+
? lookup.joinResponseWrapped.trim()
|
|
90
|
+
: undefined,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
// Tenant missing directory / not loadable — skip.
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (matches.length === 0) {
|
|
98
|
+
return { tenants: [] };
|
|
99
|
+
}
|
|
100
|
+
const rsa = new RSAEncryption_1.RSAEncryption(this.cryptoAdapter);
|
|
101
|
+
const deliveries = await Promise.all(matches.map(async (match) => {
|
|
102
|
+
try {
|
|
103
|
+
const keys = await this.tenantManager.getPublicInfosKeysForTenant(match.tenantId);
|
|
104
|
+
if (!keys.length)
|
|
105
|
+
return null;
|
|
106
|
+
const wrappedPublicInfosKeys = await Promise.all(keys.map((rawKey) => rsa.wrapKeyToBase64(rawKey, match.encryptionPublicKey)));
|
|
107
|
+
// getAllKeys is newest-first; keep wrappedPublicInfosKey as the current generation.
|
|
108
|
+
const wrappedPublicInfosKey = wrappedPublicInfosKeys[0];
|
|
109
|
+
console.log(`[DeviceDiscovery] Wrapped ${wrappedPublicInfosKeys.length} $publicinfos version(s) for tenant ${match.tenantId}`);
|
|
110
|
+
return {
|
|
111
|
+
tenantId: match.tenantId,
|
|
112
|
+
adminSigningPublicKey: match.adminSigningPublicKey,
|
|
113
|
+
adminEncryptionPublicKey: match.adminEncryptionPublicKey,
|
|
114
|
+
wrappedPublicInfosKey,
|
|
115
|
+
...(wrappedPublicInfosKeys.length > 1
|
|
116
|
+
? { wrappedPublicInfosKeys }
|
|
117
|
+
: {}),
|
|
118
|
+
...(match.joinResponseWrapped
|
|
119
|
+
? { wrappedJoinResponse: match.joinResponseWrapped }
|
|
120
|
+
: {}),
|
|
121
|
+
...(match.username_hash ? { username_hash: match.username_hash } : {}),
|
|
122
|
+
...(match.identity_hashes?.length
|
|
123
|
+
? { identity_hashes: match.identity_hashes }
|
|
124
|
+
: {}),
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
}));
|
|
131
|
+
return { tenants: deliveries.filter((d) => d !== null) };
|
|
132
|
+
}
|
|
133
|
+
async verifySignature(challenge, signature, publicKeyPem) {
|
|
134
|
+
try {
|
|
135
|
+
const subtle = this.cryptoAdapter.getSubtle();
|
|
136
|
+
const pemContents = publicKeyPem
|
|
137
|
+
.replace(/-----BEGIN PUBLIC KEY-----/g, "")
|
|
138
|
+
.replace(/-----END PUBLIC KEY-----/g, "")
|
|
139
|
+
.replace(/\s/g, "");
|
|
140
|
+
const binaryDer = Uint8Array.from(atob(pemContents), (c) => c.charCodeAt(0));
|
|
141
|
+
const key = await subtle.importKey("spki", binaryDer.buffer, { name: "Ed25519" }, false, ["verify"]);
|
|
142
|
+
const data = new TextEncoder().encode(challenge);
|
|
143
|
+
return await subtle.verify("Ed25519", key, signature.buffer.slice(signature.byteOffset, signature.byteOffset + signature.byteLength), data.buffer);
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
cleanup() {
|
|
150
|
+
const now = Date.now();
|
|
151
|
+
for (const [id, entry] of this.challenges) {
|
|
152
|
+
if (entry.used || entry.expiresAt <= now) {
|
|
153
|
+
this.challenges.delete(id);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
while (this.challenges.size > MAX_CHALLENGES) {
|
|
157
|
+
const oldest = this.challenges.keys().next().value;
|
|
158
|
+
if (oldest === undefined)
|
|
159
|
+
break;
|
|
160
|
+
this.challenges.delete(oldest);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
exports.DeviceDiscoveryService = DeviceDiscoveryService;
|
|
165
|
+
//# sourceMappingURL=DeviceDiscoveryService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DeviceDiscoveryService.js","sourceRoot":"","sources":["../../src/server/DeviceDiscoveryService.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEH,6DAAgE;AAEhE,gEAA6D;AAI7D,MAAM,gBAAgB,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;AACvC,MAAM,cAAc,GAAG,KAAM,CAAC;AAgB9B,MAAa,wBAAyB,SAAQ,KAAK;IACjD,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;IACzC,CAAC;CACF;AALD,4DAKC;AAED,MAAa,sBAAsB;IAGjC,YACmB,aAA4B,EAC5B,aAA4B;QAD5B,kBAAa,GAAb,aAAa,CAAe;QAC5B,kBAAa,GAAb,aAAa,CAAe;QAJvC,eAAU,GAAG,IAAI,GAAG,EAA2B,CAAC;IAKrD,CAAC;IAEJ;;;OAGG;IACH,eAAe,CAAC,gBAAwB;QACtC,MAAM,OAAO,GAAG,gBAAgB,CAAC,IAAI,EAAE,CAAC;QACxC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;QAClD,CAAC;QACD,MAAM,SAAS,GAAG,IAAA,iCAAkB,GAAE,CAAC;QACvC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,SAAS,EAAE;YAC7B,SAAS;YACT,gBAAgB,EAAE,OAAO;YACzB,SAAS,EAAE,GAAG;YACd,SAAS,EAAE,GAAG,GAAG,gBAAgB;YACjC,IAAI,EAAE,KAAK;SACZ,CAAC,CAAC;QACH,IAAI,CAAC,OAAO,EAAE,CAAC;QACf,OAAO,SAAS,CAAC;IACnB,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,QAAQ,CAAC,SAAiB,EAAE,SAAqB;QACrD,MAAM,aAAa,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACrD,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,MAAM,IAAI,wBAAwB,CAAC,gCAAgC,CAAC,CAAC;QACvE,CAAC;QACD,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,aAAa,CAAC,SAAS,EAAE,CAAC;YACzC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YAClC,MAAM,IAAI,wBAAwB,CAAC,mBAAmB,CAAC,CAAC;QAC1D,CAAC;QACD,IAAI,aAAa,CAAC,IAAI,EAAE,CAAC;YACvB,MAAM,IAAI,wBAAwB,CAAC,wBAAwB,CAAC,CAAC;QAC/D,CAAC;QACD,aAAa,CAAC,IAAI,GAAG,IAAI,CAAC;QAE1B,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,eAAe,CACnC,SAAS,EACT,SAAS,EACT,aAAa,CAAC,gBAAgB,CAC/B,CAAC;QACF,IAAI,CAAC,EAAE,EAAE,CAAC;YACR,MAAM,IAAI,wBAAwB,CAAC,mBAAmB,CAAC,CAAC;QAC1D,CAAC;QAED,MAAM,gBAAgB,GAAG,aAAa,CAAC,gBAAgB,CAAC;QACxD,MAAM,SAAS,GAAG,IAAI,CAAC,aAAa,CAAC,WAAW,EAAE,CAAC;QAWnD,MAAM,OAAO,GAAY,EAAE,CAAC;QAE5B,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;YACjC,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;gBAC5D,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,yBAAyB,CAAC,gBAAgB,CAAC,CAAC;gBAClF,IAAI,CAAC,MAAM,EAAE,mBAAmB;oBAAE,SAAS;gBAE3C,OAAO,CAAC,IAAI,CAAC;oBACX,QAAQ;oBACR,qBAAqB,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,qBAAqB;oBAClE,wBAAwB,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,wBAAwB;oBACxE,mBAAmB,EAAE,MAAM,CAAC,mBAAmB;oBAC/C,aAAa,EACX,OAAO,MAAM,CAAC,QAAQ,KAAK,QAAQ,IAAI,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC;wBAC5E,CAAC,CAAC,MAAM,CAAC,QAAQ;wBACjB,CAAC,CAAC,SAAS;oBACf,eAAe,EAAE,MAAM,CAAC,cAAc;oBACtC,mBAAmB,EACjB,OAAO,MAAM,CAAC,mBAAmB,KAAK,QAAQ,IAAI,MAAM,CAAC,mBAAmB,CAAC,IAAI,EAAE;wBACjF,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,IAAI,EAAE;wBACnC,CAAC,CAAC,SAAS;iBAChB,CAAC,CAAC;YACL,CAAC;YAAC,MAAM,CAAC;gBACP,kDAAkD;YACpD,CAAC;QACH,CAAC;QAED,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;QACzB,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,6BAAa,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAClD,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,GAAG,CAClC,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,EAAwC,EAAE;YAChE,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,2BAA2B,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;gBAClF,IAAI,CAAC,IAAI,CAAC,MAAM;oBAAE,OAAO,IAAI,CAAC;gBAC9B,MAAM,sBAAsB,GAAG,MAAM,OAAO,CAAC,GAAG,CAC9C,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,CAAC,eAAe,CAAC,MAAM,EAAE,KAAK,CAAC,mBAAmB,CAAC,CAAC,CAC7E,CAAC;gBACF,oFAAoF;gBACpF,MAAM,qBAAqB,GAAG,sBAAsB,CAAC,CAAC,CAAE,CAAC;gBACzD,OAAO,CAAC,GAAG,CACT,6BAA6B,sBAAsB,CAAC,MAAM,uCAAuC,KAAK,CAAC,QAAQ,EAAE,CAClH,CAAC;gBACF,OAAO;oBACL,QAAQ,EAAE,KAAK,CAAC,QAAQ;oBACxB,qBAAqB,EAAE,KAAK,CAAC,qBAAqB;oBAClD,wBAAwB,EAAE,KAAK,CAAC,wBAAwB;oBACxD,qBAAqB;oBACrB,GAAG,CAAC,sBAAsB,CAAC,MAAM,GAAG,CAAC;wBACnC,CAAC,CAAC,EAAE,sBAAsB,EAAE;wBAC5B,CAAC,CAAC,EAAE,CAAC;oBACP,GAAG,CAAC,KAAK,CAAC,mBAAmB;wBAC3B,CAAC,CAAC,EAAE,mBAAmB,EAAE,KAAK,CAAC,mBAAmB,EAAE;wBACpD,CAAC,CAAC,EAAE,CAAC;oBACP,GAAG,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,KAAK,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oBACtE,GAAG,CAAC,KAAK,CAAC,eAAe,EAAE,MAAM;wBAC/B,CAAC,CAAC,EAAE,eAAe,EAAE,KAAK,CAAC,eAAe,EAAE;wBAC5C,CAAC,CAAC,EAAE,CAAC;iBACR,CAAC;YACJ,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC,CAAC,CACH,CAAC;QAEF,OAAO,EAAE,OAAO,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAA6B,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC;IACtF,CAAC;IAEO,KAAK,CAAC,eAAe,CAC3B,SAAiB,EACjB,SAAqB,EACrB,YAAoB;QAEpB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,SAAS,EAAE,CAAC;YAC9C,MAAM,WAAW,GAAG,YAAY;iBAC7B,OAAO,CAAC,6BAA6B,EAAE,EAAE,CAAC;iBAC1C,OAAO,CAAC,2BAA2B,EAAE,EAAE,CAAC;iBACxC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YACtB,MAAM,SAAS,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;YAC7E,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,SAAS,CAChC,MAAM,EACN,SAAS,CAAC,MAAqB,EAC/B,EAAE,IAAI,EAAE,SAAS,EAAE,EACnB,KAAK,EACL,CAAC,QAAQ,CAAC,CACX,CAAC;YACF,MAAM,IAAI,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YACjD,OAAO,MAAM,MAAM,CAAC,MAAM,CACxB,SAAS,EACT,GAAG,EACH,SAAS,CAAC,MAAM,CAAC,KAAK,CACpB,SAAS,CAAC,UAAU,EACpB,SAAS,CAAC,UAAU,GAAG,SAAS,CAAC,UAAU,CAC7B,EAChB,IAAI,CAAC,MAAqB,CAC3B,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAEO,OAAO;QACb,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,KAAK,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YAC1C,IAAI,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,SAAS,IAAI,GAAG,EAAE,CAAC;gBACzC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAC7B,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC,UAAU,CAAC,IAAI,GAAG,cAAc,EAAE,CAAC;YAC7C,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;YACnD,IAAI,MAAM,KAAK,SAAS;gBAAE,MAAM;YAChC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;CACF;AA5LD,wDA4LC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-tenant persistent record of executed document-history purges.
|
|
3
|
+
*
|
|
4
|
+
* Server-side purge execution (docs/accesscontrol.md §13) physically deletes a
|
|
5
|
+
* document's history from the tenant's on-disk stores. Because
|
|
6
|
+
* {@link ContentAddressedStore.purgeDocHistory} leaves no tombstone, a stale
|
|
7
|
+
* client that has not yet reconciled could re-push the very entries that were
|
|
8
|
+
* just purged and the server would re-accept them. This registry is the churn
|
|
9
|
+
* guard: it remembers which `purgeRequestDocId`s have already been executed (so
|
|
10
|
+
* we never purge twice) and which `docId`s were purged per database (so the sync
|
|
11
|
+
* push path can reject any re-upload of a purged document).
|
|
12
|
+
*
|
|
13
|
+
* Stored under `<tenantId>/purged-docs.json` in the server data store (a file
|
|
14
|
+
* below the data directory on Node).
|
|
15
|
+
*/
|
|
16
|
+
import type { ServerDataStore } from "./ServerDataStore";
|
|
17
|
+
export declare class PurgedDocRegistry {
|
|
18
|
+
private readonly dataStore;
|
|
19
|
+
private readonly key;
|
|
20
|
+
private processedRequestDocIds;
|
|
21
|
+
private purgedDocIds;
|
|
22
|
+
private loaded;
|
|
23
|
+
constructor(dataStore: ServerDataStore, key: string);
|
|
24
|
+
private ensureLoaded;
|
|
25
|
+
private save;
|
|
26
|
+
/** True when this purge request was already executed. */
|
|
27
|
+
isRequestProcessed(purgeRequestDocId: string): boolean;
|
|
28
|
+
/** Record that a document was purged from a database (re-push denylist). */
|
|
29
|
+
recordPurgedDoc(dbId: string, docId: string): void;
|
|
30
|
+
/** Mark a purge request as executed and persist the registry. */
|
|
31
|
+
markRequestProcessed(purgeRequestDocId: string): void;
|
|
32
|
+
/** The set of purged docIds for a database (live; used by the push reject path). */
|
|
33
|
+
getPurgedDocIds(dbId: string): Set<string>;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=PurgedDocRegistry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PurgedDocRegistry.d.ts","sourceRoot":"","sources":["../../src/server/PurgedDocRegistry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAUzD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAkB;IAC5C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,sBAAsB,CAAc;IAC5C,OAAO,CAAC,YAAY,CAA2B;IAC/C,OAAO,CAAC,MAAM,CAAS;gBAEX,SAAS,EAAE,eAAe,EAAE,GAAG,EAAE,MAAM;IAOnD,OAAO,CAAC,YAAY;IA8BpB,OAAO,CAAC,IAAI;IAWZ,yDAAyD;IACzD,kBAAkB,CAAC,iBAAiB,EAAE,MAAM,GAAG,OAAO;IAKtD,4EAA4E;IAC5E,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAUlD,iEAAiE;IACjE,oBAAoB,CAAC,iBAAiB,EAAE,MAAM,GAAG,IAAI;IAMrD,oFAAoF;IACpF,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;CAI3C"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Per-tenant persistent record of executed document-history purges.
|
|
4
|
+
*
|
|
5
|
+
* Server-side purge execution (docs/accesscontrol.md §13) physically deletes a
|
|
6
|
+
* document's history from the tenant's on-disk stores. Because
|
|
7
|
+
* {@link ContentAddressedStore.purgeDocHistory} leaves no tombstone, a stale
|
|
8
|
+
* client that has not yet reconciled could re-push the very entries that were
|
|
9
|
+
* just purged and the server would re-accept them. This registry is the churn
|
|
10
|
+
* guard: it remembers which `purgeRequestDocId`s have already been executed (so
|
|
11
|
+
* we never purge twice) and which `docId`s were purged per database (so the sync
|
|
12
|
+
* push path can reject any re-upload of a purged document).
|
|
13
|
+
*
|
|
14
|
+
* Stored under `<tenantId>/purged-docs.json` in the server data store (a file
|
|
15
|
+
* below the data directory on Node).
|
|
16
|
+
*/
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.PurgedDocRegistry = void 0;
|
|
19
|
+
class PurgedDocRegistry {
|
|
20
|
+
constructor(dataStore, key) {
|
|
21
|
+
this.loaded = false;
|
|
22
|
+
this.dataStore = dataStore;
|
|
23
|
+
this.key = key;
|
|
24
|
+
this.processedRequestDocIds = new Set();
|
|
25
|
+
this.purgedDocIds = new Map();
|
|
26
|
+
}
|
|
27
|
+
ensureLoaded() {
|
|
28
|
+
if (this.loaded)
|
|
29
|
+
return;
|
|
30
|
+
this.loaded = true;
|
|
31
|
+
try {
|
|
32
|
+
const raw = this.dataStore.readText(this.key);
|
|
33
|
+
if (raw === null)
|
|
34
|
+
return;
|
|
35
|
+
const data = JSON.parse(raw);
|
|
36
|
+
if (Array.isArray(data.processedRequestDocIds)) {
|
|
37
|
+
this.processedRequestDocIds = new Set(data.processedRequestDocIds.filter((id) => typeof id === "string"));
|
|
38
|
+
}
|
|
39
|
+
if (data.purgedDocIds && typeof data.purgedDocIds === "object") {
|
|
40
|
+
for (const [dbId, ids] of Object.entries(data.purgedDocIds)) {
|
|
41
|
+
if (Array.isArray(ids)) {
|
|
42
|
+
this.purgedDocIds.set(dbId, new Set(ids.filter((id) => typeof id === "string")));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
// Corrupt or unreadable registry: start from empty rather than crashing
|
|
49
|
+
// the server. A subsequent save will overwrite it.
|
|
50
|
+
this.processedRequestDocIds = new Set();
|
|
51
|
+
this.purgedDocIds = new Map();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
save() {
|
|
55
|
+
const data = {
|
|
56
|
+
version: 1,
|
|
57
|
+
processedRequestDocIds: [...this.processedRequestDocIds],
|
|
58
|
+
purgedDocIds: Object.fromEntries([...this.purgedDocIds.entries()].map(([dbId, ids]) => [dbId, [...ids]])),
|
|
59
|
+
};
|
|
60
|
+
this.dataStore.writeText(this.key, JSON.stringify(data, null, 2));
|
|
61
|
+
}
|
|
62
|
+
/** True when this purge request was already executed. */
|
|
63
|
+
isRequestProcessed(purgeRequestDocId) {
|
|
64
|
+
this.ensureLoaded();
|
|
65
|
+
return this.processedRequestDocIds.has(purgeRequestDocId);
|
|
66
|
+
}
|
|
67
|
+
/** Record that a document was purged from a database (re-push denylist). */
|
|
68
|
+
recordPurgedDoc(dbId, docId) {
|
|
69
|
+
this.ensureLoaded();
|
|
70
|
+
let set = this.purgedDocIds.get(dbId);
|
|
71
|
+
if (!set) {
|
|
72
|
+
set = new Set();
|
|
73
|
+
this.purgedDocIds.set(dbId, set);
|
|
74
|
+
}
|
|
75
|
+
set.add(docId);
|
|
76
|
+
}
|
|
77
|
+
/** Mark a purge request as executed and persist the registry. */
|
|
78
|
+
markRequestProcessed(purgeRequestDocId) {
|
|
79
|
+
this.ensureLoaded();
|
|
80
|
+
this.processedRequestDocIds.add(purgeRequestDocId);
|
|
81
|
+
this.save();
|
|
82
|
+
}
|
|
83
|
+
/** The set of purged docIds for a database (live; used by the push reject path). */
|
|
84
|
+
getPurgedDocIds(dbId) {
|
|
85
|
+
this.ensureLoaded();
|
|
86
|
+
return this.purgedDocIds.get(dbId) ?? new Set();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
exports.PurgedDocRegistry = PurgedDocRegistry;
|
|
90
|
+
//# sourceMappingURL=PurgedDocRegistry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PurgedDocRegistry.js","sourceRoot":"","sources":["../../src/server/PurgedDocRegistry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where the server keeps its own small state: the server identity, trusted
|
|
3
|
+
* servers, the server key bag, tenant configs and per-tenant registries.
|
|
4
|
+
*
|
|
5
|
+
* Keys are `/`-separated relative paths, and on Node they are exactly the
|
|
6
|
+
* file paths below the data directory (`server.identity.json`,
|
|
7
|
+
* `trusted-servers.json`, `server.keybag`, `<tenantId>/config.json`,
|
|
8
|
+
* `<tenantId>/purged-docs.json`), so existing servers keep reading their data.
|
|
9
|
+
* Other hosts map the same keys onto their own storage, e.g. a Durable
|
|
10
|
+
* Object's SQLite.
|
|
11
|
+
*
|
|
12
|
+
* The interface is synchronous on purpose: the server code that reads this
|
|
13
|
+
* state (tenant lookup, purge denylist) is synchronous today, and both hosts
|
|
14
|
+
* have synchronous storage (Node `fs`, Durable Object SQLite).
|
|
15
|
+
*
|
|
16
|
+
* Entry payloads never go through here; they live in the content-addressed
|
|
17
|
+
* stores (see {@link ServerStoreProvider}).
|
|
18
|
+
*/
|
|
19
|
+
import type { ContentAddressedStore } from "../core/types";
|
|
20
|
+
import type { StoreKind } from "../core/appendonlystores/types";
|
|
21
|
+
import type { TenantConfig } from "./types";
|
|
22
|
+
export interface ServerDataStore {
|
|
23
|
+
/** True when `key` holds a value or has children (a "directory"). */
|
|
24
|
+
exists(key: string): boolean;
|
|
25
|
+
readText(key: string): string | null;
|
|
26
|
+
writeText(key: string, value: string): void;
|
|
27
|
+
readBytes(key: string): Uint8Array | null;
|
|
28
|
+
writeBytes(key: string, value: Uint8Array): void;
|
|
29
|
+
/** Names of the direct children of `prefix` ("" for the root) that have children themselves. */
|
|
30
|
+
listDirectories(prefix: string): string[];
|
|
31
|
+
/** Remove `prefix` and everything below it. */
|
|
32
|
+
deleteTree(prefix: string): void;
|
|
33
|
+
}
|
|
34
|
+
/** Stores of one tenant, as the tenant manager uses them. */
|
|
35
|
+
export interface TenantStoreFactory {
|
|
36
|
+
getStore(dbId: string, storeKind: StoreKind): ContentAddressedStore;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* How a host provides the content-addressed stores of a tenant. On Node these
|
|
40
|
+
* are the on-disk stores below `<dataDir>/<tenantId>/stores`.
|
|
41
|
+
*/
|
|
42
|
+
export interface ServerStoreProvider {
|
|
43
|
+
/** Called whenever a tenant is (re)loaded; the result is cached with the tenant. */
|
|
44
|
+
createTenantStores(tenantId: string, config: TenantConfig): TenantStoreFactory;
|
|
45
|
+
/** Database ids this server holds for a tenant. */
|
|
46
|
+
listDatabases(tenantId: string): string[];
|
|
47
|
+
/**
|
|
48
|
+
* Drop all stores of a removed tenant. Optional: on Node the stores live
|
|
49
|
+
* inside the tenant directory and go away with {@link ServerDataStore.deleteTree}.
|
|
50
|
+
*/
|
|
51
|
+
removeTenantStores?(tenantId: string): void | Promise<void>;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Volatile {@link ServerDataStore}: tests, and hosts that seed their state at
|
|
55
|
+
* startup.
|
|
56
|
+
*/
|
|
57
|
+
export declare class MemoryServerDataStore implements ServerDataStore {
|
|
58
|
+
private readonly values;
|
|
59
|
+
exists(key: string): boolean;
|
|
60
|
+
readText(key: string): string | null;
|
|
61
|
+
writeText(key: string, value: string): void;
|
|
62
|
+
readBytes(key: string): Uint8Array | null;
|
|
63
|
+
writeBytes(key: string, value: Uint8Array): void;
|
|
64
|
+
listDirectories(prefix: string): string[];
|
|
65
|
+
deleteTree(prefix: string): void;
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=ServerDataStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ServerDataStore.d.ts","sourceRoot":"","sources":["../../src/server/ServerDataStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C,MAAM,WAAW,eAAe;IAC9B,qEAAqE;IACrE,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAC7B,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IACrC,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5C,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAAC;IAC1C,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;IACjD,gGAAgG;IAChG,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC1C,+CAA+C;IAC/C,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAED,6DAA6D;AAC7D,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,GAAG,qBAAqB,CAAC;CACrE;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,oFAAoF;IACpF,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,kBAAkB,CAAC;IAC/E,mDAAmD;IACnD,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC1C;;;OAGG;IACH,kBAAkB,CAAC,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7D;AAMD;;;GAGG;AACH,qBAAa,qBAAsB,YAAW,eAAe;IAC3D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0C;IAEjE,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAW5B,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAMpC,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAI3C,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI;IAMzC,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI;IAIhD,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE;IAazC,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;CAQjC"}
|