@tearleads/client-sdk 0.1.15 → 0.1.16
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/Tearleads.d.ts +2 -0
- package/client/Tearleads.js +1 -0
- package/client/Tearleads.js.map +1 -1
- package/client/index.d.ts +1 -1
- package/client/index.js.map +1 -1
- package/client/organizations/index.d.ts +4 -42
- package/client/organizations/index.js +13 -0
- package/client/organizations/index.js.map +1 -1
- package/client/organizations/organizationGroupNameHydration.js +8 -1
- package/client/organizations/organizationGroupNameHydration.js.map +1 -1
- package/client/organizations/organizationsTypes.d.ts +47 -0
- package/client/organizations/organizationsTypes.js +2 -0
- package/client/organizations/organizationsTypes.js.map +1 -0
- package/client/organizations/principalMutationRecovery.d.ts +16 -0
- package/client/organizations/principalMutationRecovery.js +23 -0
- package/client/organizations/principalMutationRecovery.js.map +1 -0
- package/client/organizations/principalMutationScope.js +7 -2
- package/client/organizations/principalMutationScope.js.map +1 -1
- package/client/principalMutationApi.d.ts +24 -0
- package/client/principalMutationApi.js +108 -0
- package/client/principalMutationApi.js.map +1 -0
- package/client/principalMutationDeadline.js +23 -0
- package/client/principalMutationDeadline.js.map +1 -0
- package/client/workflowRuntime.d.ts +3 -1
- package/client/workflowRuntime.js +44 -5
- package/client/workflowRuntime.js.map +1 -1
- package/data/persistence/principalCurrentAcknowledgementPersistence.d.ts +27 -0
- package/data/persistence/principalCurrentAcknowledgementPersistence.js +109 -0
- package/data/persistence/principalCurrentAcknowledgementPersistence.js.map +1 -0
- package/data/persistence/principalGrantRetirementPersistence.d.ts +3 -3
- package/data/persistence/principalGrantRetirementPersistence.js +4 -1
- package/data/persistence/principalGrantRetirementPersistence.js.map +1 -1
- package/data/persistence/principalKeyEnvelopeCandidates.js +12 -1
- package/data/persistence/principalKeyEnvelopeCandidates.js.map +1 -1
- package/data/persistence/principalMutationJournalPersistence.d.ts +19 -0
- package/data/persistence/principalMutationJournalPersistence.js +53 -0
- package/data/persistence/principalMutationJournalPersistence.js.map +1 -0
- package/data/persistence/verifiedPrincipalPolicyBundle.js +7 -51
- package/data/persistence/verifiedPrincipalPolicyBundle.js.map +1 -1
- package/data/persistence/verifiedPrincipalPolicyCurrent.js +56 -0
- package/data/persistence/verifiedPrincipalPolicyCurrent.js.map +1 -0
- package/data/principals/principalMutationJournal.d.ts +26 -0
- package/data/principals/principalMutationJournal.js +90 -0
- package/data/principals/principalMutationJournal.js.map +1 -0
- package/data/principals/principalMutationJournalRecord.d.ts +8 -0
- package/data/principals/principalMutationJournalRecord.js +25 -0
- package/data/principals/principalMutationJournalRecord.js.map +1 -0
- package/data/sqlite/principalHistoryStageSchema.js +3 -0
- package/data/sqlite/principalHistoryStageSchema.js.map +1 -1
- package/data/sqlite/principalMutationJournalSchema.d.ts +85 -0
- package/data/sqlite/principalMutationJournalSchema.js +13 -0
- package/data/sqlite/principalMutationJournalSchema.js.map +1 -0
- package/data/sqlite/schema.d.ts +83 -0
- package/data/sqlite/schema.js +3 -0
- package/data/sqlite/schema.js.map +1 -1
- package/index.d.ts +3 -3
- package/index.js +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 +2 -0
- package/internal/crypto/keying/index.js +2 -0
- package/internal/crypto/keying/index.js.map +1 -1
- package/internal/crypto/keying/principalPolicyCurrent.d.ts +1 -1
- package/internal/crypto/keying/principalPolicyCurrent.js +3 -3
- package/internal/crypto/keying/principalPolicyCurrent.js.map +1 -1
- package/internal/crypto/keying/principalPolicyCurrentEvidence.js +16 -0
- package/internal/crypto/keying/principalPolicyCurrentEvidence.js.map +1 -0
- package/internal/crypto/keying/principalPolicyCurrentMutation.d.ts +10 -0
- package/internal/crypto/keying/principalPolicyCurrentMutation.js +51 -0
- package/internal/crypto/keying/principalPolicyCurrentMutation.js.map +1 -0
- package/internal/crypto/keying/principalPolicyCurrentSuccessor.d.ts +10 -0
- package/internal/crypto/keying/principalPolicyCurrentSuccessor.js +60 -0
- package/internal/crypto/keying/principalPolicyCurrentSuccessor.js.map +1 -0
- package/internal/crypto/keying/principalPolicyHistory.js +4 -1
- package/internal/crypto/keying/principalPolicyHistory.js.map +1 -1
- package/internal/crypto/keying/principalPolicyHistoryReferences.js +1 -1
- package/internal/crypto/keying/principalPolicyHistoryReferences.js.map +1 -1
- package/internal/crypto/keying/principalPolicyHistoryTypes.d.ts +5 -2
- package/internal/crypto/keying/principalPolicyHistoryTypes.js +6 -3
- package/internal/crypto/keying/principalPolicyHistoryTypes.js.map +1 -1
- package/package.json +1 -1
- package/workflows/containers/child/share.js +4 -0
- package/workflows/containers/child/share.js.map +1 -1
- package/workflows/containers/child/sharePrincipalPolicy.d.ts +1 -0
- package/workflows/containers/child/sharePrincipalPolicy.js.map +1 -1
- package/workflows/organizations/acknowledgedDirectoryBindings.js +18 -0
- package/workflows/organizations/acknowledgedDirectoryBindings.js.map +1 -0
- package/workflows/organizations/currentGroupMetadataAuthority.js +32 -0
- package/workflows/organizations/currentGroupMetadataAuthority.js.map +1 -0
- package/workflows/organizations/currentOrganizationAuthority.js +88 -0
- package/workflows/organizations/currentOrganizationAuthority.js.map +1 -0
- package/workflows/organizations/currentOrganizationGroupNames.js +68 -0
- package/workflows/organizations/currentOrganizationGroupNames.js.map +1 -0
- package/workflows/organizations/currentPolicyMutationAcknowledgement.js +65 -0
- package/workflows/organizations/currentPolicyMutationAcknowledgement.js.map +1 -0
- package/workflows/organizations/deleteOrganizationGroup.js +1 -0
- package/workflows/organizations/deleteOrganizationGroup.js.map +1 -1
- package/workflows/organizations/groupCreation.js +1 -0
- package/workflows/organizations/groupCreation.js.map +1 -1
- package/workflows/organizations/groupMetadataAccess.d.ts +2 -2
- package/workflows/organizations/groupMetadataAccess.js +1 -1
- package/workflows/organizations/groupMetadataAccess.js.map +1 -1
- package/workflows/organizations/groupMetadataBinding.js.map +1 -1
- package/workflows/organizations/groupMetadataContainerAuthority.js +2 -47
- package/workflows/organizations/groupMetadataContainerAuthority.js.map +1 -1
- package/workflows/organizations/groupMetadataRootBinding.js +51 -0
- package/workflows/organizations/groupMetadataRootBinding.js.map +1 -0
- package/workflows/organizations/groupMetadataRuntime.js +20 -9
- package/workflows/organizations/groupMetadataRuntime.js.map +1 -1
- package/workflows/organizations/groupMutationAuthorization.js.map +1 -1
- package/workflows/organizations/groupPolicyMutationAcknowledgement.js +9 -75
- package/workflows/organizations/groupPolicyMutationAcknowledgement.js.map +1 -1
- package/workflows/organizations/groupPolicyMutationContext.d.ts +5 -13
- package/workflows/organizations/groupPolicyMutationContext.js +1 -0
- package/workflows/organizations/groupPolicyMutationContext.js.map +1 -1
- package/workflows/organizations/groupPolicyMutationEvidence.d.ts +26 -0
- package/workflows/organizations/groupPolicyMutationEvidence.js +64 -0
- package/workflows/organizations/groupPolicyMutationEvidence.js.map +1 -0
- package/workflows/organizations/groupPolicyMutationHead.js.map +1 -1
- package/workflows/organizations/groupPolicyRequests.js +69 -63
- package/workflows/organizations/groupPolicyRequests.js.map +1 -1
- package/workflows/organizations/index.d.ts +6 -0
- package/workflows/organizations/index.js +5 -0
- package/workflows/organizations/index.js.map +1 -1
- package/workflows/organizations/organizationGroupNames.js +7 -0
- package/workflows/organizations/organizationGroupNames.js.map +1 -1
- package/workflows/organizations/principalCurrentPublicationSeal.js +51 -0
- package/workflows/organizations/principalCurrentPublicationSeal.js.map +1 -0
- package/workflows/organizations/principalMutationJournalLane.js +26 -0
- package/workflows/organizations/principalMutationJournalLane.js.map +1 -0
- package/workflows/organizations/principalMutationJournalManagement.d.ts +26 -0
- package/workflows/organizations/principalMutationJournalManagement.js +104 -0
- package/workflows/organizations/principalMutationJournalManagement.js.map +1 -0
- package/workflows/organizations/principalMutationJournalSession.d.ts +26 -0
- package/workflows/organizations/principalMutationJournalSession.js +85 -0
- package/workflows/organizations/principalMutationJournalSession.js.map +1 -0
- package/workflows/organizations/principalMutationReceipt.js +21 -0
- package/workflows/organizations/principalMutationReceipt.js.map +1 -0
- package/workflows/organizations/principalPolicyReceiptArtifacts.js +74 -0
- package/workflows/organizations/principalPolicyReceiptArtifacts.js.map +1 -0
- package/workflows/organizations/principalPolicyRequest.d.ts +5 -4
- package/workflows/organizations/principalPolicyRequest.js.map +1 -1
- package/workflows/organizations/retainAcknowledgedPrincipalCurrents.d.ts +21 -0
- package/workflows/organizations/retainAcknowledgedPrincipalCurrents.js +155 -0
- package/workflows/organizations/retainAcknowledgedPrincipalCurrents.js.map +1 -0
- package/workflows/principals/principalCurrentRecoveryBatch.js +14 -0
- package/workflows/principals/principalCurrentRecoveryBatch.js.map +1 -0
- package/workflows/principals/principalRecoveryDirectory.d.ts +1 -1
- package/workflows/principals/principalRecoveryDirectory.js +29 -4
- package/workflows/principals/principalRecoveryDirectory.js.map +1 -1
- package/workflows/principals/principalRecoveryDiscoveryPage.js +36 -0
- package/workflows/principals/principalRecoveryDiscoveryPage.js.map +1 -0
- package/workflows/principals/principalRecoveryLocalPreference.js +28 -0
- package/workflows/principals/principalRecoveryLocalPreference.js.map +1 -0
- package/workflows/principals/principalRecoveryMemo.d.ts +16 -0
- package/workflows/principals/principalRecoveryMemo.js +88 -16
- package/workflows/principals/principalRecoveryMemo.js.map +1 -1
- package/workflows/principals/recoverCurrentOrganizationPolicy.js +33 -0
- package/workflows/principals/recoverCurrentOrganizationPolicy.js.map +1 -0
- package/workflows/principals/recoverScopedPrincipalPolicyHistory.d.ts +2 -1
- package/workflows/principals/recoverScopedPrincipalPolicyHistory.js +13 -15
- package/workflows/principals/recoverScopedPrincipalPolicyHistory.js.map +1 -1
- package/workflows/principals/runtimePolicyRecovery.js +14 -8
- package/workflows/principals/runtimePolicyRecovery.js.map +1 -1
|
@@ -7,4 +7,4 @@ export interface RecoveredPolicyDirectory extends RecoveredPrincipalPolicyHistor
|
|
|
7
7
|
}
|
|
8
8
|
export declare class PrincipalRecoveryDirectoryAdvanced extends Error {
|
|
9
9
|
}
|
|
10
|
-
export declare function recoverPolicyDirectory(input: PrincipalRecoveryContext, references: readonly ReferencedPrincipalHead[]): Promise<RecoveredPolicyDirectory>;
|
|
10
|
+
export declare function recoverPolicyDirectory(input: PrincipalRecoveryContext, references: readonly ReferencedPrincipalHead[], selected?: RecoveredPolicyDirectory): Promise<RecoveredPolicyDirectory>;
|
|
@@ -5,9 +5,20 @@ import { parseOrganizationAuthorityDescriptor, } from "../../data/principals/org
|
|
|
5
5
|
import { principalHistoryEvidenceScopeId } from "../../data/principals/principalHistoryPrefixProtection.js";
|
|
6
6
|
import { loadVerifiedPrincipalHistoryPrefix } from "./principalHistoryRecoveryPrefix.js";
|
|
7
7
|
import { PrincipalPolicyHistoryReadError, } from "./principalHistoryRecoveryTypes.js";
|
|
8
|
+
import { reusePrincipalDiscoveryPage } from "./principalRecoveryDiscoveryPage.js";
|
|
8
9
|
import { recoverPrincipalPolicyHistory } from "./recoverPrincipalPolicyHistory.js";
|
|
9
10
|
export class PrincipalRecoveryDirectoryAdvanced extends Error {
|
|
10
11
|
}
|
|
12
|
+
function exactHead(state) {
|
|
13
|
+
return {
|
|
14
|
+
principalType: state.principalType,
|
|
15
|
+
principalId: state.principalId,
|
|
16
|
+
version: state.version,
|
|
17
|
+
stateHash: state.stateHash,
|
|
18
|
+
keyEpoch: state.keyEpoch,
|
|
19
|
+
keyFingerprint: state.keyFingerprint,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
11
22
|
/** An unverified discovery read chooses a pin; recovery must authenticate it. */
|
|
12
23
|
async function discoverDirectoryHead(input) {
|
|
13
24
|
assertProjectionVerificationCurrent(() => !input.signal?.aborted && input.stillCurrent());
|
|
@@ -39,7 +50,11 @@ async function discoverDirectoryHead(input) {
|
|
|
39
50
|
});
|
|
40
51
|
if (!selected.ok)
|
|
41
52
|
throw selected.error;
|
|
42
|
-
return {
|
|
53
|
+
return {
|
|
54
|
+
head: prefix.head,
|
|
55
|
+
genesis: genesis.reference,
|
|
56
|
+
apiClient: input.apiClient,
|
|
57
|
+
};
|
|
43
58
|
}
|
|
44
59
|
for await (const result of input.apiClient.getPrincipalPolicyPages("organization", input.organizationId, { signal: input.signal })) {
|
|
45
60
|
if (!result.ok)
|
|
@@ -52,6 +67,7 @@ async function discoverDirectoryHead(input) {
|
|
|
52
67
|
first.principalId !== input.organizationId)
|
|
53
68
|
throw new KeyingVerificationError("missing_dependency", "Organization directory discovery requires genesis");
|
|
54
69
|
return {
|
|
70
|
+
apiClient: reusePrincipalDiscoveryPage(input.apiClient, result),
|
|
55
71
|
genesis: {
|
|
56
72
|
principalType: first.principalType,
|
|
57
73
|
principalId: first.principalId,
|
|
@@ -72,7 +88,7 @@ async function discoverDirectoryHead(input) {
|
|
|
72
88
|
}
|
|
73
89
|
throw new KeyingVerificationError("missing_dependency", "Organization directory head is unavailable");
|
|
74
90
|
}
|
|
75
|
-
export async function recoverPolicyDirectory(input, references) {
|
|
91
|
+
export async function recoverPolicyDirectory(input, references, selected) {
|
|
76
92
|
const scoped = {
|
|
77
93
|
...input,
|
|
78
94
|
protection: {
|
|
@@ -83,15 +99,24 @@ export async function recoverPolicyDirectory(input, references) {
|
|
|
83
99
|
]),
|
|
84
100
|
},
|
|
85
101
|
};
|
|
86
|
-
const { head: expectedHead, genesis } =
|
|
102
|
+
const { head: expectedHead, genesis, apiClient, } = selected
|
|
103
|
+
? {
|
|
104
|
+
head: exactHead(selected.policy.state),
|
|
105
|
+
genesis: selected.policy.retainedHistory[0]?.state,
|
|
106
|
+
apiClient: input.apiClient,
|
|
107
|
+
}
|
|
108
|
+
: await discoverDirectoryHead(scoped);
|
|
109
|
+
if (genesis?.version !== 1)
|
|
110
|
+
throw new KeyingVerificationError("missing_dependency", "Organization directory recovery requires verified genesis");
|
|
87
111
|
if (references.some((reference) => reference.version > expectedHead.version))
|
|
88
112
|
throw new PrincipalRecoveryDirectoryAdvanced();
|
|
89
113
|
const recovered = await recoverPrincipalPolicyHistory({
|
|
90
114
|
...scoped,
|
|
115
|
+
apiClient,
|
|
91
116
|
expectedHead,
|
|
92
117
|
retainedReferences: references.some((reference) => reference.version === 1)
|
|
93
118
|
? references
|
|
94
|
-
: [genesis, ...references],
|
|
119
|
+
: [exactHead(genesis), ...references],
|
|
95
120
|
});
|
|
96
121
|
let descriptor;
|
|
97
122
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"principalRecoveryDirectory.js","sourceRoot":"","sources":["principalRecoveryDirectory.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n KeyingVerificationError,\n type ReferencedPrincipalHead,\n serializeKeyingCanonicalJson,\n verifyPrincipalPolicyHistoryReferences,\n} from \"@tearleads/crypto\";\nimport { assertProjectionVerificationCurrent } from \"../../data/keyingProjectionVerification/types\";\nimport { loadPrincipalHistoryReference } from \"../../data/persistence/principalHistoryEvidencePersistence\";\nimport {\n type OrganizationAuthorityDescriptor,\n parseOrganizationAuthorityDescriptor,\n} from \"../../data/principals/organizationAuthorityDescriptor\";\nimport { principalHistoryEvidenceScopeId } from \"../../data/principals/principalHistoryPrefixProtection\";\nimport { loadVerifiedPrincipalHistoryPrefix } from \"./principalHistoryRecoveryPrefix\";\nimport {\n PrincipalPolicyHistoryReadError,\n type RecoveredPrincipalPolicyHistory,\n type RecoverPrincipalPolicyHistoryOptions,\n} from \"./principalHistoryRecoveryTypes\";\nimport { recoverPrincipalPolicyHistory } from \"./recoverPrincipalPolicyHistory\";\n\nexport type PrincipalRecoveryContext = Omit<\n RecoverPrincipalPolicyHistoryOptions,\n | \"expectedHead\"\n | \"retainedReferences\"\n | \"historyVerification\"\n | \"loadExternalAuthority\"\n>;\n\nexport interface RecoveredPolicyDirectory\n extends RecoveredPrincipalPolicyHistory {\n readonly descriptor: OrganizationAuthorityDescriptor;\n}\n\nexport class PrincipalRecoveryDirectoryAdvanced extends Error {}\n\n/** An unverified discovery read chooses a pin; recovery must authenticate it. */\nasync function discoverDirectoryHead(input: PrincipalRecoveryContext): Promise<{\n head: ReferencedPrincipalHead;\n genesis: ReferencedPrincipalHead;\n}> {\n assertProjectionVerificationCurrent(\n () => !input.signal?.aborted && input.stillCurrent(),\n );\n if (input.offline) {\n const principal = {\n principalType: \"organization\" as const,\n principalId: input.organizationId,\n };\n const scopeId = await principalHistoryEvidenceScopeId({\n organizationId: input.organizationId,\n head: principal,\n protection: input.protection,\n });\n const prefix = await loadVerifiedPrincipalHistoryPrefix(\n input,\n principal,\n scopeId,\n );\n if (!prefix)\n throw new KeyingVerificationError(\n \"missing_dependency\",\n \"Organization directory is unavailable offline\",\n );\n const history = prefix.verifier.finish(prefix.head);\n if (!history.ok) throw history.error;\n const genesis = await loadPrincipalHistoryReference({\n execSql: input.execSql,\n scopeId,\n history: history.value,\n version: 1,\n });\n const selected = await verifyPrincipalPolicyHistoryReferences({\n history: history.value,\n references: [genesis],\n });\n if (!selected.ok) throw selected.error;\n return { head: prefix.head, genesis: genesis.reference };\n }\n for await (const result of input.apiClient.getPrincipalPolicyPages(\n \"organization\",\n input.organizationId,\n { signal: input.signal },\n )) {\n if (!result.ok) throw new PrincipalPolicyHistoryReadError(result);\n assertProjectionVerificationCurrent(\n () => !input.signal?.aborted && input.stillCurrent(),\n );\n const state = result.data.currentState;\n const first = result.data.previousStates[0]?.state ?? state;\n if (\n first.version !== 1 ||\n first.principalType !== \"organization\" ||\n first.principalId !== input.organizationId\n )\n throw new KeyingVerificationError(\n \"missing_dependency\",\n \"Organization directory discovery requires genesis\",\n );\n return {\n genesis: {\n principalType: first.principalType,\n principalId: first.principalId,\n version: first.version,\n stateHash: first.stateHash,\n keyEpoch: first.keyEpoch,\n keyFingerprint: first.keyFingerprint,\n },\n head: {\n principalType: \"organization\",\n principalId: input.organizationId,\n version: state.version,\n stateHash: state.stateHash,\n keyEpoch: state.keyEpoch,\n keyFingerprint: state.keyFingerprint,\n },\n };\n }\n throw new KeyingVerificationError(\n \"missing_dependency\",\n \"Organization directory head is unavailable\",\n );\n}\n\nexport async function recoverPolicyDirectory(\n input: PrincipalRecoveryContext,\n references: readonly ReferencedPrincipalHead[],\n): Promise<RecoveredPolicyDirectory> {\n const scoped = {\n ...input,\n protection: {\n localKey: input.protection.localKey,\n context: serializeKeyingCanonicalJson([\n \"tearleads.sdk.principal-history.directory.v1\",\n input.protection.context,\n ]),\n },\n };\n const { head: expectedHead, genesis } = await discoverDirectoryHead(scoped);\n if (references.some((reference) => reference.version > expectedHead.version))\n throw new PrincipalRecoveryDirectoryAdvanced();\n const recovered = await recoverPrincipalPolicyHistory({\n ...scoped,\n expectedHead,\n retainedReferences: references.some((reference) => reference.version === 1)\n ? references\n : [genesis, ...references],\n });\n let descriptor: OrganizationAuthorityDescriptor;\n try {\n descriptor = parseOrganizationAuthorityDescriptor(\n recovered.current.currentPayload.ciphertext,\n );\n } catch {\n throw new KeyingVerificationError(\n \"invalid_shape\",\n \"Organization directory payload is invalid\",\n );\n }\n if (descriptor.organizationId !== input.organizationId)\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"Organization directory scope does not match\",\n );\n return { ...recovered, descriptor };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"principalRecoveryDirectory.js","sourceRoot":"","sources":["principalRecoveryDirectory.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n KeyingVerificationError,\n type ReferencedPrincipalHead,\n serializeKeyingCanonicalJson,\n verifyPrincipalPolicyHistoryReferences,\n} from \"@tearleads/crypto\";\nimport { assertProjectionVerificationCurrent } from \"../../data/keyingProjectionVerification/types\";\nimport { loadPrincipalHistoryReference } from \"../../data/persistence/principalHistoryEvidencePersistence\";\nimport {\n type OrganizationAuthorityDescriptor,\n parseOrganizationAuthorityDescriptor,\n} from \"../../data/principals/organizationAuthorityDescriptor\";\nimport { principalHistoryEvidenceScopeId } from \"../../data/principals/principalHistoryPrefixProtection\";\nimport { loadVerifiedPrincipalHistoryPrefix } from \"./principalHistoryRecoveryPrefix\";\nimport {\n PrincipalPolicyHistoryReadError,\n type RecoveredPrincipalPolicyHistory,\n type RecoverPrincipalPolicyHistoryOptions,\n} from \"./principalHistoryRecoveryTypes\";\nimport { reusePrincipalDiscoveryPage } from \"./principalRecoveryDiscoveryPage\";\nimport { recoverPrincipalPolicyHistory } from \"./recoverPrincipalPolicyHistory\";\n\nexport type PrincipalRecoveryContext = Omit<\n RecoverPrincipalPolicyHistoryOptions,\n | \"expectedHead\"\n | \"retainedReferences\"\n | \"historyVerification\"\n | \"loadExternalAuthority\"\n>;\n\nexport interface RecoveredPolicyDirectory\n extends RecoveredPrincipalPolicyHistory {\n readonly descriptor: OrganizationAuthorityDescriptor;\n}\n\nexport class PrincipalRecoveryDirectoryAdvanced extends Error {}\n\nfunction exactHead(state: ReferencedPrincipalHead): ReferencedPrincipalHead {\n return {\n principalType: state.principalType,\n principalId: state.principalId,\n version: state.version,\n stateHash: state.stateHash,\n keyEpoch: state.keyEpoch,\n keyFingerprint: state.keyFingerprint,\n };\n}\n\n/** An unverified discovery read chooses a pin; recovery must authenticate it. */\nasync function discoverDirectoryHead(input: PrincipalRecoveryContext): Promise<{\n head: ReferencedPrincipalHead;\n genesis: ReferencedPrincipalHead;\n apiClient: PrincipalRecoveryContext[\"apiClient\"];\n}> {\n assertProjectionVerificationCurrent(\n () => !input.signal?.aborted && input.stillCurrent(),\n );\n if (input.offline) {\n const principal = {\n principalType: \"organization\" as const,\n principalId: input.organizationId,\n };\n const scopeId = await principalHistoryEvidenceScopeId({\n organizationId: input.organizationId,\n head: principal,\n protection: input.protection,\n });\n const prefix = await loadVerifiedPrincipalHistoryPrefix(\n input,\n principal,\n scopeId,\n );\n if (!prefix)\n throw new KeyingVerificationError(\n \"missing_dependency\",\n \"Organization directory is unavailable offline\",\n );\n const history = prefix.verifier.finish(prefix.head);\n if (!history.ok) throw history.error;\n const genesis = await loadPrincipalHistoryReference({\n execSql: input.execSql,\n scopeId,\n history: history.value,\n version: 1,\n });\n const selected = await verifyPrincipalPolicyHistoryReferences({\n history: history.value,\n references: [genesis],\n });\n if (!selected.ok) throw selected.error;\n return {\n head: prefix.head,\n genesis: genesis.reference,\n apiClient: input.apiClient,\n };\n }\n for await (const result of input.apiClient.getPrincipalPolicyPages(\n \"organization\",\n input.organizationId,\n { signal: input.signal },\n )) {\n if (!result.ok) throw new PrincipalPolicyHistoryReadError(result);\n assertProjectionVerificationCurrent(\n () => !input.signal?.aborted && input.stillCurrent(),\n );\n const state = result.data.currentState;\n const first = result.data.previousStates[0]?.state ?? state;\n if (\n first.version !== 1 ||\n first.principalType !== \"organization\" ||\n first.principalId !== input.organizationId\n )\n throw new KeyingVerificationError(\n \"missing_dependency\",\n \"Organization directory discovery requires genesis\",\n );\n return {\n apiClient: reusePrincipalDiscoveryPage(input.apiClient, result),\n genesis: {\n principalType: first.principalType,\n principalId: first.principalId,\n version: first.version,\n stateHash: first.stateHash,\n keyEpoch: first.keyEpoch,\n keyFingerprint: first.keyFingerprint,\n },\n head: {\n principalType: \"organization\",\n principalId: input.organizationId,\n version: state.version,\n stateHash: state.stateHash,\n keyEpoch: state.keyEpoch,\n keyFingerprint: state.keyFingerprint,\n },\n };\n }\n throw new KeyingVerificationError(\n \"missing_dependency\",\n \"Organization directory head is unavailable\",\n );\n}\n\nexport async function recoverPolicyDirectory(\n input: PrincipalRecoveryContext,\n references: readonly ReferencedPrincipalHead[],\n selected?: RecoveredPolicyDirectory,\n): Promise<RecoveredPolicyDirectory> {\n const scoped = {\n ...input,\n protection: {\n localKey: input.protection.localKey,\n context: serializeKeyingCanonicalJson([\n \"tearleads.sdk.principal-history.directory.v1\",\n input.protection.context,\n ]),\n },\n };\n const {\n head: expectedHead,\n genesis,\n apiClient,\n } = selected\n ? {\n head: exactHead(selected.policy.state),\n genesis: selected.policy.retainedHistory[0]?.state,\n apiClient: input.apiClient,\n }\n : await discoverDirectoryHead(scoped);\n if (genesis?.version !== 1)\n throw new KeyingVerificationError(\n \"missing_dependency\",\n \"Organization directory recovery requires verified genesis\",\n );\n if (references.some((reference) => reference.version > expectedHead.version))\n throw new PrincipalRecoveryDirectoryAdvanced();\n const recovered = await recoverPrincipalPolicyHistory({\n ...scoped,\n apiClient,\n expectedHead,\n retainedReferences: references.some((reference) => reference.version === 1)\n ? references\n : [exactHead(genesis), ...references],\n });\n let descriptor: OrganizationAuthorityDescriptor;\n try {\n descriptor = parseOrganizationAuthorityDescriptor(\n recovered.current.currentPayload.ciphertext,\n );\n } catch {\n throw new KeyingVerificationError(\n \"invalid_shape\",\n \"Organization directory payload is invalid\",\n );\n }\n if (descriptor.organizationId !== input.organizationId)\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"Organization directory scope does not match\",\n );\n return { ...recovered, descriptor };\n}\n"]}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/** Reuse the discovery bytes as untrusted input to the ordinary verifier. */
|
|
2
|
+
export function reusePrincipalDiscoveryPage(apiClient, discovery) {
|
|
3
|
+
const first = structuredClone(discovery);
|
|
4
|
+
const page = first.data;
|
|
5
|
+
const current = {
|
|
6
|
+
currentState: page.currentState,
|
|
7
|
+
currentPayload: page.currentPayload,
|
|
8
|
+
currentProjection: page.currentProjection,
|
|
9
|
+
currentGrants: page.currentGrants,
|
|
10
|
+
currentMemberEnvelopes: page.currentMemberEnvelopes,
|
|
11
|
+
};
|
|
12
|
+
return {
|
|
13
|
+
async *getPrincipalPolicyPages(principalType, principalId, options = {}) {
|
|
14
|
+
if (options.resume !== undefined ||
|
|
15
|
+
(options.afterVersion ?? 0) !== 0 ||
|
|
16
|
+
options.stateHash !== current.currentState.stateHash ||
|
|
17
|
+
principalType !== current.currentState.principalType ||
|
|
18
|
+
principalId !== current.currentState.principalId) {
|
|
19
|
+
yield* apiClient.getPrincipalPolicyPages(principalType, principalId, options);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
yield structuredClone(first);
|
|
23
|
+
const next = page.historyPage.nextAfterVersion;
|
|
24
|
+
if (next === null)
|
|
25
|
+
return;
|
|
26
|
+
// Resume binds every later page to these exact artifacts, including bytes
|
|
27
|
+
// outside the signed head. The API client's cursor/shape checks still run.
|
|
28
|
+
yield* apiClient.getPrincipalPolicyPages(principalType, principalId, {
|
|
29
|
+
...options,
|
|
30
|
+
afterVersion: undefined,
|
|
31
|
+
resume: { current, afterVersion: next },
|
|
32
|
+
});
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=principalRecoveryDiscoveryPage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"principalRecoveryDiscoveryPage.js","sourceRoot":"","sources":["principalRecoveryDiscoveryPage.ts"],"names":[],"mappings":"AAGA,6EAA6E;AAC7E,MAAM,UAAU,2BAA2B,CACzC,SAAqD,EACrD,SAAsD;IAEtD,MAAM,KAAK,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC;IACzC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;IACxB,MAAM,OAAO,GAAG;QACd,YAAY,EAAE,IAAI,CAAC,YAAY;QAC/B,cAAc,EAAE,IAAI,CAAC,cAAc;QACnC,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;QACzC,aAAa,EAAE,IAAI,CAAC,aAAa;QACjC,sBAAsB,EAAE,IAAI,CAAC,sBAAsB;KACpD,CAAC;IACF,OAAO;QACL,KAAK,CAAC,CAAC,uBAAuB,CAAC,aAAa,EAAE,WAAW,EAAE,OAAO,GAAG,EAAE;YACrE,IACE,OAAO,CAAC,MAAM,KAAK,SAAS;gBAC5B,CAAC,OAAO,CAAC,YAAY,IAAI,CAAC,CAAC,KAAK,CAAC;gBACjC,OAAO,CAAC,SAAS,KAAK,OAAO,CAAC,YAAY,CAAC,SAAS;gBACpD,aAAa,KAAK,OAAO,CAAC,YAAY,CAAC,aAAa;gBACpD,WAAW,KAAK,OAAO,CAAC,YAAY,CAAC,WAAW,EAChD,CAAC;gBACD,KAAK,CAAC,CAAC,SAAS,CAAC,uBAAuB,CACtC,aAAa,EACb,WAAW,EACX,OAAO,CACR,CAAC;gBACF,OAAO;YACT,CAAC;YACD,MAAM,eAAe,CAAC,KAAK,CAAC,CAAC;YAC7B,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,gBAAgB,CAAC;YAC/C,IAAI,IAAI,KAAK,IAAI;gBAAE,OAAO;YAC1B,0EAA0E;YAC1E,2EAA2E;YAC3E,KAAK,CAAC,CAAC,SAAS,CAAC,uBAAuB,CAAC,aAAa,EAAE,WAAW,EAAE;gBACnE,GAAG,OAAO;gBACV,YAAY,EAAE,SAAS;gBACvB,MAAM,EAAE,EAAE,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE;aACxC,CAAC,CAAC;QACL,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["import type { ApiClient, RequestSuccess } from \"@tearleads/api-client\";\nimport type { PrincipalPolicyPageResponse } from \"@tearleads/validators/response\";\n\n/** Reuse the discovery bytes as untrusted input to the ordinary verifier. */\nexport function reusePrincipalDiscoveryPage(\n apiClient: Pick<ApiClient, \"getPrincipalPolicyPages\">,\n discovery: RequestSuccess<PrincipalPolicyPageResponse>,\n): Pick<ApiClient, \"getPrincipalPolicyPages\"> {\n const first = structuredClone(discovery);\n const page = first.data;\n const current = {\n currentState: page.currentState,\n currentPayload: page.currentPayload,\n currentProjection: page.currentProjection,\n currentGrants: page.currentGrants,\n currentMemberEnvelopes: page.currentMemberEnvelopes,\n };\n return {\n async *getPrincipalPolicyPages(principalType, principalId, options = {}) {\n if (\n options.resume !== undefined ||\n (options.afterVersion ?? 0) !== 0 ||\n options.stateHash !== current.currentState.stateHash ||\n principalType !== current.currentState.principalType ||\n principalId !== current.currentState.principalId\n ) {\n yield* apiClient.getPrincipalPolicyPages(\n principalType,\n principalId,\n options,\n );\n return;\n }\n yield structuredClone(first);\n const next = page.historyPage.nextAfterVersion;\n if (next === null) return;\n // Resume binds every later page to these exact artifacts, including bytes\n // outside the signed head. The API client's cursor/shape checks still run.\n yield* apiClient.getPrincipalPolicyPages(principalType, principalId, {\n ...options,\n afterVersion: undefined,\n resume: { current, afterVersion: next },\n });\n },\n };\n}\n"]}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { KeyingVerificationError } from "../../internal/crypto/index.js";
|
|
2
|
+
import { assertProjectionVerificationCurrent } from "../../data/keyingProjectionVerification/types.js";
|
|
3
|
+
import { principalHeadMatchesReference } from "../../data/principals/organizationAuthorityDescriptor.js";
|
|
4
|
+
import { PrincipalHistoryRecoveryRaceError } from "./principalHistoryRecoveryTypes.js";
|
|
5
|
+
import { recoverWithPrincipalOutageFallback } from "./principalRecoveryOutage.js";
|
|
6
|
+
/** Reuse authenticated local artifacts only for the exact current head a caller selected. */
|
|
7
|
+
export async function recoverWithPrincipalLocalPreference(recover, options, preferLocalCurrent) {
|
|
8
|
+
if (preferLocalCurrent && !options.offline) {
|
|
9
|
+
try {
|
|
10
|
+
const local = await recover({
|
|
11
|
+
...options,
|
|
12
|
+
offline: true,
|
|
13
|
+
});
|
|
14
|
+
assertProjectionVerificationCurrent(options.stillCurrent);
|
|
15
|
+
if (principalHeadMatchesReference(local.policy.state, options.reference))
|
|
16
|
+
return local;
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
assertProjectionVerificationCurrent(options.stillCurrent);
|
|
20
|
+
if (!(error instanceof PrincipalHistoryRecoveryRaceError) &&
|
|
21
|
+
!(error instanceof KeyingVerificationError &&
|
|
22
|
+
error.code === "missing_dependency"))
|
|
23
|
+
throw error;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return recoverWithPrincipalOutageFallback(recover, options);
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=principalRecoveryLocalPreference.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"principalRecoveryLocalPreference.js","sourceRoot":"","sources":["principalRecoveryLocalPreference.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,mCAAmC,EAAE,MAAM,+CAA+C,CAAC;AACpG,OAAO,EAAE,6BAA6B,EAAE,MAAM,uDAAuD,CAAC;AACtG,OAAO,EAAE,iCAAiC,EAAE,MAAM,iCAAiC,CAAC;AACpF,OAAO,EAAE,kCAAkC,EAAE,MAAM,2BAA2B,CAAC;AAG/E,6FAA6F;AAC7F,MAAM,CAAC,KAAK,UAAU,mCAAmC,CACvD,OAAmD,EACnD,OAAkE,EAClE,kBAA2B;IAE3B,IAAI,kBAAkB,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QAC3C,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC;gBAC1B,GAAG,OAAO;gBACV,OAAO,EAAE,IAAI;aACd,CAAC,CAAC;YACH,mCAAmC,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;YAC1D,IAAI,6BAA6B,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,SAAS,CAAC;gBACtE,OAAO,KAAK,CAAC;QACjB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,mCAAmC,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;YAC1D,IACE,CAAC,CAAC,KAAK,YAAY,iCAAiC,CAAC;gBACrD,CAAC,CACC,KAAK,YAAY,uBAAuB;oBACxC,KAAK,CAAC,IAAI,KAAK,oBAAoB,CACpC;gBAED,MAAM,KAAK,CAAC;QAChB,CAAC;IACH,CAAC;IACD,OAAO,kCAAkC,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AAC9D,CAAC","sourcesContent":["import { KeyingVerificationError } from \"@tearleads/crypto\";\nimport { assertProjectionVerificationCurrent } from \"../../data/keyingProjectionVerification/types\";\nimport { principalHeadMatchesReference } from \"../../data/principals/organizationAuthorityDescriptor\";\nimport { PrincipalHistoryRecoveryRaceError } from \"./principalHistoryRecoveryTypes\";\nimport { recoverWithPrincipalOutageFallback } from \"./principalRecoveryOutage\";\nimport type { recoverScopedPrincipalPolicyHistory } from \"./recoverScopedPrincipalPolicyHistory\";\n\n/** Reuse authenticated local artifacts only for the exact current head a caller selected. */\nexport async function recoverWithPrincipalLocalPreference(\n recover: typeof recoverScopedPrincipalPolicyHistory,\n options: Parameters<typeof recoverScopedPrincipalPolicyHistory>[0],\n preferLocalCurrent: boolean,\n) {\n if (preferLocalCurrent && !options.offline) {\n try {\n const local = await recover({\n ...options,\n offline: true,\n });\n assertProjectionVerificationCurrent(options.stillCurrent);\n if (principalHeadMatchesReference(local.policy.state, options.reference))\n return local;\n } catch (error) {\n assertProjectionVerificationCurrent(options.stillCurrent);\n if (\n !(error instanceof PrincipalHistoryRecoveryRaceError) &&\n !(\n error instanceof KeyingVerificationError &&\n error.code === \"missing_dependency\"\n )\n )\n throw error;\n }\n }\n return recoverWithPrincipalOutageFallback(recover, options);\n}\n"]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type ReferencedPrincipalHead } from "../../internal/crypto/index.js";
|
|
2
|
+
import type { RecoveredPrincipalPolicyHistory } from "./principalHistoryRecoveryTypes.js";
|
|
3
|
+
import { type PrincipalRecoveryContext, type RecoveredPolicyDirectory } from "./principalRecoveryDirectory.js";
|
|
4
|
+
type Memo<T> = Map<string, Promise<{
|
|
5
|
+
value: T;
|
|
6
|
+
stillCurrent: () => boolean;
|
|
7
|
+
}>>;
|
|
8
|
+
export interface PrincipalRecoveryMemo {
|
|
9
|
+
readonly directories: Memo<RecoveredPolicyDirectory>;
|
|
10
|
+
readonly admins: Memo<RecoveredPrincipalPolicyHistory>;
|
|
11
|
+
}
|
|
12
|
+
export declare function createPrincipalRecoveryReader(input: PrincipalRecoveryContext, memo?: PrincipalRecoveryMemo): {
|
|
13
|
+
directory: (references: readonly ReferencedPrincipalHead[]) => Promise<RecoveredPolicyDirectory>;
|
|
14
|
+
admins: (expectedHead: ReferencedPrincipalHead, retainedReferences?: readonly ReferencedPrincipalHead[]) => Promise<RecoveredPrincipalPolicyHistory>;
|
|
15
|
+
};
|
|
16
|
+
export {};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { serializeKeyingCanonicalJson, } from "../../internal/crypto/index.js";
|
|
1
|
+
import { KeyingVerificationError, serializeKeyingCanonicalJson, } from "../../internal/crypto/index.js";
|
|
2
2
|
import { assertProjectionVerificationCurrent } from "../../data/keyingProjectionVerification/types.js";
|
|
3
|
+
import { principalHeadMatchesReference } from "../../data/principals/organizationAuthorityDescriptor.js";
|
|
3
4
|
import { recoverPolicyDirectory, } from "./principalRecoveryDirectory.js";
|
|
4
5
|
import { recoverPrincipalPolicyHistory } from "./recoverPrincipalPolicyHistory.js";
|
|
5
6
|
/** Only share authenticated results within one projection collection lifetime. */
|
|
@@ -19,28 +20,99 @@ async function memoPrincipalRecovery(memo, key, stillCurrent, work) {
|
|
|
19
20
|
assertProjectionVerificationCurrent(stillCurrent);
|
|
20
21
|
return result.value;
|
|
21
22
|
}
|
|
23
|
+
async function readMemoizedAdmins(input, memo, scope, expectedHead, retainedReferences) {
|
|
24
|
+
// Every recovered Current already retains its own exact head.
|
|
25
|
+
const references = retainedReferences.filter((reference) => !principalHeadMatchesReference(expectedHead, reference));
|
|
26
|
+
const key = (selected) => serializeKeyingCanonicalJson([
|
|
27
|
+
...scope,
|
|
28
|
+
{ ...expectedHead },
|
|
29
|
+
selected.map((reference) => ({ ...reference })),
|
|
30
|
+
]);
|
|
31
|
+
const known = memo?.get(key([]));
|
|
32
|
+
let sourceCurrent = () => true;
|
|
33
|
+
const current = () => !input.signal?.aborted && input.stillCurrent() && sourceCurrent();
|
|
34
|
+
return memoPrincipalRecovery(memo, key(references), current, async () => {
|
|
35
|
+
const options = {
|
|
36
|
+
...input,
|
|
37
|
+
expectedHead,
|
|
38
|
+
retainedReferences,
|
|
39
|
+
historyVerification: "direct-admins",
|
|
40
|
+
stillCurrent: current,
|
|
41
|
+
};
|
|
42
|
+
if (known) {
|
|
43
|
+
sourceCurrent = (await known).stillCurrent;
|
|
44
|
+
assertProjectionVerificationCurrent(current);
|
|
45
|
+
try {
|
|
46
|
+
// A freshly verified exact head only needs local proofs for additional
|
|
47
|
+
// citations; their signature and private-root checks still run.
|
|
48
|
+
return await recoverPrincipalPolicyHistory({
|
|
49
|
+
...options,
|
|
50
|
+
offline: true,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
assertProjectionVerificationCurrent(current);
|
|
55
|
+
if (input.offline ||
|
|
56
|
+
!(error instanceof KeyingVerificationError) ||
|
|
57
|
+
error.code !== "missing_dependency")
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return recoverPrincipalPolicyHistory(options);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
async function readMemoizedDirectory(input, memo, key, references) {
|
|
65
|
+
const known = references.length > 0 ? memo?.get(key([])) : undefined;
|
|
66
|
+
let sourceCurrent = () => true;
|
|
67
|
+
const current = () => !input.signal?.aborted && input.stillCurrent() && sourceCurrent();
|
|
68
|
+
return memoPrincipalRecovery(memo, key(references), current, async () => {
|
|
69
|
+
if (!known)
|
|
70
|
+
return recoverPolicyDirectory(input, references);
|
|
71
|
+
const source = await known;
|
|
72
|
+
sourceCurrent = source.stillCurrent;
|
|
73
|
+
assertProjectionVerificationCurrent(current);
|
|
74
|
+
try {
|
|
75
|
+
// Add authenticated historical citations to this batch's exact directory
|
|
76
|
+
// view. A newer private prefix must not silently replace that view.
|
|
77
|
+
return await recoverPolicyDirectory({ ...input, offline: true, stillCurrent: current }, references, source.value);
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
assertProjectionVerificationCurrent(current);
|
|
81
|
+
if (input.offline ||
|
|
82
|
+
!(error instanceof KeyingVerificationError) ||
|
|
83
|
+
error.code !== "missing_dependency")
|
|
84
|
+
throw error;
|
|
85
|
+
}
|
|
86
|
+
return recoverPolicyDirectory({ ...input, stillCurrent: current }, references, source.value);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
22
89
|
export function createPrincipalRecoveryReader(input, memo) {
|
|
23
90
|
const scope = [
|
|
24
91
|
input.organizationId,
|
|
25
92
|
input.protection.context,
|
|
26
93
|
input.offline === true,
|
|
27
94
|
];
|
|
28
|
-
const
|
|
95
|
+
const directoryKey = (references) => serializeKeyingCanonicalJson([
|
|
96
|
+
...scope,
|
|
97
|
+
references.map((reference) => ({ ...reference })),
|
|
98
|
+
]);
|
|
29
99
|
return {
|
|
30
|
-
directory: (references) =>
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
100
|
+
directory: async (references) => {
|
|
101
|
+
const value = await readMemoizedDirectory(input, memo?.directories, directoryKey, references);
|
|
102
|
+
// Retaining extra citations does not prevent this authenticated directory
|
|
103
|
+
// from satisfying a later read with no selected historical references.
|
|
104
|
+
const unselectedKey = directoryKey([]);
|
|
105
|
+
const selected = memo?.directories.get(directoryKey(references));
|
|
106
|
+
if (memo &&
|
|
107
|
+
selected &&
|
|
108
|
+
references.length > 0 &&
|
|
109
|
+
!memo.directories.has(unselectedKey))
|
|
110
|
+
// Keep the original lease: its expiry requires a new batch, even if
|
|
111
|
+
// a later caller still has a live lease of its own.
|
|
112
|
+
memo.directories.set(unselectedKey, selected);
|
|
113
|
+
return value;
|
|
114
|
+
},
|
|
115
|
+
admins: (expectedHead, retainedReferences = []) => readMemoizedAdmins(input, memo?.admins, scope, expectedHead, retainedReferences),
|
|
44
116
|
};
|
|
45
117
|
}
|
|
46
118
|
//# sourceMappingURL=principalRecoveryMemo.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"principalRecoveryMemo.js","sourceRoot":"","sources":["principalRecoveryMemo.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,4BAA4B,GAC7B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,mCAAmC,EAAE,MAAM,+CAA+C,CAAC;AAEpG,OAAO,EAGL,sBAAsB,GACvB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,6BAA6B,EAAE,MAAM,iCAAiC,CAAC;AAShF,kFAAkF;AAClF,KAAK,UAAU,qBAAqB,CAClC,IAAyB,EACzB,GAAW,EACX,YAA2B,EAC3B,IAAsB;IAEtB,mCAAmC,CAAC,YAAY,CAAC,CAAC;IAClD,IAAI,OAAO,GAAG,IAAI,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;IAC7B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,GAAG,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC;QAC5D,IAAI,EAAE,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC1B,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;QACpD,IAAI,IAAI,EAAE,GAAG,CAAC,GAAG,CAAC,KAAK,OAAO;YAAE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjD,MAAM,KAAK,CAAC;IACd,CAAC,CAAC,CAAC;IACH,mCAAmC,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;IACzD,mCAAmC,CAAC,YAAY,CAAC,CAAC;IAClD,OAAO,MAAM,CAAC,KAAK,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,6BAA6B,CAC3C,KAA+B,EAC/B,IAA4B;IAE5B,MAAM,KAAK,GAAG;QACZ,KAAK,CAAC,cAAc;QACpB,KAAK,CAAC,UAAU,CAAC,OAAO;QACxB,KAAK,CAAC,OAAO,KAAK,IAAI;KACvB,CAAC;IACF,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC;IACrE,OAAO;QACL,SAAS,EAAE,CAAC,UAA8C,EAAE,EAAE,CAC5D,qBAAqB,CACnB,IAAI,EAAE,WAAW,EACjB,4BAA4B,CAAC;YAC3B,GAAG,KAAK;YACR,UAAU,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,SAAS,EAAE,CAAC,CAAC;SAClD,CAAC,EACF,OAAO,EACP,GAAG,EAAE,CAAC,sBAAsB,CAAC,KAAK,EAAE,UAAU,CAAC,CAChD;QACH,MAAM,EAAE,CACN,YAAqC,EACrC,qBAAyD,EAAE,EAC3D,EAAE,CACF,qBAAqB,CACnB,IAAI,EAAE,MAAM,EACZ,4BAA4B,CAAC;YAC3B,GAAG,KAAK;YACR,EAAE,GAAG,YAAY,EAAE;YACnB,kBAAkB,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,SAAS,EAAE,CAAC,CAAC;SAC1D,CAAC,EACF,OAAO,EACP,GAAG,EAAE,CACH,6BAA6B,CAAC;YAC5B,GAAG,KAAK;YACR,YAAY;YACZ,kBAAkB;YAClB,mBAAmB,EAAE,eAAe;SACrC,CAAC,CACL;KACJ,CAAC;AACJ,CAAC","sourcesContent":["import {\n type ReferencedPrincipalHead,\n serializeKeyingCanonicalJson,\n} from \"@tearleads/crypto\";\nimport { assertProjectionVerificationCurrent } from \"../../data/keyingProjectionVerification/types\";\nimport type { RecoveredPrincipalPolicyHistory } from \"./principalHistoryRecoveryTypes\";\nimport {\n type PrincipalRecoveryContext,\n type RecoveredPolicyDirectory,\n recoverPolicyDirectory,\n} from \"./principalRecoveryDirectory\";\nimport { recoverPrincipalPolicyHistory } from \"./recoverPrincipalPolicyHistory\";\n\ntype Memo<T> = Map<string, Promise<{ value: T; stillCurrent: () => boolean }>>;\n\nexport interface PrincipalRecoveryMemo {\n readonly directories: Memo<RecoveredPolicyDirectory>;\n readonly admins: Memo<RecoveredPrincipalPolicyHistory>;\n}\n\n/** Only share authenticated results within one projection collection lifetime. */\nasync function memoPrincipalRecovery<T>(\n memo: Memo<T> | undefined,\n key: string,\n stillCurrent: () => boolean,\n work: () => Promise<T>,\n): Promise<T> {\n assertProjectionVerificationCurrent(stillCurrent);\n let pending = memo?.get(key);\n if (!pending) {\n pending = work().then((value) => ({ value, stillCurrent }));\n memo?.set(key, pending);\n }\n const result = await pending.catch((error: unknown) => {\n if (memo?.get(key) === pending) memo.delete(key);\n throw error;\n });\n assertProjectionVerificationCurrent(result.stillCurrent);\n assertProjectionVerificationCurrent(stillCurrent);\n return result.value;\n}\n\nexport function createPrincipalRecoveryReader(\n input: PrincipalRecoveryContext,\n memo?: PrincipalRecoveryMemo,\n) {\n const scope = [\n input.organizationId,\n input.protection.context,\n input.offline === true,\n ];\n const current = () => !input.signal?.aborted && input.stillCurrent();\n return {\n directory: (references: readonly ReferencedPrincipalHead[]) =>\n memoPrincipalRecovery(\n memo?.directories,\n serializeKeyingCanonicalJson([\n ...scope,\n references.map((reference) => ({ ...reference })),\n ]),\n current,\n () => recoverPolicyDirectory(input, references),\n ),\n admins: (\n expectedHead: ReferencedPrincipalHead,\n retainedReferences: readonly ReferencedPrincipalHead[] = [],\n ) =>\n memoPrincipalRecovery(\n memo?.admins,\n serializeKeyingCanonicalJson([\n ...scope,\n { ...expectedHead },\n retainedReferences.map((reference) => ({ ...reference })),\n ]),\n current,\n () =>\n recoverPrincipalPolicyHistory({\n ...input,\n expectedHead,\n retainedReferences,\n historyVerification: \"direct-admins\",\n }),\n ),\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"principalRecoveryMemo.js","sourceRoot":"","sources":["principalRecoveryMemo.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n KeyingVerificationError,\n type ReferencedPrincipalHead,\n serializeKeyingCanonicalJson,\n} from \"@tearleads/crypto\";\nimport { assertProjectionVerificationCurrent } from \"../../data/keyingProjectionVerification/types\";\nimport { principalHeadMatchesReference } from \"../../data/principals/organizationAuthorityDescriptor\";\nimport type { RecoveredPrincipalPolicyHistory } from \"./principalHistoryRecoveryTypes\";\nimport {\n type PrincipalRecoveryContext,\n type RecoveredPolicyDirectory,\n recoverPolicyDirectory,\n} from \"./principalRecoveryDirectory\";\nimport { recoverPrincipalPolicyHistory } from \"./recoverPrincipalPolicyHistory\";\n\ntype Memo<T> = Map<string, Promise<{ value: T; stillCurrent: () => boolean }>>;\n\nexport interface PrincipalRecoveryMemo {\n readonly directories: Memo<RecoveredPolicyDirectory>;\n readonly admins: Memo<RecoveredPrincipalPolicyHistory>;\n}\n\n/** Only share authenticated results within one projection collection lifetime. */\nasync function memoPrincipalRecovery<T>(\n memo: Memo<T> | undefined,\n key: string,\n stillCurrent: () => boolean,\n work: () => Promise<T>,\n): Promise<T> {\n assertProjectionVerificationCurrent(stillCurrent);\n let pending = memo?.get(key);\n if (!pending) {\n pending = work().then((value) => ({ value, stillCurrent }));\n memo?.set(key, pending);\n }\n const result = await pending.catch((error: unknown) => {\n if (memo?.get(key) === pending) memo.delete(key);\n throw error;\n });\n assertProjectionVerificationCurrent(result.stillCurrent);\n assertProjectionVerificationCurrent(stillCurrent);\n return result.value;\n}\n\nasync function readMemoizedAdmins(\n input: PrincipalRecoveryContext,\n memo: Memo<RecoveredPrincipalPolicyHistory> | undefined,\n scope: readonly (string | boolean)[],\n expectedHead: ReferencedPrincipalHead,\n retainedReferences: readonly ReferencedPrincipalHead[],\n) {\n // Every recovered Current already retains its own exact head.\n const references = retainedReferences.filter(\n (reference) => !principalHeadMatchesReference(expectedHead, reference),\n );\n const key = (selected: readonly ReferencedPrincipalHead[]) =>\n serializeKeyingCanonicalJson([\n ...scope,\n { ...expectedHead },\n selected.map((reference) => ({ ...reference })),\n ]);\n const known = memo?.get(key([]));\n let sourceCurrent = () => true;\n const current = () =>\n !input.signal?.aborted && input.stillCurrent() && sourceCurrent();\n return memoPrincipalRecovery(memo, key(references), current, async () => {\n const options = {\n ...input,\n expectedHead,\n retainedReferences,\n historyVerification: \"direct-admins\" as const,\n stillCurrent: current,\n };\n if (known) {\n sourceCurrent = (await known).stillCurrent;\n assertProjectionVerificationCurrent(current);\n try {\n // A freshly verified exact head only needs local proofs for additional\n // citations; their signature and private-root checks still run.\n return await recoverPrincipalPolicyHistory({\n ...options,\n offline: true,\n });\n } catch (error) {\n assertProjectionVerificationCurrent(current);\n if (\n input.offline ||\n !(error instanceof KeyingVerificationError) ||\n error.code !== \"missing_dependency\"\n )\n throw error;\n }\n }\n return recoverPrincipalPolicyHistory(options);\n });\n}\n\nasync function readMemoizedDirectory(\n input: PrincipalRecoveryContext,\n memo: Memo<RecoveredPolicyDirectory> | undefined,\n key: (references: readonly ReferencedPrincipalHead[]) => string,\n references: readonly ReferencedPrincipalHead[],\n) {\n const known = references.length > 0 ? memo?.get(key([])) : undefined;\n let sourceCurrent = () => true;\n const current = () =>\n !input.signal?.aborted && input.stillCurrent() && sourceCurrent();\n return memoPrincipalRecovery(memo, key(references), current, async () => {\n if (!known) return recoverPolicyDirectory(input, references);\n const source = await known;\n sourceCurrent = source.stillCurrent;\n assertProjectionVerificationCurrent(current);\n try {\n // Add authenticated historical citations to this batch's exact directory\n // view. A newer private prefix must not silently replace that view.\n return await recoverPolicyDirectory(\n { ...input, offline: true, stillCurrent: current },\n references,\n source.value,\n );\n } catch (error) {\n assertProjectionVerificationCurrent(current);\n if (\n input.offline ||\n !(error instanceof KeyingVerificationError) ||\n error.code !== \"missing_dependency\"\n )\n throw error;\n }\n return recoverPolicyDirectory(\n { ...input, stillCurrent: current },\n references,\n source.value,\n );\n });\n}\n\nexport function createPrincipalRecoveryReader(\n input: PrincipalRecoveryContext,\n memo?: PrincipalRecoveryMemo,\n) {\n const scope = [\n input.organizationId,\n input.protection.context,\n input.offline === true,\n ];\n const directoryKey = (references: readonly ReferencedPrincipalHead[]) =>\n serializeKeyingCanonicalJson([\n ...scope,\n references.map((reference) => ({ ...reference })),\n ]);\n return {\n directory: async (references: readonly ReferencedPrincipalHead[]) => {\n const value = await readMemoizedDirectory(\n input,\n memo?.directories,\n directoryKey,\n references,\n );\n // Retaining extra citations does not prevent this authenticated directory\n // from satisfying a later read with no selected historical references.\n const unselectedKey = directoryKey([]);\n const selected = memo?.directories.get(directoryKey(references));\n if (\n memo &&\n selected &&\n references.length > 0 &&\n !memo.directories.has(unselectedKey)\n )\n // Keep the original lease: its expiry requires a new batch, even if\n // a later caller still has a live lease of its own.\n memo.directories.set(unselectedKey, selected);\n return value;\n },\n admins: (\n expectedHead: ReferencedPrincipalHead,\n retainedReferences: readonly ReferencedPrincipalHead[] = [],\n ) =>\n readMemoizedAdmins(\n input,\n memo?.admins,\n scope,\n expectedHead,\n retainedReferences,\n ),\n };\n}\n"]}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { assertProjectionVerificationCurrent } from "../../data/keyingProjectionVerification/types.js";
|
|
2
|
+
import { ownPrincipalHistoryProtection } from "../../data/principals/principalHistoryProtection.js";
|
|
3
|
+
import { createPrincipalRecoveryReader, } from "./principalRecoveryMemo.js";
|
|
4
|
+
import { isPrincipalRecoveryOutage } from "./principalRecoveryOutage.js";
|
|
5
|
+
/** Discover and verify current directory artifacts, including protected offline recovery. */
|
|
6
|
+
export async function recoverCurrentOrganizationPolicy(options, memo) {
|
|
7
|
+
const input = {
|
|
8
|
+
...options,
|
|
9
|
+
protection: ownPrincipalHistoryProtection(options.protection),
|
|
10
|
+
};
|
|
11
|
+
try {
|
|
12
|
+
let directory;
|
|
13
|
+
try {
|
|
14
|
+
directory = await createPrincipalRecoveryReader(input, memo).directory([]);
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
assertProjectionVerificationCurrent(input.stillCurrent);
|
|
18
|
+
if (input.offline || !isPrincipalRecoveryOutage(error))
|
|
19
|
+
throw error;
|
|
20
|
+
directory = await createPrincipalRecoveryReader({ ...input, offline: true }, memo).directory([]);
|
|
21
|
+
}
|
|
22
|
+
assertProjectionVerificationCurrent(input.stillCurrent);
|
|
23
|
+
return {
|
|
24
|
+
current: directory.current,
|
|
25
|
+
policy: directory.policy,
|
|
26
|
+
dependencies: [],
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
finally {
|
|
30
|
+
input.protection.localKey.fill(0);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=recoverCurrentOrganizationPolicy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recoverCurrentOrganizationPolicy.js","sourceRoot":"","sources":["recoverCurrentOrganizationPolicy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mCAAmC,EAAE,MAAM,+CAA+C,CAAC;AACpG,OAAO,EAAE,6BAA6B,EAAE,MAAM,kDAAkD,CAAC;AAKjG,OAAO,EACL,6BAA6B,GAE9B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AAEtE,6FAA6F;AAC7F,MAAM,CAAC,KAAK,UAAU,gCAAgC,CACpD,OAAiC,EACjC,IAA4B;IAE5B,MAAM,KAAK,GAAG;QACZ,GAAG,OAAO;QACV,UAAU,EAAE,6BAA6B,CAAC,OAAO,CAAC,UAAU,CAAC;KAC9D,CAAC;IACF,IAAI,CAAC;QACH,IAAI,SAA6D,CAAC;QAClE,IAAI,CAAC;YACH,SAAS,GAAG,MAAM,6BAA6B,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,SAAS,CACpE,EAAE,CACH,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,mCAAmC,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;YACxD,IAAI,KAAK,CAAC,OAAO,IAAI,CAAC,yBAAyB,CAAC,KAAK,CAAC;gBAAE,MAAM,KAAK,CAAC;YACpE,SAAS,GAAG,MAAM,6BAA6B,CAC7C,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,EAC3B,IAAI,CACL,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QAClB,CAAC;QACD,mCAAmC,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QACxD,OAAO;YACL,OAAO,EAAE,SAAS,CAAC,OAAO;YAC1B,MAAM,EAAE,SAAS,CAAC,MAAM;YACxB,YAAY,EAAE,EAAE;SACjB,CAAC;IACJ,CAAC;YAAS,CAAC;QACT,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpC,CAAC;AACH,CAAC","sourcesContent":["import { assertProjectionVerificationCurrent } from \"../../data/keyingProjectionVerification/types\";\nimport { ownPrincipalHistoryProtection } from \"../../data/principals/principalHistoryProtection\";\nimport type {\n PrincipalRecoveryContext,\n recoverPolicyDirectory,\n} from \"./principalRecoveryDirectory\";\nimport {\n createPrincipalRecoveryReader,\n type PrincipalRecoveryMemo,\n} from \"./principalRecoveryMemo\";\nimport { isPrincipalRecoveryOutage } from \"./principalRecoveryOutage\";\n\n/** Discover and verify current directory artifacts, including protected offline recovery. */\nexport async function recoverCurrentOrganizationPolicy(\n options: PrincipalRecoveryContext,\n memo?: PrincipalRecoveryMemo,\n) {\n const input = {\n ...options,\n protection: ownPrincipalHistoryProtection(options.protection),\n };\n try {\n let directory: Awaited<ReturnType<typeof recoverPolicyDirectory>>;\n try {\n directory = await createPrincipalRecoveryReader(input, memo).directory(\n [],\n );\n } catch (error) {\n assertProjectionVerificationCurrent(input.stillCurrent);\n if (input.offline || !isPrincipalRecoveryOutage(error)) throw error;\n directory = await createPrincipalRecoveryReader(\n { ...input, offline: true },\n memo,\n ).directory([]);\n }\n assertProjectionVerificationCurrent(input.stillCurrent);\n return {\n current: directory.current,\n policy: directory.policy,\n dependencies: [],\n };\n } finally {\n input.protection.localKey.fill(0);\n }\n}\n"]}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type ReferencedPrincipalHead, type VerifiedPrincipalPolicyCurrent } from "../../internal/crypto/index.js";
|
|
2
2
|
import { type RecoveredPrincipalPolicyHistory } from "./principalHistoryRecoveryTypes.js";
|
|
3
3
|
import { type PrincipalRecoveryContext } from "./principalRecoveryDirectory.js";
|
|
4
|
+
import { type PrincipalRecoveryMemo } from "./principalRecoveryMemo.js";
|
|
4
5
|
export interface RecoverScopedPrincipalPolicyHistoryOptions extends PrincipalRecoveryContext {
|
|
5
6
|
readonly reference: ReferencedPrincipalHead;
|
|
6
7
|
}
|
|
@@ -10,4 +11,4 @@ export interface RecoveredScopedPrincipalPolicyHistory extends RecoveredPrincipa
|
|
|
10
11
|
}
|
|
11
12
|
export declare function recoverScopedPrincipalPolicyHistory(options: RecoverScopedPrincipalPolicyHistoryOptions): Promise<RecoveredScopedPrincipalPolicyHistory>;
|
|
12
13
|
/** Internal runtime batch: shared results never outlive one caller's collection. */
|
|
13
|
-
export declare function createScopedPrincipalPolicyHistoryBatch(): typeof recoverScopedPrincipalPolicyHistory;
|
|
14
|
+
export declare function createScopedPrincipalPolicyHistoryBatch(memo?: PrincipalRecoveryMemo): typeof recoverScopedPrincipalPolicyHistory;
|
|
@@ -73,16 +73,15 @@ async function recoverScopedPolicy(input, memo) {
|
|
|
73
73
|
})),
|
|
74
74
|
};
|
|
75
75
|
};
|
|
76
|
-
const recovered =
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
});
|
|
76
|
+
const recovered = isAdmins
|
|
77
|
+
? await read.admins(expectedHead, [input.reference])
|
|
78
|
+
: await recoverPrincipalPolicyHistory({
|
|
79
|
+
...input,
|
|
80
|
+
expectedHead,
|
|
81
|
+
retainedReferences: [input.reference],
|
|
82
|
+
protection: scopedGroupProtection(input, adminHead),
|
|
83
|
+
loadExternalAuthority,
|
|
84
|
+
});
|
|
86
85
|
return {
|
|
87
86
|
...recovered,
|
|
88
87
|
dependencies: admins ? [directory.policy, admins] : [directory.policy],
|
|
@@ -137,11 +136,10 @@ export function recoverScopedPrincipalPolicyHistory(options) {
|
|
|
137
136
|
return recoverScopedPrincipalPolicyHistoryInBatch(options);
|
|
138
137
|
}
|
|
139
138
|
/** Internal runtime batch: shared results never outlive one caller's collection. */
|
|
140
|
-
export function createScopedPrincipalPolicyHistoryBatch(
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
};
|
|
139
|
+
export function createScopedPrincipalPolicyHistoryBatch(memo = {
|
|
140
|
+
directories: new Map(),
|
|
141
|
+
admins: new Map(),
|
|
142
|
+
}) {
|
|
145
143
|
return (options) => recoverScopedPrincipalPolicyHistoryInBatch(options, memo);
|
|
146
144
|
}
|
|
147
145
|
//# sourceMappingURL=recoverScopedPrincipalPolicyHistory.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recoverScopedPrincipalPolicyHistory.js","sourceRoot":"","sources":["recoverScopedPrincipalPolicyHistory.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n createPrincipalPolicyHistoryVerifier,\n KeyingVerificationError,\n type PrincipalPolicyExternalAuthority,\n type ReferencedPrincipalHead,\n serializeKeyingCanonicalJson,\n type VerifiedPrincipalPolicyCurrent,\n} from \"@tearleads/crypto\";\nimport { assertProjectionVerificationCurrent } from \"../../data/keyingProjectionVerification/types\";\nimport { ownPrincipalHistoryProtection } from \"../../data/principals/principalHistoryProtection\";\nimport {\n PrincipalHistoryRecoveryRaceError,\n type RecoveredPrincipalPolicyHistory,\n} from \"./principalHistoryRecoveryTypes\";\nimport {\n type PrincipalRecoveryContext,\n PrincipalRecoveryDirectoryAdvanced,\n type RecoveredPolicyDirectory,\n} from \"./principalRecoveryDirectory\";\nimport {\n createPrincipalRecoveryReader,\n type PrincipalRecoveryMemo,\n} from \"./principalRecoveryMemo\";\nimport { recoverPrincipalPolicyHistory } from \"./recoverPrincipalPolicyHistory\";\n\nexport interface RecoverScopedPrincipalPolicyHistoryOptions\n extends PrincipalRecoveryContext {\n readonly reference: ReferencedPrincipalHead;\n}\n\nexport interface RecoveredScopedPrincipalPolicyHistory\n extends RecoveredPrincipalPolicyHistory {\n /** Submit these with policy when atomically admitting its organization scope. */\n readonly dependencies: readonly VerifiedPrincipalPolicyCurrent[];\n}\n\nfunction groupHead(directory: RecoveredPolicyDirectory, principalId: string) {\n const head = directory.descriptor.groupHeads.find(\n (entry) => entry.principalId === principalId,\n );\n if (!head)\n throw new KeyingVerificationError(\n \"missing_dependency\",\n \"Group is absent from the signed organization directory\",\n );\n return head;\n}\n\nfunction authorityHead(state: ReferencedPrincipalHead) {\n return {\n principalType: \"group\" as const,\n principalId: state.principalId,\n version: state.version,\n stateHash: state.stateHash,\n keyEpoch: state.keyEpoch,\n keyFingerprint: state.keyFingerprint,\n };\n}\n\nfunction scopedGroupProtection(\n input: RecoverScopedPrincipalPolicyHistoryOptions,\n adminHead: ReferencedPrincipalHead,\n) {\n return {\n localKey: input.protection.localKey,\n context: serializeKeyingCanonicalJson([\n \"tearleads.sdk.principal-history.scoped-group.v1\",\n input.protection.context,\n input.organizationId,\n adminHead.principalId,\n ]),\n };\n}\n\nasync function recoverScopedPolicy(\n input: RecoverScopedPrincipalPolicyHistoryOptions,\n memo?: PrincipalRecoveryMemo,\n): Promise<RecoveredScopedPrincipalPolicyHistory> {\n if (\n input.reference.principalType === \"organization\" &&\n input.reference.principalId !== input.organizationId\n )\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"Requested organization policy is outside its scope\",\n );\n const read = createPrincipalRecoveryReader(input, memo);\n const directory = await read.directory(\n input.reference.principalType === \"organization\" ? [input.reference] : [],\n );\n if (input.reference.principalType === \"organization\")\n return {\n current: directory.current,\n policy: directory.policy,\n dependencies: [],\n };\n const expectedHead = groupHead(directory, input.reference.principalId);\n if (input.reference.version > expectedHead.version)\n throw new PrincipalRecoveryDirectoryAdvanced();\n const adminHead = groupHead(directory, directory.descriptor.adminGroupId);\n const isAdmins = expectedHead.principalId === adminHead.principalId;\n let admins: VerifiedPrincipalPolicyCurrent | null = null;\n if (!isAdmins) {\n admins = (await read.admins(adminHead)).policy;\n }\n const loadExternalAuthority = async (\n citations: readonly ReferencedPrincipalHead[],\n ): Promise<PrincipalPolicyExternalAuthority | undefined> => {\n const references = new Map<string, ReferencedPrincipalHead>();\n for (const citation of citations) {\n if (citation.principalId !== adminHead.principalId)\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"Group cites another organization's Admins authority\",\n );\n if (citation.version > adminHead.version)\n throw new PrincipalRecoveryDirectoryAdvanced();\n references.set(`${citation.version}:${citation.stateHash}`, citation);\n }\n if (!references.size) return undefined;\n const recovered = await read.admins(adminHead, [...references.values()]);\n return {\n currentHead: adminHead,\n states: recovered.policy.retainedHistory.map(({ state, projection }) => ({\n head: authorityHead(state),\n projection,\n })),\n };\n };\n const recovered = await recoverPrincipalPolicyHistory({\n ...input,\n expectedHead,\n retainedReferences: [input.reference],\n historyVerification: isAdmins ? \"direct-admins\" : \"standard\",\n ...(isAdmins\n ? {}\n : { protection: scopedGroupProtection(input, adminHead) }),\n ...(isAdmins ? {} : { loadExternalAuthority }),\n });\n return {\n ...recovered,\n dependencies: admins ? [directory.policy, admins] : [directory.policy],\n };\n}\n\n/** Recover signed directory and strict Admins dependencies without full histories. */\nasync function recoverScopedPrincipalPolicyHistoryInBatch(\n options: RecoverScopedPrincipalPolicyHistoryOptions,\n memo?: PrincipalRecoveryMemo,\n): Promise<RecoveredScopedPrincipalPolicyHistory> {\n if (options.offline !== undefined && typeof options.offline !== \"boolean\")\n throw new KeyingVerificationError(\n \"invalid_shape\",\n \"Invalid principal history transport mode\",\n );\n if (!options.organizationId)\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"Principal recovery requires an organization scope\",\n );\n const input = {\n apiClient: options.apiClient,\n execSql: options.execSql,\n organizationId: options.organizationId,\n offline: options.offline,\n resolveTrustedUserIdentity: options.resolveTrustedUserIdentity,\n signal: options.signal,\n stillCurrent: options.stillCurrent,\n reference: structuredClone(options.reference),\n protection: ownPrincipalHistoryProtection(options.protection),\n };\n try {\n // Reject malformed exact citations before any discovery or disposable writes.\n createPrincipalPolicyHistoryVerifier({\n principalId: input.reference.principalId,\n principalType: input.reference.principalType,\n retainedReferences: [input.reference],\n });\n for (let attempt = 0; attempt < 2; attempt += 1) {\n try {\n const recovered = await recoverScopedPolicy(input, memo);\n assertProjectionVerificationCurrent(\n () => !input.signal?.aborted && input.stillCurrent(),\n );\n return recovered;\n } catch (error) {\n if (!(error instanceof PrincipalRecoveryDirectoryAdvanced)) throw error;\n memo?.directories.clear();\n memo?.admins.clear();\n if (input.offline)\n throw new KeyingVerificationError(\n \"missing_dependency\",\n \"Requested principal evidence is newer than the offline directory\",\n );\n }\n }\n throw new PrincipalHistoryRecoveryRaceError(\n \"Organization directory remains behind the requested policy evidence\",\n );\n } finally {\n input.protection.localKey.fill(0);\n }\n}\n\nexport function recoverScopedPrincipalPolicyHistory(\n options: RecoverScopedPrincipalPolicyHistoryOptions,\n): Promise<RecoveredScopedPrincipalPolicyHistory> {\n return recoverScopedPrincipalPolicyHistoryInBatch(options);\n}\n\n/** Internal runtime batch: shared results never outlive one caller's collection. */\nexport function createScopedPrincipalPolicyHistoryBatch(): typeof recoverScopedPrincipalPolicyHistory {\n const memo: PrincipalRecoveryMemo = {\n directories: new Map(),\n admins: new Map(),\n };\n return (options) => recoverScopedPrincipalPolicyHistoryInBatch(options, memo);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"recoverScopedPrincipalPolicyHistory.js","sourceRoot":"","sources":["recoverScopedPrincipalPolicyHistory.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oCAAoC,EACpC,uBAAuB,EAGvB,4BAA4B,GAE7B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,mCAAmC,EAAE,MAAM,+CAA+C,CAAC;AACpG,OAAO,EAAE,6BAA6B,EAAE,MAAM,kDAAkD,CAAC;AACjG,OAAO,EACL,iCAAiC,GAElC,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAEL,kCAAkC,GAEnC,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,6BAA6B,GAE9B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,6BAA6B,EAAE,MAAM,iCAAiC,CAAC;AAahF,SAAS,SAAS,CAAC,SAAmC,EAAE,WAAmB;IACzE,MAAM,IAAI,GAAG,SAAS,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,CAC/C,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,WAAW,KAAK,WAAW,CAC7C,CAAC;IACF,IAAI,CAAC,IAAI;QACP,MAAM,IAAI,uBAAuB,CAC/B,oBAAoB,EACpB,wDAAwD,CACzD,CAAC;IACJ,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,aAAa,CAAC,KAA8B;IACnD,OAAO;QACL,aAAa,EAAE,OAAgB;QAC/B,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,cAAc,EAAE,KAAK,CAAC,cAAc;KACrC,CAAC;AACJ,CAAC;AAED,SAAS,qBAAqB,CAC5B,KAAiD,EACjD,SAAkC;IAElC,OAAO;QACL,QAAQ,EAAE,KAAK,CAAC,UAAU,CAAC,QAAQ;QACnC,OAAO,EAAE,4BAA4B,CAAC;YACpC,iDAAiD;YACjD,KAAK,CAAC,UAAU,CAAC,OAAO;YACxB,KAAK,CAAC,cAAc;YACpB,SAAS,CAAC,WAAW;SACtB,CAAC;KACH,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,mBAAmB,CAChC,KAAiD,EACjD,IAA4B;IAE5B,IACE,KAAK,CAAC,SAAS,CAAC,aAAa,KAAK,cAAc;QAChD,KAAK,CAAC,SAAS,CAAC,WAAW,KAAK,KAAK,CAAC,cAAc;QAEpD,MAAM,IAAI,uBAAuB,CAC/B,iBAAiB,EACjB,oDAAoD,CACrD,CAAC;IACJ,MAAM,IAAI,GAAG,6BAA6B,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACxD,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,SAAS,CACpC,KAAK,CAAC,SAAS,CAAC,aAAa,KAAK,cAAc,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAC1E,CAAC;IACF,IAAI,KAAK,CAAC,SAAS,CAAC,aAAa,KAAK,cAAc;QAClD,OAAO;YACL,OAAO,EAAE,SAAS,CAAC,OAAO;YAC1B,MAAM,EAAE,SAAS,CAAC,MAAM;YACxB,YAAY,EAAE,EAAE;SACjB,CAAC;IACJ,MAAM,YAAY,GAAG,SAAS,CAAC,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IACvE,IAAI,KAAK,CAAC,SAAS,CAAC,OAAO,GAAG,YAAY,CAAC,OAAO;QAChD,MAAM,IAAI,kCAAkC,EAAE,CAAC;IACjD,MAAM,SAAS,GAAG,SAAS,CAAC,SAAS,EAAE,SAAS,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;IAC1E,MAAM,QAAQ,GAAG,YAAY,CAAC,WAAW,KAAK,SAAS,CAAC,WAAW,CAAC;IACpE,IAAI,MAAM,GAA0C,IAAI,CAAC;IACzD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,GAAG,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC;IACjD,CAAC;IACD,MAAM,qBAAqB,GAAG,KAAK,EACjC,SAA6C,EACU,EAAE;QACzD,MAAM,UAAU,GAAG,IAAI,GAAG,EAAmC,CAAC;QAC9D,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;YACjC,IAAI,QAAQ,CAAC,WAAW,KAAK,SAAS,CAAC,WAAW;gBAChD,MAAM,IAAI,uBAAuB,CAC/B,iBAAiB,EACjB,qDAAqD,CACtD,CAAC;YACJ,IAAI,QAAQ,CAAC,OAAO,GAAG,SAAS,CAAC,OAAO;gBACtC,MAAM,IAAI,kCAAkC,EAAE,CAAC;YACjD,UAAU,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,OAAO,IAAI,QAAQ,CAAC,SAAS,EAAE,EAAE,QAAQ,CAAC,CAAC;QACxE,CAAC;QACD,IAAI,CAAC,UAAU,CAAC,IAAI;YAAE,OAAO,SAAS,CAAC;QACvC,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QACzE,OAAO;YACL,WAAW,EAAE,SAAS;YACtB,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,CAAC;gBACvE,IAAI,EAAE,aAAa,CAAC,KAAK,CAAC;gBAC1B,UAAU;aACX,CAAC,CAAC;SACJ,CAAC;IACJ,CAAC,CAAC;IACF,MAAM,SAAS,GAAG,QAAQ;QACxB,CAAC,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QACpD,CAAC,CAAC,MAAM,6BAA6B,CAAC;YAClC,GAAG,KAAK;YACR,YAAY;YACZ,kBAAkB,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC;YACrC,UAAU,EAAE,qBAAqB,CAAC,KAAK,EAAE,SAAS,CAAC;YACnD,qBAAqB;SACtB,CAAC,CAAC;IACP,OAAO;QACL,GAAG,SAAS;QACZ,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC;KACvE,CAAC;AACJ,CAAC;AAED,sFAAsF;AACtF,KAAK,UAAU,0CAA0C,CACvD,OAAmD,EACnD,IAA4B;IAE5B,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS,IAAI,OAAO,OAAO,CAAC,OAAO,KAAK,SAAS;QACvE,MAAM,IAAI,uBAAuB,CAC/B,eAAe,EACf,0CAA0C,CAC3C,CAAC;IACJ,IAAI,CAAC,OAAO,CAAC,cAAc;QACzB,MAAM,IAAI,uBAAuB,CAC/B,iBAAiB,EACjB,mDAAmD,CACpD,CAAC;IACJ,MAAM,KAAK,GAAG;QACZ,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,cAAc,EAAE,OAAO,CAAC,cAAc;QACtC,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,0BAA0B,EAAE,OAAO,CAAC,0BAA0B;QAC9D,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,SAAS,EAAE,eAAe,CAAC,OAAO,CAAC,SAAS,CAAC;QAC7C,UAAU,EAAE,6BAA6B,CAAC,OAAO,CAAC,UAAU,CAAC;KAC9D,CAAC;IACF,IAAI,CAAC;QACH,8EAA8E;QAC9E,oCAAoC,CAAC;YACnC,WAAW,EAAE,KAAK,CAAC,SAAS,CAAC,WAAW;YACxC,aAAa,EAAE,KAAK,CAAC,SAAS,CAAC,aAAa;YAC5C,kBAAkB,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC;SACtC,CAAC,CAAC;QACH,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,CAAC,EAAE,CAAC;YAChD,IAAI,CAAC;gBACH,MAAM,SAAS,GAAG,MAAM,mBAAmB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;gBACzD,mCAAmC,CACjC,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,IAAI,KAAK,CAAC,YAAY,EAAE,CACrD,CAAC;gBACF,OAAO,SAAS,CAAC;YACnB,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,CAAC,CAAC,KAAK,YAAY,kCAAkC,CAAC;oBAAE,MAAM,KAAK,CAAC;gBACxE,IAAI,EAAE,WAAW,CAAC,KAAK,EAAE,CAAC;gBAC1B,IAAI,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC;gBACrB,IAAI,KAAK,CAAC,OAAO;oBACf,MAAM,IAAI,uBAAuB,CAC/B,oBAAoB,EACpB,kEAAkE,CACnE,CAAC;YACN,CAAC;QACH,CAAC;QACD,MAAM,IAAI,iCAAiC,CACzC,qEAAqE,CACtE,CAAC;IACJ,CAAC;YAAS,CAAC;QACT,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,mCAAmC,CACjD,OAAmD;IAEnD,OAAO,0CAA0C,CAAC,OAAO,CAAC,CAAC;AAC7D,CAAC;AAED,oFAAoF;AACpF,MAAM,UAAU,uCAAuC,CACrD,OAA8B;IAC5B,WAAW,EAAE,IAAI,GAAG,EAAE;IACtB,MAAM,EAAE,IAAI,GAAG,EAAE;CAClB;IAED,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,0CAA0C,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;AAChF,CAAC","sourcesContent":["import {\n createPrincipalPolicyHistoryVerifier,\n KeyingVerificationError,\n type PrincipalPolicyExternalAuthority,\n type ReferencedPrincipalHead,\n serializeKeyingCanonicalJson,\n type VerifiedPrincipalPolicyCurrent,\n} from \"@tearleads/crypto\";\nimport { assertProjectionVerificationCurrent } from \"../../data/keyingProjectionVerification/types\";\nimport { ownPrincipalHistoryProtection } from \"../../data/principals/principalHistoryProtection\";\nimport {\n PrincipalHistoryRecoveryRaceError,\n type RecoveredPrincipalPolicyHistory,\n} from \"./principalHistoryRecoveryTypes\";\nimport {\n type PrincipalRecoveryContext,\n PrincipalRecoveryDirectoryAdvanced,\n type RecoveredPolicyDirectory,\n} from \"./principalRecoveryDirectory\";\nimport {\n createPrincipalRecoveryReader,\n type PrincipalRecoveryMemo,\n} from \"./principalRecoveryMemo\";\nimport { recoverPrincipalPolicyHistory } from \"./recoverPrincipalPolicyHistory\";\n\nexport interface RecoverScopedPrincipalPolicyHistoryOptions\n extends PrincipalRecoveryContext {\n readonly reference: ReferencedPrincipalHead;\n}\n\nexport interface RecoveredScopedPrincipalPolicyHistory\n extends RecoveredPrincipalPolicyHistory {\n /** Submit these with policy when atomically admitting its organization scope. */\n readonly dependencies: readonly VerifiedPrincipalPolicyCurrent[];\n}\n\nfunction groupHead(directory: RecoveredPolicyDirectory, principalId: string) {\n const head = directory.descriptor.groupHeads.find(\n (entry) => entry.principalId === principalId,\n );\n if (!head)\n throw new KeyingVerificationError(\n \"missing_dependency\",\n \"Group is absent from the signed organization directory\",\n );\n return head;\n}\n\nfunction authorityHead(state: ReferencedPrincipalHead) {\n return {\n principalType: \"group\" as const,\n principalId: state.principalId,\n version: state.version,\n stateHash: state.stateHash,\n keyEpoch: state.keyEpoch,\n keyFingerprint: state.keyFingerprint,\n };\n}\n\nfunction scopedGroupProtection(\n input: RecoverScopedPrincipalPolicyHistoryOptions,\n adminHead: ReferencedPrincipalHead,\n) {\n return {\n localKey: input.protection.localKey,\n context: serializeKeyingCanonicalJson([\n \"tearleads.sdk.principal-history.scoped-group.v1\",\n input.protection.context,\n input.organizationId,\n adminHead.principalId,\n ]),\n };\n}\n\nasync function recoverScopedPolicy(\n input: RecoverScopedPrincipalPolicyHistoryOptions,\n memo?: PrincipalRecoveryMemo,\n): Promise<RecoveredScopedPrincipalPolicyHistory> {\n if (\n input.reference.principalType === \"organization\" &&\n input.reference.principalId !== input.organizationId\n )\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"Requested organization policy is outside its scope\",\n );\n const read = createPrincipalRecoveryReader(input, memo);\n const directory = await read.directory(\n input.reference.principalType === \"organization\" ? [input.reference] : [],\n );\n if (input.reference.principalType === \"organization\")\n return {\n current: directory.current,\n policy: directory.policy,\n dependencies: [],\n };\n const expectedHead = groupHead(directory, input.reference.principalId);\n if (input.reference.version > expectedHead.version)\n throw new PrincipalRecoveryDirectoryAdvanced();\n const adminHead = groupHead(directory, directory.descriptor.adminGroupId);\n const isAdmins = expectedHead.principalId === adminHead.principalId;\n let admins: VerifiedPrincipalPolicyCurrent | null = null;\n if (!isAdmins) {\n admins = (await read.admins(adminHead)).policy;\n }\n const loadExternalAuthority = async (\n citations: readonly ReferencedPrincipalHead[],\n ): Promise<PrincipalPolicyExternalAuthority | undefined> => {\n const references = new Map<string, ReferencedPrincipalHead>();\n for (const citation of citations) {\n if (citation.principalId !== adminHead.principalId)\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"Group cites another organization's Admins authority\",\n );\n if (citation.version > adminHead.version)\n throw new PrincipalRecoveryDirectoryAdvanced();\n references.set(`${citation.version}:${citation.stateHash}`, citation);\n }\n if (!references.size) return undefined;\n const recovered = await read.admins(adminHead, [...references.values()]);\n return {\n currentHead: adminHead,\n states: recovered.policy.retainedHistory.map(({ state, projection }) => ({\n head: authorityHead(state),\n projection,\n })),\n };\n };\n const recovered = isAdmins\n ? await read.admins(expectedHead, [input.reference])\n : await recoverPrincipalPolicyHistory({\n ...input,\n expectedHead,\n retainedReferences: [input.reference],\n protection: scopedGroupProtection(input, adminHead),\n loadExternalAuthority,\n });\n return {\n ...recovered,\n dependencies: admins ? [directory.policy, admins] : [directory.policy],\n };\n}\n\n/** Recover signed directory and strict Admins dependencies without full histories. */\nasync function recoverScopedPrincipalPolicyHistoryInBatch(\n options: RecoverScopedPrincipalPolicyHistoryOptions,\n memo?: PrincipalRecoveryMemo,\n): Promise<RecoveredScopedPrincipalPolicyHistory> {\n if (options.offline !== undefined && typeof options.offline !== \"boolean\")\n throw new KeyingVerificationError(\n \"invalid_shape\",\n \"Invalid principal history transport mode\",\n );\n if (!options.organizationId)\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"Principal recovery requires an organization scope\",\n );\n const input = {\n apiClient: options.apiClient,\n execSql: options.execSql,\n organizationId: options.organizationId,\n offline: options.offline,\n resolveTrustedUserIdentity: options.resolveTrustedUserIdentity,\n signal: options.signal,\n stillCurrent: options.stillCurrent,\n reference: structuredClone(options.reference),\n protection: ownPrincipalHistoryProtection(options.protection),\n };\n try {\n // Reject malformed exact citations before any discovery or disposable writes.\n createPrincipalPolicyHistoryVerifier({\n principalId: input.reference.principalId,\n principalType: input.reference.principalType,\n retainedReferences: [input.reference],\n });\n for (let attempt = 0; attempt < 2; attempt += 1) {\n try {\n const recovered = await recoverScopedPolicy(input, memo);\n assertProjectionVerificationCurrent(\n () => !input.signal?.aborted && input.stillCurrent(),\n );\n return recovered;\n } catch (error) {\n if (!(error instanceof PrincipalRecoveryDirectoryAdvanced)) throw error;\n memo?.directories.clear();\n memo?.admins.clear();\n if (input.offline)\n throw new KeyingVerificationError(\n \"missing_dependency\",\n \"Requested principal evidence is newer than the offline directory\",\n );\n }\n }\n throw new PrincipalHistoryRecoveryRaceError(\n \"Organization directory remains behind the requested policy evidence\",\n );\n } finally {\n input.protection.localKey.fill(0);\n }\n}\n\nexport function recoverScopedPrincipalPolicyHistory(\n options: RecoverScopedPrincipalPolicyHistoryOptions,\n): Promise<RecoveredScopedPrincipalPolicyHistory> {\n return recoverScopedPrincipalPolicyHistoryInBatch(options);\n}\n\n/** Internal runtime batch: shared results never outlive one caller's collection. */\nexport function createScopedPrincipalPolicyHistoryBatch(\n memo: PrincipalRecoveryMemo = {\n directories: new Map(),\n admins: new Map(),\n },\n): typeof recoverScopedPrincipalPolicyHistory {\n return (options) => recoverScopedPrincipalPolicyHistoryInBatch(options, memo);\n}\n"]}
|