Repository navigation
v2.9.1: admin password, security fixes, working restore
A security and reliability release. Recommended for everyone, and especially
if people you do not fully trust can reach your MeshPulse: several of the fixes
below close holes that anyone on the network, or anyone who could name a node,
was able to use.
Optional admin password
MeshPulse trusts its LAN, so until now anyone who could open the map could also
install a plugin (which runs Python on your Pi), restore a backup, read the
channel keys, arm remote admin and transmit as your node.
Set a password in Config > 🔒 Security and the map, Stats and Messages stay
open to everyone, while everything that changes the system, reads its secrets or
goes out over the air asks for it first: plugins, settings, channels (including
reading the channel keys), backup and restore, clearing stats, favourites,
remote admin, sending messages, traceroute and position requests.
- Only a PBKDF2-SHA256 hash is stored, in
config.json(owner-only). The
password never appears in the log. - A browser that logs in stays unlocked for 14 days. Changing the password or
Sign out every browser ends every session, open ones included. - Five wrong passwords from one address within 10 minutes lock it out for 5
minutes. - Forgot it? Remove
admin_password_hashfromconfig.jsonover SSH and
restart the service. - Without a password nothing changes. It does not encrypt traffic: MeshPulse
serves plain HTTP and WebSocket, so use a VPN or an authenticating reverse
proxy with TLS before exposing it to the internet.
Security fixes
- A node name could run JavaScript in your browser. Names come from the air,
and the DM, traceroute and Admin buttons put them into anonclickattribute
escaping only apostrophes. A 30-character long name was enough to run code in
every open map. Those arguments are now JSON-encoded and HTML-escaped, and the
DM list, favourites, channel name and plugin messages escape what they show. - Uninstalling a plugin could delete your home directory.
uninstall_plugin
removed whateverplugins/<id>resolved to, so an id likex/../../..went
far outside the plugins directory; a package with such an id did the same on
install. Plugin ids must now beauthor/nameand stay inside the plugins
directory. - A crafted backup could write any file, including code. Restore now writes
only what a backup contains:config.json,nodes.json,stats.db,
plugins/enabled.jsonandplugins/<author>/<name>/config.json. - The web server handed out
stats.db, with the remote admin audit and
client addresses, to anyone on the network. It is owner-only now, like
config.json. - The WebSocket server buffered up to 10 MB per message and connection. It
now stops anything over 128 KB before reading it. - Leaflet and Chart.js load with Subresource Integrity, and Chart.js is pinned to
4.6.1 instead of whatever version the CDN serves today.
Backup and restore that work
- Restoring a full backup never worked. A WebSocket message is 64 KB at most
and anything bigger was dropped without a word, so a backup withstats.db
(or a larger plugin package installed from a file) simply never arrived. The
Config page now uploads files in 40 KB pieces with a progress display, and the
Pi writes them to disk instead of memory: up to 512 MB for a backup and 32 MB
for a plugin, checked against free disk space first. - A full backup now takes a consistent snapshot of
stats.dbinstead of copying
a live file that could catch a write half done.
Faster on SD cards
stats.db runs in WAL mode. Logging a packet on a Raspberry Pi 2 SD card went
from 28.9 ms to 5.3 ms (median) and from 66 ms to 6.5 ms (p95), and that is
time spent holding the lock the rest of MeshPulse waits on. You will see
stats.db-wal and stats.db-shm next to stats.db: that is normal.
Plugins
- Updating a plugin deleted its database. The upgrade kept
config.jsonand
adata/directory, but notdata.db, the fileget_database()creates, so
every plugin using the documented API started from scratch after an update. on_positionnow carriesvia_mqtt,speed(m/s),heading(degrees),
precision_bitsandpos_time. The guide promised speed and heading for a
long time; the core never sent them. Trails uses them for real GPS speed.
Everything above was tested live on a Raspberry Pi 2 before shipping. Full list
in docs/changelog.md.
Updating
cd ~/meshpulse && git pull origin main && ./install.sh && sudo systemctl restart meshpulse
Docker
docker compose pull && docker compose up -d
Fresh Install
git clone https://github.com/maxg10/meshpulse.git
cd meshpulse
./install.sh