Compare commits
9
Commits
2fec7e976e
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6e36a70d7c | ||
|
|
5844fab166 | ||
|
|
602cbe9340 | ||
|
|
94274656d5 | ||
|
|
2d232f2aae | ||
|
|
5fcc48668a | ||
|
|
5b77f688f3 | ||
|
|
8fc0be3c36 | ||
|
|
f4cda13d9c |
@@ -1,8 +1,8 @@
|
||||
# Stelloauth for Home Assistant
|
||||
|
||||
Et Home Assistant custom add-on, som kører Stelloauth og CloakBrowser lokalt til
|
||||
OAuth-opsætning af integrationen Stellantis Vehicles. Repositoryet understøtter
|
||||
`amd64` og `aarch64`.
|
||||
A Home Assistant app (formerly known as an add-on) that runs Stelloauth and
|
||||
CloakBrowser locally for OAuth setup of the Stellantis Vehicles integration.
|
||||
The repository supports `amd64` and `aarch64`.
|
||||
|
||||
```text
|
||||
Home Assistant Core
|
||||
@@ -10,50 +10,49 @@ Home Assistant Core
|
||||
| POST http://0031621f-stelloauth:8080/worker
|
||||
v
|
||||
+--------------------------------------------------+
|
||||
| Ét add-on / én container |
|
||||
| One app / one container |
|
||||
| |
|
||||
| Stelloauth 0.0.0.0:8080 |
|
||||
| Stelloauth 0.0.0.0:8080 |
|
||||
| | |
|
||||
| | CDP http://127.0.0.1:9222 |
|
||||
| v |
|
||||
| CloakBrowser 127.0.0.1:9222 |
|
||||
| CloakBrowser 127.0.0.1:9222 |
|
||||
+--------------------------------------------------+
|
||||
```
|
||||
|
||||
Én add-on giver de to processer samme Supervisor-livscyklus og holder
|
||||
CloakBrowsers CDP-port på containerens loopback-interface. Add-onen bygges
|
||||
lokalt fra kilde, fordi CloakBrowser Binary License ikke tillader, at dette
|
||||
repository genudgiver en afledt image med den proprietære CloakBrowser-binær.
|
||||
Der publiceres derfor ingen prebuilt images.
|
||||
Running both processes in one app gives them the same Supervisor lifecycle and
|
||||
keeps CloakBrowser's CDP port on the container's loopback interface. The app
|
||||
builds locally from source because the CloakBrowser Binary License does not
|
||||
allow this repository to redistribute a derived image containing the
|
||||
proprietary CloakBrowser binary. No prebuilt images are published.
|
||||
|
||||
## Installation
|
||||
|
||||
1. Tilføj
|
||||
`https://git.radixadm.dk/dennis/homeassistant-stelloauth-addon.git` som
|
||||
repository i Home Assistants Tilføjelsesbutik.
|
||||
2. Installér **Stelloauth**, aktivér **Start ved opstart** og **Watchdog**, og
|
||||
start add-onen.
|
||||
3. Følg den fulde vejledning i [stelloauth/DOCS.md](stelloauth/DOCS.md).
|
||||
1. Go to **Settings → Apps → Install app → ⋮ → Repositories** and add
|
||||
`https://git.radixadm.dk/dennis/homeassistant-stelloauth-addon.git`.
|
||||
2. Install **Stelloauth**, enable **Start on boot** and **Watchdog**, then start
|
||||
the app.
|
||||
3. Follow the complete guide in [stelloauth/DOCS.md](stelloauth/DOCS.md).
|
||||
|
||||
HAOS-installation er ikke gennemført eller påstået som valideret. Målmaskinen
|
||||
havde ved inspektionen approximately 4 GB free, mens det lokalt byggede image
|
||||
fyldte 2.571 GB; frigør om nødvendigt mere diskplads før installation.
|
||||
When the integration asks for a security PIN, enter the four-digit PIN you
|
||||
chose when activating Remote Control in the MyOpel app. MyOpel does not send
|
||||
you a new PIN; the SMS verification code is separate.
|
||||
|
||||
## Fastlåste upstream-kilder
|
||||
## Pinned upstream sources
|
||||
|
||||
| Komponent | Version | Commit / OCI index digest |
|
||||
| Component | Version | Commit / OCI index digest |
|
||||
| --- | --- | --- |
|
||||
| Stelloauth | `v0.6.0` | `367d4f8c02a3b072c59142c49dffc129edc8548b` |
|
||||
| Stelloauth image contract | `v0.6.0` | `sha256:51b2194ec9b80cc484d11c016ec5436a12161277a493afdab7078959966d5aa9` |
|
||||
| CloakBrowser | `0.5.10` | `f04c23da285b3b3d3cf10c8f9d282e7adc1d52ce` / `sha256:2ed5b2d047cbdde22cde7ef1a796526c716aadaa5bccbe1db5ade49282b64a76` |
|
||||
| Go-builder | `1.27.1-bookworm` | `sha256:69a7b9788769bec032d238959b61854e9ae87f57be9029ec04e9885fabf99195` |
|
||||
| Go builder | `1.27.1-bookworm` | `sha256:69a7b9788769bec032d238959b61854e9ae87f57be9029ec04e9885fabf99195` |
|
||||
| Stellantis Vehicles | `2026.9.4` | `9e0ef96f8fe478af291da4c38c923ada78d0ebf6` |
|
||||
|
||||
Dockerfile og patches er build-opskriften. Supervisor henter det officielle
|
||||
CloakBrowser-image og bygger alene et lokalt image til intern brug.
|
||||
The Dockerfile and patches define the build. Supervisor downloads the official
|
||||
CloakBrowser image and builds a local image for internal use only.
|
||||
|
||||
## Licens
|
||||
## License
|
||||
|
||||
Repositoryets eget arbejde er MIT-licenseret; se [LICENSE](LICENSE). Dette
|
||||
omfatter ikke CloakBrowsers proprietære binær. Den er fortsat omfattet af den
|
||||
separate **CloakBrowser Binary License** og redistribueres ikke af repositoryet.
|
||||
The repository's original work is licensed under the MIT License; see
|
||||
[LICENSE](LICENSE). The proprietary CloakBrowser binary is not included. It
|
||||
remains subject to the separate **CloakBrowser Binary License**.
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
|
||||
## 0.1.0
|
||||
|
||||
- Fastlåser Stelloauth `v0.6.0` og CloakBrowser `0.5.10` til verificerede
|
||||
commits og OCI-digests.
|
||||
- Tilføjer fælles procesovervågning, readiness, watchdog og begrænset shutdown.
|
||||
- Dokumenterer intern Login service URL:
|
||||
- Pin Stelloauth `v0.6.0` and CloakBrowser `0.5.10` to verified commits and
|
||||
OCI digests.
|
||||
- Add shared process supervision, readiness checks, watchdog support, and a
|
||||
bounded shutdown.
|
||||
- Document the internal Login service URL:
|
||||
`http://0031621f-stelloauth:8080/worker`.
|
||||
- Begrænser CDP til loopback og hardener URL-validering, request-størrelse,
|
||||
rate limiting og logredigering.
|
||||
- Restrict CDP to loopback and harden URL validation, request size limits,
|
||||
rate limiting, and log redaction.
|
||||
|
||||
+67
-62
@@ -1,15 +1,15 @@
|
||||
# Installation og drift
|
||||
# Installation and operation
|
||||
|
||||
1. Gå til **Indstillinger → Tilføjelser → Tilføjelsesbutik → ⋮ →
|
||||
Repositorier**, og tilføj præcis
|
||||
1. Go to **Settings → Apps → Install app → ⋮ → Repositories** and add this
|
||||
exact URL:
|
||||
`https://git.radixadm.dk/dennis/homeassistant-stelloauth-addon.git`.
|
||||
|
||||
2. Installér **Stelloauth**, aktivér **Start ved opstart** og **Watchdog**, og
|
||||
start derefter add-onen. Installationen bygger et lokalt image fra kilde til
|
||||
den valgte `amd64`- eller `aarch64`-arkitektur. Repositoryet publicerer ikke
|
||||
et prebuilt image.
|
||||
2. Install **Stelloauth**, enable **Start on boot** and **Watchdog**, then start
|
||||
the app. Home Assistant builds a local image from source for the selected
|
||||
`amd64` or `aarch64` architecture. This repository does not publish a
|
||||
prebuilt image.
|
||||
|
||||
3. Vent, til loggen i denne rækkefølge viser de fem faste readiness-beskeder:
|
||||
3. Wait for the app log to show these five readiness messages in order:
|
||||
|
||||
```text
|
||||
Cleaning CloakBrowser profiles
|
||||
@@ -19,71 +19,76 @@
|
||||
Stelloauth listening on 0.0.0.0:8080
|
||||
```
|
||||
|
||||
4. Behold host-porten deaktiveret i normal drift. Ved kortvarig fejlfinding kan
|
||||
`8080/tcp` tilknyttes host-port `8080`. Kontrollér derefter
|
||||
`http://192.168.1.20:8080/` eller worker-endpointet
|
||||
`http://192.168.1.20:8080/worker`, og **deaktivér porttilknytningen igen**,
|
||||
når kontrollen er færdig. Worker-endpointet modtager MyOpel-oplysninger og
|
||||
har ingen egen autentificering.
|
||||
4. Keep the host port disabled during normal operation. For brief
|
||||
troubleshooting, map `8080/tcp` to host port `8080`. Then check
|
||||
`http://192.168.1.20:8080/` or the worker endpoint at
|
||||
`http://192.168.1.20:8080/worker`. **Disable the port mapping again** when
|
||||
you finish. The worker endpoint receives MyOpel details and has no separate
|
||||
authentication.
|
||||
|
||||
5. Åbn konfigurationen af **Stellantis Vehicles**. Angiv præcis
|
||||
`http://0031621f-stelloauth:8080/worker` som **Login service URL**.
|
||||
Integrationen tilføjer ikke `/worker`; hele stien skal derfor stå i feltet.
|
||||
5. Open the **Stellantis Vehicles** integration's configuration and set
|
||||
**Login service URL** to exactly
|
||||
`http://0031621f-stelloauth:8080/worker`. The integration does not append
|
||||
`/worker`, so include the full path.
|
||||
|
||||
6. Vælg **Brand: Opel** og **Country: DK**, og gennemfør derefter integrationens
|
||||
OAuth-opsætning med dine MyOpel-oplysninger.
|
||||
6. Select **Brand: Opel** and **Country: DK**, then complete the integration's
|
||||
OAuth setup with your MyOpel details.
|
||||
|
||||
7. Add-onens tre muligheder er:
|
||||
When asked for a security PIN, enter the four-digit PIN you chose when
|
||||
activating Remote Control in the MyOpel app. Do not wait for MyOpel to send
|
||||
you a new PIN; the SMS verification code is separate.
|
||||
|
||||
- `queue_timeout`: hvor længe et loginforsøg må vente på den ene session.
|
||||
- `rate_limit_count`: højeste antal loginforsøg i hver periode.
|
||||
- `rate_limit_duration`: længden af rate limit-perioden.
|
||||
7. The app provides three options:
|
||||
|
||||
`CLOAK_MAX_SESSIONS` er fastlåst til én session, fordi CloakBrowsers gratis
|
||||
niveau tillader ét samtidigt login. Samtidige forsøg bliver derfor køet.
|
||||
- `queue_timeout`: how long a login attempt may wait for the single session.
|
||||
- `rate_limit_count`: the maximum number of login attempts allowed in each
|
||||
period.
|
||||
- `rate_limit_duration`: the length of the login rate-limit period.
|
||||
|
||||
8. Hvert OAuth-forsøg får en midlertidig profil under `/tmp/cloakserve`.
|
||||
CloakBrowser rydder inaktive browserprocesser efter 30 sekunder, og
|
||||
process manageren rydder gamle profiler ved opstart. Credentials, cookies,
|
||||
tokens og OAuth-koder gemmes ikke i `/data`. CDP lytter kun på loopback
|
||||
`127.0.0.1:9222`, og logs bruger faste, redigerede hændelser uden email,
|
||||
passwords, URLs, koder eller tokens.
|
||||
`CLOAK_MAX_SESSIONS` is fixed at one because CloakBrowser's free tier allows
|
||||
one concurrent login. Additional attempts wait in the queue.
|
||||
|
||||
9. De målte resultater fra den reelle `linux/amd64`-kørsel under Rosetta var:
|
||||
8. Each OAuth attempt gets a temporary profile under `/tmp/cloakserve`.
|
||||
CloakBrowser removes inactive browser processes after 30 seconds, and the
|
||||
process manager removes old profiles at startup. Credentials, cookies,
|
||||
tokens, and OAuth codes are not stored in `/data`. CDP listens only on the
|
||||
loopback address `127.0.0.1:9222`. Logs use fixed, redacted messages and do
|
||||
not include email addresses, passwords, URLs, codes, or tokens.
|
||||
|
||||
- Image: 2,571,693,650 bytes (2.571 GB decimal / 2452.56 MiB).
|
||||
- Dokumenteret Task 4-måling: 121,5 MiB.
|
||||
- Stop: cirka 9.3 sekunder.
|
||||
- `amd64` runtime bestod under Rosetta; `aarch64` build bestod.
|
||||
- Mål-HAOS havde ved inspektionen approximately 4 GB free. Den knappe
|
||||
plads sammenholdt med image- og build-lag kan forhindre installationen;
|
||||
frigør plads først. Der er ikke verificeret en vellykket HAOS-installation.
|
||||
9. Measurements from a real `linux/amd64` run under Rosetta:
|
||||
|
||||
Der er ikke gennemført et live MyOpel-login.
|
||||
Login-flow RAM: not measured without real MyOpel credentials.
|
||||
- Image: 2,571,693,650 bytes (2.571 GB decimal / 2,452.56 MiB).
|
||||
- Documented Task 4 measurement: 121.5 MiB.
|
||||
- Stop time: about 9.3 seconds.
|
||||
- The `amd64` runtime passed under Rosetta; the `aarch64` build passed.
|
||||
|
||||
10. Fejlfinding og fjernelse:
|
||||
10. Troubleshooting and removal:
|
||||
|
||||
- Mangler en readiness-besked, så se efter timeout: CloakBrowser har 60
|
||||
sekunder og Stelloauth 30 sekunder. Ret årsagen og genstart add-onen.
|
||||
- Et ugyldigt eller ikke-tilladt authorize-URL giver HTTP `400`.
|
||||
- For mange loginforsøg giver HTTP `429`; vent den konfigurerede periode.
|
||||
- Hvis repository-URL eller hostname ændres, ændres Supervisor-repository-ID
|
||||
og dermed `0031621f-stelloauth`. Beregn og brug den nye interne URL.
|
||||
- Ved disk pressure: kontrollér fri plads og fjern unødvendige images eller
|
||||
backups via de normale Supervisor-funktioner før et nyt build.
|
||||
- Hvis den interne URL ikke kan nås, brug kun den midlertidige portkontrol
|
||||
fra trin 4 og deaktivér porttilknytningen bagefter.
|
||||
- Fjernelse sker i **Indstillinger → Tilføjelser → Stelloauth → Afinstallér**.
|
||||
Supervisor stopper containeren og fjerner add-onens lokale data; fjern
|
||||
også repositoryet fra Tilføjelsesbutikken, hvis det ikke længere bruges.
|
||||
- If a readiness message is missing, check for a timeout. CloakBrowser has
|
||||
60 seconds and Stelloauth has 30 seconds. Fix the cause, then restart the
|
||||
app.
|
||||
- An invalid or disallowed authorize URL returns HTTP `400`.
|
||||
- Too many login attempts return HTTP `429`; wait for the configured
|
||||
rate-limit period.
|
||||
- If the repository URL or hostname changes, the Supervisor repository ID
|
||||
and `0031621f-stelloauth` hostname also change. Calculate and use the new
|
||||
internal URL.
|
||||
- If disk space is low, check available space and remove unneeded images or
|
||||
backups through Supervisor before building again.
|
||||
- If the internal URL cannot be reached, use the temporary port check from
|
||||
step 4, then disable the port mapping again.
|
||||
- To remove the app, go to **Settings → Apps → Stelloauth → Uninstall**.
|
||||
Supervisor stops the container and removes the app's local data. If you
|
||||
no longer need the repository, remove it from **Settings → Apps → Install
|
||||
app → ⋮ → Repositories** as well.
|
||||
|
||||
## Kilder og licenser
|
||||
## Sources and licenses
|
||||
|
||||
Add-on-version `0.1.0` bygger Stelloauth `v0.6.0` fra commit
|
||||
`367d4f8c02a3b072c59142c49dffc129edc8548b` og bruger det officielle
|
||||
CloakBrowser `0.5.10`-image ved OCI index digest
|
||||
App version `0.1.0` builds Stelloauth `v0.6.0` from commit
|
||||
`367d4f8c02a3b072c59142c49dffc129edc8548b` and uses the official CloakBrowser
|
||||
`0.5.10` image at OCI index digest
|
||||
`sha256:2ed5b2d047cbdde22cde7ef1a796526c716aadaa5bccbe1db5ade49282b64a76`.
|
||||
Repositoryets egne filer og patches er MIT-licenserede. CloakBrowsers
|
||||
proprietære binær er fortsat under den separate **CloakBrowser Binary License**;
|
||||
den er ikke MIT-licenseret eller redistribueret af dette repository.
|
||||
The repository's original files and patches are licensed under the MIT License.
|
||||
The proprietary CloakBrowser binary remains subject to the separate
|
||||
**CloakBrowser Binary License**. It is not licensed under MIT or redistributed
|
||||
by this repository.
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# Stelloauth
|
||||
|
||||
Lokal OAuth-worker til integrationen Stellantis Vehicles. Add-onen bygger
|
||||
Stelloauth `v0.6.0` og CloakBrowser `0.5.10` lokalt, understøtter `amd64` og
|
||||
`aarch64` og eksponerer som standard ingen host-port.
|
||||
A local OAuth worker for the Stellantis Vehicles integration. This app builds
|
||||
Stelloauth `v0.6.0` and CloakBrowser `0.5.10` locally, supports `amd64` and
|
||||
`aarch64`, and exposes no host port by default.
|
||||
|
||||
Se [den fulde installations- og fejlfindingsvejledning](DOCS.md).
|
||||
See the [installation and troubleshooting guide](DOCS.md).
|
||||
|
||||
CloakBrowsers binær er under den separate CloakBrowser Binary License og er
|
||||
ikke omfattet af repositoryets MIT-licens.
|
||||
The CloakBrowser binary is covered by the separate CloakBrowser Binary License,
|
||||
not by this repository's MIT License.
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
configuration:
|
||||
queue_timeout:
|
||||
name: Køventetid
|
||||
description: Angiver hvor længe et loginforsøg må vente i køen.
|
||||
name: Queue timeout
|
||||
description: Sets how long a login attempt may wait in the queue.
|
||||
rate_limit_count:
|
||||
name: Loginforsøg
|
||||
description: Angiver det maksimale antal loginforsøg i hver periode.
|
||||
name: Login attempts
|
||||
description: Sets the maximum number of login attempts in each period.
|
||||
rate_limit_duration:
|
||||
name: Rate limit-periode
|
||||
description: Angiver periodens længde for begrænsning af loginforsøg.
|
||||
name: Rate limit period
|
||||
description: Sets the length of the login attempt rate-limit period.
|
||||
|
||||
@@ -7,4 +7,4 @@ configuration:
|
||||
description: Sets the maximum number of login attempts in each period.
|
||||
rate_limit_duration:
|
||||
name: Rate limit period
|
||||
description: Sets the length of the login attempt rate limit period.
|
||||
description: Sets the length of the login attempt rate-limit period.
|
||||
|
||||
@@ -55,45 +55,51 @@ def test_user_guide_documentation_contract() -> None:
|
||||
documentation = (ROOT / "stelloauth/DOCS.md").read_text(encoding="utf-8")
|
||||
for required_text in (
|
||||
REPOSITORY_URL,
|
||||
"Installér **Stelloauth**",
|
||||
"aktivér **Start ved opstart** og **Watchdog**",
|
||||
"Settings → Apps → Install app → ⋮ → Repositories",
|
||||
"Install **Stelloauth**",
|
||||
"enable **Start on boot** and **Watchdog**",
|
||||
"http://0031621f-stelloauth:8080/worker",
|
||||
"http://192.168.1.20:8080/worker",
|
||||
"Brand: Opel",
|
||||
"Country: DK",
|
||||
"Image: 2,571,693,650 bytes (2.571 GB decimal / 2452.56 MiB).",
|
||||
"Dokumenteret Task 4-måling: 121,5 MiB.",
|
||||
"Stop: cirka 9.3 sekunder.",
|
||||
"approximately 4 GB free",
|
||||
"Der er ikke gennemført et live MyOpel-login.",
|
||||
"Login-flow RAM: not measured without real MyOpel credentials.",
|
||||
"Image: 2,571,693,650 bytes (2.571 GB decimal / 2,452.56 MiB).",
|
||||
"Documented Task 4 measurement: 121.5 MiB.",
|
||||
"Stop time: about 9.3 seconds.",
|
||||
"**Settings → Apps → Stelloauth → Uninstall**",
|
||||
):
|
||||
assert required_text in documentation
|
||||
assert "deaktivér porttilknytningen igen" in documentation
|
||||
assert "Seneste idle RAM" not in documentation
|
||||
assert "Disable the port mapping again" in documentation
|
||||
assert "approximately 4 GB free" not in documentation
|
||||
assert "successful HAOS installation has not been verified" not in documentation
|
||||
|
||||
|
||||
def test_root_readme_repository_source_and_license_facts() -> None:
|
||||
readme = (ROOT / "README.md").read_text(encoding="utf-8")
|
||||
for required_text in (
|
||||
REPOSITORY_URL,
|
||||
"Settings → Apps → Install app → ⋮ → Repositories",
|
||||
"v0.6.0",
|
||||
"367d4f8c02a3b072c59142c49dffc129edc8548b",
|
||||
"0.5.10",
|
||||
"f04c23da285b3b3d3cf10c8f9d282e7adc1d52ce",
|
||||
"CloakBrowser Binary License",
|
||||
"MIT-licenseret",
|
||||
"licensed under the MIT License",
|
||||
):
|
||||
assert required_text in readme
|
||||
assert "Indstillinger" not in readme
|
||||
assert "Installér" not in readme
|
||||
|
||||
def test_translations_cover_every_option() -> None:
|
||||
keys = set(load_yaml("stelloauth/config.yaml")["options"])
|
||||
translations = {}
|
||||
for language in ("da", "en"):
|
||||
translation = load_yaml(f"stelloauth/translations/{language}.yaml")
|
||||
assert set(translation["configuration"]) == keys
|
||||
translations[language] = translation["configuration"]
|
||||
for entry in translation["configuration"].values():
|
||||
assert set(entry) == {"name", "description"}
|
||||
assert all(isinstance(value, str) and value.strip() for value in entry.values())
|
||||
assert translations["da"] == translations["en"]
|
||||
|
||||
|
||||
def test_dockerfile_uses_approved_pins_and_builds_patched_stelloauth() -> None:
|
||||
@@ -277,6 +283,9 @@ def test_runtime_requires_process_baseline_after_cdp_close_and_zero_stopped_pid(
|
||||
assert mapping_index < ready_index < baseline_index < close_index < return_index
|
||||
assert "{{.State.Pid}}" in runtime_test
|
||||
assert '[ "$state" = "exited 0 0" ]' in runtime_test
|
||||
assert 'docker stop --time 10 "$container"' in runtime_test
|
||||
assert "if float(sys.argv[1]) > 12.0:" in runtime_test
|
||||
assert "container stop exceeded 12 seconds" in runtime_test
|
||||
|
||||
|
||||
def test_runtime_process_normalization_retains_every_unknown_wrapped_child(
|
||||
|
||||
@@ -345,8 +345,8 @@ PY
|
||||
printf 'seconds=%s\n' "$elapsed" > "$timing_artifact"
|
||||
python3 - "$elapsed" <<'PY'
|
||||
import sys
|
||||
if float(sys.argv[1]) > 10.0:
|
||||
raise SystemExit(f"container stop exceeded 10 seconds: {sys.argv[1]}")
|
||||
if float(sys.argv[1]) > 12.0:
|
||||
raise SystemExit(f"container stop exceeded 12 seconds: {sys.argv[1]}")
|
||||
PY
|
||||
state="$(docker inspect --format '{{.State.Status}} {{.State.ExitCode}} {{.State.Pid}}' "$container")"
|
||||
[ "$state" = "exited 0 0" ] || fail "$container state is $state, want exited 0 with PID 0"
|
||||
|
||||
Reference in New Issue
Block a user