Es gab im ganzen Produkt kein Ereignis “ein neuer Bericht ist eingetroffen”. Benachrichtigungen erreichten ein Postfach und sonst nichts, also hatte ein Team, das seine Berichte in n8n, in Zapier oder in einem eigenen Skript haben wollte, nichts, worauf es zeigen konnte.

Jetzt gibt es ein Ziel: eine URL von Ihnen, die Ereignisse, die Sie wollen, und einen Signaturschlüssel. Vier Ereignisse, einmal benannt und überall wortgleich ausgegeben - report.created, report.status_changed, report.severity_changed und report.first_viewed. Sie sind vom Moment ihrer Auslieferung an eine Schnittstelle, denn jemand baut eines davon in einen Ablauf ein, und eine Umbenennung bricht ihn stillschweigend, also trägt die Nutzlast von der ersten Veröffentlichung an ihre eigene Version.

Was zu wissen sich lohnt, bevor Sie etwas darauf richten:

  • Jedes POST ist signiert. HMAC-SHA256 über den Zeitstempel und den rohen Rumpf, mit dem Zeitstempel innerhalb des signierten Materials, sodass eine abgefangene Anfrage später nicht gegen Sie wiederholt werden kann.
  • Das Ziel gehört dem Team, nicht einer Person. Die Adresse muss weiter funktionieren, wenn derjenige geht, der sie eingetragen hat.
  • Fehlschläge werden wiederholt und dann eingestellt. Der Backoff läuft etwa achteinhalb Stunden, bevor er aufgibt.
  • Jeder Versuch wird festgehalten. “Hat der Webhook ausgelöst?” lässt sich aus /app/webhooks beantworten und nicht aus den Produktionsprotokollen von irgendwem.

Eine vom Kunden angegebene URL ist von Natur aus eine Angriffsfläche für Request Forgery, deshalb wird die Adresse unmittelbar vor jeder Verbindung neu aufgelöst und neu geprüft statt nur beim Speichern, es wird nie einer Weiterleitung gefolgt, und der Antwortrumpf wird nur so weit gelesen, wie es zum Schließen des Streams nötig ist.

Die Seite, die ein Fremder öffnet

Die geteilte Berichtsseite ist ebenso sehr die Vorführung des Produkts wie das Sichtungswerkzeug ihres Besitzers, und die beiden wollen Verschiedenes vom selben Bildschirm.

Die Reihenfolge der Tabs war für den Besitzer entschieden: was der Melder geschrieben hat, kommt zuerst, weil es das Wertvollste in einem Bericht ist und das Kürzeste. Das ist richtig für jemanden, der sein eigenes Postfach abarbeitet, und falsch für den, an den der Link ging und der sieben Wörter vorfand, mit denen er nichts anfangen kann, während die Konsolenfehler, die fehlgeschlagenen Anfragen und die Aufzeichnung einen Klick entfernt und ungeöffnet lagen. Wer den Bericht nicht besitzt, landet jetzt bei den Belegen, und die Leiste über den Tabs sagt, was die Aufnahme enthält, statt es entdecken zu lassen.

Der Player selbst hatte zwei Fehler, beide auf einem einzigen Screenshot zu sehen. Seine dunkle Fläche zog sich über die volle Breite der Seite, sodass jede Aufzeichnung, die schmaler war als dieses Band - auf einem breiten Bildschirm die meisten -, verloren in der Mitte eines schwarzen Feldes saß. Und er öffnete pausiert auf dem Bild bei null, also auf dem, was auf dem Bildschirm des Melders zu sehen war, während dieser noch nach der Aufnahmetaste griff. Die dunkle Fläche ist jetzt Innenabstand am Medienelement selbst, sodass sie sich bei jedem Seitenverhältnis an die Aufzeichnung schmiegt, und der Player öffnet auf einem Bild, das ausgewählt wurde, weil es sich anzusehen lohnt.

Der Melder erfährt, was mit seiner Aufzeichnung geschieht

Das Interaktionsprotokoll weigert sich zu speichern, was jemand in ein Passwortfeld getippt hat. Das Netzwerkprotokoll schwärzt Zugangsdaten standardmäßig. Das Video zeigt den Bildschirm, auf dem sie getippt wurden, und nichts unternimmt etwas dagegen.

Dieselbe Frage, zwei verschiedene Antworten - und wer sie am besten entscheiden kann, ist der Melder, denn nur er weiß, ob der Kundendatensatz, der hinter dem Fehler offen steht, eine Rolle spielt. Also erfährt er jetzt, was aus der Aufzeichnung wird, bevor er sie startet, statt danach.

