PasteBins und Quotas

Ich hatte längere Zeit einen kleinen Paste Daemon benutzt der pastecat heißt. Er war wunderbar. Hatte ein einfaches Interface mit Commandline Options, in Go geschrieben, globale Speicherplatzbegrenzungen, Max-Age Settings und ein einfaches Webinterface.

Was er leider nicht kann (und das mit Absicht) sind MIMETypes. Dafür interessiert sich der Daemon nicht und ist auch nicht im Scope. In Firefox endet das beim Anzeigen eines .png in einfach nur ASCII Kram auf dem Bildschirm des Users. In Safari und Chrome war das okay. In Firefox nicht.

Letztens war es dann wieder soweit. Ich schaute mich nach etwas anderem um. Alle Services auf der awesome-selfhosted Liste durchgewühlt wollte ich eigentlich schon wieder aufgeben, da fand ich in der Sektion “File Sharing and Synchronization” den Link zu linx-server. Es sah genau so aus wie ich mir das vorgestellt hab.

Nur lässt sie dem User etwas zu viel Raum zu bestimmen wie lange und wie viele Files hochgeladen werden.

Erstmal dem wie viel widmen. Puh. Ich glaube das letzte Mal als ich irgendwo ein Filesystem Quota gesetzt habe war 2010. Alles kommt ja irgendwie wieder.

Quota Option in die fstab hängen.

# vim /etc/fstab
fbc4391bb6b72c36.k /home ffs rw,nodev,nosuid,userquota=/var/quotas/home.user 1 2

Mit edquota die Größe (4GB) setzen (natürlich dem separaten User paste vorausgesetzt).

# edquota paste
Quotas for user paste:
/home: KBytes in use: 28990, limits (soft = 400000, hard = 400000)
        inodes in use: 61, limits (soft = 0, hard = 0)

Quota überprüfen

# quota -u paste
Disk quotas for user paste (uid 1006):
  Filesystem  KBytes    quota   limit   grace    files   quota   limit   grace
       /home   28990   400000  400000              61        0       0

Was das expiry Setting angeht (sprich: wie lange wird das File aufgehoben) kreisen meine Gedanken immernoch um verschiedene Möglichkeiten.

Ich möchte im Zweifel nicht dass irgendwelche Spammer Content hochladen und expire auf never setzen.

Anfangs hatte ich mit ein bisschen nginx Zauber experimentiert. Da die API einfach nur das HTTP Header Field Linx-Expiry zur Identifikation verwendet.

location / {
  proxy_pass http://127.0.0.1:5005/;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header Host $host;
  proxy_set_header Linx-Expiry 172800;
}

Das hat auch wunderbar funktioniert bis ich statt der API mal das Webinterface statt der API benutzt habe. Diese benutzt nämlich statt die eigene API, einen Post Request. Vergleiche

curl -H "Linx-Expiry: 172800" -H "Linx-Randomize: yes" -T $1 https://p.n0q.org/upload/

und

curl -X POST --data "expiry=86400&content=foo" https://p.n0q.org/upload

funktioniert beides, aber danach stellte sich heraus, dass HTTP POST Parameter überschreiben mit nginx editieren garnicht so einfach ist. Bzw nicht geht. Da in der Dokumentation hierzu klargestellt wird

The ngx_http_rewrite_module module is used to change request URI using PCRE regular expressions, return redirects, and conditionally select configurations.

Nun ist Linx ja OpenSource. Also Issues geöffnet und als Workaround erstmal die Expiry hardcoded selbst reingepatched.

diff --git a/upload.go b/upload.go
index b0bbd9f..0d66326 100644
--- a/upload.go
+++ b/upload.go
@@ -67,7 +67,7 @@ func uploadPostHandler(c web.C, w http.ResponseWriter, r *http.Request) {
     if r.Form.Get("randomize") == "true" {
       upReq.randomBarename = true
     }
-    upReq.expiry = parseExpiry(r.Form.Get("expires"))
+    upReq.expiry = parseExpiry("172800")
     upReq.src = file
     upReq.filename = headers.Filename
   } else {
@@ -81,7 +81,7 @@ func uploadPostHandler(c web.C, w http.ResponseWriter, r *http.Request) {
     }

     upReq.src = strings.NewReader(r.FormValue("content"))
-    upReq.expiry = parseExpiry(r.FormValue("expires"))
+    upReq.expiry = parseExpiry("172800")
     upReq.filename = r.FormValue("filename") + "." + extension
   }

