mirror of
https://github.com/MarekWo/mc-webui.git
synced 2026-10-30 23:51:57 +01:00
mc-webui has no login, which is fine on a LAN and not fine once the address is handed to testers: they assume the node is theirs and rename it, and the console is right there for anyone curious enough to type into it. MC_DEMO=true refuses everything that reconfigures the radio, destroys data, reaches other people's repeaters, rebuilds the containers, publishes to an external broker, or hands out a secret. Reading and sending messages keep working, so the instance is still worth visiting. The guard is default-deny: an api_bp.before_request hook refuses every non-GET unless it is on a short allowlist, so an endpoint added later is locked without touching this module. That mattered — six mutating endpoints already had no frontend caller and would never have made a hand-written blacklist. A small read denylist covers the GETs that leak (repeater passwords, backup download, capture download, /api/logs), which the write guard never sees. Two paths bypass the HTTP layer and are closed separately: the console is a Socket.IO event, not a route, so it is checked against a read-only command set; the log viewer is refused at the connect handshake. Access is kept two ways. MC_DEMO_TRUSTED_NETS unlocks by CIDR, and MC_DEMO_UNLOCK_CODE unlocks by a code typed once in Settings and held in an HMAC cookie for 30 days — stateless, and deliberately not Flask's session, whose SECRET_KEY is a hardcoded public constant. The trap the network list walks into: published through a tunnel, every visitor arrives from the tunnel's address, and if the tunnel runs on the LAN then trusting the LAN unlocks the instance for the whole internet. An address arriving with a proxy header is therefore not matched unless MC_TRUST_PROXY is on, and startup logs report the resulting shape. Frontend is advisory only: demo-lock.js loads from _head_i18n.html so it reaches all eight entry points including the six iframes, greys out [data-demo-lock] rather than hiding it (the instance exists to show the app off), re-applies via MutationObserver for JS-rendered buttons, and turns any 403 demo_locked into a toast. Verified on the local container: the rename, reboot, updater, vacuum, cleanup and the leaky GETs all 403; sending, read markers and ordinary reads pass; `set name` is refused over the console socket while `infos` still answers; unlock/lock round-trips. 86 new unit tests, en/pl at 100%. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
149 lines
6.3 KiB
Bash
149 lines
6.3 KiB
Bash
# mc-webui Environment Configuration
|
|
# Copy this file to .env and adjust values for your setup
|
|
|
|
# ============================================
|
|
# MeshCore Device Connection
|
|
# ============================================
|
|
# Three transport options: Serial (USB), TCP (network), or BLE (Bluetooth).
|
|
# Priority: BLE > TCP > Serial. Set the relevant variable to activate.
|
|
|
|
# --- Option A: Serial (default) ---
|
|
# Use "auto" for automatic detection (recommended if only one USB device)
|
|
# Or specify manually: /dev/serial/by-id/usb-xxx or /dev/ttyUSB0
|
|
# Find available devices: ls /dev/serial/by-id/
|
|
MC_SERIAL_PORT=auto
|
|
|
|
# --- Option B: TCP (e.g. remote device via ser2net, meshcore-proxy) ---
|
|
# Set the IP/hostname of the device to connect via TCP instead of serial.
|
|
# When MC_TCP_HOST is set, MC_SERIAL_PORT is ignored.
|
|
# MC_TCP_HOST=192.168.1.100
|
|
# MC_TCP_PORT=5555
|
|
|
|
# --- Option C: BLE (Bluetooth Low Energy companion devices) ---
|
|
# Requires: USB BLE dongle on host, BlueZ installed.
|
|
# The device MUST be paired and trusted on the host BEFORE starting mc-webui.
|
|
# See docs/meshcore_bluetooth_pairing.md for detailed setup instructions.
|
|
# When MC_BLE_ADDRESS is set, serial and TCP are ignored.
|
|
# MC_BLE_ADDRESS=AA:BB:CC:DD:EE:FF
|
|
|
|
# Your MeshCore device name (used for .msgs file)
|
|
# Use "auto" for automatic detection from device (recommended)
|
|
# Or specify manually: MarWoj, SP5XYZ, MyNode
|
|
MC_DEVICE_NAME=auto
|
|
|
|
# MeshCore configuration directory (where .msgs and settings files are stored)
|
|
# Default: ./data/meshcore (inside project directory)
|
|
# This directory is mounted as a Docker volume and shared between both containers
|
|
MC_CONFIG_DIR=./data/meshcore
|
|
|
|
# ============================================
|
|
# Application Settings
|
|
# ============================================
|
|
|
|
# Note: Auto-refresh is now intelligent and checks for new messages every 10 seconds
|
|
# No configuration needed - the system automatically updates UI only when new messages arrive
|
|
# Contact cleanup threshold is set directly in the UI (default: 48 hours)
|
|
|
|
# ============================================
|
|
# Archive Configuration
|
|
# ============================================
|
|
|
|
# Directory for storing archived messages
|
|
# Default: ./data/archive (inside project directory)
|
|
# This directory is mounted as a Docker volume for mc-webui container
|
|
MC_ARCHIVE_DIR=./data/archive
|
|
|
|
# Enable automatic daily archiving at midnight
|
|
MC_ARCHIVE_ENABLED=true
|
|
|
|
# Number of days to show in live view (older messages available in archives)
|
|
MC_ARCHIVE_RETENTION_DAYS=7
|
|
|
|
# ============================================
|
|
# Flask Server Configuration
|
|
# ============================================
|
|
|
|
# Listen on all interfaces (0.0.0.0) or specific IP
|
|
FLASK_HOST=0.0.0.0
|
|
|
|
# Port to expose the web interface
|
|
FLASK_PORT=5000
|
|
|
|
# Debug mode (true/false) - use false in production
|
|
FLASK_DEBUG=false
|
|
|
|
# ============================================
|
|
# HTTPS (optional) - see docs/https-setup.md
|
|
# ============================================
|
|
# Off by default: mc-webui serves plain HTTP on FLASK_PORT and nothing else runs.
|
|
#
|
|
# Uncommenting the line below starts Nginx Proxy Manager alongside the app, which
|
|
# terminates HTTPS and forwards to it. You then configure the certificate in its
|
|
# web UI (http://<server>:81) - Let's Encrypt, or your own certificate file.
|
|
# HTTPS also unlocks browser features that require a secure context, such as
|
|
# installing mc-webui as an app on a phone.
|
|
# COMPOSE_PROFILES=https
|
|
|
|
# Ports published by the proxy. Change them if something else already uses 80/443
|
|
# on this host. Note that Let's Encrypt HTTP-01 validation needs the *public*
|
|
# port 80 to reach this container, so it only works with NPM_HTTP_PORT=80.
|
|
# NPM_HTTP_PORT=80
|
|
# NPM_HTTPS_PORT=443
|
|
# NPM_ADMIN_PORT=81
|
|
|
|
# Where the proxy keeps its configuration and issued certificates.
|
|
# Must NOT be a synced folder (Dropbox, Synology Drive) - it holds a SQLite database.
|
|
# NPM_DATA_DIR=./data/npm
|
|
# NPM_LETSENCRYPT_DIR=./data/letsencrypt
|
|
|
|
# Set to false only if your host has working IPv6.
|
|
# NPM_DISABLE_IPV6=true
|
|
|
|
# Pin the proxy image instead of following latest, e.g. jc21/nginx-proxy-manager:2.12.6
|
|
# NPM_IMAGE=jc21/nginx-proxy-manager:latest
|
|
|
|
# Let the app read the real client address and scheme from the proxy's
|
|
# X-Forwarded-* headers. Enable ONLY when reaching the app through the proxy;
|
|
# a client talking to FLASK_PORT directly can forge those headers.
|
|
# MC_TRUST_PROXY=true
|
|
|
|
# Restrict the plain-HTTP port to the machine itself, so the app is reachable
|
|
# only through HTTPS. Set this only AFTER the proxy works - otherwise you lock
|
|
# yourself out. Leave unset (0.0.0.0) to keep HTTP available as before.
|
|
# MC_BIND_ADDRESS=127.0.0.1
|
|
|
|
# ============================================
|
|
# Demo mode (optional) - see docs/demo-mode.md
|
|
# ============================================
|
|
# For an instance you hand to people you do not know: everything that changes
|
|
# the radio, deletes data, or reconfigures this server is refused, and the
|
|
# controls for it are greyed out. Reading and sending messages still work, so
|
|
# the instance is still worth visiting. Off by default.
|
|
# MC_DEMO=true
|
|
|
|
# How YOU keep full access. Two independent ways in - set either, or both.
|
|
#
|
|
# 1) By network. Comma-separated CIDRs whose visitors are never restricted.
|
|
# Empty by default, and think before filling it in: if the app is published
|
|
# through a tunnel (cloudflared, ngrok) or a reverse proxy, every visitor
|
|
# arrives from that one address, and listing the network it sits in would
|
|
# unlock the instance for everyone at once. mc-webui refuses to match on
|
|
# address alone when it sees a proxy header and MC_TRUST_PROXY is off - but
|
|
# the safe setup is still to leave this empty unless the port is reached
|
|
# directly from your LAN.
|
|
# MC_DEMO_TRUSTED_NETS=192.168.0.0/16,10.0.0.0/8
|
|
#
|
|
# 2) By code. Typed once under Settings, then remembered in a cookie for 30
|
|
# days. Works from any network, which is what you want if the app is behind
|
|
# a tunnel. Make it long - it is the only thing between a visitor and your
|
|
# radio, and it is not rate-limited beyond a one-second delay per attempt.
|
|
# MC_DEMO_UNLOCK_CODE=choose-something-long-and-unguessable
|
|
|
|
# ============================================
|
|
# System Configuration
|
|
# ============================================
|
|
|
|
# Timezone for container logs (default: UTC)
|
|
# Examples: Europe/Warsaw, America/New_York, Asia/Tokyo
|
|
TZ=Europe/Warsaw
|