# BotGuard — Human Verification & Bot Detection Platform

Production-grade bot detection built on **Core PHP 8.3 (custom MVC)** and **MySQL 8**. BotGuard
inspects a visitor's user-agent, HTTP headers, browser fingerprint, behavior and a challenge, computes
a **0–100 human score** across pluggable weighted modules, classifies the session as **Human /
Suspicious / Bot**, and routes it to a configured destination — with a dashboard, analytics and an
admin panel to tune everything.

> This is the **MVP milestone (Phases 1–4 + auth/dashboard/admin)**. The detection engine, verification
> flow, dashboards and admin are implemented and tested. Follow-on phases (behavioral modules enabled by
> default, remote CAPTCHA widgets, Excel/PDF export, SMTP, installer wizard, standalone license server)
> are noted under [Roadmap](#roadmap).

---

## Highlights

- **Custom MVC framework** — no external framework; Composer only for autoloading + PHPUnit. Also ships a
  fallback PSR-4 autoloader so it runs on hosts without `composer install`.
- **Modular scoring engine** — 14 detection modules, each independently enable/disable-able with a
  configurable weight, combined into a normalized 0–100 score. See [`config/detection.php`](config/detection.php).
- **Self-hosted challenge by default** — a slider puzzle that needs **zero external keys**; reCAPTCHA,
  hCaptcha and Cloudflare Turnstile are pluggable behind one interface.
- **Security by default** — PDO prepared statements everywhere, CSRF on all state-changing routes,
  CSP + security headers, argon2id/bcrypt password hashing, per-IP rate limiting, audit logging.
- **Config-driven** — module weights and score thresholds live in the database and are editable from the
  admin panel with no code changes.
- **Exports & email, zero extra deps** — CSV, native **XLSX** (via `zip`) and a hand-rolled **PDF** report
  engine; a self-contained **SMTP** mailer (STARTTLS/SSL, AUTH LOGIN/PLAIN) with the password encrypted at
  rest (AES-256-GCM).

---

## Requirements

- PHP **8.3+** with `pdo_mysql`, `mbstring`, `json` (and `curl` recommended for remote CAPTCHA)
- MySQL **8.0+**
- Apache / Nginx / LiteSpeed (or `php -S` for local dev). Cloudflare/SSL compatible.

---

## Quick start (XAMPP / Laragon on Windows)

```bash
cd platform
composer install                 # installs dev tooling (PHPUnit); app runs without it too
```

Create an empty database:

```sql
CREATE DATABASE botguard CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
```

Serve it (point your web root at `platform/public`, or for local dev):

```bash
php -S localhost:8000 -t public
```

Then choose **one** of:

**A) Web installer (recommended).** Open the site — an uninstalled instance redirects to **`/install`**.
The wizard walks through License → Requirements → Database → Administrator → Website → Install, writes
`.env`, builds the schema, seeds everything and drops `storage/installed.lock`. No manual `.env` needed.

**B) CLI.** Copy the env file and migrate:

```bash
cp .env.example .env             # edit DB_* + ADMIN_* values
php bin/migrate.php              # creates all tables + seeds admin, modules, thresholds
```

> The installer is sealed off automatically once `storage/installed.lock` exists. Delete that file only
> to reinstall.

Now:

- Visit **`/verify`** — watch the security checks run, solve the slider, and get routed by your score.
- Sign in at **`/login`** with the seeded admin (`ADMIN_EMAIL` / `ADMIN_PASSWORD` from `.env`).
- Open **`/admin/modules`** and **`/admin/thresholds`** to tune scoring; re-run `/verify` to see it change.

### Try the engine without a database

```bash
php bin/simulate.php both        # runs the real engine on a human + bot sample, prints the breakdown
```

Example output: the human sample scores **99/100 → redirect_primary**, the headless-bot sample
**22/100 → block**, with a per-module failed-checks table.

---

## How verification works

```
GET /verify ─► VerifyController issues a session token + challenge, renders the page
   │
   ▼ (assets/js/verify.js collects fingerprint, JS probes, cookies, behavior, solves puzzle)
POST /api/verify ─► VerificationService:
   1. verify challenge (CaptchaProvider)         4. run DetectionEngine over the SignalBag
   2. inject server signals (rate, session, geo) 5. classify (Human/Suspicious/Bot) + action
   3. record fingerprint (repeat-visitor)        6. persist result + per-module detection_logs
   ◄── JSON { score, classification, action, redirect_url, block_message, breakdown }
```

