Cole Munz

build log · Android apps

A second place your location goes

2026-09-30

Issue #10 asked for something reasonable. The person runs colota-forwarder on their own server, which passes location updates on to Reitti for a timeline and Home Assistant for automations. Starling was the app their friends and family would actually use, but they didn't want two apps on their phone both working the GPS. Could Starling send their position to their own server too?

Posting a JSON body to a URL is an afternoon. The question that took longer was what else that feature is. A setting that quietly sends your position to a second address is exactly what someone with access to your phone would set, and Starling already tells people to check who has access to their phone when a share stops unexpectedly. So the rule was that it stays loud, or it doesn't ship.

What loud means here

It only runs while you're sharing, and it only ever sends your own position, never your circle's. The sharing notification names the server ("Also sending to …") and so does the line under your name on the map, though the lock screen copy of the notification stays generic, so a locked phone lying on a table still gives nothing away. With the app lock on, setting, changing or clearing the address takes your passcode. The duress passcode gets refused there like any wrong one; wiping a phone from a settings screen would be a strange thing to do.

Two smaller rules. The app only ever reads back the host, never the full address, because Reitti and Dawarich both put their key in the query string, so Settings and the data export show relay.example.org and nothing after it. And nothing goes out while Tor mode is on. Tor mode promises that nothing leaves the phone outside Tor, and a request from the native side would have.

Why the native side sends it

Everything else Starling sends goes out from the web page. This doesn't. A POST from the page to someone's forwarder is a cross-origin request, which only works if that server answers the browser's CORS check, and servers built for phone apps have no reason to. The page can also be frozen, which was its own story. So the Kotlin side sends it from the location service, in OwnTracks' HTTP format, at most every fifteen seconds, over https only, following no redirects, with a wake lock held just for the request.

Testing it without anyone's server

The app refuses anything but https, and release builds only trust the system's certificate authorities. For the emulator test, debug builds now also trust user-added ones, through a debug-overrides block that release builds ignore. With a throwaway CA, a certificate for 10.0.2.2 (the emulator's name for the machine it runs on) and a short Python receiver, I could watch the whole path.

A wrong passcode left the setting alone. With the app in the background, screen off and the position moving, a post landed every fifteen seconds. Tor mode on: nothing for 35 seconds. Tor mode off again: three posts. After the share stopped, nothing at all.

What else turned up

Testing Tor showed me an older edge. Switching Tor mode reloads the page, and with the app lock on, the reloaded page sits on the lock screen while the location service keeps running until you type your passcode. The notification stays up the whole time, so it isn't silent, but for that window the app and the service disagree about whether you're sharing. That one is written down and not fixed yet.

Nobody asked for the passcode prompt or the host-only readback. They're most of the work, and in a location app they're the part I'd want someone else to have thought about.