Derselbe Instinkt steckt hinter drei kleineren Änderungen auf der anderen Seite. Dass jemand seinen eigenen Bericht liest, hat noch nie für dessen Aufrufzahl gezählt, aber nirgends stand das; die Berichtsseite, die Berichtsliste und die Übersicht erklären jetzt jeweils, warum die Zahl ihn nicht mitzählt.

Session Replay

Kostenlose Chrome-Erweiterung. Ein Klick auf der Seite, die sich falsch verhält, erfasst den Screenshot, die Konsole und das Netzwerkprotokoll und gibt Ihnen einen Link, den Sie ins Ticket einfügen können.

Erweiterung holen

Die Aufnahme ist billiger geworden, und ihre Schwärzung einheitlich

Eine Aufnahme läuft mit dem Device Pixel Ratio des Bildschirms, solange nichts anderes gesagt wird, also nahm ein 6K-Bildschirm 6016 Pixel in der Breite auf. Diese Pixel wurden dreimal bezahlt: beim Hochladen durch den Melder, wo sie das Byte-Budget des Tarifs aufzehren und damit die Länge, die er aufnehmen darf; beim Speichern, weil das Original behalten wird, was auch immer daneben kodiert wird; und bei jedem Transcode, wo das Dekodieren die teure Hälfte ist. Auf der Produktion gemessen kostete ein zweiunddreißig Sekunden langer Clip neun Minuten und vierundfünfzig Sekunden CPU-Zeit. Die Aufnahme ist jetzt auf 1920 in der Breite gedeckelt.

Die Korrektur an der Schwärzung ist die wichtigere. Eine Domain, die zu ungeschwärzter Aufnahme berechtigt war, ließ die Maske für Header und Query-String auf die Kartennamen allein zusammenschrumpfen, sodass eine einzige Aufzeichnung ein Formularfeld namens api_key schwärzen konnte und zugleich einen X-Api-Key-Header, ein CSRF-Token und ein ?password= aus derselben Anfrage im Klartext behielt. Niemand hat das so gewählt: es waren zwei Wege durch eine Datei, die dieselbe Frage unterschiedlich beantworteten. Zugangsdaten in Headern und URLs werden auch auf einer berechtigten Domain maskiert, und ein Passfeld, das die Liste der Zugangsdaten verschluckt hatte, wird jetzt richtig erfasst.

Drei Dinge, die wir angekündigt hatten

Es lohnt sich, sie zusammen aufzuzählen, weil über jedes davon hier geschrieben wurde, bevor es getan war.

Die Erweiterung legt ihre Icons und Klänge nicht mehr für jede Herkunft offen. web_accessible_resources gab beide Verzeichnisse für alle URLs frei, und keine Seite hat je eines von beiden geladen - eine Erweiterung liest ihre eigenen mitgelieferten Dateien ohne jede Freigabe. Das war das Geschwister der ungenutzten Berechtigung, über die wir am Sonntag geschrieben haben, und beide sind jetzt weg; Erweiterung 1.6.2 steht im Store.

Die Integrationsbibliothek wird von unseren eigenen Seiten als 0.4.0 ausgeliefert, sodass identify() mit jedem Schlüssel, den auch ein Meta-Tag tragen kann, nicht länger nur für Leute gilt, die über npm installieren. Drei Stellen, die Seitenbetreibern noch sagten, es nehme fünf Schlüssel, sind korrigiert.

Und heute um halb eins in der Nacht hat der MCP-Server begonnen, beim Handshake zu sagen, dass der Text, den er weitergibt, von Dritten stammt: dass Kommentar, Titel, URL und Name eines Berichts von demjenigen geschrieben wurden, der den Fehler gemeldet hat, meist eine beliebige Person, und dass sie als Daten zu lesen und zu zitieren sind, nie als Anweisungen, denen man folgt. Wir haben das gestern eingetragen, gestützt auf die GhostSplice-Forschung, und darüber geschrieben, warum.

Kleinere Dinge

  • Der Inhaber des Abonnements entscheidet über dessen Kündigung und Fortsetzung.
  • Eine beanspruchte Domain heißt überall dort, wo die Oberfläche sie benennt, eine Domain, statt in der Hälfte der Fälle eine Website.
  • Artikelbilder hier können eine Bildunterschrift, einen Alternativtext und eine Größe tragen und passen in die Breite, die der Artikel ihnen gibt.
  • Die Seiten zu Bedingungen und Sicherheit sind in die sechs anderen Sprachen übersetzt, und jede statische Seite gibt jetzt an, in welcher Sprache sie tatsächlich geschrieben ist.
  • Die API gibt eine Sitzung pro Token aus statt einer pro Aktualisierung, und die Token-Seite liest sich als eine Zeile pro Token.