88
99
1010from django import forms
11+ from django .forms .widgets import HiddenInput
1112from django .http import JsonResponse
1213from django .utils .translation import gettext_lazy as _
1314from django .views .decorators .http import require_GET
1617import altcha
1718from altcha import ChallengeOptions
1819from altcha import create_challenge
19- from django .forms .widgets import HiddenInput
2020
2121ALTCHA_HMAC_KEY = "your-altcha-hmac-key"
2222
2323
2424class AltchaWidget (HiddenInput ):
2525 template_name = "widgets/altcha.html"
26+ default_options = {
27+ # Required: URL of your server to fetch the challenge from.
28+ "challengeurl" : None ,
29+ # Required: JSON-encoded challenge data
30+ # (use instead of challengeurl to avoid HTTP request).
31+ "challengejson" : None ,
32+ # Automatically verify without user interaction.
33+ # Possible values: "off", "onfocus", "onload", "onsubmit".
34+ "auto" : None ,
35+ # Artificial delay before verification (in milliseconds, default: 0).
36+ "delay" : None ,
37+ # Challenge expiration duration (in milliseconds).
38+ "expire" : None ,
39+ # Enable floating UI.
40+ # Possible values: "auto", "top", "bottom".
41+ "floating" : None ,
42+ # CSS selector of the “anchor” to which the floating UI is attached.
43+ # Default: submit button in the related form.
44+ "floatinganchor" : None ,
45+ # Y offset from the anchor element for the floating UI (in pixels, default: 12).
46+ "floatingoffset" : None ,
47+ # Hide the footer (ALTCHA link).
48+ "hidefooter" : None ,
49+ # Hide the ALTCHA logo.
50+ "hidelogo" : None ,
51+ # Max number to iterate to (default: 1,000,000).
52+ "maxnumber" : None ,
53+ # JSON-encoded translation strings for customization.
54+ "strings" : None ,
55+ # Automatically re-fetch and re-validate when the challenge expires
56+ # (default: true).
57+ "refetchonexpire" : None ,
58+ # Number of workers for Proof of Work (PoW).
59+ # Default: navigator.hardwareConcurrency or 8 (max value: 16).
60+ "workers" : None ,
61+ # URL of the Worker script (default: ./worker.js, only for external builds).
62+ "workerurl" : None ,
63+ # Print log messages in the console (for debugging).
64+ "debug" : None ,
65+ # Causes verification to always fail with a "mock" error.
66+ "mockerror" : None ,
67+ # Generates a “mock” challenge within the widget, bypassing the request to
68+ # challengeurl.
69+ "test" : None ,
70+ }
2671
27- def __init__ (self , challengeurl = None , floating = False , attrs = None ):
28- super ().__init__ (attrs )
29- self .challengeurl = challengeurl
30- self .floating = floating
72+ def __init__ (self , ** kwargs ):
73+ """Initialize the ALTCHA widget with configurable options."""
74+ super ().__init__ ()
75+ self .options = {
76+ key : kwargs .get (key , self .default_options [key ]) for key in self .default_options
77+ }
3178
3279 def get_context (self , name , value , attrs ):
3380 context = super ().get_context (name , value , attrs )
34- context ["widget" ]["challengeurl" ] = self .challengeurl
35- context ["widget" ]["floating" ] = self .floating
81+ context ["widget" ]["altcha_options" ] = self .options # Pass options to template
3682 return context
3783
3884
@@ -44,8 +90,9 @@ class AltchaField(forms.Field):
4490 "required" : _ ("Altcha CAPTCHA token is missing." ),
4591 }
4692
47- def __init__ (self , challengeurl = None , floating = False , * args , ** kwargs ):
48- kwargs ["widget" ] = AltchaWidget (challengeurl = challengeurl , floating = floating )
93+ def __init__ (self , * args , ** kwargs ):
94+ widget_options = {key : kwargs .pop (key , None ) for key in AltchaWidget .default_options }
95+ kwargs ["widget" ] = AltchaWidget (** widget_options )
4996 super ().__init__ (* args , ** kwargs )
5097
5198 def validate (self , value ):
0 commit comments