Update meiner Open source docs

Freitag, 19. August, 2022

Unter https://www.axel-hahn.de/docs/[POJEKT] habe ich diverse Hilfen für PHP- und Javascript Tools bereitgestellt, die ich mit einem Parser generieren lasse. Jener Ansatz ist etwas älter und länger her - und stellt bereits geraume Zeit so einige meiner Dokumentationen bereit…

Eigentlich suchte ich nach einem mehr generischen Ansatz, um heutzutage in Git übliche Markdown-Dateien in statisches HTML umzuwandeln. Es gibt da diverse Tools, aber ich bin beim PHP-CLI Tool Daux hängengeblieben. Insbesondere, weil ich hier im Gegensatz zu anderen angetesten Werkzeugen keine Extra Konfiguration für einen Navigationsbaum als Config-Datei hinterlegen muss. Auch hat der Entwickler sehr schnell reagiert und auf gemeldete Feature Requests reagiert. Kurz: ich habe nun diverse einzelne Dokumentationen verschiedener Produkte und Klassen mit Daux gebaut. Das sind jeweils statische Verzeichnisse mit statischen HTML-Dateien + Javascript und Css out of the Box in jedem Browser laufen, wenn man sie vom Filesystem oder aber USB-Stick startet.

Was diverse Markdown zu Html Generatoren bieten, ist ein eingebauer Webserver für eine Vorschau. Der hilft beim Schreiben der Markdown-Dateien. Mittlerweile in Markdown Quasi-Standard ist der Support von mathematischen Formeln oder aber Graphen (mermaid.js) - das soweit ich auf Github, Gitlab oder aber lokal im Visual Studio Code per Markdown Preview gesehen habe.

Soweit so gut. Und wenn ich nun zig alleinstehende Dokumentationen habe und eine Index-Seite haben will?

Ich habe dazu einen Ansatz zum Generieren einer Index-Seite wie folgt gewählt:

  • ich möchte Gruppen: nach Programmiersprache oder nach einer sonstigen Rubrik
  • in jeder Rubrik werden N Projekt-Dokumenationen verlinkt
  • … wobei jene referenziert wird als Git-Repository, um diese mit Daux on the fly generieren zu lassen
  • … oder aber: weil ich noch meine geparsten Dokumentationen habe: ich kann anderweitig bestehende Dokumentationen ebenfalls einbetten
  • die Index-Seite soll flexibel sein und verschiedene Templates/ CSS/ Javascritpt unterstützen

Ich habe dazu ein Bash-Skript geschrieben, das mit jq eine JSON Config-Datei parst und mittels eines Templates die Seitenelemente generieren lässt. Die Flexibilität steckt in den Templates - dese bestimmen, ob es ein

OK, all das ist zu viel Text … so sieht meine Übersichtsseite mit dem Template mit Gruppen und Boxen sieht so aus: Axels Docs

2022-08-20-multidoc-generator-page_boxes.png

weiterführende Links: (en)

  1. Axels Docs-Index-Seite
  2. daux.io Hilfe-generator - Markdown zu HTML
  3. Github: axelhahn/multidoc-generator
  4. Statische Hilfe zum multidoc-generator
  5. Mermaid.js

Flatpress Theme A touch glass Update

Montag, 27. Juni, 2022

Mein Theme des Flatpress-Blog hat vor ein paar Wochen ein Update erhalten und wurde responsive. OK, das war auch überfällig, dass man auf Smartphone und Tablets ebenfalls Blog Texte lesen kann. Es gibt 3 Zoomstufen mit unterschiedlichen Rahmenbreiten.

2022-06-27-atog-01.png

Bei kleinen Auflösungen werden linke/ rechte Spalte mit Klick auf ein Hamburger-Menü eingeblendet.

2022-06-27-atog-02.png

