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/components/templates/Authors.astro | 355 +++++++++++++++++++++++++++++++++ 1 file changed, 355 insertions(+) create mode 100644 src/components/templates/Authors.astro (limited to 'src/components/templates/Authors.astro') diff --git a/src/components/templates/Authors.astro b/src/components/templates/Authors.astro new file mode 100644 index 0000000..61ca026 --- /dev/null +++ b/src/components/templates/Authors.astro @@ -0,0 +1,355 @@ +--- +import { type RevocationReason, toPK } from "@lib/pgp"; +import type { Verification } from "@lib/pgp/verify"; +import { defined, get } from "@utils/anonymous"; +import type { getSigners } from "@lib/collection/helpers"; +import type { PublicKey, UserIDPacket } from "openpgp"; +import { + createVerificationSummary, + VerificationResult, +} from "@lib/pgp/summary"; +import Date from "@components/organisms/Date.astro"; + +interface Props { + verifications: NonNullable; + expectedSigners: Map< + string, + { + signer: Awaited>[number]; + users: UserIDPacket[]; + key: PublicKey; + } + >; + commitSignerKey?: string; +} + +const { + verifications: verificationsPromise, + expectedSigners, + commitSignerKey, +} = Astro.props; + +let verifications = await Promise.all( + verificationsPromise.map(async (verification) => { + const { key, keyID, userID, verified } = verification; + return { + key: await key, + keyID, + userID: await userID, + verified: await verified.catch(() => false), + summary: await createVerificationSummary(verification), + }; + }), +); + +const expectedKeys = Array.from(expectedSigners.values()).map(get("key")); + +const expectedFingerprints = new Set( + expectedKeys.map((key) => key.getFingerprint()), +); + +const verifiedFingerprints = new Set( + verifications.map((v) => v.key).filter(defined).map(toPK).map((key) => + key.getFingerprint() + ), +); + +if (!expectedFingerprints.isSubsetOf(verifiedFingerprints)) { + throw new Error( + `Missing signature from expected signers: ${[ + ...expectedFingerprints.difference(verifiedFingerprints).values(), + ]}`, + ); +} +--- + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + { + verifications.map( + ({ userID, key, keyID, verified, summary }) => { + const fingerprint = key + ? toPK(key).getFingerprint() + : undefined; + const info = fingerprint + ? expectedSigners.get(fingerprint) + : undefined; + const primary = userID?.[0]; + const signer = info?.signer; + let role = ""; + switch (signer?.role) { + case "author": { + role = "Autor"; + break; + } + case "co-author": { + role = "Co-autor"; + break; + } + case "translator": { + role = "Tradutor"; + break; + } + } + const { + reasons, + created, + expired, + revoked, + revocationReason, + trusted, + } = (summary[1].get(keyID.toHex()) ?? []).reduce( + (acc, x) => { + if (!("key" in x || "keyID" in x)) { + return acc; + } + + switch (x.result) { + case VerificationResult.MISSING_KEY: + acc.reasons.push(x.reason); + acc.created = x.created ?? undefined; + break; + case VerificationResult.UNTRUSTED_KEY: + acc.created = x.created ?? undefined; + acc.trusted &&= false; + break; + case VerificationResult.TRUSTED_KEY: + acc.created = x.created ?? undefined; + acc.trusted = true; + break; + case VerificationResult + .EXPIRATION_AFTER_SIGNATURE: + acc.created = x.created ?? undefined; + acc.expired = x.expired; + break; + case VerificationResult + .EXPIRATION_BEFORE_SIGNATURE: + acc.created = x.created ?? undefined; + acc.expired = x.expired; + break; + case VerificationResult + .REVOCATION_AFTER_SIGNATURE: + acc.created = x.created ?? undefined; + acc.revoked = x.revoked; + acc.revocationReason = x.revocationReason; + break; + case VerificationResult + .REVOCATION_BEFORE_SIGNATURE: + acc.created = x.created ?? undefined; + acc.revoked = x.revoked; + acc.revocationReason = x.revocationReason; + break; + case VerificationResult.KEY_DOES_NOT_SIGN: + break; + } + + return acc; + }, + { + reasons: [], + created: undefined, + expired: undefined, + revoked: undefined, + revocationReason: undefined, + trusted: false, + } as { + reasons: Error[]; + created?: Date; + expired?: Date; + revoked?: Date; + revocationReason?: RevocationReason; + trusted: boolean; + }, + ); + return ( + + + + + + + + + ); + }, + ) + } + +
+ Assinaturas +

+ Para verificar uma assinatura é necessário a mensagem, a assinatura digital e as chaves públicas dos assinantes. Esta tabela mostra algumas + informações sobre os assinantes, as suas chaves públicas e as suas + assinaturas. +

+
AssinanteFunçãoFingerprintVálidoCommiterMais Informações
+ + {signer !== undefined && <>
Ver perfil} +
{role} + { + key + ? "0x" + toPK(key).getKeyID().toHex() + : "0x" + keyID.toHex() + } + {verified ? "✅" : "❌"} + { + commitSignerKey && + key?.getFingerprint().toUpperCase()?.endsWith( + commitSignerKey.toUpperCase(), + ) && "✅" + } + + { + key && ( + <> + +
+

Erros

+ { + summary[0].map((x) => { + if (!("reason" in x)) { + return undefined; + } + + let reason = x.reason; + + return
{reason.message}
; + }) + } +

Informações

+
+ { + reasons.map(({ message }) => ( + <>
Erro
{message}
+ )) + } + { + created && ( + <> +
Data da assinatura
+
+ + ) + } + { + expired && ( + <> +
Data de expiração
+
+ + ) + } + { + revoked && ( + <> +
Data de revogação
+
+ + ) + } + { + revocationReason && ( + <> +
Razão para a revogação
+
+ {revocationReason.flag}: {revocationReason.msg} +
+ + ) + } +
Chave confiável
+
{trusted ? "✅" : "❌"}
+
+
+ ) + } +
+
+ + -- cgit v1.2.3