The score is `round( 100 × Σ(moduleScore × weight) / Σ(weight) )`. Each module returns a
human-likelihood in `[0,1]`; a module that throws is neutralised (0.5) so one bad module can never take
down the gate. See [`app/Services/Detection/DetectionEngine.php`](app/Services/Detection/DetectionEngine.php).

---

## Project structure

```
platform/
├── public/               # web root — front controller + assets (only this is exposed)
├── app/
│   ├── Core/             # Kernel, Router, Request/Response, Container(DI), Database(PDO),
│   │                     #   Config, Session, Csrf, Auth, Validator, View, Logger, Cache/
│   ├── Middleware/       # SecurityHeaders, Csrf, Auth, Admin, RateLimit
│   ├── Controllers/      # Web / Api / Auth / User / Admin
│   ├── Models/           # User, VerificationResult/Session, Fingerprint, ModuleConfig, ...
│   ├── Services/
│   │   ├── Detection/    # DetectionEngine, SignalBag, ModuleResult, EngineFactory, Modules/
│   │   ├── Captcha/      # provider interface + Puzzle + Remote (reCAPTCHA/hCaptcha/Turnstile)
│   │   ├── Export/       # CsvExporter
│   │   ├── VerificationService.php, RateTracker.php
│   ├── Views/            # layouts, web (verify/blocked/success), auth, user, admin, partials
│   └── Helpers/          # UserAgentParser, Geo, global functions
├── config/               # app, database, detection, captcha
├── database/             # migrations/*.sql + seeds/DatabaseSeeder.php
├── routes/               # web.php, api.php
├── bin/                  # migrate.php, simulate.php
└── tests/                # PHPUnit (engine + modules)
```

---

## Testing

```bash
composer install
php vendor/phpunit/phpunit/phpunit      # 14 tests: engine classification, per-module, UA parser
```

The tests use deterministic human/bot fixtures ([`tests/Unit/SignalFixtures.php`](tests/Unit/SignalFixtures.php))
and need no database.

---

## Detection modules

| Key | Module | Default weight | Signals |
|-----|--------|:--:|---------|
| `user_agent` | User-Agent analysis | 15 | browser/OS/engine, headless & bot markers |
| `headers` | HTTP header fingerprinting | 15 | Accept*, Sec-CH-UA, Sec-Fetch, consistency |
| `fingerprint` | Browser fingerprinting | 15 | canvas, WebGL, audio, fonts, hardware |
| `honeypot` | Honeypot fields | 15 | hidden decoys, render-to-submit delay |
| `captcha` | Challenge verification | 20 | verified, solve time, retries |
| `rate_limit` | Request velocity | 10 | per second/minute/hour |
| `session` | Session analysis | 10 | integrity, burst, dwell, repeat visitor |
| `javascript` | JS execution | 10 | ES6, async, event loop, `navigator.webdriver` |
| `timing` | Request timing | 10 | time-to-interact / submit / on page |
| `cookies` | Cookie & storage | 5 | cookies, persistence, local/session storage |
| `referrer` | Referrer analysis | 5 | direct/search/social/internal |
| `mouse` | Mouse dynamics | 20 | speed variance, curvature, click jitter |
| `keyboard` | Keyboard behavior | 10 | inter-key variance, paste, corrections |
| `scroll` | Scroll behavior | 10 | speed variance, direction changes, dwell |
| `link_interaction` | Link interaction | 5 | hover dwell, instant-click / double-click patterns |

All 15 modules are **enabled by default**. Behavioral modules stay *neutral* when the relevant
interaction didn't occur (no typing, touch device, short page), so they reward genuine human behaviour
without penalising its absence. Toggle any module or retune its weight in **Admin → Modules**.

---

## Roadmap

- Scheduled log-retention pruning; per-key API scopes/rate-limits
- Standalone **License Server** portal (separate project); the client already activates against it
  (or installs in offline/trial mode) — see [`app/Services/License`](app/Services/License)
- Redis cache driver (interface already in place: [`app/Core/Cache`](app/Core/Cache))

The **installation wizard** is implemented (`/install`) — see [Quick start](#quick-start-xampp--laragon-on-windows).

See [`docs/DEPLOYMENT.md`](docs/DEPLOYMENT.md) for Apache/Nginx/LiteSpeed/Cloudflare configuration and
[`docs/API.md`](docs/API.md) for the verification API contract.
