mirror of
https://github.com/prdlk/dotfiles.git
synced 2026-11-08 04:57:36 +00:00
refactor(turnstile-spin): tighten auth handling, expand documentation, and add tldraw-offline matcher
This commit is contained in:
1 parent
20dc5f4489
commit
03ef5c94ea
14 files changed
+1559
-499
No files matched your search
@@ -1,6 +1,6 @@
|
||||
# Hugo
|
||||
|
||||
For Hugo static sites. Use a partial for the widget so it can be referenced from any layout or content file.
|
||||
For Hugo static sites. The widget renders on any page that includes the partial; siteverify happens at whatever backend handles your form submissions (a Cloudflare Pages Function, a Worker, an external API, or a form host with a server-side hook).
|
||||
|
||||
```html title="layouts/partials/turnstile.html"
|
||||
<script
|
||||
@@ -9,12 +9,12 @@ For Hugo static sites. Use a partial for the widget so it can be referenced from
|
||||
defer
|
||||
></script>
|
||||
|
||||
<form action="{{ .Site.Params.turnstileWorkerUrl }}/" method="POST">
|
||||
<form action="{{ .Site.Params.turnstileFormEndpoint }}" method="POST">
|
||||
<input name="email" type="email" required />
|
||||
<div
|
||||
class="cf-turnstile"
|
||||
data-sitekey="{{ .Site.Params.turnstileSitekey }}"
|
||||
data-action="turnstile-spin-v1"
|
||||
data-action="subscribe"
|
||||
></div>
|
||||
<button type="submit">Subscribe</button>
|
||||
</form>
|
||||
@@ -25,7 +25,7 @@ Add the params to your site config:
|
||||
```toml title="hugo.toml"
|
||||
[params]
|
||||
turnstileSitekey = "YOUR_SITEKEY"
|
||||
turnstileWorkerUrl = "https://YOUR_WORKER_URL"
|
||||
turnstileFormEndpoint = "/api/subscribe" # path to your existing form handler
|
||||
```
|
||||
|
||||
Reference the partial from any layout or content file:
|
||||
@@ -34,6 +34,57 @@ Reference the partial from any layout or content file:
|
||||
{{ partial "turnstile.html" . }}
|
||||
```
|
||||
|
||||
## Backend (where siteverify lives)
|
||||
|
||||
Hugo doesn't host server-side code, so the form endpoint must live elsewhere. Two common setups:
|
||||
|
||||
**Cloudflare Pages Function** (`functions/api/subscribe.js`):
|
||||
|
||||
```js
|
||||
export async function onRequestPost({ request, env }) {
|
||||
const form = await request.formData();
|
||||
const token = form.get("cf-turnstile-response");
|
||||
|
||||
const expectedHostnames = new Set(
|
||||
(env.TURNSTILE_HOSTNAMES ?? "")
|
||||
.split(",")
|
||||
.map((h) => h.trim())
|
||||
.filter(Boolean),
|
||||
);
|
||||
if (expectedHostnames.size === 0) {
|
||||
return new Response("forbidden", { status: 403 });
|
||||
}
|
||||
|
||||
const r = await fetch("https://challenges.cloudflare.com/turnstile/v0/siteverify", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
||||
body: new URLSearchParams({
|
||||
secret: env.TURNSTILE_SECRET,
|
||||
response: token,
|
||||
remoteip: request.headers.get("CF-Connecting-IP"),
|
||||
}),
|
||||
});
|
||||
const result = await r.json();
|
||||
if (
|
||||
r.ok !== true ||
|
||||
result.success !== true ||
|
||||
result.action !== "subscribe" ||
|
||||
!expectedHostnames.has(result.hostname)
|
||||
) {
|
||||
return new Response("forbidden", { status: 403 });
|
||||
}
|
||||
|
||||
// process subscribe
|
||||
return new Response("ok");
|
||||
}
|
||||
```
|
||||
|
||||
`subscribe` is the stable action for this surface. Preserve an existing custom migration action and compare the returned action to the same value. Siteverify is mandatory for every widget mode, including pre-clearance. Set `TURNSTILE_HOSTNAMES` to the deployment-specific frontend hostnames; a production value must not include `localhost` or `127.0.0.1`.
|
||||
|
||||
After the user approves a canonical absolute `WRANGLER_BIN` outside the project, set the secret with `(set +x; printf '%s' "$WIDGET_SECRET" | "$WRANGLER_BIN" pages secret put TURNSTILE_SECRET)` (or use the dashboard's Pages → your project → Settings → Environment variables → Add secret).
|
||||
|
||||
**External backend**: any Node/Ruby/Python/Go handler can do the same call. See the [vanilla-html reference](./vanilla-html.md) for non-Cloudflare-specific snippets.
|
||||
|
||||
## Variant: shortcode for content files
|
||||
|
||||
If you want to drop the widget into Markdown content (not just layouts), create a shortcode:
|
||||
@@ -56,7 +107,8 @@ Contact us:
|
||||
|
||||
## Substitutions
|
||||
|
||||
| Placeholder | Replace with |
|
||||
| ------------------ | ------------------------------------------- |
|
||||
| `YOUR_WORKER_URL` | Deployed Worker URL from Step 5 |
|
||||
| `YOUR_SITEKEY` | Widget site key from Step 4 |
|
||||
| Placeholder | Replace with |
|
||||
| ------------------------ | -------------------------------------------------------------------- |
|
||||
| `YOUR_SITEKEY` | The widget site key from Step 8 |
|
||||
| `turnstileFormEndpoint` | The path or URL to your form handler (Pages Function, Worker, etc.) |
|
||||
| `TURNSTILE_SECRET` | Env-var name in your backend. Value is the secret captured in Step 8.|
|
||||
Reference in new issue
Block a user