ZKRINET Docs
Byggblock

Formulär

På Zkrinet: lägg till blocket under Byggblock i panelen — ett klick, din egen kod rörs inte och en ögonblicksbild tas först. Installationsstegen nedan gäller om du kör PocketBase själv, till exempel efter en export.

Kontakt- och leadformulär för landningssidor. Besökaren skickar utan att logga in, inlämningen sparas i databasen och mejlas till dig. Med botskydd (honungsfält + minsta ifyllnadstid alltid på, captcha valbart), rate limit per IP och skydd mot öppen redirect.

Kräver Mejl-pluginet. Testat mot PocketBase 0.40.4.

Installation

  1. Installera Mejl först (och ställ in SMTP), kopiera sedan pb_hooks/ och pb_migrations/ till din PocketBase och starta om.
  2. Skapa ett formulär i zk_formular i adminpanelen:
Fält
namnAnvänds i adressen: kontakt → /api/zk/formular/kontakt (a–z, 0–9, -, _)
rubrikVisas i mejlet till dig, t.ex. "Offertförfrågan"
faltVilka fält formuläret har (se nedan)
mottagareVart inlämningarna mejlas
aktivAv = formuläret svarar 404
tack_urlValfri. Dit vanliga formulär skickas efter inlämning. Måste ligga på appens adress eller i tillatna_adresser.
captchaingen, friendly, turnstile eller hcaptcha
kvittoSkicka ett kort "tack, vi har fått ditt meddelande" till avsändaren (första fältet av typen epost)
max_per_timmeInlämningar per IP och timme. Tomt = 10

falt är en JSON-lista:

[
  { "namn": "namn",       "etikett": "Namn",       "typ": "text",  "obligatorisk": true, "max": 100 },
  { "namn": "epost",      "etikett": "E-post",     "typ": "epost", "obligatorisk": true },
  { "namn": "telefon",    "etikett": "Telefon",    "typ": "text" },
  { "namn": "meddelande", "etikett": "Meddelande", "typ": "lang",  "obligatorisk": true, "max": 2000 }
]

Typer: text (en rad), lang (flera rader), epost. max är antal tecken (standard 200 / 5000 / 254, högst 20 000). Högst 30 fält. Fältnamn får inte börja med zk_. Schemat kontrolleras när du sparar formuläret. Fält som inte står i schemat sparas aldrig, oavsett vad som skickas.

  1. Inställningar: zk_formular_installningar har redan en rad. Där finns captcha-nycklarna (se nedan), tillatna_adresser (kommaseparerade adresser för din landningssida om den ligger på en annan domän än PocketBase, t.ex. https://min-sajt.se, https://www.min-sajt.se), minsta_sekunder (standard 3) och hemlighet (skapas automatiskt — rör den inte).
  1. Ligger PocketBase bakom en proxy (Cloudflare, nginx, Caddy)? Ställ in Settings → Trusted proxy så att PocketBase ser besökarens riktiga IP. Annars delar alla besökare proxyns IP — och därmed samma gräns per timme.

Användning

Varje formulär behöver en färsk starttid (zk_start) från servern. Den bevisar hur länge formuläret varit öppet; robotar som skickar direkt nekas.

Med JavaScript (fetch)

const PB = "https://din-pb.se"
const f = await fetch(`${PB}/api/zk/formular/kontakt`).then(r => r.json())
// f = { namn, rubrik, falt: [...], captcha: "friendly", sitekey: "…", start: "1762…", honungsfalt: "zk_webbplats" }

const r = await fetch(`${PB}/api/zk/formular/kontakt`, {
  method: "POST", headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ namn: "Anna", epost: "anna@exempel.se", meddelande: "Hej!",
                         zk_start: f.start, zk_webbplats: "",
                         "frc-captcha-response": tokenFranWidgeten }),
})
// 200 { ok: true } · 400 { fel, falt: { epost: "ogiltig e-postadress" } } · 404 · 429 · 503

Vanligt HTML-formulär

<form id="kontakt" method="post" action="https://din-pb.se/api/zk/formular/kontakt">
  <input name="namn" required>
  <input name="epost" type="email" required>
  <textarea name="meddelande" required></textarea>
  <!-- Honungsfält: ska vara tomt. Göm med CSS, INTE type="hidden" (det hoppar robotar över). -->
  <div style="position:absolute;left:-9999px" aria-hidden="true">
    <label>Lämna tomt <input name="zk_webbplats" tabindex="-1" autocomplete="off"></label>
  </div>
  <input type="hidden" name="zk_start">
  <input type="hidden" name="zk_tack" value="https://min-sajt.se/tack">  <!-- valfri, måste vara vitlistad -->
  <button>Skicka</button>
</form>
<script>
  fetch("https://din-pb.se/api/zk/formular/kontakt").then(r => r.json())
    .then(f => { document.querySelector("#kontakt [name=zk_start]").value = f.start })
</script>

Efter inlämning skickas besökaren (303) till zk_tack eller formulärets tack_url. Finns ingen visas en enkel tack-sida. Fel visas som en enkel felsida.

Både application/x-www-form-urlencoded och multipart/form-data fungerar. Värden sparas exakt som de skrevs (0701… behåller nollan).

Captcha

Välj per formulär. Nyckeln sparas i ett dolt fält i zk_formular_installningar eller som miljövariabel (miljön vinner):

LeverantörInställningMiljövariabelWidgetens fält
Friendly Captcha (Tyskland, EU — förstahandsval)friendly_api_nyckel (dold), friendly_sitekey, friendly_euZK_FORMULAR_FRIENDLY_NYCKELfrc-captcha-response
Cloudflare Turnstileturnstile_hemlig (dold)ZK_FORMULAR_TURNSTILE_HEMLIGcf-turnstile-response
hCaptchahcaptcha_hemlig (dold), hcaptcha_sitekeyZK_FORMULAR_HCAPTCHA_HEMLIGh-captcha-response

Widgeten lägger själv in sitt fält i formuläret. Med fetch kan du också skicka token som zk_captcha.

Säkerhet

Begränsningar

Testa

./bank.py formular

21 tester. Captcha testas mot en låtsas-leverantör (ZK_FORMULAR_FRIENDLY_URL, ZK_FORMULAR_TURNSTILE_URL, ZK_FORMULAR_HCAPTCHA_URL pekar om verify-adressen; ZK_FORMULAR_CAPTCHA_TIMEOUT sänker timeouten) — inget når internet. Godkänd, underkänd, timeout och serverfel testas för Friendly Captcha och Turnstile, godkänd/underkänd för hCaptcha. Mot de riktiga leverantörerna är pluginet inte provkört. Säkerhetstesterna är mutantverifierade: varje skydd har brutits med flit och fångats av ett test.