# 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
```mermaid
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
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
jsonstore]
end
F --> I
I -.->|Session Check| B
```
## Captcha Flow
```mermaid
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
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
```go
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
```go
type ProviderBase struct {
Expiry time.Duration `json:"session_expiry"` // Default: 24 hours
}
func (p *ProviderBase) SessionExpiry() time.Duration
```
### hCAPTCHA Provider
```go
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
```go
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
```go
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
```go
func PreRequest(p Provider, w http.ResponseWriter, r *http.Request) (proceed bool)
```
This function:
1. Checks for valid session cookie
1. Validates session expiry
1. Returns true if session is valid
1. For non-HTML requests, returns 403 Forbidden
1. For POST requests, verifies the captcha token
1. For GET requests, renders the CAPTCHA challenge page
## Configuration
### hCAPTCHA Configuration
```yaml
middleware:
my-captcha:
use: hcaptcha
site_key: "YOUR_SITE_KEY"
secret: "YOUR_SECRET"
session_expiry: 24h # optional, default 24h
```
### Route Configuration
```yaml
routes:
- host: example.com
path: /admin
middlewares:
- my-captcha
```
## Usage Examples
### Basic Setup
```go
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
```yaml
# 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_session` with HttpOnly flag
```mermaid
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:
```go
// 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 (`