Repository navigation
gotify-commander v0.3.0
Highlights
- Built for Gotify 3.1.1 and 2.9.1, on amd64, arm64 and armv7: one file per Gotify version.
- The control panel is locked by default, with a generated password shown only on the plugin page in Gotify.
- Only Gotify administrators get a working plugin instance.
Built for Gotify 3.1.1 and 2.9.1, on amd64, arm64 and armv7. The 0.2.0 file
loads only in Gotify 2.6.x; pick the file that matches your server from the
compatibility table in the README.
Upgrade note: SSH targets now need the remote host key in the known_hosts
file of the user that runs Gotify (ssh-keyscan -p <port> <host> >> ~/.ssh/known_hosts), or the path set in known_hosts_file for that target.
Until then, commands to that machine fail with a host key error.
Security
- The control panel is protected by default. When
web_passwordis empty the
plugin generates a random password on enable, stores it in the plugin
storage and shows it only on the plugin page in Gotify. It is never logged
or sent in a message. - Panel authentication accepts only
Authorization: Bearer, compared in
constant time. The?token=query parameter is gone. POST /executerequiresContent-Type: application/json, limits the body
to 64 KiB, checksOriginandSec-Fetch-Site, runs at most 2 commands at
a time and 10 per minute per plugin instance.- Every panel route sends
Content-Security-Policywith a per-request nonce,
X-Frame-Options: DENY,Cache-Control: no-store,
Referrer-Policy: no-referrerandX-Content-Type-Options: nosniff. Pico
CSS is embedded instead of loaded from a CDN. - The panel URL, which carries the plugin token, is no longer printed by
help, sent in the "Commander Online" message or written to the log. - Only Gotify administrators get a working plugin instance. Other users see a
notice and no routes or stream are opened. - Command timeouts kill the whole process group (
Setpgidplus aCancel
that signals the group), so pipelines such assleep | catstop on time.
Output is capped at 64 KiB. certs,analyticsandlocateno longer run throughbash -c. The one
remaining shell script intrafficis fixed text and receives the domain
and the temp file path as positional arguments.- SSH host keys are verified against
known_hosts;InsecureIgnoreHostKey
is gone. Remote commands are shell-quoted word by word. - The Gotify client token travels in the
X-Gotify-Keyheader instead of the
websocket URL, and every stream log line is passed through a redaction
helper. locatevalidates that latitude and longitude are finite and in range,
escapes the OpenStreetMap text before building markdown, sets a proper
User-Agentand keeps coordinates out of error messages and logs.- Panics in a command handler or in the stream goroutines are recovered,
logged with a stack trace and answered with an "internal error" message
instead of killing the Gotify process.
Changed
- The stream read loop only reads. Commands go to a bounded queue (16) and a
worker runs them, so ping/pong keeps working during long commands such as
trafficand the client is no longer dropped after 60 s. When the queue is
full the sender gets "busy, try later". - Reconnection uses exponential backoff from 1 s to 60 s with jitter.
Stopon the listener cancels the context, closes the connection and waits
for the goroutines. Config changes made in the Gotify UI restart the
listener and the commander with the new values.response_app_tokenis no longer required (it was unused).command_app_id
must be a positive integer and category command names are validated
against the registry.- The plugin version comes from
-ldflags "-X main.version=..."set by the
Makefile fromgit describe. analyticsparses the goaccess CSV in Go;python3is no longer needed.trafficmatches the domain as plain text instead of a regular
expression.- The panel asks for the password in its own dialog, keeps it in
sessionStoragefor the tab and sends it with every request. A 401 clears
it and asks again.
Fixed
- The
traffictemp file is removed on timeout as well. Listener.connwas accessed without synchronisation andStopdid not
wait for the read goroutine.esc()in the panel did not escape quotes although it was used inside
attributes.- Removed the development "seed history" entries and
user-scalable=no
from the panel. HandleCommandandExecuteshare one code path.
Added
scripts/pin-gotify.sh <version>pinsgo.modto the Gotify server's
module versions and records them in.gotify-versionand.go-version.
scripts/check-plugin-abi.shcompares a built.sowith the server's
go.modand fails on any mismatch.make build-plugin GOTIFY_VERSION=<v> ARCH=<arch>builds inside the
officialgotify/buildimages;make build-allcovers the whole matrix.
Thedeploytargets with placeholder hosts are now a commented example.- GitHub Actions:
ci.yml(gofmt, vet, race tests, govulncheck),
release.yml(matrix build, ABI check, checksums, release notes from this
file with a compatibility table) andgotify-watch.yml(weekly check for
new Gotify releases that opens an issue). Dependabot covers actions only. test/e2e/smoke.sh: starts Gotify in Docker with the plugin, sends
ping, expectspong, checks the panel authentication and a restart.
Run against 3.1.1 and 2.9.1 on amd64 and arm64 before this release.SECURITY.mdwith the reporting process and the threat model.- Tests for the panel routes, the executor timeouts, the stream queue,
recovery and shutdown, SSH quoting and host key checks. Root package
coverage went from 0 % to about 90 %,internal/streamfrom 17 % to
97 %,internal/executorfrom 37 % to 85 %.
Compatibility
A Go plugin only loads in the Gotify release it was built for.
Pick the file for your Gotify version and architecture.
| Gotify | Architecture | File |
|---|---|---|
| 3.1.1 | amd64 | gotify-commander-linux-amd64-for-gotify-3.1.1.so |
| 3.1.1 | arm-7 | gotify-commander-linux-arm-7-for-gotify-3.1.1.so |
| 3.1.1 | arm64 | gotify-commander-linux-arm64-for-gotify-3.1.1.so |
| 2.9.1 | amd64 | gotify-commander-linux-amd64-for-gotify-2.9.1.so |
| 2.9.1 | arm-7 | gotify-commander-linux-arm-7-for-gotify-2.9.1.so |
| 2.9.1 | arm64 | gotify-commander-linux-arm64-for-gotify-2.9.1.so |
Each file has a .sha256 next to it: sha256sum -c <file>.sha256.