@@ -163,7 +163,7 @@ func uploadRemote(c web.C, w http.ResponseWriter, r *http.Request) {
   upReq.src = resp.Body
   upReq.deletionKey = r.FormValue("deletekey")
   upReq.randomBarename = r.FormValue("randomize") == "yes"
-  upReq.expiry = parseExpiry(r.FormValue("expiry"))
+  upReq.expiry = parseExpiry("172800")

   upload, err := processUpload(upReq)

@@ -194,7 +194,7 @@ func uploadHeaderProcess(r *http.Request, upReq *UploadRequest) {
   upReq.deletionKey = r.Header.Get("Linx-Delete-Key")

   // Get seconds until expiry. Non-integer responses never expire.
-  expStr := r.Header.Get("Linx-Expiry")
+  expStr := "172800"
   upReq.expiry = parseExpiry(expStr)

 }

Beide Probleme erstmal gelöst. Es soll durchaus Menschen geben die ihren Paste Service ohne Expiry und Limits betreiben, aber irgendwie hab ich mich dann etwas reingesteigert :P Trotzdem was gelernt.

OpenBSD Login Classes

Mit Login Classes lassen sich allerhand Limitierungen für Benutzer und Gruppen in OpenBSD regeln. Wer also bei seinem Webserver auf das OpenFiles Limit läuft oder beim Compilen von Software XY einen OutOfMemory Fehler bekommt sollte sich das mal anschauen. Hier lassen sich auch Authentication Methods und ganz viel anderer Kram definieren. Die Manpage würde ich jedem mal empfehlen.

$ doas vim /etc/login.conf
staff:\
    :umask=022:\
    :datasize-max=1024M:\
    :datasize-cur=1024M:\
    :maxproc-max=1024:\
    :maxproc-cur=1024:\
    :openfiles-cur=2048:\
    :openfiles-max=2048:\
    :stacksize-cur=4M:\
    :localcipher=blowfish,8:\
    :tc=auth-defaults:\
    :tc=auth-ftp-defaults:

Aber welche Klasse hat mein User eigentlich? Dafür gibt es eine extra Spalte in der /etc/passwd.

    $ userinfo noqqe
    login   noqqe
    passwd  *
    uid     1001
    groups  noqqe wheel
    change  NEVER
    class
    gecos   ,,,
    dir     /home/noqqe
    shell   /usr/local/bin/bash
    expire  NEVER

Aha. Keine also. Wie assigne ich meinem User so eine Grouppe? Mit chsh. Das geht bestimmt auch noch anders, aber in dem meinsten Fällen arbeite ich mit dem Tool.

$ chsh noqqe
...
class: staff
...

Gut. Nachdem mir die Werte immernoch nicht gefallen, muss ich die login.conf doch noch anpassen. Einfach die Gruppe an sich editieren und das DB File neu bauen.

    $ vim /etc/login.conf
    # build new db
    $ sudo cap_mkdb /etc/login.conf

Erstmal stehts da jetzt. Ob das auch wirklich geklappt hat (zumindest die Formatierung des Files) kann man überprüfen in dem man ein bestimmtes Attribut einer Klasse überprüft.

    $ getcap -f /etc/login.conf -s openfiles-max staff
    4096

Alles klar, das hat geklappt. Das unangenehme bei der Sache ist, dass das neue Limit erst beim nächsten Login greift. Also neue ksh starten reicht nicht. Es muss ein neues TTY her. Bei Daemons wusste ich mir bisher nicht anders zu helfen, als kurz zu rebooten. Irgendwelche Ideen?

    $ ulimit -a
    core file size          (blocks, -c) unlimited
    data seg size           (kbytes, -d) 1572864
    file size               (blocks, -f) unlimited
    max locked memory       (kbytes, -l) 331942
    max memory size         (kbytes, -m) 993656
    open files                      (-n) 4096
    pipe size            (512 bytes, -p) 1
    stack size              (kbytes, -s) 4096
    cpu time               (seconds, -t) unlimited
    max user processes              (-u) 256
    virtual memory          (kbytes, -v) 1576960

ulimit ist hier (wie auch bei Linux) das mittel der Wahl um die neu gesetzten Limits zu überprüfen.

Benutzereinschränkungen über die login.conf wirken irgendwie stabiler und sicherer als ulimit Statements in irgendwelche /etc/profile wie man es bei Linux so kennt. Auch die 1000 anderen Features die das System bietet muss ich mir unbedingt noch anschauen.

Mechanische Tastaturen. Wenn's klick macht.

Eigentlich wollte ich nur eine neue Tastatur. Das war schon der erste Fehler. Ehe man sich versieht fällt man hinein in den Kaninchenbau mechanischer Tastaturen.

Wo fängt man an. Man ließt Begriffe wie TKL, PBT und DSA. Als Otto Normalverbraucher hat man davon noch nie etwas gehört. Zuerst ist einmal wichtig überhaupt das Format zu kennen. Die Größe eines Boards wird von 60% bis 100% definiert. Aber auch 66 Keys was eben dann 65 / 70% heisst. Oder eben TKL (Ten-Keyless) nur bedeutet dass es keinen Nummernblock gibt.

_Quelle: Wikipedia

Layout. Die meisten Keyboards haben US Layout. Ich war eigentlich bisher immer mit DE Layout unterwegs. Der Wechsel auf US ist auch Teil der Übung (von mir persönlich). Die Größe des Return Key ist auch etwas, dass man erstmal wissen muss.

Die Wahl der Schalter. Cherry MX Schalter sind irgendwie am Verbreitetsten. Es gibt auch MX kompatible Schalter von anderen Herstellern. Es ist auf jedenfall wichtig, dass die Schalter auf das Keycaps Set passen. Dazu gleich mehr. Aber welche Schalter sollen es sein? Linear, Acuation, Clicky, Non-Linear… Solls klicken und ab wie viel Kraftaufwand? Eine gute Zusammenfassung findet man auf Reddit. Im Endeffekt wurden es bei mir wieder die Cherry MX Blue. Auch wenn ich kurz mit den Brown geliebäugelt habe.

Die Tastatur selbst. Die obigen Anforderungen reichen schonmal grob, um sich auf eine Tastatur mit den richtigen Schaltern, Layout und Format umzusehen. In Deutschland ist das Zeug alles bisschen schwer zu bekommen. Da bleibt fast nur getDigital übrig :) Der ein oder andere hat hier sowieso schon einen Account.