Nun kam noch ebenjenes im Screenshot sichtbare Farbschema neu hinzu: den ganz farbenreichen Themes gesellt sich nun ein etwas einfacheres und mehrheitlich weisses. Ich hoffe es gefällt.

Zum Updaten in seiner Flatpress Instanz: im Ordner ./fp-interface/themes/ das Verzeichnis “atog” löschen und durch den im Github Repository ersetzen. In der Admin von Flatpress unter “Themes” kann man das Theme “A touch of glass” wählen und mit dem Link “Styles” die Farbwahl treffen.

weiterführende Links:

  1. Github: Projekt Seite des Themes
  2. Github: Theme A Touch Of Glass als ZIP
  3. Flatpress.org Blogging Engine in PHP ohne Datenbank

Mysqldump - trotz Exitcode 0 keine Daten im Dumpfile

Dienstag, 22. März, 2022

Ich verwende diesen Aufruf, um Schemata auf dem Mysql Server zu dumpen:

  mysqldump --opt 
            --default-character-set=utf8 
            --flush-logs 
            --single-transaction 
            --no-autocommit 
            --result-file="$_dumpfile" 
            "$_dbname" 2>&1
  $myrc=$?

… und stand vor dem Phänomen, dass der Exitcode 0 war - also eigentlich den Erfolg meldet - aber es keinerlei Daten im Dump gab.

Das Betriebssystem war ein Centos8 Stream. Das Problem lag in der Option –flush-logs, die nicht ausgeführt werden konnte, da das Verzeichnis /var/log/mysql/ (warum auch immer) nicht mehr vorhanden war. Dass ein leerer Dump ohne Daten erzeugt wird und kein Exitcode > 0, ist m.E. ein Fehler im mysqldump. Und den versuche ich, zu umschiffen.

Ich habe nach dem Dump noch einen Check hinzugefügt, der das Vorhandensein auf mind. ein CREATE oder aber INSERT Statements prüft. Oder anders: wenn man eine (korrekte) leere Datenbank ohne einzige Tabelle oder auch nur 1 einzigem gesicherten Datensatz hat, würde ein Fehler beim Backup gemeldet. Ich meine, damit lässt es sich leben.

  mysqldump --opt 
            --default-character-set=utf8 
            --flush-logs 
            --single-transaction 
            --no-autocommit 
            --result-file="$_dumpfile" 
            "$_dbname" 2>&1
  $myrc=$?

  if [ $myrc -eq 0 ]; then
        if ! zgrep -iE "(CREATE|INSERT)" "$_dumpfile" >/dev/null
        then
          typeset -i local _iTables
          _iTables=$( mysql --skip-column-names --batch -e "use $_dbname; show tables ;" | wc -l )
          if [ $_iTables -eq 0 ];
          then
            echo "EMPTY DATABASE: $_dbname"
          else
            echo "ERROR: no data - the dump doesn't contain any CREATE or INSERT statement."
            # force an error
            $myrc=1
          fi
        fi
  fi

  if [ $myrc -eq 0 ]; then
        echo "OK"

        # Und dann hier noch komprimieren... 
        # gzip $_dumpfile"
        # ... und Erfolg der Kompression auswerten

  else
        echo "ERROR: mysqldump failed."
  fi

Update:

  1. 24.03.2022 - eine leere Datenbank würde als Fehler gemeldet - daher zähle ich mal noch die Tabellen

weiterführende Links:

  1. mysql.com: mysqldump
  2. mariadb.com: mysqldump
  3. IML open source: IML-Backup (mein Backup Tool an unserem Institut zum lokalen Dumpen div. DBs und Backup mit Restic/ Duplicity)
  4. DOCs: os-docs.iml.unibe.ch/iml-backup/

20 Jahre Axels Cron-wrapper

Donnerstag, 10. März, 2022

Ich habe grad in die History geschaut: 20 Jahre (!!!) nutze ich schon den meinigen Cronwrapper auf Linux/ Unix-Systemen.

