feat: integrazione hCaptcha nel form contatti
- contatti.astro: widget hCaptcha, token incluso nel payload, messaggio di errore se challenge non completata - docs/INFRA.md: documentata configurazione hCaptcha (site key, secret key in appSettings, flusso di verifica) Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -88,3 +88,23 @@ restituiscono la homepage Astro invece del contenuto atteso.
|
||||
| `https://api.smart-roots.net/api/contatti` | POST | Invio form contatti |
|
||||
|
||||
Il controller è in `SmartRootsServices/SRServices/Controllers/SmartRootsSite/ContattiController.cs`.
|
||||
|
||||
Validazioni lato server: campi obbligatori, messaggio minimo 10 caratteri,
|
||||
rate limiting (3 invii/ora per IP), honeypot anti-bot, verifica hCaptcha.
|
||||
|
||||
---
|
||||
|
||||
## hCaptcha
|
||||
|
||||
Il form contatti è protetto da **hCaptcha** (piano gratuito).
|
||||
|
||||
- **Site key** (pubblica, nel frontend): `813a0980-869a-42f4-9a7c-abaae7dccd96`
|
||||
- **Secret key** (privata, solo server): configurata in `<appSettings>` nel `web.config`
|
||||
di SmartRootsServices sul server — **non è in source control**
|
||||
|
||||
```xml
|
||||
<add key="HcaptchaSecret" value="..." />
|
||||
```
|
||||
|
||||
Il controller verifica il token chiamando `https://hcaptcha.com/siteverify` prima
|
||||
di processare il form. Se la verifica fallisce restituisce HTTP 400.
|
||||
|
||||
@@ -10,6 +10,7 @@ import Footer from '../components/Footer.astro';
|
||||
canonical="https://www.smart-roots.net/contatti"
|
||||
noindex={true}
|
||||
>
|
||||
<script slot="head" src="https://js.hcaptcha.com/1/api.js" async defer></script>
|
||||
|
||||
<Nav variant="back" />
|
||||
|
||||
@@ -67,6 +68,8 @@ import Footer from '../components/Footer.astro';
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
<div class="h-captcha" data-sitekey="813a0980-869a-42f4-9a7c-abaae7dccd96" style="margin-bottom:1.5rem"></div>
|
||||
|
||||
<button type="submit" class="btn-submit" id="submit-btn">
|
||||
Invia messaggio
|
||||
</button>
|
||||
@@ -126,12 +129,23 @@ import Footer from '../components/Footer.astro';
|
||||
okMsg.style.display = 'none';
|
||||
errMsg.style.display = 'none';
|
||||
|
||||
const hcaptchaToken = (document.querySelector('[name="h-captcha-response"]') as HTMLInputElement)?.value;
|
||||
if (!hcaptchaToken) {
|
||||
errMsg.innerHTML = errMsgDefault;
|
||||
errMsg.textContent = 'Completa la verifica antispam.';
|
||||
errMsg.style.display = 'block';
|
||||
submitBtn.disabled = false;
|
||||
submitBtn.textContent = 'Invia messaggio';
|
||||
return;
|
||||
}
|
||||
|
||||
const payload = {
|
||||
nome: (document.getElementById('nome') as HTMLInputElement).value.trim(),
|
||||
azienda: (document.getElementById('azienda') as HTMLInputElement).value.trim(),
|
||||
email: (document.getElementById('email') as HTMLInputElement).value.trim(),
|
||||
ambito: (document.getElementById('ambito') as HTMLSelectElement).value,
|
||||
messaggio:(document.getElementById('messaggio') as HTMLTextAreaElement).value.trim(),
|
||||
nome: (document.getElementById('nome') as HTMLInputElement).value.trim(),
|
||||
azienda: (document.getElementById('azienda') as HTMLInputElement).value.trim(),
|
||||
email: (document.getElementById('email') as HTMLInputElement).value.trim(),
|
||||
ambito: (document.getElementById('ambito') as HTMLSelectElement).value,
|
||||
messaggio: (document.getElementById('messaggio') as HTMLTextAreaElement).value.trim(),
|
||||
hcaptchaToken,
|
||||
};
|
||||
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user