Files
Harlekin e0b03ea336
Prüfung / Lint, Typen, Tests (push) Canceled after 0s
Prüfung / Images bauen (pdf) (push) Canceled after 0s
Prüfung / Images bauen (web) (push) Canceled after 0s
Prüfung / Images bauen (worker) (push) Canceled after 0s
Images / bauen (pdf, docker/pdf.Dockerfile) (push) Canceled after 0s
Images / bauen (web, docker/web.Dockerfile) (push) Canceled after 0s
Images / bauen (worker, docker/worker.Dockerfile) (push) Canceled after 0s
Gedankenstriche durch Bindestriche ersetzt
375 Vorkommen in 210 Dateien. Betrifft Kommentare, Oberflaechentexte und die
README; an keiner Stelle Bedeutung, nur Zeichensetzung.
2026-09-04 08:54:52 +02:00

95 lines
3.4 KiB
TypeScript
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// @vitest-environment node
import { describe, expect, it } from 'vitest'
import sharp from 'sharp'
import { reencode } from '@/lib/files/reencode'
import { detectType } from '@/lib/files/magic'
/**
* Die Neukodierung ist die wirksamste Massnahme der Kette: ein Bild, das durch
* `sharp` gelaufen ist, besteht nur noch aus Pixeln.
*
* Diese Tests prüfen genau das - nicht, dass irgendetwas herauskommt, sondern
* dass das, was nicht Inhalt ist, **weg** ist.
*/
async function testbild(): Promise<Buffer> {
return sharp({
create: { width: 24, height: 16, channels: 3, background: { r: 200, g: 40, b: 40 } },
})
.jpeg()
.withMetadata({
exif: {
IFD0: { Copyright: 'GEHEIMER FOTOGRAF', Software: 'Kamera 9000' },
},
})
.toBuffer()
}
describe('Bilder neu kodieren', () => {
it('wirft die Metadaten weg, statt sie zu filtern', async () => {
const original = await testbild()
// Gegenprobe: das Original trägt die Daten wirklich.
expect(original.includes(Buffer.from('GEHEIMER FOTOGRAF'))).toBe(true)
const ergebnis = await reencode(new Uint8Array(original), 'image/jpeg')
expect(ergebnis.ok).toBe(true)
if (!ergebnis.ok) return
const neu = Buffer.from(ergebnis.result.content)
expect(neu.includes(Buffer.from('GEHEIMER FOTOGRAF'))).toBe(false)
expect(neu.includes(Buffer.from('Kamera 9000'))).toBe(false)
// Und es ist noch dasselbe Bild.
const info = await sharp(neu).metadata()
expect(info.width).toBe(24)
expect(info.height).toBe(16)
expect(ergebnis.result.width).toBe(24)
})
it('zerstört eine angehängte Nutzlast', async () => {
// Der klassische Trick: hinter das Bildende Daten kleben. Nach der
// Neukodierung ist davon nichts mehr da, weil nur die Pixel übernommen
// werden.
const angehaengt = Buffer.concat([
await testbild(),
Buffer.from('<?php system($_GET["c"]); ?>'),
])
const ergebnis = await reencode(new Uint8Array(angehaengt), 'image/jpeg')
expect(ergebnis.ok).toBe(true)
if (!ergebnis.ok) return
expect(Buffer.from(ergebnis.result.content).includes(Buffer.from('<?php'))).toBe(false)
})
it('erzeugt Vorschaubild und Platzhalter', async () => {
const ergebnis = await reencode(new Uint8Array(await testbild()), 'image/jpeg')
expect(ergebnis.ok).toBe(true)
if (!ergebnis.ok) return
expect(ergebnis.result.thumb).toBeDefined()
// Das Vorschaubild ist immer WebP, damit die Auslieferung es gefahrlos
// inline schicken kann.
expect(detectType(ergebnis.result.thumb!)).toEqual({ ok: true, type: 'image/webp' })
expect(ergebnis.result.blurhash).toMatch(/^[\w#$%*+,\-.:;=?@[\]^_{|}~]{6,}$/)
})
it('lehnt ab, was kein Bild ist', async () => {
const ergebnis = await reencode(new TextEncoder().encode('kein Bild'), 'image/png')
expect(ergebnis.ok).toBe(false)
})
})
describe('Text normalisieren', () => {
it('entfernt die Stückliste am Anfang', async () => {
const mitBom = new TextEncoder().encode('Hallo Welt')
const ergebnis = await reencode(mitBom, 'text/plain')
expect(ergebnis.ok).toBe(true)
if (!ergebnis.ok) return
expect(new TextDecoder().decode(ergebnis.result.content)).toBe('Hallo Welt')
})
it('lehnt ungültiges UTF-8 ab', async () => {
const ergebnis = await reencode(new Uint8Array([0xff, 0xfe, 0x41]), 'text/plain')
expect(ergebnis.ok).toBe(false)
})
})