mirror of
https://github.com/Patiun/com.gregkilmer.www.git
synced 2026-11-08 04:08:24 +00:00
Turnstile and OTS update
This commit is contained in:
@@ -52,6 +52,16 @@ export default defineConfig({
|
|||||||
|
|
||||||
vite: {
|
vite: {
|
||||||
plugins: [tailwindcss()],
|
plugins: [tailwindcss()],
|
||||||
|
build: {
|
||||||
|
// Never inline assets as data URIs. The default (4096 bytes) causes Vite
|
||||||
|
// to inline the smallest font subsets (e.g. cyrillic-ext woff2) as
|
||||||
|
// data:font/woff2 base64, which (a) requires data: in font-src and (b)
|
||||||
|
// triggers Chromium "OTS parsing error: Size of decompressed WOFF 2.0 is
|
||||||
|
// less than compressed size" warnings on those inlined subsets. Forcing
|
||||||
|
// every asset to a real file keeps font-src tight at 'self' and avoids
|
||||||
|
// the OTS parse errors.
|
||||||
|
assetsInlineLimit: 0,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
server: {
|
server: {
|
||||||
|
|||||||
@@ -131,18 +131,8 @@ export default function ContactForm({ turnstileSiteKey }: Props) {
|
|||||||
// widget rapidly flashing. Instead we leave the widget in its errored
|
// widget rapidly flashing. Instead we leave the widget in its errored
|
||||||
// state; the next form submission will reset it for a fresh attempt.
|
// state; the next form submission will reset it for a fresh attempt.
|
||||||
// The error surfaces as the token being empty, which onSubmit reports.
|
// The error surfaces as the token being empty, which onSubmit reports.
|
||||||
'error-callback': (error: unknown) => {
|
'error-callback': () => {
|
||||||
turnstileTokenRef.current = '';
|
turnstileTokenRef.current = '';
|
||||||
// TEMPORARY DIAGNOSTIC: Turnstile passes an error code/string when the
|
|
||||||
// widget fails its challenge (e.g. "110200-domain-not-authorized",
|
|
||||||
// "300030-..."). The 400 on challenges.cloudflare.com/cdn-cgi/
|
|
||||||
// challenge-platform/... originates here. Log it so the browser
|
|
||||||
// console shows the exact reason. Remove once resolved.
|
|
||||||
console.warn('[contact] turnstile widget error:', error, {
|
|
||||||
sitekey: turnstileSiteKey,
|
|
||||||
origin: location.origin,
|
|
||||||
hostname: location.hostname,
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
theme: 'dark',
|
theme: 'dark',
|
||||||
},
|
},
|
||||||
|
|||||||
+6
-8
@@ -31,10 +31,9 @@
|
|||||||
* need the origin. (SRI is intentionally NOT applied to the Turnstile
|
* need the origin. (SRI is intentionally NOT applied to the Turnstile
|
||||||
* loader — see ContactForm.tsx for why.)
|
* loader — see ContactForm.tsx for why.)
|
||||||
*
|
*
|
||||||
* Fonts: Fontsource variable fonts (woff2) are self-hosted, but Vite inlines
|
* Fonts: Fontsource variable fonts (woff2) are self-hosted and emitted as
|
||||||
* font subsets below build.assetsInlineLimit (default 4096 bytes) as
|
* real files (Vite's assetsInlineLimit is set to 0 in astro.config.mjs so no
|
||||||
* data:font/woff2 base64 URIs. At least two small cyrillic-ext subsets fall
|
* subset is inlined as a data URI), so font-src can stay 'self'.
|
||||||
* under that threshold, so font-src MUST include data: or they are blocked.
|
|
||||||
*
|
*
|
||||||
* Images: board-game covers are self-hosted (fetched at build time by
|
* Images: board-game covers are self-hosted (fetched at build time by
|
||||||
* scripts/fetch-bgg-covers.mjs) and the hero portrait is local, but TCG deck
|
* scripts/fetch-bgg-covers.mjs) and the hero portrait is local, but TCG deck
|
||||||
@@ -67,10 +66,9 @@ const CONTENT_SECURITY_POLICY = [
|
|||||||
// storage.googleapis.com origin serves TCG deck featured-card art hotlinked
|
// storage.googleapis.com origin serves TCG deck featured-card art hotlinked
|
||||||
// from Archidekt's card-image bucket (see src/lib/archidekt.ts).
|
// from Archidekt's card-image bucket (see src/lib/archidekt.ts).
|
||||||
"img-src 'self' data: https://storage.googleapis.com",
|
"img-src 'self' data: https://storage.googleapis.com",
|
||||||
// Self-hosted variable fonts (woff2) via @fontsource-variable. data: is
|
// Self-hosted variable fonts (woff2) via @fontsource-variable, emitted as
|
||||||
// required because Vite inlines font subsets under assetsInlineLimit as
|
// real files (assetsInlineLimit: 0 — see astro.config.mjs).
|
||||||
// data:font/woff2 base64 URIs.
|
"font-src 'self'",
|
||||||
"font-src 'self' data:",
|
|
||||||
// Same-origin fetch/XHR (the contact form POSTs to /api/contact) plus the
|
// Same-origin fetch/XHR (the contact form POSTs to /api/contact) plus the
|
||||||
// Turnstile siteverify calls the widget makes from the browser.
|
// Turnstile siteverify calls the widget makes from the browser.
|
||||||
"connect-src 'self' https://challenges.cloudflare.com",
|
"connect-src 'self' https://challenges.cloudflare.com",
|
||||||
|
|||||||
@@ -94,17 +94,7 @@ async function verifyTurnstile(token: string | undefined, ip: string): Promise<b
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: form,
|
body: form,
|
||||||
});
|
});
|
||||||
const data = (await res.json()) as { success: boolean; 'error-codes'?: string[] };
|
const data = (await res.json()) as { success: boolean };
|
||||||
// TEMPORARY DIAGNOSTIC: Cloudflare returns HTTP 200 even on failure, with the
|
|
||||||
// reason in error-codes (e.g. "invalid-input-secret", "invalid-input-response",
|
|
||||||
// "timeout-or-duplicate"). Log it so we can see why verification is failing.
|
|
||||||
// Remove this log once the Turnstile issue is resolved.
|
|
||||||
if (!data.success) {
|
|
||||||
console.warn('[contact] turnstile siteverify failed:', {
|
|
||||||
status: res.status,
|
|
||||||
errorCodes: data['error-codes'] ?? [],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return Boolean(data.success);
|
return Boolean(data.success);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// Network error talking to Cloudflare. Fail closed: reject the submission
|
// Network error talking to Cloudflare. Fail closed: reject the submission
|
||||||
|
|||||||
Reference in New Issue
Block a user