Omahub
← All plugins
J

Swiss Transport

by Jerome Maeder

Live Swiss public transport on a map: trains, metros, trams, buses, boats and mountain lifts moving around you, from the federal Open Journey Planner. Click a vehicle for its number, type, speed, status and neighbouring stops. English, French or German.

Security review

Potentially dangerous behavior detected · 2 findings

Deterministic scan — not a security guarantee

High
Risk level
High
Analyzed commit
508cc3a
Scanned
2 weeks ago
  • high destructive_filesystem tools/test.js:1046

    Destructive operation on the root filesystem or a block device.

    rm -rf /']), null)
  • Docs obfuscation docs/security.md:133

    Augments a command with octal/hex escape sequences.

    \x10JFIF...'

Automated analysis only — not a security guarantee.

AI advisory review

No obvious issues detected

Language-model assessment · ~deepseek/deepseek-v4-flash-latest — advisory only

Low
AI risk level
Low
Recommendation
install
Model
~deepseek/deepseek-v4-flash-latest
Analyzed commit
508cc3a
Reviewed
2 weeks ago

The plugin is a well-documented QML bar widget that only contacts an allowlist of Swiss open-data services, stores its API key in a 0600 curlrc, and has no install-time shell script or destructive runtime behavior. The deterministic 'high' finding is a negative unit-test string in tools/test.js, not code executed at install or runtime, and the 'obfuscation' finding is a JPEG magic-byte example in docs/security.md. The actual user-facing risk is low.

  • The tools/test.js:1046 'rm -rf /' snippet appears to be a unit-test fixture/assertion for rejecting dangerous input, not a destructive command in the plugin's runtime or install path.
  • The docs/security.md obfuscation finding is an illustrative byte sequence from a documented symlink-attack test, not executable code.
  • Runtime network access is restricted to opentransportdata.swiss, ipapi.co, and swisstopo hosts; the API key is validated, stored with restrictive permissions, and never passed on the curl argv.
How this check works

This review combines the deterministic scan (the rule-based results above) with an independent look at the plugin's code by a language model. The model reads a trimmed sample of the repository's files, the manifest, and the README, then gives a plain-language risk level and a recommendation: install (no notable danger), review (look closer first), or avoid (clearly dangerous).

It runs on the same analyzed commit as the deterministic scan and is strictly advisory — it is not a security guarantee and never blocks a plugin by itself. A human moderator still reviews plugins before they are listed.

AI advisory only — automated analysis, not a security guarantee.

Install
$ omarchy plugin add https://github.com/jmaeder/omarchy-swisstransport --enable
Widgets #bar #quickshell

Swiss Transport

Live Swiss public transport on a map in the Omarchy bar: trains, metros, trams, buses, boats and mountain lifts moving around you, from the federal Open Journey Planner — in English, French or German.

Left alone it is a single locomotive in the bar with a small Swiss cross on it, and it makes no requests at all. Click it and it becomes a live map of the square kilometre around you.

The Swiss Transport panel: opening the map, following a tram, reading a stop's departures, searching for Davos and switching to the mountain presets

Highlights

  • Vehicles moving on a map, each carrying the glyph of what it is — train, metro, tram, bus, boat, cable car, funicular — with a pip showing which way it is going. Positions are recomputed five times a second at no network cost.
  • Where they come from is stated plainly. Switzerland publishes no vehicle-position feed, so a position is derived by interpolating between two timetabled calls and their real-time estimates. Every speed on screen is labelled derived, and each vehicle says whether it is running on real-time data or on the timetable alone.
  • Click a vehicle for its number, type, derived speed, status and the stops immediately behind and ahead — Not applicable where there genuinely is no previous or next stop — with its route drawn on the map.
  • Click a stop for its departure board and, above it, every line that calls there at all: the interchange, which is what a dot on a map cannot show. Click a boxed line number and that whole line is drawn across the map.
  • Drag to pan, wheel to zoom, 200 m to 20 km, remembered. The wheel zooms about the pointer, so what you lean towards stays under it.
  • Favourites with their full name and canton — Le Grand-St-Bernard (VS), Hospice — starred on the map and listed with their distance from where you are looking.
  • The swisstopo national map underneath, grey or colour. Cached, with the zoom level either side fetched in advance so zooming does not pause.
  • Two mountain presets. I'm hiking! and I'm skiing! narrow the transport to what gets you to and from the mountain — and narrow the stops polled, so a map of lifts is not mostly buses — then answer what is on the ground where you click: the altitude anywhere in the country, the signposted hiking routes with their numbers and stages, or the ski-touring routes with the club's grade, the ascent, the climbing time and the hut they lead to.
  • An empty map says which kind of empty it is. Outside the cities the usual case is a timetable with nothing on it, so the panel names the next departure instead of leaving you wondering whether it is broken. A lift shut for the season reads as shut, not as an error.
  • English, French or German, switchable in the panel and sent to the planner, so stop names and product categories come back in it too.

