@tearleads/client-sdk 0.1.16 → 0.1.17
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/client/index.d.ts +1 -1
- package/client/index.js.map +1 -1
- package/client/organizations/currentPrincipalMutations.js +96 -0
- package/client/organizations/currentPrincipalMutations.js.map +1 -0
- package/client/organizations/index.d.ts +1 -1
- package/client/organizations/index.js +4 -3
- package/client/organizations/index.js.map +1 -1
- package/client/organizations/organizationGroupHistory.js +44 -0
- package/client/organizations/organizationGroupHistory.js.map +1 -0
- package/client/organizations/organizationGroupNameHydration.js +7 -1
- package/client/organizations/organizationGroupNameHydration.js.map +1 -1
- package/client/organizations/organizationGroupPresentation.d.ts +1 -0
- package/client/organizations/organizationGroupPresentation.js +16 -2
- package/client/organizations/organizationGroupPresentation.js.map +1 -1
- package/client/organizations/organizationReadModels.d.ts +1 -1
- package/client/organizations/organizationReadModels.js +11 -1
- package/client/organizations/organizationReadModels.js.map +1 -1
- package/client/organizations/organizationsTypes.d.ts +8 -5
- package/client/organizations/organizationsTypes.js.map +1 -1
- package/client/organizations/principalContainerMutations.js +2 -0
- package/client/organizations/principalContainerMutations.js.map +1 -1
- package/client/organizations/principalMutations.d.ts +4 -308
- package/client/organizations/principalMutations.js +165 -87
- package/client/organizations/principalMutations.js.map +1 -1
- package/data/persistence/principalCurrentAcknowledgementPersistence.d.ts +2 -2
- package/data/persistence/principalCurrentAcknowledgementPersistence.js +21 -14
- package/data/persistence/principalCurrentAcknowledgementPersistence.js.map +1 -1
- package/data/principals/currentPolicyReferenceResolver.js +2 -0
- package/data/principals/currentPolicyReferenceResolver.js.map +1 -0
- package/data/principals/principalHistoryScopeProtection.js +23 -0
- package/data/principals/principalHistoryScopeProtection.js.map +1 -0
- package/data/principals/principalPolicyAdminSigners.js.map +1 -1
- package/index.d.ts +1 -1
- package/index.js.map +1 -1
- package/internal/crypto/index.d.ts +1 -1
- package/internal/crypto/index.js +1 -1
- package/internal/crypto/index.js.map +1 -1
- package/internal/crypto/keying/index.d.ts +1 -0
- package/internal/crypto/keying/index.js +1 -0
- package/internal/crypto/keying/index.js.map +1 -1
- package/internal/crypto/keying/principalPolicyCurrentPredecessorReferences.d.ts +8 -0
- package/internal/crypto/keying/principalPolicyCurrentPredecessorReferences.js +46 -0
- package/internal/crypto/keying/principalPolicyCurrentPredecessorReferences.js.map +1 -0
- package/package.json +1 -1
- package/workflows/containers/child/carriedDescendantRekeys.js +9 -1
- package/workflows/containers/child/carriedDescendantRekeys.js.map +1 -1
- package/workflows/containers/child/replacementPrincipalPolicyReferences.js +19 -0
- package/workflows/containers/child/replacementPrincipalPolicyReferences.js.map +1 -0
- package/workflows/organizations/commitCurrentGroupPolicyMutation.js +72 -0
- package/workflows/organizations/commitCurrentGroupPolicyMutation.js.map +1 -0
- package/workflows/organizations/createCurrentOrganizationGroup.js +85 -0
- package/workflows/organizations/createCurrentOrganizationGroup.js.map +1 -0
- package/workflows/organizations/currentGroupMetadataAuthority.js +24 -3
- package/workflows/organizations/currentGroupMetadataAuthority.js.map +1 -1
- package/workflows/organizations/currentGroupMutationReferences.js +35 -0
- package/workflows/organizations/currentGroupMutationReferences.js.map +1 -0
- package/workflows/organizations/currentGroupPolicyMutationContext.js +79 -0
- package/workflows/organizations/currentGroupPolicyMutationContext.js.map +1 -0
- package/workflows/organizations/currentOrganizationGroupNames.js +5 -1
- package/workflows/organizations/currentOrganizationGroupNames.js.map +1 -1
- package/workflows/organizations/currentOrganizationMutationAuthority.js +16 -0
- package/workflows/organizations/currentOrganizationMutationAuthority.js.map +1 -0
- package/workflows/organizations/currentOrganizationMutationRetention.js +53 -0
- package/workflows/organizations/currentOrganizationMutationRetention.js.map +1 -0
- package/workflows/organizations/currentPrincipalMutationLease.js +38 -0
- package/workflows/organizations/currentPrincipalMutationLease.js.map +1 -0
- package/workflows/organizations/deleteCurrentOrganizationGroup.js +35 -0
- package/workflows/organizations/deleteCurrentOrganizationGroup.js.map +1 -0
- package/workflows/organizations/deleteOrganizationGroup.d.ts +1 -0
- package/workflows/organizations/deleteOrganizationGroup.js +10 -0
- package/workflows/organizations/deleteOrganizationGroup.js.map +1 -1
- package/workflows/organizations/groupCreation.d.ts +1 -0
- package/workflows/organizations/groupCreation.js +8 -0
- package/workflows/organizations/groupCreation.js.map +1 -1
- package/workflows/organizations/groupMembershipName.d.ts +1 -1
- package/workflows/organizations/groupMembershipName.js.map +1 -1
- package/workflows/organizations/groupMetadataRuntime.js +14 -9
- package/workflows/organizations/groupMetadataRuntime.js.map +1 -1
- package/workflows/organizations/groupNameUniqueness.js +1 -1
- package/workflows/organizations/groupNameUniqueness.js.map +1 -1
- package/workflows/organizations/groupPolicyHistoryPage.js +31 -0
- package/workflows/organizations/groupPolicyHistoryPage.js.map +1 -0
- package/workflows/organizations/groupPolicyMutationAcknowledgement.js +1 -0
- package/workflows/organizations/groupPolicyMutationAcknowledgement.js.map +1 -1
- package/workflows/organizations/groupPolicyMutationContext.d.ts +18 -0
- package/workflows/organizations/groupPolicyMutationContext.js +1 -1
- package/workflows/organizations/groupPolicyMutationContext.js.map +1 -1
- package/workflows/organizations/initialPrincipalCurrentPublication.js +83 -0
- package/workflows/organizations/initialPrincipalCurrentPublication.js.map +1 -0
- package/workflows/organizations/organizationGroupDirectory.js +6 -0
- package/workflows/organizations/organizationGroupDirectory.js.map +1 -1
- package/workflows/organizations/organizationGroupNames.js.map +1 -1
- package/workflows/organizations/policyHistoryTypes.d.ts +2 -0
- package/workflows/organizations/policyHistoryTypes.js.map +1 -1
- package/workflows/organizations/principalContainerRematerialization.js +12 -2
- package/workflows/organizations/principalContainerRematerialization.js.map +1 -1
- package/workflows/organizations/principalContainerRematerializationPlanning.js +1 -0
- package/workflows/organizations/principalContainerRematerializationPlanning.js.map +1 -1
- package/workflows/organizations/principalContainerRematerializationTargets.js.map +1 -1
- package/workflows/organizations/retainAcknowledgedPrincipalCurrents.d.ts +2 -0
- package/workflows/organizations/retainAcknowledgedPrincipalCurrents.js +5 -1
- package/workflows/organizations/retainAcknowledgedPrincipalCurrents.js.map +1 -1
- package/workflows/organizations/runtimeCurrentGroupMutation.js +85 -0
- package/workflows/organizations/runtimeCurrentGroupMutation.js.map +1 -0
- package/workflows/organizations/runtimeCurrentOrganizationMutation.js +48 -0
- package/workflows/organizations/runtimeCurrentOrganizationMutation.js.map +1 -0
- package/workflows/principals/loadRecoveredPrincipalHistoryPage.d.ts +11 -0
- package/workflows/principals/loadRecoveredPrincipalHistoryPage.js +120 -0
- package/workflows/principals/loadRecoveredPrincipalHistoryPage.js.map +1 -0
- package/workflows/principals/principalHistoryRecoveryReferences.js +8 -0
- package/workflows/principals/principalHistoryRecoveryReferences.js.map +1 -1
- package/workflows/principals/principalRecoveryDirectory.js +3 -8
- package/workflows/principals/principalRecoveryDirectory.js.map +1 -1
- package/workflows/principals/principalRecoveryLocalPreference.js +3 -2
- package/workflows/principals/principalRecoveryLocalPreference.js.map +1 -1
- package/workflows/principals/recoverCurrentOrganizationPolicy.js.map +1 -1
- package/workflows/principals/recoverPrincipalHistoryPage.js +30 -0
- package/workflows/principals/recoverPrincipalHistoryPage.js.map +1 -0
- package/workflows/principals/recoverPrincipalPolicyHistory.d.ts +2 -0
- package/workflows/principals/recoverPrincipalPolicyHistory.js +14 -2
- package/workflows/principals/recoverPrincipalPolicyHistory.js.map +1 -1
- package/workflows/principals/recoverScopedPrincipalPolicyHistory.d.ts +6 -0
- package/workflows/principals/recoverScopedPrincipalPolicyHistory.js +31 -19
- package/workflows/principals/recoverScopedPrincipalPolicyHistory.js.map +1 -1
- package/workflows/principals/runtimePolicyRecovery.js +25 -4
- package/workflows/principals/runtimePolicyRecovery.js.map +1 -1
- package/workflows/principals/runtimePolicyWarmer.js +2 -2
- package/workflows/principals/runtimePolicyWarmer.js.map +1 -1
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { assertProjectionVerificationCurrent } from "../../data/keyingProjectionVerification/types.js";
|
|
2
|
+
import { prepareAuthoredGroupPolicy } from "./groupPolicyMutationAcknowledgement.js";
|
|
3
|
+
import { submitGroupPolicyCommit, } from "./groupPolicyMutationContext.js";
|
|
4
|
+
import { groupPolicyMutationHead } from "./groupPolicyMutationHead.js";
|
|
5
|
+
import { buildOrganizationGroupDirectoryPolicyRequest, replaceOrganizationGroupHead, } from "./organizationGroupDirectory.js";
|
|
6
|
+
import { projectionUserIds, resolveRequiredUserIdentities, } from "./trustedOrganizationUsers.js";
|
|
7
|
+
/** Commit and retain one exact compound successor without rebuilding full history. */
|
|
8
|
+
export async function commitCurrentGroupPolicyMutation(input) {
|
|
9
|
+
const { context } = input;
|
|
10
|
+
assertProjectionVerificationCurrent(context.stillCurrent);
|
|
11
|
+
const [signer] = await resolveRequiredUserIdentities({
|
|
12
|
+
resolveTrustedUserIdentity: input.resolveTrustedUserIdentity,
|
|
13
|
+
userIds: [input.signerUserId],
|
|
14
|
+
});
|
|
15
|
+
if (!signer)
|
|
16
|
+
throw new Error("Group policy signer is unavailable");
|
|
17
|
+
const expectedHead = await groupPolicyMutationHead(input.request);
|
|
18
|
+
const nextPolicy = await prepareAuthoredGroupPolicy({
|
|
19
|
+
verifiedCurrentPolicy: context.verifiedCurrentPolicy,
|
|
20
|
+
expectedHead,
|
|
21
|
+
request: input.request,
|
|
22
|
+
signerPublicKeys: [signer],
|
|
23
|
+
externalAuthority: context.externalAuthority,
|
|
24
|
+
localPolicyCheckpoint: context.localPolicyCheckpoint,
|
|
25
|
+
stillCurrent: context.stillCurrent,
|
|
26
|
+
});
|
|
27
|
+
const prepared = await input.prepareContainerMutations(nextPolicy);
|
|
28
|
+
input.request.containerMutations = [...prepared.requests];
|
|
29
|
+
const adminProjection = context.isOrganizationAdminsGroup
|
|
30
|
+
? input.request.projection
|
|
31
|
+
: context.adminCurrent.current.currentProjection;
|
|
32
|
+
const adminUsers = await resolveRequiredUserIdentities({
|
|
33
|
+
resolveTrustedUserIdentity: input.resolveTrustedUserIdentity,
|
|
34
|
+
userIds: projectionUserIds(adminProjection),
|
|
35
|
+
});
|
|
36
|
+
const organizationRequest = await buildOrganizationGroupDirectoryPolicyRequest({
|
|
37
|
+
adminProjection,
|
|
38
|
+
adminUsers,
|
|
39
|
+
currentPolicy: context.organizationCurrent.current,
|
|
40
|
+
descriptor: context.organizationDescriptor,
|
|
41
|
+
groupHeads: replaceOrganizationGroupHead({
|
|
42
|
+
descriptor: context.organizationDescriptor,
|
|
43
|
+
nextHead: expectedHead,
|
|
44
|
+
}),
|
|
45
|
+
signerUserId: input.signerUserId,
|
|
46
|
+
signingFingerprint: input.signingFingerprint,
|
|
47
|
+
signingKeyPair: input.signingKeyPair,
|
|
48
|
+
});
|
|
49
|
+
assertProjectionVerificationCurrent(context.stillCurrent);
|
|
50
|
+
const response = await submitGroupPolicyCommit({
|
|
51
|
+
apiClient: input.apiClient,
|
|
52
|
+
groupId: input.groupId,
|
|
53
|
+
organizationId: input.organizationId,
|
|
54
|
+
request: input.request,
|
|
55
|
+
organizationRequest,
|
|
56
|
+
carryDescendantRekeys: prepared.carry,
|
|
57
|
+
stillCurrent: context.stillCurrent,
|
|
58
|
+
});
|
|
59
|
+
if (!response)
|
|
60
|
+
throw new Error("Group policy update failed");
|
|
61
|
+
assertProjectionVerificationCurrent(context.stillCurrent);
|
|
62
|
+
await context.retainAcknowledged({
|
|
63
|
+
request: input.request,
|
|
64
|
+
organizationRequest,
|
|
65
|
+
response,
|
|
66
|
+
retiredContainerIds: prepared.retiredContainerIds,
|
|
67
|
+
});
|
|
68
|
+
await prepared.acknowledge(response.groupPolicy.containerMutations, context.stillCurrent);
|
|
69
|
+
assertProjectionVerificationCurrent(context.stillCurrent);
|
|
70
|
+
return response.groupPolicy;
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=commitCurrentGroupPolicyMutation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commitCurrentGroupPolicyMutation.js","sourceRoot":"","sources":["commitCurrentGroupPolicyMutation.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n SigningKeyPair,\n VerifiedPrincipalPolicyCurrent,\n} from \"@tearleads/crypto\";\nimport type { PutPrincipalPolicyRequest } from \"@tearleads/validators/request\";\nimport type { PrincipalPolicyMutationResponse } from \"@tearleads/validators/response\";\nimport { assertProjectionVerificationCurrent } from \"../../data/keyingProjectionVerification/types\";\nimport type { TrustedUserIdentityResolver } from \"../../data/trustedUserIdentity\";\nimport { prepareAuthoredGroupPolicy } from \"./groupPolicyMutationAcknowledgement\";\nimport {\n type PrincipalPolicyReadWriteApi,\n submitGroupPolicyCommit,\n} from \"./groupPolicyMutationContext\";\nimport { groupPolicyMutationHead } from \"./groupPolicyMutationHead\";\nimport {\n buildOrganizationGroupDirectoryPolicyRequest,\n replaceOrganizationGroupHead,\n} from \"./organizationGroupDirectory\";\nimport type { PreparedPrincipalContainerRematerializationBatch } from \"./principalContainerRematerialization\";\nimport type { RuntimeCurrentGroupMutationContext } from \"./runtimeCurrentGroupMutation\";\nimport {\n projectionUserIds,\n resolveRequiredUserIdentities,\n} from \"./trustedOrganizationUsers\";\n\n/** Commit and retain one exact compound successor without rebuilding full history. */\nexport async function commitCurrentGroupPolicyMutation(input: {\n readonly apiClient: PrincipalPolicyReadWriteApi;\n readonly context: RuntimeCurrentGroupMutationContext;\n readonly groupId: string;\n readonly organizationId: string;\n readonly request: PutPrincipalPolicyRequest;\n readonly signerUserId: string;\n readonly signingFingerprint: string;\n readonly signingKeyPair: SigningKeyPair;\n readonly resolveTrustedUserIdentity: TrustedUserIdentityResolver;\n readonly prepareContainerMutations: (\n nextPolicy: VerifiedPrincipalPolicyCurrent,\n ) => Promise<PreparedPrincipalContainerRematerializationBatch>;\n}): Promise<PrincipalPolicyMutationResponse> {\n const { context } = input;\n assertProjectionVerificationCurrent(context.stillCurrent);\n const [signer] = await resolveRequiredUserIdentities({\n resolveTrustedUserIdentity: input.resolveTrustedUserIdentity,\n userIds: [input.signerUserId],\n });\n if (!signer) throw new Error(\"Group policy signer is unavailable\");\n const expectedHead = await groupPolicyMutationHead(input.request);\n const nextPolicy = await prepareAuthoredGroupPolicy({\n verifiedCurrentPolicy: context.verifiedCurrentPolicy,\n expectedHead,\n request: input.request,\n signerPublicKeys: [signer],\n externalAuthority: context.externalAuthority,\n localPolicyCheckpoint: context.localPolicyCheckpoint,\n stillCurrent: context.stillCurrent,\n });\n const prepared = await input.prepareContainerMutations(nextPolicy);\n input.request.containerMutations = [...prepared.requests];\n const adminProjection = context.isOrganizationAdminsGroup\n ? input.request.projection\n : context.adminCurrent.current.currentProjection;\n const adminUsers = await resolveRequiredUserIdentities({\n resolveTrustedUserIdentity: input.resolveTrustedUserIdentity,\n userIds: projectionUserIds(adminProjection),\n });\n const organizationRequest =\n await buildOrganizationGroupDirectoryPolicyRequest({\n adminProjection,\n adminUsers,\n currentPolicy: context.organizationCurrent.current,\n descriptor: context.organizationDescriptor,\n groupHeads: replaceOrganizationGroupHead({\n descriptor: context.organizationDescriptor,\n nextHead: expectedHead,\n }),\n signerUserId: input.signerUserId,\n signingFingerprint: input.signingFingerprint,\n signingKeyPair: input.signingKeyPair,\n });\n assertProjectionVerificationCurrent(context.stillCurrent);\n const response = await submitGroupPolicyCommit({\n apiClient: input.apiClient,\n groupId: input.groupId,\n organizationId: input.organizationId,\n request: input.request,\n organizationRequest,\n carryDescendantRekeys: prepared.carry,\n stillCurrent: context.stillCurrent,\n });\n if (!response) throw new Error(\"Group policy update failed\");\n assertProjectionVerificationCurrent(context.stillCurrent);\n await context.retainAcknowledged({\n request: input.request,\n organizationRequest,\n response,\n retiredContainerIds: prepared.retiredContainerIds,\n });\n await prepared.acknowledge(\n response.groupPolicy.containerMutations,\n context.stillCurrent,\n );\n assertProjectionVerificationCurrent(context.stillCurrent);\n return response.groupPolicy;\n}\n"]}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { assertProjectionVerificationCurrent } from "../../data/keyingProjectionVerification/types.js";
|
|
2
|
+
import { advanceKeyingCheckpointsAtomically } from "../../data/persistence/keyingCheckpointAdvancePersistence.js";
|
|
3
|
+
import { principalPolicyReferenceFromBundle } from "../../data/principals/principalPolicyAdminSigners.js";
|
|
4
|
+
import { assertGroupMetadataBinding } from "./groupMetadataBinding.js";
|
|
5
|
+
import { readDirectoryGroupName } from "./groupNameUniqueness.js";
|
|
6
|
+
import { acknowledgeInitialGroupPolicy } from "./groupPolicyMutationAcknowledgement.js";
|
|
7
|
+
import { groupPolicyMutationHead } from "./groupPolicyMutationHead.js";
|
|
8
|
+
import { buildOrganizationGroupDirectoryPolicyRequest, replaceOrganizationGroupHead, } from "./organizationGroupDirectory.js";
|
|
9
|
+
import { buildInitialGroupPolicyRequest, canonicalGroupNameKey, } from "./principalPolicyRequest.js";
|
|
10
|
+
import { projectionUserIds, resolveRequiredUserIdentities, } from "./trustedOrganizationUsers.js";
|
|
11
|
+
/** Create from bounded current evidence and publish its genuine genesis with the directory. */
|
|
12
|
+
export async function createCurrentOrganizationGroup(input) {
|
|
13
|
+
const { context } = input;
|
|
14
|
+
assertProjectionVerificationCurrent(context.stillCurrent);
|
|
15
|
+
const nameKey = canonicalGroupNameKey(input.name);
|
|
16
|
+
// Each current recovery is queued by organization. Retain verified heads one
|
|
17
|
+
// at a time so the walk stays bounded without collecting full group histories.
|
|
18
|
+
for (const head of context.descriptor.groupHeads) {
|
|
19
|
+
const group = await context.readGroup(head.principalId);
|
|
20
|
+
const stillCurrent = () => context.stillCurrent() && group.stillCurrent();
|
|
21
|
+
assertProjectionVerificationCurrent(stillCurrent);
|
|
22
|
+
assertGroupMetadataBinding(group.current, context.descriptor);
|
|
23
|
+
const name = await readDirectoryGroupName({ ...input, readEncryptedName: input.metadataAccess.readName }, group.current);
|
|
24
|
+
// Remember independently verified heads even if uniqueness or dispatch
|
|
25
|
+
// later fails; these are observed policies, never speculative successors.
|
|
26
|
+
await advanceKeyingCheckpointsAtomically({
|
|
27
|
+
execSql: input.execSql,
|
|
28
|
+
organizationId: input.organizationId,
|
|
29
|
+
access: [],
|
|
30
|
+
policies: [...group.dependencies, group.policy],
|
|
31
|
+
stillCurrent,
|
|
32
|
+
});
|
|
33
|
+
if (name !== null && canonicalGroupNameKey(name) === nameKey)
|
|
34
|
+
throw new Error("Another signed group in this organization already carries this name");
|
|
35
|
+
}
|
|
36
|
+
const request = await buildInitialGroupPolicyRequest({
|
|
37
|
+
...input,
|
|
38
|
+
groupId: crypto.randomUUID(),
|
|
39
|
+
includeSignerAsAdmin: false,
|
|
40
|
+
externalAuthority: {
|
|
41
|
+
...principalPolicyReferenceFromBundle(context.admins.current),
|
|
42
|
+
principalType: "group",
|
|
43
|
+
},
|
|
44
|
+
metadataKey: await input.metadataAccess.loadEncryptionKey(),
|
|
45
|
+
});
|
|
46
|
+
const head = await groupPolicyMutationHead(request.initialGroupPolicy);
|
|
47
|
+
const adminProjection = context.admins.policy.projection;
|
|
48
|
+
const organizationRequest = await buildOrganizationGroupDirectoryPolicyRequest({
|
|
49
|
+
...input,
|
|
50
|
+
currentPolicy: context.directory.current,
|
|
51
|
+
descriptor: context.descriptor,
|
|
52
|
+
groupHeads: replaceOrganizationGroupHead({
|
|
53
|
+
descriptor: context.descriptor,
|
|
54
|
+
nextHead: head,
|
|
55
|
+
}),
|
|
56
|
+
adminProjection,
|
|
57
|
+
adminUsers: await resolveRequiredUserIdentities({
|
|
58
|
+
resolveTrustedUserIdentity: input.resolveTrustedUserIdentity,
|
|
59
|
+
userIds: projectionUserIds(adminProjection),
|
|
60
|
+
}),
|
|
61
|
+
});
|
|
62
|
+
assertProjectionVerificationCurrent(context.stillCurrent);
|
|
63
|
+
const stored = await input.apiClient.createOrganizationGroup(input.organizationId, { ...request, organizationPolicy: organizationRequest });
|
|
64
|
+
assertProjectionVerificationCurrent(context.stillCurrent);
|
|
65
|
+
if (!stored)
|
|
66
|
+
throw new Error("Group could not be created");
|
|
67
|
+
// Genesis really has one signed state. Reconstruct only the exact authored
|
|
68
|
+
// artifacts whose commitments match the summary, then verify them privately.
|
|
69
|
+
const { bundle } = await acknowledgeInitialGroupPolicy({
|
|
70
|
+
organizationId: input.organizationId,
|
|
71
|
+
request,
|
|
72
|
+
response: stored.group,
|
|
73
|
+
stateHash: head.stateHash,
|
|
74
|
+
});
|
|
75
|
+
const { previousStates: _previousStates, ...current } = bundle;
|
|
76
|
+
await context.retainCreatedGroup({
|
|
77
|
+
request: request.initialGroupPolicy,
|
|
78
|
+
response: { ...current, containerMutations: [] },
|
|
79
|
+
organizationRequest,
|
|
80
|
+
organizationResponse: stored.organizationPolicy,
|
|
81
|
+
});
|
|
82
|
+
assertProjectionVerificationCurrent(context.stillCurrent);
|
|
83
|
+
return { ...stored.group, name: input.name.trim(), nameUnreadable: false };
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=createCurrentOrganizationGroup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createCurrentOrganizationGroup.js","sourceRoot":"","sources":["createCurrentOrganizationGroup.ts"],"names":[],"mappings":"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","sourcesContent":["import type { EncapsulationKeyPair, SigningKeyPair } from \"@tearleads/crypto\";\nimport { assertProjectionVerificationCurrent } from \"../../data/keyingProjectionVerification/types\";\nimport { advanceKeyingCheckpointsAtomically } from \"../../data/persistence/keyingCheckpointAdvancePersistence\";\nimport { principalPolicyReferenceFromBundle } from \"../../data/principals/principalPolicyAdminSigners\";\nimport type { SecurityIncidentReporter } from \"../../data/securityIncidents\";\nimport type { ExecSql } from \"../../data/sqlite/sqlSchema\";\nimport type { TrustedUserIdentityResolver } from \"../../data/trustedUserIdentity\";\nimport type { createGroupMetadataAccess } from \"./groupMetadataAccess\";\nimport { assertGroupMetadataBinding } from \"./groupMetadataBinding\";\nimport { readDirectoryGroupName } from \"./groupNameUniqueness\";\nimport { acknowledgeInitialGroupPolicy } from \"./groupPolicyMutationAcknowledgement\";\nimport type { OrganizationPrincipalPolicyApi } from \"./groupPolicyMutationContext\";\nimport { groupPolicyMutationHead } from \"./groupPolicyMutationHead\";\nimport {\n buildOrganizationGroupDirectoryPolicyRequest,\n replaceOrganizationGroupHead,\n} from \"./organizationGroupDirectory\";\nimport {\n buildInitialGroupPolicyRequest,\n canonicalGroupNameKey,\n} from \"./principalPolicyRequest\";\nimport type { OrganizationGroupSummary } from \"./readModel\";\nimport type { CurrentOrganizationMutationContext } from \"./runtimeCurrentOrganizationMutation\";\nimport {\n projectionUserIds,\n resolveRequiredUserIdentities,\n} from \"./trustedOrganizationUsers\";\n\n/** Create from bounded current evidence and publish its genuine genesis with the directory. */\nexport async function createCurrentOrganizationGroup(input: {\n readonly apiClient: Pick<\n OrganizationPrincipalPolicyApi,\n \"createOrganizationGroup\"\n >;\n readonly context: CurrentOrganizationMutationContext;\n readonly creatorEncapsulationKeyPair: EncapsulationKeyPair;\n readonly execSql: ExecSql;\n readonly metadataAccess: ReturnType<typeof createGroupMetadataAccess>;\n readonly name: string;\n readonly organizationId: string;\n readonly reportSecurityIncident: SecurityIncidentReporter;\n readonly resolveTrustedUserIdentity: TrustedUserIdentityResolver;\n readonly signerUserId: string;\n readonly signingFingerprint: string;\n readonly signingKeyPair: SigningKeyPair;\n}): Promise<OrganizationGroupSummary> {\n const { context } = input;\n assertProjectionVerificationCurrent(context.stillCurrent);\n const nameKey = canonicalGroupNameKey(input.name);\n // Each current recovery is queued by organization. Retain verified heads one\n // at a time so the walk stays bounded without collecting full group histories.\n for (const head of context.descriptor.groupHeads) {\n const group = await context.readGroup(head.principalId);\n const stillCurrent = () => context.stillCurrent() && group.stillCurrent();\n assertProjectionVerificationCurrent(stillCurrent);\n assertGroupMetadataBinding(group.current, context.descriptor);\n const name = await readDirectoryGroupName(\n { ...input, readEncryptedName: input.metadataAccess.readName },\n group.current,\n );\n // Remember independently verified heads even if uniqueness or dispatch\n // later fails; these are observed policies, never speculative successors.\n await advanceKeyingCheckpointsAtomically({\n execSql: input.execSql,\n organizationId: input.organizationId,\n access: [],\n policies: [...group.dependencies, group.policy],\n stillCurrent,\n });\n if (name !== null && canonicalGroupNameKey(name) === nameKey)\n throw new Error(\n \"Another signed group in this organization already carries this name\",\n );\n }\n const request = await buildInitialGroupPolicyRequest({\n ...input,\n groupId: crypto.randomUUID(),\n includeSignerAsAdmin: false,\n externalAuthority: {\n ...principalPolicyReferenceFromBundle(context.admins.current),\n principalType: \"group\",\n },\n metadataKey: await input.metadataAccess.loadEncryptionKey(),\n });\n const head = await groupPolicyMutationHead(request.initialGroupPolicy);\n const adminProjection = context.admins.policy.projection;\n const organizationRequest =\n await buildOrganizationGroupDirectoryPolicyRequest({\n ...input,\n currentPolicy: context.directory.current,\n descriptor: context.descriptor,\n groupHeads: replaceOrganizationGroupHead({\n descriptor: context.descriptor,\n nextHead: head,\n }),\n adminProjection,\n adminUsers: await resolveRequiredUserIdentities({\n resolveTrustedUserIdentity: input.resolveTrustedUserIdentity,\n userIds: projectionUserIds(adminProjection),\n }),\n });\n assertProjectionVerificationCurrent(context.stillCurrent);\n const stored = await input.apiClient.createOrganizationGroup(\n input.organizationId,\n { ...request, organizationPolicy: organizationRequest },\n );\n assertProjectionVerificationCurrent(context.stillCurrent);\n if (!stored) throw new Error(\"Group could not be created\");\n // Genesis really has one signed state. Reconstruct only the exact authored\n // artifacts whose commitments match the summary, then verify them privately.\n const { bundle } = await acknowledgeInitialGroupPolicy({\n organizationId: input.organizationId,\n request,\n response: stored.group,\n stateHash: head.stateHash,\n });\n const { previousStates: _previousStates, ...current } = bundle;\n await context.retainCreatedGroup({\n request: request.initialGroupPolicy,\n response: { ...current, containerMutations: [] },\n organizationRequest,\n organizationResponse: stored.organizationPolicy,\n });\n assertProjectionVerificationCurrent(context.stillCurrent);\n return { ...stored.group, name: input.name.trim(), nameUnreadable: false };\n}\n"]}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import { KeyingVerificationError, } from "../../internal/crypto/index.js";
|
|
2
|
+
import { ProjectionDependencyUnavailableError } from "../../data/keyingProjectionVerification/dependencyUnavailable.js";
|
|
1
3
|
import { assertProjectionVerificationCurrent } from "../../data/keyingProjectionVerification/types.js";
|
|
4
|
+
import { principalHeadMatchesReference } from "../../data/principals/organizationAuthorityDescriptor.js";
|
|
2
5
|
import { loadCurrentOrganizationAuthority } from "./currentOrganizationAuthority.js";
|
|
3
6
|
import { assertMetadataRootBinding } from "./groupMetadataRootBinding.js";
|
|
4
7
|
/** Authenticate metadata-root grants with current policies and only its cited predecessors. */
|
|
@@ -9,6 +12,26 @@ export function createCurrentGroupMetadataContainerVerifier(input) {
|
|
|
9
12
|
...input,
|
|
10
13
|
organizationReference,
|
|
11
14
|
});
|
|
15
|
+
await createSelectedCurrentGroupMetadataContainerVerifier({
|
|
16
|
+
authority,
|
|
17
|
+
organizationId: input.organizationId,
|
|
18
|
+
stillCurrent: input.stillCurrent,
|
|
19
|
+
})(state, organizationReference);
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/** Reuse one mutation's verified authority without broadening its lease or scope. */
|
|
23
|
+
export function createSelectedCurrentGroupMetadataContainerVerifier(input) {
|
|
24
|
+
return async (state, organizationReference) => {
|
|
25
|
+
const { authority } = input;
|
|
26
|
+
const stillCurrent = () => input.stillCurrent() && authority.stillCurrent();
|
|
27
|
+
assertProjectionVerificationCurrent(stillCurrent);
|
|
28
|
+
if (organizationReference) {
|
|
29
|
+
if (organizationReference.principalType !== "organization" ||
|
|
30
|
+
organizationReference.principalId !== input.organizationId)
|
|
31
|
+
throw new KeyingVerificationError("object_mismatch", "Current policy reference is outside its scope");
|
|
32
|
+
if (!principalHeadMatchesReference(authority.directory.policy.state, organizationReference))
|
|
33
|
+
throw new ProjectionDependencyUnavailableError("Metadata root belongs to a changed organization directory");
|
|
34
|
+
}
|
|
12
35
|
const { adminGroupId, memberGroupId } = authority.descriptor;
|
|
13
36
|
const citation = (groupId) => state.referencedPrincipalHeads.find((head) => head.principalType === "group" && head.principalId === groupId);
|
|
14
37
|
const admins = await authority.readGroup(adminGroupId, citation(adminGroupId));
|
|
@@ -24,9 +47,7 @@ export function createCurrentGroupMetadataContainerVerifier(input) {
|
|
|
24
47
|
members,
|
|
25
48
|
state,
|
|
26
49
|
});
|
|
27
|
-
assertProjectionVerificationCurrent(() =>
|
|
28
|
-
admins.stillCurrent() &&
|
|
29
|
-
members.stillCurrent());
|
|
50
|
+
assertProjectionVerificationCurrent(() => stillCurrent() && admins.stillCurrent() && members.stillCurrent());
|
|
30
51
|
};
|
|
31
52
|
}
|
|
32
53
|
//# sourceMappingURL=currentGroupMetadataAuthority.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"currentGroupMetadataAuthority.js","sourceRoot":"","sources":["currentGroupMetadataAuthority.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"currentGroupMetadataAuthority.js","sourceRoot":"","sources":["currentGroupMetadataAuthority.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,uBAAuB,GAExB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,oCAAoC,EAAE,MAAM,+DAA+D,CAAC;AACrH,OAAO,EAAE,mCAAmC,EAAE,MAAM,+CAA+C,CAAC;AACpG,OAAO,EAAE,6BAA6B,EAAE,MAAM,uDAAuD,CAAC;AACtG,OAAO,EAAE,gCAAgC,EAAE,MAAM,gCAAgC,CAAC;AAClF,OAAO,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AAEvE,+FAA+F;AAC/F,MAAM,UAAU,2CAA2C,CACzD,KAGC;IAED,OAAO,KAAK,EACV,KAAmC,EACnC,qBAA+C,EAChC,EAAE;QACjB,mCAAmC,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QACxD,MAAM,SAAS,GAAG,MAAM,gCAAgC,CAAC;YACvD,GAAG,KAAK;YACR,qBAAqB;SACtB,CAAC,CAAC;QACH,MAAM,mDAAmD,CAAC;YACxD,SAAS;YACT,cAAc,EAAE,KAAK,CAAC,cAAc;YACpC,YAAY,EAAE,KAAK,CAAC,YAAY;SACjC,CAAC,CAAC,KAAK,EAAE,qBAAqB,CAAC,CAAC;IACnC,CAAC,CAAC;AACJ,CAAC;AAED,qFAAqF;AACrF,MAAM,UAAU,mDAAmD,CAAC,KAMnE;IACC,OAAO,KAAK,EACV,KAAmC,EACnC,qBAA+C,EAChC,EAAE;QACjB,MAAM,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC;QAC5B,MAAM,YAAY,GAAG,GAAG,EAAE,CAAC,KAAK,CAAC,YAAY,EAAE,IAAI,SAAS,CAAC,YAAY,EAAE,CAAC;QAC5E,mCAAmC,CAAC,YAAY,CAAC,CAAC;QAClD,IAAI,qBAAqB,EAAE,CAAC;YAC1B,IACE,qBAAqB,CAAC,aAAa,KAAK,cAAc;gBACtD,qBAAqB,CAAC,WAAW,KAAK,KAAK,CAAC,cAAc;gBAE1D,MAAM,IAAI,uBAAuB,CAC/B,iBAAiB,EACjB,+CAA+C,CAChD,CAAC;YACJ,IACE,CAAC,6BAA6B,CAC5B,SAAS,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,EAChC,qBAAqB,CACtB;gBAED,MAAM,IAAI,oCAAoC,CAC5C,2DAA2D,CAC5D,CAAC;QACN,CAAC;QACD,MAAM,EAAE,YAAY,EAAE,aAAa,EAAE,GAAG,SAAS,CAAC,UAAU,CAAC;QAC7D,MAAM,QAAQ,GAAG,CAAC,OAAe,EAAE,EAAE,CACnC,KAAK,CAAC,wBAAwB,CAAC,IAAI,CACjC,CAAC,IAAI,EAAE,EAAE,CACP,IAAI,CAAC,aAAa,KAAK,OAAO,IAAI,IAAI,CAAC,WAAW,KAAK,OAAO,CACjE,CAAC;QACJ,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,SAAS,CACtC,YAAY,EACZ,QAAQ,CAAC,YAAY,CAAC,CACvB,CAAC;QACF,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,SAAS,CACvC,aAAa,EACb,QAAQ,CAAC,aAAa,CAAC,CACxB,CAAC;QACF,yBAAyB,CAAC;YACxB,cAAc,EAAE,KAAK,CAAC,cAAc;YACpC,SAAS,EAAE;gBACT,UAAU,EAAE,SAAS,CAAC,UAAU;gBAChC,YAAY;gBACZ,aAAa;gBACb,WAAW,EAAE,MAAM,CAAC,MAAM;aAC3B;YACD,OAAO;YACP,KAAK;SACN,CAAC,CAAC;QACH,mCAAmC,CACjC,GAAG,EAAE,CAAC,YAAY,EAAE,IAAI,MAAM,CAAC,YAAY,EAAE,IAAI,OAAO,CAAC,YAAY,EAAE,CACxE,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import {\n type ContainerAccessManifestState,\n KeyingVerificationError,\n type ReferencedPrincipalHead,\n} from \"@tearleads/crypto\";\nimport { ProjectionDependencyUnavailableError } from \"../../data/keyingProjectionVerification/dependencyUnavailable\";\nimport { assertProjectionVerificationCurrent } from \"../../data/keyingProjectionVerification/types\";\nimport { principalHeadMatchesReference } from \"../../data/principals/organizationAuthorityDescriptor\";\nimport { loadCurrentOrganizationAuthority } from \"./currentOrganizationAuthority\";\nimport { assertMetadataRootBinding } from \"./groupMetadataRootBinding\";\n\n/** Authenticate metadata-root grants with current policies and only its cited predecessors. */\nexport function createCurrentGroupMetadataContainerVerifier(\n input: Omit<\n Parameters<typeof loadCurrentOrganizationAuthority>[0],\n \"organizationReference\"\n >,\n) {\n return async (\n state: ContainerAccessManifestState,\n organizationReference?: ReferencedPrincipalHead,\n ): Promise<void> => {\n assertProjectionVerificationCurrent(input.stillCurrent);\n const authority = await loadCurrentOrganizationAuthority({\n ...input,\n organizationReference,\n });\n await createSelectedCurrentGroupMetadataContainerVerifier({\n authority,\n organizationId: input.organizationId,\n stillCurrent: input.stillCurrent,\n })(state, organizationReference);\n };\n}\n\n/** Reuse one mutation's verified authority without broadening its lease or scope. */\nexport function createSelectedCurrentGroupMetadataContainerVerifier(input: {\n readonly authority: Awaited<\n ReturnType<typeof loadCurrentOrganizationAuthority>\n >;\n readonly organizationId: string;\n readonly stillCurrent: () => boolean;\n}) {\n return async (\n state: ContainerAccessManifestState,\n organizationReference?: ReferencedPrincipalHead,\n ): Promise<void> => {\n const { authority } = input;\n const stillCurrent = () => input.stillCurrent() && authority.stillCurrent();\n assertProjectionVerificationCurrent(stillCurrent);\n if (organizationReference) {\n if (\n organizationReference.principalType !== \"organization\" ||\n organizationReference.principalId !== input.organizationId\n )\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"Current policy reference is outside its scope\",\n );\n if (\n !principalHeadMatchesReference(\n authority.directory.policy.state,\n organizationReference,\n )\n )\n throw new ProjectionDependencyUnavailableError(\n \"Metadata root belongs to a changed organization directory\",\n );\n }\n const { adminGroupId, memberGroupId } = authority.descriptor;\n const citation = (groupId: string) =>\n state.referencedPrincipalHeads.find(\n (head) =>\n head.principalType === \"group\" && head.principalId === groupId,\n );\n const admins = await authority.readGroup(\n adminGroupId,\n citation(adminGroupId),\n );\n const members = await authority.readGroup(\n memberGroupId,\n citation(memberGroupId),\n );\n assertMetadataRootBinding({\n organizationId: input.organizationId,\n authority: {\n descriptor: authority.descriptor,\n adminGroupId,\n memberGroupId,\n adminPolicy: admins.policy,\n },\n members,\n state,\n });\n assertProjectionVerificationCurrent(\n () => stillCurrent() && admins.stillCurrent() && members.stillCurrent(),\n );\n };\n}\n"]}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { selectPrincipalPolicyCurrentPredecessorReferences, } from "../../internal/crypto/index.js";
|
|
2
|
+
import { assertProjectionVerificationCurrent } from "../../data/keyingProjectionVerification/types.js";
|
|
3
|
+
/** Select only this path's old citations, preserving the authored membership. */
|
|
4
|
+
export async function resolveCurrentGroupMutationReferences(input) {
|
|
5
|
+
assertProjectionVerificationCurrent(input.stillCurrent);
|
|
6
|
+
const references = structuredClone(input.references);
|
|
7
|
+
const select = (current, predecessor, selected) => selectPrincipalPolicyCurrentPredecessorReferences({
|
|
8
|
+
current,
|
|
9
|
+
predecessor,
|
|
10
|
+
references: selected,
|
|
11
|
+
});
|
|
12
|
+
// Normalize and bound the entire request before any per-reference I/O.
|
|
13
|
+
const initial = select(input.current, input.predecessor, references);
|
|
14
|
+
if (initial.ok)
|
|
15
|
+
return initial.value;
|
|
16
|
+
if (initial.error.code !== "missing_dependency")
|
|
17
|
+
throw initial.error;
|
|
18
|
+
let current = input.current;
|
|
19
|
+
const selected = [];
|
|
20
|
+
for (const reference of references) {
|
|
21
|
+
assertProjectionVerificationCurrent(input.stillCurrent);
|
|
22
|
+
selected.push(reference);
|
|
23
|
+
let result = select(current, input.predecessor, selected);
|
|
24
|
+
if (!result.ok && result.error.code === "missing_dependency") {
|
|
25
|
+
const predecessor = await input.readPredecessorReference(reference);
|
|
26
|
+
assertProjectionVerificationCurrent(input.stillCurrent);
|
|
27
|
+
result = select(current, predecessor, selected);
|
|
28
|
+
}
|
|
29
|
+
if (!result.ok)
|
|
30
|
+
throw result.error;
|
|
31
|
+
current = result.value;
|
|
32
|
+
}
|
|
33
|
+
return current;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=currentGroupMutationReferences.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"currentGroupMutationReferences.js","sourceRoot":"","sources":["currentGroupMutationReferences.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,iDAAiD,GAElD,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,mCAAmC,EAAE,MAAM,+CAA+C,CAAC;AAEpG,iFAAiF;AACjF,MAAM,CAAC,KAAK,UAAU,qCAAqC,CAAC,KAQ3D;IACC,mCAAmC,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IACxD,MAAM,UAAU,GAAG,eAAe,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACrD,MAAM,MAAM,GAAG,CACb,OAAuC,EACvC,WAA2C,EAC3C,QAA4C,EAC5C,EAAE,CACF,iDAAiD,CAAC;QAChD,OAAO;QACP,WAAW;QACX,UAAU,EAAE,QAAQ;KACrB,CAAC,CAAC;IACL,uEAAuE;IACvE,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;IACrE,IAAI,OAAO,CAAC,EAAE;QAAE,OAAO,OAAO,CAAC,KAAK,CAAC;IACrC,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,oBAAoB;QAAE,MAAM,OAAO,CAAC,KAAK,CAAC;IACrE,IAAI,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;IAC5B,MAAM,QAAQ,GAA8B,EAAE,CAAC;IAC/C,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,mCAAmC,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QACxD,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACzB,IAAI,MAAM,GAAG,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;QAC1D,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,KAAK,oBAAoB,EAAE,CAAC;YAC7D,MAAM,WAAW,GAAG,MAAM,KAAK,CAAC,wBAAwB,CAAC,SAAS,CAAC,CAAC;YACpE,mCAAmC,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;YACxD,MAAM,GAAG,MAAM,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;QAClD,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,EAAE;YAAE,MAAM,MAAM,CAAC,KAAK,CAAC;QACnC,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC;IACzB,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC","sourcesContent":["import {\n type ReferencedPrincipalHead,\n selectPrincipalPolicyCurrentPredecessorReferences,\n type VerifiedPrincipalPolicyCurrent,\n} from \"@tearleads/crypto\";\nimport { assertProjectionVerificationCurrent } from \"../../data/keyingProjectionVerification/types\";\n\n/** Select only this path's old citations, preserving the authored membership. */\nexport async function resolveCurrentGroupMutationReferences(input: {\n readonly current: VerifiedPrincipalPolicyCurrent;\n readonly predecessor: VerifiedPrincipalPolicyCurrent;\n readonly references: readonly ReferencedPrincipalHead[];\n readonly readPredecessorReference: (\n reference: ReferencedPrincipalHead,\n ) => Promise<VerifiedPrincipalPolicyCurrent>;\n readonly stillCurrent: () => boolean;\n}): Promise<VerifiedPrincipalPolicyCurrent> {\n assertProjectionVerificationCurrent(input.stillCurrent);\n const references = structuredClone(input.references);\n const select = (\n current: VerifiedPrincipalPolicyCurrent,\n predecessor: VerifiedPrincipalPolicyCurrent,\n selected: readonly ReferencedPrincipalHead[],\n ) =>\n selectPrincipalPolicyCurrentPredecessorReferences({\n current,\n predecessor,\n references: selected,\n });\n // Normalize and bound the entire request before any per-reference I/O.\n const initial = select(input.current, input.predecessor, references);\n if (initial.ok) return initial.value;\n if (initial.error.code !== \"missing_dependency\") throw initial.error;\n let current = input.current;\n const selected: ReferencedPrincipalHead[] = [];\n for (const reference of references) {\n assertProjectionVerificationCurrent(input.stillCurrent);\n selected.push(reference);\n let result = select(current, input.predecessor, selected);\n if (!result.ok && result.error.code === \"missing_dependency\") {\n const predecessor = await input.readPredecessorReference(reference);\n assertProjectionVerificationCurrent(input.stillCurrent);\n result = select(current, predecessor, selected);\n }\n if (!result.ok) throw result.error;\n current = result.value;\n }\n return current;\n}\n"]}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { serializeKeyingCanonicalJson, } from "../../internal/crypto/index.js";
|
|
2
|
+
import { assertProjectionVerificationCurrent } from "../../data/keyingProjectionVerification/types.js";
|
|
3
|
+
import { advanceKeyingCheckpointsAtomically } from "../../data/persistence/keyingCheckpointAdvancePersistence.js";
|
|
4
|
+
import { requireOrganizationGroupHead } from "../../data/principals/organizationAuthorityDescriptor.js";
|
|
5
|
+
import { createSelectedCurrentGroupMetadataContainerVerifier } from "./currentGroupMetadataAuthority.js";
|
|
6
|
+
import { loadCurrentOrganizationMutationAuthority } from "./currentOrganizationMutationAuthority.js";
|
|
7
|
+
import { assertGroupMetadataBinding } from "./groupMetadataBinding.js";
|
|
8
|
+
import { requireSignerCanManageGroup } from "./groupMutationAuthorization.js";
|
|
9
|
+
/** Exact current directory, strict Admins and group evidence for one mutation. */
|
|
10
|
+
export async function loadCurrentGroupPolicyMutationContext(input) {
|
|
11
|
+
input = { ...input };
|
|
12
|
+
const { authority, currentOrgAdminUserIds } = await loadCurrentOrganizationMutationAuthority(input);
|
|
13
|
+
const group = await authority.readGroup(input.groupId);
|
|
14
|
+
const stillCurrent = () => input.stillCurrent() && authority.stillCurrent() && group.stillCurrent();
|
|
15
|
+
assertProjectionVerificationCurrent(stillCurrent);
|
|
16
|
+
assertGroupMetadataBinding(group.current, authority.descriptor);
|
|
17
|
+
requireSignerCanManageGroup(group.current, currentOrgAdminUserIds, input.signerUserId);
|
|
18
|
+
await advanceKeyingCheckpointsAtomically({
|
|
19
|
+
access: [],
|
|
20
|
+
execSql: input.execSql,
|
|
21
|
+
organizationId: input.organizationId,
|
|
22
|
+
policies: [...group.dependencies, group.policy],
|
|
23
|
+
stillCurrent,
|
|
24
|
+
});
|
|
25
|
+
assertProjectionVerificationCurrent(stillCurrent);
|
|
26
|
+
const adminHead = requireOrganizationGroupHead(authority.descriptor, authority.descriptor.adminGroupId);
|
|
27
|
+
const externalAuthority = {
|
|
28
|
+
currentHead: adminHead,
|
|
29
|
+
states: [
|
|
30
|
+
{ head: adminHead, projection: authority.admins.policy.projection },
|
|
31
|
+
],
|
|
32
|
+
};
|
|
33
|
+
const references = new Map();
|
|
34
|
+
return {
|
|
35
|
+
adminGroupId: authority.descriptor.adminGroupId,
|
|
36
|
+
adminCurrent: authority.admins,
|
|
37
|
+
currentPolicy: group.current,
|
|
38
|
+
verifiedCurrentPolicy: group.policy,
|
|
39
|
+
verifyMetadataContainer: createSelectedCurrentGroupMetadataContainerVerifier({
|
|
40
|
+
authority,
|
|
41
|
+
organizationId: input.organizationId,
|
|
42
|
+
stillCurrent,
|
|
43
|
+
}),
|
|
44
|
+
currentOrgAdminUserIds,
|
|
45
|
+
externalAuthority,
|
|
46
|
+
isOrganizationAdminsGroup: input.groupId === authority.descriptor.adminGroupId,
|
|
47
|
+
localPolicyCheckpoint: group.policy.checkpoint,
|
|
48
|
+
memberGroupId: authority.descriptor.memberGroupId,
|
|
49
|
+
organizationDescriptor: authority.descriptor,
|
|
50
|
+
organizationCurrent: authority.directory,
|
|
51
|
+
async readPredecessorReference(reference) {
|
|
52
|
+
assertProjectionVerificationCurrent(stillCurrent);
|
|
53
|
+
const owned = structuredClone(reference);
|
|
54
|
+
const key = serializeKeyingCanonicalJson({ ...owned });
|
|
55
|
+
let pending = references.get(key);
|
|
56
|
+
if (!pending) {
|
|
57
|
+
// Keep at most one bounded selection's citations, even across many paths.
|
|
58
|
+
if (references.size === 128) {
|
|
59
|
+
const oldest = references.keys().next().value;
|
|
60
|
+
if (oldest !== undefined)
|
|
61
|
+
references.delete(oldest);
|
|
62
|
+
}
|
|
63
|
+
pending = authority
|
|
64
|
+
.readGroup(input.groupId, owned)
|
|
65
|
+
.then((selected) => selected.policy);
|
|
66
|
+
references.set(key, pending);
|
|
67
|
+
}
|
|
68
|
+
const policy = await pending.catch((error) => {
|
|
69
|
+
if (references.get(key) === pending)
|
|
70
|
+
references.delete(key);
|
|
71
|
+
throw error;
|
|
72
|
+
});
|
|
73
|
+
assertProjectionVerificationCurrent(stillCurrent);
|
|
74
|
+
return policy;
|
|
75
|
+
},
|
|
76
|
+
stillCurrent,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=currentGroupPolicyMutationContext.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"currentGroupPolicyMutationContext.js","sourceRoot":"","sources":["currentGroupPolicyMutationContext.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,4BAA4B,GAE7B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,mCAAmC,EAAE,MAAM,+CAA+C,CAAC;AACpG,OAAO,EAAE,kCAAkC,EAAE,MAAM,2DAA2D,CAAC;AAC/G,OAAO,EAAE,4BAA4B,EAAE,MAAM,uDAAuD,CAAC;AAGrG,OAAO,EAAE,mDAAmD,EAAE,MAAM,iCAAiC,CAAC;AACtG,OAAO,EAAE,wCAAwC,EAAE,MAAM,wCAAwC,CAAC;AAClG,OAAO,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AACpE,OAAO,EAAE,2BAA2B,EAAE,MAAM,8BAA8B,CAAC;AAE3E,kFAAkF;AAClF,MAAM,CAAC,KAAK,UAAU,qCAAqC,CAAC,KAY3D;IACC,KAAK,GAAG,EAAE,GAAG,KAAK,EAAE,CAAC;IACrB,MAAM,EAAE,SAAS,EAAE,sBAAsB,EAAE,GACzC,MAAM,wCAAwC,CAAC,KAAK,CAAC,CAAC;IACxD,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACvD,MAAM,YAAY,GAAG,GAAG,EAAE,CACxB,KAAK,CAAC,YAAY,EAAE,IAAI,SAAS,CAAC,YAAY,EAAE,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC;IAC3E,mCAAmC,CAAC,YAAY,CAAC,CAAC;IAClD,0BAA0B,CAAC,KAAK,CAAC,OAAO,EAAE,SAAS,CAAC,UAAU,CAAC,CAAC;IAChE,2BAA2B,CACzB,KAAK,CAAC,OAAO,EACb,sBAAsB,EACtB,KAAK,CAAC,YAAY,CACnB,CAAC;IACF,MAAM,kCAAkC,CAAC;QACvC,MAAM,EAAE,EAAE;QACV,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,cAAc,EAAE,KAAK,CAAC,cAAc;QACpC,QAAQ,EAAE,CAAC,GAAG,KAAK,CAAC,YAAY,EAAE,KAAK,CAAC,MAAM,CAAC;QAC/C,YAAY;KACb,CAAC,CAAC;IACH,mCAAmC,CAAC,YAAY,CAAC,CAAC;IAClD,MAAM,SAAS,GAAG,4BAA4B,CAC5C,SAAS,CAAC,UAAU,EACpB,SAAS,CAAC,UAAU,CAAC,YAAY,CAClC,CAAC;IACF,MAAM,iBAAiB,GAAqC;QAC1D,WAAW,EAAE,SAAS;QACtB,MAAM,EAAE;YACN,EAAE,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE;SACpE;KACF,CAAC;IACF,MAAM,UAAU,GAAG,IAAI,GAAG,EAAmD,CAAC;IAC9E,OAAO;QACL,YAAY,EAAE,SAAS,CAAC,UAAU,CAAC,YAAY;QAC/C,YAAY,EAAE,SAAS,CAAC,MAAM;QAC9B,aAAa,EAAE,KAAK,CAAC,OAAO;QAC5B,qBAAqB,EAAE,KAAK,CAAC,MAAM;QACnC,uBAAuB,EACrB,mDAAmD,CAAC;YAClD,SAAS;YACT,cAAc,EAAE,KAAK,CAAC,cAAc;YACpC,YAAY;SACb,CAAC;QACJ,sBAAsB;QACtB,iBAAiB;QACjB,yBAAyB,EACvB,KAAK,CAAC,OAAO,KAAK,SAAS,CAAC,UAAU,CAAC,YAAY;QACrD,qBAAqB,EAAE,KAAK,CAAC,MAAM,CAAC,UAAU;QAC9C,aAAa,EAAE,SAAS,CAAC,UAAU,CAAC,aAAa;QACjD,sBAAsB,EAAE,SAAS,CAAC,UAAU;QAC5C,mBAAmB,EAAE,SAAS,CAAC,SAAS;QACxC,KAAK,CAAC,wBAAwB,CAAC,SAAkC;YAC/D,mCAAmC,CAAC,YAAY,CAAC,CAAC;YAClD,MAAM,KAAK,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC;YACzC,MAAM,GAAG,GAAG,4BAA4B,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC;YACvD,IAAI,OAAO,GAAG,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAClC,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,0EAA0E;gBAC1E,IAAI,UAAU,CAAC,IAAI,KAAK,GAAG,EAAE,CAAC;oBAC5B,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;oBAC9C,IAAI,MAAM,KAAK,SAAS;wBAAE,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;gBACtD,CAAC;gBACD,OAAO,GAAG,SAAS;qBAChB,SAAS,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC;qBAC/B,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;gBACvC,UAAU,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;YAC/B,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;gBACpD,IAAI,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,OAAO;oBAAE,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBAC5D,MAAM,KAAK,CAAC;YACd,CAAC,CAAC,CAAC;YACH,mCAAmC,CAAC,YAAY,CAAC,CAAC;YAClD,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,YAAY;KACb,CAAC;AACJ,CAAC","sourcesContent":["import {\n type PrincipalPolicyExternalAuthority,\n type ReferencedPrincipalHead,\n serializeKeyingCanonicalJson,\n type VerifiedPrincipalPolicyCurrent,\n} from \"@tearleads/crypto\";\nimport { assertProjectionVerificationCurrent } from \"../../data/keyingProjectionVerification/types\";\nimport { advanceKeyingCheckpointsAtomically } from \"../../data/persistence/keyingCheckpointAdvancePersistence\";\nimport { requireOrganizationGroupHead } from \"../../data/principals/organizationAuthorityDescriptor\";\nimport type { ExecSql } from \"../../data/sqlite/sqlSchema\";\nimport type { createRuntimePrincipalPolicyCurrentResolver } from \"../principals/runtimePolicyRecovery\";\nimport { createSelectedCurrentGroupMetadataContainerVerifier } from \"./currentGroupMetadataAuthority\";\nimport { loadCurrentOrganizationMutationAuthority } from \"./currentOrganizationMutationAuthority\";\nimport { assertGroupMetadataBinding } from \"./groupMetadataBinding\";\nimport { requireSignerCanManageGroup } from \"./groupMutationAuthorization\";\n\n/** Exact current directory, strict Admins and group evidence for one mutation. */\nexport async function loadCurrentGroupPolicyMutationContext(input: {\n readonly execSql: ExecSql;\n readonly groupId: string;\n readonly organizationId: string;\n readonly signerUserId: string;\n readonly resolveCurrentPolicy: NonNullable<\n ReturnType<typeof createRuntimePrincipalPolicyCurrentResolver>\n >;\n readonly recoverPendingPrincipalMutation: (\n organizationId: string,\n ) => Promise<void>;\n readonly stillCurrent: () => boolean;\n}) {\n input = { ...input };\n const { authority, currentOrgAdminUserIds } =\n await loadCurrentOrganizationMutationAuthority(input);\n const group = await authority.readGroup(input.groupId);\n const stillCurrent = () =>\n input.stillCurrent() && authority.stillCurrent() && group.stillCurrent();\n assertProjectionVerificationCurrent(stillCurrent);\n assertGroupMetadataBinding(group.current, authority.descriptor);\n requireSignerCanManageGroup(\n group.current,\n currentOrgAdminUserIds,\n input.signerUserId,\n );\n await advanceKeyingCheckpointsAtomically({\n access: [],\n execSql: input.execSql,\n organizationId: input.organizationId,\n policies: [...group.dependencies, group.policy],\n stillCurrent,\n });\n assertProjectionVerificationCurrent(stillCurrent);\n const adminHead = requireOrganizationGroupHead(\n authority.descriptor,\n authority.descriptor.adminGroupId,\n );\n const externalAuthority: PrincipalPolicyExternalAuthority = {\n currentHead: adminHead,\n states: [\n { head: adminHead, projection: authority.admins.policy.projection },\n ],\n };\n const references = new Map<string, Promise<VerifiedPrincipalPolicyCurrent>>();\n return {\n adminGroupId: authority.descriptor.adminGroupId,\n adminCurrent: authority.admins,\n currentPolicy: group.current,\n verifiedCurrentPolicy: group.policy,\n verifyMetadataContainer:\n createSelectedCurrentGroupMetadataContainerVerifier({\n authority,\n organizationId: input.organizationId,\n stillCurrent,\n }),\n currentOrgAdminUserIds,\n externalAuthority,\n isOrganizationAdminsGroup:\n input.groupId === authority.descriptor.adminGroupId,\n localPolicyCheckpoint: group.policy.checkpoint,\n memberGroupId: authority.descriptor.memberGroupId,\n organizationDescriptor: authority.descriptor,\n organizationCurrent: authority.directory,\n async readPredecessorReference(reference: ReferencedPrincipalHead) {\n assertProjectionVerificationCurrent(stillCurrent);\n const owned = structuredClone(reference);\n const key = serializeKeyingCanonicalJson({ ...owned });\n let pending = references.get(key);\n if (!pending) {\n // Keep at most one bounded selection's citations, even across many paths.\n if (references.size === 128) {\n const oldest = references.keys().next().value;\n if (oldest !== undefined) references.delete(oldest);\n }\n pending = authority\n .readGroup(input.groupId, owned)\n .then((selected) => selected.policy);\n references.set(key, pending);\n }\n const policy = await pending.catch((error: unknown) => {\n if (references.get(key) === pending) references.delete(key);\n throw error;\n });\n assertProjectionVerificationCurrent(stillCurrent);\n return policy;\n },\n stillCurrent,\n };\n}\n"]}
|
|
@@ -9,6 +9,10 @@ import { readGroupPolicyPayloadName, } from "./principalPolicyRequest.js";
|
|
|
9
9
|
/** Names consume verified current artifacts; paged recovery retains their separate evidence. */
|
|
10
10
|
export async function hydrateCurrentOrganizationGroupNames(input) {
|
|
11
11
|
const authority = await loadCurrentOrganizationAuthority(input);
|
|
12
|
+
const nameInput = {
|
|
13
|
+
...input,
|
|
14
|
+
readEncryptedName: input.createCurrentNameReader?.(authority) ?? input.readEncryptedName,
|
|
15
|
+
};
|
|
12
16
|
const names = [];
|
|
13
17
|
const unreadable = new Set();
|
|
14
18
|
const lifetimes = [authority.stillCurrent];
|
|
@@ -19,7 +23,7 @@ export async function hydrateCurrentOrganizationGroupNames(input) {
|
|
|
19
23
|
const verified = await authority.readGroup(group.groupId);
|
|
20
24
|
lifetimes.push(verified.stillCurrent);
|
|
21
25
|
assertGroupMetadataBinding(verified.current, authority.descriptor);
|
|
22
|
-
const name = await readCurrentGroupName(
|
|
26
|
+
const name = await readCurrentGroupName(nameInput, verified.current);
|
|
23
27
|
if (name === null)
|
|
24
28
|
unreadable.add(group.groupId);
|
|
25
29
|
else
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"currentOrganizationGroupNames.js","sourceRoot":"","sources":["currentOrganizationGroupNames.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,mCAAmC,EAAE,MAAM,+CAA+C,CAAC;AACpG,OAAO,EAAE,kCAAkC,EAAE,MAAM,2DAA2D,CAAC;AAC/G,OAAO,EAAE,iCAAiC,EAAE,MAAM,uEAAuE,CAAC;AAE1H,OAAO,EAAE,gCAAgC,EAAE,MAAM,gCAAgC,CAAC;AAClF,OAAO,EAAE,4BAA4B,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AACpE,OAAO,EAEL,0BAA0B,GAC3B,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"currentOrganizationGroupNames.js","sourceRoot":"","sources":["currentOrganizationGroupNames.ts"],"names":[],"mappings":"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","sourcesContent":["import { KeyingVerificationError } from \"@tearleads/crypto\";\nimport { assertProjectionVerificationCurrent } from \"../../data/keyingProjectionVerification/types\";\nimport { advanceKeyingCheckpointsAtomically } from \"../../data/persistence/keyingCheckpointAdvancePersistence\";\nimport { saveOrganizationGroupDisplayNames } from \"../../data/persistence/organizations/organizationGroupNamePersistence\";\nimport type { SecurityIncidentReporter } from \"../../data/securityIncidents\";\nimport { loadCurrentOrganizationAuthority } from \"./currentOrganizationAuthority\";\nimport { GroupMetadataUnreadableError } from \"./groupMetadataAccess\";\nimport { assertGroupMetadataBinding } from \"./groupMetadataBinding\";\nimport {\n type GroupPolicyNameReader,\n readGroupPolicyPayloadName,\n} from \"./principalPolicyRequest\";\nimport type { OrganizationDirectoryAndGroups } from \"./readModel\";\n\ntype Input = Parameters<typeof loadCurrentOrganizationAuthority>[0] & {\n readonly directory: OrganizationDirectoryAndGroups;\n readonly readEncryptedName?: GroupPolicyNameReader | undefined;\n readonly createCurrentNameReader?:\n | ((\n authority: Awaited<ReturnType<typeof loadCurrentOrganizationAuthority>>,\n ) => GroupPolicyNameReader)\n | undefined;\n readonly reportSecurityIncident: SecurityIncidentReporter;\n};\n\n/** Names consume verified current artifacts; paged recovery retains their separate evidence. */\nexport async function hydrateCurrentOrganizationGroupNames(\n input: Input,\n): Promise<OrganizationDirectoryAndGroups> {\n const authority = await loadCurrentOrganizationAuthority(input);\n const nameInput = {\n ...input,\n readEncryptedName:\n input.createCurrentNameReader?.(authority) ?? input.readEncryptedName,\n };\n const names: { groupId: string; name: string; stateHash: string }[] = [];\n const unreadable = new Set<string>();\n const lifetimes: (() => boolean)[] = [authority.stillCurrent];\n for (const group of input.directory.groups) {\n const head = authority.descriptor.groupHeads.find(\n (head) => head.principalId === group.groupId,\n );\n if (!head || head.stateHash !== group.currentState?.stateHash)\n throw new Error(\"Group listing does not match the signed directory\");\n const verified = await authority.readGroup(group.groupId);\n lifetimes.push(verified.stillCurrent);\n assertGroupMetadataBinding(verified.current, authority.descriptor);\n const name = await readCurrentGroupName(nameInput, verified.current);\n if (name === null) unreadable.add(group.groupId);\n else\n names.push({ groupId: group.groupId, name, stateHash: head.stateHash });\n }\n const stillCurrent = () =>\n input.stillCurrent() && lifetimes.every((current) => current());\n assertProjectionVerificationCurrent(stillCurrent);\n // Match the authority admission performed by the full-bundle path. Group\n // name reads alone do not move group checkpoints.\n await advanceKeyingCheckpointsAtomically({\n access: [],\n execSql: input.execSql,\n organizationId: input.organizationId,\n policies: [authority.directory.policy, authority.admins.policy],\n stillCurrent,\n });\n await saveOrganizationGroupDisplayNames({ ...input, names, stillCurrent });\n assertProjectionVerificationCurrent(stillCurrent);\n const byId = new Map(names.map((entry) => [entry.groupId, entry.name]));\n return {\n ...input.directory,\n groups: input.directory.groups.map((group) => ({\n ...group,\n name: byId.get(group.groupId) ?? \"\",\n nameUnreadable: unreadable.has(group.groupId),\n })),\n };\n}\n\nasync function readCurrentGroupName(\n input: Input,\n current: Parameters<GroupPolicyNameReader>[0],\n) {\n try {\n return await readGroupPolicyPayloadName(current, input.readEncryptedName);\n } catch (error) {\n if (!(error instanceof GroupMetadataUnreadableError)) throw error;\n await input.reportSecurityIncident(\n new KeyingVerificationError(\n \"invalid_shape\",\n \"Signed group name does not open under the cited metadata key\",\n ),\n {\n evidenceHashes: { stateHash: current.currentState.stateHash },\n objectId: current.currentState.principalId,\n objectKind: \"principal\",\n operation: \"organization.groupName\",\n organizationId: input.organizationId,\n },\n );\n return null;\n }\n}\n"]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { assertProjectionVerificationCurrent } from "../../data/keyingProjectionVerification/types.js";
|
|
2
|
+
import { organizationAdminSignerUserIds } from "../../data/principals/principalPolicyAdminSigners.js";
|
|
3
|
+
import { loadCurrentOrganizationAuthority } from "./currentOrganizationAuthority.js";
|
|
4
|
+
/** Resolve uncertain work and verify the signing administrator before any mutation pins. */
|
|
5
|
+
export async function loadCurrentOrganizationMutationAuthority(input) {
|
|
6
|
+
const owned = { ...input };
|
|
7
|
+
assertProjectionVerificationCurrent(owned.stillCurrent);
|
|
8
|
+
await owned.recoverPendingPrincipalMutation(owned.organizationId);
|
|
9
|
+
assertProjectionVerificationCurrent(owned.stillCurrent);
|
|
10
|
+
const authority = await loadCurrentOrganizationAuthority(owned);
|
|
11
|
+
const currentOrgAdminUserIds = organizationAdminSignerUserIds(authority.admins.policy);
|
|
12
|
+
if (!currentOrgAdminUserIds.includes(owned.signerUserId))
|
|
13
|
+
throw new Error("Organization admin authority is required");
|
|
14
|
+
return { authority, currentOrgAdminUserIds };
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=currentOrganizationMutationAuthority.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"currentOrganizationMutationAuthority.js","sourceRoot":"","sources":["currentOrganizationMutationAuthority.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mCAAmC,EAAE,MAAM,+CAA+C,CAAC;AACpG,OAAO,EAAE,8BAA8B,EAAE,MAAM,mDAAmD,CAAC;AACnG,OAAO,EAAE,gCAAgC,EAAE,MAAM,gCAAgC,CAAC;AAElF,4FAA4F;AAC5F,MAAM,CAAC,KAAK,UAAU,wCAAwC,CAC5D,KAQC;IAED,MAAM,KAAK,GAAG,EAAE,GAAG,KAAK,EAAE,CAAC;IAC3B,mCAAmC,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IACxD,MAAM,KAAK,CAAC,+BAA+B,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IAClE,mCAAmC,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IACxD,MAAM,SAAS,GAAG,MAAM,gCAAgC,CAAC,KAAK,CAAC,CAAC;IAChE,MAAM,sBAAsB,GAAG,8BAA8B,CAC3D,SAAS,CAAC,MAAM,CAAC,MAAM,CACxB,CAAC;IACF,IAAI,CAAC,sBAAsB,CAAC,QAAQ,CAAC,KAAK,CAAC,YAAY,CAAC;QACtD,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;IAC9D,OAAO,EAAE,SAAS,EAAE,sBAAsB,EAAE,CAAC;AAC/C,CAAC","sourcesContent":["import { assertProjectionVerificationCurrent } from \"../../data/keyingProjectionVerification/types\";\nimport { organizationAdminSignerUserIds } from \"../../data/principals/principalPolicyAdminSigners\";\nimport { loadCurrentOrganizationAuthority } from \"./currentOrganizationAuthority\";\n\n/** Resolve uncertain work and verify the signing administrator before any mutation pins. */\nexport async function loadCurrentOrganizationMutationAuthority(\n input: Omit<\n Parameters<typeof loadCurrentOrganizationAuthority>[0],\n \"organizationReference\"\n > & {\n readonly signerUserId: string;\n readonly recoverPendingPrincipalMutation: (\n organizationId: string,\n ) => Promise<void>;\n },\n) {\n const owned = { ...input };\n assertProjectionVerificationCurrent(owned.stillCurrent);\n await owned.recoverPendingPrincipalMutation(owned.organizationId);\n assertProjectionVerificationCurrent(owned.stillCurrent);\n const authority = await loadCurrentOrganizationAuthority(owned);\n const currentOrgAdminUserIds = organizationAdminSignerUserIds(\n authority.admins.policy,\n );\n if (!currentOrgAdminUserIds.includes(owned.signerUserId))\n throw new Error(\"Organization admin authority is required\");\n return { authority, currentOrgAdminUserIds };\n}\n"]}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { assertProjectionVerificationCurrent } from "../../data/keyingProjectionVerification/types.js";
|
|
2
|
+
import { scopedGroupHistoryProtection } from "../../data/principals/principalHistoryScopeProtection.js";
|
|
3
|
+
import { principalPolicyReferenceFromBundle } from "../../data/principals/principalPolicyAdminSigners.js";
|
|
4
|
+
import { retainAcknowledgedPrincipalCurrents, } from "./retainAcknowledgedPrincipalCurrents.js";
|
|
5
|
+
/** Couple directory acknowledgements to any newly created group under the same lease. */
|
|
6
|
+
export function createCurrentOrganizationMutationRetention(input) {
|
|
7
|
+
const retain = async (entries) => {
|
|
8
|
+
assertProjectionVerificationCurrent(input.stillCurrent);
|
|
9
|
+
await retainAcknowledgedPrincipalCurrents({
|
|
10
|
+
execSql: input.runtime.infra.execSql,
|
|
11
|
+
organizationId: input.organizationId,
|
|
12
|
+
entries,
|
|
13
|
+
stillCurrent: input.stillCurrent,
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
return {
|
|
17
|
+
retainDirectory: (request, response) => retain([{ request, response, recovery: input.directoryRecovery }]),
|
|
18
|
+
retainCreatedGroup: (receipt) => {
|
|
19
|
+
const adminHead = {
|
|
20
|
+
...principalPolicyReferenceFromBundle(input.authority.admins.current),
|
|
21
|
+
principalType: "group",
|
|
22
|
+
};
|
|
23
|
+
return retain([
|
|
24
|
+
{
|
|
25
|
+
initialGroup: true,
|
|
26
|
+
request: receipt.request,
|
|
27
|
+
response: receipt.response,
|
|
28
|
+
recovery: {
|
|
29
|
+
apiClient: { getPrincipalPolicyPages: input.readPages },
|
|
30
|
+
expectedHead: principalPolicyReferenceFromBundle(receipt.response),
|
|
31
|
+
protection: scopedGroupHistoryProtection(input.protection, input.organizationId, input.authority.descriptor.adminGroupId),
|
|
32
|
+
resolveTrustedUserIdentity: input.runtime.resolveTrustedUserIdentity,
|
|
33
|
+
loadExternalAuthority: async () => ({
|
|
34
|
+
currentHead: adminHead,
|
|
35
|
+
states: [
|
|
36
|
+
{
|
|
37
|
+
head: adminHead,
|
|
38
|
+
projection: input.authority.admins.policy.projection,
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
}),
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
request: receipt.organizationRequest,
|
|
46
|
+
response: receipt.organizationResponse,
|
|
47
|
+
recovery: input.directoryRecovery,
|
|
48
|
+
},
|
|
49
|
+
]);
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=currentOrganizationMutationRetention.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"currentOrganizationMutationRetention.js","sourceRoot":"","sources":["currentOrganizationMutationRetention.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,mCAAmC,EAAE,MAAM,+CAA+C,CAAC;AACpG,OAAO,EAAE,4BAA4B,EAAE,MAAM,uDAAuD,CAAC;AACrG,OAAO,EAAE,kCAAkC,EAAE,MAAM,mDAAmD,CAAC;AAGvG,OAAO,EAEL,mCAAmC,GACpC,MAAM,uCAAuC,CAAC;AAE/C,yFAAyF;AACzF,MAAM,UAAU,0CAA0C,CAAC,KAU1D;IACC,MAAM,MAAM,GAAG,KAAK,EAClB,OAAqD,EACrD,EAAE;QACF,mCAAmC,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QACxD,MAAM,mCAAmC,CAAC;YACxC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO;YACpC,cAAc,EAAE,KAAK,CAAC,cAAc;YACpC,OAAO;YACP,YAAY,EAAE,KAAK,CAAC,YAAY;SACjC,CAAC,CAAC;IACL,CAAC,CAAC;IACF,OAAO;QACL,eAAe,EAAE,CACf,OAAkC,EAClC,QAAyC,EACzC,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,iBAAiB,EAAE,CAAC,CAAC;QACvE,kBAAkB,EAAE,CAAC,OAKpB,EAAE,EAAE;YACH,MAAM,SAAS,GAAG;gBAChB,GAAG,kCAAkC,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC;gBACrE,aAAa,EAAE,OAAgB;aAChC,CAAC;YACF,OAAO,MAAM,CAAC;gBACZ;oBACE,YAAY,EAAE,IAAI;oBAClB,OAAO,EAAE,OAAO,CAAC,OAAO;oBACxB,QAAQ,EAAE,OAAO,CAAC,QAAQ;oBAC1B,QAAQ,EAAE;wBACR,SAAS,EAAE,EAAE,uBAAuB,EAAE,KAAK,CAAC,SAAS,EAAE;wBACvD,YAAY,EAAE,kCAAkC,CAAC,OAAO,CAAC,QAAQ,CAAC;wBAClE,UAAU,EAAE,4BAA4B,CACtC,KAAK,CAAC,UAAU,EAChB,KAAK,CAAC,cAAc,EACpB,KAAK,CAAC,SAAS,CAAC,UAAU,CAAC,YAAY,CACxC;wBACD,0BAA0B,EACxB,KAAK,CAAC,OAAO,CAAC,0BAA0B;wBAC1C,qBAAqB,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;4BAClC,WAAW,EAAE,SAAS;4BACtB,MAAM,EAAE;gCACN;oCACE,IAAI,EAAE,SAAS;oCACf,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU;iCACrD;6BACF;yBACF,CAAC;qBACH;iBACF;gBACD;oBACE,OAAO,EAAE,OAAO,CAAC,mBAAmB;oBACpC,QAAQ,EAAE,OAAO,CAAC,oBAAoB;oBACtC,QAAQ,EAAE,KAAK,CAAC,iBAAiB;iBAClC;aACF,CAAC,CAAC;QACL,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["import type { ApiClient } from \"@tearleads/api-client\";\nimport type { PrincipalPolicyHistoryProgressOptions } from \"@tearleads/crypto\";\nimport type { PutPrincipalPolicyRequest } from \"@tearleads/validators/request\";\nimport type { PrincipalPolicyMutationResponse } from \"@tearleads/validators/response\";\nimport { assertProjectionVerificationCurrent } from \"../../data/keyingProjectionVerification/types\";\nimport { scopedGroupHistoryProtection } from \"../../data/principals/principalHistoryScopeProtection\";\nimport { principalPolicyReferenceFromBundle } from \"../../data/principals/principalPolicyAdminSigners\";\nimport type { PrincipalPolicyRecoveryRuntime } from \"../principals/runtimePolicyRecovery\";\nimport type { loadCurrentOrganizationAuthority } from \"./currentOrganizationAuthority\";\nimport {\n type AcknowledgedPrincipalCurrentInput,\n retainAcknowledgedPrincipalCurrents,\n} from \"./retainAcknowledgedPrincipalCurrents\";\n\n/** Couple directory acknowledgements to any newly created group under the same lease. */\nexport function createCurrentOrganizationMutationRetention(input: {\n readonly runtime: PrincipalPolicyRecoveryRuntime;\n readonly authority: Awaited<\n ReturnType<typeof loadCurrentOrganizationAuthority>\n >;\n readonly protection: PrincipalPolicyHistoryProgressOptions;\n readonly readPages: ApiClient[\"getPrincipalPolicyPages\"];\n readonly organizationId: string;\n readonly directoryRecovery: AcknowledgedPrincipalCurrentInput[\"recovery\"];\n readonly stillCurrent: () => boolean;\n}) {\n const retain = async (\n entries: readonly AcknowledgedPrincipalCurrentInput[],\n ) => {\n assertProjectionVerificationCurrent(input.stillCurrent);\n await retainAcknowledgedPrincipalCurrents({\n execSql: input.runtime.infra.execSql,\n organizationId: input.organizationId,\n entries,\n stillCurrent: input.stillCurrent,\n });\n };\n return {\n retainDirectory: (\n request: PutPrincipalPolicyRequest,\n response: PrincipalPolicyMutationResponse,\n ) => retain([{ request, response, recovery: input.directoryRecovery }]),\n retainCreatedGroup: (receipt: {\n readonly request: PutPrincipalPolicyRequest;\n readonly response: PrincipalPolicyMutationResponse;\n readonly organizationRequest: PutPrincipalPolicyRequest;\n readonly organizationResponse: PrincipalPolicyMutationResponse;\n }) => {\n const adminHead = {\n ...principalPolicyReferenceFromBundle(input.authority.admins.current),\n principalType: \"group\" as const,\n };\n return retain([\n {\n initialGroup: true,\n request: receipt.request,\n response: receipt.response,\n recovery: {\n apiClient: { getPrincipalPolicyPages: input.readPages },\n expectedHead: principalPolicyReferenceFromBundle(receipt.response),\n protection: scopedGroupHistoryProtection(\n input.protection,\n input.organizationId,\n input.authority.descriptor.adminGroupId,\n ),\n resolveTrustedUserIdentity:\n input.runtime.resolveTrustedUserIdentity,\n loadExternalAuthority: async () => ({\n currentHead: adminHead,\n states: [\n {\n head: adminHead,\n projection: input.authority.admins.policy.projection,\n },\n ],\n }),\n },\n },\n {\n request: receipt.organizationRequest,\n response: receipt.organizationResponse,\n recovery: input.directoryRecovery,\n },\n ]);\n },\n };\n}\n"]}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { assertProjectionVerificationCurrent } from "../../data/keyingProjectionVerification/types.js";
|
|
2
|
+
import { readPrincipalHistoryProtection } from "../../data/principals/principalHistoryRuntime.js";
|
|
3
|
+
import { directoryHistoryProtection } from "../../data/principals/principalHistoryScopeProtection.js";
|
|
4
|
+
import { principalPolicyReferenceFromBundle } from "../../data/principals/principalPolicyAdminSigners.js";
|
|
5
|
+
import { createRuntimePrincipalPolicyCurrentResolver, } from "../principals/runtimePolicyRecovery.js";
|
|
6
|
+
/** One lifetime fence and private custody boundary for every current-policy mutation. */
|
|
7
|
+
export function createCurrentPrincipalMutationLease(runtime) {
|
|
8
|
+
const lease = readPrincipalHistoryProtection(runtime);
|
|
9
|
+
const resolveCurrentPolicy = createRuntimePrincipalPolicyCurrentResolver(runtime);
|
|
10
|
+
const readPages = runtime.apiClient.getPrincipalPolicyPages?.bind(runtime.apiClient);
|
|
11
|
+
if (!lease || !resolveCurrentPolicy || !readPages)
|
|
12
|
+
return undefined;
|
|
13
|
+
return async (callerCurrent, work) => lease(async ({ protection, stillCurrent: leaseCurrent }) => {
|
|
14
|
+
let active = true;
|
|
15
|
+
const stillCurrent = () => active && leaseCurrent() && callerCurrent();
|
|
16
|
+
try {
|
|
17
|
+
assertProjectionVerificationCurrent(stillCurrent);
|
|
18
|
+
const result = await work({
|
|
19
|
+
protection,
|
|
20
|
+
stillCurrent,
|
|
21
|
+
resolveCurrentPolicy,
|
|
22
|
+
readPages,
|
|
23
|
+
directoryRecovery: (current) => ({
|
|
24
|
+
apiClient: { getPrincipalPolicyPages: readPages },
|
|
25
|
+
expectedHead: principalPolicyReferenceFromBundle(current),
|
|
26
|
+
protection: directoryHistoryProtection(protection),
|
|
27
|
+
resolveTrustedUserIdentity: runtime.resolveTrustedUserIdentity,
|
|
28
|
+
}),
|
|
29
|
+
});
|
|
30
|
+
assertProjectionVerificationCurrent(stillCurrent);
|
|
31
|
+
return result;
|
|
32
|
+
}
|
|
33
|
+
finally {
|
|
34
|
+
active = false;
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=currentPrincipalMutationLease.js.map
|