Files
Infosec/Alert Hub System
2026-09-13 20:09:20 +01:00
..
2026-09-13 20:09:20 +01:00
2026-09-13 20:09:20 +01:00
2026-09-13 20:09:20 +01:00
2026-09-13 20:09:20 +01:00
2026-09-13 20:09:20 +01:00
2026-09-13 20:09:20 +01:00
2026-09-13 20:09:20 +01:00
2026-09-13 20:09:20 +01:00
2026-09-13 20:09:20 +01:00
2026-09-13 20:09:20 +01:00
2026-09-13 20:09:20 +01:00
2026-09-13 20:09:20 +01:00
2026-09-13 20:09:20 +01:00

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

# 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 AccountSet up MFA (scan the QR code with Google Authenticator, Authy, 1Password, etc.). Any user can do this.
  4. (Optional) AccountProfile 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.

# 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

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.