Blink antwortet mit 202 — und niemand kam hinein
Die Anmeldung scheiterte in der getesteten Fassung. Drei Tage später hatte das Projekt drei neue Versionen. Was dazwischen lag, war kein Code.
Inhalt
Im ersten Teil habe ich ein Projekt für halb eingeschlafen gehalten und mich geirrt. Der eigentliche Befund war nicht „niemand interessiert sich“, sondern „niemand kommt hinein“.
Hier steht, woran es lag. Es war eine dreistellige Zahl, die niemand abgefragt hat.
Der beworbene Weg funktionierte nicht
Die Anmeldung bei Blink verlangt eine PIN per SMS. Das Add-on sah dafür zwei Starts vor: Beim ersten wird die Anmeldung begonnen und die PIN kommt, beim zweiten trägt man sie ein.
Das funktionierte nie. Bei jedem Versuch kam die SMS, und bei jedem Versuch stand
anschließend Login failed.
Mein erster Fund war ein selbstgemachter: Die Optionsdatei hatte
Windows-Zeilenenden, und das Startskript las dadurch ein Zeichen zu viel. Ein
peinlicher Fehler, schnell behoben — und danach stand dasselbe Login failed
wieder da.
Der Befund, der endgültig schien
Nachgelesen im Quelltext: Die Anmeldung legt beim ersten Schritt zwei Werte im Arbeitsspeicher ab, die der zweite Schritt braucht. Startet der Dienst neu, sind sie weg.
if not hasattr(self, "_oauth_csrf_token") or not hasattr(self, "_oauth_code_verifier"):
_LOGGER.error("No OAuth 2FA state found. Start login flow first.")
return False
Damit ist die Zwei-Start-Anmeldung prinzipiell unmöglich. Nicht „geht gerade nicht“, sondern: Sie kann nicht gelingen, solange zwischen den beiden Schritten ein Neustart liegt.
Ich hielt das für den endgültigen Befund. Es war nur die halbe Antwort.
Die Beobachtung, die alles umwarf
Dann der Satz, der die Richtung änderte — und er kam nicht aus dem Quelltext, sondern aus dem Haus:
Beim zweiten Anlauf schickte Blink dieselbe PIN wie beim ersten.
Das ist kein Nebenbefund. Nicht die PIN verfällt — die Sitzung verfällt. Die PIN hängt am Konto und bleibt gültig; was fehlt, sind die beiden Werte aus dem Arbeitsspeicher.
Und daraus folgt sofort der einfachste Weg: Ist die PIN vorab bekannt, muss niemand auf einen zweiten Start warten.
Anmeldung -> 2FA verlangt -> PIN liegt bereit -> sofort eingelöst -> Token gespeichert
Kein Warteblock, kein zweiter Start. Die Wartelogik bleibt als Rückfall für den Fall, dass die PIN einmal nicht vorab bekannt ist.
Eine Beobachtung aus dem Alltag hat hier eine Codeanalyse geschlagen. Ich hatte den Quelltext gelesen und richtig verstanden — und trotzdem die falsche Schlussfolgerung gezogen, weil ich nicht wusste, dass die PIN gleich bleibt.
Und dann die Zahl
Mit einer zusätzlichen Diagnosezeile im Protokoll kam der fehlende Fakt:
oauth_signin HTTP 202
Login failed
Die verwendete Bibliothek kennt an dieser Stelle genau zwei Fälle:
if response.status == 412: return "2FA_REQUIRED"
elif response.status in [301,302,303,307,308]: return "SUCCESS"
return None # -> "Login failed"
Blink antwortet aber mit 202 Accepted — Zugangsdaten angenommen, 2FA-Code
verschickt. Dieser Fall fällt durch beide Prüfungen und wird als Fehlschlag
gemeldet.
Damit erklärt sich rückwirkend alles:
| Beobachtung | Erklärung |
|---|---|
| bei jedem Versuch kam eine SMS | die Anmeldung ging jedes Mal durch |
trotzdem stand jedes Mal Login failed |
202 wird nicht erkannt |
| dreimal dieselbe PIN | dieselbe offene Abfrage, nichts war gesperrt |
Die Anmeldung hatte nie versagt. Sie wurde nur falsch gelesen.
Eine Fehlermeldung, die „Login failed“ sagt, obwohl die Anmeldung erfolgreich war, schickt jeden Benutzer in die falsche Richtung. Man prüft Kennwörter, Konten, Sperren — und nichts davon ist das Problem.
Das ist der Grund, warum niemand hineinkam. Nicht fehlendes Interesse, sondern eine Statusabfrage, die einen dritten Fall nicht kennt.
Was dann passiert ist
Ich habe zwei Beiträge eingereicht. Was in den folgenden 72 Stunden geschah, hat meine Einschätzung aus Teil 1 endgültig erledigt:
| 30.08. | zwei Beiträge eingereicht |
| 31.08. | Betreuer führt acht Beiträge zusammen, v0.2.0, automatische Bauprüfung, Roadmap |
| 31.08. | einer meiner Beiträge „taken as written“ übernommen |
| 01.09. | ausführlicher Review zum zweiten, drei konkrete Punkte |
| 02.09. | ein zweiter, unabhängiger Prüfer testet vier Kameras aus meinem Zweig |
| 02.09. | v0.3.0, v0.4.0, v0.4.1 — neun Commits an einem Tag |
Drei Versionssprünge und ein zweiter unabhängiger Prüfer in drei Tagen.
Woraus der Schubs bestand — nicht aus Codemenge
Das ist der Teil, den ich am wichtigsten finde. Mein Anteil war kleiner, als die Wirkung vermuten lässt. Es war kein großer Beitrag und keine neue Funktion.
Was zählte, war zwei blockierende Fehler genau zu benennen, mitsamt dem Grund:
- Die Anmeldung scheiterte in der Fassung, die ich getestet habe — und warum: HTTP 202 statt 412, und die an die Sitzung gebundenen Werte.
- Der Videostrom bricht ab, bevor die Kamera überhaupt geweckt ist — und weshalb: weil Blinks Server an drei Stellen anders antwortet, als es die Protokollbeschreibung erwarten lässt.
Zwei Diagnosen, jede mit Protokollauszug und Quelltextstelle. Kein „geht nicht bei mir“, sondern „hier ist die Zeile, und hier ist, was stattdessen zurückkommt“.
Und was heißt das?
- Eine falsche Fehlermeldung ist teurer als gar keine.
Login failedbei erfolgreicher Anmeldung hat vermutlich mehr Leute vertrieben als jede fehlende Funktion. - Lies den Quelltext — aber glaub deiner Schlussfolgerung nicht sofort. Ich hatte alles richtig gelesen und war trotzdem auf dem Holzweg, bis eine Alltagsbeobachtung dazukam.
- Eine Beobachtung schlägt eine Analyse, wenn sie etwas zeigt, das im Code nicht steht. Dass die PIN gleich bleibt, steht nirgends geschrieben. Man sieht es nur, wenn man zweimal hinschaut.
- Ein präziser Fehlerbericht ist ein Beitrag. Man muss nichts programmieren, um ein Projekt voranzubringen. Man muss sagen können, woran genau es hakt.
- Prüf die Rückgabewerte, die nicht behandelt werden. Zwei Fälle abgefragt, alles andere als Fehler — das ist eine Falle, die in sehr viel Code steckt.
Im dritten Teil wird es unangenehm: Der Betreuer antwortet ausführlich — und berichtigt mich. Zu Recht.
Wenn du das verfolgen willst: nimm RSS
Kein Newsletter. Du gibst mir keine Adresse, ich führe keine Liste, und niemand muss einer Einwilligung zustimmen, um zu erfahren, dass ein Artikel fertig ist. RSS ist die ältere und für beide Seiten ehrlichere Lösung.
Wie das geht, und warum kein Newsletter
- 1Hol dir einen Feed-Leser. Ohne Konto geht das mit einer App am Telefon oder einer Erweiterung im Browser; wer mag, nimmt einen Dienst mit Konto.
- 2Trag die Adresse von oben dort ein.
- 3Fertig. Neue Artikel erscheinen von selbst in deinem Leser — ungelesen bleibt ungelesen, und nichts landet zwischen Rechnungen und Werbung im Postfach.
Warum das besser ist: Dein Leser holt die Datei ab. Ich bekomme keine Adresse und kann nicht sehen, wer liest oder ob jemand geöffnet hat. Abbestellen heißt, den Eintrag zu löschen — ohne Link, ohne Bestätigungsmail, ohne mich.