Einfacher Unix-Chat
(the-dam.org)sucist Simple Unix Chat, eine Umsetzung einiger Kernfunktionen von Slack- oder Mattermost-artigem Chat mit UNIX-Grundbausteinen und Bash; die Kernschleife umfasst 5 Zeilen, das tatsächliche Skript ist jedoch länger- Nachrichten werden zeilenweise von der Standardeingabe gelesen, mit Datum und Benutzername versehen und an eine Kanaldatei unter
/var/lib/suc/angehängt; Authentifizierung und Zugriffskontrolle werden SSH und dem UNIX-Rechtemodell überlassen - Im Gegensatz zum Mattermost-Server, der allein rund 500.000 Zeilen Go-Code umfasst, betont
suc, dass sich ein ähnliches Kernverhalten mit deutlich weniger Code bauen lässt usuckombinierttail -f,rlwrap,pygmentizeund das Befehlspräfix:, um Kanäle zu lesen, Ausgabe im Markdown-Stil und das Teilen von Befehlsergebnissen zu unterstützen- Da Kanäle einfache Textdateien sind, lassen sie sich leicht mit UNIX-Tools wie
grep,tail,bat,lnav, Git-Hooks und Bot-Skripten verbinden
Die Komplexität, die suc reduzieren will
sucsteht für Simple Unix Chat; es bietet weniger Funktionen als Slack, Mattermost oder IRC und umfasst insgesamt mehr als 5 Zeilen, doch die Kernschleife zum Schreiben von Nachrichten besteht aus 5 Zeilen Bash- Die Zielfunktionen sind Echtzeit-Chat mit Rich Text, Filesharing, feingranulare Zugriffskontrolle, Automatisierung und Integration externer Tools, Verschlüsselung während der Übertragung, optionale Verschlüsselung im Ruhezustand sowie Benutzerauthentifizierung
- Die kleine Implementierung ist möglich, weil sie die konsistenten und kombinierbaren Grundbausteine nutzt, die moderne UNIX-Implementierungen bereitstellen
- Der Mattermost-Server dient als Kontrast mit allein rund 500.000 Zeilen Go-Code;
sucgeht davon aus, Mattermost-Kernfunktionen mit 0,005 % dieses Codes umsetzen zu können
Die 5-zeilige Schleife zum Schreiben von Nachrichten
- Die zentrale Bash-Schleife von
sucliest eine Zeile von der Standardeingabe, fügt Datum und tatsächlichen Benutzernamen hinzu und hängt sie an die Datei/var/lib/suc/"$1"an - Das tatsächliche Skript ist wegen sicherheitsbezogener Vorverarbeitung und der Berechnung von Farben für Benutzernamen länger, doch die Kernhandlung zum Schreiben des Chatverlaufs lässt sich in drei Punkte zusammenfassen
- Eine Zeile von der Standardeingabe lesen
- Datum und tatsächlichen Benutzernamen hinzufügen
- An eine Kanaldatei unter
/var/lib/suc/anhängen
- Authentifizierung, Zugriffskontrolle, Verschlüsselung und Rich Text werden nicht durch Code innerhalb von
sucselbst erledigt, sondern durch SSH, UNIX-APIs zur Zugriffskontrolle und textbasierte Modularität
SSH übernimmt die Authentifizierung
- Da der
suc-Prozess von einem bereits authentifizierten Benutzer ausgeführt wird, enthältsucselbst keinen Authentifizierungscode - Remote-Authentifizierung wird wie bei einem üblichen UNIX-Server von
ssherledigt- Geteilte Geheimnisse wie Passwörter
- Kryptografische Challenges
- Geräte zur Erzeugung von Einmalpasswörtern (OTP)
- MFA als Kombination mehrerer Verfahren
sshauthentifiziert auch den Server gegenüber dem Client, verhindert so Man-in-the-Middle-Angriffe und verschlüsselt sämtliche Daten zwischen Client und Server- Eine
suc-Installation hängt von einem UNIX-Host und der Konfiguration desssh-Servers ab- Der Benutzer muss im System existieren
- Der
ssh-Server muss Remote-Logins für diesen Benutzer erlauben
- In GNU Guix lassen sich Benutzer und SSH-Schlüssel mit einer deklarativen Konfiguration in einer Zeile hinzufügen; verschwindet die Konfigurationszeile, wird der Benutzer beim Rekonfigurieren entfernt
Das UNIX-Rechtemodell übernimmt die Zugriffskontrolle
sucenthält neben Authentifizierung auch keinen Code für Zugriffskontrolle; dieser Ansatz wird Sicherheitsagnostizismus (security agnosticism) genannt- Der UNIX-Kernel kennt Benutzer, Gruppen, Prozesse und Dateien und entscheidet anhand des effektiven Besitzers (effective owner) eines Prozesses, ob Dateien gelesen oder geschrieben werden dürfen
- Die Kanaldateien unter
/var/lib/sucgehören dem Benutzersuc; über gruppenbasierte Leserechte wird festgelegt, dass Benutzer bestimmte Kanäle lesen können - Normale Benutzer schreiben nicht direkt in die Dateien, sondern führen
sucaus; Berechtigungsabgleich und Sperren übernimmt der Kernel - In stärker eingeschränkten Communitys können gruppenspezifische
setuid-Binaries bereitgestellt werden- Zum Beispiel gehört
suc_bluedem Benutzerblueund ist nur von der Gruppeblueausführbar - Benutzer der Gruppe
bluekönnen übersuc_bluein den Kanalblueschreiben - Benutzer der Gruppe
redkönnen den Kanalblueweder lesen noch beschreiben
- Zum Beispiel gehört
- Das Hilfsskript zur Kanalerstellung
suc_channel.shumfasst rund 80 Zeilen; Nutzer von GNU Guix können mit einer einzigen Zeile(suc-private-channel "red" "red")die benötigten setuid-Binaries, Benutzer, Gruppen und Kanaldateien erzeugen - Transaktionale Updates in GNU Guix garantieren, dass Konfigurationsänderungen entweder vollständig oder gar nicht angewendet werden, und ermöglichen ein Rollback auf einen früheren funktionierenden Zustand
Rich Text und usuc
- Viele Chat-Apps rendern Text mit einer HTML-Engine; der Mattermost-Desktop-Client verwendet Electron
sucnutzt pro Kanal eine Textdatei, die Benutzer mit Kommandozeilenwerkzeugen wietailodercatansehen können- Mit ANSI-Escape-Codes und UTF-8-Unterstützung im Terminal lassen sich Farben, Emoji und eine grundlegende Rich-Text-Erfahrung erzeugen
sucschreibt nur in Kanaldateien; das Lesen übernimmtusucsucist ein privilegiertes Binary, daher sollten Logik und externe Abhängigkeiten minimal bleibenusucläuft mit den Rechten des aufrufenden Benutzers, sodass dort freier Funktionen eingebaut werden können
usucverknüpft mehrere kleine Tools und fungiert so als Chat-Clientrlwrapstellt Verlauf und Zeilenbearbeitung bereit- Auswahl des passenden setuid-
suc-Binary anhand des Besitzers der Kanaldatei - Anzeige der letzten 20 Zeilen und danach angehängter Zeilen mit
tail -f -n 20 - Prüfung, ob eine Eingabezeile mit
:beginnt - Verarbeitung des vom Benutzer eingegebenen Texts mit
pygmentize
pygmentizeinterpretiert die Standardeingabe als Markdown und gibt ANSI-farbigen Text aus; Markup wie**bold**lässt sich so mit einer einzigen Codezeile unterstützen
Chat-Befehle und Shell-Integration
- Wenn eine Nachricht mit
:beginnt, sendetusucsie nicht als normale Nachricht, sondern führt den entsprechenden Befehl aus und sendet die Ausgabe ansuc - Wird zum Beispiel
gum style --border=rounded --bold --foreground=#F00 "Hello World !"ausgeführt, erscheint Text mit Rahmen und Stil im Kanal - Befehle laufen im Namespace des Benutzers, der
usucaufgerufen hat; Nutzer können daher eigene Chat-Makros haben, ohne andere Nutzer zu beeinflussen - Bei the dam wird dies während Tabletop-Rollenspielen verwendet, um mit Befehlen wie
roll 2d6Würfel zu werfen
Text-Pipes und Integration externer Tools
- Statt der Befehlsausführung von
usuckönnen Benutzer die Ausgabe von Befehlen direkt aus der Shell insucpipen - Wenn die farbige Ausgabe von
batansucgesendet wird, lassen sich Codeausschnitte mit Syntax-Highlighting im Kanal teilen make test > testlog || (suc devops < testlog ; exit 1)ist ein Bash-Einzeiler, der bei fehlgeschlagenen Tests das Log an den Kanaldevopssendet- Dieser Einzeiler kann in einen
update-Hook eines Git-Repositorys aufgenommen werden; beim Push werden Tests ausgeführt, und bei einem Fehlschlag wird das Update abgelehnt und das DevOps-Team benachrichtigt - Aufgaben, die Integrationen in Slack oder Mattermost entsprechen, lassen sich mit UNIX-Text-Pipes und Skripten umsetzen
Kanäle lesen, Benachrichtigungen, Bots
suc-Kanäle sind laufend aktualisierte Textdateien, sodass neue Zeilen mittail -fgelesen und verarbeitet werden können- Wenn eine neue Nachricht erscheint, lässt sich eine Pipeline bauen, die mit
notify-sendeine Benachrichtigung anzeigt; mitgrepkann nur nach Namen oder Schlüsselwörtern wie „build failure“ gefiltert werden - Um mehrere Kanäle zu einem Feed zusammenzuführen, kann
tail -f /var/lib/suc/*verwendet werden - Mit lnav lassen sich Lesepositionen merken, Lesezeichen setzen, Kanalfarben nutzen, Datum, Benutzername und benutzerdefinierte Felder parsen, filtern und SQL-Abfragen ausführen
- Bots sind implementierbar, wenn sie einen Kanal lesen und gleichzeitig schreiben können
- Ein Beispiel sucht im Kanal nach Längenangaben wie
33000 ft - Es konvertiert sie mit dem Befehl
unitsin Meter - Es schreibt eine Antwort wie
[metric_bot] 33000 ft is 10058.4 meters.in denselben Kanal
- Ein Beispiel sucht im Kanal nach Längenangaben wie
Vergleich und Fazit
- Als Vergleich dienen große Systeme wie Slack, Mattermost und Discord, doch fairere Vergleichsmaßstäbe umfassen auch IRC,
talkundwrite - IRC wird als funktionsärmer als
sucbewertet, weil zum Lesen vergangener Chatverläufe ein Bouncer benötigt wird talk,ytalkundwallließen sich demnach auf modernen Linux-Distributionen nicht zum Laufen bringensucüberlässt Authentifizierung SSH, Zugriffskontrolle und Kombinierbarkeit UNIX und hält Kanäle als Textdateien vor- Tools können in jeder Sprache geschrieben werden, solange sie Text lesen und schreiben können
1 Kommentare
Hacker-News-Meinungen
Musste sofort an „Master Foo and the Ten Thousand Lines“ denken: http://catb.org/~esr/writings/unix-koans/ten-thousand.html
Darin erzählt Master Foo einem besuchenden Programmierer, dass „eine Zeile Shell-Skript mehr Unix-Wesen enthält als 10.000 Zeilen C“
Wenn sich die festgelegte Kernfunktion von etwas zu leicht und banal nachbauen lässt, ist diese Funktion möglicherweise nicht der eigentliche Kern oder Ursprung des Werts
Ich frage mich, wie viel der UI-Entwicklung seit den 1980ern von der Softwaretechnik aufgenommen und automatisiert wurde und wie viel noch immer im Bereich reiner menschlicher Kunst liegt
Schon bevor Slack aufkam und andere verdrängte, gab es sowohl kommerziell als auch als Open Source bereits Dutzende Apps, die genau das taten
Der eigentliche Wert von Slack liegt im nächsten Schritt: Es bietet eine optisch ansprechende und sehr intuitive UI/UX, sodass fast jeder sich hinsetzen und sofort loslegen kann, ohne Einarbeitung, Konfiguration, Handbuch oder Schulung. Man braucht kein technisches Wissen, und alles außer „Benutzername und Passwort eingeben“ wirkt selbsterklärend
Aber dann stellt sich die schwierigere Frage: Ist der Preis von Slack es wert im Vergleich zu der Alternative, Benutzer weiter zu schulen, die bereits einen sehr grundlegenden Kommandozeilenaufruf beherrschen? Und wie sieht es aus, wenn man berücksichtigt, dass Slack die Daten festhält und nicht wieder herausgibt? Wie teuer ist der Ausstieg aus Slack?
suc ist zwar unbequem, aber vielleicht könnte es sich zu etwas entwickeln, das weniger aufgebläht und weniger proprietär ist als Slack
Das Ergebnis an sich gefällt mir. Es ist großartig zu sehen, was man mit Komponierbarkeit bauen kann
Der Vergleich mit Slack und Ähnlichem überzeugt mich allerdings nicht. Kein Ingenieur würde so ein zusammengeflochtenes Konstrukt in der Produktion verantworten wollen. Wie will man dafür Leute einstellen, wie testen und debuggen, wie Logging und Analytik machen?
Der Artikel dupliziert zwar einen Teil der Chat-Funktionalität von Slack-artigen Apps, aber Chat ist nicht 100 % solcher Apps. Diese Dinge wurden in völlig unterschiedlichen Umgebungen gebaut, und den Status quo deshalb als aufgebläht anzugreifen wirkt wie eine Stockton-Rush-artig verdrehte Auslegung. Software hat durchaus Bloat, aber „Schaut mal, ich habe aus Gerümpel ein U-Boot gebaut, also sind teure U-Boote dumm“ klingt nicht wie die Widerlegung, die der Autor beabsichtigt hat
Einzelne Utilities lassen sich normalerweise separat leichter verstehen, testen und debuggen, und Logging ist ohnehin schon im System vorhanden. Gibt es nicht syslog? Und warum braucht man überhaupt Analytik?
Trotzdem würde mich wirklich interessieren, wie ein Slack-artiges Tool aussähe, wenn es Einfachheit aggressiv über neue Features stellen würde. Der Kapitalismus als Ganzes scheint solche Entwicklung nicht zu fördern, daher gibt es nicht viele Beispiele für Unternehmenssoftware, die so einfach ist, wie vernünftigerweise möglich. Als Gedankenexperiment ist es aber interessant
Ähnlich gibt es auch ii, das direkt auf IRC läuft: https://tools.suckless.org/ii/
Es nutzt für alle Unterhaltungen eine einzige Standarddatei, Authentifizierung und Zugriffskontrolle werden direkt vom IRC-Netzwerk verwaltet, und es gibt bereits viele UIs. Genau wie hier können Plugins alles sein, was irgendeine Datei liest und in eine andere Datei schreibt
Es wäre lustig, ein spawn-of-unix-Diagramm zu machen, das Startups versammelt, die Nischen aus Unix-Funktionalität herausgeschnitten haben, ähnlich wie dieses Craigslist-Diagramm
https://thegongshow.tumblr.com/post/345941486/the-spawn-of-craigslist-like-most-vcs-that-focus
ftp/rsync => Dropbox
suc => Slack
...
Wenn der Titel wie Clickbait wirkt und man deshalb weiterscrollen will: Ein gewisser Clickbait-Faktor ist schon da, aber tatsächlich war es ein ziemlich guter Artikel.
Es geht um ein Utility namens „suc“ (Simple Unix Chat), das mit einer sehr kleinen Codebasis Server-Funktionen wie bei Slack oder Discord umsetzt.
Das Neue daran ist, dass es bestehende Unix-Tools und -Methoden nutzt, statt sie neu zu erfinden. Authentifizierung übernimmt SSH, Channels sind einfach Dateien, und Admin-/Moderator-Kontrolle wird über Benutzergruppen und Dateiberechtigungen geregelt. Formatierten Text oder Datei-Uploads kann man ebenfalls abbilden, indem man die gewünschten Daten in den Channel schreibt und der Client sie interpretieren lässt. Auch Bots sind sehr einfach, wenn man Pipes mit den Channel-Dateien verbindet.
Mit den im Artikel gezeigten fünf Zeilen zum Schreiben von Nachrichten in einen Channel baut man zwar keinen perfekten Slack-Klon, aber es ist schon ziemlich beeindruckend, wie weit man mit wirklich simplen Unix-Tools kommen kann.
Dass es praktisch keine großen Produktionssysteme gibt, die nach dem Paradigma „alles ist eine Datei“ und mit Shell-Skripten gebaut sind, hat einen Grund. Für nichttriviale Systeme, die in der realen Welt eingesetzt werden sollen, ist das in inakzeptabler Weise ungeeignet.
Dazu gehören ein Admin-UI, ein User-Management-UI, Skalierbarkeit, Webhooks usw. Mit „wenn sich alle auf diese Box einloggen, können sie unter Linux mit anderen Benutzern chatten“ wird nichts davon gelöst. Solche Funktionen gab es auf allen *nix-Systemen schon, bevor die meisten Leser hier geboren wurden.
Leider wurde diese Plan-9-Funktion bisher noch nicht auf Linux portiert. Das sind Berechtigungsbits ähnlich wie „Lesen“ oder „Schreiben“, aber viel spezifischer.
Das ist kein Vorwurf an den Autor; im Artikel wird das auch sehr ehrlich offengelegt.
Slack und Discord haben Bildschirmfreigabe und Sprachchat. Das sind keine Zusatzfunktionen, sondern ziemlich entscheidende Features für ihre Marktbeherrschung.
Auch wenn von Anfang an ehrlich eingeräumt wird, dass sich dieser Blogpost um suc dreht und der Titel etwas irreführend sein kann, bleibt am Ende eine wichtige Botschaft, die nicht direkt mit suc zu tun hat.
Fast jede moderne Software ist absurd aufgebläht. Die Vorstellung, dass ein funktionsreicher Chat-Server 1,7 Millionen Zeilen braucht, ist lächerlich. Um es im Stil von Bill Gates zu sagen: Selbst wenn ich es versuchte, könnte ich in einem Chat-Server wohl kaum so viele Codezeilen „verbrauchen“.
Nicht nur dafür, das Problem anzusprechen oder Alternativen zu zeigen, sondern auch dafür, daran zu erinnern, dass man das Rad nicht neu erfinden muss, gibt es Applaus. Die Eigenschaften bestehender Systeme und Subsysteme klug zu nutzen — etwa SSH für Authentifizierung und Verschlüsselung einzusetzen, auch wenn das nicht exakt der ursprünglich vorgestellte Einsatzzweck war, aber sehr wohl der beabsichtigten Eigenschaft entspricht — ist ein gutes Beispiel für den Hacker-Geist.
Hoffentlich kann die Software-Welt von diesem Konzept viel lernen. Niedrigere Kosten, kürzere Entwicklungszeiten und weniger verschwendete Engineering-Zeit für das erneute Schreiben funktional gleicher Logik sind gut für Entwickler und Unternehmen, für Endnutzer und letztlich für die Menschheit insgesamt. Ich würde gern mehr solcher kreativer Zerstörung sehen und solche cleveren Techniken auch in künftigen Projekten selbst anwenden.
Deshalb wäre es eigentlich richtiger, nur die Go-Codezeilen zu zählen.
[0] https://github.com/mattermost/mattermost/tree/master/e2e-tests
[1] https://github.com/mattermost/mattermost/tree/master/webapp
Das ist meistens eine gute Idee, weil es die Time-to-Market verbessert und die Größe der Organisation reduziert. Der Trade-off sind allerdings hohe Komplexität und zusätzliche Abstraktion. Je höher das Abstraktionsniveau, desto schlimmer kann es werden. Es ist also nicht völlig grundlos.
Derzeit verhindern die meisten Distributionen aus Sicherheitsgründen, dass man setuid-Bash-Skripte erstellen kann.
Mit einem bestimmten sudoers-Eintrag lässt sich aber fast derselbe Effekt erzielen.
uid != euidist.https://perldoc.perl.org/perlsec#Taint-mode
Auf manchen Systemen kann es eine grundlegende Race Condition geben:
https://perldoc.perl.org/perlsec#Shebang-Race-Condition
Auch
sudo -Tist in diesem Zusammenhang einen Blick wert:https://perldoc.perl.org/perlsec#Using-Sudo
Schade, dass der Taint-Modus kürzlich aus Ruby entfernt wurde. Taint-Tracking ist ein mächtiger Mechanismus, der weit über Skripte hinausgehen kann. Hätte man zum Beispiel
#html_safein Rack/Rails per Taint-Tracking behandelt, hätte das deutlich gründlicher funktioniert und hätte schon in dem Moment einen Fehler ausgelöst, in dem ein unsicherer Benutzer-String an ein SQL-Fragment angehängt, in dieses interpoliert oder dafür formatiert wird, sodass eine bestimmte Klasse von SQL-Injections bereits durch das Design verhindert worden wäre.Früher gab es auch Leute, die Taint-Tracking in CGI/mod_perl sehr effektiv eingesetzt haben. Es ist absolut kein Allheilmittel, aber immer noch ein ziemlich wirksames Werkzeug.
https://gitlab.com/edouardklein/suc/-/blob/master/suc_wrapper.c
Bis ich die Wrapper-Datei im GitLab-Repository gesehen habe, hatte ich beim Lesen gehofft, dass es dafür doch irgendeinen Weg gibt.
Das ist zwar ein anderes Thema, aber ich bin überrascht, dass talk(1) nicht erwähnt wurde: https://man.netbsd.org/talk.1
Das Gute daran ist, dass man den Empfang auf lokal beschränken kann; dann braucht man dafür ein Benutzerkonto auf dieser Maschine. Deshalb passt es gut zu Dingen wie SDF oder auch zu größeren Clustern. Die Authentifizierung muss man nicht selbst machen, sondern kann sie PAM oder BSD_Auth überlassen. Um Sockets oder Verschlüsselung muss man sich ebenfalls nicht selbst kümmern, sondern kann das TLS überlassen. Man kann sich auch per SSH in eine sichere Shell einloggen und dann tmux und (n)talk verwenden.
Natürlich ist (n)talk in C geschrieben und nicht in 5 Zeilen Bash.
[1] https://man7.org/linux/man-pages/man2/write.2.html