Astro 7: die AVIF-Lücke in sharp/Astro 5 schließen
GHSA-26w7-cxv4-gfx2 (kritisch, RCE beim Verarbeiten von AVIF) hat für Astro 5 keinen Fix. Also hoch auf Astro 7.3.2, @astrojs/node 11, @astrojs/react 6 und sharp 0.35. `npm audit`: 0 Funde. Zwei Stellen mussten mit: - `experimental.csp` heißt seit Astro 7 `security.csp`. Das ist keine kosmetische Umbenennung: ein `csp` auf oberster Ebene wird ohne Warnung geschluckt und die Seite läuft ganz ohne Policy. Gemessen — Header vorher weg, nach der Korrektur wieder da, mit denselben Skript-Hashes wie unter Astro 5. - sharp exportiert den Typ `Sharp` jetzt benannt statt als Namensraum. Dazu das Image: node 20 → 22 (Astro 7 verlangt mehr als 20.19, die Tests brauchen 22.6 für --experimental-strip-types), und `npm ci` mit Lockfile statt `npm install` — sonst baut das Image nicht die Versionen, die getestet wurden. Geprüft gegen echtes Postgres: alle Seiten 200, Upload durch sharp 0.35, Bogen-PDF auf 210,00 × 297,00 mm gemessen, Einzelbild 35 × 45 mm bei 300 dpi = 413 × 531 px mit korrekter dpi-Angabe. 124 Tests grün.
This commit is contained in:
1 parent
5ba448f250
commit
2c2ef9d458
6 files changed
+1746
-3845
No files matched your search
+5
-3
@@ -1,4 +1,4 @@
|
|||||||
FROM node:20-bookworm-slim
|
FROM node:22-bookworm-slim
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
ENV NODE_ENV=production PORT=4321 HOST=0.0.0.0
|
ENV NODE_ENV=production PORT=4321 HOST=0.0.0.0
|
||||||
@@ -8,8 +8,10 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||||||
python3 make g++ ca-certificates \
|
python3 make g++ ca-certificates \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
COPY package.json ./
|
# Lockfile zuerst: `npm ci` baut exakt die Versionen, die getestet wurden —
|
||||||
RUN npm install --no-audit --no-fund
|
# nicht das, wozu die ^-Bereiche heute zufällig auflösen.
|
||||||
|
COPY package.json package-lock.json ./
|
||||||
|
RUN npm ci --no-audit --no-fund
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN npm run build
|
RUN npm run build
|
||||||
|
|||||||
+6
-3
@@ -9,11 +9,14 @@ export default defineConfig({
|
|||||||
integrations: [react()],
|
integrations: [react()],
|
||||||
// CSRF: eigener Schutz über SameSite=Lax-Session-Cookie. Astros checkOrigin
|
// CSRF: eigener Schutz über SameSite=Lax-Session-Cookie. Astros checkOrigin
|
||||||
// bricht multipart-Uploads hinter dem Reverse-Proxy (http↔https-Mismatch).
|
// bricht multipart-Uploads hinter dem Reverse-Proxy (http↔https-Mismatch).
|
||||||
security: { checkOrigin: false },
|
//
|
||||||
// Content-Security-Policy mit Hashes statt 'unsafe-inline': Astro rechnet die
|
// Content-Security-Policy mit Hashes statt 'unsafe-inline': Astro rechnet die
|
||||||
// Hashes seiner eigenen inline-Skripte und -Styles beim Bauen aus. Die übrigen
|
// Hashes seiner eigenen inline-Skripte und -Styles beim Bauen aus. Die übrigen
|
||||||
// Direktiven setzt die Middleware (src/middleware.ts).
|
// Direktiven ergänzt die Middleware (src/middleware.ts).
|
||||||
experimental: {
|
// Seit Astro 7 stabil und unter `security.csp` — nicht mehr unter `experimental`.
|
||||||
|
// Achtung: ein `csp` auf oberster Ebene wird stillschweigend ignoriert.
|
||||||
|
security: {
|
||||||
|
checkOrigin: false,
|
||||||
csp: {
|
csp: {
|
||||||
directives: [
|
directives: [
|
||||||
"default-src 'self'",
|
"default-src 'self'",
|
||||||
|
|||||||
Generated
+1725
-3832
File diff suppressed because it is too large.
Load diff
+7
-4
@@ -3,6 +3,9 @@
|
|||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=22.6"
|
||||||
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "astro dev",
|
"dev": "astro dev",
|
||||||
"build": "astro build",
|
"build": "astro build",
|
||||||
@@ -12,15 +15,15 @@
|
|||||||
"test": "node --experimental-strip-types --test tests/*.test.ts"
|
"test": "node --experimental-strip-types --test tests/*.test.ts"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/node": "^9.1.3",
|
"@astrojs/node": "^11.1.5",
|
||||||
"@astrojs/react": "^4.2.1",
|
"@astrojs/react": "^6.0.5",
|
||||||
"@aws-sdk/client-s3": "^3.700.0",
|
"@aws-sdk/client-s3": "^3.700.0",
|
||||||
"@aws-sdk/s3-request-presigner": "^3.700.0",
|
"@aws-sdk/s3-request-presigner": "^3.700.0",
|
||||||
"@fontsource/space-grotesk": "^5.1.0",
|
"@fontsource/space-grotesk": "^5.1.0",
|
||||||
"@fontsource/space-mono": "^5.1.0",
|
"@fontsource/space-mono": "^5.1.0",
|
||||||
"archiver": "^7.0.1",
|
"archiver": "^7.0.1",
|
||||||
"argon2": "^0.41.1",
|
"argon2": "^0.41.1",
|
||||||
"astro": "^5.5.0",
|
"astro": "^7.3.2",
|
||||||
"basic-ftp": "^5.0.5",
|
"basic-ftp": "^5.0.5",
|
||||||
"grammy": "^1.30.0",
|
"grammy": "^1.30.0",
|
||||||
"heic-convert": "^2.1.0",
|
"heic-convert": "^2.1.0",
|
||||||
@@ -30,7 +33,7 @@
|
|||||||
"pg-boss": "^10.1.5",
|
"pg-boss": "^10.1.5",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
"sharp": "^0.33.5",
|
"sharp": "^0.35.4",
|
||||||
"ssh2-sftp-client": "^11.0.0"
|
"ssh2-sftp-client": "^11.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Rendern des Druckbogens: Zuschnitt (sharp) + PDF-Aufbau (pdf-lib).
|
// Rendern des Druckbogens: Zuschnitt (sharp) + PDF-Aufbau (pdf-lib).
|
||||||
// Bewusst ohne KI — reine Geometrie und Skalierung, damit das Ergebnis
|
// Bewusst ohne KI — reine Geometrie und Skalierung, damit das Ergebnis
|
||||||
// vorhersagbar und wiederholbar ist.
|
// vorhersagbar und wiederholbar ist.
|
||||||
import sharp from 'sharp';
|
import sharp, { type Sharp } from 'sharp';
|
||||||
import { PDFDocument, StandardFonts, rgb, degrees } from 'pdf-lib';
|
import { PDFDocument, StandardFonts, rgb, degrees } from 'pdf-lib';
|
||||||
import { mmToPt, mmToPx } from './paper.ts';
|
import { mmToPt, mmToPx } from './paper.ts';
|
||||||
import type { Line, Page, SheetSpec } from './printlayout.ts';
|
import type { Line, Page, SheetSpec } from './printlayout.ts';
|
||||||
@@ -110,7 +110,7 @@ export async function renderCell(
|
|||||||
const ext: 'jpg' | 'png' = opt.ext === 'png' || hasAlpha ? 'png' : 'jpg';
|
const ext: 'jpg' | 'png' = opt.ext === 'png' || hasAlpha ? 'png' : 'jpg';
|
||||||
if (hasAlpha && ext === 'jpg') img = img.flatten({ background: bg });
|
if (hasAlpha && ext === 'jpg') img = img.flatten({ background: bg });
|
||||||
|
|
||||||
const encode = (pipe: sharp.Sharp) => (ext === 'png'
|
const encode = (pipe: Sharp) => (ext === 'png'
|
||||||
? pipe.withMetadata({ density: dpi }).png({ compressionLevel: 9 })
|
? pipe.withMetadata({ density: dpi }).png({ compressionLevel: 9 })
|
||||||
: pipe.withMetadata({ density: dpi }).jpeg({ quality: 94, mozjpeg: true }));
|
: pipe.withMetadata({ density: dpi }).jpeg({ quality: 94, mozjpeg: true }));
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -54,7 +54,7 @@ export const onRequest = defineMiddleware(async (ctx, next) => {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sicherheits-Header. Die Content-Security-Policy selbst baut Astro beim Bauen
|
* Sicherheits-Header. Die Content-Security-Policy selbst baut Astro beim Bauen
|
||||||
* (`experimental.csp` in `astro.config.mjs`) und hängt echte **Hashes** für jedes
|
* (`csp` in `astro.config.mjs`) und hängt echte **Hashes** für jedes
|
||||||
* eigene inline-Skript an — also kein `'unsafe-inline'` für Skripte, das ist der
|
* eigene inline-Skript an — also kein `'unsafe-inline'` für Skripte, das ist der
|
||||||
* wichtige Teil gegen eingeschleusten Code.
|
* wichtige Teil gegen eingeschleusten Code.
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in new issue
Block a user