@tearleads/client-sdk 0.1.115 → 0.1.116
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/containerContents/documentDiscovery.js +5 -3
- package/client/containerContents/documentDiscovery.js.map +1 -1
- package/internal/api-client/ApiClient.d.ts +118 -0
- package/internal/api-client/ApiClient.js +4 -0
- package/internal/api-client/ApiClient.js.map +1 -1
- package/internal/api-client/index.d.ts +1 -1
- package/internal/api-client/index.js.map +1 -1
- package/internal/api-client/principalPolicyPages.d.ts +15 -1
- package/internal/api-client/principalPolicyPages.js +48 -2
- package/internal/api-client/principalPolicyPages.js.map +1 -1
- package/internal/api-client/principalPolicyRequests.d.ts +118 -1
- package/internal/api-client/principalPolicyRequests.js +4 -1
- package/internal/api-client/principalPolicyRequests.js.map +1 -1
- package/internal/validators/operation/principalPolicyPageQuery.d.ts +9 -0
- package/internal/validators/operation/principalPolicyPageQuery.js +10 -0
- package/internal/validators/operation/principalPolicyPageQuery.js.map +1 -1
- package/internal/validators/operation/principals.d.ts +37 -4
- package/internal/validators/operation/principals.js +5 -3
- package/internal/validators/operation/principals.js.map +1 -1
- package/internal/validators/response/index.d.ts +1 -1
- package/internal/validators/response/index.js +1 -1
- package/internal/validators/response/index.js.map +1 -1
- package/internal/validators/response/principalPolicyPage.d.ts +497 -1
- package/internal/validators/response/principalPolicyPage.js +18 -0
- package/internal/validators/response/principalPolicyPage.js.map +1 -1
- package/package.json +1 -1
- package/workflows/container-contents/documentLinks/index.d.ts +4 -0
- package/workflows/container-contents/documentLinks/index.js +10 -3
- package/workflows/container-contents/documentLinks/index.js.map +1 -1
- package/workflows/container-contents/remoteHydration/remoteContainers/remoteContainerPageHydration.js +7 -2
- package/workflows/container-contents/remoteHydration/remoteContainers/remoteContainerPageHydration.js.map +1 -1
- package/workflows/container-contents/tombstones/documentTombstoneEvidence.js +6 -5
- package/workflows/container-contents/tombstones/documentTombstoneEvidence.js.map +1 -1
- package/workflows/principals/principalPolicyHistoryReader.d.ts +6 -1
- package/workflows/principals/principalPolicyHistoryReader.js +4 -1
- package/workflows/principals/principalPolicyHistoryReader.js.map +1 -1
- package/workflows/principals/recoveryOperation/principalRecoveryDirectory.js +108 -59
- package/workflows/principals/recoveryOperation/principalRecoveryDirectory.js.map +1 -1
- package/workflows/principals/runtimePolicyRecovery.js +26 -14
- package/workflows/principals/runtimePolicyRecovery.js.map +1 -1
- package/workflows/principals/runtimePolicyWarmer.d.ts +26 -0
- package/workflows/principals/runtimePolicyWarmer.js +8 -5
- package/workflows/principals/runtimePolicyWarmer.js.map +1 -1
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { KeyingVerificationError, verifyPrincipalPolicyHistoryReferences, } from "../../../internal/crypto/index.js";
|
|
2
|
+
import { isPrincipalPolicyPageResponse, isPrincipalPolicyUnchangedResponse, } from "../../../internal/validators/response/index.js";
|
|
2
3
|
import { assertProjectionVerificationCurrent } from "../../../data/keyingProjectionVerification/types.js";
|
|
3
4
|
import { loadPrincipalHistoryReference } from "../../../data/persistence/principalHistory/principalHistoryEvidencePersistence.js";
|
|
4
|
-
import { parseOrganizationAuthorityDescriptor, } from "../../../data/principals/organizationAuthorityDescriptor.js";
|
|
5
|
+
import { parseOrganizationAuthorityDescriptor, principalHeadMatchesReference, } from "../../../data/principals/organizationAuthorityDescriptor.js";
|
|
5
6
|
import { principalHistoryEvidenceScopeId } from "../../../data/principals/principalHistoryPrefixProtection.js";
|
|
6
7
|
import { directoryHistoryProtection } from "../../../data/principals/principalHistoryScopeProtection.js";
|
|
7
8
|
import { loadVerifiedPrincipalHistoryPrefix } from "../historyRecovery/principalHistoryRecoveryPrefix.js";
|
|
@@ -20,72 +21,120 @@ function exactHead(state) {
|
|
|
20
21
|
keyFingerprint: state.keyFingerprint,
|
|
21
22
|
};
|
|
22
23
|
}
|
|
23
|
-
|
|
24
|
-
async function discoverDirectoryHead(input) {
|
|
24
|
+
function assertDiscoveryCurrent(input) {
|
|
25
25
|
assertProjectionVerificationCurrent(() => !input.signal?.aborted && input.stillCurrent());
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The directory head and genesis this device has completely authenticated,
|
|
29
|
+
* from its protected verified prefix, or null when it holds none.
|
|
30
|
+
*/
|
|
31
|
+
async function loadHeldDirectoryHead(input) {
|
|
32
|
+
const principal = {
|
|
33
|
+
principalType: "organization",
|
|
34
|
+
principalId: input.organizationId,
|
|
35
|
+
};
|
|
36
|
+
const scopeId = await principalHistoryEvidenceScopeId({
|
|
37
|
+
organizationId: input.organizationId,
|
|
38
|
+
head: principal,
|
|
39
|
+
protection: input.protection,
|
|
40
|
+
});
|
|
41
|
+
const prefix = await loadVerifiedPrincipalHistoryPrefix(input, principal, scopeId);
|
|
42
|
+
if (!prefix)
|
|
43
|
+
return null;
|
|
44
|
+
const history = prefix.verifier.finish(prefix.head);
|
|
45
|
+
if (!history.ok)
|
|
46
|
+
throw history.error;
|
|
47
|
+
const genesis = await loadPrincipalHistoryReference({
|
|
48
|
+
execSql: input.execSql,
|
|
49
|
+
scopeId,
|
|
50
|
+
history: history.value,
|
|
51
|
+
version: 1,
|
|
52
|
+
});
|
|
53
|
+
const selected = await verifyPrincipalPolicyHistoryReferences({
|
|
54
|
+
history: history.value,
|
|
55
|
+
references: [genesis],
|
|
56
|
+
});
|
|
57
|
+
if (!selected.ok)
|
|
58
|
+
throw selected.error;
|
|
59
|
+
return { head: exactHead(prefix.head), genesis: genesis.reference };
|
|
60
|
+
}
|
|
61
|
+
/** Disposable local evidence never refuses an online discovery; it reads fully. */
|
|
62
|
+
async function loadHeldDirectoryHeadOnline(input) {
|
|
63
|
+
try {
|
|
64
|
+
return await loadHeldDirectoryHead(input);
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
assertDiscoveryCurrent(input);
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function discoveredPage(input, result) {
|
|
72
|
+
const state = result.data.currentState;
|
|
73
|
+
const first = result.data.previousStates[0]?.state ?? state;
|
|
74
|
+
if (first.version !== 1 ||
|
|
75
|
+
first.principalType !== "organization" ||
|
|
76
|
+
first.principalId !== input.organizationId)
|
|
77
|
+
throw new KeyingVerificationError("missing_dependency", "Organization directory discovery requires genesis");
|
|
78
|
+
return {
|
|
79
|
+
historyReader: reusePrincipalDiscoveryPage(input.historyReader, result),
|
|
80
|
+
genesis: exactHead(first),
|
|
81
|
+
// The requested identity, never the page's: discovery picks only a pin.
|
|
82
|
+
head: {
|
|
28
83
|
principalType: "organization",
|
|
29
84
|
principalId: input.organizationId,
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
85
|
+
version: state.version,
|
|
86
|
+
stateHash: state.stateHash,
|
|
87
|
+
keyEpoch: state.keyEpoch,
|
|
88
|
+
keyFingerprint: state.keyFingerprint,
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Ask whether the held head is still live. An `unchanged` reply naming exactly
|
|
94
|
+
* that head reuses it; recovery then authenticates the held artifacts again
|
|
95
|
+
* and reloads the checkpoint. Any other reply that is not a page leaves the
|
|
96
|
+
* caller to read the first page unconditionally.
|
|
97
|
+
*/
|
|
98
|
+
async function discoverConditionally(input, discover) {
|
|
99
|
+
const held = await loadHeldDirectoryHeadOnline(input);
|
|
100
|
+
assertDiscoveryCurrent(input);
|
|
101
|
+
const result = await discover("organization", input.organizationId, {
|
|
102
|
+
signal: input.signal,
|
|
103
|
+
ifHead: held?.head,
|
|
104
|
+
});
|
|
105
|
+
if (!result.ok)
|
|
106
|
+
throw new PrincipalPolicyHistoryReadError(result);
|
|
107
|
+
assertDiscoveryCurrent(input);
|
|
108
|
+
const reply = result.data;
|
|
109
|
+
if (isPrincipalPolicyUnchangedResponse(reply))
|
|
110
|
+
return held && principalHeadMatchesReference(reply.head, held.head)
|
|
111
|
+
? { ...held, historyReader: input.historyReader }
|
|
112
|
+
: null;
|
|
113
|
+
// Anything but the strict bare head must be a page; otherwise read again.
|
|
114
|
+
return isPrincipalPolicyPageResponse(reply)
|
|
115
|
+
? discoveredPage(input, { ok: true, data: reply })
|
|
116
|
+
: null;
|
|
117
|
+
}
|
|
118
|
+
/** An unverified discovery read chooses a pin; recovery must authenticate it. */
|
|
119
|
+
async function discoverDirectoryHead(input) {
|
|
120
|
+
assertDiscoveryCurrent(input);
|
|
121
|
+
if (input.offline) {
|
|
122
|
+
const held = await loadHeldDirectoryHead(input);
|
|
123
|
+
if (!held)
|
|
38
124
|
throw new KeyingVerificationError("missing_dependency", "Organization directory is unavailable offline");
|
|
39
|
-
|
|
40
|
-
if (!history.ok)
|
|
41
|
-
throw history.error;
|
|
42
|
-
const genesis = await loadPrincipalHistoryReference({
|
|
43
|
-
execSql: input.execSql,
|
|
44
|
-
scopeId,
|
|
45
|
-
history: history.value,
|
|
46
|
-
version: 1,
|
|
47
|
-
});
|
|
48
|
-
const selected = await verifyPrincipalPolicyHistoryReferences({
|
|
49
|
-
history: history.value,
|
|
50
|
-
references: [genesis],
|
|
51
|
-
});
|
|
52
|
-
if (!selected.ok)
|
|
53
|
-
throw selected.error;
|
|
54
|
-
return {
|
|
55
|
-
head: prefix.head,
|
|
56
|
-
genesis: genesis.reference,
|
|
57
|
-
historyReader: input.historyReader,
|
|
58
|
-
};
|
|
125
|
+
return { ...held, historyReader: input.historyReader };
|
|
59
126
|
}
|
|
127
|
+
const discover = input.historyReader.getPrincipalPolicyDiscovery;
|
|
128
|
+
const conditional = discover
|
|
129
|
+
? await discoverConditionally(input, discover)
|
|
130
|
+
: null;
|
|
131
|
+
if (conditional)
|
|
132
|
+
return conditional;
|
|
60
133
|
for await (const result of input.historyReader.getPrincipalPolicyPages("organization", input.organizationId, { signal: input.signal })) {
|
|
61
134
|
if (!result.ok)
|
|
62
135
|
throw new PrincipalPolicyHistoryReadError(result);
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const first = result.data.previousStates[0]?.state ?? state;
|
|
66
|
-
if (first.version !== 1 ||
|
|
67
|
-
first.principalType !== "organization" ||
|
|
68
|
-
first.principalId !== input.organizationId)
|
|
69
|
-
throw new KeyingVerificationError("missing_dependency", "Organization directory discovery requires genesis");
|
|
70
|
-
return {
|
|
71
|
-
historyReader: reusePrincipalDiscoveryPage(input.historyReader, result),
|
|
72
|
-
genesis: {
|
|
73
|
-
principalType: first.principalType,
|
|
74
|
-
principalId: first.principalId,
|
|
75
|
-
version: first.version,
|
|
76
|
-
stateHash: first.stateHash,
|
|
77
|
-
keyEpoch: first.keyEpoch,
|
|
78
|
-
keyFingerprint: first.keyFingerprint,
|
|
79
|
-
},
|
|
80
|
-
head: {
|
|
81
|
-
principalType: "organization",
|
|
82
|
-
principalId: input.organizationId,
|
|
83
|
-
version: state.version,
|
|
84
|
-
stateHash: state.stateHash,
|
|
85
|
-
keyEpoch: state.keyEpoch,
|
|
86
|
-
keyFingerprint: state.keyFingerprint,
|
|
87
|
-
},
|
|
88
|
-
};
|
|
136
|
+
assertDiscoveryCurrent(input);
|
|
137
|
+
return discoveredPage(input, result);
|
|
89
138
|
}
|
|
90
139
|
throw new KeyingVerificationError("missing_dependency", "Organization directory head is unavailable");
|
|
91
140
|
}
|
|
@@ -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 verifyPrincipalPolicyHistoryReferences,\n} from \"@tearleads/crypto\";\nimport { assertProjectionVerificationCurrent } from \"../../../data/keyingProjectionVerification/types\";\nimport { loadPrincipalHistoryReference } from \"../../../data/persistence/principalHistory/principalHistoryEvidencePersistence\";\nimport {\n type OrganizationAuthorityDescriptor,\n parseOrganizationAuthorityDescriptor,\n} from \"../../../data/principals/organizationAuthorityDescriptor\";\nimport { principalHistoryEvidenceScopeId } from \"../../../data/principals/principalHistoryPrefixProtection\";\nimport { directoryHistoryProtection } from \"../../../data/principals/principalHistoryScopeProtection\";\nimport { loadVerifiedPrincipalHistoryPrefix } from \"../historyRecovery/principalHistoryRecoveryPrefix\";\nimport {\n PrincipalPolicyHistoryReadError,\n type RecoveredPrincipalPolicyHistory,\n type RecoverPrincipalPolicyHistoryOptions,\n} from \"../historyRecovery/principalHistoryRecoveryTypes\";\nimport { recoverPrincipalPolicyHistory } from \"../historyRecovery/recoverPrincipalPolicyHistory\";\nimport { reusePrincipalDiscoveryPage } from \"./principalRecoveryDiscoveryPage\";\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 historyReader: PrincipalRecoveryContext[\"historyReader\"];\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 historyReader: input.historyReader,\n };\n }\n for await (const result of input.historyReader.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 historyReader: reusePrincipalDiscoveryPage(input.historyReader, 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: directoryHistoryProtection(input.protection),\n };\n const {\n head: expectedHead,\n genesis,\n historyReader,\n } = selected\n ? {\n head: exactHead(selected.policy.state),\n genesis: selected.policy.retainedHistory[0]?.state,\n historyReader: input.historyReader,\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 historyReader,\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"]}
|
|
1
|
+
{"version":3,"file":"principalRecoveryDirectory.js","sourceRoot":"","sources":["principalRecoveryDirectory.ts"],"names":[],"mappings":"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","sourcesContent":["import type { RequestSuccess } from \"@tearleads/api-client\";\nimport {\n KeyingVerificationError,\n type ReferencedPrincipalHead,\n verifyPrincipalPolicyHistoryReferences,\n} from \"@tearleads/crypto\";\nimport {\n isPrincipalPolicyPageResponse,\n isPrincipalPolicyUnchangedResponse,\n type PrincipalPolicyPageResponse,\n} from \"@tearleads/validators/response\";\nimport { assertProjectionVerificationCurrent } from \"../../../data/keyingProjectionVerification/types\";\nimport { loadPrincipalHistoryReference } from \"../../../data/persistence/principalHistory/principalHistoryEvidencePersistence\";\nimport {\n type OrganizationAuthorityDescriptor,\n parseOrganizationAuthorityDescriptor,\n principalHeadMatchesReference,\n} from \"../../../data/principals/organizationAuthorityDescriptor\";\nimport { principalHistoryEvidenceScopeId } from \"../../../data/principals/principalHistoryPrefixProtection\";\nimport { directoryHistoryProtection } from \"../../../data/principals/principalHistoryScopeProtection\";\nimport { loadVerifiedPrincipalHistoryPrefix } from \"../historyRecovery/principalHistoryRecoveryPrefix\";\nimport {\n PrincipalPolicyHistoryReadError,\n type RecoveredPrincipalPolicyHistory,\n type RecoverPrincipalPolicyHistoryOptions,\n} from \"../historyRecovery/principalHistoryRecoveryTypes\";\nimport { recoverPrincipalPolicyHistory } from \"../historyRecovery/recoverPrincipalPolicyHistory\";\nimport { reusePrincipalDiscoveryPage } from \"./principalRecoveryDiscoveryPage\";\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\ninterface DiscoveredDirectoryHead {\n readonly head: ReferencedPrincipalHead;\n readonly genesis: ReferencedPrincipalHead;\n readonly historyReader: PrincipalRecoveryContext[\"historyReader\"];\n}\n\nfunction assertDiscoveryCurrent(input: PrincipalRecoveryContext): void {\n assertProjectionVerificationCurrent(\n () => !input.signal?.aborted && input.stillCurrent(),\n );\n}\n\n/**\n * The directory head and genesis this device has completely authenticated,\n * from its protected verified prefix, or null when it holds none.\n */\nasync function loadHeldDirectoryHead(\n input: PrincipalRecoveryContext,\n): Promise<Omit<DiscoveredDirectoryHead, \"historyReader\"> | null> {\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) return null;\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: exactHead(prefix.head), genesis: genesis.reference };\n}\n\n/** Disposable local evidence never refuses an online discovery; it reads fully. */\nasync function loadHeldDirectoryHeadOnline(input: PrincipalRecoveryContext) {\n try {\n return await loadHeldDirectoryHead(input);\n } catch {\n assertDiscoveryCurrent(input);\n return null;\n }\n}\n\nfunction discoveredPage(\n input: PrincipalRecoveryContext,\n result: RequestSuccess<PrincipalPolicyPageResponse>,\n): DiscoveredDirectoryHead {\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 historyReader: reusePrincipalDiscoveryPage(input.historyReader, result),\n genesis: exactHead(first),\n // The requested identity, never the page's: discovery picks only a pin.\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\n/**\n * Ask whether the held head is still live. An `unchanged` reply naming exactly\n * that head reuses it; recovery then authenticates the held artifacts again\n * and reloads the checkpoint. Any other reply that is not a page leaves the\n * caller to read the first page unconditionally.\n */\nasync function discoverConditionally(\n input: PrincipalRecoveryContext,\n discover: NonNullable<\n PrincipalRecoveryContext[\"historyReader\"][\"getPrincipalPolicyDiscovery\"]\n >,\n): Promise<DiscoveredDirectoryHead | null> {\n const held = await loadHeldDirectoryHeadOnline(input);\n assertDiscoveryCurrent(input);\n const result = await discover(\"organization\", input.organizationId, {\n signal: input.signal,\n ifHead: held?.head,\n });\n if (!result.ok) throw new PrincipalPolicyHistoryReadError(result);\n assertDiscoveryCurrent(input);\n const reply = result.data;\n if (isPrincipalPolicyUnchangedResponse(reply))\n return held && principalHeadMatchesReference(reply.head, held.head)\n ? { ...held, historyReader: input.historyReader }\n : null;\n // Anything but the strict bare head must be a page; otherwise read again.\n return isPrincipalPolicyPageResponse(reply)\n ? discoveredPage(input, { ok: true, data: reply })\n : null;\n}\n\n/** An unverified discovery read chooses a pin; recovery must authenticate it. */\nasync function discoverDirectoryHead(\n input: PrincipalRecoveryContext,\n): Promise<DiscoveredDirectoryHead> {\n assertDiscoveryCurrent(input);\n if (input.offline) {\n const held = await loadHeldDirectoryHead(input);\n if (!held)\n throw new KeyingVerificationError(\n \"missing_dependency\",\n \"Organization directory is unavailable offline\",\n );\n return { ...held, historyReader: input.historyReader };\n }\n const discover = input.historyReader.getPrincipalPolicyDiscovery;\n const conditional = discover\n ? await discoverConditionally(input, discover)\n : null;\n if (conditional) return conditional;\n for await (const result of input.historyReader.getPrincipalPolicyPages(\n \"organization\",\n input.organizationId,\n { signal: input.signal },\n )) {\n if (!result.ok) throw new PrincipalPolicyHistoryReadError(result);\n assertDiscoveryCurrent(input);\n return discoveredPage(input, result);\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: directoryHistoryProtection(input.protection),\n };\n const {\n head: expectedHead,\n genesis,\n historyReader,\n } = selected\n ? {\n head: exactHead(selected.policy.state),\n genesis: selected.policy.retainedHistory[0]?.state,\n historyReader: input.historyReader,\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 historyReader,\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"]}
|
|
@@ -3,7 +3,7 @@ import { ProjectionDependencyUnavailableError } from "../../data/keyingProjectio
|
|
|
3
3
|
import { runWithSecurityIncidentReporting } from "../../data/keyingProjectionVerification/error.js";
|
|
4
4
|
import { assertProjectionVerificationCurrent, } from "../../data/keyingProjectionVerification/types.js";
|
|
5
5
|
import { readPrincipalHistoryProtection } from "../../data/principals/principalHistoryRuntime.js";
|
|
6
|
-
import { getOrCreatePrincipalPolicyCoordinator } from "../../data/principals/principalPolicyCoordinator.js";
|
|
6
|
+
import { getOrCreatePrincipalPolicyCoordinator, } from "../../data/principals/principalPolicyCoordinator.js";
|
|
7
7
|
import { PrincipalHistoryRecoveryRaceError, PrincipalPolicyHistoryReadError, } from "./historyRecovery/principalHistoryRecoveryTypes.js";
|
|
8
8
|
import { apiPrincipalPolicyPageReader, } from "./principalPolicyHistoryReader.js";
|
|
9
9
|
import { createPrincipalCurrentRecoveryBatch } from "./recoveryOperation/principalCurrentRecoveryBatch.js";
|
|
@@ -16,6 +16,28 @@ export function createRuntimePrincipalPolicyResolver(runtime, options = {}) {
|
|
|
16
16
|
? (input) => resolve({ ...input, preferLocalCurrent: options.preferLocalCurrent })
|
|
17
17
|
: undefined;
|
|
18
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* Operation batches belong to the database's coordinator, keyed by the
|
|
21
|
+
* operation token, so every resolver and warmer one operation creates for that
|
|
22
|
+
* database shares one authenticated view. A batch dies with its token (the end
|
|
23
|
+
* of the pass or workflow) and its entries with any organization hint.
|
|
24
|
+
*/
|
|
25
|
+
const operationBatches = new WeakMap();
|
|
26
|
+
function operationRecoveryBatch(coordinator, operation) {
|
|
27
|
+
if (!operation)
|
|
28
|
+
return createPrincipalCurrentRecoveryBatch();
|
|
29
|
+
let batches = operationBatches.get(coordinator);
|
|
30
|
+
if (!batches) {
|
|
31
|
+
batches = new WeakMap();
|
|
32
|
+
operationBatches.set(coordinator, batches);
|
|
33
|
+
}
|
|
34
|
+
let batch = batches.get(operation);
|
|
35
|
+
if (!batch) {
|
|
36
|
+
batch = createPrincipalCurrentRecoveryBatch();
|
|
37
|
+
batches.set(operation, batch);
|
|
38
|
+
}
|
|
39
|
+
return batch;
|
|
40
|
+
}
|
|
19
41
|
/** One recovery attempt for a resolver request through the operation's batch. */
|
|
20
42
|
function recoverPolicyCurrent(batch, options, input) {
|
|
21
43
|
return input.reference
|
|
@@ -32,18 +54,8 @@ export function createRuntimePrincipalPolicyCurrentResolver(runtime) {
|
|
|
32
54
|
const historyReader = apiPrincipalPolicyPageReader(runtime.apiClient);
|
|
33
55
|
if (!lease || !historyReader)
|
|
34
56
|
return undefined;
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
if (!batch)
|
|
38
|
-
return createPrincipalCurrentRecoveryBatch();
|
|
39
|
-
let recover = batches.get(batch);
|
|
40
|
-
if (!recover) {
|
|
41
|
-
recover = createPrincipalCurrentRecoveryBatch();
|
|
42
|
-
batches.set(batch, recover);
|
|
43
|
-
}
|
|
44
|
-
return recover;
|
|
45
|
-
};
|
|
46
|
-
return (input) => getOrCreatePrincipalPolicyCoordinator(runtime.infra.execSql).queueRecovery(input.organizationId, () => runWithSecurityIncidentReporting(runtime.util.reportSecurityIncident, {
|
|
57
|
+
const coordinator = getOrCreatePrincipalPolicyCoordinator(runtime.infra.execSql);
|
|
58
|
+
return (input) => coordinator.queueRecovery(input.organizationId, () => runWithSecurityIncidentReporting(runtime.util.reportSecurityIncident, {
|
|
47
59
|
objectId: input.reference?.principalId ?? input.organizationId,
|
|
48
60
|
objectKind: "principal",
|
|
49
61
|
operation: "principal.policy.recover",
|
|
@@ -63,7 +75,7 @@ export function createRuntimePrincipalPolicyCurrentResolver(runtime) {
|
|
|
63
75
|
resolveTrustedUserIdentity: runtime.resolveTrustedUserIdentity,
|
|
64
76
|
stillCurrent,
|
|
65
77
|
};
|
|
66
|
-
const result = await resumeAfterSupersededStage(() => recoverPolicyCurrent(
|
|
78
|
+
const result = await resumeAfterSupersededStage(() => recoverPolicyCurrent(operationRecoveryBatch(coordinator, input.recoveryBatch), options, input), stillCurrent);
|
|
67
79
|
// Reused evidence stays bound to every producer lifetime.
|
|
68
80
|
const resultCurrent = () => stillCurrent() && result.stillCurrent();
|
|
69
81
|
assertProjectionVerificationCurrent(resultCurrent);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtimePolicyRecovery.js","sourceRoot":"","sources":["runtimePolicyRecovery.ts"],"names":[],"mappings":"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","sourcesContent":["import type { PrincipalPolicyPageCurrent } from \"@tearleads/api-client\";\nimport { KeyingVerificationError } from \"@tearleads/crypto\";\nimport { ProjectionDependencyUnavailableError } from \"../../data/keyingProjectionVerification/dependencyUnavailable\";\nimport { runWithSecurityIncidentReporting } from \"../../data/keyingProjectionVerification/error\";\nimport {\n assertProjectionVerificationCurrent,\n type PrincipalPolicyResolveRequest,\n type ReferencedPrincipalPolicyWarmer,\n type ResolvedPrincipalPolicyEvidence,\n} from \"../../data/keyingProjectionVerification/types\";\nimport type { PrincipalHistoryProtectionLease } from \"../../data/principals/principalHistoryProtection\";\nimport { readPrincipalHistoryProtection } from \"../../data/principals/principalHistoryRuntime\";\nimport { getOrCreatePrincipalPolicyCoordinator } from \"../../data/principals/principalPolicyCoordinator\";\nimport type { SecurityIncidentReporter } from \"../../data/shared/securityIncidents\";\nimport type { ExecSql } from \"../../data/sqlite/sqlSchema\";\nimport type { TrustedUserIdentityResolver } from \"../../data/trustedUserIdentity\";\nimport type { RecoveredPrincipalHistoryPage } from \"./historyRecovery/loadRecoveredPrincipalHistoryPage\";\nimport {\n PrincipalHistoryRecoveryRaceError,\n PrincipalPolicyHistoryReadError,\n} from \"./historyRecovery/principalHistoryRecoveryTypes\";\nimport type { ScopedPrincipalPolicyRecovery } from \"./historyRecovery/recoverScopedPrincipalPolicyHistory\";\nimport {\n apiPrincipalPolicyPageReader,\n type PrincipalPolicyHistoryReader,\n} from \"./principalPolicyHistoryReader\";\nimport { createPrincipalCurrentRecoveryBatch } from \"./recoveryOperation/principalCurrentRecoveryBatch\";\nimport { recoverWithPrincipalLocalPreference } from \"./recoveryOperation/principalRecoveryLocalPreference\";\nimport { resumeAfterSupersededStage } from \"./recoveryOperation/supersededStageResume\";\n\nexport interface PrincipalPolicyRecoveryRuntime {\n readonly apiClient: Partial<PrincipalPolicyHistoryReader>;\n readonly infra: { readonly execSql: ExecSql };\n readonly state?: { readonly online: boolean } | undefined;\n readonly util: { readonly reportSecurityIncident: SecurityIncidentReporter };\n readonly resolveTrustedUserIdentity: TrustedUserIdentityResolver;\n readonly withPrincipalHistoryProtection?:\n | PrincipalHistoryProtectionLease\n | undefined;\n}\n\n/** Keep the private recovery key inside its runtime lease while resolving cited evidence. */\nexport function createRuntimePrincipalPolicyResolver(\n runtime: PrincipalPolicyRecoveryRuntime,\n options: { readonly preferLocalCurrent?: boolean } = {},\n): ReferencedPrincipalPolicyWarmer[\"resolveReference\"] {\n const resolve = createRuntimePrincipalPolicyCurrentResolver(runtime);\n return resolve\n ? (input) =>\n resolve({ ...input, preferLocalCurrent: options.preferLocalCurrent })\n : undefined;\n}\n\nexport interface ResolvedPrincipalPolicyCurrent\n extends ResolvedPrincipalPolicyEvidence {\n readonly current: PrincipalPolicyPageCurrent;\n /** Rows end at the selected reference; current/policy may describe a newer recovered head. */\n readonly historyPage?: RecoveredPrincipalHistoryPage | undefined;\n}\n\ninterface PrincipalPolicyCurrentRequest\n extends Omit<PrincipalPolicyResolveRequest, \"reference\"> {\n readonly reference?: PrincipalPolicyResolveRequest[\"reference\"] | undefined;\n /** A read-model caller has selected this exact signed head; not a freshness read. */\n readonly preferLocalCurrent?: boolean | undefined;\n readonly historyPage?: { readonly beforeVersion?: number } | undefined;\n}\n\n/** One recovery attempt for a resolver request through the operation's batch. */\nfunction recoverPolicyCurrent(\n batch: ReturnType<typeof createPrincipalCurrentRecoveryBatch>,\n options: Parameters<\n ReturnType<typeof createPrincipalCurrentRecoveryBatch>[\"discover\"]\n >[0],\n input: PrincipalPolicyCurrentRequest,\n): Promise<ScopedPrincipalPolicyRecovery> {\n return input.reference\n ? recoverWithPrincipalLocalPreference(\n batch.recover,\n {\n ...options,\n reference: input.reference,\n historyPage: input.historyPage,\n },\n input.preferLocalCurrent === true || input.preferLocalHistory === true,\n input.preferLocalHistory === true,\n )\n : batch.discover(options);\n}\n\n/** Keep current artifacts with their verified evidence and private runtime lifetime. */\nexport function createRuntimePrincipalPolicyCurrentResolver(\n runtime: PrincipalPolicyRecoveryRuntime,\n):\n | ((\n input: PrincipalPolicyCurrentRequest,\n ) => Promise<ResolvedPrincipalPolicyCurrent>)\n | undefined {\n const lease = readPrincipalHistoryProtection(runtime);\n const historyReader = apiPrincipalPolicyPageReader(runtime.apiClient);\n if (!lease || !historyReader) return undefined;\n const batches = new WeakMap<\n object,\n ReturnType<typeof createPrincipalCurrentRecoveryBatch>\n >();\n const recoverFor = (batch: object | undefined) => {\n if (!batch) return createPrincipalCurrentRecoveryBatch();\n let recover = batches.get(batch);\n if (!recover) {\n recover = createPrincipalCurrentRecoveryBatch();\n batches.set(batch, recover);\n }\n return recover;\n };\n return (input) =>\n getOrCreatePrincipalPolicyCoordinator(runtime.infra.execSql).queueRecovery(\n input.organizationId,\n () =>\n runWithSecurityIncidentReporting(\n runtime.util.reportSecurityIncident,\n {\n objectId: input.reference?.principalId ?? input.organizationId,\n objectKind: \"principal\",\n operation: \"principal.policy.recover\",\n organizationId: input.organizationId,\n },\n () =>\n lease(async ({ protection, stillCurrent: leaseCurrent }) => {\n const stillCurrent = () =>\n leaseCurrent() && input.stillCurrent?.() !== false;\n assertProjectionVerificationCurrent(stillCurrent);\n assertHistoryPageRequest(input);\n const offline = runtime.state?.online === false;\n try {\n const options = {\n historyReader,\n execSql: runtime.infra.execSql,\n offline,\n organizationId: input.organizationId,\n protection,\n resolveTrustedUserIdentity:\n runtime.resolveTrustedUserIdentity,\n stillCurrent,\n };\n const result = await resumeAfterSupersededStage(\n () =>\n recoverPolicyCurrent(\n recoverFor(input.recoveryBatch),\n options,\n input,\n ),\n stillCurrent,\n );\n // Reused evidence stays bound to every producer lifetime.\n const resultCurrent = () =>\n stillCurrent() && result.stillCurrent();\n assertProjectionVerificationCurrent(resultCurrent);\n return {\n current: result.current,\n organizationId: input.organizationId,\n policy: result.policy,\n dependencies: result.dependencies,\n historyPage: result.historyPage,\n stillCurrent: resultCurrent,\n };\n } catch (error) {\n assertProjectionVerificationCurrent(stillCurrent);\n if (\n error instanceof PrincipalPolicyHistoryReadError ||\n error instanceof PrincipalHistoryRecoveryRaceError ||\n (error instanceof KeyingVerificationError &&\n error.code === \"missing_dependency\")\n )\n throw new ProjectionDependencyUnavailableError(error.message);\n throw error;\n }\n }),\n ),\n );\n}\n\nfunction assertHistoryPageRequest(input: PrincipalPolicyCurrentRequest) {\n if (!input.historyPage) return;\n const before = input.historyPage.beforeVersion;\n if (\n !input.reference ||\n (before !== undefined &&\n (!Number.isSafeInteger(before) ||\n before <= 1 ||\n before > input.reference.version + 1))\n )\n throw new KeyingVerificationError(\n \"invalid_shape\",\n \"History display requires a selected head and an in-range cursor\",\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"runtimePolicyRecovery.js","sourceRoot":"","sources":["runtimePolicyRecovery.ts"],"names":[],"mappings":"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","sourcesContent":["import type { PrincipalPolicyPageCurrent } from \"@tearleads/api-client\";\nimport { KeyingVerificationError } from \"@tearleads/crypto\";\nimport { ProjectionDependencyUnavailableError } from \"../../data/keyingProjectionVerification/dependencyUnavailable\";\nimport { runWithSecurityIncidentReporting } from \"../../data/keyingProjectionVerification/error\";\nimport {\n assertProjectionVerificationCurrent,\n type PrincipalPolicyResolveRequest,\n type ReferencedPrincipalPolicyWarmer,\n type ResolvedPrincipalPolicyEvidence,\n} from \"../../data/keyingProjectionVerification/types\";\nimport type { PrincipalHistoryProtectionLease } from \"../../data/principals/principalHistoryProtection\";\nimport { readPrincipalHistoryProtection } from \"../../data/principals/principalHistoryRuntime\";\nimport {\n getOrCreatePrincipalPolicyCoordinator,\n type PrincipalPolicyCoordinator,\n} from \"../../data/principals/principalPolicyCoordinator\";\nimport type { SecurityIncidentReporter } from \"../../data/shared/securityIncidents\";\nimport type { ExecSql } from \"../../data/sqlite/sqlSchema\";\nimport type { TrustedUserIdentityResolver } from \"../../data/trustedUserIdentity\";\nimport type { RecoveredPrincipalHistoryPage } from \"./historyRecovery/loadRecoveredPrincipalHistoryPage\";\nimport {\n PrincipalHistoryRecoveryRaceError,\n PrincipalPolicyHistoryReadError,\n} from \"./historyRecovery/principalHistoryRecoveryTypes\";\nimport type { ScopedPrincipalPolicyRecovery } from \"./historyRecovery/recoverScopedPrincipalPolicyHistory\";\nimport {\n apiPrincipalPolicyPageReader,\n type PrincipalPolicyHistoryReader,\n} from \"./principalPolicyHistoryReader\";\nimport { createPrincipalCurrentRecoveryBatch } from \"./recoveryOperation/principalCurrentRecoveryBatch\";\nimport { recoverWithPrincipalLocalPreference } from \"./recoveryOperation/principalRecoveryLocalPreference\";\nimport { resumeAfterSupersededStage } from \"./recoveryOperation/supersededStageResume\";\n\nexport interface PrincipalPolicyRecoveryRuntime {\n readonly apiClient: Partial<PrincipalPolicyHistoryReader>;\n readonly infra: { readonly execSql: ExecSql };\n readonly state?: { readonly online: boolean } | undefined;\n readonly util: { readonly reportSecurityIncident: SecurityIncidentReporter };\n readonly resolveTrustedUserIdentity: TrustedUserIdentityResolver;\n readonly withPrincipalHistoryProtection?:\n | PrincipalHistoryProtectionLease\n | undefined;\n}\n\n/** Keep the private recovery key inside its runtime lease while resolving cited evidence. */\nexport function createRuntimePrincipalPolicyResolver(\n runtime: PrincipalPolicyRecoveryRuntime,\n options: { readonly preferLocalCurrent?: boolean } = {},\n): ReferencedPrincipalPolicyWarmer[\"resolveReference\"] {\n const resolve = createRuntimePrincipalPolicyCurrentResolver(runtime);\n return resolve\n ? (input) =>\n resolve({ ...input, preferLocalCurrent: options.preferLocalCurrent })\n : undefined;\n}\n\nexport interface ResolvedPrincipalPolicyCurrent\n extends ResolvedPrincipalPolicyEvidence {\n readonly current: PrincipalPolicyPageCurrent;\n /** Rows end at the selected reference; current/policy may describe a newer recovered head. */\n readonly historyPage?: RecoveredPrincipalHistoryPage | undefined;\n}\n\ninterface PrincipalPolicyCurrentRequest\n extends Omit<PrincipalPolicyResolveRequest, \"reference\"> {\n readonly reference?: PrincipalPolicyResolveRequest[\"reference\"] | undefined;\n /** A read-model caller has selected this exact signed head; not a freshness read. */\n readonly preferLocalCurrent?: boolean | undefined;\n readonly historyPage?: { readonly beforeVersion?: number } | undefined;\n}\n\ntype PrincipalCurrentRecoveryBatch = ReturnType<\n typeof createPrincipalCurrentRecoveryBatch\n>;\n\n/**\n * Operation batches belong to the database's coordinator, keyed by the\n * operation token, so every resolver and warmer one operation creates for that\n * database shares one authenticated view. A batch dies with its token (the end\n * of the pass or workflow) and its entries with any organization hint.\n */\nconst operationBatches = new WeakMap<\n PrincipalPolicyCoordinator,\n WeakMap<object, PrincipalCurrentRecoveryBatch>\n>();\n\nfunction operationRecoveryBatch(\n coordinator: PrincipalPolicyCoordinator,\n operation: object | undefined,\n): PrincipalCurrentRecoveryBatch {\n if (!operation) return createPrincipalCurrentRecoveryBatch();\n let batches = operationBatches.get(coordinator);\n if (!batches) {\n batches = new WeakMap();\n operationBatches.set(coordinator, batches);\n }\n let batch = batches.get(operation);\n if (!batch) {\n batch = createPrincipalCurrentRecoveryBatch();\n batches.set(operation, batch);\n }\n return batch;\n}\n\n/** One recovery attempt for a resolver request through the operation's batch. */\nfunction recoverPolicyCurrent(\n batch: ReturnType<typeof createPrincipalCurrentRecoveryBatch>,\n options: Parameters<\n ReturnType<typeof createPrincipalCurrentRecoveryBatch>[\"discover\"]\n >[0],\n input: PrincipalPolicyCurrentRequest,\n): Promise<ScopedPrincipalPolicyRecovery> {\n return input.reference\n ? recoverWithPrincipalLocalPreference(\n batch.recover,\n {\n ...options,\n reference: input.reference,\n historyPage: input.historyPage,\n },\n input.preferLocalCurrent === true || input.preferLocalHistory === true,\n input.preferLocalHistory === true,\n )\n : batch.discover(options);\n}\n\n/** Keep current artifacts with their verified evidence and private runtime lifetime. */\nexport function createRuntimePrincipalPolicyCurrentResolver(\n runtime: PrincipalPolicyRecoveryRuntime,\n):\n | ((\n input: PrincipalPolicyCurrentRequest,\n ) => Promise<ResolvedPrincipalPolicyCurrent>)\n | undefined {\n const lease = readPrincipalHistoryProtection(runtime);\n const historyReader = apiPrincipalPolicyPageReader(runtime.apiClient);\n if (!lease || !historyReader) return undefined;\n const coordinator = getOrCreatePrincipalPolicyCoordinator(\n runtime.infra.execSql,\n );\n return (input) =>\n coordinator.queueRecovery(input.organizationId, () =>\n runWithSecurityIncidentReporting(\n runtime.util.reportSecurityIncident,\n {\n objectId: input.reference?.principalId ?? input.organizationId,\n objectKind: \"principal\",\n operation: \"principal.policy.recover\",\n organizationId: input.organizationId,\n },\n () =>\n lease(async ({ protection, stillCurrent: leaseCurrent }) => {\n const stillCurrent = () =>\n leaseCurrent() && input.stillCurrent?.() !== false;\n assertProjectionVerificationCurrent(stillCurrent);\n assertHistoryPageRequest(input);\n const offline = runtime.state?.online === false;\n try {\n const options = {\n historyReader,\n execSql: runtime.infra.execSql,\n offline,\n organizationId: input.organizationId,\n protection,\n resolveTrustedUserIdentity: runtime.resolveTrustedUserIdentity,\n stillCurrent,\n };\n const result = await resumeAfterSupersededStage(\n () =>\n recoverPolicyCurrent(\n operationRecoveryBatch(coordinator, input.recoveryBatch),\n options,\n input,\n ),\n stillCurrent,\n );\n // Reused evidence stays bound to every producer lifetime.\n const resultCurrent = () =>\n stillCurrent() && result.stillCurrent();\n assertProjectionVerificationCurrent(resultCurrent);\n return {\n current: result.current,\n organizationId: input.organizationId,\n policy: result.policy,\n dependencies: result.dependencies,\n historyPage: result.historyPage,\n stillCurrent: resultCurrent,\n };\n } catch (error) {\n assertProjectionVerificationCurrent(stillCurrent);\n if (\n error instanceof PrincipalPolicyHistoryReadError ||\n error instanceof PrincipalHistoryRecoveryRaceError ||\n (error instanceof KeyingVerificationError &&\n error.code === \"missing_dependency\")\n )\n throw new ProjectionDependencyUnavailableError(error.message);\n throw error;\n }\n }),\n ),\n );\n}\n\nfunction assertHistoryPageRequest(input: PrincipalPolicyCurrentRequest) {\n if (!input.historyPage) return;\n const before = input.historyPage.beforeVersion;\n if (\n !input.reference ||\n (before !== undefined &&\n (!Number.isSafeInteger(before) ||\n before <= 1 ||\n before > input.reference.version + 1))\n )\n throw new KeyingVerificationError(\n \"invalid_shape\",\n \"History display requires a selected head and an in-range cursor\",\n );\n}\n"]}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type ReferencedPrincipalPolicyWarmer } from "../../data/keyingProjectionVerification/types.js";
|
|
2
|
+
import { type PrincipalPolicyRecoveryRuntime } from "./runtimePolicyRecovery.js";
|
|
3
|
+
interface PrincipalPolicyWarmRuntime extends PrincipalPolicyRecoveryRuntime {
|
|
4
|
+
readonly util: PrincipalPolicyRecoveryRuntime["util"] & {
|
|
5
|
+
readonly log?: ((message: string) => void) | undefined;
|
|
6
|
+
};
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* The token of one reconciliation pass or user workflow. Every warmer created
|
|
10
|
+
* with it shares one authenticated directory view, discovered once; the view
|
|
11
|
+
* dies with the token, an organization hint, a durable pin past it, or the end
|
|
12
|
+
* of its producing lease. Mint one at the pass or workflow root.
|
|
13
|
+
*/
|
|
14
|
+
export type PrincipalPolicyOperation = object;
|
|
15
|
+
export declare function createPrincipalPolicyOperation(): PrincipalPolicyOperation;
|
|
16
|
+
/**
|
|
17
|
+
* One warmer serves one workflow operation: either the `operation` its root
|
|
18
|
+
* minted, or a fresh one of its own. Its projection collections share one
|
|
19
|
+
* authenticated directory view per operation. Prefetch is best-effort; exact
|
|
20
|
+
* resolution still rejects unavailable evidence.
|
|
21
|
+
*/
|
|
22
|
+
export declare function createRuntimePrincipalPolicyWarmer(runtime: PrincipalPolicyWarmRuntime, options?: {
|
|
23
|
+
readonly preferLocalCurrent?: boolean;
|
|
24
|
+
readonly operation?: PrincipalPolicyOperation | undefined;
|
|
25
|
+
}): ReferencedPrincipalPolicyWarmer;
|
|
26
|
+
export {};
|
|
@@ -4,15 +4,18 @@ import { assertProjectionVerificationCurrent, isProjectionVerificationCancelledE
|
|
|
4
4
|
import { errorMessage } from "../../data/shared/errorMessage.js";
|
|
5
5
|
import { createRuntimePrincipalPolicyResolver, } from "./runtimePolicyRecovery.js";
|
|
6
6
|
import { createRuntimeProjectionPolicyResolver } from "./runtimeProjectionPolicyRecovery.js";
|
|
7
|
+
export function createPrincipalPolicyOperation() {
|
|
8
|
+
return {};
|
|
9
|
+
}
|
|
7
10
|
/**
|
|
8
|
-
* One warmer serves one workflow operation
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
11
|
+
* One warmer serves one workflow operation: either the `operation` its root
|
|
12
|
+
* minted, or a fresh one of its own. Its projection collections share one
|
|
13
|
+
* authenticated directory view per operation. Prefetch is best-effort; exact
|
|
14
|
+
* resolution still rejects unavailable evidence.
|
|
12
15
|
*/
|
|
13
16
|
export function createRuntimePrincipalPolicyWarmer(runtime, options = {}) {
|
|
14
17
|
const resolve = createRuntimePrincipalPolicyResolver(runtime, options);
|
|
15
|
-
const operation =
|
|
18
|
+
const operation = options.operation ?? createPrincipalPolicyOperation();
|
|
16
19
|
const resolveReference = async (input) => {
|
|
17
20
|
if (!resolve)
|
|
18
21
|
throw new ProjectionDependencyUnavailableError("Principal policies require private paged recovery");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtimePolicyWarmer.js","sourceRoot":"","sources":["runtimePolicyWarmer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oCAAoC,EAAE,MAAM,+DAA+D,CAAC;AACrH,OAAO,EAAE,8BAA8B,EAAE,MAAM,+CAA+C,CAAC;AAC/F,OAAO,EACL,mCAAmC,EACnC,sCAAsC,GAEvC,MAAM,+CAA+C,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,EACL,oCAAoC,GAErC,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,qCAAqC,EAAE,MAAM,mCAAmC,CAAC;
|
|
1
|
+
{"version":3,"file":"runtimePolicyWarmer.js","sourceRoot":"","sources":["runtimePolicyWarmer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oCAAoC,EAAE,MAAM,+DAA+D,CAAC;AACrH,OAAO,EAAE,8BAA8B,EAAE,MAAM,+CAA+C,CAAC;AAC/F,OAAO,EACL,mCAAmC,EACnC,sCAAsC,GAEvC,MAAM,+CAA+C,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,EACL,oCAAoC,GAErC,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,qCAAqC,EAAE,MAAM,mCAAmC,CAAC;AAmB1F,MAAM,UAAU,8BAA8B;IAC5C,OAAO,EAAE,CAAC;AACZ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kCAAkC,CAChD,OAAmC,EACnC,UAGI,EAAE;IAEN,MAAM,OAAO,GAAG,oCAAoC,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACvE,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,8BAA8B,EAAE,CAAC;IACxE,MAAM,gBAAgB,GAAmB,KAAK,EAAE,KAAK,EAAE,EAAE;QACvD,IAAI,CAAC,OAAO;YACV,MAAM,IAAI,oCAAoC,CAC5C,mDAAmD,CACpD,CAAC;QACJ,OAAO,OAAO,CAAC;YACb,GAAG,KAAK;YACR,aAAa,EAAE,KAAK,CAAC,aAAa,IAAI,SAAS;SAChD,CAAC,CAAC;IACL,CAAC,CAAC;IACF,OAAO,MAAM,CAAC,MAAM,CAClB,CAAC,KAAqD,EAAE,EAAE,CACxD,kBAAkB,CAAC,OAAO,EAAE,gBAAgB,EAAE,KAAK,CAAC,EACtD;QACE,gBAAgB;QAChB,wBAAwB,EAAE,qCAAqC,CAAC,OAAO,CAAC;KACzE,CACF,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,kBAAkB,CAC/B,OAAmC,EACnC,OAAuB,EACvB,KAAqD;IAErD,KAAK,MAAM,SAAS,IAAI,KAAK,CAAC,UAAU,EAAE,CAAC;QACzC,IAAI,CAAC;YACH,mCAAmC,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;YACxD,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,EAAE,GAAG,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;YACxD,mCAAmC,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;QAC7D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,sCAAsC,CAAC,KAAK,CAAC;gBAAE,OAAO;YAC1D,0EAA0E;YAC1E,8BAA8B,CAAC,KAAK,CAAC,CAAC;YACtC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAChB,8BAA8B,SAAS,CAAC,WAAW,KAAK,YAAY,CAAC,KAAK,CAAC,EAAE,CAC9E,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC","sourcesContent":["import { ProjectionDependencyUnavailableError } from \"../../data/keyingProjectionVerification/dependencyUnavailable\";\nimport { rethrowKeyingVerificationError } from \"../../data/keyingProjectionVerification/error\";\nimport {\n assertProjectionVerificationCurrent,\n isProjectionVerificationCancelledError,\n type ReferencedPrincipalPolicyWarmer,\n} from \"../../data/keyingProjectionVerification/types\";\nimport { errorMessage } from \"../../data/shared/errorMessage\";\nimport {\n createRuntimePrincipalPolicyResolver,\n type PrincipalPolicyRecoveryRuntime,\n} from \"./runtimePolicyRecovery\";\nimport { createRuntimeProjectionPolicyResolver } from \"./runtimeProjectionPolicyRecovery\";\n\ntype PolicyResolver = NonNullable<\n ReferencedPrincipalPolicyWarmer[\"resolveReference\"]\n>;\ninterface PrincipalPolicyWarmRuntime extends PrincipalPolicyRecoveryRuntime {\n readonly util: PrincipalPolicyRecoveryRuntime[\"util\"] & {\n readonly log?: ((message: string) => void) | undefined;\n };\n}\n\n/**\n * The token of one reconciliation pass or user workflow. Every warmer created\n * with it shares one authenticated directory view, discovered once; the view\n * dies with the token, an organization hint, a durable pin past it, or the end\n * of its producing lease. Mint one at the pass or workflow root.\n */\nexport type PrincipalPolicyOperation = object;\n\nexport function createPrincipalPolicyOperation(): PrincipalPolicyOperation {\n return {};\n}\n\n/**\n * One warmer serves one workflow operation: either the `operation` its root\n * minted, or a fresh one of its own. Its projection collections share one\n * authenticated directory view per operation. Prefetch is best-effort; exact\n * resolution still rejects unavailable evidence.\n */\nexport function createRuntimePrincipalPolicyWarmer(\n runtime: PrincipalPolicyWarmRuntime,\n options: {\n readonly preferLocalCurrent?: boolean;\n readonly operation?: PrincipalPolicyOperation | undefined;\n } = {},\n): ReferencedPrincipalPolicyWarmer {\n const resolve = createRuntimePrincipalPolicyResolver(runtime, options);\n const operation = options.operation ?? createPrincipalPolicyOperation();\n const resolveReference: PolicyResolver = async (input) => {\n if (!resolve)\n throw new ProjectionDependencyUnavailableError(\n \"Principal policies require private paged recovery\",\n );\n return resolve({\n ...input,\n recoveryBatch: input.recoveryBatch ?? operation,\n });\n };\n return Object.assign(\n (input: Parameters<ReferencedPrincipalPolicyWarmer>[0]) =>\n prefetchReferences(runtime, resolveReference, input),\n {\n resolveReference,\n resolveProjectionHistory: createRuntimeProjectionPolicyResolver(runtime),\n },\n );\n}\n\nasync function prefetchReferences(\n runtime: PrincipalPolicyWarmRuntime,\n resolve: PolicyResolver,\n input: Parameters<ReferencedPrincipalPolicyWarmer>[0],\n): Promise<void> {\n for (const reference of input.references) {\n try {\n assertProjectionVerificationCurrent(input.stillCurrent);\n const resolved = await resolve({ ...input, reference });\n assertProjectionVerificationCurrent(resolved.stillCurrent);\n } catch (error) {\n if (isProjectionVerificationCancelledError(error)) return;\n // Recovery already reports signature/authority failures. Keep them fatal.\n rethrowKeyingVerificationError(error);\n runtime.util.log?.(\n `Principal policy prefetch: ${reference.principalId}: ${errorMessage(error)}`,\n );\n }\n }\n}\n"]}
|