@tearleads/client-sdk 0.1.55 → 0.1.57
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/data/containers/shared/types.d.ts +1 -2
- package/data/containers/shared/types.js.map +1 -1
- package/data/persistence/organizations/organizationAccessRevocationPersistence.js +2 -2
- package/data/persistence/organizations/organizationAccessRevocationPersistence.js.map +1 -1
- package/data/persistence/organizations/organizationReadModelPersistence.js +2 -2
- package/data/persistence/organizations/organizationReadModelPersistence.js.map +1 -1
- package/data/principals/principalPolicyCoordinator.js +40 -0
- package/data/principals/principalPolicyCoordinator.js.map +1 -0
- package/package.json +1 -1
- package/workflows/container-contents/container-state/types.js.map +1 -1
- package/workflows/container-contents/remoteHydration/types.d.ts +5 -4
- package/workflows/container-contents/remoteHydration/types.js.map +1 -1
- package/workflows/containers/child/sharePrincipalPolicy.d.ts +3 -3
- package/workflows/containers/child/sharePrincipalPolicy.js +1 -1
- package/workflows/containers/child/sharePrincipalPolicy.js.map +1 -1
- package/workflows/organizations/deleteOrganizationGroup.js +1 -1
- package/workflows/organizations/deleteOrganizationGroup.js.map +1 -1
- package/workflows/organizations/groupCreation.js +1 -1
- package/workflows/organizations/groupCreation.js.map +1 -1
- package/workflows/organizations/groupNameUniqueness.js.map +1 -1
- package/workflows/organizations/groupPolicyMutationContext.js +1 -1
- package/workflows/organizations/groupPolicyMutationContext.js.map +1 -1
- package/workflows/organizations/organizationGroupNamePolicies.js +19 -5
- package/workflows/organizations/organizationGroupNamePolicies.js.map +1 -1
- package/workflows/organizations/principalMutationJournalManagement.js +3 -3
- package/workflows/organizations/principalMutationJournalManagement.js.map +1 -1
- package/workflows/organizations/principalMutationJournalSession.js +3 -3
- package/workflows/organizations/principalMutationJournalSession.js.map +1 -1
- package/workflows/organizations/principalPolicyApi.d.ts +3 -3
- package/workflows/organizations/principalPolicyApi.js.map +1 -1
- package/workflows/principals/currentPrincipalPolicyReader.d.ts +12 -0
- package/workflows/principals/currentPrincipalPolicyReader.js +2 -0
- package/workflows/principals/currentPrincipalPolicyReader.js.map +1 -0
- package/workflows/principals/externalAdminPolicy.d.ts +2 -1
- package/workflows/principals/externalAdminPolicy.js +3 -3
- package/workflows/principals/externalAdminPolicy.js.map +1 -1
- package/workflows/principals/policyCache.d.ts +3 -2
- package/workflows/principals/policyCache.js +9 -9
- package/workflows/principals/policyCache.js.map +1 -1
- package/workflows/principals/principalPolicyOrganizationScope.js +1 -1
- package/workflows/principals/principalPolicyOrganizationScope.js.map +1 -1
- package/workflows/principals/principalRecoveryMemoValidity.js +2 -2
- package/workflows/principals/principalRecoveryMemoValidity.js.map +1 -1
- package/workflows/principals/runtimePolicyRecovery.js +2 -2
- package/workflows/principals/runtimePolicyRecovery.js.map +1 -1
- package/workflows/principals/runtimeProjectionPolicyRecovery.js +2 -2
- package/workflows/principals/runtimeProjectionPolicyRecovery.js.map +1 -1
- package/workflows/registration/provisionedPrincipalHistory.js +2 -2
- package/workflows/registration/provisionedPrincipalHistory.js.map +1 -1
- package/data/principals/principalRecoveryEpoch.js +0 -18
- package/data/principals/principalRecoveryEpoch.js.map +0 -1
- package/workflows/organizations/principalMutationJournalLane.js +0 -26
- package/workflows/organizations/principalMutationJournalLane.js.map +0 -1
- package/workflows/principals/principalRecoveryQueue.js +0 -22
- package/workflows/principals/principalRecoveryQueue.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"externalAdminPolicy.js","sourceRoot":"","sources":["externalAdminPolicy.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n KeyingVerificationError,\n type PrincipalPolicyExternalAuthority,\n type VerifiedPrincipalPolicy,\n verifyPrincipalPolicyBundle,\n} from \"@tearleads/crypto\";\nimport type { PrincipalPolicyBundleResponse } from \"@tearleads/validators/response\";\nimport { persistVerifiedPrincipalPolicyBundlesAtomically } from \"../../data/persistence/keyingCheckpointAdvancePersistence\";\nimport { loadPrincipalPolicyCheckpoint } from \"../../data/persistence/keyingCheckpointPersistence\";\nimport {\n type OrganizationAuthorityDescriptor,\n parseOrganizationAuthorityDescriptor,\n previousStatesIncludeHead,\n principalHeadMatchesReference,\n requireOrganizationGroupHead,\n} from \"../../data/principals/organizationAuthorityDescriptor\";\nimport {\n organizationAdminExternalAuthority,\n organizationAdminSignerUserIds,\n principalPolicyReferenceFromBundle,\n verifyOrganizationAdminPolicy,\n} from \"../../data/principals/principalPolicyAdminSigners\";\nimport type { ExecSql } from \"../../data/sqlite/sqlSchema\";\nimport type { TrustedUserIdentityResolver } from \"../../data/trustedUserIdentity\";\nimport {\n collectPrincipalPolicySignerPublicKeys,\n type PrincipalPolicySignerPublicKeyLoadErrorCode,\n} from \"./policyVerification\";\n\nexport interface VerifiedExternalAdminPolicy {\n readonly adminBundle: PrincipalPolicyBundleResponse;\n readonly adminGroupId: string;\n readonly adminPolicy: VerifiedPrincipalPolicy;\n readonly bundle: PrincipalPolicyBundleResponse;\n readonly descriptor: OrganizationAuthorityDescriptor;\n readonly memberGroupId: string;\n readonly policy: VerifiedPrincipalPolicy;\n readonly externalAuthority: PrincipalPolicyExternalAuthority;\n readonly signerUserIds: readonly string[];\n}\n\nexport function externalAdminPolicyPersistenceEntries(\n authority: VerifiedExternalAdminPolicy,\n): ReadonlyArray<{\n readonly bundle: PrincipalPolicyBundleResponse;\n readonly policy: VerifiedPrincipalPolicy;\n}> {\n return [\n { bundle: authority.bundle, policy: authority.policy },\n { bundle: authority.adminBundle, policy: authority.adminPolicy },\n ];\n}\n\nfunction assertAdminsPolicyShape(policy: VerifiedPrincipalPolicy): void {\n if (\n (policy.history ?? [{ projection: policy.projection }]).some(\n (entry) =>\n entry.projection.length === 0 ||\n entry.projection.some((member) => member.role !== \"admin\"),\n )\n ) {\n throw new KeyingVerificationError(\n \"invalid_shape\",\n \"reserved Admins policy must contain only direct admin users\",\n );\n }\n}\n\n/**\n * A signer the caller cannot resolve is a cache miss, but a resolved signer\n * whose trusted key differs from the one the policy signed with is a\n * verification failure, as on every other policy path (#2365 finding 23).\n */\nfunction signerKeyLoadFailure(\n error: PrincipalPolicySignerPublicKeyLoadErrorCode,\n): null {\n if (error === \"fingerprint-mismatch\") {\n throw new KeyingVerificationError(\n \"signer_mismatch\",\n \"external admin policy signer key fingerprint mismatch\",\n );\n }\n return null;\n}\n\nasync function verifyOrganizationPolicy(input: {\n readonly bundle: PrincipalPolicyBundleResponse;\n readonly execSql: ExecSql;\n readonly organizationId: string;\n readonly resolveTrustedUserIdentity: TrustedUserIdentityResolver;\n}): Promise<VerifiedPrincipalPolicy | null> {\n const localCheckpoint = await loadPrincipalPolicyCheckpoint(\n input.execSql,\n \"organization\",\n input.organizationId,\n );\n const signerPublicKeys = await collectPrincipalPolicySignerPublicKeys({\n bundle: input.bundle,\n resolveTrustedUserIdentity: input.resolveTrustedUserIdentity,\n });\n if (\"error\" in signerPublicKeys) {\n return signerKeyLoadFailure(signerPublicKeys.error);\n }\n const verified = await verifyOrganizationAdminPolicy({\n bundle: input.bundle,\n localCheckpoint,\n organizationId: input.organizationId,\n signerPublicKeys: signerPublicKeys.signerPublicKeys,\n });\n if (!verified.ok) {\n throw verified.error;\n }\n return verified.value;\n}\n\nfunction parseScopedAuthorityDescriptor(\n bundle: PrincipalPolicyBundleResponse,\n organizationId: string,\n): OrganizationAuthorityDescriptor {\n let descriptor: OrganizationAuthorityDescriptor;\n try {\n descriptor = parseOrganizationAuthorityDescriptor(\n bundle.currentPayload.ciphertext,\n );\n } catch {\n throw new KeyingVerificationError(\n \"invalid_shape\",\n \"organization authority descriptor is invalid\",\n );\n }\n if (descriptor.organizationId !== organizationId) {\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"organization authority descriptor scope does not match\",\n );\n }\n return descriptor;\n}\n\n/**\n * The organization and its Admins group are separate reads, so an honest\n * Admins commit between them serves a chain that extends the head the\n * directory cites: a stale directory, not tampering (#2365 finding 22). The\n * claim is checked before any signer is trusted, so it is unverified and buys\n * only one organization refetch; a disagreement after that is an incident.\n */\nclass AdminsHeadAdvanced extends Error {}\n\nasync function loadVerifiedAdminsPolicy(input: {\n readonly adminGroupId: string;\n readonly expectedHead: ReturnType<typeof requireOrganizationGroupHead>;\n readonly mayRefetchDirectory: boolean;\n readonly execSql: ExecSql;\n readonly getCurrentPrincipalPolicy: (\n principalType: \"group\" | \"organization\",\n principalId: string,\n ) => Promise<PrincipalPolicyBundleResponse | null>;\n readonly resolveTrustedUserIdentity: TrustedUserIdentityResolver;\n}): Promise<{\n readonly bundle: PrincipalPolicyBundleResponse;\n readonly policy: VerifiedPrincipalPolicy;\n} | null> {\n const bundle = await input.getCurrentPrincipalPolicy(\n \"group\",\n input.adminGroupId,\n );\n if (!bundle) {\n return null;\n }\n if (\n !principalHeadMatchesReference(\n principalPolicyReferenceFromBundle(bundle),\n input.expectedHead,\n )\n ) {\n if (\n input.mayRefetchDirectory &&\n previousStatesIncludeHead(bundle, input.expectedHead)\n ) {\n throw new AdminsHeadAdvanced();\n }\n throw new KeyingVerificationError(\n \"hash_mismatch\",\n \"reserved Admins policy does not match the signed organization directory\",\n );\n }\n const localCheckpoint = await loadPrincipalPolicyCheckpoint(\n input.execSql,\n \"group\",\n input.adminGroupId,\n );\n const signerPublicKeys = await collectPrincipalPolicySignerPublicKeys({\n bundle,\n resolveTrustedUserIdentity: input.resolveTrustedUserIdentity,\n });\n if (\"error\" in signerPublicKeys) {\n return signerKeyLoadFailure(signerPublicKeys.error);\n }\n const verified = await verifyPrincipalPolicyBundle({\n bundle,\n expectedReference: input.expectedHead,\n localCheckpoint,\n signerPublicKeys: signerPublicKeys.signerPublicKeys,\n });\n if (!verified.ok) {\n throw verified.error;\n }\n if (\n verified.value.principalType !== \"group\" ||\n verified.value.principalId !== input.adminGroupId\n ) {\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"reserved Admins policy target does not match\",\n );\n }\n assertAdminsPolicyShape(verified.value);\n return { bundle, policy: verified.value };\n}\n\ninterface ExternalAdminPolicyInput {\n readonly execSql: ExecSql;\n readonly getCurrentPrincipalPolicy: (\n principalType: \"group\" | \"organization\",\n principalId: string,\n ) => Promise<PrincipalPolicyBundleResponse | null>;\n readonly organizationId: string | null | undefined;\n readonly resolveTrustedUserIdentity: TrustedUserIdentityResolver;\n readonly stillCurrent?: (() => boolean) | undefined;\n}\n\nasync function loadExternalAdminPolicyOnce(\n input: ExternalAdminPolicyInput,\n organizationId: string,\n mayRefetchDirectory: boolean,\n): Promise<VerifiedExternalAdminPolicy | null> {\n const bundle = await input.getCurrentPrincipalPolicy(\n \"organization\",\n organizationId,\n );\n if (!bundle) {\n return null;\n }\n const policy = await verifyOrganizationPolicy({\n bundle,\n execSql: input.execSql,\n organizationId,\n resolveTrustedUserIdentity: input.resolveTrustedUserIdentity,\n });\n if (!policy) {\n return null;\n }\n const descriptor = parseScopedAuthorityDescriptor(bundle, organizationId);\n const admin = await loadVerifiedAdminsPolicy({\n adminGroupId: descriptor.adminGroupId,\n mayRefetchDirectory,\n expectedHead: requireOrganizationGroupHead(\n descriptor,\n descriptor.adminGroupId,\n ),\n execSql: input.execSql,\n getCurrentPrincipalPolicy: input.getCurrentPrincipalPolicy,\n resolveTrustedUserIdentity: input.resolveTrustedUserIdentity,\n });\n if (!admin) {\n return null;\n }\n\n const verified: VerifiedExternalAdminPolicy = {\n adminBundle: admin.bundle,\n adminGroupId: descriptor.adminGroupId,\n adminPolicy: admin.policy,\n bundle,\n descriptor,\n externalAuthority: organizationAdminExternalAuthority(admin.policy),\n memberGroupId: descriptor.memberGroupId,\n policy,\n signerUserIds: organizationAdminSignerUserIds(admin.policy),\n };\n await persistVerifiedPrincipalPolicyBundlesAtomically({\n entries: externalAdminPolicyPersistenceEntries(verified),\n execSql: input.execSql,\n organizationId,\n stillCurrent: input.stillCurrent,\n updatedAt: new Date().toISOString(),\n });\n return verified;\n}\n\nexport async function loadOrganizationExternalAdminPolicy(\n input: ExternalAdminPolicyInput,\n): Promise<VerifiedExternalAdminPolicy | null> {\n const { organizationId } = input;\n if (!organizationId) {\n return null;\n }\n try {\n try {\n return await loadExternalAdminPolicyOnce(input, organizationId, true);\n } catch (error) {\n if (!(error instanceof AdminsHeadAdvanced)) throw error;\n return await loadExternalAdminPolicyOnce(input, organizationId, false);\n }\n } catch (error) {\n if (error instanceof KeyingVerificationError) {\n throw error;\n }\n return null;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"externalAdminPolicy.js","sourceRoot":"","sources":["externalAdminPolicy.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n KeyingVerificationError,\n type PrincipalPolicyExternalAuthority,\n type VerifiedPrincipalPolicy,\n verifyPrincipalPolicyBundle,\n} from \"@tearleads/crypto\";\nimport type { PrincipalPolicyBundleResponse } from \"@tearleads/validators/response\";\nimport { persistVerifiedPrincipalPolicyBundlesAtomically } from \"../../data/persistence/keyingCheckpointAdvancePersistence\";\nimport { loadPrincipalPolicyCheckpoint } from \"../../data/persistence/keyingCheckpointPersistence\";\nimport {\n type OrganizationAuthorityDescriptor,\n parseOrganizationAuthorityDescriptor,\n previousStatesIncludeHead,\n principalHeadMatchesReference,\n requireOrganizationGroupHead,\n} from \"../../data/principals/organizationAuthorityDescriptor\";\nimport {\n organizationAdminExternalAuthority,\n organizationAdminSignerUserIds,\n principalPolicyReferenceFromBundle,\n verifyOrganizationAdminPolicy,\n} from \"../../data/principals/principalPolicyAdminSigners\";\nimport type { ExecSql } from \"../../data/sqlite/sqlSchema\";\nimport type { TrustedUserIdentityResolver } from \"../../data/trustedUserIdentity\";\nimport type { CurrentPrincipalPolicyReader } from \"./currentPrincipalPolicyReader\";\nimport {\n collectPrincipalPolicySignerPublicKeys,\n type PrincipalPolicySignerPublicKeyLoadErrorCode,\n} from \"./policyVerification\";\n\nexport interface VerifiedExternalAdminPolicy {\n readonly adminBundle: PrincipalPolicyBundleResponse;\n readonly adminGroupId: string;\n readonly adminPolicy: VerifiedPrincipalPolicy;\n readonly bundle: PrincipalPolicyBundleResponse;\n readonly descriptor: OrganizationAuthorityDescriptor;\n readonly memberGroupId: string;\n readonly policy: VerifiedPrincipalPolicy;\n readonly externalAuthority: PrincipalPolicyExternalAuthority;\n readonly signerUserIds: readonly string[];\n}\n\nexport function externalAdminPolicyPersistenceEntries(\n authority: VerifiedExternalAdminPolicy,\n): ReadonlyArray<{\n readonly bundle: PrincipalPolicyBundleResponse;\n readonly policy: VerifiedPrincipalPolicy;\n}> {\n return [\n { bundle: authority.bundle, policy: authority.policy },\n { bundle: authority.adminBundle, policy: authority.adminPolicy },\n ];\n}\n\nfunction assertAdminsPolicyShape(policy: VerifiedPrincipalPolicy): void {\n if (\n (policy.history ?? [{ projection: policy.projection }]).some(\n (entry) =>\n entry.projection.length === 0 ||\n entry.projection.some((member) => member.role !== \"admin\"),\n )\n ) {\n throw new KeyingVerificationError(\n \"invalid_shape\",\n \"reserved Admins policy must contain only direct admin users\",\n );\n }\n}\n\n/**\n * A signer the caller cannot resolve is a cache miss, but a resolved signer\n * whose trusted key differs from the one the policy signed with is a\n * verification failure, as on every other policy path (#2365 finding 23).\n */\nfunction signerKeyLoadFailure(\n error: PrincipalPolicySignerPublicKeyLoadErrorCode,\n): null {\n if (error === \"fingerprint-mismatch\") {\n throw new KeyingVerificationError(\n \"signer_mismatch\",\n \"external admin policy signer key fingerprint mismatch\",\n );\n }\n return null;\n}\n\nasync function verifyOrganizationPolicy(input: {\n readonly bundle: PrincipalPolicyBundleResponse;\n readonly execSql: ExecSql;\n readonly organizationId: string;\n readonly resolveTrustedUserIdentity: TrustedUserIdentityResolver;\n}): Promise<VerifiedPrincipalPolicy | null> {\n const localCheckpoint = await loadPrincipalPolicyCheckpoint(\n input.execSql,\n \"organization\",\n input.organizationId,\n );\n const signerPublicKeys = await collectPrincipalPolicySignerPublicKeys({\n bundle: input.bundle,\n resolveTrustedUserIdentity: input.resolveTrustedUserIdentity,\n });\n if (\"error\" in signerPublicKeys) {\n return signerKeyLoadFailure(signerPublicKeys.error);\n }\n const verified = await verifyOrganizationAdminPolicy({\n bundle: input.bundle,\n localCheckpoint,\n organizationId: input.organizationId,\n signerPublicKeys: signerPublicKeys.signerPublicKeys,\n });\n if (!verified.ok) {\n throw verified.error;\n }\n return verified.value;\n}\n\nfunction parseScopedAuthorityDescriptor(\n bundle: PrincipalPolicyBundleResponse,\n organizationId: string,\n): OrganizationAuthorityDescriptor {\n let descriptor: OrganizationAuthorityDescriptor;\n try {\n descriptor = parseOrganizationAuthorityDescriptor(\n bundle.currentPayload.ciphertext,\n );\n } catch {\n throw new KeyingVerificationError(\n \"invalid_shape\",\n \"organization authority descriptor is invalid\",\n );\n }\n if (descriptor.organizationId !== organizationId) {\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"organization authority descriptor scope does not match\",\n );\n }\n return descriptor;\n}\n\n/**\n * The organization and its Admins group are separate reads, so an honest\n * Admins commit between them serves a chain that extends the head the\n * directory cites: a stale directory, not tampering (#2365 finding 22). The\n * claim is checked before any signer is trusted, so it is unverified and buys\n * only one organization refetch; a disagreement after that is an incident.\n */\nclass AdminsHeadAdvanced extends Error {}\n\nasync function loadVerifiedAdminsPolicy(input: {\n readonly adminGroupId: string;\n readonly expectedHead: ReturnType<typeof requireOrganizationGroupHead>;\n readonly mayRefetchDirectory: boolean;\n readonly execSql: ExecSql;\n readonly currentPolicyReader: CurrentPrincipalPolicyReader;\n readonly resolveTrustedUserIdentity: TrustedUserIdentityResolver;\n}): Promise<{\n readonly bundle: PrincipalPolicyBundleResponse;\n readonly policy: VerifiedPrincipalPolicy;\n} | null> {\n const bundle = await input.currentPolicyReader.getCurrentPrincipalPolicy(\n \"group\",\n input.adminGroupId,\n );\n if (!bundle) {\n return null;\n }\n if (\n !principalHeadMatchesReference(\n principalPolicyReferenceFromBundle(bundle),\n input.expectedHead,\n )\n ) {\n if (\n input.mayRefetchDirectory &&\n previousStatesIncludeHead(bundle, input.expectedHead)\n ) {\n throw new AdminsHeadAdvanced();\n }\n throw new KeyingVerificationError(\n \"hash_mismatch\",\n \"reserved Admins policy does not match the signed organization directory\",\n );\n }\n const localCheckpoint = await loadPrincipalPolicyCheckpoint(\n input.execSql,\n \"group\",\n input.adminGroupId,\n );\n const signerPublicKeys = await collectPrincipalPolicySignerPublicKeys({\n bundle,\n resolveTrustedUserIdentity: input.resolveTrustedUserIdentity,\n });\n if (\"error\" in signerPublicKeys) {\n return signerKeyLoadFailure(signerPublicKeys.error);\n }\n const verified = await verifyPrincipalPolicyBundle({\n bundle,\n expectedReference: input.expectedHead,\n localCheckpoint,\n signerPublicKeys: signerPublicKeys.signerPublicKeys,\n });\n if (!verified.ok) {\n throw verified.error;\n }\n if (\n verified.value.principalType !== \"group\" ||\n verified.value.principalId !== input.adminGroupId\n ) {\n throw new KeyingVerificationError(\n \"object_mismatch\",\n \"reserved Admins policy target does not match\",\n );\n }\n assertAdminsPolicyShape(verified.value);\n return { bundle, policy: verified.value };\n}\n\ninterface ExternalAdminPolicyInput {\n readonly currentPolicyReader: CurrentPrincipalPolicyReader;\n readonly execSql: ExecSql;\n readonly organizationId: string | null | undefined;\n readonly resolveTrustedUserIdentity: TrustedUserIdentityResolver;\n readonly stillCurrent?: (() => boolean) | undefined;\n}\n\nasync function loadExternalAdminPolicyOnce(\n input: ExternalAdminPolicyInput,\n organizationId: string,\n mayRefetchDirectory: boolean,\n): Promise<VerifiedExternalAdminPolicy | null> {\n const bundle = await input.currentPolicyReader.getCurrentPrincipalPolicy(\n \"organization\",\n organizationId,\n );\n if (!bundle) {\n return null;\n }\n const policy = await verifyOrganizationPolicy({\n bundle,\n execSql: input.execSql,\n organizationId,\n resolveTrustedUserIdentity: input.resolveTrustedUserIdentity,\n });\n if (!policy) {\n return null;\n }\n const descriptor = parseScopedAuthorityDescriptor(bundle, organizationId);\n const admin = await loadVerifiedAdminsPolicy({\n adminGroupId: descriptor.adminGroupId,\n mayRefetchDirectory,\n expectedHead: requireOrganizationGroupHead(\n descriptor,\n descriptor.adminGroupId,\n ),\n execSql: input.execSql,\n currentPolicyReader: input.currentPolicyReader,\n resolveTrustedUserIdentity: input.resolveTrustedUserIdentity,\n });\n if (!admin) {\n return null;\n }\n\n const verified: VerifiedExternalAdminPolicy = {\n adminBundle: admin.bundle,\n adminGroupId: descriptor.adminGroupId,\n adminPolicy: admin.policy,\n bundle,\n descriptor,\n externalAuthority: organizationAdminExternalAuthority(admin.policy),\n memberGroupId: descriptor.memberGroupId,\n policy,\n signerUserIds: organizationAdminSignerUserIds(admin.policy),\n };\n await persistVerifiedPrincipalPolicyBundlesAtomically({\n entries: externalAdminPolicyPersistenceEntries(verified),\n execSql: input.execSql,\n organizationId,\n stillCurrent: input.stillCurrent,\n updatedAt: new Date().toISOString(),\n });\n return verified;\n}\n\nexport async function loadOrganizationExternalAdminPolicy(\n input: ExternalAdminPolicyInput,\n): Promise<VerifiedExternalAdminPolicy | null> {\n const { organizationId } = input;\n if (!organizationId) {\n return null;\n }\n try {\n try {\n return await loadExternalAdminPolicyOnce(input, organizationId, true);\n } catch (error) {\n if (!(error instanceof AdminsHeadAdvanced)) throw error;\n return await loadExternalAdminPolicyOnce(input, organizationId, false);\n }\n } catch (error) {\n if (error instanceof KeyingVerificationError) {\n throw error;\n }\n return null;\n }\n}\n"]}
|
|
@@ -2,9 +2,10 @@ import type { PrincipalPolicyBundleResponse, ReferencedPrincipalStateResponse }
|
|
|
2
2
|
import type { SecurityIncidentReporter } from "../../data/securityIncidents.js";
|
|
3
3
|
import type { ExecSql } from "../../data/sqlite/sqlSchema.js";
|
|
4
4
|
import type { TrustedUserIdentityResolver } from "../../data/trustedUserIdentity/index.js";
|
|
5
|
+
import type { CurrentPrincipalPolicyReader } from "./currentPrincipalPolicyReader.js";
|
|
5
6
|
export interface CacheReferencedPrincipalPoliciesOptions {
|
|
7
|
+
currentPolicyReader: CurrentPrincipalPolicyReader;
|
|
6
8
|
execSql: ExecSql;
|
|
7
|
-
getCurrentPrincipalPolicy: (principalType: "group" | "organization", principalId: string) => Promise<PrincipalPolicyBundleResponse | null>;
|
|
8
9
|
log?: (message: string) => void;
|
|
9
10
|
organizationId: string;
|
|
10
11
|
reportSecurityIncident: SecurityIncidentReporter;
|
|
@@ -16,4 +17,4 @@ export interface CachePrincipalPolicyBundlesOptions extends Omit<CacheReferenced
|
|
|
16
17
|
bundles: ReadonlyArray<PrincipalPolicyBundleResponse> | undefined;
|
|
17
18
|
}
|
|
18
19
|
export declare function cacheReferencedPrincipalPolicies(input: CacheReferencedPrincipalPoliciesOptions): Promise<void>;
|
|
19
|
-
export declare function cachePrincipalPolicyBundles({ bundles,
|
|
20
|
+
export declare function cachePrincipalPolicyBundles({ bundles, currentPolicyReader, execSql, log, organizationId, reportSecurityIncident, resolveTrustedUserIdentity, stillCurrent, }: CachePrincipalPolicyBundlesOptions): Promise<void>;
|
|
@@ -29,7 +29,7 @@ function dedupePrincipalPolicyBundles(bundles) {
|
|
|
29
29
|
}
|
|
30
30
|
return Array.from(bundlesByPrincipal.values());
|
|
31
31
|
}
|
|
32
|
-
async function cacheReferencedPrincipalPolicy(execSql,
|
|
32
|
+
async function cacheReferencedPrincipalPolicy(execSql, reader, reference, resolveTrustedUserIdentity, log, loadExternalAdminPolicy, organizationId, stillCurrent, loadDirectory, fresh) {
|
|
33
33
|
const localCheckpoint = await loadPrincipalPolicyCheckpoint(execSql, reference.principalType, reference.principalId);
|
|
34
34
|
// Only null is a recoverable local miss. Integrity failures remain typed and
|
|
35
35
|
// must escape rather than being hidden by a canonical network retry.
|
|
@@ -37,7 +37,7 @@ async function cacheReferencedPrincipalPolicy(execSql, getCurrentPrincipalPolicy
|
|
|
37
37
|
? null
|
|
38
38
|
: await loadPrincipalPolicyBundleForReference(execSql, reference, localCheckpoint);
|
|
39
39
|
let bundle = cachedBundle ??
|
|
40
|
-
(await getCurrentPrincipalPolicy(reference.principalType, reference.principalId));
|
|
40
|
+
(await reader.getCurrentPrincipalPolicy(reference.principalType, reference.principalId));
|
|
41
41
|
if (!bundle) {
|
|
42
42
|
log?.(`Principal policy cache: failed to fetch ${getReferencedPrincipalKey(reference)}`);
|
|
43
43
|
return [];
|
|
@@ -64,7 +64,7 @@ async function cacheReferencedPrincipalPolicy(execSql, getCurrentPrincipalPolicy
|
|
|
64
64
|
loadDirectory,
|
|
65
65
|
organizationId,
|
|
66
66
|
reloadBundle: cachedBundle
|
|
67
|
-
? () => getCurrentPrincipalPolicy("group", reference.principalId)
|
|
67
|
+
? () => reader.getCurrentPrincipalPolicy("group", reference.principalId)
|
|
68
68
|
: null,
|
|
69
69
|
});
|
|
70
70
|
if (!scoped) {
|
|
@@ -151,8 +151,8 @@ async function runPrincipalPolicyCache(input) {
|
|
|
151
151
|
let externalAdminPolicy = null;
|
|
152
152
|
const loadExternalAdminPolicy = () => {
|
|
153
153
|
externalAdminPolicy ??= loadOrganizationExternalAdminPolicy({
|
|
154
|
+
currentPolicyReader: input.currentPolicyReader,
|
|
154
155
|
execSql: input.execSql,
|
|
155
|
-
getCurrentPrincipalPolicy: input.getCurrentPrincipalPolicy,
|
|
156
156
|
organizationId: input.organizationId,
|
|
157
157
|
resolveTrustedUserIdentity: input.resolveTrustedUserIdentity,
|
|
158
158
|
stillCurrent: input.stillCurrent,
|
|
@@ -197,12 +197,12 @@ async function runPrincipalPolicyCache(input) {
|
|
|
197
197
|
return [];
|
|
198
198
|
}
|
|
199
199
|
}
|
|
200
|
-
async function loadReferencedPrincipalPolicies({
|
|
200
|
+
async function loadReferencedPrincipalPolicies({ currentPolicyReader, execSql, log, organizationId, reportSecurityIncident, references, resolveTrustedUserIdentity, stillCurrent, }) {
|
|
201
201
|
return runPrincipalPolicyCache({
|
|
202
|
-
cacheItem: (reference, loadExternalAdminPolicy, loadDirectory, fresh) => cacheReferencedPrincipalPolicy(execSql,
|
|
202
|
+
cacheItem: (reference, loadExternalAdminPolicy, loadDirectory, fresh) => cacheReferencedPrincipalPolicy(execSql, currentPolicyReader, reference, resolveTrustedUserIdentity, log, loadExternalAdminPolicy, organizationId, stillCurrent, loadDirectory, fresh),
|
|
203
|
+
currentPolicyReader,
|
|
203
204
|
dedupe: dedupeReferencedPrincipalStates,
|
|
204
205
|
execSql,
|
|
205
|
-
getCurrentPrincipalPolicy,
|
|
206
206
|
itemKey: getReferencedPrincipalKey,
|
|
207
207
|
items: references,
|
|
208
208
|
log,
|
|
@@ -215,7 +215,7 @@ async function loadReferencedPrincipalPolicies({ execSql, getCurrentPrincipalPol
|
|
|
215
215
|
export async function cacheReferencedPrincipalPolicies(input) {
|
|
216
216
|
await loadReferencedPrincipalPolicies(input);
|
|
217
217
|
}
|
|
218
|
-
export async function cachePrincipalPolicyBundles({ bundles,
|
|
218
|
+
export async function cachePrincipalPolicyBundles({ bundles, currentPolicyReader, execSql, log, organizationId, reportSecurityIncident, resolveTrustedUserIdentity, stillCurrent, }) {
|
|
219
219
|
await runPrincipalPolicyCache({
|
|
220
220
|
cacheItem: (bundle, loadExternalAdminPolicy, loadDirectory) => cachePrincipalPolicyBundle({
|
|
221
221
|
bundle,
|
|
@@ -227,9 +227,9 @@ export async function cachePrincipalPolicyBundles({ bundles, execSql, getCurrent
|
|
|
227
227
|
resolveTrustedUserIdentity,
|
|
228
228
|
stillCurrent,
|
|
229
229
|
}),
|
|
230
|
+
currentPolicyReader,
|
|
230
231
|
dedupe: dedupePrincipalPolicyBundles,
|
|
231
232
|
execSql,
|
|
232
|
-
getCurrentPrincipalPolicy,
|
|
233
233
|
itemKey: getBundlePrincipalKey,
|
|
234
234
|
items: bundles,
|
|
235
235
|
log,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"policyCache.js","sourceRoot":"","sources":["policyCache.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,sCAAsC,EAAE,MAAM,yCAAyC,CAAC;AACjG,OAAO,EACL,uCAAuC,EACvC,8BAA8B,GAC/B,MAAM,+CAA+C,CAAC;AACvD,OAAO,EAAE,+BAA+B,EAAE,MAAM,8DAA8D,CAAC;AAC/G,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AACnG,OAAO,EAAE,2BAA2B,EAAE,MAAM,mDAAmD,CAAC;AAChG,OAAO,EAAE,qCAAqC,EAAE,MAAM,4DAA4D,CAAC;AACnH,OAAO,EAAE,kCAAkC,EAAE,MAAM,mDAAmD,CAAC;AAIvG,OAAO,EACL,qCAAqC,EACrC,mCAAmC,GAEpC,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,kCAAkC,EAClC,gCAAgC,GACjC,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,6BAA6B,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,qCAAqC,EAAE,MAAM,kCAAkC,CAAC;AACzF,OAAO,EACL,2BAA2B,EAC3B,4BAA4B,GAG7B,MAAM,oCAAoC,CAAC;AAqB5C,SAAS,yBAAyB,CAChC,SAA2C;IAE3C,OAAO,GAAG,SAAS,CAAC,aAAa,IAAI,SAAS,CAAC,WAAW,EAAE,CAAC;AAC/D,CAAC;AAED,SAAS,qBAAqB,CAAC,MAAqC;IAClE,OAAO,GAAG,MAAM,CAAC,YAAY,CAAC,aAAa,IAAI,MAAM,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC;AACnF,CAAC;AAED,SAAS,4BAA4B,CACnC,OAAqD;IAErD,MAAM,kBAAkB,GAAG,IAAI,GAAG,EAAyC,CAAC;IAE5E,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,GAAG,GAAG,qBAAqB,CAAC,MAAM,CAAC,CAAC;QAC1C,MAAM,QAAQ,GAAG,kBAAkB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC7C,IACE,CAAC,QAAQ;YACT,MAAM,CAAC,YAAY,CAAC,OAAO,GAAG,QAAQ,CAAC,YAAY,CAAC,OAAO,EAC3D,CAAC;YACD,kBAAkB,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,MAAM,EAAE,CAAC,CAAC;AACjD,CAAC;AAED,KAAK,UAAU,8BAA8B,CAC3C,OAAgB,EAChB,yBAA+F,EAC/F,SAA2C,EAC3C,0BAAuD,EACvD,GAA4C,EAC5C,uBAA0E,EAC1E,cAAsB,EACtB,YAAyC,EACzC,aAAoC,EACpC,KAAc;IAEd,MAAM,eAAe,GAAG,MAAM,6BAA6B,CACzD,OAAO,EACP,SAAS,CAAC,aAAa,EACvB,SAAS,CAAC,WAAW,CACtB,CAAC;IACF,6EAA6E;IAC7E,qEAAqE;IACrE,MAAM,YAAY,GAAG,KAAK;QACxB,CAAC,CAAC,IAAI;QACN,CAAC,CAAC,MAAM,qCAAqC,CACzC,OAAO,EACP,SAAS,EACT,eAAe,CAChB,CAAC;IACN,IAAI,MAAM,GACR,YAAY;QACZ,CAAC,MAAM,yBAAyB,CAC9B,SAAS,CAAC,aAAa,EACvB,SAAS,CAAC,WAAW,CACtB,CAAC,CAAC;IACL,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,GAAG,EAAE,CACH,2CAA2C,yBAAyB,CAAC,SAAS,CAAC,EAAE,CAClF,CAAC;QACF,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,UAAU,GAAG,MAAM,qCAAqC,CAAC;QAC3D,MAAM;QACN,uBAAuB;QACvB,eAAe;QACf,SAAS;QACT,0BAA0B;KAC3B,CAAC,CAAC;IACH,IAAI,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC;QACnB,MAAM,UAAU,CAAC,KAAK,CAAC;IACzB,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,6BAA6B,CAAC;QACjD,MAAM;QACN,UAAU;QACV,eAAe,EAAE;YACf,uBAAuB;YACvB,eAAe;YACf,SAAS;YACT,0BAA0B;SAC3B;QACD,aAAa;QACb,cAAc;QACd,YAAY,EAAE,YAAY;YACxB,CAAC,CAAC,GAAG,EAAE,CAAC,yBAAyB,CAAC,OAAO,EAAE,SAAS,CAAC,WAAW,CAAC;YACjE,CAAC,CAAC,IAAI;KACT,CAAC,CAAC;IACH,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,GAAG,EAAE,CACH,wEAAwE,yBAAyB,CAAC,SAAS,CAAC,EAAE,CAC/G,CAAC;QACF,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IACvB,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;IAC/B,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;IACnC,MAAM,eAAe,GAAG,UAAU,CAAC,mBAAmB;QACpD,CAAC,CAAC,qCAAqC,CACnC,UAAU,CAAC,mBAAmB,CAC/B,CAAC,MAAM,CACN,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,SAAS,IAAI,KAAK,CAAC,MAAM,CAAC,aAAa,KAAK,cAAc,CACvE;QACH,CAAC,CAAC,EAAE,CAAC;IACP,MAAM,gBAAgB,GAAG,SAAS;QAChC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,MAAM,EAAE,CAAC;QAC1D,CAAC,CAAC,EAAE,CAAC;IACP,MAAM,kCAAkC,CAAC;QACvC,OAAO,EAAE;YACP,GAAG,eAAe;YAClB,GAAG,gBAAgB;YACnB,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE;SACtC;QACD,OAAO;QACP,cAAc;QACd,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,YAAY;KACb,CAAC,CAAC;IACH,OAAO,CAAC,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;AAC7E,CAAC;AAED,KAAK,UAAU,0BAA0B,CAAC,KASzC;IACC,MAAM,SAAS,GAAG,kCAAkC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACnE,6EAA6E;IAC7E,4EAA4E;IAC5E,MAAM,eAAe,GAAG,MAAM,6BAA6B,CACzD,KAAK,CAAC,OAAO,EACb,SAAS,CAAC,aAAa,EACvB,SAAS,CAAC,WAAW,CACtB,CAAC;IACF,MAAM,UAAU,GAAG,MAAM,qCAAqC,CAAC;QAC7D,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,uBAAuB,EAAE,KAAK,CAAC,uBAAuB;QACtD,eAAe;QACf,SAAS;QACT,0BAA0B,EAAE,KAAK,CAAC,0BAA0B;KAC7D,CAAC,CAAC;IACH,IAAI,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC;QACnB,MAAM,UAAU,CAAC,KAAK,CAAC;IACzB,CAAC;IAED,IAAI,SAAS,GAAmC,IAAI,CAAC;IACrD,IAAI,SAAS,CAAC,aAAa,KAAK,OAAO,EAAE,CAAC;QACxC,SAAS,GAAG,MAAM,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAC7C,IAAI,CAAC,4BAA4B,CAAC,SAAS,EAAE,UAAU,CAAC,MAAM,EAAE,SAAS,CAAC;YACxE,SAAS,GAAG,MAAM,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;QAC9C,IACE,CAAC,4BAA4B,CAAC,SAAS,EAAE,UAAU,CAAC,MAAM,EAAE,SAAS,CAAC,EACtE,CAAC;YACD,KAAK,CAAC,GAAG,EAAE,CACT,qFAAqF,CACtF,CAAC;YACF,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;SAAM,IAAI,SAAS,CAAC,WAAW,KAAK,KAAK,CAAC,cAAc,EAAE,CAAC;QAC1D,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,eAAe,GAAG,UAAU,CAAC,mBAAmB;QACpD,CAAC,CAAC,qCAAqC,CACnC,UAAU,CAAC,mBAAmB,CAC/B,CAAC,MAAM,CACN,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,SAAS,IAAI,KAAK,CAAC,MAAM,CAAC,aAAa,KAAK,cAAc,CACvE;QACH,CAAC,CAAC,EAAE,CAAC;IACP,MAAM,gBAAgB,GAAG,SAAS;QAChC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,MAAM,EAAE,CAAC;QAC1D,CAAC,CAAC,EAAE,CAAC;IACP,MAAM,kCAAkC,CAAC;QACvC,OAAO,EAAE;YACP,GAAG,eAAe;YAClB,GAAG,gBAAgB;YACnB,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE;SACpD;QACD,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,cAAc,EAAE,KAAK,CAAC,cAAc;QACpC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,YAAY,EAAE,KAAK,CAAC,YAAY;KACjC,CAAC,CAAC;IACH,OAAO,CAAC,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;AAC7E,CAAC;AAED,KAAK,UAAU,uBAAuB,CAAe,KAiBpD;IACC,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7C,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,CAAC;QACH,MAAM,2BAA2B,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACjD,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC9C,MAAM,aAAa,GAAG,2BAA2B,CAAC,KAAK,CAAC,CAAC;QACzD,IAAI,mBAAmB,GACrB,IAAI,CAAC;QACP,MAAM,uBAAuB,GAAG,GAAG,EAAE;YACnC,mBAAmB,KAAK,mCAAmC,CAAC;gBAC1D,OAAO,EAAE,KAAK,CAAC,OAAO;gBACtB,yBAAyB,EAAE,KAAK,CAAC,yBAAyB;gBAC1D,cAAc,EAAE,KAAK,CAAC,cAAc;gBAEpC,0BAA0B,EAAE,KAAK,CAAC,0BAA0B;gBAC5D,YAAY,EAAE,KAAK,CAAC,YAAY;aACjC,CAAC,CAAC;YACH,OAAO,mBAAmB,CAAC;QAC7B,CAAC,CAAC;QAEF,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAC/B,WAAW,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;YAC7B,IAAI,CAAC;gBACH,OAAO,MAAM,gCAAgC,CAAC,CAAC,KAAK,EAAE,EAAE;oBACtD,MAAM,eAAe,GAAG,2BAA2B,CAAC,KAAK,CAAC,CAAC;oBAC3D,IAAI,iBAAiB,GACnB,IAAI,CAAC;oBACP,OAAO,KAAK,CAAC,SAAS,CACpB,IAAI,EACJ,KAAK;wBACH,CAAC,CAAC,GAAG,EAAE,CACH,CAAC,iBAAiB;4BAChB,mCAAmC,CAAC,KAAK,CAAC,CAAC;wBACjD,CAAC,CAAC,uBAAuB,EAC3B,KAAK,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,aAAa,EACnD,KAAK,CACN,CAAC;gBACJ,CAAC,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,sCAAsC,CAAC,KAAK,CAAC;oBAAE,OAAO,EAAE,CAAC;gBAC7D,MAAM,uCAAuC,CAC3C,KAAK,EACL,KAAK,CAAC,sBAAsB,EAC5B;oBACE,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;oBAC7B,UAAU,EAAE,WAAW;oBACvB,SAAS,EAAE,wBAAwB;oBACnC,cAAc,EAAE,KAAK,CAAC,cAAc;iBACrC,CACF,CAAC;gBACF,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;gBACpC,KAAK,CAAC,GAAG,EAAE,CACT,2CAA2C,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,OAAO,EAAE,CAC7E,CAAC;gBACF,OAAO,EAAE,CAAC;YACZ,CAAC;QACH,CAAC,CAAC,CACH,CAAC;QACF,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC;IACxB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,sCAAsC,CAAC,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QAC7D,0EAA0E;QAC1E,uCAAuC;QACvC,8BAA8B,CAAC,KAAK,CAAC,CAAC;QACtC,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;QACpC,KAAK,CAAC,GAAG,EAAE,CACT,uDAAuD,OAAO,EAAE,CACjE,CAAC;QACF,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,KAAK,UAAU,+BAA+B,CAAC,EAC7C,OAAO,EACP,yBAAyB,EACzB,GAAG,EACH,cAAc,EACd,sBAAsB,EACtB,UAAU,EACV,0BAA0B,EAC1B,YAAY,GAC4B;IAGxC,OAAO,uBAAuB,CAAC;QAC7B,SAAS,EAAE,CAAC,SAAS,EAAE,uBAAuB,EAAE,aAAa,EAAE,KAAK,EAAE,EAAE,CACtE,8BAA8B,CAC5B,OAAO,EACP,yBAAyB,EACzB,SAAS,EACT,0BAA0B,EAC1B,GAAG,EACH,uBAAuB,EACvB,cAAc,EACd,YAAY,EACZ,aAAa,EACb,KAAK,CACN;QACH,MAAM,EAAE,+BAA+B;QACvC,OAAO;QACP,yBAAyB;QACzB,OAAO,EAAE,yBAAyB;QAClC,KAAK,EAAE,UAAU;QACjB,GAAG;QACH,cAAc;QAEd,sBAAsB;QACtB,0BAA0B;QAC1B,YAAY;KACb,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gCAAgC,CACpD,KAA8C;IAE9C,MAAM,+BAA+B,CAAC,KAAK,CAAC,CAAC;AAC/C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAAC,EAChD,OAAO,EACP,OAAO,EACP,yBAAyB,EACzB,GAAG,EACH,cAAc,EACd,sBAAsB,EACtB,0BAA0B,EAC1B,YAAY,GACuB;IACnC,MAAM,uBAAuB,CAAC;QAC5B,SAAS,EAAE,CAAC,MAAM,EAAE,uBAAuB,EAAE,aAAa,EAAE,EAAE,CAC5D,0BAA0B,CAAC;YACzB,MAAM;YACN,OAAO;YACP,uBAAuB;YACvB,aAAa;YACb,GAAG;YACH,cAAc;YACd,0BAA0B;YAC1B,YAAY;SACb,CAAC;QACJ,MAAM,EAAE,4BAA4B;QACpC,OAAO;QACP,yBAAyB;QACzB,OAAO,EAAE,qBAAqB;QAC9B,KAAK,EAAE,OAAO;QACd,GAAG;QACH,cAAc;QAEd,sBAAsB;QACtB,0BAA0B;QAC1B,YAAY;KACb,CAAC,CAAC;AACL,CAAC","sourcesContent":["import type { VerifiedPrincipalPolicy } from \"@tearleads/crypto\";\nimport type {\n PrincipalPolicyBundleResponse,\n ReferencedPrincipalStateResponse,\n} from \"@tearleads/validators/response\";\nimport { errorMessage } from \"../../data/errorMessage\";\nimport { isProjectionVerificationCancelledError } from \"../../data/keyingProjectionVerification\";\nimport {\n reportAndRethrowKeyingVerificationError,\n rethrowKeyingVerificationError,\n} from \"../../data/keyingProjectionVerification/error\";\nimport { dedupeReferencedPrincipalStates } from \"../../data/keyingProjectionVerification/principalPolicyCache\";\nimport { loadPrincipalPolicyCheckpoint } from \"../../data/persistence/keyingCheckpointPersistence\";\nimport { ensurePrincipalPolicyTables } from \"../../data/persistence/principalPolicyPersistence\";\nimport { loadPrincipalPolicyBundleForReference } from \"../../data/persistence/principalPolicyReferencePersistence\";\nimport { principalPolicyReferenceFromBundle } from \"../../data/principals/principalPolicyAdminSigners\";\nimport type { SecurityIncidentReporter } from \"../../data/securityIncidents\";\nimport type { ExecSql } from \"../../data/sqlite/sqlSchema\";\nimport type { TrustedUserIdentityResolver } from \"../../data/trustedUserIdentity\";\nimport {\n externalAdminPolicyPersistenceEntries,\n loadOrganizationExternalAdminPolicy,\n type VerifiedExternalAdminPolicy,\n} from \"./externalAdminPolicy\";\nimport {\n persistPrincipalPolicyCacheEntries,\n retryPrincipalPolicyCacheAdvance,\n} from \"./principalPolicyCacheAdvance\";\nimport { scopeReferencedPolicyForCache } from \"./principalPolicyCacheScope\";\nimport { validatePrincipalPolicyBundleForCache } from \"./principalPolicyCacheValidation\";\nimport {\n createPolicyDirectoryLoader,\n directoryBindsGroupReference,\n type PolicyDirectoryLoader,\n type VerifiedPolicyDirectory,\n} from \"./principalPolicyOrganizationScope\";\n\nexport interface CacheReferencedPrincipalPoliciesOptions {\n execSql: ExecSql;\n getCurrentPrincipalPolicy: (\n principalType: \"group\" | \"organization\",\n principalId: string,\n ) => Promise<PrincipalPolicyBundleResponse | null>;\n log?: (message: string) => void;\n organizationId: string;\n reportSecurityIncident: SecurityIncidentReporter;\n references: ReadonlyArray<ReferencedPrincipalStateResponse> | undefined;\n resolveTrustedUserIdentity: TrustedUserIdentityResolver;\n stillCurrent?: (() => boolean) | undefined;\n}\n\nexport interface CachePrincipalPolicyBundlesOptions\n extends Omit<CacheReferencedPrincipalPoliciesOptions, \"references\"> {\n bundles: ReadonlyArray<PrincipalPolicyBundleResponse> | undefined;\n}\n\nfunction getReferencedPrincipalKey(\n reference: ReferencedPrincipalStateResponse,\n): string {\n return `${reference.principalType}:${reference.principalId}`;\n}\n\nfunction getBundlePrincipalKey(bundle: PrincipalPolicyBundleResponse): string {\n return `${bundle.currentState.principalType}:${bundle.currentState.principalId}`;\n}\n\nfunction dedupePrincipalPolicyBundles(\n bundles: ReadonlyArray<PrincipalPolicyBundleResponse>,\n): PrincipalPolicyBundleResponse[] {\n const bundlesByPrincipal = new Map<string, PrincipalPolicyBundleResponse>();\n\n for (const bundle of bundles) {\n const key = getBundlePrincipalKey(bundle);\n const previous = bundlesByPrincipal.get(key);\n if (\n !previous ||\n bundle.currentState.version > previous.currentState.version\n ) {\n bundlesByPrincipal.set(key, bundle);\n }\n }\n\n return Array.from(bundlesByPrincipal.values());\n}\n\nasync function cacheReferencedPrincipalPolicy(\n execSql: ExecSql,\n getCurrentPrincipalPolicy: CacheReferencedPrincipalPoliciesOptions[\"getCurrentPrincipalPolicy\"],\n reference: ReferencedPrincipalStateResponse,\n resolveTrustedUserIdentity: TrustedUserIdentityResolver,\n log: ((message: string) => void) | undefined,\n loadExternalAdminPolicy: () => Promise<VerifiedExternalAdminPolicy | null>,\n organizationId: string,\n stillCurrent: (() => boolean) | undefined,\n loadDirectory: PolicyDirectoryLoader,\n fresh: boolean,\n): Promise<VerifiedPrincipalPolicy[]> {\n const localCheckpoint = await loadPrincipalPolicyCheckpoint(\n execSql,\n reference.principalType,\n reference.principalId,\n );\n // Only null is a recoverable local miss. Integrity failures remain typed and\n // must escape rather than being hidden by a canonical network retry.\n const cachedBundle = fresh\n ? null\n : await loadPrincipalPolicyBundleForReference(\n execSql,\n reference,\n localCheckpoint,\n );\n let bundle =\n cachedBundle ??\n (await getCurrentPrincipalPolicy(\n reference.principalType,\n reference.principalId,\n ));\n if (!bundle) {\n log?.(\n `Principal policy cache: failed to fetch ${getReferencedPrincipalKey(reference)}`,\n );\n return [];\n }\n\n let validation = await validatePrincipalPolicyBundleForCache({\n bundle,\n loadExternalAdminPolicy,\n localCheckpoint,\n reference,\n resolveTrustedUserIdentity,\n });\n if (!validation.ok) {\n throw validation.error;\n }\n\n const scoped = await scopeReferencedPolicyForCache({\n bundle,\n validation,\n validationInput: {\n loadExternalAdminPolicy,\n localCheckpoint,\n reference,\n resolveTrustedUserIdentity,\n },\n loadDirectory,\n organizationId,\n reloadBundle: cachedBundle\n ? () => getCurrentPrincipalPolicy(\"group\", reference.principalId)\n : null,\n });\n if (!scoped) {\n log?.(\n `Principal policy cache: signed organization directory does not cover ${getReferencedPrincipalKey(reference)}`,\n );\n return [];\n }\n bundle = scoped.bundle;\n validation = scoped.validation;\n const directory = scoped.directory;\n const externalEntries = validation.externalAdminPolicy\n ? externalAdminPolicyPersistenceEntries(\n validation.externalAdminPolicy,\n ).filter(\n (entry) => !directory || entry.policy.principalType !== \"organization\",\n )\n : [];\n const directoryEntries = directory\n ? [{ bundle: directory.bundle, policy: directory.policy }]\n : [];\n await persistPrincipalPolicyCacheEntries({\n entries: [\n ...externalEntries,\n ...directoryEntries,\n { bundle, policy: validation.policy },\n ],\n execSql,\n organizationId,\n updatedAt: new Date().toISOString(),\n stillCurrent,\n });\n return [...externalEntries.map(({ policy }) => policy), validation.policy];\n}\n\nasync function cachePrincipalPolicyBundle(input: {\n readonly bundle: PrincipalPolicyBundleResponse;\n readonly execSql: ExecSql;\n readonly loadExternalAdminPolicy: () => Promise<VerifiedExternalAdminPolicy | null>;\n readonly log: ((message: string) => void) | undefined;\n readonly loadDirectory: PolicyDirectoryLoader;\n readonly organizationId: string;\n readonly resolveTrustedUserIdentity: TrustedUserIdentityResolver;\n readonly stillCurrent?: (() => boolean) | undefined;\n}): Promise<VerifiedPrincipalPolicy[]> {\n const reference = principalPolicyReferenceFromBundle(input.bundle);\n // The API supplied this bundle after rejecting a write, but local storage is\n // only updated after normal signature, signer, and checkpoint verification.\n const localCheckpoint = await loadPrincipalPolicyCheckpoint(\n input.execSql,\n reference.principalType,\n reference.principalId,\n );\n const validation = await validatePrincipalPolicyBundleForCache({\n bundle: input.bundle,\n loadExternalAdminPolicy: input.loadExternalAdminPolicy,\n localCheckpoint,\n reference,\n resolveTrustedUserIdentity: input.resolveTrustedUserIdentity,\n });\n if (!validation.ok) {\n throw validation.error;\n }\n\n let directory: VerifiedPolicyDirectory | null = null;\n if (reference.principalType === \"group\") {\n directory = await input.loadDirectory(false);\n if (!directoryBindsGroupReference(directory, validation.policy, reference))\n directory = await input.loadDirectory(true);\n if (\n !directoryBindsGroupReference(directory, validation.policy, reference)\n ) {\n input.log?.(\n \"Principal policy cache: signed organization directory does not cover supplied group\",\n );\n return [];\n }\n } else if (reference.principalId !== input.organizationId) {\n return [];\n }\n const externalEntries = validation.externalAdminPolicy\n ? externalAdminPolicyPersistenceEntries(\n validation.externalAdminPolicy,\n ).filter(\n (entry) => !directory || entry.policy.principalType !== \"organization\",\n )\n : [];\n const directoryEntries = directory\n ? [{ bundle: directory.bundle, policy: directory.policy }]\n : [];\n await persistPrincipalPolicyCacheEntries({\n entries: [\n ...externalEntries,\n ...directoryEntries,\n { bundle: input.bundle, policy: validation.policy },\n ],\n execSql: input.execSql,\n organizationId: input.organizationId,\n updatedAt: new Date().toISOString(),\n stillCurrent: input.stillCurrent,\n });\n return [...externalEntries.map(({ policy }) => policy), validation.policy];\n}\n\nasync function runPrincipalPolicyCache<Item, Result>(input: {\n readonly cacheItem: (\n item: Item,\n loadExternalAdminPolicy: () => Promise<VerifiedExternalAdminPolicy | null>,\n loadDirectory: PolicyDirectoryLoader,\n fresh: boolean,\n ) => Promise<readonly Result[]>;\n readonly dedupe: (items: ReadonlyArray<Item>) => Item[];\n readonly execSql: ExecSql;\n readonly getCurrentPrincipalPolicy: CacheReferencedPrincipalPoliciesOptions[\"getCurrentPrincipalPolicy\"];\n readonly itemKey: (item: Item) => string;\n readonly items: ReadonlyArray<Item> | undefined;\n readonly log: ((message: string) => void) | undefined;\n readonly organizationId: string;\n readonly reportSecurityIncident: SecurityIncidentReporter;\n readonly resolveTrustedUserIdentity: TrustedUserIdentityResolver;\n readonly stillCurrent?: (() => boolean) | undefined;\n}): Promise<Result[]> {\n if (!input.items || input.items.length === 0) {\n return [];\n }\n\n try {\n await ensurePrincipalPolicyTables(input.execSql);\n const uniqueItems = input.dedupe(input.items);\n const loadDirectory = createPolicyDirectoryLoader(input);\n let externalAdminPolicy: Promise<VerifiedExternalAdminPolicy | null> | null =\n null;\n const loadExternalAdminPolicy = () => {\n externalAdminPolicy ??= loadOrganizationExternalAdminPolicy({\n execSql: input.execSql,\n getCurrentPrincipalPolicy: input.getCurrentPrincipalPolicy,\n organizationId: input.organizationId,\n\n resolveTrustedUserIdentity: input.resolveTrustedUserIdentity,\n stillCurrent: input.stillCurrent,\n });\n return externalAdminPolicy;\n };\n\n const results = await Promise.all(\n uniqueItems.map(async (item) => {\n try {\n return await retryPrincipalPolicyCacheAdvance((fresh) => {\n const reloadDirectory = createPolicyDirectoryLoader(input);\n let reloadedAuthority: Promise<VerifiedExternalAdminPolicy | null> | null =\n null;\n return input.cacheItem(\n item,\n fresh\n ? () =>\n (reloadedAuthority ??=\n loadOrganizationExternalAdminPolicy(input))\n : loadExternalAdminPolicy,\n fresh ? () => reloadDirectory(true) : loadDirectory,\n fresh,\n );\n });\n } catch (error) {\n if (isProjectionVerificationCancelledError(error)) return [];\n await reportAndRethrowKeyingVerificationError(\n error,\n input.reportSecurityIncident,\n {\n objectId: input.itemKey(item),\n objectKind: \"principal\",\n operation: \"principal.policy.cache\",\n organizationId: input.organizationId,\n },\n );\n const message = errorMessage(error);\n input.log?.(\n `Principal policy cache: failed to store ${input.itemKey(item)}: ${message}`,\n );\n return [];\n }\n }),\n );\n return results.flat();\n } catch (error) {\n if (isProjectionVerificationCancelledError(error)) return [];\n // Per-item verification failures were reported above before reaching this\n // initialization/aggregation boundary.\n rethrowKeyingVerificationError(error);\n const message = errorMessage(error);\n input.log?.(\n `Principal policy cache: failed to initialize cache: ${message}`,\n );\n return [];\n }\n}\n\nasync function loadReferencedPrincipalPolicies({\n execSql,\n getCurrentPrincipalPolicy,\n log,\n organizationId,\n reportSecurityIncident,\n references,\n resolveTrustedUserIdentity,\n stillCurrent,\n}: CacheReferencedPrincipalPoliciesOptions): Promise<\n VerifiedPrincipalPolicy[]\n> {\n return runPrincipalPolicyCache({\n cacheItem: (reference, loadExternalAdminPolicy, loadDirectory, fresh) =>\n cacheReferencedPrincipalPolicy(\n execSql,\n getCurrentPrincipalPolicy,\n reference,\n resolveTrustedUserIdentity,\n log,\n loadExternalAdminPolicy,\n organizationId,\n stillCurrent,\n loadDirectory,\n fresh,\n ),\n dedupe: dedupeReferencedPrincipalStates,\n execSql,\n getCurrentPrincipalPolicy,\n itemKey: getReferencedPrincipalKey,\n items: references,\n log,\n organizationId,\n\n reportSecurityIncident,\n resolveTrustedUserIdentity,\n stillCurrent,\n });\n}\n\nexport async function cacheReferencedPrincipalPolicies(\n input: CacheReferencedPrincipalPoliciesOptions,\n): Promise<void> {\n await loadReferencedPrincipalPolicies(input);\n}\n\nexport async function cachePrincipalPolicyBundles({\n bundles,\n execSql,\n getCurrentPrincipalPolicy,\n log,\n organizationId,\n reportSecurityIncident,\n resolveTrustedUserIdentity,\n stillCurrent,\n}: CachePrincipalPolicyBundlesOptions): Promise<void> {\n await runPrincipalPolicyCache({\n cacheItem: (bundle, loadExternalAdminPolicy, loadDirectory) =>\n cachePrincipalPolicyBundle({\n bundle,\n execSql,\n loadExternalAdminPolicy,\n loadDirectory,\n log,\n organizationId,\n resolveTrustedUserIdentity,\n stillCurrent,\n }),\n dedupe: dedupePrincipalPolicyBundles,\n execSql,\n getCurrentPrincipalPolicy,\n itemKey: getBundlePrincipalKey,\n items: bundles,\n log,\n organizationId,\n\n reportSecurityIncident,\n resolveTrustedUserIdentity,\n stillCurrent,\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"policyCache.js","sourceRoot":"","sources":["policyCache.ts"],"names":[],"mappings":"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","sourcesContent":["import type { VerifiedPrincipalPolicy } from \"@tearleads/crypto\";\nimport type {\n PrincipalPolicyBundleResponse,\n ReferencedPrincipalStateResponse,\n} from \"@tearleads/validators/response\";\nimport { errorMessage } from \"../../data/errorMessage\";\nimport { isProjectionVerificationCancelledError } from \"../../data/keyingProjectionVerification\";\nimport {\n reportAndRethrowKeyingVerificationError,\n rethrowKeyingVerificationError,\n} from \"../../data/keyingProjectionVerification/error\";\nimport { dedupeReferencedPrincipalStates } from \"../../data/keyingProjectionVerification/principalPolicyCache\";\nimport { loadPrincipalPolicyCheckpoint } from \"../../data/persistence/keyingCheckpointPersistence\";\nimport { ensurePrincipalPolicyTables } from \"../../data/persistence/principalPolicyPersistence\";\nimport { loadPrincipalPolicyBundleForReference } from \"../../data/persistence/principalPolicyReferencePersistence\";\nimport { principalPolicyReferenceFromBundle } from \"../../data/principals/principalPolicyAdminSigners\";\nimport type { SecurityIncidentReporter } from \"../../data/securityIncidents\";\nimport type { ExecSql } from \"../../data/sqlite/sqlSchema\";\nimport type { TrustedUserIdentityResolver } from \"../../data/trustedUserIdentity\";\nimport type { CurrentPrincipalPolicyReader } from \"./currentPrincipalPolicyReader\";\nimport {\n externalAdminPolicyPersistenceEntries,\n loadOrganizationExternalAdminPolicy,\n type VerifiedExternalAdminPolicy,\n} from \"./externalAdminPolicy\";\nimport {\n persistPrincipalPolicyCacheEntries,\n retryPrincipalPolicyCacheAdvance,\n} from \"./principalPolicyCacheAdvance\";\nimport { scopeReferencedPolicyForCache } from \"./principalPolicyCacheScope\";\nimport { validatePrincipalPolicyBundleForCache } from \"./principalPolicyCacheValidation\";\nimport {\n createPolicyDirectoryLoader,\n directoryBindsGroupReference,\n type PolicyDirectoryLoader,\n type VerifiedPolicyDirectory,\n} from \"./principalPolicyOrganizationScope\";\n\nexport interface CacheReferencedPrincipalPoliciesOptions {\n currentPolicyReader: CurrentPrincipalPolicyReader;\n execSql: ExecSql;\n log?: (message: string) => void;\n organizationId: string;\n reportSecurityIncident: SecurityIncidentReporter;\n references: ReadonlyArray<ReferencedPrincipalStateResponse> | undefined;\n resolveTrustedUserIdentity: TrustedUserIdentityResolver;\n stillCurrent?: (() => boolean) | undefined;\n}\n\nexport interface CachePrincipalPolicyBundlesOptions\n extends Omit<CacheReferencedPrincipalPoliciesOptions, \"references\"> {\n bundles: ReadonlyArray<PrincipalPolicyBundleResponse> | undefined;\n}\n\nfunction getReferencedPrincipalKey(\n reference: ReferencedPrincipalStateResponse,\n): string {\n return `${reference.principalType}:${reference.principalId}`;\n}\n\nfunction getBundlePrincipalKey(bundle: PrincipalPolicyBundleResponse): string {\n return `${bundle.currentState.principalType}:${bundle.currentState.principalId}`;\n}\n\nfunction dedupePrincipalPolicyBundles(\n bundles: ReadonlyArray<PrincipalPolicyBundleResponse>,\n): PrincipalPolicyBundleResponse[] {\n const bundlesByPrincipal = new Map<string, PrincipalPolicyBundleResponse>();\n\n for (const bundle of bundles) {\n const key = getBundlePrincipalKey(bundle);\n const previous = bundlesByPrincipal.get(key);\n if (\n !previous ||\n bundle.currentState.version > previous.currentState.version\n ) {\n bundlesByPrincipal.set(key, bundle);\n }\n }\n\n return Array.from(bundlesByPrincipal.values());\n}\n\nasync function cacheReferencedPrincipalPolicy(\n execSql: ExecSql,\n reader: CurrentPrincipalPolicyReader,\n reference: ReferencedPrincipalStateResponse,\n resolveTrustedUserIdentity: TrustedUserIdentityResolver,\n log: ((message: string) => void) | undefined,\n loadExternalAdminPolicy: () => Promise<VerifiedExternalAdminPolicy | null>,\n organizationId: string,\n stillCurrent: (() => boolean) | undefined,\n loadDirectory: PolicyDirectoryLoader,\n fresh: boolean,\n): Promise<VerifiedPrincipalPolicy[]> {\n const localCheckpoint = await loadPrincipalPolicyCheckpoint(\n execSql,\n reference.principalType,\n reference.principalId,\n );\n // Only null is a recoverable local miss. Integrity failures remain typed and\n // must escape rather than being hidden by a canonical network retry.\n const cachedBundle = fresh\n ? null\n : await loadPrincipalPolicyBundleForReference(\n execSql,\n reference,\n localCheckpoint,\n );\n let bundle =\n cachedBundle ??\n (await reader.getCurrentPrincipalPolicy(\n reference.principalType,\n reference.principalId,\n ));\n if (!bundle) {\n log?.(\n `Principal policy cache: failed to fetch ${getReferencedPrincipalKey(reference)}`,\n );\n return [];\n }\n\n let validation = await validatePrincipalPolicyBundleForCache({\n bundle,\n loadExternalAdminPolicy,\n localCheckpoint,\n reference,\n resolveTrustedUserIdentity,\n });\n if (!validation.ok) {\n throw validation.error;\n }\n\n const scoped = await scopeReferencedPolicyForCache({\n bundle,\n validation,\n validationInput: {\n loadExternalAdminPolicy,\n localCheckpoint,\n reference,\n resolveTrustedUserIdentity,\n },\n loadDirectory,\n organizationId,\n reloadBundle: cachedBundle\n ? () => reader.getCurrentPrincipalPolicy(\"group\", reference.principalId)\n : null,\n });\n if (!scoped) {\n log?.(\n `Principal policy cache: signed organization directory does not cover ${getReferencedPrincipalKey(reference)}`,\n );\n return [];\n }\n bundle = scoped.bundle;\n validation = scoped.validation;\n const directory = scoped.directory;\n const externalEntries = validation.externalAdminPolicy\n ? externalAdminPolicyPersistenceEntries(\n validation.externalAdminPolicy,\n ).filter(\n (entry) => !directory || entry.policy.principalType !== \"organization\",\n )\n : [];\n const directoryEntries = directory\n ? [{ bundle: directory.bundle, policy: directory.policy }]\n : [];\n await persistPrincipalPolicyCacheEntries({\n entries: [\n ...externalEntries,\n ...directoryEntries,\n { bundle, policy: validation.policy },\n ],\n execSql,\n organizationId,\n updatedAt: new Date().toISOString(),\n stillCurrent,\n });\n return [...externalEntries.map(({ policy }) => policy), validation.policy];\n}\n\nasync function cachePrincipalPolicyBundle(input: {\n readonly bundle: PrincipalPolicyBundleResponse;\n readonly execSql: ExecSql;\n readonly loadExternalAdminPolicy: () => Promise<VerifiedExternalAdminPolicy | null>;\n readonly log: ((message: string) => void) | undefined;\n readonly loadDirectory: PolicyDirectoryLoader;\n readonly organizationId: string;\n readonly resolveTrustedUserIdentity: TrustedUserIdentityResolver;\n readonly stillCurrent?: (() => boolean) | undefined;\n}): Promise<VerifiedPrincipalPolicy[]> {\n const reference = principalPolicyReferenceFromBundle(input.bundle);\n // The API supplied this bundle after rejecting a write, but local storage is\n // only updated after normal signature, signer, and checkpoint verification.\n const localCheckpoint = await loadPrincipalPolicyCheckpoint(\n input.execSql,\n reference.principalType,\n reference.principalId,\n );\n const validation = await validatePrincipalPolicyBundleForCache({\n bundle: input.bundle,\n loadExternalAdminPolicy: input.loadExternalAdminPolicy,\n localCheckpoint,\n reference,\n resolveTrustedUserIdentity: input.resolveTrustedUserIdentity,\n });\n if (!validation.ok) {\n throw validation.error;\n }\n\n let directory: VerifiedPolicyDirectory | null = null;\n if (reference.principalType === \"group\") {\n directory = await input.loadDirectory(false);\n if (!directoryBindsGroupReference(directory, validation.policy, reference))\n directory = await input.loadDirectory(true);\n if (\n !directoryBindsGroupReference(directory, validation.policy, reference)\n ) {\n input.log?.(\n \"Principal policy cache: signed organization directory does not cover supplied group\",\n );\n return [];\n }\n } else if (reference.principalId !== input.organizationId) {\n return [];\n }\n const externalEntries = validation.externalAdminPolicy\n ? externalAdminPolicyPersistenceEntries(\n validation.externalAdminPolicy,\n ).filter(\n (entry) => !directory || entry.policy.principalType !== \"organization\",\n )\n : [];\n const directoryEntries = directory\n ? [{ bundle: directory.bundle, policy: directory.policy }]\n : [];\n await persistPrincipalPolicyCacheEntries({\n entries: [\n ...externalEntries,\n ...directoryEntries,\n { bundle: input.bundle, policy: validation.policy },\n ],\n execSql: input.execSql,\n organizationId: input.organizationId,\n updatedAt: new Date().toISOString(),\n stillCurrent: input.stillCurrent,\n });\n return [...externalEntries.map(({ policy }) => policy), validation.policy];\n}\n\nasync function runPrincipalPolicyCache<Item, Result>(input: {\n readonly cacheItem: (\n item: Item,\n loadExternalAdminPolicy: () => Promise<VerifiedExternalAdminPolicy | null>,\n loadDirectory: PolicyDirectoryLoader,\n fresh: boolean,\n ) => Promise<readonly Result[]>;\n readonly currentPolicyReader: CurrentPrincipalPolicyReader;\n readonly dedupe: (items: ReadonlyArray<Item>) => Item[];\n readonly execSql: ExecSql;\n readonly itemKey: (item: Item) => string;\n readonly items: ReadonlyArray<Item> | undefined;\n readonly log: ((message: string) => void) | undefined;\n readonly organizationId: string;\n readonly reportSecurityIncident: SecurityIncidentReporter;\n readonly resolveTrustedUserIdentity: TrustedUserIdentityResolver;\n readonly stillCurrent?: (() => boolean) | undefined;\n}): Promise<Result[]> {\n if (!input.items || input.items.length === 0) {\n return [];\n }\n\n try {\n await ensurePrincipalPolicyTables(input.execSql);\n const uniqueItems = input.dedupe(input.items);\n const loadDirectory = createPolicyDirectoryLoader(input);\n let externalAdminPolicy: Promise<VerifiedExternalAdminPolicy | null> | null =\n null;\n const loadExternalAdminPolicy = () => {\n externalAdminPolicy ??= loadOrganizationExternalAdminPolicy({\n currentPolicyReader: input.currentPolicyReader,\n execSql: input.execSql,\n organizationId: input.organizationId,\n\n resolveTrustedUserIdentity: input.resolveTrustedUserIdentity,\n stillCurrent: input.stillCurrent,\n });\n return externalAdminPolicy;\n };\n\n const results = await Promise.all(\n uniqueItems.map(async (item) => {\n try {\n return await retryPrincipalPolicyCacheAdvance((fresh) => {\n const reloadDirectory = createPolicyDirectoryLoader(input);\n let reloadedAuthority: Promise<VerifiedExternalAdminPolicy | null> | null =\n null;\n return input.cacheItem(\n item,\n fresh\n ? () =>\n (reloadedAuthority ??=\n loadOrganizationExternalAdminPolicy(input))\n : loadExternalAdminPolicy,\n fresh ? () => reloadDirectory(true) : loadDirectory,\n fresh,\n );\n });\n } catch (error) {\n if (isProjectionVerificationCancelledError(error)) return [];\n await reportAndRethrowKeyingVerificationError(\n error,\n input.reportSecurityIncident,\n {\n objectId: input.itemKey(item),\n objectKind: \"principal\",\n operation: \"principal.policy.cache\",\n organizationId: input.organizationId,\n },\n );\n const message = errorMessage(error);\n input.log?.(\n `Principal policy cache: failed to store ${input.itemKey(item)}: ${message}`,\n );\n return [];\n }\n }),\n );\n return results.flat();\n } catch (error) {\n if (isProjectionVerificationCancelledError(error)) return [];\n // Per-item verification failures were reported above before reaching this\n // initialization/aggregation boundary.\n rethrowKeyingVerificationError(error);\n const message = errorMessage(error);\n input.log?.(\n `Principal policy cache: failed to initialize cache: ${message}`,\n );\n return [];\n }\n}\n\nasync function loadReferencedPrincipalPolicies({\n currentPolicyReader,\n execSql,\n log,\n organizationId,\n reportSecurityIncident,\n references,\n resolveTrustedUserIdentity,\n stillCurrent,\n}: CacheReferencedPrincipalPoliciesOptions): Promise<\n VerifiedPrincipalPolicy[]\n> {\n return runPrincipalPolicyCache({\n cacheItem: (reference, loadExternalAdminPolicy, loadDirectory, fresh) =>\n cacheReferencedPrincipalPolicy(\n execSql,\n currentPolicyReader,\n reference,\n resolveTrustedUserIdentity,\n log,\n loadExternalAdminPolicy,\n organizationId,\n stillCurrent,\n loadDirectory,\n fresh,\n ),\n currentPolicyReader,\n dedupe: dedupeReferencedPrincipalStates,\n execSql,\n itemKey: getReferencedPrincipalKey,\n items: references,\n log,\n organizationId,\n\n reportSecurityIncident,\n resolveTrustedUserIdentity,\n stillCurrent,\n });\n}\n\nexport async function cacheReferencedPrincipalPolicies(\n input: CacheReferencedPrincipalPoliciesOptions,\n): Promise<void> {\n await loadReferencedPrincipalPolicies(input);\n}\n\nexport async function cachePrincipalPolicyBundles({\n bundles,\n currentPolicyReader,\n execSql,\n log,\n organizationId,\n reportSecurityIncident,\n resolveTrustedUserIdentity,\n stillCurrent,\n}: CachePrincipalPolicyBundlesOptions): Promise<void> {\n await runPrincipalPolicyCache({\n cacheItem: (bundle, loadExternalAdminPolicy, loadDirectory) =>\n cachePrincipalPolicyBundle({\n bundle,\n execSql,\n loadExternalAdminPolicy,\n loadDirectory,\n log,\n organizationId,\n resolveTrustedUserIdentity,\n stillCurrent,\n }),\n currentPolicyReader,\n dedupe: dedupePrincipalPolicyBundles,\n execSql,\n itemKey: getBundlePrincipalKey,\n items: bundles,\n log,\n organizationId,\n\n reportSecurityIncident,\n resolveTrustedUserIdentity,\n stillCurrent,\n });\n}\n"]}
|
|
@@ -24,7 +24,7 @@ export function createPolicyDirectoryLoader(input) {
|
|
|
24
24
|
if (bundle &&
|
|
25
25
|
!principalPolicyHeadMeetsCheckpoint(bundle.currentState, checkpoint))
|
|
26
26
|
bundle = null;
|
|
27
|
-
bundle ??= await input.getCurrentPrincipalPolicy("organization", input.organizationId);
|
|
27
|
+
bundle ??= await input.currentPolicyReader.getCurrentPrincipalPolicy("organization", input.organizationId);
|
|
28
28
|
if (!bundle)
|
|
29
29
|
return null;
|
|
30
30
|
const signers = await collectPrincipalPolicySignerPublicKeys({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"principalPolicyOrganizationScope.js","sourceRoot":"","sources":["principalPolicyOrganizationScope.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,GAGxB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AACnG,OAAO,EAAE,kCAAkC,EAAE,MAAM,2DAA2D,CAAC;AAC/G,OAAO,EAAE,yBAAyB,EAAE,MAAM,mDAAmD,CAAC;AAC9F,OAAO,EAEL,oCAAoC,EACpC,6BAA6B,GAC9B,MAAM,uDAAuD,CAAC;AAC/D,OAAO,EAAE,6BAA6B,EAAE,MAAM,mDAAmD,CAAC;
|
|
1
|
+
{"version":3,"file":"principalPolicyOrganizationScope.js","sourceRoot":"","sources":["principalPolicyOrganizationScope.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n KeyingVerificationError,\n type ReferencedPrincipalHead,\n type VerifiedPrincipalPolicy,\n} from \"@tearleads/crypto\";\nimport type { PrincipalPolicyBundleResponse } from \"@tearleads/validators/response\";\nimport { loadPrincipalPolicyCheckpoint } from \"../../data/persistence/keyingCheckpointPersistence\";\nimport { principalPolicyHeadMeetsCheckpoint } from \"../../data/persistence/principalPolicyCheckpointSelection\";\nimport { loadPrincipalPolicyBundle } from \"../../data/persistence/principalPolicyPersistence\";\nimport {\n type OrganizationAuthorityDescriptor,\n parseOrganizationAuthorityDescriptor,\n principalHeadMatchesReference,\n} from \"../../data/principals/organizationAuthorityDescriptor\";\nimport { verifyOrganizationAdminPolicy } from \"../../data/principals/principalPolicyAdminSigners\";\nimport type { ExecSql } from \"../../data/sqlite/sqlSchema\";\nimport type { TrustedUserIdentityResolver } from \"../../data/trustedUserIdentity\";\nimport type { CurrentPrincipalPolicyReader } from \"./currentPrincipalPolicyReader\";\nimport { collectPrincipalPolicySignerPublicKeys } from \"./policyVerification\";\n\nexport interface VerifiedPolicyDirectory {\n readonly bundle: PrincipalPolicyBundleResponse;\n readonly policy: VerifiedPrincipalPolicy;\n readonly descriptor: OrganizationAuthorityDescriptor;\n}\n\nexport type PolicyDirectoryLoader = (\n remote: boolean,\n) => Promise<VerifiedPolicyDirectory | null>;\n\nexport function directoryBindsGroupReference(\n directory: VerifiedPolicyDirectory | null,\n policy: VerifiedPrincipalPolicy,\n reference: ReferencedPrincipalHead,\n): boolean {\n const head = directory?.descriptor.groupHeads.find(\n (head) => head.principalId === reference.principalId,\n );\n // A newer directory head authenticates its verified predecessors too.\n // Requiring equality with a historical manifest citation bricks old reads.\n return (\n !!head &&\n head.version >= reference.version &&\n head.version === policy.version &&\n [policy.state, ...(policy.history ?? []).map((entry) => entry.state)].some(\n (state) => principalHeadMatchesReference(state, head),\n )\n );\n}\n\nexport function createPolicyDirectoryLoader(input: {\n readonly execSql: ExecSql;\n readonly organizationId: string;\n readonly currentPolicyReader: CurrentPrincipalPolicyReader;\n readonly resolveTrustedUserIdentity: TrustedUserIdentityResolver;\n}): PolicyDirectoryLoader {\n const memo = new Map<boolean, Promise<VerifiedPolicyDirectory | null>>();\n const load = async (\n remote: boolean,\n ): Promise<VerifiedPolicyDirectory | null> => {\n const checkpoint = await loadPrincipalPolicyCheckpoint(\n input.execSql,\n \"organization\",\n input.organizationId,\n );\n let bundle = remote\n ? null\n : await loadPrincipalPolicyBundle(\n input.execSql,\n \"organization\",\n input.organizationId,\n );\n if (\n bundle &&\n !principalPolicyHeadMeetsCheckpoint(bundle.currentState, checkpoint)\n )\n bundle = null;\n bundle ??= await input.currentPolicyReader.getCurrentPrincipalPolicy(\n \"organization\",\n input.organizationId,\n );\n if (!bundle) return null;\n const signers = await collectPrincipalPolicySignerPublicKeys({\n bundle,\n resolveTrustedUserIdentity: input.resolveTrustedUserIdentity,\n });\n if (\"error\" in signers) {\n if (signers.error === \"fingerprint-mismatch\")\n throw new KeyingVerificationError(\n \"signer_mismatch\",\n \"organization directory signer fingerprint does not match\",\n );\n return null;\n }\n const verified = await verifyOrganizationAdminPolicy({\n bundle,\n localCheckpoint: checkpoint,\n organizationId: input.organizationId,\n signerPublicKeys: signers.signerPublicKeys,\n });\n if (!verified.ok) throw verified.error;\n let descriptor: OrganizationAuthorityDescriptor;\n try {\n descriptor = parseOrganizationAuthorityDescriptor(\n bundle.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 { bundle, policy: verified.value, descriptor };\n };\n return (remote) => {\n let pending = memo.get(remote);\n if (!pending) {\n pending = load(remote);\n memo.set(remote, pending);\n }\n return pending;\n };\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { loadPrincipalPolicyCheckpoint } from "../../data/persistence/keyingCheckpointPersistence.js";
|
|
2
|
-
import {
|
|
2
|
+
import { getOrCreatePrincipalPolicyCoordinator } from "../../data/principals/principalPolicyCoordinator.js";
|
|
3
3
|
async function pinCovers(input, head) {
|
|
4
4
|
const pin = await loadPrincipalPolicyCheckpoint(input.execSql, head.principalType, head.principalId);
|
|
5
5
|
return (!pin ||
|
|
@@ -7,7 +7,7 @@ async function pinCovers(input, head) {
|
|
|
7
7
|
(pin.version === head.version && pin.stateHash === head.stateHash));
|
|
8
8
|
}
|
|
9
9
|
function organizationEpoch(input) {
|
|
10
|
-
return () =>
|
|
10
|
+
return () => getOrCreatePrincipalPolicyCoordinator(input.execSql).recoveryEpoch(input.organizationId);
|
|
11
11
|
}
|
|
12
12
|
/** A directory names every group head; a newer pin on any of them evicts it. */
|
|
13
13
|
export function directoryMemoValidity(input) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"principalRecoveryMemoValidity.js","sourceRoot":"","sources":["principalRecoveryMemoValidity.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AACnG,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"principalRecoveryMemoValidity.js","sourceRoot":"","sources":["principalRecoveryMemoValidity.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AACnG,OAAO,EAAE,qCAAqC,EAAE,MAAM,kDAAkD,CAAC;AAoBzG,KAAK,UAAU,SAAS,CACtB,KAA+B,EAC/B,IAAgB;IAEhB,MAAM,GAAG,GAAG,MAAM,6BAA6B,CAC7C,KAAK,CAAC,OAAO,EACb,IAAI,CAAC,aAAa,EAClB,IAAI,CAAC,WAAW,CACjB,CAAC;IACF,OAAO,CACL,CAAC,GAAG;QACJ,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO;QAC1B,CAAC,GAAG,CAAC,OAAO,KAAK,IAAI,CAAC,OAAO,IAAI,GAAG,CAAC,SAAS,KAAK,IAAI,CAAC,SAAS,CAAC,CACnE,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB,CAAC,KAA+B;IACxD,OAAO,GAAG,EAAE,CACV,qCAAqC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,aAAa,CAChE,KAAK,CAAC,cAAc,CACrB,CAAC;AACN,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,qBAAqB,CACnC,KAA+B;IAE/B,OAAO;QACL,KAAK,EAAE,iBAAiB,CAAC,KAAK,CAAC;QAC/B,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE;YAC1B,KAAK,MAAM,IAAI,IAAI;gBACjB,SAAS,CAAC,MAAM,CAAC,KAAK;gBACtB,GAAG,SAAS,CAAC,UAAU,CAAC,UAAU;aACnC;gBACC,IAAI,CAAC,CAAC,MAAM,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;oBAAE,OAAO,KAAK,CAAC;YACpD,OAAO,IAAI,CAAC;QACd,CAAC;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,kBAAkB,CAChC,KAA+B,EAC/B,YAAwB;IAExB,OAAO;QACL,KAAK,EAAE,iBAAiB,CAAC,KAAK,CAAC;QAC/B,MAAM,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,KAAK,EAAE,YAAY,CAAC;KAC7C,CAAC;AACJ,CAAC","sourcesContent":["import type { ReferencedPrincipalHead } from \"@tearleads/crypto\";\nimport { loadPrincipalPolicyCheckpoint } from \"../../data/persistence/keyingCheckpointPersistence\";\nimport { getOrCreatePrincipalPolicyCoordinator } from \"../../data/principals/principalPolicyCoordinator\";\nimport type { RecoveredPrincipalPolicyHistory } from \"./principalHistoryRecoveryTypes\";\nimport type {\n PrincipalRecoveryContext,\n RecoveredPolicyDirectory,\n} from \"./principalRecoveryDirectory\";\n\n/** What keeps a memo entry valid beyond its producer's lease. */\nexport interface PrincipalRecoveryMemoValidity<T> {\n /** Organization hint epoch; production records it before its reads. */\n readonly epoch: () => number;\n /** No durable pin has moved past or forked from a memoized head. */\n readonly covers: (value: T) => Promise<boolean>;\n}\n\ntype PinnedHead = Pick<\n ReferencedPrincipalHead,\n \"principalType\" | \"principalId\" | \"version\" | \"stateHash\"\n>;\n\nasync function pinCovers(\n input: PrincipalRecoveryContext,\n head: PinnedHead,\n): Promise<boolean> {\n const pin = await loadPrincipalPolicyCheckpoint(\n input.execSql,\n head.principalType,\n head.principalId,\n );\n return (\n !pin ||\n pin.version < head.version ||\n (pin.version === head.version && pin.stateHash === head.stateHash)\n );\n}\n\nfunction organizationEpoch(input: PrincipalRecoveryContext) {\n return () =>\n getOrCreatePrincipalPolicyCoordinator(input.execSql).recoveryEpoch(\n input.organizationId,\n );\n}\n\n/** A directory names every group head; a newer pin on any of them evicts it. */\nexport function directoryMemoValidity(\n input: PrincipalRecoveryContext,\n): PrincipalRecoveryMemoValidity<RecoveredPolicyDirectory> {\n return {\n epoch: organizationEpoch(input),\n covers: async (directory) => {\n for (const head of [\n directory.policy.state,\n ...directory.descriptor.groupHeads,\n ])\n if (!(await pinCovers(input, head))) return false;\n return true;\n },\n };\n}\n\nexport function adminsMemoValidity(\n input: PrincipalRecoveryContext,\n expectedHead: PinnedHead,\n): PrincipalRecoveryMemoValidity<RecoveredPrincipalPolicyHistory> {\n return {\n epoch: organizationEpoch(input),\n covers: () => pinCovers(input, expectedHead),\n };\n}\n"]}
|
|
@@ -3,11 +3,11 @@ 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
7
|
import { createPrincipalCurrentRecoveryBatch } from "./principalCurrentRecoveryBatch.js";
|
|
7
8
|
import { PrincipalHistoryRecoveryRaceError, PrincipalPolicyHistoryReadError, } from "./principalHistoryRecoveryTypes.js";
|
|
8
9
|
import { apiPrincipalPolicyPageReader, } from "./principalPolicyHistoryReader.js";
|
|
9
10
|
import { recoverWithPrincipalLocalPreference } from "./principalRecoveryLocalPreference.js";
|
|
10
|
-
import { queuePrincipalRecovery } from "./principalRecoveryQueue.js";
|
|
11
11
|
/** Keep the private recovery key inside its runtime lease while resolving cited evidence. */
|
|
12
12
|
export function createRuntimePrincipalPolicyResolver(runtime, options = {}) {
|
|
13
13
|
const resolve = createRuntimePrincipalPolicyCurrentResolver(runtime);
|
|
@@ -32,7 +32,7 @@ export function createRuntimePrincipalPolicyCurrentResolver(runtime) {
|
|
|
32
32
|
}
|
|
33
33
|
return recover;
|
|
34
34
|
};
|
|
35
|
-
return (input) =>
|
|
35
|
+
return (input) => getOrCreatePrincipalPolicyCoordinator(runtime.infra.execSql).queueRecovery(input.organizationId, () => runWithSecurityIncidentReporting(runtime.util.reportSecurityIncident, {
|
|
36
36
|
objectId: input.reference?.principalId ?? input.organizationId,
|
|
37
37
|
objectKind: "principal",
|
|
38
38
|
operation: "principal.policy.recover",
|
|
@@ -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 type { SecurityIncidentReporter } from \"../../data/securityIncidents\";\nimport type { ExecSql } from \"../../data/sqlite/sqlSchema\";\nimport type { TrustedUserIdentityResolver } from \"../../data/trustedUserIdentity\";\nimport type { RecoveredPrincipalHistoryPage } from \"./loadRecoveredPrincipalHistoryPage\";\nimport { createPrincipalCurrentRecoveryBatch } from \"./principalCurrentRecoveryBatch\";\nimport {\n PrincipalHistoryRecoveryRaceError,\n PrincipalPolicyHistoryReadError,\n} from \"./principalHistoryRecoveryTypes\";\nimport {\n apiPrincipalPolicyPageReader,\n type PrincipalPolicyHistoryReader,\n} from \"./principalPolicyHistoryReader\";\nimport { recoverWithPrincipalLocalPreference } from \"./principalRecoveryLocalPreference\";\nimport { queuePrincipalRecovery } from \"./principalRecoveryQueue\";\nimport type { ScopedPrincipalPolicyRecovery } from \"./recoverScopedPrincipalPolicyHistory\";\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/** 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 queuePrincipalRecovery(runtime.infra.execSql, 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 batch = recoverFor(input.recoveryBatch);\n const result: ScopedPrincipalPolicyRecovery = input.reference\n ? await recoverWithPrincipalLocalPreference(\n batch.recover,\n {\n ...options,\n reference: input.reference,\n historyPage: input.historyPage,\n },\n input.preferLocalCurrent === true ||\n input.preferLocalHistory === true,\n input.preferLocalHistory === true,\n )\n : await batch.discover(options);\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 { getOrCreatePrincipalPolicyCoordinator } from \"../../data/principals/principalPolicyCoordinator\";\nimport type { SecurityIncidentReporter } from \"../../data/securityIncidents\";\nimport type { ExecSql } from \"../../data/sqlite/sqlSchema\";\nimport type { TrustedUserIdentityResolver } from \"../../data/trustedUserIdentity\";\nimport type { RecoveredPrincipalHistoryPage } from \"./loadRecoveredPrincipalHistoryPage\";\nimport { createPrincipalCurrentRecoveryBatch } from \"./principalCurrentRecoveryBatch\";\nimport {\n PrincipalHistoryRecoveryRaceError,\n PrincipalPolicyHistoryReadError,\n} from \"./principalHistoryRecoveryTypes\";\nimport {\n apiPrincipalPolicyPageReader,\n type PrincipalPolicyHistoryReader,\n} from \"./principalPolicyHistoryReader\";\nimport { recoverWithPrincipalLocalPreference } from \"./principalRecoveryLocalPreference\";\nimport type { ScopedPrincipalPolicyRecovery } from \"./recoverScopedPrincipalPolicyHistory\";\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/** 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 batch = recoverFor(input.recoveryBatch);\n const result: ScopedPrincipalPolicyRecovery = input.reference\n ? await recoverWithPrincipalLocalPreference(\n batch.recover,\n {\n ...options,\n reference: input.reference,\n historyPage: input.historyPage,\n },\n input.preferLocalCurrent === true ||\n input.preferLocalHistory === true,\n input.preferLocalHistory === true,\n )\n : await batch.discover(options);\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"]}
|
|
@@ -3,10 +3,10 @@ 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
7
|
import { PrincipalPolicyHistoryReadError } from "./principalHistoryRecoveryTypes.js";
|
|
7
8
|
import { apiProjectionPolicyHistoryReader } from "./principalPolicyHistoryReader.js";
|
|
8
9
|
import { isPrincipalRecoveryOutage } from "./principalRecoveryOutage.js";
|
|
9
|
-
import { queuePrincipalRecovery } from "./principalRecoveryQueue.js";
|
|
10
10
|
import { recoverProjectionPolicyHistory, } from "./recoverProjectionPolicyHistory.js";
|
|
11
11
|
async function recoverWithOutageFallback(options) {
|
|
12
12
|
try {
|
|
@@ -24,7 +24,7 @@ export function createRuntimeProjectionPolicyResolver(runtime) {
|
|
|
24
24
|
const historyReader = apiProjectionPolicyHistoryReader(runtime.apiClient);
|
|
25
25
|
if (!lease || !historyReader)
|
|
26
26
|
return undefined;
|
|
27
|
-
return (input) =>
|
|
27
|
+
return (input) => getOrCreatePrincipalPolicyCoordinator(runtime.infra.execSql).queueRecovery(input.organizationId, () => runWithSecurityIncidentReporting(runtime.util.reportSecurityIncident, {
|
|
28
28
|
objectId: input.organizationId,
|
|
29
29
|
objectKind: "principal",
|
|
30
30
|
operation: "principal.projection.recover",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtimeProjectionPolicyRecovery.js","sourceRoot":"","sources":["runtimeProjectionPolicyRecovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,oCAAoC,EAAE,MAAM,+DAA+D,CAAC;AACrH,OAAO,EAAE,gCAAgC,EAAE,MAAM,+CAA+C,CAAC;AACjG,OAAO,EACL,mCAAmC,GAEpC,MAAM,+CAA+C,CAAC;AACvD,OAAO,EAAE,8BAA8B,EAAE,MAAM,+CAA+C,CAAC;AAC/F,OAAO,EAAE
|
|
1
|
+
{"version":3,"file":"runtimeProjectionPolicyRecovery.js","sourceRoot":"","sources":["runtimeProjectionPolicyRecovery.ts"],"names":[],"mappings":"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","sourcesContent":["import { KeyingVerificationError } from \"@tearleads/crypto\";\nimport { ProjectionDependencyUnavailableError } from \"../../data/keyingProjectionVerification/dependencyUnavailable\";\nimport { runWithSecurityIncidentReporting } from \"../../data/keyingProjectionVerification/error\";\nimport {\n assertProjectionVerificationCurrent,\n type ReferencedPrincipalPolicyWarmer,\n} from \"../../data/keyingProjectionVerification/types\";\nimport { readPrincipalHistoryProtection } from \"../../data/principals/principalHistoryRuntime\";\nimport { getOrCreatePrincipalPolicyCoordinator } from \"../../data/principals/principalPolicyCoordinator\";\nimport { PrincipalPolicyHistoryReadError } from \"./principalHistoryRecoveryTypes\";\nimport { apiProjectionPolicyHistoryReader } from \"./principalPolicyHistoryReader\";\nimport { isPrincipalRecoveryOutage } from \"./principalRecoveryOutage\";\nimport {\n type ProjectionPolicyHistoryRecoveryOptions,\n recoverProjectionPolicyHistory,\n} from \"./recoverProjectionPolicyHistory\";\nimport type { PrincipalPolicyRecoveryRuntime } from \"./runtimePolicyRecovery\";\n\nasync function recoverWithOutageFallback(\n options: ProjectionPolicyHistoryRecoveryOptions,\n) {\n try {\n return await recoverProjectionPolicyHistory(options);\n } catch (error) {\n assertProjectionVerificationCurrent(options.stillCurrent);\n if (options.offline || !isPrincipalRecoveryOutage(error)) throw error;\n return recoverProjectionPolicyHistory({ ...options, offline: true });\n }\n}\n\nexport function createRuntimeProjectionPolicyResolver(\n runtime: PrincipalPolicyRecoveryRuntime,\n): ReferencedPrincipalPolicyWarmer[\"resolveProjectionHistory\"] {\n const lease = readPrincipalHistoryProtection(runtime);\n const historyReader = apiProjectionPolicyHistoryReader(runtime.apiClient);\n if (!lease || !historyReader) return undefined;\n return (input) =>\n getOrCreatePrincipalPolicyCoordinator(runtime.infra.execSql).queueRecovery(\n input.organizationId,\n () =>\n runWithSecurityIncidentReporting(\n runtime.util.reportSecurityIncident,\n {\n objectId: input.organizationId,\n objectKind: \"principal\",\n operation: \"principal.projection.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 try {\n const policies = await recoverWithOutageFallback({\n ...input,\n historyReader,\n execSql: runtime.infra.execSql,\n protection,\n stillCurrent,\n offline: runtime.state?.online === false,\n resolveTrustedUserIdentity:\n runtime.resolveTrustedUserIdentity,\n });\n return { policies, stillCurrent };\n } catch (error) {\n assertProjectionVerificationCurrent(stillCurrent);\n if (\n error instanceof PrincipalPolicyHistoryReadError ||\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"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { assertProjectionVerificationCurrent } from "../../data/keyingProjectionVerification/types.js";
|
|
2
2
|
import { principalPolicyReferenceFromBundle } from "../../data/principals/principalPolicyAdminSigners.js";
|
|
3
|
+
import { getOrCreatePrincipalPolicyCoordinator } from "../../data/principals/principalPolicyCoordinator.js";
|
|
3
4
|
import { createPrincipalCurrentRecoveryBatch } from "../principals/principalCurrentRecoveryBatch.js";
|
|
4
|
-
import { queuePrincipalRecovery } from "../principals/principalRecoveryQueue.js";
|
|
5
5
|
/**
|
|
6
6
|
* Serves only the acknowledged initial heads, each complete in one page. The
|
|
7
7
|
* ordinary verifier still checks every signature, the directory binding and
|
|
@@ -91,7 +91,7 @@ async function primeInProvisioningScope(runtime, input) {
|
|
|
91
91
|
? identity
|
|
92
92
|
: null;
|
|
93
93
|
};
|
|
94
|
-
await
|
|
94
|
+
await getOrCreatePrincipalPolicyCoordinator(execSql).queueRecovery(input.organizationId, () => lease(({ protection, stillCurrent }) => primeProvisionedPrincipalHistory({
|
|
95
95
|
execSql,
|
|
96
96
|
organizationId: input.organizationId,
|
|
97
97
|
policies: input.policies,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provisionedPrincipalHistory.js","sourceRoot":"","sources":["provisionedPrincipalHistory.ts"],"names":[],"mappings":"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","sourcesContent":["import type { PrincipalPolicyHistoryProgressOptions } from \"@tearleads/crypto\";\nimport type { PrincipalPolicyBundleResponse } from \"@tearleads/validators/response\";\nimport { assertProjectionVerificationCurrent } from \"../../data/keyingProjectionVerification/types\";\nimport type { PrincipalHistoryProtectionLease } from \"../../data/principals/principalHistoryProtection\";\nimport { principalPolicyReferenceFromBundle } from \"../../data/principals/principalPolicyAdminSigners\";\nimport type { ExecSql, ExecSqlClientLike } from \"../../data/sqlite/sqlSchema\";\nimport type {\n TrustedUserIdentity,\n TrustedUserIdentityResolver,\n} from \"../../data/trustedUserIdentity\";\nimport { createPrincipalCurrentRecoveryBatch } from \"../principals/principalCurrentRecoveryBatch\";\nimport type { PrincipalPolicyPageReader } from \"../principals/principalPolicyHistoryReader\";\nimport { queuePrincipalRecovery } from \"../principals/principalRecoveryQueue\";\n\n/** The version-1 policies a provisioning request signed and its response acknowledged. */\ninterface ProvisionedPrincipalPolicies {\n readonly adminGroup: PrincipalPolicyBundleResponse;\n readonly memberGroup: PrincipalPolicyBundleResponse;\n readonly organization: PrincipalPolicyBundleResponse;\n}\n\n/**\n * Records verified recovery progress for an organization's founding policy\n * heads, so the device's first scoped recovery of them needs no history read.\n * It is bound to the provisioning scope: the database the bootstrap committed\n * to and the identity that signed it. Failure leaves the online path.\n */\nexport type ProvisionedPrincipalHistoryPrimer = (input: {\n /** The database client the provisioning bootstrap committed to. */\n readonly database: ExecSqlClientLike;\n /** Whether the identity that provisioned is still the active one. */\n readonly isCurrent: () => boolean;\n readonly organizationId: string;\n readonly policies: ProvisionedPrincipalPolicies;\n readonly userId: string;\n}) => Promise<void>;\n\n/**\n * Serves only the acknowledged initial heads, each complete in one page. The\n * ordinary verifier still checks every signature, the directory binding and\n * strict Admins rules before any progress is saved.\n */\nfunction provisionedPolicyPages(\n policies: ProvisionedPrincipalPolicies,\n): PrincipalPolicyPageReader {\n const bundles = [\n policies.organization,\n policies.adminGroup,\n policies.memberGroup,\n ];\n return {\n async *getPrincipalPolicyPages(principalType, principalId, options = {}) {\n const bundle = bundles.find(\n ({ currentState }) =>\n currentState.principalType === principalType &&\n currentState.principalId === principalId,\n );\n if (\n !bundle ||\n options.resume !== undefined ||\n (options.afterVersion ?? 0) !== 0 ||\n (options.stateHash !== undefined &&\n options.stateHash !== bundle.currentState.stateHash)\n )\n throw new Error(\n \"Provisioned principal history holds only the acknowledged initial heads\",\n );\n yield {\n ok: true,\n data: {\n ...structuredClone(bundle),\n historyPage: { afterVersion: 0, nextAfterVersion: null },\n },\n };\n },\n };\n}\n\nasync function primeProvisionedPrincipalHistory(input: {\n readonly execSql: ExecSql;\n readonly organizationId: string;\n readonly policies: ProvisionedPrincipalPolicies;\n readonly protection: PrincipalPolicyHistoryProgressOptions;\n readonly resolveTrustedUserIdentity: TrustedUserIdentityResolver;\n readonly stillCurrent: () => boolean;\n}): Promise<void> {\n const { recover } = createPrincipalCurrentRecoveryBatch();\n const options = {\n historyReader: provisionedPolicyPages(input.policies),\n execSql: input.execSql,\n offline: false,\n organizationId: input.organizationId,\n protection: input.protection,\n resolveTrustedUserIdentity: input.resolveTrustedUserIdentity,\n stillCurrent: input.stillCurrent,\n };\n // Scoped recovery of each group also completes the directory and strict\n // Admins stages; Members reuses them through the shared batch.\n for (const group of [input.policies.adminGroup, input.policies.memberGroup])\n await recover({\n ...options,\n reference: principalPolicyReferenceFromBundle(group),\n });\n}\n\n/** The runtime seams priming reads; none of them writes durable state. */\ninterface ProvisionedPrincipalHistoryRuntime {\n readonly bindLease: () => PrincipalHistoryProtectionLease | undefined;\n /** The runtime executor, only while `database` is its ready database. */\n readonly execSqlFor: (database: ExecSqlClientLike) => ExecSql | null;\n readonly logError: (message: string | Error, cause?: unknown) => void;\n /** Read-only: the identity the trust store already pins for a user. */\n readonly loadPinnedIdentity: (\n execSql: ExecSql,\n userId: string,\n ) => Promise<TrustedUserIdentity | null>;\n readonly signingFingerprint: () => string | null;\n}\n\n/**\n * Binds priming to the exact provisioning scope, captured before any await:\n * the bootstrap's database and runtime executor, the identity whose key signed\n * the founding states, and a protection lease for that identity. Every later\n * step, and every progress write inside its transaction, rechecks that scope,\n * so a switched identity or database aborts priming without a durable write.\n * Priming never writes a trust pin; it only reads the founder's existing one.\n */\nexport function createProvisionedPrincipalHistoryPrimer(\n runtime: ProvisionedPrincipalHistoryRuntime,\n): ProvisionedPrincipalHistoryPrimer {\n return async (input) => {\n try {\n await primeInProvisioningScope(runtime, input);\n } catch (error) {\n runtime.logError(\n \"Provisioned principal history was not primed; recovery reads it online\",\n error,\n );\n }\n };\n}\n\nasync function primeInProvisioningScope(\n runtime: ProvisionedPrincipalHistoryRuntime,\n input: Parameters<ProvisionedPrincipalHistoryPrimer>[0],\n): Promise<void> {\n // Everything below is captured synchronously, before the first await.\n const founderFingerprint =\n input.policies.organization.currentState.signerUserKeyFingerprint;\n const execSql = runtime.execSqlFor(input.database);\n const scopeCurrent = () =>\n execSql !== null &&\n input.isCurrent() &&\n runtime.execSqlFor(input.database) === execSql &&\n runtime.signingFingerprint() === founderFingerprint;\n const lease = scopeCurrent() ? runtime.bindLease() : undefined;\n if (!execSql || !lease) return;\n const resolveTrustedUserIdentity: TrustedUserIdentityResolver = async (\n signerUserId,\n ) => {\n if (signerUserId !== input.userId) return null;\n assertProjectionVerificationCurrent(scopeCurrent);\n const identity = await runtime.loadPinnedIdentity(execSql, input.userId);\n assertProjectionVerificationCurrent(scopeCurrent);\n return identity?.signingKeyFingerprint === founderFingerprint\n ? identity\n : null;\n };\n await queuePrincipalRecovery(execSql, input.organizationId, () =>\n lease(({ protection, stillCurrent }) =>\n primeProvisionedPrincipalHistory({\n execSql,\n organizationId: input.organizationId,\n policies: input.policies,\n protection,\n resolveTrustedUserIdentity,\n // Progress writes check this inside their transactions.\n stillCurrent: () => stillCurrent() && scopeCurrent(),\n }),\n ),\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"provisionedPrincipalHistory.js","sourceRoot":"","sources":["provisionedPrincipalHistory.ts"],"names":[],"mappings":"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","sourcesContent":["import type { PrincipalPolicyHistoryProgressOptions } from \"@tearleads/crypto\";\nimport type { PrincipalPolicyBundleResponse } from \"@tearleads/validators/response\";\nimport { assertProjectionVerificationCurrent } from \"../../data/keyingProjectionVerification/types\";\nimport type { PrincipalHistoryProtectionLease } from \"../../data/principals/principalHistoryProtection\";\nimport { principalPolicyReferenceFromBundle } from \"../../data/principals/principalPolicyAdminSigners\";\nimport { getOrCreatePrincipalPolicyCoordinator } from \"../../data/principals/principalPolicyCoordinator\";\nimport type { ExecSql, ExecSqlClientLike } from \"../../data/sqlite/sqlSchema\";\nimport type {\n TrustedUserIdentity,\n TrustedUserIdentityResolver,\n} from \"../../data/trustedUserIdentity\";\nimport { createPrincipalCurrentRecoveryBatch } from \"../principals/principalCurrentRecoveryBatch\";\nimport type { PrincipalPolicyPageReader } from \"../principals/principalPolicyHistoryReader\";\n\n/** The version-1 policies a provisioning request signed and its response acknowledged. */\ninterface ProvisionedPrincipalPolicies {\n readonly adminGroup: PrincipalPolicyBundleResponse;\n readonly memberGroup: PrincipalPolicyBundleResponse;\n readonly organization: PrincipalPolicyBundleResponse;\n}\n\n/**\n * Records verified recovery progress for an organization's founding policy\n * heads, so the device's first scoped recovery of them needs no history read.\n * It is bound to the provisioning scope: the database the bootstrap committed\n * to and the identity that signed it. Failure leaves the online path.\n */\nexport type ProvisionedPrincipalHistoryPrimer = (input: {\n /** The database client the provisioning bootstrap committed to. */\n readonly database: ExecSqlClientLike;\n /** Whether the identity that provisioned is still the active one. */\n readonly isCurrent: () => boolean;\n readonly organizationId: string;\n readonly policies: ProvisionedPrincipalPolicies;\n readonly userId: string;\n}) => Promise<void>;\n\n/**\n * Serves only the acknowledged initial heads, each complete in one page. The\n * ordinary verifier still checks every signature, the directory binding and\n * strict Admins rules before any progress is saved.\n */\nfunction provisionedPolicyPages(\n policies: ProvisionedPrincipalPolicies,\n): PrincipalPolicyPageReader {\n const bundles = [\n policies.organization,\n policies.adminGroup,\n policies.memberGroup,\n ];\n return {\n async *getPrincipalPolicyPages(principalType, principalId, options = {}) {\n const bundle = bundles.find(\n ({ currentState }) =>\n currentState.principalType === principalType &&\n currentState.principalId === principalId,\n );\n if (\n !bundle ||\n options.resume !== undefined ||\n (options.afterVersion ?? 0) !== 0 ||\n (options.stateHash !== undefined &&\n options.stateHash !== bundle.currentState.stateHash)\n )\n throw new Error(\n \"Provisioned principal history holds only the acknowledged initial heads\",\n );\n yield {\n ok: true,\n data: {\n ...structuredClone(bundle),\n historyPage: { afterVersion: 0, nextAfterVersion: null },\n },\n };\n },\n };\n}\n\nasync function primeProvisionedPrincipalHistory(input: {\n readonly execSql: ExecSql;\n readonly organizationId: string;\n readonly policies: ProvisionedPrincipalPolicies;\n readonly protection: PrincipalPolicyHistoryProgressOptions;\n readonly resolveTrustedUserIdentity: TrustedUserIdentityResolver;\n readonly stillCurrent: () => boolean;\n}): Promise<void> {\n const { recover } = createPrincipalCurrentRecoveryBatch();\n const options = {\n historyReader: provisionedPolicyPages(input.policies),\n execSql: input.execSql,\n offline: false,\n organizationId: input.organizationId,\n protection: input.protection,\n resolveTrustedUserIdentity: input.resolveTrustedUserIdentity,\n stillCurrent: input.stillCurrent,\n };\n // Scoped recovery of each group also completes the directory and strict\n // Admins stages; Members reuses them through the shared batch.\n for (const group of [input.policies.adminGroup, input.policies.memberGroup])\n await recover({\n ...options,\n reference: principalPolicyReferenceFromBundle(group),\n });\n}\n\n/** The runtime seams priming reads; none of them writes durable state. */\ninterface ProvisionedPrincipalHistoryRuntime {\n readonly bindLease: () => PrincipalHistoryProtectionLease | undefined;\n /** The runtime executor, only while `database` is its ready database. */\n readonly execSqlFor: (database: ExecSqlClientLike) => ExecSql | null;\n readonly logError: (message: string | Error, cause?: unknown) => void;\n /** Read-only: the identity the trust store already pins for a user. */\n readonly loadPinnedIdentity: (\n execSql: ExecSql,\n userId: string,\n ) => Promise<TrustedUserIdentity | null>;\n readonly signingFingerprint: () => string | null;\n}\n\n/**\n * Binds priming to the exact provisioning scope, captured before any await:\n * the bootstrap's database and runtime executor, the identity whose key signed\n * the founding states, and a protection lease for that identity. Every later\n * step, and every progress write inside its transaction, rechecks that scope,\n * so a switched identity or database aborts priming without a durable write.\n * Priming never writes a trust pin; it only reads the founder's existing one.\n */\nexport function createProvisionedPrincipalHistoryPrimer(\n runtime: ProvisionedPrincipalHistoryRuntime,\n): ProvisionedPrincipalHistoryPrimer {\n return async (input) => {\n try {\n await primeInProvisioningScope(runtime, input);\n } catch (error) {\n runtime.logError(\n \"Provisioned principal history was not primed; recovery reads it online\",\n error,\n );\n }\n };\n}\n\nasync function primeInProvisioningScope(\n runtime: ProvisionedPrincipalHistoryRuntime,\n input: Parameters<ProvisionedPrincipalHistoryPrimer>[0],\n): Promise<void> {\n // Everything below is captured synchronously, before the first await.\n const founderFingerprint =\n input.policies.organization.currentState.signerUserKeyFingerprint;\n const execSql = runtime.execSqlFor(input.database);\n const scopeCurrent = () =>\n execSql !== null &&\n input.isCurrent() &&\n runtime.execSqlFor(input.database) === execSql &&\n runtime.signingFingerprint() === founderFingerprint;\n const lease = scopeCurrent() ? runtime.bindLease() : undefined;\n if (!execSql || !lease) return;\n const resolveTrustedUserIdentity: TrustedUserIdentityResolver = async (\n signerUserId,\n ) => {\n if (signerUserId !== input.userId) return null;\n assertProjectionVerificationCurrent(scopeCurrent);\n const identity = await runtime.loadPinnedIdentity(execSql, input.userId);\n assertProjectionVerificationCurrent(scopeCurrent);\n return identity?.signingKeyFingerprint === founderFingerprint\n ? identity\n : null;\n };\n await getOrCreatePrincipalPolicyCoordinator(execSql).queueRecovery(\n input.organizationId,\n () =>\n lease(({ protection, stillCurrent }) =>\n primeProvisionedPrincipalHistory({\n execSql,\n organizationId: input.organizationId,\n policies: input.policies,\n protection,\n resolveTrustedUserIdentity,\n // Progress writes check this inside their transactions.\n stillCurrent: () => stillCurrent() && scopeCurrent(),\n }),\n ),\n );\n}\n"]}
|