Und ich bin noch immer am Aktualisieren und Verfeinern von dessen Skripten oder Dokumentation. Auch weil ich dessen Idee so mag. Alles ist OpenSource - GNU GPL 3.0.

Das Repository [1] enthält

  • cronwrapper.sh - ein Wrapper - wenn man Cronjobs hat, dann stellt man den einfach mal vorn dran
  • cronstatus.sh - das Skript zeigt den Status aller auf dem System befindlichen Cronjobs
  • inc_cronfunctions.sh - ein Script, dass in Bash geschriebene Cronjobs gesourct werden kann, um div. nützliche Funktionen zu nutzen.
  • Dokumentation im Markdown Format zur Installation und allen Features.

Der einfachste Einstieg ist, den Wrapper cronwrapper.sh zu verwenden: mit allen bestehenden Cronjobs, egal welcher Programmiersprache jene sind, lässt sich dieser ergänzen. Und man erhält out-of-the-box kleine nette Features.

  • STDOUT und STDERR werden eingefangen und in ein normiertes Logfile geschrieben (ohne jenes explizit angeben zu müssen)
  • Das Logfile wird normiert und ist mit grep nach Output oder Metadaten durchsuchbar

Alle Cronjobs, die den Wrapper verwenden, werden mit dem Skript cronstatus.sh aufgelistet und bewertet:

  • weisen sie exitcode 0 auf?
  • sind sie in der vorgegebenen Frist gestartet worden?

Diese Ausgabe kann man auch in einem Monitoring Script für die Überwachng aller Cronjobs auf seinen Systemen einbinden.

Und als Goodie gibt es ein Include file inc_cronfunctions.sh,welches hilfreich sein kann, sofern die Cronjobs in Bash geschrieben sind: eine Reihe nützlicher Funktionen werden darin bereitgestellt, um das Schreiben von “sicheren” und lesbaren Conjobs zu erleichtern.

weiterführende Links: (en)

  1. Github: cronwrapper
  2. Docs auf axel-hahn.de

IML Appmonitor ist nun PHP 8.1 kompatibel

Donnerstag, 16. Dezember, 2021

Der Appmonitor ist eine PHP-Applikation mit geringstmöglichen Anforderungen. Mit dieser lassen sich andere (Web-)Applikationen in einem Webfrontend überwachen und bei Statuswechsel Notifikationen per E-Mail und Slack an die am Projekt beteiligten Personen auslösen.

Das Applikationsmonitoring ergänzt unser System-Monitoring, weil es die applikationsseitigen Checks aus Sicht der Applikation und mit den Rechten der Applikation ausführt.

Der Appmonitor ist Freie Software, Opensource und untersteht der GNU GPL 3.0.

Nach gefühlt 2 Jahren habe ich am IML Appmonitor weitergecodet. Es sollte PHP 8 kompatibel werden. Und weil soeben PHP 8.1 erschienen ist, wurde es nun auch für ebenjene Version 8.1 fit gemacht:

Tadaaa: der Appmonitor ist die erste PHP 8.1 kompatible Opensource Applikation unseres Instituts :-)

Zudem wird die Plugin-Unterstützung vorangetrieben, es kam eine grafische Darstellung der Checks in einem ersten Wurf hinzu und die Möglichkeit, die Checks nach vorgegebenen Gruppen zu clustern. Die Notifikation eines Fehlers erfolgt nicht beim ersten Auftreten, sondern wird erst bei der 3. Wiederholung ausgelöst.

2021-12-16-appmonitor-appview.png

Ich bin gerade motiviert, weitere Updates einzubringen und nachzuliefern. Es gibt beispielsweise vorgefertigte Checks für einige PHP-Applikationen, wie Wordpress, Ilias LMS, Concrete5 und Matomo. Diese befinden sich in einem separaten Repository und werden in Kürze in das Repo integriert.

