A demo project with:
- a protected product website
- a standalone captcha service
- configurable captcha UI settings
- extensible question banks for text, image, and custom challenges
The current demo includes a virtual product homepage and product detail page, while every protected visit is gated by the captcha service first.
- Two independent backend services
- App service:
http://127.0.0.1:4174 - Captcha service:
http://127.0.0.1:4175
- App service:
- Protected routes
//goods/data/goods
- Every direct visit to a protected page redirects to the captcha service
- Successful verification returns the user to the original page with a one-time ticket
- Failed verification retries automatically
- Lockout after 5 failures with a 5-minute cooldown
- UI setting panel for:
- theme color
- language
- captcha mode
- Captcha modes
- letter selection
- image selection
- custom challenges
- Supports:
- single-select questions
- multi-select questions
- up to 9 grid items per question
server/
app-service.js
captcha-service.js
index.js
shared/
captcha-store.js
html.js
question-bank.js
The app service renders the protected product pages.
GET /GET /goodsGET /data/goods
When a user visits one of these pages directly, the request is redirected to the captcha service unless a valid one-time captcha ticket is present.
The captcha service renders the captcha page and verifies answers.
GET /challengePOST /verify
It also manages:
- challenge generation
- refresh behavior
- single-select and multi-select validation
- failure counting
- cooldown lock state
The question bank lives in:
- server/shared/question-bank.js
Questions are grouped by mode:
const QUESTION_BANK = {
letter: [],
image: [],
custom: [],
};Each question uses this format:
{
id: "unique-id",
selectionMode: "single" | "multiple",
prompt: {
en: "English prompt",
zh: "Chinese prompt"
},
answers: ["correct-value-1", "correct-value-2"],
choices: [
{
value: "option-value",
label: "display text or localized object",
hint: {
en: "Choice 1",
zh: "候选 1"
},
kind: "text" | "image" | "custom",
image: "optional image url or data url"
}
]
}Rules:
idmust be uniqueselectionModemust besingleormultipleanswersmust be an arraychoicescan contain at most 9 items- every answer must exist in
choices[].value
Install dependencies:
cd D:\Project\CapthaDemo
cmd /c npm installStart the services:
node server/index.jsThen open:
- The captcha page is rendered by the backend directly
- The product pages are plain server-rendered pages
- Refreshing a protected business page will trigger captcha again because the ticket is one-time use
- The refresh button on the captcha page forces a new challenge in the current mode
- move question banks into standalone JSON files
- add an admin editing interface for challenge management
- add image assets from a real media folder instead of inline SVG data URLs
- persist sessions in Redis or a database instead of in-memory Maps