mindoodb 0.0.50 → 0.0.53
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 +11 -2
- package/dist/appendonlystores/network/ClientNetworkContentAddressedStore.d.ts +13 -1
- package/dist/appendonlystores/network/ClientNetworkContentAddressedStore.d.ts.map +1 -1
- package/dist/appendonlystores/network/ClientNetworkContentAddressedStore.js +45 -20
- package/dist/appendonlystores/network/ClientNetworkContentAddressedStore.js.map +1 -1
- package/dist/appendonlystores/network/HttpTransport.d.ts +2 -0
- package/dist/appendonlystores/network/HttpTransport.d.ts.map +1 -1
- package/dist/appendonlystores/network/HttpTransport.js +6 -62
- package/dist/appendonlystores/network/HttpTransport.js.map +1 -1
- package/dist/appendonlystores/network/ServerNetworkContentAddressedStore.d.ts +24 -0
- package/dist/appendonlystores/network/ServerNetworkContentAddressedStore.d.ts.map +1 -1
- package/dist/appendonlystores/network/ServerNetworkContentAddressedStore.js +75 -24
- package/dist/appendonlystores/network/ServerNetworkContentAddressedStore.js.map +1 -1
- package/dist/browser/index.mjs +72 -0
- package/dist/core/BaseMindooDB.d.ts +89 -14
- package/dist/core/BaseMindooDB.d.ts.map +1 -1
- package/dist/core/BaseMindooDB.js +692 -201
- package/dist/core/BaseMindooDB.js.map +1 -1
- package/dist/core/BaseMindooTenant.d.ts +59 -7
- package/dist/core/BaseMindooTenant.d.ts.map +1 -1
- package/dist/core/BaseMindooTenant.js +427 -90
- package/dist/core/BaseMindooTenant.js.map +1 -1
- package/dist/core/BaseMindooTenantDirectory.d.ts +61 -9
- package/dist/core/BaseMindooTenantDirectory.d.ts.map +1 -1
- package/dist/core/BaseMindooTenantDirectory.js +363 -35
- package/dist/core/BaseMindooTenantDirectory.js.map +1 -1
- package/dist/core/BaseMindooTenantFactory.d.ts +17 -1
- package/dist/core/BaseMindooTenantFactory.d.ts.map +1 -1
- package/dist/core/BaseMindooTenantFactory.js +292 -16
- package/dist/core/BaseMindooTenantFactory.js.map +1 -1
- package/dist/core/accesscontrol/DirectoryStateNode.d.ts +68 -1
- package/dist/core/accesscontrol/DirectoryStateNode.d.ts.map +1 -1
- package/dist/core/accesscontrol/DirectoryStateNode.js +157 -4
- package/dist/core/accesscontrol/DirectoryStateNode.js.map +1 -1
- package/dist/core/accesscontrol/directoryProjection.d.ts.map +1 -1
- package/dist/core/accesscontrol/directoryProjection.js +14 -5
- package/dist/core/accesscontrol/directoryProjection.js.map +1 -1
- package/dist/core/accesscontrol/grantKeys.d.ts +17 -14
- package/dist/core/accesscontrol/grantKeys.d.ts.map +1 -1
- package/dist/core/accesscontrol/grantKeys.js +51 -21
- package/dist/core/accesscontrol/grantKeys.js.map +1 -1
- package/dist/core/accesscontrol/types.d.ts +13 -7
- package/dist/core/accesscontrol/types.d.ts.map +1 -1
- package/dist/core/accesscontrol/types.js +16 -10
- package/dist/core/accesscontrol/types.js.map +1 -1
- package/dist/core/appendonlystores/network/AuthenticationService.d.ts +7 -0
- package/dist/core/appendonlystores/network/AuthenticationService.d.ts.map +1 -1
- package/dist/core/appendonlystores/network/AuthenticationService.js +70 -14
- package/dist/core/appendonlystores/network/AuthenticationService.js.map +1 -1
- package/dist/core/appendonlystores/network/entryWireCodec.d.ts +51 -0
- package/dist/core/appendonlystores/network/entryWireCodec.d.ts.map +1 -0
- package/dist/core/appendonlystores/network/entryWireCodec.js +93 -0
- package/dist/core/appendonlystores/network/entryWireCodec.js.map +1 -0
- package/dist/core/builtinDbInvariants.d.ts +53 -0
- package/dist/core/builtinDbInvariants.d.ts.map +1 -0
- package/dist/core/builtinDbInvariants.js +147 -0
- package/dist/core/builtinDbInvariants.js.map +1 -0
- package/dist/core/copy/feasibility.d.ts.map +1 -1
- package/dist/core/copy/feasibility.js +3 -0
- package/dist/core/copy/feasibility.js.map +1 -1
- package/dist/core/copy/flatten.d.ts.map +1 -1
- package/dist/core/copy/flatten.js +7 -2
- package/dist/core/copy/flatten.js.map +1 -1
- package/dist/core/copy/host.d.ts +5 -0
- package/dist/core/copy/host.d.ts.map +1 -1
- package/dist/core/copy/preflight.d.ts.map +1 -1
- package/dist/core/copy/preflight.js +7 -1
- package/dist/core/copy/preflight.js.map +1 -1
- package/dist/core/copy/types.d.ts +8 -1
- package/dist/core/copy/types.d.ts.map +1 -1
- package/dist/core/crypto/EntrySignature.d.ts +8 -2
- package/dist/core/crypto/EntrySignature.d.ts.map +1 -1
- package/dist/core/crypto/EntrySignature.js +14 -5
- package/dist/core/crypto/EntrySignature.js.map +1 -1
- package/dist/core/crypto/MindooDocSigner.d.ts.map +1 -1
- package/dist/core/crypto/MindooDocSigner.js +11 -2
- package/dist/core/crypto/MindooDocSigner.js.map +1 -1
- package/dist/core/crypto/RSAEncryption.d.ts +19 -0
- package/dist/core/crypto/RSAEncryption.d.ts.map +1 -1
- package/dist/core/crypto/RSAEncryption.js +36 -3
- package/dist/core/crypto/RSAEncryption.js.map +1 -1
- package/dist/core/crypto/privateKeyEncryption.js +1 -1
- package/dist/core/crypto/privateKeyEncryption.js.map +1 -1
- package/dist/core/crypto/rsaOaep3072.d.ts +12 -0
- package/dist/core/crypto/rsaOaep3072.d.ts.map +1 -0
- package/dist/core/crypto/rsaOaep3072.js +30 -0
- package/dist/core/crypto/rsaOaep3072.js.map +1 -0
- package/dist/core/databaseIdValidation.d.ts +23 -0
- package/dist/core/databaseIdValidation.d.ts.map +1 -1
- package/dist/core/databaseIdValidation.js +59 -1
- package/dist/core/databaseIdValidation.js.map +1 -1
- package/dist/core/index.d.ts +9 -2
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +40 -4
- package/dist/core/index.js.map +1 -1
- package/dist/core/join/deviceJoinBootstrap.d.ts +23 -0
- package/dist/core/join/deviceJoinBootstrap.d.ts.map +1 -0
- package/dist/core/join/deviceJoinBootstrap.js +37 -0
- package/dist/core/join/deviceJoinBootstrap.js.map +1 -0
- package/dist/core/keys/KeyBag.d.ts +20 -2
- package/dist/core/keys/KeyBag.d.ts.map +1 -1
- package/dist/core/keys/KeyBag.js +22 -10
- package/dist/core/keys/KeyBag.js.map +1 -1
- package/dist/core/logging/MindooLogger.d.ts.map +1 -1
- package/dist/core/logging/MindooLogger.js +65 -40
- package/dist/core/logging/MindooLogger.js.map +1 -1
- package/dist/core/tenantIdValidation.d.ts.map +1 -1
- package/dist/core/tenantIdValidation.js +1 -1
- package/dist/core/tenantIdValidation.js.map +1 -1
- package/dist/core/tenantSetup.d.ts +109 -0
- package/dist/core/tenantSetup.d.ts.map +1 -0
- package/dist/core/tenantSetup.js +250 -0
- package/dist/core/tenantSetup.js.map +1 -0
- package/dist/core/types.d.ts +333 -43
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +27 -9
- package/dist/core/types.js.map +1 -1
- package/dist/core/uri/joinRequestUri.d.ts +37 -0
- package/dist/core/uri/joinRequestUri.d.ts.map +1 -0
- package/dist/core/uri/joinRequestUri.js +168 -0
- package/dist/core/uri/joinRequestUri.js.map +1 -0
- package/dist/core/userid/canonicalUsername.d.ts +66 -0
- package/dist/core/userid/canonicalUsername.d.ts.map +1 -0
- package/dist/core/userid/canonicalUsername.js +235 -0
- package/dist/core/userid/canonicalUsername.js.map +1 -0
- package/dist/core/userid/index.d.ts +9 -0
- package/dist/core/userid/index.d.ts.map +1 -1
- package/dist/core/userid/index.js +14 -0
- package/dist/core/userid/index.js.map +1 -1
- package/dist/core/userkeys/UserKeyDocument.d.ts +50 -0
- package/dist/core/userkeys/UserKeyDocument.d.ts.map +1 -0
- package/dist/core/userkeys/UserKeyDocument.js +145 -0
- package/dist/core/userkeys/UserKeyDocument.js.map +1 -0
- package/dist/core/userkeys/UserKeyManager.d.ts +170 -0
- package/dist/core/userkeys/UserKeyManager.d.ts.map +1 -0
- package/dist/core/userkeys/UserKeyManager.js +1277 -0
- package/dist/core/userkeys/UserKeyManager.js.map +1 -0
- package/dist/core/userkeys/fingerprint.d.ts +17 -0
- package/dist/core/userkeys/fingerprint.d.ts.map +1 -0
- package/dist/core/userkeys/fingerprint.js +59 -0
- package/dist/core/userkeys/fingerprint.js.map +1 -0
- package/dist/core/userkeys/index.d.ts +11 -0
- package/dist/core/userkeys/index.d.ts.map +1 -0
- package/dist/core/userkeys/index.js +49 -0
- package/dist/core/userkeys/index.js.map +1 -0
- package/dist/core/userkeys/recipients.d.ts +51 -0
- package/dist/core/userkeys/recipients.d.ts.map +1 -0
- package/dist/core/userkeys/recipients.js +292 -0
- package/dist/core/userkeys/recipients.js.map +1 -0
- package/dist/core/userkeys/resolveUserKeyDocument.d.ts +21 -0
- package/dist/core/userkeys/resolveUserKeyDocument.d.ts.map +1 -0
- package/dist/core/userkeys/resolveUserKeyDocument.js +98 -0
- package/dist/core/userkeys/resolveUserKeyDocument.js.map +1 -0
- package/dist/core/userkeys/sealedCrypto.d.ts +21 -0
- package/dist/core/userkeys/sealedCrypto.d.ts.map +1 -0
- package/dist/core/userkeys/sealedCrypto.js +79 -0
- package/dist/core/userkeys/sealedCrypto.js.map +1 -0
- package/dist/core/userkeys/sealedTypes.d.ts +72 -0
- package/dist/core/userkeys/sealedTypes.d.ts.map +1 -0
- package/dist/core/userkeys/sealedTypes.js +14 -0
- package/dist/core/userkeys/sealedTypes.js.map +1 -0
- package/dist/core/userkeys/types.d.ts +70 -0
- package/dist/core/userkeys/types.d.ts.map +1 -0
- package/dist/core/userkeys/types.js +48 -0
- package/dist/core/userkeys/types.js.map +1 -0
- package/dist/core/userkeys/validateUserKeyDocument.d.ts +19 -0
- package/dist/core/userkeys/validateUserKeyDocument.d.ts.map +1 -0
- package/dist/core/userkeys/validateUserKeyDocument.js +42 -0
- package/dist/core/userkeys/validateUserKeyDocument.js.map +1 -0
- package/dist/core/utils/idGeneration.d.ts +39 -20
- package/dist/core/utils/idGeneration.d.ts.map +1 -1
- package/dist/core/utils/idGeneration.js +82 -62
- package/dist/core/utils/idGeneration.js.map +1 -1
- package/dist/core/utils/index.d.ts +1 -1
- package/dist/core/utils/index.d.ts.map +1 -1
- package/dist/core/utils/index.js +4 -1
- package/dist/core/utils/index.js.map +1 -1
- package/dist/node/server/CapabilityMatcher.d.ts +5 -0
- package/dist/node/server/CapabilityMatcher.d.ts.map +1 -1
- package/dist/node/server/CapabilityMatcher.js +10 -1
- package/dist/node/server/CapabilityMatcher.js.map +1 -1
- package/dist/node/server/DeviceDiscoveryService.d.ts +36 -0
- package/dist/node/server/DeviceDiscoveryService.d.ts.map +1 -0
- package/dist/node/server/DeviceDiscoveryService.js +165 -0
- package/dist/node/server/DeviceDiscoveryService.js.map +1 -0
- package/dist/node/server/MindooDBServer.d.ts +13 -0
- package/dist/node/server/MindooDBServer.d.ts.map +1 -1
- package/dist/node/server/MindooDBServer.js +99 -61
- package/dist/node/server/MindooDBServer.js.map +1 -1
- package/dist/node/server/SystemAdminAuth.d.ts +7 -0
- package/dist/node/server/SystemAdminAuth.d.ts.map +1 -1
- package/dist/node/server/SystemAdminAuth.js +4 -1
- package/dist/node/server/SystemAdminAuth.js.map +1 -1
- package/dist/node/server/TenantManager.d.ts +29 -0
- package/dist/node/server/TenantManager.d.ts.map +1 -1
- package/dist/node/server/TenantManager.js +146 -7
- package/dist/node/server/TenantManager.js.map +1 -1
- package/package.json +5 -5
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tenant setup document helpers.
|
|
3
|
+
*
|
|
4
|
+
* The singleton directory document `tenantsetup` is encrypted under
|
|
5
|
+
* `$publicinfos` so it syncs to every member (and to the sync server). The
|
|
6
|
+
* human-readable tenant label itself is field-encrypted under the tenant
|
|
7
|
+
* `default` key (`label_encrypted` / `label_encrypted_key`) so the server
|
|
8
|
+
* cannot read the display name — same pattern as `user_details_encrypted`
|
|
9
|
+
* on grant documents.
|
|
10
|
+
*
|
|
11
|
+
* The document also records the tenant's administrators. An admin holds no
|
|
12
|
+
* `grantaccess` document of its own, so without this list a member can only
|
|
13
|
+
* name the administration key by its fingerprint. Each entry carries the
|
|
14
|
+
* admin's name field-encrypted under `default` plus its device key pairs in
|
|
15
|
+
* the very same `userKeyPairs` shape a grant uses (docs/accesscontrol.md
|
|
16
|
+
* §6.5), so the same helpers read and write both, and additional admins or
|
|
17
|
+
* admin devices can be appended later.
|
|
18
|
+
*/
|
|
19
|
+
import { GrantKeyPair, MindooDB, MindooTenant, TENANT_SETUP_DOC_ID, SigningKeyPair } from "./types";
|
|
20
|
+
export { TENANT_SETUP_DOC_ID };
|
|
21
|
+
/**
|
|
22
|
+
* One administrator as stored on the `tenantsetup` document. The name is
|
|
23
|
+
* field-encrypted under `default`; the device keys use the canonical
|
|
24
|
+
* `userKeyPairs` list of a grant document so both can be parsed by
|
|
25
|
+
* {@link extractKeyPairs}.
|
|
26
|
+
*/
|
|
27
|
+
export interface TenantAdministratorData {
|
|
28
|
+
/** Base64 AES-GCM ciphertext of the canonical username under `default`. */
|
|
29
|
+
username_encrypted?: string;
|
|
30
|
+
/** Key id used for `username_encrypted`; always `"default"`. */
|
|
31
|
+
username_encrypted_key?: string;
|
|
32
|
+
/** This admin's device key pairs, same shape as a grant's `userKeyPairs`. */
|
|
33
|
+
userKeyPairs?: unknown;
|
|
34
|
+
/** Trusted time (ms since Unix epoch) at which the entry was first written. */
|
|
35
|
+
addedAt?: number;
|
|
36
|
+
}
|
|
37
|
+
export interface TenantSetupData {
|
|
38
|
+
/**
|
|
39
|
+
* @deprecated Legacy plaintext label. New writes use `label_encrypted`.
|
|
40
|
+
* Still read for older tenants until the next admin write migrates them.
|
|
41
|
+
*/
|
|
42
|
+
label?: string;
|
|
43
|
+
/** Base64 AES-GCM ciphertext of the UTF-8 label under `default`. */
|
|
44
|
+
label_encrypted?: string;
|
|
45
|
+
/** Key id used for `label_encrypted`; always `"default"`. */
|
|
46
|
+
label_encrypted_key?: string;
|
|
47
|
+
/** The tenant's administrators, oldest first. */
|
|
48
|
+
administrators?: TenantAdministratorData[];
|
|
49
|
+
}
|
|
50
|
+
/** An administrator entry with its name decrypted, as read by callers. */
|
|
51
|
+
export interface TenantAdministrator {
|
|
52
|
+
/**
|
|
53
|
+
* Canonical username. Absent when the reader has no `default` key (e.g. a
|
|
54
|
+
* device that joined but has not imported the tenant key yet).
|
|
55
|
+
*/
|
|
56
|
+
username?: string;
|
|
57
|
+
/** The admin's device key pairs (§6.5), active ones first. */
|
|
58
|
+
keyPairs: GrantKeyPair[];
|
|
59
|
+
addedAt?: number;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Read the tenant label from the directory database's `tenantsetup` document.
|
|
63
|
+
* Requires the tenant `default` key to decrypt `label_encrypted`. Returns
|
|
64
|
+
* `undefined` when the document is missing, the key is absent, or there is no
|
|
65
|
+
* label. Legacy plaintext `label` is still accepted for older tenants.
|
|
66
|
+
*/
|
|
67
|
+
export declare function readTenantSetupLabel(directoryDb: MindooDB, tenant: MindooTenant): Promise<string | undefined>;
|
|
68
|
+
/**
|
|
69
|
+
* Create or update the `tenantsetup` document with the given label.
|
|
70
|
+
* Must be signed with the tenant admin signing key. Stores the label as
|
|
71
|
+
* `label_encrypted` under the tenant `default` key and clears any legacy
|
|
72
|
+
* plaintext `label` field.
|
|
73
|
+
*/
|
|
74
|
+
export declare function writeTenantSetupLabel(directoryDb: MindooDB, label: string, adminSigningKeyPair: SigningKeyPair, adminSigningKeyPassword: string, tenant: MindooTenant): Promise<void>;
|
|
75
|
+
/**
|
|
76
|
+
* The tenant's administrators from the `tenantsetup` document, oldest first.
|
|
77
|
+
* Names need the tenant `default` key; entries whose name cannot be decrypted
|
|
78
|
+
* are still returned (with their key pairs) so callers can at least match a
|
|
79
|
+
* signing key. Returns an empty list for tenants created before this field.
|
|
80
|
+
*/
|
|
81
|
+
export declare function readTenantSetupAdministrators(directoryDb: MindooDB, tenant: MindooTenant): Promise<TenantAdministrator[]>;
|
|
82
|
+
/**
|
|
83
|
+
* Record an administrator on the `tenantsetup` document: its name
|
|
84
|
+
* field-encrypted under `default` plus its device key pairs. Must be signed
|
|
85
|
+
* with the tenant admin signing key.
|
|
86
|
+
*
|
|
87
|
+
* An entry for the same admin — matched by name, or by sharing a signing key
|
|
88
|
+
* when the name is unreadable — is updated in place and has its key pairs
|
|
89
|
+
* merged, so passing only a new pair enrolls another device of an admin that is
|
|
90
|
+
* already listed. Otherwise a new entry is appended. Idempotent when called
|
|
91
|
+
* again with the same name and keys.
|
|
92
|
+
*/
|
|
93
|
+
export declare function writeTenantSetupAdministrator(directoryDb: MindooDB, administrator: {
|
|
94
|
+
username: string;
|
|
95
|
+
keyPairs: GrantKeyPair[];
|
|
96
|
+
}, adminSigningKeyPair: SigningKeyPair, adminSigningKeyPassword: string, tenant: MindooTenant): Promise<void>;
|
|
97
|
+
/**
|
|
98
|
+
* Record an administrator only when it is missing from `tenantsetup`, and
|
|
99
|
+
* report whether a write happened. Tenants created before the
|
|
100
|
+
* `administrators` field have no entry at all, and a grant is a natural moment
|
|
101
|
+
* to heal that: the admin proves its identity and its keys there anyway. The
|
|
102
|
+
* check keeps repeated grants from appending a no-op revision to the
|
|
103
|
+
* append-only store.
|
|
104
|
+
*/
|
|
105
|
+
export declare function ensureTenantSetupAdministrator(directoryDb: MindooDB, administrator: {
|
|
106
|
+
username: string;
|
|
107
|
+
keyPairs: GrantKeyPair[];
|
|
108
|
+
}, adminSigningKeyPair: SigningKeyPair, adminSigningKeyPassword: string, tenant: MindooTenant): Promise<boolean>;
|
|
109
|
+
//# sourceMappingURL=tenantSetup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tenantSetup.d.ts","sourceRoot":"","sources":["../../src/core/tenantSetup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAEL,YAAY,EACZ,QAAQ,EACR,YAAY,EAEZ,mBAAmB,EACnB,cAAc,EACf,MAAM,SAAS,CAAC;AAOjB,OAAO,EAAE,mBAAmB,EAAE,CAAC;AAE/B;;;;;GAKG;AACH,MAAM,WAAW,uBAAuB;IACtC,2EAA2E;IAC3E,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,gEAAgE;IAChE,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,6EAA6E;IAC7E,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,+EAA+E;IAC/E,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oEAAoE;IACpE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,6DAA6D;IAC7D,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,iDAAiD;IACjD,cAAc,CAAC,EAAE,uBAAuB,EAAE,CAAC;CAC5C;AAED,0EAA0E;AAC1E,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8DAA8D;IAC9D,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAsDD;;;;;GAKG;AACH,wBAAsB,oBAAoB,CACxC,WAAW,EAAE,QAAQ,EACrB,MAAM,EAAE,YAAY,GACnB,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAoB7B;AAED;;;;;GAKG;AACH,wBAAsB,qBAAqB,CACzC,WAAW,EAAE,QAAQ,EACrB,KAAK,EAAE,MAAM,EACb,mBAAmB,EAAE,cAAc,EACnC,uBAAuB,EAAE,MAAM,EAC/B,MAAM,EAAE,YAAY,GACnB,OAAO,CAAC,IAAI,CAAC,CAaf;AAsCD;;;;;GAKG;AACH,wBAAsB,6BAA6B,CACjD,WAAW,EAAE,QAAQ,EACrB,MAAM,EAAE,YAAY,GACnB,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAwBhC;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,6BAA6B,CACjD,WAAW,EAAE,QAAQ,EACrB,aAAa,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,YAAY,EAAE,CAAA;CAAE,EAC7D,mBAAmB,EAAE,cAAc,EACnC,uBAAuB,EAAE,MAAM,EAC/B,MAAM,EAAE,YAAY,GACnB,OAAO,CAAC,IAAI,CAAC,CAkDf;AAED;;;;;;;GAOG;AACH,wBAAsB,8BAA8B,CAClD,WAAW,EAAE,QAAQ,EACrB,aAAa,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,YAAY,EAAE,CAAA;CAAE,EAC7D,mBAAmB,EAAE,cAAc,EACnC,uBAAuB,EAAE,MAAM,EAC/B,MAAM,EAAE,YAAY,GACnB,OAAO,CAAC,OAAO,CAAC,CA2BlB"}
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Tenant setup document helpers.
|
|
4
|
+
*
|
|
5
|
+
* The singleton directory document `tenantsetup` is encrypted under
|
|
6
|
+
* `$publicinfos` so it syncs to every member (and to the sync server). The
|
|
7
|
+
* human-readable tenant label itself is field-encrypted under the tenant
|
|
8
|
+
* `default` key (`label_encrypted` / `label_encrypted_key`) so the server
|
|
9
|
+
* cannot read the display name — same pattern as `user_details_encrypted`
|
|
10
|
+
* on grant documents.
|
|
11
|
+
*
|
|
12
|
+
* The document also records the tenant's administrators. An admin holds no
|
|
13
|
+
* `grantaccess` document of its own, so without this list a member can only
|
|
14
|
+
* name the administration key by its fingerprint. Each entry carries the
|
|
15
|
+
* admin's name field-encrypted under `default` plus its device key pairs in
|
|
16
|
+
* the very same `userKeyPairs` shape a grant uses (docs/accesscontrol.md
|
|
17
|
+
* §6.5), so the same helpers read and write both, and additional admins or
|
|
18
|
+
* admin devices can be appended later.
|
|
19
|
+
*/
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
exports.TENANT_SETUP_DOC_ID = void 0;
|
|
22
|
+
exports.readTenantSetupLabel = readTenantSetupLabel;
|
|
23
|
+
exports.writeTenantSetupLabel = writeTenantSetupLabel;
|
|
24
|
+
exports.readTenantSetupAdministrators = readTenantSetupAdministrators;
|
|
25
|
+
exports.writeTenantSetupAdministrator = writeTenantSetupAdministrator;
|
|
26
|
+
exports.ensureTenantSetupAdministrator = ensureTenantSetupAdministrator;
|
|
27
|
+
const types_1 = require("./types");
|
|
28
|
+
Object.defineProperty(exports, "TENANT_SETUP_DOC_ID", { enumerable: true, get: function () { return types_1.TENANT_SETUP_DOC_ID; } });
|
|
29
|
+
const encryptedFields_1 = require("./crypto/encryptedFields");
|
|
30
|
+
const grantKeys_1 = require("./accesscontrol/grantKeys");
|
|
31
|
+
const DirectoryStateNode_1 = require("./accesscontrol/DirectoryStateNode");
|
|
32
|
+
const canonicalUsername_1 = require("./userid/canonicalUsername");
|
|
33
|
+
const timeSource_1 = require("./utils/timeSource");
|
|
34
|
+
function uint8ArrayToBase64(bytes) {
|
|
35
|
+
let binary = "";
|
|
36
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
37
|
+
binary += String.fromCharCode(bytes[i]);
|
|
38
|
+
}
|
|
39
|
+
return btoa(binary);
|
|
40
|
+
}
|
|
41
|
+
/** Field-encrypt a string under the tenant `default` key. */
|
|
42
|
+
async function encryptUnderDefaultKey(tenant, value) {
|
|
43
|
+
const encrypted = await tenant.encryptPayload(new TextEncoder().encode(value), types_1.DEFAULT_TENANT_KEY_ID);
|
|
44
|
+
return uint8ArrayToBase64(encrypted);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Apply a mutation to the `tenantsetup` document, creating it (under
|
|
48
|
+
* `$publicinfos`) when it does not exist yet. Must be signed with the tenant
|
|
49
|
+
* admin signing key.
|
|
50
|
+
*/
|
|
51
|
+
async function changeTenantSetup(directoryDb, adminSigningKeyPair, adminSigningKeyPassword, mutate) {
|
|
52
|
+
let doc;
|
|
53
|
+
try {
|
|
54
|
+
doc = await directoryDb.getDocument(types_1.TENANT_SETUP_DOC_ID);
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
doc = await directoryDb.createDocument({
|
|
58
|
+
id: types_1.TENANT_SETUP_DOC_ID,
|
|
59
|
+
signingKeyPair: adminSigningKeyPair,
|
|
60
|
+
signingKeyPassword: adminSigningKeyPassword,
|
|
61
|
+
decryptionKeyId: types_1.PUBLIC_INFOS_KEY_ID,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
await directoryDb.changeDoc(doc, (d) => {
|
|
65
|
+
mutate(d.getData());
|
|
66
|
+
}, {
|
|
67
|
+
signingKeyPair: adminSigningKeyPair,
|
|
68
|
+
signingKeyPassword: adminSigningKeyPassword,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Read the tenant label from the directory database's `tenantsetup` document.
|
|
73
|
+
* Requires the tenant `default` key to decrypt `label_encrypted`. Returns
|
|
74
|
+
* `undefined` when the document is missing, the key is absent, or there is no
|
|
75
|
+
* label. Legacy plaintext `label` is still accepted for older tenants.
|
|
76
|
+
*/
|
|
77
|
+
async function readTenantSetupLabel(directoryDb, tenant) {
|
|
78
|
+
try {
|
|
79
|
+
const doc = await directoryDb.getDocument(types_1.TENANT_SETUP_DOC_ID);
|
|
80
|
+
const data = doc.getData();
|
|
81
|
+
const decrypted = await (0, encryptedFields_1.decryptEncryptedField)(tenant, data, "label_encrypted");
|
|
82
|
+
if (typeof decrypted === "string") {
|
|
83
|
+
const trimmed = decrypted.trim();
|
|
84
|
+
if (trimmed.length > 0)
|
|
85
|
+
return trimmed;
|
|
86
|
+
}
|
|
87
|
+
// Legacy: plaintext label written before field encryption.
|
|
88
|
+
if (typeof data.label === "string") {
|
|
89
|
+
const trimmed = data.label.trim();
|
|
90
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
// Document missing or unreadable.
|
|
95
|
+
}
|
|
96
|
+
return undefined;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Create or update the `tenantsetup` document with the given label.
|
|
100
|
+
* Must be signed with the tenant admin signing key. Stores the label as
|
|
101
|
+
* `label_encrypted` under the tenant `default` key and clears any legacy
|
|
102
|
+
* plaintext `label` field.
|
|
103
|
+
*/
|
|
104
|
+
async function writeTenantSetupLabel(directoryDb, label, adminSigningKeyPair, adminSigningKeyPassword, tenant) {
|
|
105
|
+
const trimmed = label.trim();
|
|
106
|
+
if (!trimmed) {
|
|
107
|
+
throw new Error("Tenant label must be a non-empty string");
|
|
108
|
+
}
|
|
109
|
+
const labelEncrypted = await encryptUnderDefaultKey(tenant, trimmed);
|
|
110
|
+
await changeTenantSetup(directoryDb, adminSigningKeyPair, adminSigningKeyPassword, (data) => {
|
|
111
|
+
data.label_encrypted = labelEncrypted;
|
|
112
|
+
data.label_encrypted_key = types_1.DEFAULT_TENANT_KEY_ID;
|
|
113
|
+
delete data.label;
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
/** Normalize a stored administrator entry into a plain, writable object. */
|
|
117
|
+
function normalizeAdministratorEntry(entry) {
|
|
118
|
+
if (!entry || typeof entry !== "object")
|
|
119
|
+
return null;
|
|
120
|
+
const record = entry;
|
|
121
|
+
const pairs = (0, grantKeys_1.extractKeyPairs)(record);
|
|
122
|
+
if (pairs.length === 0)
|
|
123
|
+
return null;
|
|
124
|
+
const normalized = { userKeyPairs: pairs.map(toStoredKeyPair) };
|
|
125
|
+
if (typeof record.username_encrypted === "string" && record.username_encrypted) {
|
|
126
|
+
normalized.username_encrypted = record.username_encrypted;
|
|
127
|
+
normalized.username_encrypted_key =
|
|
128
|
+
typeof record.username_encrypted_key === "string" && record.username_encrypted_key
|
|
129
|
+
? record.username_encrypted_key
|
|
130
|
+
: types_1.DEFAULT_TENANT_KEY_ID;
|
|
131
|
+
}
|
|
132
|
+
if (typeof record.addedAt === "number")
|
|
133
|
+
normalized.addedAt = record.addedAt;
|
|
134
|
+
return normalized;
|
|
135
|
+
}
|
|
136
|
+
/** A {@link GrantKeyPair} reduced to the fields stored on the document. */
|
|
137
|
+
function toStoredKeyPair(pair) {
|
|
138
|
+
const stored = {
|
|
139
|
+
signingPublicKey: pair.signingPublicKey,
|
|
140
|
+
encryptionPublicKey: pair.encryptionPublicKey,
|
|
141
|
+
};
|
|
142
|
+
if (pair.label)
|
|
143
|
+
stored.label = pair.label;
|
|
144
|
+
if (typeof pair.addedAt === "number")
|
|
145
|
+
stored.addedAt = pair.addedAt;
|
|
146
|
+
return stored;
|
|
147
|
+
}
|
|
148
|
+
function administratorEntries(data) {
|
|
149
|
+
if (!Array.isArray(data.administrators))
|
|
150
|
+
return [];
|
|
151
|
+
return data.administrators
|
|
152
|
+
.map(normalizeAdministratorEntry)
|
|
153
|
+
.filter((entry) => entry !== null);
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* The tenant's administrators from the `tenantsetup` document, oldest first.
|
|
157
|
+
* Names need the tenant `default` key; entries whose name cannot be decrypted
|
|
158
|
+
* are still returned (with their key pairs) so callers can at least match a
|
|
159
|
+
* signing key. Returns an empty list for tenants created before this field.
|
|
160
|
+
*/
|
|
161
|
+
async function readTenantSetupAdministrators(directoryDb, tenant) {
|
|
162
|
+
let entries = [];
|
|
163
|
+
try {
|
|
164
|
+
const doc = await directoryDb.getDocument(types_1.TENANT_SETUP_DOC_ID);
|
|
165
|
+
entries = administratorEntries(doc.getData());
|
|
166
|
+
}
|
|
167
|
+
catch {
|
|
168
|
+
return [];
|
|
169
|
+
}
|
|
170
|
+
const administrators = [];
|
|
171
|
+
for (const entry of entries) {
|
|
172
|
+
const decrypted = await (0, encryptedFields_1.decryptEncryptedField)(tenant, entry, "username_encrypted");
|
|
173
|
+
const username = typeof decrypted === "string" ? decrypted.trim() : "";
|
|
174
|
+
administrators.push({
|
|
175
|
+
...(username ? { username } : {}),
|
|
176
|
+
keyPairs: (0, grantKeys_1.extractKeyPairs)(entry),
|
|
177
|
+
...(typeof entry.addedAt === "number" ? { addedAt: entry.addedAt } : {}),
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
return administrators;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Record an administrator on the `tenantsetup` document: its name
|
|
184
|
+
* field-encrypted under `default` plus its device key pairs. Must be signed
|
|
185
|
+
* with the tenant admin signing key.
|
|
186
|
+
*
|
|
187
|
+
* An entry for the same admin — matched by name, or by sharing a signing key
|
|
188
|
+
* when the name is unreadable — is updated in place and has its key pairs
|
|
189
|
+
* merged, so passing only a new pair enrolls another device of an admin that is
|
|
190
|
+
* already listed. Otherwise a new entry is appended. Idempotent when called
|
|
191
|
+
* again with the same name and keys.
|
|
192
|
+
*/
|
|
193
|
+
async function writeTenantSetupAdministrator(directoryDb, administrator, adminSigningKeyPair, adminSigningKeyPassword, tenant) {
|
|
194
|
+
const username = administrator.username.trim();
|
|
195
|
+
if (!username) {
|
|
196
|
+
throw new Error("Administrator username must be a non-empty string");
|
|
197
|
+
}
|
|
198
|
+
const incoming = administrator.keyPairs.filter((pair) => pair.signingPublicKey.trim().length > 0);
|
|
199
|
+
if (incoming.length === 0) {
|
|
200
|
+
throw new Error("Administrator must have at least one signing key");
|
|
201
|
+
}
|
|
202
|
+
const usernameEncrypted = await encryptUnderDefaultKey(tenant, username);
|
|
203
|
+
const now = (0, timeSource_1.semanticNow)();
|
|
204
|
+
// Names are only comparable after decryption, which cannot happen inside the
|
|
205
|
+
// synchronous document mutation below.
|
|
206
|
+
const existingIndex = (await readTenantSetupAdministrators(directoryDb, tenant)).findIndex((entry) => entry.username
|
|
207
|
+
? (0, canonicalUsername_1.usernamesEqual)(entry.username, username)
|
|
208
|
+
: entry.keyPairs.some((pair) => incoming.some((candidate) => (0, DirectoryStateNode_1.signingKeysEqual)(pair.signingPublicKey, candidate.signingPublicKey))));
|
|
209
|
+
await changeTenantSetup(directoryDb, adminSigningKeyPair, adminSigningKeyPassword, (data) => {
|
|
210
|
+
const entries = administratorEntries(data);
|
|
211
|
+
const target = existingIndex >= 0 ? entries[existingIndex] ?? { addedAt: now } : { addedAt: now };
|
|
212
|
+
const merged = (0, grantKeys_1.mergeKeyPairs)((0, grantKeys_1.extractKeyPairs)(target), incoming.map((pair) => ({ ...pair, addedAt: pair.addedAt ?? now })));
|
|
213
|
+
const next = {
|
|
214
|
+
username_encrypted: usernameEncrypted,
|
|
215
|
+
username_encrypted_key: types_1.DEFAULT_TENANT_KEY_ID,
|
|
216
|
+
userKeyPairs: merged.map(toStoredKeyPair),
|
|
217
|
+
addedAt: typeof target.addedAt === "number" ? target.addedAt : now,
|
|
218
|
+
};
|
|
219
|
+
if (existingIndex >= 0 && existingIndex < entries.length) {
|
|
220
|
+
entries[existingIndex] = next;
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
entries.push(next);
|
|
224
|
+
}
|
|
225
|
+
data.administrators = entries;
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Record an administrator only when it is missing from `tenantsetup`, and
|
|
230
|
+
* report whether a write happened. Tenants created before the
|
|
231
|
+
* `administrators` field have no entry at all, and a grant is a natural moment
|
|
232
|
+
* to heal that: the admin proves its identity and its keys there anyway. The
|
|
233
|
+
* check keeps repeated grants from appending a no-op revision to the
|
|
234
|
+
* append-only store.
|
|
235
|
+
*/
|
|
236
|
+
async function ensureTenantSetupAdministrator(directoryDb, administrator, adminSigningKeyPair, adminSigningKeyPassword, tenant) {
|
|
237
|
+
const username = administrator.username.trim();
|
|
238
|
+
if (!username) {
|
|
239
|
+
throw new Error("Administrator username must be a non-empty string");
|
|
240
|
+
}
|
|
241
|
+
const recorded = await readTenantSetupAdministrators(directoryDb, tenant);
|
|
242
|
+
const isComplete = recorded.some((entry) => entry.username !== undefined &&
|
|
243
|
+
(0, canonicalUsername_1.usernamesEqual)(entry.username, username) &&
|
|
244
|
+
administrator.keyPairs.every((candidate) => entry.keyPairs.some((pair) => (0, DirectoryStateNode_1.signingKeysEqual)(pair.signingPublicKey, candidate.signingPublicKey))));
|
|
245
|
+
if (isComplete)
|
|
246
|
+
return false;
|
|
247
|
+
await writeTenantSetupAdministrator(directoryDb, administrator, adminSigningKeyPair, adminSigningKeyPassword, tenant);
|
|
248
|
+
return true;
|
|
249
|
+
}
|
|
250
|
+
//# sourceMappingURL=tenantSetup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tenantSetup.js","sourceRoot":"","sources":["../../src/core/tenantSetup.ts"],"names":[],"mappings":"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"}
|