weiterführende Links:

  1. Github: Quellcode des IML Appmonitors
  2. Github: vorgefertigte Appmonitor-Checks für Drittanbieter Applikationen
  3. DOCs: os-docs.iml.unibe.ch
  4. git-repo.iml.unibe.ch - Opensource Projekte des IML

Mysql Replikation neu aufsetzen als Bash Skript

Donnerstag, 24. Juni, 2021

Wenn eine bestehende Mysql Replikation nicht mehr funktioniert, so half mir etliche Male im Laufe der Berufszeit als Webmaster beim Schweizer Radio DRS / Sysadmin Daseins an der Uni Bern ein top-down-Skript weiter. Wenn gerade Stress ist und man in der Situation nicht erst alle Kommandos zur Wiederinbetriebnahme des Slave nachschlagen mag, dann ist ist man froh, wenn man ein Skript dafür parat liegen hat.

reinit_mysql_replication.sh

Es gibt keine Parameter.

Installation:

Man benötigt einen Mysql Client. Ich hatte daher die Skripte am Mysql-Slave unterhalb /root zu liegen. Daher ist die Verbindung zum Slave ohne Passwort (wird aus der /root/.my.cnf gelesen).
Es wird auch vom eigenen Rechner aus funktionieren, der die Mysql-Ports von Master und Slave erreichen kann. Es ist nur “einen Tick” langsamer (sprich: bei vielen und/ oder grossen Datenbanken > 1 GB Gesamtgrösse nicht zu empfehlen).

Konfiguration:

Die *dist Datei ist umzukopieren und die Hostnamen und Root-Passwörter für Master + Slave sind zu setzen.

Start:

Das Skript reinit_mysql_replication.sh führt der Reihe nach folgende Aktionen aus: es …

  • zeigt aktuellen Slave Status
  • wartet dann auf ein RETURN, bevor die Replikation neu aufgesetzt wird

Aktionen zum Neuaufsetzen der Replikation: das Skript …

  • liest die Position des Binlog am Master (per SQL “SHOW MASTER STATUS G;”)
  • sperrt den Master für Schreibaktionen (”FLUSH TABLES WITH READ LOCK;”)
  • holt aktuelle Datenbank-Dumps vom Master (mysqldump –all-databases –lock-all-tables …)
  • hebt Schreibsperre am Master auf (”UNLOCK TABLES;”)
  • stoppt den Slave (”STOP SLAVE G;”)
  • importiert Dumps des Master auf dem Slave (cat $dumpMaster | mysql $paramdbSlave)
  • setzt am Slave binfile und Position (”CHANGE MASTER TO MASTER_LOG_FILE = …” ; “CHANGE MASTER TO MASTER_LOG_POS = …”)
  • startet den Slave (”START SLAVE G;”)

weiterführende Links:

  1. git-repo.iml.unibe.ch: iml-open-source/mysql-slave-scripts

Restic client auf 64 Bit Linux installieren

Mittwoch, 28. April, 2021

Restic [1] ist ein in Go geschriebenes Backup-Tool für die Kommandozeile … oder zum Skripten. Es besteht aus einem einzigen Binary und hat keinerlei Abhängigkeiten zu Libs, Paketen oder irgendwas. Es erzeugt dedulizierte Backups: initial wird ein Vollbackup gemacht und dann nie wieder - es braucht dann nur noch inkrementelle Backups. Restic gibt es für Windows/ Mac/ Linux und diverse Plattformen (BSD, Solaris, Mips, … - siehe Releases (dort etwas scrollen :-) [2]).

Das hat was.

Daheim werfe ich gerade einen Http-Server als Backup-Endpoint auf die Synology [3].

Auf Systeme am Institut habe ich grob 150 Linux-Systeme - mit altem und neuen Linux Varianten verschiedener Distributionen. Ich habe ein Bash Skript geschrieben, das mit wget das Binary des Restic Client holt, entpackt und ins /usr/bin legt. Wer es für ein anderes OS oder Architektur braucht, müsste den Suffix “_linux_amd64” ersetzen … oder aber auch dynamisch machen (mit

uname -a

könnte man hinkommen).

