Masterplan Optimiser

Security & Integrity

Masterplan Optimiser uses a multi-layered approach to protect both the desktop application and the server-hosted web application. This page describes every mechanism in place, organised by deployment type and then by concern: authenticity, integrity, privacy, and security.

Desktop Application

The desktop application runs locally on your machine and bundles a backend service (which includes the optimisation engine) and a frontend UI. The protections below ensure the software is genuine, untampered, and that local data and credentials stay safe across normal app updates.

Authenticity

Every official release on GitHub includes a checksums.txt file containing the SHA-256 hashes of all installer files. You can verify that your downloaded installer matches the official build before running it.

How to verify

Download the installer and the checksums.txt file from the same GitHub Release. Then compute the hash of the downloaded file and compare it to the value in checksums.txt.

Windows (PowerShell)

certutil -hashfile "Masterplan-Optimiser-Setup-3.x.x.exe" SHA256

macOS

shasum -a 256 Masterplan-Optimiser-3.x.x.dmg

Linux

sha256sum Masterplan-Optimiser-3.x.x.AppImage

Compare the output hash to the corresponding line in checksums.txt. If they match, the file is authentic and has not been altered during download.

Integrity

Two independent mechanisms verify that the installed application has not been tampered with after release.

ASAR Integrity (Automatic)

The Electron application shell is packaged into an ASAR archive. During the build process, electron-builder computes block-level SHA-256 hashes of this archive and embeds them directly into the Electron binary. When the application starts, Electron's native code verifies every block before executing any JavaScript. If the archive has been modified, the application will refuse to start.

Signed Hash Manifest (Ed25519)

During CI/CD, SHA-256 hashes are computed for every critical bundled file - the backend service, the frontend bundle, and the ASAR archive itself. These hashes are collected into a manifest file, which is cryptographically signed using an Ed25519 private key held exclusively in the build environment.

The matching public key is embedded in the application. On every packaged startup, the application opens a compact startup window first and shows the integrity check as part of the visible loading sequence. Backend and frontend services are not started until the check has passed. If bundled files or the manifest signature do not verify, a warning dialogue is shown and the user must either quit or explicitly choose to continue anyway.

In development mode, the same startup screen marks the integrity step as skipped because local files are expected to change while developing. In packaged builds, the integrity step is always shown before Backend and Interface startup steps.

You can also verify integrity on demand at any time:

  1. Open the About dialogue (click the Info icon in the top-right corner of the application).
  2. Click the Verify button next to the Integrity row.
  3. A green shield icon indicates all files are intact. A red shield indicates one or more files have been modified, with details listed below.

Privacy

Persistent desktop data is stored in Electron's stable per-user data directory, not inside the application bundle. This means normal reinstalling or updating of the desktop app replaces application files only; existing projects, settings, the SQLite database, and the local encryption key remain in the user-data directory. This guarantee applies when the database schema is unchanged.

Long-lived credential values are stored in the operating system's secure credential store, such as Windows Credential Manager, macOS Keychain, or the Linux Secret Service. The secure store contains only the secret value itself: Google OAuth access tokens, Google OAuth refresh tokens, MP-Backend publish secrets, and comparable API tokens. Non-sensitive metadata such as server URLs, calendar IDs, account emails, connection status, and event data remains in the normal local database.

The app never stores JSON configuration blobs in the secure credential store. Existing legacy database secrets are migrated to secure storage only after the secure write succeeds; otherwise they are left untouched and credential-dependent actions are blocked with a clear error.

The local database still uses Fernet encryption for remaining sensitive compatibility fields and encrypted settings. The encryption key is generated once, stored alongside the active desktop data directory, and reused across app updates so encrypted settings remain readable.

All data stays on your machine. The desktop application does not phone home or transmit usage data to any external service. Project export/import deliberately excludes credential values; integrations must be reconnected when secrets are not available locally.

Security

The Electron shell generates a random 256-bit authentication token on each launch and injects it into every request to the local backend. This prevents other processes running on the same machine from accessing the service. The token is never persisted to disc and is regenerated on every application restart. A Content Security Policy restricts scripts, connections, and framing inside the renderer process.

Diagnostic log dumps are available only from crash/error screens and stay local unless the user chooses to share them. Normal settings and About screens do not expose a log-dump action, and secret values are not written to diagnostics.

Summary

ConcernMechanismUser Action
AuthenticitySHA-256 checksums published with every releaseManual - compare hash before installation
IntegrityVisible startup integrity checklist; ASAR block hashes; Ed25519-signed manifest of bundled filesAutomatic before backend/frontend startup; manual via About dialogue
PrivacyOS secure credential storage for secret values; stable per-user data directory; Fernet encryption for remaining encrypted local fieldsAutomatic
SecurityPer-session 256-bit auth token for the local backend, including its mounted compute API; renderer CSP; local-only crash diagnosticsAutomatic

Web Application

When Masterplan Optimiser is deployed with a server for multi-user calendar publishing, the following protections are in place.

Authenticity

The server uses WebAuthn / passkey-only authentication. There are no passwords - users register a hardware or platform authenticator (e.g. Windows Hello, Touch ID, or a security key) during activation, and all subsequent logins require that authenticator with user verification (biometric or PIN).

  • Phishing-resistant: credentials are bound to the server's origin and cannot be replayed on a different site.
  • No shared secrets: the server only stores public keys; private keys never leave the authenticator.
  • One-time activation links allow admins to invite users; each link expires after use.

