Code review fixes: app 2.9.0, server 2.2.0
Telemetry no longer loses queued batches. The server drops a bad value, or a sample without a plausible time, instead of rejecting the batch, and answers 200 with what it dropped. The app sends only values inside the server's ranges (speed as a magnitude, so reversing is fine) and no samples before the head unit's clock is set. Server: - Pairing hands out and accepts a token only after the device is saved; a failed save leaves the request pending. - A paired token serves only the installation id it was paired with (403 otherwise); the shared INGEST_TOKEN still serves any. - Wrong-password lockouts and open pairing requests are limited per client address (last X-Forwarded-For entry), so a stranger cannot lock the owner out; a car starting again replaces its own request. - ABRP forwarding skips samples stamped ahead of the server's clock, which used to stop it until a restart. App: - Settings written to plaintext during a keystore failure move back into encrypted storage; the stored installation id wins. - The installation id is derived from ANDROID_ID on first start, so a reinstall finds its history; a stored or imported id still wins. - The scanned config file is deleted after import (it holds the token). - GPS stops while live telemetry is off or the server unconfigured, and pauses while parked and idle, keeping the fix the car parked with. - Range estimates use the monotonic clock. - One HTTP helper (ServerHttp) for telemetry, sync and pairing. - Last Turkish strings translated; mise logs shows the NilsMG4 tags. Grafana reads InfluxDB with its own read-only token (new grafana-influx Secret, created by hand as described in k8s/README.md). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
This commit is contained in:
+13
-7
@@ -31,18 +31,22 @@ The ABRP credentials never reach the car.
|
||||
## Endpoints
|
||||
|
||||
The ingest endpoints accept `Authorization: Bearer <token>` with either the shared `INGEST_TOKEN`
|
||||
or a paired car's own token.
|
||||
or a paired car's own token. A paired token only works for the installation id it was paired
|
||||
with (403 otherwise); the shared token works for any.
|
||||
|
||||
- `POST /v1/telemetry` — `{ installationId, samples: [...] }`, up to 500 samples in ABRP's `tlm`
|
||||
field names and units (`utc` in epoch seconds; flags as 0/1 or booleans). Unknown fields are
|
||||
dropped, known ones bounded. Stored, then the newest sample is forwarded to ABRP if it is under
|
||||
5 minutes old.
|
||||
dropped, known ones bounded: a value out of range is dropped on its own, and a sample without
|
||||
a plausible time (before 2001, or more than an hour ahead) is dropped whole. The rest is stored
|
||||
and the answer is `200 {stored, droppedCount, dropped}`, even when nothing was usable, since
|
||||
the car would only send it again. The newest sample is forwarded to ABRP if it is under
|
||||
5 minutes old and not ahead of the server's clock.
|
||||
- `PUT /v1/consumption/daily` — one delta chunk of a day's consumption.
|
||||
- `PUT /v1/charging-sessions/{sessionId}` — a finished DC session with its curve.
|
||||
- `GET /v1/consumption/history/{installationId}` — the car reads its own totals back.
|
||||
- `GET /v1/health` — `{"status":"ok"}`.
|
||||
|
||||
A bad request is a 400 naming the field; a database failure is a 500 without detail.
|
||||
A malformed request is a 400 naming the field; a database failure is a 500 without detail.
|
||||
|
||||
## Pairing a car by QR code
|
||||
|
||||
@@ -52,13 +56,15 @@ on only when `APPROVAL_PASSWORD` is set.
|
||||
1. The car calls `POST /v1/pair/start` `{installationId}` and shows the returned
|
||||
`verificationUriComplete` as a QR code, plus the short `userCode` (e.g. `K7F-3QX`).
|
||||
2. The phone opens `/pair?code=…`, the owner checks the code and approves with the approval
|
||||
password. Five wrong passwords lock approvals for a minute.
|
||||
password. Five wrong passwords from one address lock that address out for a minute; other
|
||||
addresses are unaffected (the address is the last `X-Forwarded-For` entry, which Traefik sets).
|
||||
An address may hold three open requests; a car starting again replaces its own.
|
||||
3. The car polls `POST /v1/pair/poll` `{deviceCode}`: 202 pending, 200 with its own token
|
||||
(handed out once), 403 denied, 410 expired (after 10 minutes) or unknown.
|
||||
|
||||
Each car gets its own 43-character token; only its SHA-256 is stored (measurement `device` in
|
||||
the same bucket), and the device is persisted before the car can collect the token, so a
|
||||
restart never loses a paired car. Manage cars with the approval password:
|
||||
the same bucket), and the token is only handed out, and only accepted, once the device is
|
||||
persisted, so a restart never loses a paired car. Manage cars with the approval password:
|
||||
|
||||
```sh
|
||||
curl -H "Authorization: Bearer $APPROVAL_PASSWORD" https://car.k8s.stinnesbeck.com/v1/devices
|
||||
|
||||
Reference in New Issue
Block a user