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/signature/Authors.astro | 275 ------------------------------ src/components/signature/Commit.astro | 86 ---------- src/components/signature/Downloads.astro | 63 ------- src/components/signature/Signature.astro | 44 ----- src/components/signature/Summary.astro | 279 ------------------------------- 5 files changed, 747 deletions(-) delete mode 100644 src/components/signature/Authors.astro delete mode 100644 src/components/signature/Commit.astro delete mode 100644 src/components/signature/Downloads.astro delete mode 100644 src/components/signature/Signature.astro delete mode 100644 src/components/signature/Summary.astro (limited to 'src/components/signature') diff --git a/src/components/signature/Authors.astro b/src/components/signature/Authors.astro deleted file mode 100644 index 4e52d4e..0000000 --- a/src/components/signature/Authors.astro +++ /dev/null @@ -1,275 +0,0 @@ ---- -import { toPK } from "@lib/pgp"; -import { createKeyFromArmor } from "@lib/pgp/create"; -import type { Verification } from "@lib/pgp/verify"; -import { defined, get, instanciate } from "@utils/anonymous"; -import { z } from "astro:content"; -import type { EntityTypesEnum } from "src/consts"; -import qrcode from "yaqrcode"; -import type { getSigners } from "@lib/collection/helpers"; - -interface Props { - verifications: NonNullable; - expectedSigners: Awaited>; - commitSignerKey?: string; -} - -const { - verifications: verificationsPromise, - expectedSigners, - commitSignerKey, -} = Astro.props; - -const fingerprintToData = new Map< - string, - { websites: URL[]; role: z.infer } ->(); - -for (const { entity, role } of expectedSigners) { - const key = await createKeyFromArmor(entity.data.publickey.armor); - const fingerprint = key.getFingerprint(); - fingerprintToData.set(fingerprint, { - websites: entity.data.websites?.map(instanciate(URL)) ?? [], - role, - }); -} - -let verifications = await Promise.all( - verificationsPromise.map(async ({ key, keyID, userID, verified }) => { - return { - key: await key, - keyID, - userID: await userID, - verified: await verified.catch(() => false), - }; - }), -); - -const expectedKeys = await Promise.all( - expectedSigners.map(get("entity")).map(({ data }) => - createKeyFromArmor(data.publickey.armor) - ), -); - -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 }) => { - const fingerprint = key - ? toPK(key).getFingerprint() - : undefined; - const info = fingerprint - ? fingerprintToData.get(fingerprint) - : undefined; - const primary = userID?.[0]; - let role = ""; - switch (info?.role) { - case "author": { - role = "Autor"; - break; - } - case "co-author": { - role = "Co-autor"; - break; - } - case "translator": { - role = "Tradutor"; - break; - } - } - 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 e as suas chaves públicas. -

-
AssinanteFunçãoFingerprintVálidoCommiter
- - {role} - <>{ - key - ? "0x" + toPK(key).getKeyID().toHex() - : "0x" + keyID.toHex() - } - { - key && false && ( - - ) - } - { - key && - ( - -
-
{toPK(key).armor()}
-
- ) - } - -
{verified ? "✅" : "❌"} - { - commitSignerKey && - key?.getFingerprint().toUpperCase()?.endsWith( - commitSignerKey.toUpperCase(), - ) && "✅" - } -
-
- - diff --git a/src/components/signature/Commit.astro b/src/components/signature/Commit.astro deleted file mode 100644 index 328a8f9..0000000 --- a/src/components/signature/Commit.astro +++ /dev/null @@ -1,86 +0,0 @@ ---- -import { gitDir } from "@lib/git"; -import type { Commit } from "@lib/git/types"; -import { toIso8601Full } from "@utils/datetime"; - -type Props = { commit: Commit; lang: string }; - -const dir = await gitDir(); -const { hash, files, author, committer, signature } = Astro.props.commit; - -const formatter = new Intl.DateTimeFormat([Astro.props.lang], { - dateStyle: "short", - timeStyle: "short", -}); ---- - -
-
- - Informações sobre o último commit que modificou ficheiros relacionados a - este blog post: - -
-
Hash
-
0x{hash.short.toUpperCase()}
-
Ficheiros modificados
- { - files.length > 0 - ? files.map((file) => ( -
{file.path.pathname.replace(dir.pathname, "")}
- )) - :
Nenhum ficheiro modificado
- } -
- Autor () -
-
- {author.name} <{ - author.email - }> -
-
- Commiter () -
-
- {committer.name} <{ - committer.email - }> -
- { - signature && - ( -
Assinatura do commit
-
-
-
Tipo
-
{signature.type}
-
Assinante
-
{signature.signer}
-
Fingerprint da chave
-
0x{signature.key.short}
-
-
- ) - } -
-
-
- - diff --git a/src/components/signature/Downloads.astro b/src/components/signature/Downloads.astro deleted file mode 100644 index 3497b37..0000000 --- a/src/components/signature/Downloads.astro +++ /dev/null @@ -1,63 +0,0 @@ ---- -import { gitDir } from "@lib/git"; -import { get } from "@utils/anonymous"; - -interface Props { - lang: string; -} - -const { lang } = Astro.props; - -let source = new URL( - `${Astro.url.href.replace(/\/$/, "")}.md`, -); - -const dir = await gitDir(); - -const format: Intl.NumberFormatOptions = { - notation: "compact", - style: "unit", - unit: "byte", - unitDisplay: "narrow", -}; - -const formatter = new Intl.NumberFormat(lang, format); - -const sourceSize = formatter.format( - await Deno.stat( - new URL("public" + source.pathname, dir), - ).then(get("size")), -); -const sig = await Deno.stat( - new URL("public" + source.pathname + ".sig", dir), -).then(get("size")).catch(() => undefined); -const sigSize = formatter.format(sig); ---- - -
-

Ficheiros para descarregar:

-
-
Blog post
-
- text/markdown, {sourceSize} -
- { - sig && ( -
Assinatura digital
-
- application/pgp-signature, {sigSize} -
- ) - } -
-
diff --git a/src/components/signature/Signature.astro b/src/components/signature/Signature.astro deleted file mode 100644 index 57e9902..0000000 --- a/src/components/signature/Signature.astro +++ /dev/null @@ -1,44 +0,0 @@ ---- -import type { Verification } from "@lib/pgp/verify"; -import Summary from "./Summary.astro"; -import Downloads from "./Downloads.astro"; -import Commit from "./Commit.astro"; - -interface Props { - verification: Verification; - lang: string; -} - -const { verification, lang } = Astro.props; -const commit = await verification.commit; ---- - - - - - diff --git a/src/components/signature/Summary.astro b/src/components/signature/Summary.astro deleted file mode 100644 index f25c1d1..0000000 --- a/src/components/signature/Summary.astro +++ /dev/null @@ -1,279 +0,0 @@ ---- -import { - createVerificationSummary, - logLevel, - type Summary, - VerificationResult, -} from "@lib/pgp/summary"; -import type { Verification } from "@lib/pgp/verify"; -import { Level } from "@utils/index"; -import type { NonEmptyArray } from "@utils/iterator"; - -interface Props extends Verification {} - -let [errors, keys] = await createVerificationSummary(Astro.props); -const failed = errors.filter((summary) => "reason" in summary); - -if (failed.length > 0) { - errors = failed as NonEmptyArray; -} - -let worst; - -for (const summary of errors) { - if (worst === undefined) { - worst = summary; - } - - const { result } = summary; - const a = logLevel(worst.result); - const b = logLevel(result); - if (a[0] === b[0] && !a[1] && b[1]) { - worst = summary; - } else if (b[0] === Level.ERROR) { - worst = summary; - } else if (a[0] === Level.OK && b[0] === Level.WARN) { - worst = summary; - } -} - -let lvl: [Level, boolean] | undefined = undefined; - -let label; - -let title = ""; -let content; -const error = worst && "reason" in worst ? worst.reason : undefined; - -if (worst) { - lvl = logLevel(worst.result); - switch (lvl[0]) { - case Level.OK: { - label = "OK"; - break; - } - case Level.WARN: { - label = "Aviso"; - break; - } - case Level.ERROR: { - label = "Erro"; - break; - } - default: { - throw new Error("Unreachable"); - } - } - - switch (worst.result) { - case VerificationResult.NO_SIGNATURE: { - title = "Assinatura não encontrada"; - content = `

-Este blog post não foi assinado. -

-

-Não existe forma de verificar a autentacidade do autor ou a integridade do texto escrito. -

-`; - break; - } - case VerificationResult.MISSING_KEY: { - title = "Chave não encontrada"; - content = `

-Este blog post está assinado digitalmente, porém a chave pública com KeyID 0x${worst.keyID} com que foi assinado não foi encontrada no chaveiro sendo impossível verificar a assinatura, quer dizer, não existe forma de verificar a autentacidade do autor ou a integridade do texto escrito. -

-

-Procure a chave noutro sítio da internet para conseguir fazer a verificação manualmente. -

-`; - break; - } - case VerificationResult.SIGNATURE_CORRUPTED: { - title = "Assinatura corrumpida"; - content = `

-Exite um ficheiro que supostamente é a assinatura, mas ele está corrompido ou com um formato inválido. -

-

-Não existe forma de verificar a autentacidade do autor ou a integridade do texto escrito. -

-`; - break; - } - case VerificationResult.SIGNATURE_COULD_NOT_BE_CHECKED: { - title = "Erro desconhecido"; - content = `

-A assinatura foi encontrada mas ocorreu um erro inesperado durante a verificação. -

-

-Não existe forma de verificar a autentacidade do autor ou a integridade do texto escrito. -

-`; - break; - } - case VerificationResult.BAD_SIGNATURE: { - title = "Assinatura inválida"; - content = `

-Existe uma assinatura digital porém o conteúdo da blog post não corresponde à assinatura. Talvez o texto tenha sido alterado sem ter sido criada uma nova assinatura. -

-

-Pode tentar verificar a assinatura com versões antigas do blog post, mas esta versão não pode ser verificada quanto à autentacidade do autor ou à integridade do texto escrito. -

-`; - break; - } - case VerificationResult.UNTRUSTED_KEY: { - title = "Assinatura válida (chave não confiada)"; - content = `

-A assinatura digital é criptograficamente válida, porém a chave utilizada não é suficientemente confiada pelo servidor. Mas podes ter a certeza que o dono da chave pública é a mesma pessoa que assinou este blog post. -

-`; - break; - } - case VerificationResult.TRUSTED_KEY: { - title = "Assinatura válida"; - content = `

-A assinatura digital é criptograficamente válida. O dono da chave pública é a mesma pessoa que assinou este blog post exatamente como ele está, sem alterações. -

-`; - break; - } - case VerificationResult.EXPIRATION_AFTER_SIGNATURE: { - break; - } - case VerificationResult.EXPIRATION_BEFORE_SIGNATURE: { - break; - } - case VerificationResult.REVOCATION_AFTER_SIGNATURE: { - break; - } - case VerificationResult.REVOCATION_BEFORE_SIGNATURE: { - break; - } - case VerificationResult.KEY_DOES_NOT_SIGN: { - break; - } - default: { - throw new Error("Unreachable"); - } - } -} ---- - -{ - lvl && - ( -
- {label?.toUpperCase()}: {title.toUpperCase()} - - {error &&
{error}
} -
- ) -} - - -- cgit v1.2.3