Add initial hCaptcha integration

This commit is contained in:
Yannik Rödel 2022-10-12 18:01:21 +02:00
parent 45ab77d754
commit c1c598d3b1
2 changed files with 23 additions and 11 deletions

View file

@ -4,6 +4,7 @@ import base64
import io
import cgi
import collections
from collections.abc import Mapping
import hmac
import mimetypes
import os
@ -31,6 +32,7 @@ CAPTCHA_FIELD_VALUE = "Main"
SITE_DIRECTORY = os.environ.get("SITE_DIRECTORY", "")
request_uri = os.environ.get("REQUEST_URI", "").lower().rstrip("/")
serializer = itsdangerous.URLSafeSerializer("secret key", "salt")
session = requests.Session()
cookies = dict[str, str]()
for entry in os.environ.get("HTTP_COOKIE", "").split(";"):
@ -73,25 +75,24 @@ match os.environ.get("REQUEST_METHOD", "").upper():
# a) only one form on the site and
# b) the <form> tag doesn't end on the same line.
if "</form" in line.lower():
print(
f'<input type="hidden" name="csrftoken" value="{csrf_token}" />')
print(f'<input type="hidden" name="csrftoken" value="{csrf_token}" />')
print(f'<label class="form-input">')
print(f'<span>{CAPTCHA_FIELD_QUESTION}</span>')
print(
f'<input type="text" name="{CAPTCHA_FIELD_NAME}" value="" placeholder="Gebe hier \'{CAPTCHA_FIELD_VALUE}\' ein." autocomplete="off" />')
print(f'<input type="text" name="{CAPTCHA_FIELD_NAME}" value="" placeholder="Gebe hier \'{CAPTCHA_FIELD_VALUE}\' ein." autocomplete="off" />')
print(f'</label>')
print(f'<label class="form-input">')
print(f'<span>Bitte lasse dieses Feld leer:</span>')
print(
f'<input type="text" name="{HONEYPOT_FIELD_NAME}" value="" placeholder="Hier nichts eingeben." tabindex="-1" autocomplete="off" />')
print(f'<input type="text" name="{HONEYPOT_FIELD_NAME}" value="" placeholder="Hier nichts eingeben." tabindex="-1" autocomplete="off" />')
print(f'</label>')
print(f'<script type="text/javascript">')
print(
f'document.querySelector("input[name={HONEYPOT_FIELD_NAME}]").parentNode.classList.add("isolated")')
print(f'document.querySelector("input[name={HONEYPOT_FIELD_NAME}]").parentNode.classList.add("isolated")')
print(f'</script>')
print('<script src="https://js.hcaptcha.com/1/api.js" async defer></script>')
print(f'<div class="h-captcha" data-sitekey="{os.environ.get("HCAPTCHA_SITE_KEY", "")}></div>')
print(line)
exit(0)
@ -156,6 +157,16 @@ if (
):
fail("200 OK", f"Invalid value for field: {CAPTCHA_FIELD_NAME}")
if not (hcaptcha_token := get_form_value("h-captcha-response", "")):
fail("200 OK", "Empty hCaptcha token")
response = session.post("https://hcaptcha.com/siteverify", data={
"secret": os.environ.get("HCAPTCHA_SECRET_KEY", ""),
"response": hcaptcha_token,
})
hcaptcha_data = response.json()
if not isinstance(hcaptcha_data, Mapping) or not hcaptcha_data.get("success", False):
fail("200 OK", "hCaptcha fail")
# Extract all the actually provided form data. This is different from form to
# form (see the match block below).
contact_name = get_form_value("contactname")
@ -228,7 +239,6 @@ form_group = os.environ.get("ZAMMAD_GROUP", "") or form_group
ZAMMAD_URL = os.environ.get("ZAMMAD_URL", "").rstrip("/")
ZAMMAD_TOKEN = os.environ.get("ZAMMAD_TOKEN", "")
session = requests.Session()
session.headers.update(Authorization=f"Token token={ZAMMAD_TOKEN}")
try:

View file

@ -11,7 +11,7 @@ server.document-root = "@site@"
index-file.names = ( "index.html" )
setenv.set-response-header += (
"Content-Security-Policy" => "default-src 'self'; script-src 'self' 'unsafe-inline'; frame-ancestors 'none'",
"Content-Security-Policy" => "default-src 'self'; script-src 'self' 'unsafe-inline' https://hcaptcha.com https://*.hcaptcha.com; frame-src 'self' https://hcaptcha.com https://*.hcaptcha.com; style-src 'self' https://hcaptcha.com, https://*.hcaptcha.com; connect-src 'self' https://hcaptcha.com https://*.hcaptcha.com; frame-ancestors 'none'",
)
url.redirect = (
@ -61,6 +61,8 @@ $HTTP["url"] =~ "^/cgi-bin/" {
"SITE_DIRECTORY" => "@site@",
"ZAMMAD_URL" => env.ZAMMAD_URL,
"ZAMMAD_TOKEN" => env.ZAMMAD_TOKEN,
"ZAMMAD_GROUP" => env.ZAMMAD_GROUP
"ZAMMAD_GROUP" => env.ZAMMAD_GROUP,
"HCAPTCHA_SITE_KEY" => env.HCAPTCHA_SITE_KEY,
"HCAPTCHA_SECRET_KEY" => env.HCAPTCHA_SECRET_KEY,
)
}