mirror of
https://github.com/yusing/godoxy.git
synced 2026-01-16 07:06:51 +01:00
Captcha Middleware
CAPTCHA verification middleware package providing session-based captcha challenge and verification.
Overview
This package implements CAPTCHA verification middleware that protects routes by requiring users to complete a CAPTCHA challenge before accessing the protected resource. It supports pluggable providers (currently hCAPTCHA) and uses encrypted sessions for verification state.
Architecture
graph TD
A[Client Request] --> B{Captcha Session?}
B -->|Valid| C[Proceed to Backend]
B -->|Invalid| D[Show CAPTCHA Page]
D --> E{POST with Token?}
E -->|Valid| F[Create Session<br/>Set Cookie]
E -->|Invalid| G[Show Error]
F --> C
subgraph Captcha Provider
H[hCAPTCHA API]
D -->|Script/Form HTML| H
F -->|Verify Token| H
end
subgraph Session Store
I[CaptchaSessions<br/>jsonstore]
end
F --> I
I -.->|Session Check| B
Captcha Flow
sequenceDiagram
participant C as Client
participant M as Middleware
participant P as Provider
participant S as Session Store
participant B as Backend
C->>M: Request (no session)
M->>M: Check cookie
M->>M: Session not found/expired
M->>C: Send CAPTCHA Page
C->>M: POST with captcha response
M->>P: Verify token
P-->>M: Verification result
alt Verification successful
M->>S: Store session
M->>C: Set session cookie<br/>Redirect to protected path
C->>M: Request (with session cookie)
M->>S: Validate session
M->>B: Forward request
else Verification failed
M->>C: Error: verification failed
end
Core Components
Provider Interface
type Provider interface {
// CSP directives for the captcha provider
CSPDirectives() []string
// CSP sources for the captcha provider
CSPSources() []string
// Verify the captcha response from the request
Verify(r *http.Request) error
// Session expiry duration after successful verification
SessionExpiry() time.Duration
// Script HTML to include in the page
ScriptHTML() string
// Form HTML to render the captcha widget
FormHTML() string
}
ProviderBase
type ProviderBase struct {
Expiry time.Duration `json:"session_expiry"` // Default: 24 hours
}
func (p *ProviderBase) SessionExpiry() time.Duration
hCAPTCHA Provider
type HcaptchaProvider struct {
ProviderBase
SiteKey string `json:"site_key" validate:"required"`
Secret string `json:"secret" validate:"required"`
}
// CSP Directives: script-src, frame-src, style-src, connect-src
// CSP Sources: https://hcaptcha.com, https://*.hcaptcha.com
Captcha Session
type CaptchaSession struct {
ID string `json:"id"`
Expiry time.Time `json:"expiry"`
}
var CaptchaSessions = jsonstore.Store[*CaptchaSession]("captcha_sessions")
func newCaptchaSession(p Provider) *CaptchaSession
func (s *CaptchaSession) expired() bool
Middleware Integration
type hCaptcha struct {
captcha.HcaptchaProvider
}
func (h *hCaptcha) before(w http.ResponseWriter, r *http.Request) bool {
return captcha.PreRequest(h, w, r)
}
var HCaptcha = NewMiddleware[hCaptcha]()
PreRequest Handler
func PreRequest(p Provider, w http.ResponseWriter, r *http.Request) (proceed bool)
This function:
- Checks for valid session cookie
- Validates session expiry
- Returns true if session is valid
- For non-HTML requests, returns 403 Forbidden
- For POST requests, verifies the captcha token
- For GET requests, renders the CAPTCHA challenge page
Configuration
hCAPTCHA Configuration
middleware:
my-captcha:
use: hcaptcha
site_key: "YOUR_SITE_KEY"
secret: "YOUR_SECRET"
session_expiry: 24h # optional, default 24h
Route Configuration
routes:
- host: example.com
path: /admin
middlewares:
- my-captcha
Usage Examples
Basic Setup
import "github.com/yusing/godoxy/internal/net/gphttp/middleware"
hcaptchaMiddleware := middleware.HCaptcha.New(middleware.OptionsRaw{
"site_key": "your-site-key",
"secret": "your-secret",
})
Using in Middleware Chain
# config/middlewares/admin-protection.yml
- use: captcha
site_key: "${HCAPTCHA_SITE_KEY}"
secret: "${HCAPTCHA_SECRET}"
bypass:
- type: CIDR
value: 10.0.0.0/8
Session Management
Sessions are stored in a JSON-based store with the following properties:
- Session ID: 32-byte CRNG (
crypto/rand.Read) random hex string - Expiry: Configurable duration (default 24 hours)
- Cookie:
godoxy_captcha_sessionwith HttpOnly flag
flowchart TD
A[Session Created] --> B[Cookie Set]
B --> C[Client Sends Cookie]
C --> D{Session Valid?}
D -->|Yes| E[Proceed]
D -->|No| F{HTML Request?}
F -->|Yes| G[Show CAPTCHA]
F -->|No| H[403 Forbidden]
CSP Integration
The CAPTCHA provider supplies CSP directives that should be added to the response:
// hCAPTCHA CSP Directives
CSPDirectives() []string
// Returns: ["script-src", "frame-src", "style-src", "connect-src"]
CSPSources() []string
// Returns: ["https://hcaptcha.com", "https://*.hcaptcha.com"]
HTML Template
The package includes an embedded HTML template (captcha.html) that renders the CAPTCHA challenge page with:
- Provider script (
<script src="https://js.hcaptcha.com/1/api.js">) - Provider form (
<div class="h-captcha" data-sitekey="...">) - Auto-submit callback on successful verification
Security Considerations
- Session Cookie: Uses HttpOnly flag to prevent JavaScript access
- Token Verification: Tokens are verified server-side with the CAPTCHA provider
- Remote IP: Client IP is included in verification request to prevent token reuse
- Session Expiry: Sessions expire after configurable duration
- Non-HTML Fallback: Non-HTML requests receive 403 without challenge page
Error Handling
var ErrCaptchaVerificationFailed = gperr.New("captcha verification failed")
// Verification errors are logged with request details
log.Warn().Err(err).Str("url", r.URL.String()).Str("remote_addr", r.RemoteAddr).Msg("failed to verify captcha")
Integration with GoDoxy
The captcha middleware integrates with GoDoxy's:
- Authentication: Sessions are managed via
auth.SetTokenCookie - Session Store: Uses
jsonstorefor persistent session storage - Middleware Framework: Implements
RequestModifierinterface