Install

omarchy plugin add https://github.com/jmaeder/omarchy-swisstransport.git --enable

--enable asks where to put it in the bar. To place it yourself:

omarchy plugin enable jmaeder.swisstransport center --before omarchy.clock

Needs Omarchy 4 (Quattro) with shell plugin support, curl, and a Nerd Font for the vehicle glyphs — a stock install has all three.

Your own API key

The plugin needs an Open Journey Planner key, which the federal platform issues free of charge to anyone who asks. Register at api-manager.opentransportdata.swiss, subscribe to the OJP 2.0 API, and copy the token: about two minutes, no cost, no approval step.

A plugin cannot ship a shared key. It would be a public secret in a public repository, and the first misuse would get it revoked for everyone at once.

Open the panel and paste the key. It is stored at ~/.local/state/omarchy/plugins/jmaeder.swisstransport/curlrc, created with mode 0600 inside a 0700 directory, in a form curl reads directly. The panel never loads it back: what it checks is whether the file exists, not what is in it. Forget key in the footer deletes it.

Controls

Action Result
Click the bar item Open / close the panel
Drag the map Pan
Wheel, or + / − Zoom about the pointer
Click a vehicle Follow it, and draw its route
Click a stop Its departure board and interchange
Click a boxed line number Draw that whole line across the map
Click empty map Clear the selection — in a mountain preset, ask what is on the ground there
↻ on the location chip Look up where you are again
★ in the header The full favourites list
Esc Back to the map, then close

Settings

Set these on the widget's entry in ~/.config/omarchy/shell.json.

Key Default Meaning
language (locale) en, fr or de; the panel's own selector overrides it
swissCross true Badge the bar locomotive with a small Swiss cross
sideMetres 1000 Side of the square of ground the map covers. Clamped to 200–20000; the panel's own zoom writes here
renderSeconds 0.2 How often positions are re-interpolated. This is the whole of the animation. Costs no request; clamped to 0.1–10
networkSeconds 20 How often the planner is polled. Clamped to 10–300, and further limited by the quota guard
maxStops 6 How many nearby stops are queried per cycle. More stops, more vehicles, more requests. Clamped to 1–12
detectLocation true Detect your region once, on first run
basemap true Kill switch, not a mode: false stops every swisstopo request, tiles and cantons both
basemapLayer grey grey or colour; the panel's own tick overrides it
basemapOpacity (per layer) How strongly the map shows through, 0.05–0.8. Left unset, each sheet uses the strength that suits it

Data and privacy

Everything on screen is federal open data. Transport comes from api.opentransportdata.swiss (Open Journey Planner 2.0), under your own key. The national map, the ski-touring and footpath sheets, the altitude and the canton of a place come from swisstopo, at wmts.geo.admin.ch and api3.geo.admin.ch — the journey planner publishes none of those. Location detection is one request to ipapi.co, at most once, and only if you leave detectLocation on. Those four hosts are the only ones the plugin ever contacts; the list is enforced in code, the host is re-derived from the finished URL before every request, and redirects are not followed.

Your search terms travel in the request body, never in a URL. The plugin writes your key, a small state file and a tile cache, all under ~/.local/state/ and ~/.cache/, and nothing else.

Requests are held under the published quota by a token bucket checked before every call rather than by trusting the timer intervals. swisstopo asks only that it be credited, which the map does in its corner.

Documentation

Licence

MIT — see LICENSE.

Transport data from opentransportdata.swiss (Open Journey Planner 2.0). National map, ski-touring and footpath sheets and cantonal boundaries © swisstopo. Coarse first-run geolocation by ipapi.co. The data this plugin displays is governed by the terms of those services.