Destructive admin operations - deleting a user, deleting an event, or regenerating a publish secret - require the admin to re-authenticate with their passkey within the last 5 minutes. This prevents an attacker who has obtained a valid session from performing irreversible actions without possessing the physical authenticator.

Integrity

The server is deployed behind a Caddy reverse proxy which enforces HTTPS with automatic TLS certificate management. Security headers applied to every response include:

  • Content Security Policy: restricts scripts, styles, fonts, images, and connections to 'self'. Frames are blocked (frame-ancestors 'none'), and additional directives (base-uri, form-action, object-src) further minimise the attack surface. Fonts are self-hosted, eliminating external CDN dependencies.
  • Strict-Transport-Security: HSTS with a 1-year max-age.
  • X-Content-Type-Options / X-Frame-Options / Referrer-Policy: standard hardening headers are set.
  • Server header: removed to avoid revealing infrastructure details.

The frontend includes global and page-level React error boundaries that display a user-friendly message without exposing stack traces or internal details. The interactive Swagger and ReDoc API documentation endpoints are only available in development mode.

Privacy

IP addresses stored in session records are hashed with a daily-rotating salt - enough for anomaly detection without retaining raw addresses.

The server automatically purges stale authentication data on each startup to minimise the data footprint:

  • Expired sessions are deleted after 1 day.
  • Revoked sessions are deleted after 7 days.
  • Used or invalidated activation links are deleted after 30 days.
  • Expired passkey challenges and exchange codes are purged immediately.
  • Audit log entries are purged after 90 days (configurable).

All retention periods are configurable via environment variables or the admin settings panel.

GDPR compliance endpoints allow administrators to export all data associated with a user, fully anonymise a user account, or process a self-service deletion request submitted by the user.

Security

Session Management

All sessions are server-side. The browser only stores an opaque session ID in an HttpOnly, Secure, SameSite=Lax cookie.

  • Short TTLs: admin sessions expire after 1 hour; regular user sessions after 8 hours. An inactivity timeout (30 minutes) revokes idle sessions automatically.
  • CSRF protection: every session has a paired CSRF token delivered via a separate cookie. All state-changing requests must include the token in a header.
  • Fingerprinting: sessions are bound to a hash of the browser's User-Agent and Accept-Language headers. Requests from a different browser fingerprint are rejected.
  • Automatic revocation: when a passkey is registered or deleted, all existing sessions for that user are revoked immediately.

Rate Limiting

All authentication endpoints and sensitive admin operations are rate-limited per IP address. Passkey authentication is limited to 10 attempts per minute; auth completion to 5 per minute. Publish and bootstrap endpoints are separately limited. Admin create and delete endpoints are separately limited. A 5 MB request body limit is enforced at the reverse proxy level.

Content-Type Enforcement

All write requests to the API must include a valid JSON Content-Type header. Requests without it are rejected with a 415 status code, preventing content-type confusion attacks.

Push Notification Validation

Push subscription endpoints are validated against an allowlist of trusted push service domains (e.g. FCM, Mozilla, WNS, Apple) and must use HTTPS. This prevents the server from being used to send requests to arbitrary URLs.

Publish Secret Rotation

Each event's publish secret has a tracked creation date. Secrets older than a configurable maximum age (default: 90 days) are automatically rejected by the publish endpoint, prompting administrators to regenerate them. The HTTPS-only requirement for server URLs is enforced in the desktop application.

Audit Logging

Security-relevant actions are recorded in a retained application audit log, including logins, logouts, passkey operations, event management, user administration, publish events, and announcement changes. Each entry captures a hashed IP, timestamp, and outcome. Audit logs are queryable by administrators and automatically pruned based on configurable retention settings. Infrastructure actions performed through MP-OPT are recorded separately in a sanitised append-only SHA-256 hash chain that operators can verify from the SSH management interface.

Structured Request Logging

Every API request is assigned a unique request ID, logged with timing, method, path, status code, and authenticated user. The request ID is returned in the response headers for traceability.

Secrets Management

Production setup writes application, VAPID, root-bootstrap and optional SMTP credentials to protected Docker secret files. Secrets are mounted as files inside the container rather than passed as environment variables, preventing exposure via docker inspect. The guarded production wizard, rotation actions and recovery workflow preserve mode-0600 files and never place the SMTP token or private snapshot recovery identity in .env.

High-Availability Write Fencing

In two-node mode, a Cloudflare Durable Object owns one writer lease. FastAPI checks a short-lived permit before a mutating request and SQLAlchemy checks again before ORM commits. If the witness cannot be reached, writes fail closed with HTTP 503 rather than allowing two primaries. Encrypted peer copies are accepted only from the current lease holder and only after manifest, release and generation checks.

Summary

ConcernMechanism
AuthenticityWebAuthn passkey-only, phishing-resistant; re-auth for destructive ops
IntegrityHTTPS with HSTS, strict CSP, self-hosted fonts, error boundaries
PrivacyHashed IPs with rotating salt, configurable data retention, GDPR data export and anonymisation
SecurityServer-side sessions, CSRF tokens, fingerprinting, per-IP rate limiting, content-type enforcement, audit logging, publish secret rotation, Docker Secrets, push validation