From 0af094770c4ebabc56ff761a8bd215bc397c0f7e Mon Sep 17 00:00:00 2001 From: João Augusto Costa Branco Marado Torres Date: Tue, 5 Aug 2025 18:50:37 +0100 Subject: refactor: reading page review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: João Augusto Costa Branco Marado Torres --- src/lib/pgp/summary.ts | 216 +++++++++++++++++++++++++------------------------ src/lib/pgp/verify.ts | 38 +++++---- 2 files changed, 134 insertions(+), 120 deletions(-) (limited to 'src/lib/pgp') diff --git a/src/lib/pgp/summary.ts b/src/lib/pgp/summary.ts index 5c8a81c..bcd9bc8 100644 --- a/src/lib/pgp/summary.ts +++ b/src/lib/pgp/summary.ts @@ -57,7 +57,7 @@ export type Summary = { result: VerificationResult.MISSING_KEY; reason: Error; keyID: string; - created: Date; + created: Date | null; } | { result: | VerificationResult.SIGNATURE_CORRUPTED @@ -67,11 +67,11 @@ export type Summary = { } | { result: VerificationResult.TRUSTED_KEY; key: PublicKey | Subkey; - created: Date; + created: Date | null; } | { result: VerificationResult.UNTRUSTED_KEY; key: PublicKey | Subkey; - created: Date; + created: Date | null; } | { result: VerificationResult.EXPIRATION_AFTER_SIGNATURE; key: PublicKey | Subkey; @@ -99,7 +99,7 @@ export type Summary = { key: PublicKey | Subkey; }; -export async function createVerificationSummary( +export async function createVerificationsSummary( { dataCorrupted, verifications, signature }: Verification, ): Promise<[NonEmptyArray, Map>]> { if (signature === undefined) { @@ -116,107 +116,7 @@ export async function createVerificationSummary( const summaries = await Promise.all< Promise<[Summary[], Map]>[] - >( - (verifications ?? []).map( - async ({ signatureCorrupted, verified, packet, key }) => { - const errors: Summary[] = []; - const keys: Map = new Map(); - - try { - await verified; - } catch (e) { - if (e instanceof Error) { - if ( - e.message.startsWith("Could not find signing key with key ID") - ) { - const keyID = e.message.slice(e.message.lastIndexOf(" ")); - const key = keys.get(keyID) ?? []; - key.push({ - result: VerificationResult.MISSING_KEY, - keyID, - reason: e, - }); - keys.set(keyID, key); - } else { - errors.push({ - result: VerificationResult.SIGNATURE_COULD_NOT_BE_CHECKED, - reason: e, - }); - } - } else { - throw e; - } - } - - const corrupted = await signatureCorrupted; - if (corrupted[0]) { - errors.push({ - result: VerificationResult.SIGNATURE_CORRUPTED, - reason: corrupted[1], - }); - } - - const sig = await packet; - const keyID = sig.issuerKeyID; - - sig.created; - - const keyAwaited = await key; - - if (keyAwaited === undefined) { - const key = keys.get(keyID.toHex()) ?? []; - key.push({ - result: VerificationResult.MISSING_KEY, - keyID: keyID.toHex(), - reason: new Error( - `Could not find signing key with key ID ${keyID.toHex()}`, - ), - }); - keys.set(keyID.toHex(), key); - - return [errors, keys] as [Summary[], Map]; - } - - const keySummaries = keys.get(keyAwaited.getKeyID().toHex()) ?? []; - const expired = await isKeyExpired(keyAwaited); - - if (expired !== null && sig.created !== null) { - keySummaries.push({ - result: expired <= sig.created - ? VerificationResult.EXPIRATION_BEFORE_SIGNATURE - : VerificationResult.EXPIRATION_AFTER_SIGNATURE, - key: keyAwaited, - date: expired, - }); - } - - const revoked = isKeyRevoked(keyAwaited); - if (revoked?.date !== undefined && sig.created !== null) { - keySummaries.push({ - result: revoked?.date <= sig.created - ? VerificationResult.REVOCATION_BEFORE_SIGNATURE - : VerificationResult.REVOCATION_AFTER_SIGNATURE, - key: keyAwaited, - date: revoked.date, - revocationReason: revoked.reason, - }); - } - - const trust = sig.trustAmount ?? await keyTrust(keyAwaited as Key); - - keySummaries.push({ - result: trust > 0 - ? VerificationResult.TRUSTED_KEY - : VerificationResult.UNTRUSTED_KEY, - key: keyAwaited, - }); - - keys.set(keyAwaited.getKeyID().toHex(), keySummaries); - - return [errors, keys] as [Summary[], Map]; - }, - ), - ); + >((verifications ?? []).map(createVerificationSummary)); const errors = summaries.flatMap(([x]) => x); const keys = new Map(summaries.flatMap(([, x]) => x.entries().toArray())); @@ -230,3 +130,109 @@ export async function createVerificationSummary( throw new Error("unreachable"); } + +export const createVerificationSummary = async ( + { signatureCorrupted, verified, packet, key }: NonNullable< + Verification["verifications"] + >[number], +): Promise<[Summary[], Map]> => { + const errors: Summary[] = []; + const keys: Map = new Map(); + + const sig = await packet; + + try { + await verified; + } catch (e) { + if (e instanceof Error) { + if ( + e.message.startsWith("Could not find signing key with key ID") + ) { + const keyID = e.message.slice(e.message.lastIndexOf(" ")); + const key = keys.get(keyID) ?? []; + key.push({ + result: VerificationResult.MISSING_KEY, + keyID, + reason: e, + created: sig.created, + }); + keys.set(keyID, key); + } else { + errors.push({ + result: VerificationResult.SIGNATURE_COULD_NOT_BE_CHECKED, + reason: e, + }); + } + } else { + throw e; + } + } + + const corrupted = await signatureCorrupted; + if (corrupted[0]) { + errors.push({ + result: VerificationResult.SIGNATURE_CORRUPTED, + reason: corrupted[1], + }); + } + + const keyID = sig.issuerKeyID; + + const keyAwaited = await key; + + if (keyAwaited === undefined) { + const key = keys.get(keyID.toHex()) ?? []; + key.push({ + result: VerificationResult.MISSING_KEY, + keyID: keyID.toHex(), + reason: new Error( + `Could not find signing key with key ID ${keyID.toHex()}`, + ), + created: sig.created, + }); + keys.set(keyID.toHex(), key); + + return [errors, keys] as [Summary[], Map]; + } + + const keySummaries = keys.get(keyAwaited.getKeyID().toHex()) ?? []; + const expired = await isKeyExpired(keyAwaited); + + if (expired !== null && sig.created !== null) { + keySummaries.push({ + result: expired <= sig.created + ? VerificationResult.EXPIRATION_BEFORE_SIGNATURE + : VerificationResult.EXPIRATION_AFTER_SIGNATURE, + key: keyAwaited, + created: sig.created, + expired, + }); + } + + const revoked = isKeyRevoked(keyAwaited); + if (revoked?.date !== undefined && sig.created !== null) { + keySummaries.push({ + result: revoked?.date <= sig.created + ? VerificationResult.REVOCATION_BEFORE_SIGNATURE + : VerificationResult.REVOCATION_AFTER_SIGNATURE, + key: keyAwaited, + created: sig.created, + revoked: revoked.date, + revocationReason: revoked.reason, + }); + } + + const trust = sig.trustAmount ?? await keyTrust(keyAwaited as Key); + + keySummaries.push({ + result: trust > 0 + ? VerificationResult.TRUSTED_KEY + : VerificationResult.UNTRUSTED_KEY, + key: keyAwaited, + created: sig.created, + }); + + keys.set(keyAwaited.getKeyID().toHex(), keySummaries); + + return [errors, keys] as [Summary[], Map]; +}; diff --git a/src/lib/pgp/verify.ts b/src/lib/pgp/verify.ts index 026b6df..1003147 100644 --- a/src/lib/pgp/verify.ts +++ b/src/lib/pgp/verify.ts @@ -24,6 +24,7 @@ import type { Commit } from "../git/types.ts"; import { findMapAsync, type MaybeIterable } from "../../utils/iterator.ts"; import { getUserIDsFromKey } from "./user.ts"; import { env } from "../environment.ts"; +import { toPK } from "./index.ts"; type DataURL = [URL, URL?]; type Corrupted = [false] | [true, Error]; @@ -195,18 +196,21 @@ export class SignatureVerifier { } } - addKey(key: MaybeIterable): void { + addKey(key: MaybeIterable): Iterable { if (key instanceof PublicKey) { this.keys.push(key); + return [key]; } else { this.keys.push(...key); + return key; } } async addKeysFromDir( key: string | URL, rules: KeyDiscoveryRules = DEFAULT_KEY_DISCOVERY_RULES, - ): Promise { + ): Promise> { + const keys: PublicKey[] = []; for await ( const i of createKeysFromDir(key, rules, { encoder: this.#encoder, @@ -214,39 +218,43 @@ export class SignatureVerifier { }) ) { this.keys.push(i); + keys.push(i); } + return keys; } async addKeyFromFile( key: string | URL, type: KeyFileFormat, - ): Promise { + ): Promise { switch (type) { case armored: { - this.keys.push(await createKeyFromFile(key, type, this.#decoder)); - break; + const k = await createKeyFromFile(key, type, this.#decoder); + this.keys.push(k); + return k; } case binary: { - this.keys.push(await createKeyFromFile(key, type, this.#encoder)); - break; + const k = await createKeyFromFile(key, type, this.#encoder); + this.keys.push(k); + return k; } } } async addKeyFromArmor( key: string | Uint8Array, - ): Promise { - this.keys.push( - await createKeyFromArmor(key, this.#decoder).then((x) => x.toPublic()), - ); + ): Promise { + const k = await createKeyFromArmor(key, this.#decoder).then(toPK); + this.keys.push(k); + return k; } async addKeyFromBinary( key: string | Uint8Array, - ): Promise { - this.keys.push( - await createKeyFromBinary(key, this.#encoder).then((x) => x.toPublic()), - ); + ): Promise { + const k = await createKeyFromBinary(key, this.#encoder).then(toPK); + this.keys.push(k); + return k; } public static async instance(): Promise { -- cgit v1.2.3