feat(ql3): establish 3.0 incubation baseline

This commit is contained in:
whyour
2026-08-12 00:25:26 +08:00
parent 4bf92dcfeb
commit c699c32461
2817 changed files with 779642 additions and 653 deletions
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,671 @@
import type { DatabaseSync } from 'node:sqlite';
import {
LocalOwnerCredentialRecoveryCredentialUnavailableError,
LocalOwnerCredentialRecoveryInProgressError,
LocalOwnerCredentialRecoveryMutationConflictError,
LocalOwnerCredentialRecoveryNotAcknowledgedError,
LocalOwnerCredentialRecoveryRepositoryUnavailableError,
normalizeAcknowledgeLocalOwnerCredentialRecoveryCommand,
normalizeCompleteLocalOwnerCredentialRecoveryCommand,
normalizeIssueLocalOwnerCredentialRecoveryCommand,
type AcknowledgeLocalOwnerCredentialRecoveryCommand,
type CompleteLocalOwnerCredentialRecoveryCommand,
type IssueLocalOwnerCredentialRecoveryCommand,
type LocalOwnerCredentialRecoveryRecord,
type LocalOwnerCredentialRecoveryRepository,
type LocalOwnerCredentialRecoveryResult,
} from '@qinglong/runtime-core/local-owner-credential-recovery';
import {
normalizeApiCredentialRecord,
type ApiCredentialRecord,
} from '@qinglong/runtime-core/api-credential';
import type { SecurityAuditRecord } from '@qinglong/runtime-core/security-audit';
import { LocalSqliteOperationAuthority } from '../authority/operationAuthority';
type QueryRow = Record<string, unknown>;
const RECOVERY_SELECT = `
SELECT recovery.*,
replacement."state" AS "replacement_state",
replacement."subject_type" AS "replacement_subject_type",
replacement."subject_id" AS "replacement_subject_id",
replacement."secret_digest" AS "replacement_secret_digest",
replacement."created_at_ms" AS "replacement_created_at_ms",
replacement."not_before_at_ms" AS "replacement_not_before_at_ms",
replacement."expires_at_ms" AS "replacement_expires_at_ms",
identity."status" AS "replacement_subject_status",
pepper."pepper_key_id" AS "replacement_pepper_key_id"
FROM "QingLong3LocalOwnerCredentialRecoveries" AS recovery
JOIN "QingLong3ApiCredentials" AS replacement
ON replacement."credential_id" = recovery."replacement_credential_id"
AND replacement."version" = recovery."replacement_credential_version"
JOIN "QingLong3IdentitySubjects" AS identity
ON identity."subject_type" = replacement."subject_type"
AND identity."subject_id" = replacement."subject_id"
JOIN "QingLong3ApiCredentialPepperBindings" AS pepper
ON pepper."credential_id" = replacement."credential_id"
AND pepper."credential_version" = replacement."version"`;
const CREDENTIAL_SELECT = `
SELECT credential."credential_id" AS "credential_credential_id",
credential."version" AS "credential_credential_version",
credential."state" AS "credential_state",
credential."subject_type" AS "credential_subject_type",
credential."subject_id" AS "credential_subject_id",
credential."secret_digest" AS "credential_secret_digest",
credential."created_at_ms" AS "credential_created_at_ms",
credential."not_before_at_ms" AS "credential_not_before_at_ms",
credential."expires_at_ms" AS "credential_expires_at_ms",
identity."status" AS "credential_subject_status",
pepper."pepper_key_id" AS "credential_pepper_key_id"
FROM "QingLong3ApiCredentials" AS credential
JOIN "QingLong3IdentitySubjects" AS identity
ON identity."subject_type" = credential."subject_type"
AND identity."subject_id" = credential."subject_id"
JOIN "QingLong3ApiCredentialPepperBindings" AS pepper
ON pepper."credential_id" = credential."credential_id"
AND pepper."credential_version" = credential."version"`;
function string(row: QueryRow, name: string): string {
const value = row[name];
if (typeof value !== 'string') {
throw new LocalOwnerCredentialRecoveryRepositoryUnavailableError();
}
return value;
}
function optionalString(row: QueryRow, name: string): string | undefined {
const value = row[name];
if (value === null || value === undefined) return undefined;
return string(row, name);
}
function integer(row: QueryRow, name: string): number {
const value = row[name];
if (typeof value !== 'number' || !Number.isSafeInteger(value)) {
throw new LocalOwnerCredentialRecoveryRepositoryUnavailableError();
}
return value;
}
function optionalInteger(row: QueryRow, name: string): number | undefined {
const value = row[name];
if (value === null || value === undefined) return undefined;
return integer(row, name);
}
function credentialFromRow(
row: QueryRow,
prefix: 'credential' | 'replacement',
): Readonly<ApiCredentialRecord> {
try {
return normalizeApiCredentialRecord({
credentialId: string(row, `${prefix}_credential_id`),
version: integer(row, `${prefix}_credential_version`),
pepperKeyId: string(row, `${prefix}_pepper_key_id`),
state: string(row, `${prefix}_state`) as ApiCredentialRecord['state'],
subject: {
type: string(
row,
`${prefix}_subject_type`,
) as ApiCredentialRecord['subject']['type'],
id: string(row, `${prefix}_subject_id`),
},
subjectStatus: string(
row,
`${prefix}_subject_status`,
) as ApiCredentialRecord['subjectStatus'],
secretDigest: string(row, `${prefix}_secret_digest`),
createdAtMs: integer(row, `${prefix}_created_at_ms`),
notBeforeAtMs: integer(row, `${prefix}_not_before_at_ms`),
expiresAtMs: integer(row, `${prefix}_expires_at_ms`),
});
} catch (error) {
if (
error instanceof LocalOwnerCredentialRecoveryRepositoryUnavailableError
) {
throw error;
}
throw new LocalOwnerCredentialRecoveryRepositoryUnavailableError();
}
}
function recoveryFromRow(
row: QueryRow,
): Readonly<LocalOwnerCredentialRecoveryRecord> {
const state = string(row, 'state');
if (state !== 'issued' && state !== 'acknowledged' && state !== 'completed') {
throw new LocalOwnerCredentialRecoveryRepositoryUnavailableError();
}
const deliveryDigest = optionalString(row, 'delivery_digest');
const acknowledgedAtMs = optionalInteger(row, 'acknowledged_at_ms');
const completeMutationId = optionalString(row, 'complete_mutation_id');
const completeRequestId = optionalString(row, 'complete_request_id');
const revokedCredentialVersion = optionalInteger(
row,
'revoked_credential_version',
);
const completedAtMs = optionalInteger(row, 'completed_at_ms');
if (
(state === 'issued' &&
(deliveryDigest !== undefined ||
acknowledgedAtMs !== undefined ||
completeMutationId !== undefined ||
completeRequestId !== undefined ||
revokedCredentialVersion !== undefined ||
completedAtMs !== undefined)) ||
(state === 'acknowledged' &&
(deliveryDigest === undefined ||
acknowledgedAtMs === undefined ||
completeMutationId !== undefined ||
completeRequestId !== undefined ||
revokedCredentialVersion !== undefined ||
completedAtMs !== undefined)) ||
(state === 'completed' &&
(deliveryDigest === undefined ||
acknowledgedAtMs === undefined ||
completeMutationId === undefined ||
completeRequestId === undefined ||
revokedCredentialVersion === undefined ||
completedAtMs === undefined))
) {
throw new LocalOwnerCredentialRecoveryRepositoryUnavailableError();
}
return Object.freeze({
issueMutationId: string(row, 'issue_mutation_id'),
issueRequestId: string(row, 'issue_request_id'),
subjectId: string(row, 'subject_id'),
previousCredentialId: string(row, 'previous_credential_id'),
previousCredentialVersion: integer(row, 'previous_credential_version'),
replacementCredential: credentialFromRow(row, 'replacement'),
state,
issuedAtMs: integer(row, 'issued_at_ms'),
...(deliveryDigest === undefined ? {} : { deliveryDigest }),
...(acknowledgedAtMs === undefined ? {} : { acknowledgedAtMs }),
...(completeMutationId === undefined ? {} : { completeMutationId }),
...(completeRequestId === undefined ? {} : { completeRequestId }),
...(revokedCredentialVersion === undefined
? {}
: { revokedCredentialVersion }),
...(completedAtMs === undefined ? {} : { completedAtMs }),
});
}
function sameCredential(
left: Readonly<ApiCredentialRecord>,
right: Readonly<ApiCredentialRecord>,
): boolean {
return JSON.stringify(left) === JSON.stringify(right);
}
function insertAudit(
client: DatabaseSync,
audit: Readonly<SecurityAuditRecord>,
) {
client
.prepare(
`INSERT INTO "QingLong3SecurityAuditEvents" (
event_id, request_id, operation_id, project_id, subject_type,
subject_id, authentication_id, outcome, reasons_json,
fence_project_version, fence_binding_version, occurred_at_ms
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
)
.run(
audit.eventId,
audit.requestId,
audit.operationId,
audit.projectId,
audit.subject?.type ?? null,
audit.subject?.id ?? null,
audit.authenticationId,
audit.outcome,
JSON.stringify(audit.reasons),
audit.fence?.projectVersion ?? null,
audit.fence?.bindingVersion ?? null,
audit.occurredAtMs,
);
}
function isDomainError(error: unknown): boolean {
return (
error instanceof LocalOwnerCredentialRecoveryMutationConflictError ||
error instanceof LocalOwnerCredentialRecoveryInProgressError ||
error instanceof LocalOwnerCredentialRecoveryNotAcknowledgedError ||
error instanceof LocalOwnerCredentialRecoveryCredentialUnavailableError ||
error instanceof LocalOwnerCredentialRecoveryRepositoryUnavailableError
);
}
export class LocalSqliteOwnerCredentialRecoveryRepository
implements LocalOwnerCredentialRecoveryRepository
{
private readonly authority: LocalSqliteOperationAuthority;
constructor(authority: LocalSqliteOperationAuthority | DatabaseSync) {
this.authority =
authority instanceof LocalSqliteOperationAuthority
? authority
: new LocalSqliteOperationAuthority(authority);
}
private resolveDirect(
issueMutationId: string,
): Readonly<LocalOwnerCredentialRecoveryRecord> | null {
const rows = this.authority.client
.prepare(
`${RECOVERY_SELECT} WHERE recovery."issue_mutation_id" = ? LIMIT 2`,
)
.all(issueMutationId) as QueryRow[];
if (rows.length > 1) {
throw new LocalOwnerCredentialRecoveryRepositoryUnavailableError();
}
return rows[0] ? recoveryFromRow(rows[0]) : null;
}
private currentCredentialDirect(
credentialId: string,
): Readonly<ApiCredentialRecord> | null {
const row = this.authority.client
.prepare(
`${CREDENTIAL_SELECT}
WHERE credential."credential_id" = ?
ORDER BY credential."version" DESC LIMIT 1`,
)
.get(credentialId) as QueryRow | undefined;
return row ? credentialFromRow(row, 'credential') : null;
}
resolve(
issueMutationId: string,
): Promise<Readonly<LocalOwnerCredentialRecoveryRecord> | null> {
return this.authority.enqueue(
async () => {
try {
return this.resolveDirect(issueMutationId);
} catch (error) {
if (
error instanceof
LocalOwnerCredentialRecoveryRepositoryUnavailableError
) {
throw error;
}
throw new LocalOwnerCredentialRecoveryRepositoryUnavailableError();
}
},
() => new LocalOwnerCredentialRecoveryRepositoryUnavailableError(),
);
}
issue(
input: IssueLocalOwnerCredentialRecoveryCommand,
): Promise<LocalOwnerCredentialRecoveryResult> {
const command = normalizeIssueLocalOwnerCredentialRecoveryCommand(input);
return this.authority.enqueue(
async () => {
const client = this.authority.client;
client.exec('BEGIN IMMEDIATE');
try {
const replay = this.resolveDirect(command.mutationId);
if (replay) {
if (
replay.issueRequestId !== command.requestId ||
replay.previousCredentialId !== command.previousCredentialId ||
replay.previousCredentialVersion !==
command.expectedPreviousVersion ||
!sameCredential(
replay.replacementCredential,
command.replacementCredential,
)
) {
throw new LocalOwnerCredentialRecoveryMutationConflictError();
}
client.exec('COMMIT');
return Object.freeze({
status: 'existing' as const,
recovery: replay,
});
}
if (
client
.prepare(
`SELECT 1 FROM "QingLong3LocalOwnerCredentialRecoveries"
WHERE "subject_id" = ? AND "state" <> 'completed' LIMIT 1`,
)
.get(command.replacementCredential.subject.id)
) {
throw new LocalOwnerCredentialRecoveryInProgressError();
}
const previous = this.currentCredentialDirect(
command.previousCredentialId,
);
if (
!previous ||
previous.version !== command.expectedPreviousVersion ||
previous.state !== 'active' ||
previous.subject.type !== 'user' ||
previous.subject.id !== command.replacementCredential.subject.id ||
previous.subjectStatus !== 'active' ||
previous.notBeforeAtMs >
command.replacementCredential.createdAtMs ||
previous.expiresAtMs <= command.replacementCredential.createdAtMs
) {
throw new LocalOwnerCredentialRecoveryCredentialUnavailableError();
}
const activePepper = client
.prepare(
`SELECT key."pepper_key_id"
FROM "QingLong3LocalOwnerPepperActivations" AS activation
JOIN "QingLong3LocalOwnerPepperKeys" AS key
ON key."pepper_key_id" = activation."active_pepper_key_id"
WHERE key."state" = 'active'
ORDER BY activation."generation" DESC LIMIT 1`,
)
.get() as QueryRow | undefined;
if (
!activePepper ||
string(activePepper, 'pepper_key_id') !==
command.replacementCredential.pepperKeyId
) {
throw new LocalOwnerCredentialRecoveryCredentialUnavailableError();
}
if (
client
.prepare(
`SELECT 1 FROM "QingLong3ApiCredentials"
WHERE "credential_id" = ? LIMIT 1`,
)
.get(command.replacementCredential.credentialId) ||
client
.prepare(
`SELECT 1 FROM "QingLong3SecurityAuditEvents"
WHERE "event_id" = ? LIMIT 1`,
)
.get(command.audit.eventId)
) {
throw new LocalOwnerCredentialRecoveryMutationConflictError();
}
const replacement = command.replacementCredential;
client
.prepare(
`INSERT INTO "QingLong3ApiCredentials" (
credential_id, version, state, subject_type, subject_id,
secret_digest, created_at_ms, not_before_at_ms, expires_at_ms
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
)
.run(
replacement.credentialId,
replacement.version,
replacement.state,
replacement.subject.type,
replacement.subject.id,
replacement.secretDigest,
replacement.createdAtMs,
replacement.notBeforeAtMs,
replacement.expiresAtMs,
);
client
.prepare(
`INSERT INTO "QingLong3ApiCredentialPepperBindings" (
credential_id, credential_version, pepper_key_id
) VALUES (?, ?, ?)`,
)
.run(
replacement.credentialId,
replacement.version,
replacement.pepperKeyId,
);
insertAudit(client, command.audit);
client
.prepare(
`INSERT INTO "QingLong3LocalOwnerCredentialRecoveries" (
issue_mutation_id, issue_request_id, subject_type, subject_id,
previous_credential_id, previous_credential_version,
replacement_credential_id, replacement_credential_version,
state, issued_at_ms, issue_audit_event_id
) VALUES (?, ?, 'user', ?, ?, ?, ?, ?, 'issued', ?, ?)`,
)
.run(
command.mutationId,
command.requestId,
replacement.subject.id,
command.previousCredentialId,
command.expectedPreviousVersion,
replacement.credentialId,
replacement.version,
replacement.createdAtMs,
command.audit.eventId,
);
const recovery = this.resolveDirect(command.mutationId);
if (!recovery) {
throw new LocalOwnerCredentialRecoveryRepositoryUnavailableError();
}
client.exec('COMMIT');
return Object.freeze({ status: 'inserted' as const, recovery });
} catch (error) {
if (client.isTransaction) client.exec('ROLLBACK');
if (isDomainError(error)) throw error;
throw new LocalOwnerCredentialRecoveryRepositoryUnavailableError();
}
},
() => new LocalOwnerCredentialRecoveryRepositoryUnavailableError(),
);
}
acknowledge(
input: AcknowledgeLocalOwnerCredentialRecoveryCommand,
): Promise<LocalOwnerCredentialRecoveryResult> {
const command =
normalizeAcknowledgeLocalOwnerCredentialRecoveryCommand(input);
return this.authority.enqueue(
async () => {
const client = this.authority.client;
client.exec('BEGIN IMMEDIATE');
try {
const recovery = this.resolveDirect(command.issueMutationId);
if (
!recovery ||
recovery.issueRequestId !== command.requestId ||
recovery.replacementCredential.credentialId !==
command.credentialId ||
recovery.replacementCredential.secretDigest !==
command.factDigest ||
command.acknowledgedAtMs < recovery.issuedAtMs ||
command.acknowledgedAtMs >=
recovery.replacementCredential.expiresAtMs
) {
throw new LocalOwnerCredentialRecoveryMutationConflictError();
}
if (recovery.state !== 'issued') {
if (
recovery.deliveryDigest !== command.deliveryDigest ||
recovery.acknowledgedAtMs !== command.acknowledgedAtMs
) {
throw new LocalOwnerCredentialRecoveryMutationConflictError();
}
client.exec('COMMIT');
return Object.freeze({
status: 'existing' as const,
recovery,
});
}
const changed = client
.prepare(
`UPDATE "QingLong3LocalOwnerCredentialRecoveries"
SET state = 'acknowledged', delivery_digest = ?,
acknowledged_at_ms = ?
WHERE issue_mutation_id = ? AND state = 'issued'`,
)
.run(
command.deliveryDigest,
command.acknowledgedAtMs,
command.issueMutationId,
);
if (changed.changes !== 1) {
throw new LocalOwnerCredentialRecoveryMutationConflictError();
}
const acknowledged = this.resolveDirect(command.issueMutationId);
if (!acknowledged || acknowledged.state !== 'acknowledged') {
throw new LocalOwnerCredentialRecoveryRepositoryUnavailableError();
}
client.exec('COMMIT');
return Object.freeze({
status: 'inserted' as const,
recovery: acknowledged,
});
} catch (error) {
if (client.isTransaction) client.exec('ROLLBACK');
if (isDomainError(error)) throw error;
throw new LocalOwnerCredentialRecoveryRepositoryUnavailableError();
}
},
() => new LocalOwnerCredentialRecoveryRepositoryUnavailableError(),
);
}
complete(
input: CompleteLocalOwnerCredentialRecoveryCommand,
): Promise<LocalOwnerCredentialRecoveryResult> {
const command = normalizeCompleteLocalOwnerCredentialRecoveryCommand(input);
return this.authority.enqueue(
async () => {
const client = this.authority.client;
client.exec('BEGIN IMMEDIATE');
try {
const replayRow = client
.prepare(
`SELECT "issue_mutation_id"
FROM "QingLong3LocalOwnerCredentialRecoveries"
WHERE "complete_mutation_id" = ? LIMIT 1`,
)
.get(command.mutationId) as QueryRow | undefined;
if (replayRow) {
const replay = this.resolveDirect(
string(replayRow, 'issue_mutation_id'),
);
const replayedRevocation = replay
? this.currentCredentialDirect(replay.previousCredentialId)
: null;
if (
!replay ||
!replayedRevocation ||
replay.issueMutationId !== command.issueMutationId ||
replay.completeRequestId !== command.requestId ||
replay.previousCredentialVersion !==
command.expectedPreviousVersion ||
replay.revokedCredentialVersion !==
command.revokedCredential.version ||
replay.completedAtMs !== command.revokedCredential.createdAtMs ||
!sameCredential(replayedRevocation, command.revokedCredential)
) {
throw new LocalOwnerCredentialRecoveryMutationConflictError();
}
client.exec('COMMIT');
return Object.freeze({
status: 'existing' as const,
recovery: replay,
});
}
const recovery = this.resolveDirect(command.issueMutationId);
if (!recovery) {
throw new LocalOwnerCredentialRecoveryCredentialUnavailableError();
}
if (recovery.state === 'issued') {
throw new LocalOwnerCredentialRecoveryNotAcknowledgedError();
}
if (recovery.state === 'completed') {
throw new LocalOwnerCredentialRecoveryMutationConflictError();
}
const previous = this.currentCredentialDirect(
recovery.previousCredentialId,
);
const revoked = command.revokedCredential;
if (
!previous ||
previous.version !== command.expectedPreviousVersion ||
previous.version !== recovery.previousCredentialVersion ||
previous.state !== 'active' ||
previous.subject.id !== recovery.subjectId ||
revoked.credentialId !== previous.credentialId ||
revoked.subject.type !== previous.subject.type ||
revoked.subject.id !== previous.subject.id ||
revoked.subjectStatus !== previous.subjectStatus ||
revoked.pepperKeyId !== previous.pepperKeyId ||
revoked.createdAtMs < (recovery.acknowledgedAtMs ?? 0) ||
revoked.createdAtMs >= recovery.replacementCredential.expiresAtMs
) {
throw new LocalOwnerCredentialRecoveryCredentialUnavailableError();
}
if (
client
.prepare(
`SELECT 1 FROM "QingLong3SecurityAuditEvents"
WHERE "event_id" = ? LIMIT 1`,
)
.get(command.audit.eventId)
) {
throw new LocalOwnerCredentialRecoveryMutationConflictError();
}
client
.prepare(
`INSERT INTO "QingLong3ApiCredentials" (
credential_id, version, state, subject_type, subject_id,
secret_digest, created_at_ms, not_before_at_ms, expires_at_ms
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
)
.run(
revoked.credentialId,
revoked.version,
revoked.state,
revoked.subject.type,
revoked.subject.id,
revoked.secretDigest,
revoked.createdAtMs,
revoked.notBeforeAtMs,
revoked.expiresAtMs,
);
client
.prepare(
`INSERT INTO "QingLong3ApiCredentialPepperBindings" (
credential_id, credential_version, pepper_key_id
) VALUES (?, ?, ?)`,
)
.run(revoked.credentialId, revoked.version, revoked.pepperKeyId);
insertAudit(client, command.audit);
const changed = client
.prepare(
`UPDATE "QingLong3LocalOwnerCredentialRecoveries"
SET state = 'completed', complete_mutation_id = ?,
complete_request_id = ?, revoked_credential_version = ?,
completed_at_ms = ?, complete_audit_event_id = ?
WHERE issue_mutation_id = ? AND state = 'acknowledged'`,
)
.run(
command.mutationId,
command.requestId,
revoked.version,
revoked.createdAtMs,
command.audit.eventId,
command.issueMutationId,
);
if (changed.changes !== 1) {
throw new LocalOwnerCredentialRecoveryMutationConflictError();
}
const completed = this.resolveDirect(command.issueMutationId);
if (!completed || completed.state !== 'completed') {
throw new LocalOwnerCredentialRecoveryRepositoryUnavailableError();
}
client.exec('COMMIT');
return Object.freeze({
status: 'inserted' as const,
recovery: completed,
});
} catch (error) {
if (client.isTransaction) client.exec('ROLLBACK');
if (isDomainError(error)) throw error;
throw new LocalOwnerCredentialRecoveryRepositoryUnavailableError();
}
},
() => new LocalOwnerCredentialRecoveryRepositoryUnavailableError(),
);
}
}
@@ -0,0 +1,508 @@
import type { DatabaseSync } from 'node:sqlite';
import {
localOwnerSecretDeliveryAcknowledgementSemanticDigest,
normalizeLocalOwnerSecretDeliveryAcknowledgementRecord,
type LocalOwnerSecretDeliveryAcknowledgementRecord,
} from '@qinglong/runtime-core/local-owner-bootstrap';
import {
LocalOwnerDeliveryAcknowledgementGcMutationConflictError,
LocalOwnerDeliveryAcknowledgementGcReferenceConflictError,
LocalOwnerDeliveryAcknowledgementGcRepositoryUnavailableError,
LocalOwnerDeliveryAcknowledgementGcRetentionPendingError,
localOwnerDeliveryAcknowledgementGcRetentionPolicyDigest,
normalizeCompactLocalOwnerDeliveryAcknowledgementCommand,
type CompactLocalOwnerDeliveryAcknowledgementCommand,
type LocalOwnerDeliveryAcknowledgementGcRecord,
type LocalOwnerDeliveryAcknowledgementGcRepository,
type LocalOwnerDeliveryAcknowledgementGcResult,
} from '@qinglong/runtime-core/local-owner-delivery-acknowledgement-gc';
import type { SecurityAuditRecord } from '@qinglong/runtime-core/security-audit';
import { LocalSqliteOperationAuthority } from '../authority/operationAuthority';
type QueryRow = Record<string, unknown>;
const GC_SELECT = `
SELECT * FROM "QingLong3LocalOwnerDeliveryAcknowledgementGc"`;
function text(row: QueryRow, name: string): string {
const value = row[name];
if (typeof value !== 'string') {
throw new LocalOwnerDeliveryAcknowledgementGcRepositoryUnavailableError();
}
return value;
}
function optionalText(row: QueryRow, name: string): string | undefined {
const value = row[name];
if (value === null || value === undefined) return undefined;
return text(row, name);
}
function integer(row: QueryRow, name: string): number {
const value = row[name];
if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < 0) {
throw new LocalOwnerDeliveryAcknowledgementGcRepositoryUnavailableError();
}
return value;
}
function safeRetentionTimestamp(base: number, duration: number): number {
const result = base + duration;
if (!Number.isSafeInteger(result) || result < 0) {
throw new LocalOwnerDeliveryAcknowledgementGcRepositoryUnavailableError();
}
return result;
}
function acknowledgementFromRow(
row: QueryRow,
): Readonly<LocalOwnerSecretDeliveryAcknowledgementRecord> {
try {
const common = {
mutationId: text(row, 'mutation_id'),
requestId: text(row, 'request_id'),
factDigest: text(row, 'fact_digest'),
deliveryDigest: text(row, 'delivery_digest'),
ttlMs: integer(row, 'ttl_ms'),
acknowledgedAtMs: integer(row, 'acknowledged_at_ms'),
};
const kind = text(row, 'kind');
return normalizeLocalOwnerSecretDeliveryAcknowledgementRecord(
kind === 'credential'
? {
...common,
kind,
subjectId: text(row, 'subject_id'),
credentialId: text(row, 'credential_id'),
}
: {
...common,
kind: kind as 'challenge',
projectId: text(row, 'project_id'),
challengeId: text(row, 'challenge_id'),
},
);
} catch (error) {
if (
error instanceof
LocalOwnerDeliveryAcknowledgementGcRepositoryUnavailableError
) {
throw error;
}
throw new LocalOwnerDeliveryAcknowledgementGcRepositoryUnavailableError();
}
}
function gcRecord(
row: QueryRow,
): Readonly<LocalOwnerDeliveryAcknowledgementGcRecord> {
const kind = text(row, 'acknowledgement_kind');
const provisioningMutationId = optionalText(row, 'provisioning_mutation_id');
const challengeMutationId = optionalText(row, 'challenge_mutation_id');
const acknowledgementMutationId = text(row, 'acknowledgement_mutation_id');
if (
(kind !== 'credential' && kind !== 'challenge') ||
(kind === 'credential' &&
(provisioningMutationId !== acknowledgementMutationId ||
challengeMutationId !== undefined)) ||
(kind === 'challenge' &&
(challengeMutationId !== acknowledgementMutationId ||
provisioningMutationId !== undefined))
) {
throw new LocalOwnerDeliveryAcknowledgementGcRepositoryUnavailableError();
}
const retentionPolicy = Object.freeze({
version: 1 as const,
replayRetentionMs: integer(row, 'replay_retention_ms'),
auditRetentionMs: integer(row, 'audit_retention_ms'),
});
const retentionPolicyDigest = text(row, 'retention_policy_digest');
if (
integer(row, 'retention_policy_version') !== 1 ||
localOwnerDeliveryAcknowledgementGcRetentionPolicyDigest(
retentionPolicy,
) !== retentionPolicyDigest
) {
throw new LocalOwnerDeliveryAcknowledgementGcRepositoryUnavailableError();
}
return Object.freeze({
mutationId: text(row, 'gc_mutation_id'),
requestId: text(row, 'gc_request_id'),
acknowledgementMutationId,
acknowledgementKind: kind,
deliveryDigest: text(row, 'delivery_digest'),
acknowledgedAtMs: integer(row, 'acknowledged_at_ms'),
acknowledgementSemanticDigest: text(row, 'acknowledgement_semantic_digest'),
bridgeClearEvidenceDigest: text(row, 'bridge_clear_evidence_digest'),
retentionPolicy,
retentionPolicyDigest,
retentionEligibleAtMs: integer(row, 'retention_eligible_at_ms'),
compactedAtMs: integer(row, 'compacted_at_ms'),
});
}
function sameCompact(
record: Readonly<LocalOwnerDeliveryAcknowledgementGcRecord>,
command: Readonly<CompactLocalOwnerDeliveryAcknowledgementCommand>,
): boolean {
return (
record.mutationId === command.mutationId &&
record.requestId === command.requestId &&
record.acknowledgementMutationId === command.acknowledgementMutationId &&
record.acknowledgementKind === command.expectedKind &&
record.deliveryDigest === command.expectedDeliveryDigest &&
record.bridgeClearEvidenceDigest ===
command.bridgeClearEvidence.evidenceDigest &&
record.retentionPolicyDigest ===
localOwnerDeliveryAcknowledgementGcRetentionPolicyDigest(
command.retentionPolicy,
) &&
record.compactedAtMs === command.compactedAtMs
);
}
function insertAudit(
client: DatabaseSync,
audit: Readonly<SecurityAuditRecord>,
): void {
client
.prepare(
`INSERT INTO "QingLong3SecurityAuditEvents" (
event_id, request_id, operation_id, project_id, subject_type,
subject_id, authentication_id, outcome, reasons_json,
fence_project_version, fence_binding_version, occurred_at_ms
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
)
.run(
audit.eventId,
audit.requestId,
audit.operationId,
audit.projectId,
audit.subject?.type ?? null,
audit.subject?.id ?? null,
audit.authenticationId,
audit.outcome,
JSON.stringify(audit.reasons),
audit.fence?.projectVersion ?? null,
audit.fence?.bindingVersion ?? null,
audit.occurredAtMs,
);
}
function sourceRetentionEligibleAt(
client: DatabaseSync,
acknowledgement: Readonly<LocalOwnerSecretDeliveryAcknowledgementRecord>,
command: Readonly<CompactLocalOwnerDeliveryAcknowledgementCommand>,
): number {
const replayEligibleAt = safeRetentionTimestamp(
acknowledgement.acknowledgedAtMs,
command.retentionPolicy.replayRetentionMs,
);
if (acknowledgement.kind === 'credential') {
const source = client
.prepare(
`SELECT provisioning."request_id", provisioning."subject_id",
provisioning."credential_id", credential."version",
credential."secret_digest", credential."not_before_at_ms",
credential."expires_at_ms", audit."occurred_at_ms"
FROM "QingLong3LocalIdentityProvisionings" AS provisioning
JOIN "QingLong3ApiCredentials" AS credential
ON credential."credential_id" = provisioning."credential_id"
AND credential."version" = provisioning."credential_version"
JOIN "QingLong3SecurityAuditEvents" AS audit
ON audit."event_id" = provisioning."audit_event_id"
WHERE provisioning."mutation_id" = ?`,
)
.get(acknowledgement.mutationId) as QueryRow | undefined;
if (
!source ||
text(source, 'request_id') !== acknowledgement.requestId ||
text(source, 'subject_id') !== acknowledgement.subjectId ||
text(source, 'credential_id') !== acknowledgement.credentialId ||
text(source, 'secret_digest') !== acknowledgement.factDigest ||
integer(source, 'expires_at_ms') - integer(source, 'not_before_at_ms') !==
acknowledgement.ttlMs
) {
throw new LocalOwnerDeliveryAcknowledgementGcMutationConflictError();
}
const current = client
.prepare(
`SELECT "state", "expires_at_ms"
FROM "QingLong3ApiCredentials"
WHERE "credential_id" = ?
ORDER BY "version" DESC LIMIT 1`,
)
.get(acknowledgement.credentialId) as QueryRow | undefined;
if (
!current ||
(text(current, 'state') === 'active' &&
integer(current, 'expires_at_ms') > command.compactedAtMs)
) {
throw new LocalOwnerDeliveryAcknowledgementGcReferenceConflictError();
}
if (
client
.prepare(
`SELECT 1
FROM "QingLong3LocalOwnerCredentialRecoveries"
WHERE "state" <> 'completed'
AND (("previous_credential_id" = ? AND "previous_credential_version" = ?)
OR ("replacement_credential_id" = ? AND "replacement_credential_version" = ?))
LIMIT 1`,
)
.get(
acknowledgement.credentialId,
integer(source, 'version'),
acknowledgement.credentialId,
integer(source, 'version'),
)
) {
throw new LocalOwnerDeliveryAcknowledgementGcReferenceConflictError();
}
return Math.max(
replayEligibleAt,
integer(source, 'expires_at_ms'),
safeRetentionTimestamp(
integer(source, 'occurred_at_ms'),
command.retentionPolicy.auditRetentionMs,
),
);
}
const source = client
.prepare(
`SELECT challenge."issue_request_id", challenge."project_id",
challenge."challenge_id", challenge."token_digest",
challenge."issued_at_ms", challenge."expires_at_ms",
challenge."consumed_at_ms",
issue_audit."occurred_at_ms" AS "issue_audit_at_ms",
claim_audit."occurred_at_ms" AS "claim_audit_at_ms"
FROM "QingLong3LocalOwnerBootstrapChallenges" AS challenge
JOIN "QingLong3SecurityAuditEvents" AS issue_audit
ON issue_audit."event_id" = challenge."issue_audit_event_id"
LEFT JOIN "QingLong3SecurityAuditEvents" AS claim_audit
ON claim_audit."event_id" = challenge."claim_audit_event_id"
WHERE challenge."issue_mutation_id" = ?`,
)
.get(acknowledgement.mutationId) as QueryRow | undefined;
if (
!source ||
text(source, 'issue_request_id') !== acknowledgement.requestId ||
text(source, 'project_id') !== acknowledgement.projectId ||
text(source, 'challenge_id') !== acknowledgement.challengeId ||
text(source, 'token_digest') !== acknowledgement.factDigest ||
integer(source, 'expires_at_ms') - integer(source, 'issued_at_ms') !==
acknowledgement.ttlMs
) {
throw new LocalOwnerDeliveryAcknowledgementGcMutationConflictError();
}
if (
source.consumed_at_ms === null &&
integer(source, 'expires_at_ms') > command.compactedAtMs
) {
throw new LocalOwnerDeliveryAcknowledgementGcReferenceConflictError();
}
const claimAuditAtMs =
source.claim_audit_at_ms === null
? undefined
: integer(source, 'claim_audit_at_ms');
return Math.max(
replayEligibleAt,
integer(source, 'expires_at_ms'),
safeRetentionTimestamp(
integer(source, 'issue_audit_at_ms'),
command.retentionPolicy.auditRetentionMs,
),
...(claimAuditAtMs === undefined
? []
: [
safeRetentionTimestamp(
claimAuditAtMs,
command.retentionPolicy.auditRetentionMs,
),
]),
);
}
function isDomainError(error: unknown): boolean {
return (
error instanceof LocalOwnerDeliveryAcknowledgementGcMutationConflictError ||
error instanceof
LocalOwnerDeliveryAcknowledgementGcReferenceConflictError ||
error instanceof LocalOwnerDeliveryAcknowledgementGcRetentionPendingError ||
error instanceof
LocalOwnerDeliveryAcknowledgementGcRepositoryUnavailableError
);
}
export class LocalSqliteOwnerDeliveryAcknowledgementGcRepository
implements LocalOwnerDeliveryAcknowledgementGcRepository
{
private readonly authority: LocalSqliteOperationAuthority;
constructor(authority: LocalSqliteOperationAuthority | DatabaseSync) {
this.authority =
authority instanceof LocalSqliteOperationAuthority
? authority
: new LocalSqliteOperationAuthority(authority);
}
resolveByAcknowledgement(
acknowledgementMutationId: string,
): Promise<Readonly<LocalOwnerDeliveryAcknowledgementGcRecord> | null> {
if (typeof acknowledgementMutationId !== 'string') {
throw new LocalOwnerDeliveryAcknowledgementGcRepositoryUnavailableError();
}
return this.authority.enqueue(
async () => {
try {
const row = this.authority.client
.prepare(`${GC_SELECT} WHERE "acknowledgement_mutation_id" = ?`)
.get(acknowledgementMutationId) as QueryRow | undefined;
return row ? gcRecord(row) : null;
} catch (error) {
if (isDomainError(error)) throw error;
throw new LocalOwnerDeliveryAcknowledgementGcRepositoryUnavailableError();
}
},
() => new LocalOwnerDeliveryAcknowledgementGcRepositoryUnavailableError(),
);
}
compact(
candidate: CompactLocalOwnerDeliveryAcknowledgementCommand,
): Promise<Readonly<LocalOwnerDeliveryAcknowledgementGcResult>> {
const command =
normalizeCompactLocalOwnerDeliveryAcknowledgementCommand(candidate);
return this.authority.enqueue(
async () => {
const client = this.authority.client;
try {
client.exec('BEGIN IMMEDIATE');
const replay = client
.prepare(`${GC_SELECT} WHERE "gc_mutation_id" = ?`)
.get(command.mutationId) as QueryRow | undefined;
if (replay) {
const record = gcRecord(replay);
if (!sameCompact(record, command)) {
throw new LocalOwnerDeliveryAcknowledgementGcMutationConflictError();
}
client.exec('COMMIT');
return Object.freeze({ status: 'existing' as const, record });
}
if (
client
.prepare(`${GC_SELECT} WHERE "acknowledgement_mutation_id" = ?`)
.get(command.acknowledgementMutationId)
) {
throw new LocalOwnerDeliveryAcknowledgementGcMutationConflictError();
}
const row = client
.prepare(
`SELECT * FROM "QingLong3LocalOwnerDeliveryAcknowledgements"
WHERE "mutation_id" = ?`,
)
.get(command.acknowledgementMutationId) as QueryRow | undefined;
if (!row) {
throw new LocalOwnerDeliveryAcknowledgementGcMutationConflictError();
}
const acknowledgement = acknowledgementFromRow(row);
if (
acknowledgement.kind !== command.expectedKind ||
acknowledgement.deliveryDigest !== command.expectedDeliveryDigest
) {
throw new LocalOwnerDeliveryAcknowledgementGcMutationConflictError();
}
const eligibleAtMs = sourceRetentionEligibleAt(
client,
acknowledgement,
command,
);
if (command.compactedAtMs < eligibleAtMs) {
throw new LocalOwnerDeliveryAcknowledgementGcRetentionPendingError(
eligibleAtMs,
);
}
if (
client
.prepare(
`SELECT 1 FROM "QingLong3SecurityAuditEvents"
WHERE "event_id" = ?`,
)
.get(command.audit.eventId)
) {
throw new LocalOwnerDeliveryAcknowledgementGcMutationConflictError();
}
const semanticDigest =
localOwnerSecretDeliveryAcknowledgementSemanticDigest(
acknowledgement,
);
const policyDigest =
localOwnerDeliveryAcknowledgementGcRetentionPolicyDigest(
command.retentionPolicy,
);
insertAudit(client, command.audit);
client
.prepare(
`INSERT INTO "QingLong3LocalOwnerDeliveryAcknowledgementGc" (
gc_mutation_id, gc_request_id,
acknowledgement_mutation_id, acknowledgement_kind,
delivery_digest, acknowledged_at_ms,
acknowledgement_semantic_digest,
bridge_clear_evidence_digest, retention_policy_version,
replay_retention_ms, audit_retention_ms,
retention_policy_digest, retention_eligible_at_ms,
compacted_at_ms, audit_event_id,
provisioning_mutation_id, challenge_mutation_id
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?, ?, ?, ?, ?)`,
)
.run(
command.mutationId,
command.requestId,
acknowledgement.mutationId,
acknowledgement.kind,
acknowledgement.deliveryDigest,
acknowledgement.acknowledgedAtMs,
semanticDigest,
command.bridgeClearEvidence.evidenceDigest,
command.retentionPolicy.replayRetentionMs,
command.retentionPolicy.auditRetentionMs,
policyDigest,
eligibleAtMs,
command.compactedAtMs,
command.audit.eventId,
acknowledgement.kind === 'credential'
? acknowledgement.mutationId
: null,
acknowledgement.kind === 'challenge'
? acknowledgement.mutationId
: null,
);
const deleted = client
.prepare(
`DELETE FROM "QingLong3LocalOwnerDeliveryAcknowledgements"
WHERE "mutation_id" = ?`,
)
.run(acknowledgement.mutationId);
if (deleted.changes !== 1) {
throw new LocalOwnerDeliveryAcknowledgementGcMutationConflictError();
}
const inserted = client
.prepare(`${GC_SELECT} WHERE "gc_mutation_id" = ?`)
.get(command.mutationId) as QueryRow | undefined;
if (!inserted) {
throw new LocalOwnerDeliveryAcknowledgementGcRepositoryUnavailableError();
}
const record = gcRecord(inserted);
client.exec('COMMIT');
return Object.freeze({ status: 'inserted' as const, record });
} catch (error) {
if (client.isTransaction) client.exec('ROLLBACK');
if (isDomainError(error)) throw error;
throw new LocalOwnerDeliveryAcknowledgementGcRepositoryUnavailableError();
}
},
() => new LocalOwnerDeliveryAcknowledgementGcRepositoryUnavailableError(),
);
}
}
@@ -0,0 +1,607 @@
import type { DatabaseSync } from 'node:sqlite';
import {
LocalOwnerPepperMaterialGcInProgressError,
LocalOwnerPepperMaterialGcMutationConflictError,
LocalOwnerPepperMaterialGcReferenceConflictError,
LocalOwnerPepperMaterialGcRepositoryUnavailableError,
LocalOwnerPepperMaterialGcRetentionPendingError,
localOwnerPepperMaterialGcRetentionPolicyDigest,
normalizeCompleteLocalOwnerPepperMaterialGcCommand,
normalizePrepareLocalOwnerPepperMaterialGcCommand,
type CompleteLocalOwnerPepperMaterialGcCommand,
type LocalOwnerPepperMaterialGcRecord,
type LocalOwnerPepperMaterialGcRepository,
type LocalOwnerPepperMaterialGcResult,
type PrepareLocalOwnerPepperMaterialGcCommand,
} from '@qinglong/runtime-core/local-owner-pepper-material-gc';
import type { SecurityAuditRecord } from '@qinglong/runtime-core/security-audit';
import { LocalSqliteOperationAuthority } from '../authority/operationAuthority';
type QueryRow = Record<string, unknown>;
const GC_SELECT = `
SELECT * FROM "QingLong3LocalOwnerPepperMaterialGc"`;
function text(row: QueryRow, name: string): string {
const value = row[name];
if (typeof value !== 'string') {
throw new LocalOwnerPepperMaterialGcRepositoryUnavailableError();
}
return value;
}
function optionalText(row: QueryRow, name: string): string | undefined {
const value = row[name];
if (value === null || value === undefined) return undefined;
return text(row, name);
}
function integer(row: QueryRow, name: string): number {
const value = row[name];
if (typeof value !== 'number' || !Number.isSafeInteger(value)) {
throw new LocalOwnerPepperMaterialGcRepositoryUnavailableError();
}
return value;
}
function optionalInteger(row: QueryRow, name: string): number | undefined {
const value = row[name];
if (value === null || value === undefined) return undefined;
return integer(row, name);
}
function gcRecord(row: QueryRow): Readonly<LocalOwnerPepperMaterialGcRecord> {
const state = text(row, 'state');
const completeMutationId = optionalText(row, 'complete_mutation_id');
const completeRequestId = optionalText(row, 'complete_request_id');
const destructionProofDigest = optionalText(row, 'destruction_proof_digest');
const completedAtMs = optionalInteger(row, 'completed_at_ms');
if (
(state !== 'prepared' && state !== 'completed') ||
(state === 'prepared' &&
(completeMutationId !== undefined ||
completeRequestId !== undefined ||
destructionProofDigest !== undefined ||
completedAtMs !== undefined)) ||
(state === 'completed' &&
(completeMutationId === undefined ||
completeRequestId === undefined ||
destructionProofDigest === undefined ||
completedAtMs === undefined))
) {
throw new LocalOwnerPepperMaterialGcRepositoryUnavailableError();
}
const retentionPolicy = Object.freeze({
version: 1 as const,
acknowledgementRetentionMs: integer(row, 'acknowledgement_retention_ms'),
auditRetentionMs: integer(row, 'audit_retention_ms'),
backupRetentionMs: integer(row, 'backup_retention_ms'),
});
if (
integer(row, 'retention_policy_version') !== 1 ||
localOwnerPepperMaterialGcRetentionPolicyDigest(retentionPolicy) !==
text(row, 'retention_policy_digest')
) {
throw new LocalOwnerPepperMaterialGcRepositoryUnavailableError();
}
return Object.freeze({
prepareMutationId: text(row, 'prepare_mutation_id'),
prepareRequestId: text(row, 'prepare_request_id'),
pepperKeyId: text(row, 'pepper_key_id'),
materialDigest: text(row, 'material_digest'),
backupMaterialDigest: text(row, 'backup_material_digest'),
activePepperKeyId: text(row, 'active_pepper_key_id'),
activeGeneration: integer(row, 'active_generation'),
activeMaterialDigest: text(row, 'active_material_digest'),
retentionPolicy,
retentionPolicyDigest: text(row, 'retention_policy_digest'),
referencesInspectedAtMs: integer(row, 'references_inspected_at_ms'),
retentionEligibleAtMs: integer(row, 'retention_eligible_at_ms'),
preparedAtMs: integer(row, 'prepared_at_ms'),
state,
...(completeMutationId === undefined ? {} : { completeMutationId }),
...(completeRequestId === undefined ? {} : { completeRequestId }),
...(destructionProofDigest === undefined ? {} : { destructionProofDigest }),
...(completedAtMs === undefined ? {} : { completedAtMs }),
});
}
function insertAudit(
client: DatabaseSync,
audit: Readonly<SecurityAuditRecord>,
): void {
client
.prepare(
`INSERT INTO "QingLong3SecurityAuditEvents" (
event_id, request_id, operation_id, project_id, subject_type,
subject_id, authentication_id, outcome, reasons_json,
fence_project_version, fence_binding_version, occurred_at_ms
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
)
.run(
audit.eventId,
audit.requestId,
audit.operationId,
audit.projectId,
audit.subject?.type ?? null,
audit.subject?.id ?? null,
audit.authenticationId,
audit.outcome,
JSON.stringify(audit.reasons),
audit.fence?.projectVersion ?? null,
audit.fence?.bindingVersion ?? null,
audit.occurredAtMs,
);
}
function safeRetentionTimestamp(base: number, duration: number): number {
const result = base + duration;
if (!Number.isSafeInteger(result) || result < 0) {
throw new LocalOwnerPepperMaterialGcRepositoryUnavailableError();
}
return result;
}
function nullableMaximum(row: QueryRow | undefined): number | undefined {
const value = row?.latest_at_ms;
if (value === null || value === undefined) return undefined;
if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < 0) {
throw new LocalOwnerPepperMaterialGcRepositoryUnavailableError();
}
return value;
}
function retentionEligibleAt(
client: DatabaseSync,
pepperKeyId: string,
retiredAtMs: number,
command: Readonly<PrepareLocalOwnerPepperMaterialGcCommand>,
): number {
const acknowledgement = nullableMaximum(
client
.prepare(
`SELECT MAX("acknowledged_at_ms") AS "latest_at_ms"
FROM (
SELECT acknowledgement."acknowledged_at_ms"
FROM "QingLong3LocalOwnerDeliveryAcknowledgements" AS acknowledgement
JOIN "QingLong3ApiCredentialPepperBindings" AS binding
ON binding."credential_id" = acknowledgement."credential_id"
WHERE acknowledgement."kind" = 'credential'
AND binding."pepper_key_id" = ?
UNION ALL
SELECT compacted."acknowledged_at_ms"
FROM "QingLong3LocalOwnerDeliveryAcknowledgementGc" AS compacted
JOIN "QingLong3LocalIdentityProvisionings" AS provisioning
ON provisioning."mutation_id" = compacted."provisioning_mutation_id"
JOIN "QingLong3ApiCredentialPepperBindings" AS binding
ON binding."credential_id" = provisioning."credential_id"
AND binding."credential_version" = provisioning."credential_version"
WHERE compacted."acknowledgement_kind" = 'credential'
AND binding."pepper_key_id" = ?
UNION ALL
SELECT recovery."acknowledged_at_ms"
FROM "QingLong3LocalOwnerCredentialRecoveries" AS recovery
WHERE recovery."acknowledged_at_ms" IS NOT NULL
AND (
EXISTS (
SELECT 1 FROM "QingLong3ApiCredentialPepperBindings" AS previous
WHERE previous."credential_id" = recovery."previous_credential_id"
AND previous."credential_version" = recovery."previous_credential_version"
AND previous."pepper_key_id" = ?
)
OR EXISTS (
SELECT 1 FROM "QingLong3ApiCredentialPepperBindings" AS replacement
WHERE replacement."credential_id" = recovery."replacement_credential_id"
AND replacement."credential_version" = recovery."replacement_credential_version"
AND replacement."pepper_key_id" = ?
)
)
)`,
)
.get(pepperKeyId, pepperKeyId, pepperKeyId, pepperKeyId) as
| QueryRow
| undefined,
);
const securityAudit = nullableMaximum(
client
.prepare(
`SELECT MAX(audit."occurred_at_ms") AS "latest_at_ms"
FROM "QingLong3SecurityAuditEvents" AS audit
WHERE audit."event_id" IN (
SELECT provisioning."audit_event_id"
FROM "QingLong3LocalIdentityProvisionings" AS provisioning
JOIN "QingLong3ApiCredentialPepperBindings" AS binding
ON binding."credential_id" = provisioning."credential_id"
AND binding."credential_version" = provisioning."credential_version"
WHERE binding."pepper_key_id" = ?
UNION
SELECT recovery."issue_audit_event_id"
FROM "QingLong3LocalOwnerCredentialRecoveries" AS recovery
WHERE EXISTS (
SELECT 1 FROM "QingLong3ApiCredentialPepperBindings" AS binding
WHERE binding."pepper_key_id" = ?
AND (
(binding."credential_id" = recovery."previous_credential_id"
AND binding."credential_version" = recovery."previous_credential_version")
OR (binding."credential_id" = recovery."replacement_credential_id"
AND binding."credential_version" = recovery."replacement_credential_version")
)
)
UNION
SELECT recovery."complete_audit_event_id"
FROM "QingLong3LocalOwnerCredentialRecoveries" AS recovery
WHERE recovery."complete_audit_event_id" IS NOT NULL
AND EXISTS (
SELECT 1 FROM "QingLong3ApiCredentialPepperBindings" AS binding
WHERE binding."pepper_key_id" = ?
AND (
(binding."credential_id" = recovery."previous_credential_id"
AND binding."credential_version" = recovery."previous_credential_version")
OR (binding."credential_id" = recovery."replacement_credential_id"
AND binding."credential_version" = recovery."replacement_credential_version")
)
)
)`,
)
.get(pepperKeyId, pepperKeyId, pepperKeyId) as QueryRow | undefined,
);
return Math.max(
safeRetentionTimestamp(
retiredAtMs,
command.retentionPolicy.backupRetentionMs,
),
...(acknowledgement === undefined
? []
: [
safeRetentionTimestamp(
acknowledgement,
command.retentionPolicy.acknowledgementRetentionMs,
),
]),
...(securityAudit === undefined
? []
: [
safeRetentionTimestamp(
securityAudit,
command.retentionPolicy.auditRetentionMs,
),
]),
);
}
function hasRuntimeReferences(
client: DatabaseSync,
pepperKeyId: string,
inspectedAtMs: number,
): boolean {
const current = client
.prepare(
`SELECT 1
FROM "QingLong3ApiCredentialPepperBindings" AS binding
JOIN "QingLong3ApiCredentials" AS credential
ON credential."credential_id" = binding."credential_id"
AND credential."version" = binding."credential_version"
WHERE binding."pepper_key_id" = ?
AND credential."state" = 'active'
AND credential."expires_at_ms" > ?
AND NOT EXISTS (
SELECT 1 FROM "QingLong3ApiCredentials" AS later
WHERE later."credential_id" = credential."credential_id"
AND later."version" > credential."version"
)
LIMIT 1`,
)
.get(pepperKeyId, inspectedAtMs);
if (current) return true;
return !!client
.prepare(
`SELECT 1
FROM "QingLong3LocalOwnerCredentialRecoveries" AS recovery
WHERE recovery."state" <> 'completed'
AND (
EXISTS (
SELECT 1 FROM "QingLong3ApiCredentialPepperBindings" AS previous
WHERE previous."credential_id" = recovery."previous_credential_id"
AND previous."credential_version" = recovery."previous_credential_version"
AND previous."pepper_key_id" = ?
)
OR EXISTS (
SELECT 1 FROM "QingLong3ApiCredentialPepperBindings" AS replacement
WHERE replacement."credential_id" = recovery."replacement_credential_id"
AND replacement."credential_version" = recovery."replacement_credential_version"
AND replacement."pepper_key_id" = ?
)
)
LIMIT 1`,
)
.get(pepperKeyId, pepperKeyId);
}
function samePrepare(
record: Readonly<LocalOwnerPepperMaterialGcRecord>,
command: Readonly<PrepareLocalOwnerPepperMaterialGcCommand>,
): boolean {
return (
record.prepareMutationId === command.mutationId &&
record.prepareRequestId === command.requestId &&
record.pepperKeyId === command.pepperKeyId &&
record.materialDigest === command.expectedMaterialDigest &&
record.backupMaterialDigest === command.expectedBackupMaterialDigest &&
record.activePepperKeyId === command.expectedActivePepperKeyId &&
record.activeGeneration === command.expectedActiveGeneration &&
record.activeMaterialDigest === command.expectedActiveMaterialDigest &&
record.retentionPolicyDigest ===
localOwnerPepperMaterialGcRetentionPolicyDigest(
command.retentionPolicy,
) &&
record.preparedAtMs === command.preparedAtMs
);
}
function sameComplete(
record: Readonly<LocalOwnerPepperMaterialGcRecord>,
command: Readonly<CompleteLocalOwnerPepperMaterialGcCommand>,
): boolean {
return (
record.completeMutationId === command.mutationId &&
record.completeRequestId === command.requestId &&
record.destructionProofDigest === command.destructionProofDigest &&
record.completedAtMs === command.completedAtMs
);
}
function isDomainError(error: unknown): boolean {
return (
error instanceof LocalOwnerPepperMaterialGcMutationConflictError ||
error instanceof LocalOwnerPepperMaterialGcInProgressError ||
error instanceof LocalOwnerPepperMaterialGcReferenceConflictError ||
error instanceof LocalOwnerPepperMaterialGcRetentionPendingError ||
error instanceof LocalOwnerPepperMaterialGcRepositoryUnavailableError
);
}
export class LocalSqliteOwnerPepperMaterialGcRepository
implements LocalOwnerPepperMaterialGcRepository
{
private readonly authority: LocalSqliteOperationAuthority;
constructor(authority: LocalSqliteOperationAuthority | DatabaseSync) {
this.authority =
authority instanceof LocalSqliteOperationAuthority
? authority
: new LocalSqliteOperationAuthority(authority);
}
resolve(
prepareMutationId: string,
): Promise<Readonly<LocalOwnerPepperMaterialGcRecord> | null> {
if (typeof prepareMutationId !== 'string') {
throw new LocalOwnerPepperMaterialGcRepositoryUnavailableError();
}
return this.authority.enqueue(
async () => {
try {
const row = this.authority.client
.prepare(`${GC_SELECT} WHERE "prepare_mutation_id" = ?`)
.get(prepareMutationId) as QueryRow | undefined;
return row ? gcRecord(row) : null;
} catch (error) {
if (isDomainError(error)) throw error;
throw new LocalOwnerPepperMaterialGcRepositoryUnavailableError();
}
},
() => new LocalOwnerPepperMaterialGcRepositoryUnavailableError(),
);
}
prepare(
candidate: PrepareLocalOwnerPepperMaterialGcCommand,
): Promise<LocalOwnerPepperMaterialGcResult> {
const command =
normalizePrepareLocalOwnerPepperMaterialGcCommand(candidate);
return this.authority.enqueue(
async () => {
const client = this.authority.client;
try {
client.exec('BEGIN IMMEDIATE');
const replay = client
.prepare(`${GC_SELECT} WHERE "prepare_mutation_id" = ?`)
.get(command.mutationId) as QueryRow | undefined;
if (replay) {
const record = gcRecord(replay);
if (!samePrepare(record, command)) {
throw new LocalOwnerPepperMaterialGcMutationConflictError();
}
client.exec('COMMIT');
return Object.freeze({ status: 'existing' as const, record });
}
if (
client
.prepare(`${GC_SELECT} WHERE "state" = 'prepared' LIMIT 1`)
.get()
) {
throw new LocalOwnerPepperMaterialGcInProgressError();
}
const key = client
.prepare(
`SELECT "material_digest", "backup_digest", "retired_at_ms"
FROM "QingLong3LocalOwnerPepperKeys"
WHERE "pepper_key_id" = ? AND "state" = 'retired'`,
)
.get(command.pepperKeyId) as QueryRow | undefined;
if (
!key ||
text(key, 'material_digest') !== command.expectedMaterialDigest ||
text(key, 'backup_digest') !== command.expectedBackupMaterialDigest
) {
throw new LocalOwnerPepperMaterialGcMutationConflictError();
}
const active = client
.prepare(
`SELECT activation."generation", key."pepper_key_id",
key."material_digest"
FROM "QingLong3LocalOwnerPepperActivations" AS activation
JOIN "QingLong3LocalOwnerPepperKeys" AS key
ON key."pepper_key_id" = activation."active_pepper_key_id"
WHERE key."state" = 'active'
ORDER BY activation."generation" DESC
LIMIT 1`,
)
.get() as QueryRow | undefined;
if (
!active ||
integer(active, 'generation') !==
command.expectedActiveGeneration ||
text(active, 'pepper_key_id') !==
command.expectedActivePepperKeyId ||
text(active, 'material_digest') !==
command.expectedActiveMaterialDigest
) {
throw new LocalOwnerPepperMaterialGcMutationConflictError();
}
if (
hasRuntimeReferences(
client,
command.pepperKeyId,
command.preparedAtMs,
)
) {
throw new LocalOwnerPepperMaterialGcReferenceConflictError();
}
const eligibleAtMs = retentionEligibleAt(
client,
command.pepperKeyId,
integer(key, 'retired_at_ms'),
command,
);
if (command.preparedAtMs < eligibleAtMs) {
throw new LocalOwnerPepperMaterialGcRetentionPendingError(
eligibleAtMs,
);
}
const policyDigest = localOwnerPepperMaterialGcRetentionPolicyDigest(
command.retentionPolicy,
);
insertAudit(client, command.audit);
client
.prepare(
`INSERT INTO "QingLong3LocalOwnerPepperMaterialGc" (
prepare_mutation_id, prepare_request_id, pepper_key_id,
material_digest, backup_material_digest,
active_pepper_key_id, active_generation,
active_material_digest, retention_policy_version,
acknowledgement_retention_ms, audit_retention_ms,
backup_retention_ms, retention_policy_digest,
references_inspected_at_ms, retention_eligible_at_ms,
prepared_at_ms, prepare_audit_event_id, state
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?, ?, ?, ?, ?, 'prepared')`,
)
.run(
command.mutationId,
command.requestId,
command.pepperKeyId,
command.expectedMaterialDigest,
command.expectedBackupMaterialDigest,
command.expectedActivePepperKeyId,
command.expectedActiveGeneration,
command.expectedActiveMaterialDigest,
command.retentionPolicy.acknowledgementRetentionMs,
command.retentionPolicy.auditRetentionMs,
command.retentionPolicy.backupRetentionMs,
policyDigest,
command.preparedAtMs,
eligibleAtMs,
command.preparedAtMs,
command.audit.eventId,
);
const inserted = client
.prepare(`${GC_SELECT} WHERE "prepare_mutation_id" = ?`)
.get(command.mutationId) as QueryRow | undefined;
if (!inserted) {
throw new LocalOwnerPepperMaterialGcRepositoryUnavailableError();
}
const record = gcRecord(inserted);
client.exec('COMMIT');
return Object.freeze({ status: 'inserted' as const, record });
} catch (error) {
if (client.isTransaction) client.exec('ROLLBACK');
if (isDomainError(error)) throw error;
throw new LocalOwnerPepperMaterialGcRepositoryUnavailableError();
}
},
() => new LocalOwnerPepperMaterialGcRepositoryUnavailableError(),
);
}
complete(
candidate: CompleteLocalOwnerPepperMaterialGcCommand,
): Promise<LocalOwnerPepperMaterialGcResult> {
const command =
normalizeCompleteLocalOwnerPepperMaterialGcCommand(candidate);
return this.authority.enqueue(
async () => {
const client = this.authority.client;
try {
client.exec('BEGIN IMMEDIATE');
const row = client
.prepare(`${GC_SELECT} WHERE "prepare_mutation_id" = ?`)
.get(command.prepareMutationId) as QueryRow | undefined;
if (!row) {
throw new LocalOwnerPepperMaterialGcMutationConflictError();
}
const existing = gcRecord(row);
if (existing.state === 'completed') {
if (!sameComplete(existing, command)) {
throw new LocalOwnerPepperMaterialGcMutationConflictError();
}
client.exec('COMMIT');
return Object.freeze({
status: 'existing' as const,
record: existing,
});
}
if (command.completedAtMs < existing.preparedAtMs) {
throw new LocalOwnerPepperMaterialGcMutationConflictError();
}
insertAudit(client, command.audit);
const result = client
.prepare(
`UPDATE "QingLong3LocalOwnerPepperMaterialGc"
SET "state" = 'completed',
"complete_mutation_id" = ?,
"complete_request_id" = ?,
"destruction_proof_digest" = ?,
"completed_at_ms" = ?,
"complete_audit_event_id" = ?
WHERE "prepare_mutation_id" = ? AND "state" = 'prepared'`,
)
.run(
command.mutationId,
command.requestId,
command.destructionProofDigest,
command.completedAtMs,
command.audit.eventId,
command.prepareMutationId,
);
if (result.changes !== 1) {
throw new LocalOwnerPepperMaterialGcMutationConflictError();
}
const completed = client
.prepare(`${GC_SELECT} WHERE "prepare_mutation_id" = ?`)
.get(command.prepareMutationId) as QueryRow | undefined;
if (!completed) {
throw new LocalOwnerPepperMaterialGcRepositoryUnavailableError();
}
const record = gcRecord(completed);
client.exec('COMMIT');
return Object.freeze({ status: 'inserted' as const, record });
} catch (error) {
if (client.isTransaction) client.exec('ROLLBACK');
if (isDomainError(error)) throw error;
throw new LocalOwnerPepperMaterialGcRepositoryUnavailableError();
}
},
() => new LocalOwnerPepperMaterialGcRepositoryUnavailableError(),
);
}
}
@@ -0,0 +1,566 @@
import {
LocalOwnerPepperCatalogFullError,
LocalOwnerPepperGenerationConflictError,
LocalOwnerPepperKeyNotActivatableError,
LocalOwnerPepperMutationConflictError,
LocalOwnerPepperRepositoryUnavailableError,
MAX_LOCAL_OWNER_PEPPER_KEYS,
normalizeActivateLocalOwnerPepperKeyCommand,
normalizeRegisterLocalOwnerPepperKeyCommand,
type ActivateLocalOwnerPepperKeyCommand,
type ActivateLocalOwnerPepperKeyResult,
type LocalOwnerPepperActivationRecord,
type LocalOwnerPepperKeyRecord,
type LocalOwnerPepperKeyState,
type LocalOwnerPepperReferenceRepository,
type LocalOwnerPepperReferenceSummary,
type RegisterLocalOwnerPepperKeyCommand,
type RegisterLocalOwnerPepperKeyResult,
} from '@qinglong/runtime-core/local-owner-pepper';
import { assertApiCredentialPepperKeyId } from '@qinglong/runtime-core/api-credential';
import { LocalSqliteOperationAuthority } from '../authority/operationAuthority';
interface KeyRow {
pepper_key_id: unknown;
material_digest: unknown;
backup_digest: unknown;
state: unknown;
version: unknown;
register_mutation_id: unknown;
activate_mutation_id: unknown;
retire_mutation_id: unknown;
registered_at_ms: unknown;
activated_at_ms: unknown;
retired_at_ms: unknown;
}
interface ActivationRow {
generation: unknown;
mutation_id: unknown;
expected_generation: unknown;
previous_pepper_key_id: unknown;
active_pepper_key_id: unknown;
material_digest: unknown;
backup_digest: unknown;
activated_at_ms: unknown;
}
const DIGEST_PATTERN = /^[0-9a-f]{64}$/;
const KEY_STATES = new Set<LocalOwnerPepperKeyState>([
'recovery_required',
'staged',
'active',
'retired',
]);
function requiredString(value: unknown): string {
if (typeof value !== 'string') {
throw new LocalOwnerPepperRepositoryUnavailableError();
}
return value;
}
function optionalString(value: unknown): string | undefined {
if (value === null) return undefined;
return requiredString(value);
}
function integer(value: unknown, minimum: number): number {
if (
typeof value !== 'number' ||
!Number.isSafeInteger(value) ||
value < minimum ||
value > 2_147_483_647
) {
throw new LocalOwnerPepperRepositoryUnavailableError();
}
return value;
}
function optionalTimestamp(value: unknown): number | undefined {
if (value === null) return undefined;
return timestamp(value);
}
function timestamp(value: unknown): number {
if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < 0) {
throw new LocalOwnerPepperRepositoryUnavailableError();
}
return value;
}
function digest(value: unknown): string {
const result = requiredString(value);
if (!DIGEST_PATTERN.test(result)) {
throw new LocalOwnerPepperRepositoryUnavailableError();
}
return result;
}
function keyRecord(row: KeyRow): Readonly<LocalOwnerPepperKeyRecord> {
const pepperKeyId = requiredString(row.pepper_key_id);
const state = requiredString(row.state) as LocalOwnerPepperKeyState;
try {
assertApiCredentialPepperKeyId(pepperKeyId);
} catch {
throw new LocalOwnerPepperRepositoryUnavailableError();
}
if (!KEY_STATES.has(state)) {
throw new LocalOwnerPepperRepositoryUnavailableError();
}
const materialDigest = optionalString(row.material_digest);
const backupDigest = optionalString(row.backup_digest);
if (
(materialDigest !== undefined && !DIGEST_PATTERN.test(materialDigest)) ||
(backupDigest !== undefined && !DIGEST_PATTERN.test(backupDigest)) ||
(materialDigest === undefined) !== (backupDigest === undefined)
) {
throw new LocalOwnerPepperRepositoryUnavailableError();
}
return Object.freeze({
pepperKeyId,
...(materialDigest === undefined ? {} : { materialDigest }),
...(backupDigest === undefined ? {} : { backupDigest }),
state,
version: integer(row.version, 1),
...(optionalString(row.register_mutation_id) === undefined
? {}
: { registerMutationId: requiredString(row.register_mutation_id) }),
...(optionalString(row.activate_mutation_id) === undefined
? {}
: { activateMutationId: requiredString(row.activate_mutation_id) }),
...(optionalString(row.retire_mutation_id) === undefined
? {}
: { retireMutationId: requiredString(row.retire_mutation_id) }),
registeredAtMs: timestamp(row.registered_at_ms),
...(optionalTimestamp(row.activated_at_ms) === undefined
? {}
: { activatedAtMs: timestamp(row.activated_at_ms) }),
...(optionalTimestamp(row.retired_at_ms) === undefined
? {}
: { retiredAtMs: timestamp(row.retired_at_ms) }),
});
}
function activationRecord(
row: ActivationRow,
): Readonly<LocalOwnerPepperActivationRecord> {
const activePepperKeyId = requiredString(row.active_pepper_key_id);
const previousPepperKeyId = optionalString(row.previous_pepper_key_id);
try {
assertApiCredentialPepperKeyId(activePepperKeyId);
if (previousPepperKeyId !== undefined) {
assertApiCredentialPepperKeyId(previousPepperKeyId);
}
} catch {
throw new LocalOwnerPepperRepositoryUnavailableError();
}
return Object.freeze({
generation: integer(row.generation, 1),
mutationId: requiredString(row.mutation_id),
expectedGeneration: integer(row.expected_generation, 0),
...(previousPepperKeyId === undefined ? {} : { previousPepperKeyId }),
activePepperKeyId,
materialDigest: digest(row.material_digest),
backupDigest: digest(row.backup_digest),
activatedAtMs: timestamp(row.activated_at_ms),
});
}
function sameRegistration(
key: LocalOwnerPepperKeyRecord,
command: RegisterLocalOwnerPepperKeyCommand,
): boolean {
return (
key.pepperKeyId === command.pepperKeyId &&
key.materialDigest === command.materialDigest &&
key.backupDigest === command.backupDigest &&
key.registerMutationId === command.mutationId &&
key.registeredAtMs === command.registeredAtMs
);
}
function sameActivation(
activation: LocalOwnerPepperActivationRecord,
command: ActivateLocalOwnerPepperKeyCommand,
): boolean {
return (
activation.mutationId === command.mutationId &&
activation.activePepperKeyId === command.pepperKeyId &&
activation.expectedGeneration === command.expectedGeneration &&
activation.previousPepperKeyId === command.expectedActivePepperKeyId &&
activation.activatedAtMs === command.activatedAtMs
);
}
const KEY_SELECT = `
SELECT pepper_key_id, material_digest, backup_digest, state, version,
register_mutation_id, activate_mutation_id, retire_mutation_id,
registered_at_ms, activated_at_ms, retired_at_ms
FROM "QingLong3LocalOwnerPepperKeys"`;
const ACTIVATION_SELECT = `
SELECT generation, mutation_id, expected_generation,
previous_pepper_key_id, active_pepper_key_id,
material_digest, backup_digest, activated_at_ms
FROM "QingLong3LocalOwnerPepperActivations"`;
export class LocalSqliteOwnerPepperRepository
implements LocalOwnerPepperReferenceRepository
{
private readonly authority: LocalSqliteOperationAuthority;
constructor(authority: LocalSqliteOperationAuthority) {
this.authority = authority;
}
resolveKey(
pepperKeyId: string,
): Promise<Readonly<LocalOwnerPepperKeyRecord> | null> {
try {
assertApiCredentialPepperKeyId(pepperKeyId);
} catch {
throw new LocalOwnerPepperRepositoryUnavailableError();
}
return this.authority.enqueue(
async () => {
try {
const row = this.authority.client
.prepare(`${KEY_SELECT} WHERE pepper_key_id = ?`)
.get(pepperKeyId) as KeyRow | undefined;
return row ? keyRecord(row) : null;
} catch (error) {
if (error instanceof LocalOwnerPepperRepositoryUnavailableError) {
throw error;
}
throw new LocalOwnerPepperRepositoryUnavailableError();
}
},
() => new LocalOwnerPepperRepositoryUnavailableError(),
);
}
resolveActive(): Promise<Readonly<LocalOwnerPepperActivationRecord> | null> {
return this.authority.enqueue(
async () => {
try {
const row = this.authority.client
.prepare(`${ACTIVATION_SELECT} ORDER BY generation DESC LIMIT 1`)
.get() as ActivationRow | undefined;
return row ? activationRecord(row) : null;
} catch (error) {
if (error instanceof LocalOwnerPepperRepositoryUnavailableError) {
throw error;
}
throw new LocalOwnerPepperRepositoryUnavailableError();
}
},
() => new LocalOwnerPepperRepositoryUnavailableError(),
);
}
inspectReferences(
pepperKeyId: string,
inspectedAtMs: number,
): Promise<Readonly<LocalOwnerPepperReferenceSummary>> {
try {
assertApiCredentialPepperKeyId(pepperKeyId);
} catch {
throw new LocalOwnerPepperRepositoryUnavailableError();
}
if (!Number.isSafeInteger(inspectedAtMs) || inspectedAtMs < 0) {
throw new LocalOwnerPepperRepositoryUnavailableError();
}
return this.authority.enqueue(
async () => {
try {
const keyRow = this.authority.client
.prepare(`${KEY_SELECT} WHERE pepper_key_id = ?`)
.get(pepperKeyId) as KeyRow | undefined;
if (!keyRow) throw new LocalOwnerPepperRepositoryUnavailableError();
const key = keyRecord(keyRow);
const historical = this.authority.client
.prepare(
`SELECT COUNT(*) AS count
FROM "QingLong3ApiCredentialPepperBindings"
WHERE "pepper_key_id" = ?`,
)
.get(pepperKeyId) as { count?: unknown } | undefined;
const current = this.authority.client
.prepare(
`SELECT COUNT(*) AS count
FROM "QingLong3ApiCredentialPepperBindings" AS binding
JOIN "QingLong3ApiCredentials" AS credential
ON credential."credential_id" = binding."credential_id"
AND credential."version" = binding."credential_version"
WHERE binding."pepper_key_id" = ?
AND credential."state" = 'active'
AND credential."expires_at_ms" > ?
AND NOT EXISTS (
SELECT 1 FROM "QingLong3ApiCredentials" AS later
WHERE later."credential_id" = credential."credential_id"
AND later."version" > credential."version"
)`,
)
.get(pepperKeyId, inspectedAtMs) as { count?: unknown } | undefined;
const inFlight = this.authority.client
.prepare(
`SELECT COUNT(*) AS count
FROM "QingLong3LocalOwnerCredentialRecoveries" AS recovery
WHERE recovery."state" <> 'completed'
AND (
EXISTS (
SELECT 1
FROM "QingLong3ApiCredentialPepperBindings" AS previous
WHERE previous."credential_id" = recovery."previous_credential_id"
AND previous."credential_version" = recovery."previous_credential_version"
AND previous."pepper_key_id" = ?
)
OR EXISTS (
SELECT 1
FROM "QingLong3ApiCredentialPepperBindings" AS replacement
WHERE replacement."credential_id" = recovery."replacement_credential_id"
AND replacement."credential_version" = recovery."replacement_credential_version"
AND replacement."pepper_key_id" = ?
)
)`,
)
.get(pepperKeyId, pepperKeyId) as { count?: unknown } | undefined;
const currentCredentialReferences = integer(current?.count, 0);
const inFlightRecoveryReferences = integer(inFlight?.count, 0);
return Object.freeze({
pepperKeyId,
inspectedAtMs,
currentCredentialReferences,
inFlightRecoveryReferences,
historicalCredentialReferences: integer(historical?.count, 0),
runtimeReferencesClear:
key.state === 'retired' &&
currentCredentialReferences === 0 &&
inFlightRecoveryReferences === 0,
});
} catch (error) {
if (error instanceof LocalOwnerPepperRepositoryUnavailableError) {
throw error;
}
throw new LocalOwnerPepperRepositoryUnavailableError();
}
},
() => new LocalOwnerPepperRepositoryUnavailableError(),
);
}
register(
input: RegisterLocalOwnerPepperKeyCommand,
): Promise<RegisterLocalOwnerPepperKeyResult> {
const command = normalizeRegisterLocalOwnerPepperKeyCommand(input);
return this.authority.enqueue(
async () => {
const client = this.authority.client;
client.exec('BEGIN IMMEDIATE');
try {
const replay = client
.prepare(`${KEY_SELECT} WHERE register_mutation_id = ?`)
.get(command.mutationId) as KeyRow | undefined;
if (replay) {
const key = keyRecord(replay);
if (!sameRegistration(key, command)) {
throw new LocalOwnerPepperMutationConflictError();
}
client.exec('COMMIT');
return Object.freeze({ status: 'existing' as const, key });
}
const existingRow = client
.prepare(`${KEY_SELECT} WHERE pepper_key_id = ?`)
.get(command.pepperKeyId) as KeyRow | undefined;
if (existingRow) {
const existing = keyRecord(existingRow);
if (existing.state !== 'recovery_required') {
throw new LocalOwnerPepperMutationConflictError();
}
const changed = client
.prepare(
`UPDATE "QingLong3LocalOwnerPepperKeys"
SET material_digest = ?, backup_digest = ?, state = 'staged',
version = version + 1, register_mutation_id = ?,
registered_at_ms = ?
WHERE pepper_key_id = ? AND version = ?
AND state = 'recovery_required'`,
)
.run(
command.materialDigest,
command.backupDigest,
command.mutationId,
command.registeredAtMs,
command.pepperKeyId,
existing.version,
);
if (changed.changes !== 1) {
throw new LocalOwnerPepperMutationConflictError();
}
} else {
const count = client
.prepare(
`SELECT COUNT(*) AS count FROM "QingLong3LocalOwnerPepperKeys"`,
)
.get() as { count?: unknown } | undefined;
if (integer(count?.count, 0) >= MAX_LOCAL_OWNER_PEPPER_KEYS) {
throw new LocalOwnerPepperCatalogFullError();
}
client
.prepare(
`INSERT INTO "QingLong3LocalOwnerPepperKeys" (
pepper_key_id, material_digest, backup_digest, state,
version, register_mutation_id, registered_at_ms
) VALUES (?, ?, ?, 'staged', 1, ?, ?)`,
)
.run(
command.pepperKeyId,
command.materialDigest,
command.backupDigest,
command.mutationId,
command.registeredAtMs,
);
}
const key = keyRecord(
client
.prepare(`${KEY_SELECT} WHERE pepper_key_id = ?`)
.get(command.pepperKeyId) as unknown as KeyRow,
);
client.exec('COMMIT');
return Object.freeze({ status: 'inserted' as const, key });
} catch (error) {
if (client.isTransaction) client.exec('ROLLBACK');
if (
error instanceof LocalOwnerPepperMutationConflictError ||
error instanceof LocalOwnerPepperCatalogFullError ||
error instanceof LocalOwnerPepperRepositoryUnavailableError
) {
throw error;
}
throw new LocalOwnerPepperRepositoryUnavailableError();
}
},
() => new LocalOwnerPepperRepositoryUnavailableError(),
);
}
activate(
input: ActivateLocalOwnerPepperKeyCommand,
): Promise<ActivateLocalOwnerPepperKeyResult> {
const command = normalizeActivateLocalOwnerPepperKeyCommand(input);
return this.authority.enqueue(
async () => {
const client = this.authority.client;
client.exec('BEGIN IMMEDIATE');
try {
const replay = client
.prepare(`${ACTIVATION_SELECT} WHERE mutation_id = ?`)
.get(command.mutationId) as ActivationRow | undefined;
if (replay) {
const activation = activationRecord(replay);
if (!sameActivation(activation, command)) {
throw new LocalOwnerPepperMutationConflictError();
}
client.exec('COMMIT');
return Object.freeze({ status: 'existing' as const, activation });
}
const currentRow = client
.prepare(`${ACTIVATION_SELECT} ORDER BY generation DESC LIMIT 1`)
.get() as ActivationRow | undefined;
const current = currentRow ? activationRecord(currentRow) : null;
const generation = current?.generation ?? 0;
if (
generation !== command.expectedGeneration ||
current?.activePepperKeyId !== command.expectedActivePepperKeyId
) {
throw new LocalOwnerPepperGenerationConflictError();
}
const targetRow = client
.prepare(`${KEY_SELECT} WHERE pepper_key_id = ?`)
.get(command.pepperKeyId) as KeyRow | undefined;
const target = targetRow ? keyRecord(targetRow) : null;
if (
!target ||
target.state !== 'staged' ||
!target.materialDigest ||
!target.backupDigest ||
command.activatedAtMs < target.registeredAtMs
) {
throw new LocalOwnerPepperKeyNotActivatableError();
}
if (current) {
const retired = client
.prepare(
`UPDATE "QingLong3LocalOwnerPepperKeys"
SET state = 'retired', version = version + 1,
retire_mutation_id = ?, retired_at_ms = ?
WHERE pepper_key_id = ? AND state = 'active'`,
)
.run(
command.mutationId,
command.activatedAtMs,
current.activePepperKeyId,
);
if (retired.changes !== 1) {
throw new LocalOwnerPepperGenerationConflictError();
}
}
const activated = client
.prepare(
`UPDATE "QingLong3LocalOwnerPepperKeys"
SET state = 'active', version = version + 1,
activate_mutation_id = ?, activated_at_ms = ?
WHERE pepper_key_id = ? AND version = ? AND state = 'staged'`,
)
.run(
command.mutationId,
command.activatedAtMs,
command.pepperKeyId,
target.version,
);
if (activated.changes !== 1) {
throw new LocalOwnerPepperGenerationConflictError();
}
client
.prepare(
`INSERT INTO "QingLong3LocalOwnerPepperActivations" (
generation, mutation_id, expected_generation,
previous_pepper_key_id, active_pepper_key_id,
material_digest, backup_digest, activated_at_ms
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
)
.run(
generation + 1,
command.mutationId,
command.expectedGeneration,
current?.activePepperKeyId ?? null,
command.pepperKeyId,
target.materialDigest,
target.backupDigest,
command.activatedAtMs,
);
const activation = activationRecord(
client
.prepare(`${ACTIVATION_SELECT} WHERE mutation_id = ?`)
.get(command.mutationId) as unknown as ActivationRow,
);
client.exec('COMMIT');
return Object.freeze({ status: 'inserted' as const, activation });
} catch (error) {
if (client.isTransaction) client.exec('ROLLBACK');
if (
error instanceof LocalOwnerPepperMutationConflictError ||
error instanceof LocalOwnerPepperGenerationConflictError ||
error instanceof LocalOwnerPepperKeyNotActivatableError ||
error instanceof LocalOwnerPepperRepositoryUnavailableError
) {
throw error;
}
throw new LocalOwnerPepperRepositoryUnavailableError();
}
},
() => new LocalOwnerPepperRepositoryUnavailableError(),
);
}
}