Sobald man mit dem Thema durch ist, gehts direkt weiter zum nächsten Problem. Keycaps sind so das was mich ne wichtige Rolle gespielt hat. Erstmal will man sich wohl die verschiedenen “Families” ansehen. Das ist eigentlich nur die Form der Tasten. Eine davon (vom Hersteller Signature Plastics) ist das eingangs genannte DSA.

Es gibt Keycap Sets in Hülle und Fülle. Im Endeffekt wurde es bei mir das DSA Dolch Set.

Wenn es mit einem Set nicht getan ist, weil man auch noch einzelne Keys in irgendwelchen Farben oder Motiven will, muss man sich auch noch mit den Größen auseinander setzen. Eigentlich läuft das wie bei CSS mit em nur das es Unit heisst. 1 Unit ist die Normalgröße eines Keys. Um sich eine andersfarbige CTRL Taste zu holen braucht man dann zum Beispiel einen 1.25 Units großen Key.

Apropos Andersfarbig. Farbschema der Keys. Farben wirken immer anders. Deshalb gibts beim Hersteller Signature Plastics auch noch Farbcode Tabellen. Natürlich sind die Farbcodes wieder abhängig vom Material. Achja, Material! Damit habe ich mich garnicht beschäftigt. Ehrlich.

Und dann.. wars das eigentlich auch schon. Man hat alles zusammen. Außer Kabel. USB Kabel sind auch so eine Style Geschichte. Allerdings nicht so bescheuert wie bei Audiophilen mit ihrem bei Mondschein mit Blutdiamanten gefeilten vom Dalai Lama gewickelten Goldadapter Scheiss. Es geht ums aussehen und dem Gefühl wenns am Tisch rumliegt. Mehr nicht. Da kann man sich zum Beispiel bei pexonpcs.co.uk Kabel in beliebiger Länge, Anschlüsse, Farbe und Krümmung zusammenstellen. Ich hab mich teilweise schwer getan das Wording zu verstehen.

Und das wars! So schnell hat man seine Tastatur zusammen. Bei mir sieht das jetzt so aus. Die Spacebar ist noch nicht ausgetauscht.

TL;DR: Alles was man braucht sind eigentlich Reddit, das DeskThority Wiki, für Inspirationen und Neugier geekhack.org, Flickr, Imgur und einen netten Menschen der einem bei den typischen Fragen, nach denen man nicht zu googeln weiß, den richtigen Hint gibt. In meinem Fall war das bl1nk. Danke nochmal :)

Es ist teilweise eine komische Community die gefühlt viel in Japan unterwegs ist und sich zu größeren Horden zusammenschliesst und eine Sammelbestellung von Custom Keycaps bei einer Plastikgießerei einwirft. Nach allem Warten und viel zu viel ausgegebenem Geld, kann ich nicht genau sagen ob ich das nocheinmal machen würde. Aber jetzt liegt die Tastatur hier und ich kann mich daran erfreuen. Und das tue ich sehr. Weil es immer ein gutes Gefühl ist alles abzuwägen, sich schlau zu lesen und dann das zusammenstellt, was man sich vorstellt.