Files
2026-09-13 19:59:54 +01:00

145 lines
9.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# AlertHub
**Version 1.5 — Martinhal IT (Joao Vaz)**
A Dockerized alert/reminder web application with email notifications, MFA-capable authentication, and role-based access control. Designed for tracking expiration dates (licenses, renewals, certificates, contracts) with live countdown timers and configurable email reminders.
## Features
- **First-run admin setup** — On the very first launch (no accounts yet) you're taken to a "Create administrator" screen to set the admin username & password yourself. No seeded/default admin credentials.
- **Single-port architecture** — Everything runs on one port (`:8080`). The frontoffice (alerts + management) is at the root; the admin backoffice (users, mail, settings, audit log, mail log) is served on the **same port** under `/backoffice` and is restricted to admins.
- **Backoffice shortcut** — Admins get a **Backoffice** link in the top bar (and a **Frontoffice** link back) that switches between the two areas. Only visible to admins.
- **Authentication** — Password (bcrypt, 12 rounds) with optional TOTP MFA. **Any user** can self-enable MFA from *Account → MFA*; it is never mandatory.
- **User avatars** — Any user can upload a profile picture (PNG/JPG/GIF/WebP). Images are auto-squared and resized to 256×256 and stored in the database (survives upgrades). Shown in the top bar.
- **RBAC** — Two roles: `user` (view-only) and `admin` (full access)
- **Live countdown timers** — Per-alert ticking timers (days/hours/minutes/seconds) with state-based color coding (warning, critical, expired)
- **Email reminders** — Configurable SMTP + IMAP editable from the backoffice. Per-alert override of reminder lead times.
- **Mail log** — Every message the platform sends is recorded in the backoffice **Mail Log** (recipients, subject, delivery status, whether the Sent-folder copy was saved, and who triggered it).
- **Sent-folder copy (IMAP)** — After each successful send, a copy of the message is appended to the mailbox's **Sent** folder over IMAP, so it appears in your normal mail client.
- **Log export & email** — Both the Audit log and Mail log can be exported to CSV or emailed (as a CSV attachment) to any destination address.
- **Account security** — Lockout after 5 failed attempts (15-minute window), audit log of sensitive actions, security headers (CSP, X-Frame-Options, HSTS-ready)
- **IT-terminal aesthetic** — JetBrains Mono + IBM Plex Sans, signal-green accents, light + dark mode (auto-detect + manual toggle)
- **Consistent footer** — `© 2026 Martinhal IT - Joao Vaz - Version 1.5` on every page except the login screen.
- **Hardened container** — Non-root user, all capabilities dropped, `no-new-privileges`, healthcheck
## Stack
Python 3.13 · Flask 3.1 · SQLAlchemy 2 · Flask-Login · Flask-WTF · APScheduler · pyotp · bcrypt · gunicorn · SQLite
## Quick start
```bash
# 1. Get the code, then:
cp .env.example .env
# 2. Edit .env — at minimum, change:
# - SECRET_KEY (use: python -c "import secrets; print(secrets.token_hex(32))")
# - SMTP_* / IMAP_* (your Purelymail credentials)
# 3. Build and start:
docker compose up -d --build
# 4. Open:
# App: http://localhost:8080
# Backoffice: http://localhost:8080/backoffice (admins only)
# 5. First visit → you'll be sent to the "Create administrator" screen.
# Set the admin username, email, and password there.
```
### First-run checklist
1. Open the app — you'll land on **Create administrator**. Set the admin username, email and password.
2. Sign in with the credentials you just created.
3. (Optional) Go to **Account****Set up MFA** (scan the QR code with Google Authenticator, Authy, 1Password, etc.). Any user can do this.
4. (Optional) **Account****Profile avatar** → upload a picture.
5. Open the backoffice → **Mail** → confirm the Purelymail SMTP/IMAP settings, fill in the mailbox username/password, and send a test email. Check the **Mail Log** to confirm it sent and that a copy was saved to the mailbox's Sent folder.
6. Backoffice → **Settings** → set the default reminder lead times (e.g. `30,14,7,1` days before expiry).
7. Frontoffice → **Manage Alerts** → add your first alert.
## Configuration
All configuration lives in `.env`. The `docker-compose.yml` only references the file via `env_file` — no secrets are baked into the image or compose file.
| Variable | Purpose |
|---|---|
| `SECRET_KEY` | Flask session signing key (required, generate a new one) |
| `FRONTOFFICE_PORT` | The single host port (default 8080). `BACKOFFICE_PORT` is no longer used. |
| `GUNICORN_WORKERS` / `GUNICORN_THREADS` | Web server sizing. Keep workers at 1 so the reminder scheduler runs once (default 1 worker / 4 threads). |
| `DATABASE_PATH` | SQLite path inside the container (default `/data/alerthub.db`) |
| `SESSION_LIFETIME_HOURS` | Login session length |
| `MAX_LOGIN_ATTEMPTS` / `LOCKOUT_MINUTES` | Brute-force protection |
| `SCHEDULER_INTERVAL_MINUTES` | How often the reminder job runs (default 60) |
| `SMTP_HOST` / `SMTP_PORT` / `SMTP_USERNAME` / `SMTP_PASSWORD` / `SMTP_ENCRYPTION` / `SMTP_FROM_ADDRESS` / `SMTP_FROM_NAME` | Initial outgoing-mail config (Purelymail defaults; seeded into DB on first run; admins edit live values via backoffice afterwards) |
| `IMAP_HOST` / `IMAP_PORT` / `IMAP_USERNAME` / `IMAP_PASSWORD` / `IMAP_SENT_FOLDER` | IMAP settings for saving a copy of sent mail to the Sent folder (Purelymail defaults). Leave user/pass blank to reuse the SMTP credentials. |
| `DEFAULT_REMINDER_DAYS` | Default reminder thresholds, comma-separated (e.g. `30,14,7,1`) |
> **Admin account:** There is no seeded admin. The first launch presents a one-time **Create administrator** screen. The old `INITIAL_ADMIN_*` variables are no longer used.
> **Note:** `SMTP_*` / `IMAP_*` values seed the database on first launch. After that, the backoffice **Mail** page is the source of truth — edits there persist independently of `.env`.
### Purelymail mail settings
Defaults ship pre-configured for Purelymail:
- **Outgoing (SMTP):** `smtp.purelymail.com`, port **465**, SSL/TLS. (If your client only supports STARTTLS, use port **587** with `SMTP_ENCRYPTION=starttls`.)
- **Incoming (IMAP):** `imap.purelymail.com`, port **993**, SSL/TLS — used to append sent messages to the **Sent** folder.
Just fill in your mailbox username and password (in `.env` or the backoffice **Mail** page).
## Upgrading in place (no data loss)
This build is designed to be **unzipped over the previous version**. On startup the app runs additive migrations: it creates any new tables (e.g. the mail log) and adds any new columns (avatars) to the existing SQLite database in the `/data` volume, without touching your existing users, alerts, settings, or audit history.
```bash
# from the folder containing your existing docker-compose.yml / .env / app:
unzip -o alerthub.zip # overwrite code in place (keeps .env and the /data volume)
docker compose up -d --build # rebuild & restart; migrations run automatically
```
Your customised SMTP settings are preserved on upgrade; the new IMAP keys are seeded with the Purelymail defaults (adjust them in the backoffice **Mail** page).
## Architecture
```
┌──────────── Docker container ────────────┐
│ │
│ entrypoint.sh │
│ └── gunicorn wsgi:application :8080 │
│ ├── frontoffice (/) │
│ ├── backoffice (/backoffice) │
│ └── scheduler (APScheduler) │
│ │
│ /data/alerthub.db (named volume) │
└──────────────────────────────────────────┘
```
Both processes share the same SQLite database (mounted as a Docker named volume). The reminder scheduler runs only inside the frontoffice process to avoid duplicate emails.
## Security notes
- Passwords stored as bcrypt hashes (cost 12).
- TOTP secrets stored encrypted at rest is NOT implemented — the secret is stored as-is. If your threat model requires it, mount the DB on an encrypted volume.
- CSP is strict (no inline scripts except the early theme bootstrap which is `nonce`-able if you tighten further).
- Container runs as uid `10001`, drops all Linux capabilities, and uses `no-new-privileges`.
- Brute-force lockout is per-username, not per-IP.
## Operational tips
- **Trigger a reminder check manually:** Backoffice → Settings → "Run check now".
- **Reset a user's MFA:** Backoffice → Users → row menu → Reset MFA.
- **Unlock a locked-out user:** Backoffice → Users → row menu → Unlock.
- **Inspect activity:** Backoffice → Audit log (paginated).
- **Reset reminder history for an alert** (e.g. after extending the date): Manage Alerts → row → Reset reminders.
## Uninstall / data reset
```bash
docker compose down # stop containers, keep data
docker compose down -v # also remove the alerthub_data volume (deletes DB)
```
## License
Provided as-is for internal use. No warranty.