#!/usr/bin/env bash

# ------------------------------------------------------
# CONFIG
# ------------------------------------------------------
resticversion=0.12.0
doLink=0

installdir=/usr/bin
resticfile=restic_${resticversion}_linux_amd64
downloadfile=${resticfile}.bz2
downloadurl=https://github.com/restic/restic/releases/download/v${resticversion}/${downloadfile}

# ------------------------------------------------------
# MAIN
# ------------------------------------------------------
echo
echo "##### INSTALL RESTIC CLIENT into $installdir #####"
echo

echo ----- DOWNLOAD
if [ ! -f "${downloadfile}" ]; then
         wget -O "${downloadfile}.running" -S "${downloadurl}" 
                 && mv "${downloadfile}.running" "${downloadfile}"

else
         echo SKIP download
fi
echo

echo ----- UNCOMPRESS
bzip2 -d "${downloadfile}"
echo

echo ----- INSTALL
mv "${resticfile}" "${installdir}"
chmod 755 "${installdir}/${resticfile}"
rm -f "${installdir}/restic" 2>/dev/null
test $doLink -eq 0 || ln -s "${installdir}/${resticfile}" "${installdir}/restic"
test $doLink -eq 0 && mv "${installdir}/${resticfile}" "${installdir}/restic"

echo
echo ----- SELF-UPDATE
restic self-update
echo
echo ----- RESULT:
test $doLink -eq 0 || ls -l "${installdir}/${resticfile}" 
ls -l "${installdir}/restic"
echo
echo ----- CURRENT VERSION:
restic version
echo
echo ----- DONE

weiterführende Links:

  1. https://restic.net/ Homepage von Restic
  2. Github: Restic Releases
  3. Github: Skript zur Installation eines Restic Http Servers auf einer Synology

AhCrawler läuft mit PHP8

Montag, 28. Dezember, 2020

Der AhCrawler ist ein PHP Open Source Projekt, das für den Einbau einer Suche auf der eigenen Webseite enststand. Im Backend kann man den Suchindex wie auch die von Besuchern eingegebenen Suchbegriffe analysieren. Hinzu kommen Werkzeuge, wie Linkchecker, Http-Header-Analyse, SSL-Check und Annehmlichkeiten, wie der integrierte webbasierte Updater oder die Verwaltungsmöglichkeit mehrerer Webseiten.

2020-12-28-ahcrawler-v139-is-php8-compatiblepng.png

Nachdem PHP in Version 8 erschien, kam Anfang Dezember 2020 eine Version heraus, die offensichtliche Fehler in der WebGUI unter PHP8 bereinigte. Der Crawler zeigte hingegen bei Http Head Requests mit Curl “irgendwann” ein komisches Verhalten und brach mit einem “Segmentation Fault” ab.

Mit dem heutigen Release des AhCrawler ist aber auch das Geschichte. Ich bezeichne die Software nunmehr als PHP8 kompatibel! Tusch :-)

weiterführende Links:

  1. AhCrawler (de)
  2. DOCs: AhCrawler (en)

Flatpress - sichere Passwortfunktion statt MD5 Hash

Sonntag, 20. Dezember, 2020

Ich hatte es es ja genauso in mein meinen Webtools mit Login gern gemacht: neben dem Admin User wurde das Passwort als MD5 Hash in einer Config-Datei hinterlegt.

Die Hashfunktion MD5 ist nach IT Masstäben nicht mehr wirklich sicher - heisst: man kann mit einem zeitlich vertretbaren Aufwand aus dem Hash das (oder ein) Passwort ermitteln, dass auf den Hash matcht. Verzichtet man gar auf Salts, ist der Angreifer mit Rainbow Tables gar in Sekundenbruchteilen am Ziel. Das ist gar nicht gut. Auf MD5 sollte man heutzutage beim Hashing von Passwörtern - egal ob in einer Konfigurationsdatei oder Datenbank-Feld - komplett verzichten.

Ich will es keineswegs verdammen: als reine Hash Funktion zum Bilden von Prüfsummen von nicht-sensiblen Daten, wie Prüfsummen von Download-Dateien, ist es bedenkenlos einsetzbar.

Aber zurück zum Speichern von Passwörtern. PHP bietet seit einiger Zeit von Haus sichere Funktionen an, sichere Passwort-Hashes zu generieren [2] wie auch eine Check-Funktion [3]. Auf dieses Paar habe ich meine Tools umgestellt und kannte das Prozedere der Umstellung bereits.

Da ich hier als “mein” Blogtool Flatpress seit gefühlten Äonen selbst verwende, hab ich mich gern auch an jenem Tool drangesetzt, und dessen md5 Passwort-Hash durch eine sicherere Variante ersetzt - und eine Lösung für den Issue #59 [4] als Pull Request eingereicht.

Das gilt nicht nur für die neu angelegten Passwörter - auch die Migration ist berücksichtigt: bestehende mit md5 Hash gespeicherte Passwörter werden on the fly beim nächsten Login umgeschrieben.

Arvid, danke und merci für den Merge und Erwähnung auf Twitter [1] für die kommende Version 1.2!

I love OpenSource :-)

weiterführende Links:

  1. Twitter-Nachricht
  2. PHP: Funktion password_hash
  3. PHP: Funktion password_hash
  4. Github Flatpress: Issue #59
  5. Flatpress.org

Matomo-Javascript Tracking Code auslagern

Samstag, 3. Oktober, 2020

Matomo empfiehlt zum Tracken einer Webseite den Einbau des Codeschnipsels innerhalb des HTML Dokuments … im Head Bereich. [1]

Aber: das Hineinschreiben von Javascript Code in das HTML Dokument ist nicht so recht günstig, wenn man im CSP Security Header das Attribut script-src sicher und ohne unsafe-inline konfigurieren will. [3]

Die Abhilfe besteht darin, dass man [2]

  1. das Snippet in eine Javascript Datei auslagert.
  2. den Aufruf des Trackens im Onload Event einfügt - der ebenfalls in der Javascript-Datei ist und nicht im HTML-Code einer Webseite.

Hier einmal ist die Funktion embedTrackingCode benannt:

function embedTrackingCode() {
	var _paq = window._paq = window._paq || [];
	_paq.push(["trackPageView"]);
	_paq.push(["enableLinkTracking"]);

	var u="/matomo/";
	_paq.push(['setTrackerUrl', u+'matomo.php']);
	_paq.push(['setSiteId', 1]);

	var d=document, g=d.createElement("script"), s=d.getElementsByTagName("script")[0]; g.type="text/javascript";
	g.defer=true; g.async=true; g.src=u+"matomo.js"; s.parentNode.insertBefore(g,s);    
}

… welche bei Abschluss des Ladevorgangs initialisiert wird:

window.onload = (event) => {
	embedTrackingCode();
};

Hinweis:

Wenn der Tracking Code in einer Javascript-Datei ist, muss man das Http-Caching der JS Datei bei einem expires= im Http Response Header beachten. Man ist u.U. nicht mehr so flexibel, wenn man den Code anpassen wollte, weil Browser das Javascript aus dem Cache nehmen, statt frisch vom Server die angepasste Version zu holen. Man kann per ETag cachen lassen … oder kann die JS-Datei mit Versionsnummer benennen.

weiterführende Links:

  1. Matomo Guide: JavaScript Tracking Client (en)
  2. Matomo Blog: Different ways of embedding the Matomo tracking code for faster website performance (en)
  3. developer.mozilla.org: CSP Header - script-src (en)