Advertise with Googlier.com Jörgs Webnotizen https://blog.jkip.de Blog über Debian GNU/Linux, Webserver und Webprogrammierung Wed, 22 Jul 2026 15:04:38 +0000 de hourly 1 https://wordpress.org/?v=7.1.4 Optionale Checks in ShellCheck https://blog.jkip.de/optionale-checks-in-shellcheck/ https://blog.jkip.de/optionale-checks-in-shellcheck/#respond Wed, 22 Jul 2026 12:35:27 +0000 https://blog.jkip.de/?p=1530 Zum Überprüfen von Fehlern in Shell-Scripten hat sich das Kommandozeilen-Tool ShellCheck als Quasi-Standard etabliert. Den Shell-Dialekt (sh, bash, dash, ksh oder busybox), dessen jeweilige Checks angewandt werden sollen, kann ShellCheck anhand der Dateiendung oder dem Shebang des zu prüfenden Scripts erkennen, andernfalls muss dieser mit der Option --shell bestimmt werden.

Die Warnungen von ShellCheck bei Bash-Scripten sind eher konservativ gehalten, so dass eine Behebung der angezeigten Fehler nicht unnötigerweise „Bashismen“ erzeugt. Ein moderner Coding-Style mit doppelten statt einfacher Klammern, wie z. B. im Shell Style Guide von Google gefordert, ließe sich aber mit dem optionalen Check require-double-brackets forcieren. Mit der Option --list-optional können die in der jeweiligen Version von ShellCheck verfügbaren optionalen Checks inklusive Beschreibung und Beispiel-Code mit Fix aufgeführt werden, beispielsweise für die Version 0.11.0:


$ shellcheck --version
ShellCheck - shell script analysis tool
version: 0.11.0
license: GNU General Public License, version 3
website: https://www.shellcheck.net
$ shellcheck --list-optional
name:    add-default-case
desc:    Suggest adding a default case in `case` statements
example: case $? in 0) echo 'Success';; esac
fix:     case $? in 0) echo 'Success';; *) echo 'Fail' ;; esac

name:    avoid-negated-conditions
desc:    Suggest removing unnecessary comparison negations
example: [ ! "$var" -eq 1 ]
fix:     [ "$var" -ne 1 ]

name:    avoid-nullary-conditions
desc:    Suggest explicitly using -n in `[ $var ]`
example: [ "$var" ]
fix:     [ -n "$var" ]

name:    check-extra-masked-returns
desc:    Check for additional cases where exit codes are masked
example: rm -r "$(get_chroot_dir)/home"
fix:     set -e; dir="$(get_chroot_dir)"; rm -r "$dir/home"

name:    check-set-e-suppressed
desc:    Notify when set -e is suppressed during function invocation
example: set -e; func() { cp *.txt ~/backup; rm *.txt; }; func && echo ok
fix:     set -e; func() { cp *.txt ~/backup; rm *.txt; }; func; echo ok

name:    check-unassigned-uppercase
desc:    Warn when uppercase variables are unassigned
example: echo $VAR
fix:     VAR=hello; echo $VAR

name:    deprecate-which
desc:    Suggest 'command -v' instead of 'which'
example: which javac
fix:     command -v javac

name:    quote-safe-variables
desc:    Suggest quoting variables without metacharacters
example: var=hello; echo $var
fix:     var=hello; echo "$var"

name:    require-double-brackets
desc:    Require [[ and warn about [ in Bash/Ksh
example: [ -e /etc/issue ]
fix:     [[ -e /etc/issue ]]

name:    require-variable-braces
desc:    Suggest putting braces around all variable references
example: var=hello; echo $var
fix:     var=hello; echo ${var}

name:    useless-use-of-cat
desc:    Check for Useless Use Of Cat (UUOC)
example: cat foo | grep bar
fix:     grep bar foo

Optionale Checks können mit der Direktive enable in der User-Konfigurationsdatei ~/.config/shellcheckrc aktiviert werden, so dass ShellCheck diese künftig automatisch mit berücksichtigt, so z. B.:


enable=avoid-negated-conditions
enable=avoid-nullary-conditions
enable=deprecate-which
enable=require-double-brackets
enable=useless-use-of-cat
]]>
https://blog.jkip.de/optionale-checks-in-shellcheck/feed/ 0
Konfiguration mit vimrc und / oder .editorconfig https://blog.jkip.de/konfiguration-mit-vimrc-und-oder-editorconfig/ https://blog.jkip.de/konfiguration-mit-vimrc-und-oder-editorconfig/#respond Tue, 30 Jun 2026 13:15:00 +0000 https://blog.jkip.de/?p=1512 In dem Beitrag Projektspezifische Konfiguration von vim hatte ich vor sechseinhalb Jahren beschrieben, wie mit dem vim Plugin localvimrc Konfigurationsdateien geladen werden können, die in einzelnen Projektordnern wirksam sind. Inzwischen verwende ich dieses Plugins und die lokalen .lvimrc Dateien seit längerem nicht mehr, stattdessen kommen in Projekten zur Definition von Coding-Styles .editorconfig Dateien zum Einsatz.

Von Vorteil sind diese vor allem, da der EditorConfig-Standard zwischenzeitlich von vielen Editoren unmittelbar oder mittels eines Plugins unterstützt wird und so in einem Projekt-Team mit unterschiedlichen Editoren für einheitliche Coding-Styles sorgen kann. In vim 9.1, welches im Repository von Debian Trixie enthalten ist, muss nicht einmal mehr ein Plugin installiert werden, .editorconfig Dateien werden direkt unterstützt. Für ältere vim Versionen existiert das Plugin vim-editorconfig.

Allgemein gehe ich so vor, dass ich globale Coding-Styles, die vor allem für die Bearbeitung von Shellscript- und Konfigurations-Dateien (v.a. durch root) relevant sind, weiterhin in der systemweiten Konfigurationsdatei /etc/vim/vimrc.local definiere:

set autoindent
set expandtab
set tabstop=2
set shiftwidth=2

Ich habe hier eine automatische Einrückung von zwei Leerzeichen gewählt, da dies auch bei vielen Dateien unterhalb von /etc der Fall ist.

In den jeweiligen Projektordnern liegen dann .editorconfig Dateien, deren Anweisungen von vim als vorrangig gegenüber denen der /etc/vim/vimrc oder ~/.vimrc behandelt werden. Beispiel einer .editorconfig Datei für ein Python-Projekt, mit einer automatischen Einrückung von vier Leerzeichen:

root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 4

In der .editorconfig Datei für ein WordPress-Plugin kommt dagegen der für WordPress übliche Standard von Einrückung mittels Tabs zum Zuge:

root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = tab

]]>
https://blog.jkip.de/konfiguration-mit-vimrc-und-oder-editorconfig/feed/ 0
Einrichtung von dmarcts-report-parser auf Debian https://blog.jkip.de/einrichtung-von-dmarcts-report-parser-auf-debian/ Mon, 23 Mar 2026 14:53:28 +0000 https://blog.jkip.de/?p=1493 Mit einem DMARC-Record im DNS kann nicht nur festgelegt werden, wie mit Emails zu verfahren ist, die mit den SPF- und DKIM-Einträgen nicht konform gehen. Im Parameter rua kann auch eine Adresse angegeben werden, an welche die Mailserver aggregierte Berichte senden können, wie hier z. B. die Adresse dmarc@example.org:

_dmarc	3600	IN	TXT	"v=DMARC1;p=quarantine;rua=mailto:dmarc@example.org"

Die Berichte werden als XML-Dateien im Anhang versandt. Der Paketmanager von Debian bietet gleich drei verschiedene Tools zur Installation an, welche die XML-Dateien parsen können: dmarc-cat, dmarc-srg und dmarcts-report-parser. Mit letzterem kann auch direkt auf das IMAP-Konto zugegriffen werden, in welchem die Berichte landen. Die extrahierten Daten werden dabei in einer Datenbank gespeichert.

Da dmarcts-report-parser im Repository von Debian Trixie enthalten ist, ist die Installation einfacher als auf der Github-Seite angegeben:

# apt install dmarcts-report-parser

Nach der Installation muss manuell eine MariaDB oder PostgreSQL Datenbank angelegt werden. In der Datei /etc/dmarcts-report-parser.conf werden dann die Zugangsdaten zu dieser Datenbank eingetragen, ebenso die Zugangsdaten zum IMAP-Konto sowie ggf. – entsprechend den erläuternden Kommentaren – weitere Einstellungen. Bei der Angabe von Unterordnern funktionierte in meinem Fall (Dovecot mit Maildir auf dem Server) die Trennung mit einem Slash nicht, stattdessen mit einem Punkt:

$imapmovefolder = 'dmarc.processed';

Nachdem die Konfigurationsdatei fertiggestellt ist, kann ein erster Prozess angestoßen werden:

# dmarcts-report-parser -i

In der Datenbank sollten dann die Tabellen rptrecord und report mit den geparsten Einträgen gespeichert sein. Wenn alles ordnungsgemäß verlaufen ist, kann in der Datei /etc/default/dmarcts-report-parser der täglich laufende Cronjob bzw. Timer, der bereits bei der Installation von dmarcts-report-parser eingerichet wurde, „scharf geschaltet“ werden:

# This tool/script is run via CRON only if the below IS_CONFIGURED variable is set to "1"
IS_CONFIGURED="1"

Um die Daten der Datenbanktabellen besser zu erfassen, können entsprechende Views eingerichtet werden. So z. B. die neuesten Einträge zuoberst, beschränkt auf die Auswertungsdaten der empfangenden Mailserver:

CREATE VIEW view_dmarc AS
SELECT DATE(rep.maxdate) AS rep_date, rep.domain,
    IF(rec.ip IS NULL, INET6_NTOA(rec.ip6), INET_NTOA(rec.ip)) AS ip, rep.org,
    rec.dkimresult AS dkim, rec.dkim_align, rec.spfresult AS spf, rec.spf_align,
    rec.disposition
FROM rptrecord AS rec
INNER JOIN report AS rep
ON rec.serial = rep.serial
ORDER BY rep_date DESC

Mit einem ergänzendem Statement WHERE disposition != "none" ließe sich der View auch auf die problematischen Einträge beschränken, bei denen Emails geblockt oder in die Quarantäne verschoben wurden.

]]>
„doveadm expunge“ löscht ältere Mail nicht? https://blog.jkip.de/doveadm-expunge-loescht-aeltere-mail-nicht/ Thu, 19 Feb 2026 10:49:27 +0000 https://blog.jkip.de/?p=1481 Nach 30 Tagen sollten Mails aus dem Ordner ‚xyz‘ des Users ‚joe‘ automatisch gelöscht werden. Hierzu wurde auf dem Server ein Cronjob eingerichtet, der täglich ein Script aufruft, welches den Löschauftrag mit dovecot expunge ausführt:

#!/bin/bash

/usr/bin/doveadm expunge -u 'joe' mailbox 'xyz' savedbefore 30d

Die Kontrolle in Thunderbird am nächsten Tag ergab, dass zwar die meisten Mails aus dem Ordner ‚xyz‘ mit einem Datum älter als 30 Tage gelöscht waren, eine Mail aus dem letzten Jahr aber noch im Ordner verblieben war. Wie konnte das sein?

Das Schlüsselwort savedbefore bezieht sich auf das Speicherdatum der Mails, welches folgendermaßen von doveadm für die Mails des betreffenden Ordners ausgegeben werden kann:

doveadm -f tab fetch -u 'joe' "uid date.saved" mailbox 'xyz'

Und in der Tat werden dabei keine Datumsangaben älter als 30 Tage angezeigt, doveadm-expunge hat hier also korrekt gearbeitet. Thunderbird zeigt nun nicht das Speicherdatum, sondern das Empfangsdatum der Mails an und dieses lässt sich folgendermaßen von doveadm ausgeben:

doveadm -f tab fetch -u 'joe' "uid date.received" mailbox 'xyz'

Bein einem Vergleich fällt hier die Mail mit der UID 9358 auf:

# doveadm -f tab fetch -u 'joe' "uid date.saved" mailbox 'xyz'
uid	date.saved
....	....
9358	2026-02-03 09:10:01
....	....

# doveadm -f tab fetch -u 'joe' "uid date.received" mailbox 'xyz'
uid	date.received
....	....
9358	2025-05-06 16:53:23
....	....

Empfangen wurde sie bereits im letzten Jahr, gespeichert erst am 03.02. diesen Jahres. Des Rätsels Lösung war letztendlich, dass diese Mail am 03.02. aus einem anderen Ordner in den Ordner ‚xyz‘ verschoben wurde und bei diesem Vorgang wird eine Mail erneut gespeichert!

doveadm bezieht sich mit dem Schlüsselwort savedbefore auf die letztmalige Speicherung der Mails und bei dem Trash-Ordner beispielsweise macht dies ja durchaus Sinn:

/usr/bin/doveadm expunge -u 'joe' mailbox 'Trash' savedbefore 7d

Damit werden Mails gelöscht, nachdem sie sieben Tage im Trash-Ordner verblieben sind (und nicht bereits sieben Tage, nachdem sie erstmalig empfangen wurden)

]]>
Einfache CSS-Container-Queries statt komplexer Media-Queries https://blog.jkip.de/einfache-css-container-queries-statt-komplexer-media-queries/ Tue, 10 Feb 2026 14:37:49 +0000 https://blog.jkip.de/?p=1434 Schon seit 2023 werden CSS-Container-Queries von den gängigsten Browser-Versionen unterstützt. Während die althergebrachten Media-Queries sich stets am Viewport orientierten, kann sich eine Container-Query auf eine einzelnes Blockelement beziehen. Das ist mitunter eine große Erleichterung auch bei der Anpassung älterer Webseiten, wie das folgende Beispiel zeigt.

In einem klassischen Layout mit Header, Sidebar, Footer sollen im Hauptinhaltsbereich (im Element main) zwei Textboxen untergebracht werden. Ist der Hauptinhaltsbereich breiter als 480px, sollen die Textboxen nebeneinander, andernfalls untereinander dargestellt werden. Hinzu kommt, dass die Sidebar nur oberhalb einer Breite von 640px neben dem Hauptinhalt, andernfalls unterhalb angezeigt wird, so wie es in einem responsiven Layout sinnvoll ist.

Die folgenden Bilder illustrieren dies. Bei einem sehr schmalen Viewport werden die Textboxen untereinander angezeigt (erstes Bild), bei etwas mehr Breite passen die Textboxen nebeneinander (zweites Bild), bevor die Sidebar den Hauptinhaltsbereich einzwängt (drittes Bild) und erst eine größere Gesamtbreite wieder genug Platz lässt für zwei Textboxen nebeneinander (viertes Bild):

Der HTML-Code des Hautpinhaltes könnte so ausschauen:

<main>
    <h1>Main Content</h1>
    <div id="boxes">
        <div>
            <h2>Box 1</h2>
            <p>...</p>
        </div>
        <div>
            <h2>Box 2</h2>
            <p>...</p>
        </div>
    </div>
</main>

Früher wäre eine sehr komplexe Media-Query mit min-width und max-width notwendig gewesen, um die Bereiche zu erfassen, in denen das Elternelement (hier: div#boxes) als Flexbox definiert wird, so dass die Text-Boxen nebeneinander dargestellt werden:

@media screen and (
  (
    (min-width: 30em) 
    and 
    (max-width: 39.9375em)
  )
  or 
  (min-width: 42em)
) {
  #boxes {
    display: flex;
    gap: 1em;
  }
  #boxes > div {
    flex-grow: 1;
  }
}

Wir haben hier drei Breakpoints. Die mühsam errechneten Angaben müssen mit den logischen Operatoren and und or verknüpft sowie korrekt geklammert werden.

Mit einer Container-Query geht dies sehr viel einfacher. Der Hauptinhaltsbereich (main) wird hier als Container mit dem Namen main definiert:

main {
  container-name: main;
  container-type: inline-size;
}

Anschließend kann eine Container-Query diesen Namen referenzieren:

@container main (width >= 30em) {
  #boxes {
    display: flex;
    gap: 1em;
  }
  #boxes > div {
    flex-grow: 1;
  }
}

Hier können dann ganz einfach die 30em (~ 480px) als Breakpoint gesetzt werden.

]]>
Root-Login in MariaDB nach Debian-Upgrade nicht mehr möglich https://blog.jkip.de/root-login-in-mariadb-nach-debian-upgrade-nicht-mehr-moeglich/ Fri, 05 Sep 2025 13:31:34 +0000 https://blog.jkip.de/?p=1406 Nach einem Upgrade eines älteren Entwicklungssystems von Debian Bookworm auf Debian Trixie funktionierte der Login des Users root in MariaDB nicht mehr. Ein systemctl status mariadb gab folgende Fehler aus:

Reading datadir from the MariaDB server failed. Got the following error when executing the 'mysql' command line client
ERROR 1698 (28000): Access denied for user 'root'@'localhost'
FATAL ERROR: Upgrade failed

Schon seit einigen Debian-Versionen erfolgt die Authentifizierung des MariaDB-Users root nicht mehr über eine Passwortabfrage, sondern über einen Unix-Socket. Der Socket war auch aktiv:

Version: '11.8.2-MariaDB-1 from Debian' socket: '/run/mysqld/mysqld.sock' port: 3306 --

Der Linux-Root sollte sich demnach ohne Passwort als MariaDB-User root einloggen können. Genau das funktionierte hier nicht mehr:


$ su -
Password:
# mysql
ERROR 1698 (28000): Access denied for user 'root'@'localhost'

Andere User dagegen können sich problemlos per Passwort einloggen.

Vor dem Debian-Upgrade hatte ich, wie in den Release-Notes empfohlen, den MariaDB-Server gestoppt. Trotzdem schien hier irgendwas schief gelaufen zu sein. Um die Situation als root zu begutachten und ggf. zu bereinigen, startete ich MariaDB über mariadbd-safe mit der Option –skip-grant-tables. Danach war ein passwortloser Login mit dem mysql Client möglich:


# systemctl stop mariadb.service
# mariadbd-safe --skip-grant-tables &
[1] 171235
250902 15:22:55 mysqld_safe Starting mariadbd daemon with databases from /var/lib/mysql
# mysql
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 3
Server version: 11.8.2-MariaDB-1 from Debian -- Please help get to 10k stars at https://github.com/MariaDB/Server

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

Eine Abfrage nach dem Authentifizierungs-Plugin von root@localhost ergab, dass wie bisher das Plugin unix_socket genutzt wird:


MariaDB [(none)]> FLUSH PRIVILEGES;
MariaDB [(none)]> USE mysql;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
MariaDB [mysql]> SELECT Host, User, plugin FROM user WHERE User = 'root';
+-----------+------+-------------+
| Host      | User | plugin      |
+-----------+------+-------------+
| localhost | root | unix_socket |
+-----------+------+-------------+
1 row in set (0.003 sec)

Das FLUSH PRIVILEGES am Anfang ist notwendig, um folgende Änderungen vornehmen zu können. Eine Änderung auf das Plugin mysql_native_password wäre möglich (wobei dann unbedingt auch ein Passwort für root gesetzt werden muss!). Aber ich wollte die Authentifizierungsmethode unix_socket beibehalten. Mein Reparaturversuch sah dann so aus, dass ich die Authentifizierungsmethode zweimal änderte:


MariaDB [mysql]> ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password;
MariaDB [mysql]> FLUSH PRIVILEGES;
MariaDB [mysql]> ALTER USER 'root'@'localhost' IDENTIFIED WITH unix_socket;
MariaDB [mysql]> FLUSH PRIVILEGES;
MariaDB [mysql]> quit

Nachdem die Instanz von mariadbd-safe beendet und der MariaDB-Server neu gestartet wurde, konnte root sich wieder in MariaDB einloggen – der Reparaturversuch war anscheinend geglückt:


# pkill mariadb
# systemctl start mariadb
# mysql
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 3
Server version: 11.8.2-MariaDB-1 from Debian -- Please help get to 10k stars at https://github.com/MariaDB/Server

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

Und auch systemctl status mariadb vermeldete statt der vorherigen Fehler den bedarfsweisen Upgrade der Tabellen:

Upgrading MariaDB tables if necessary.

]]>
MariaDB: Autoincrement bei zusammengesetzten Primärschlüsseln https://blog.jkip.de/mariadb-autoincrement-bei-zusammengesetzten-primaerschluesseln/ https://blog.jkip.de/mariadb-autoincrement-bei-zusammengesetzten-primaerschluesseln/#comments Tue, 29 Jul 2025 14:05:25 +0000 https://blog.jkip.de/?p=1387 Letztens musste ich eine MariaDB-Tabelle vom älteren MyIsam– in das heute geläufige InnoDB-Engine-Format übertragen. Allerdings wurde die Umsetzung mit einer Fehlermeldung quittiert:

ERROR 1075 (42000): Incorrect table definition; there can be only one auto column and it must be defined as a key

Vereinfacht war der Aufbau der MyIsam-Tabelle wie folgt:

CREATE TABLE foo_table (
  foo_group tinyint(3) unsigned NOT NULL,
  foo_id int(10) unsigned NOT NULL AUTO_INCREMENT,
  foo_description varchar(255) NOT NULL,
  PRIMARY KEY(foo_group, foo_id)
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

Der Primary Key der Tabelle foo_table umfasste als Composite Key zwei Spalten: foo_group und foo_id, wobei für foo_id ein auto_increment definiert war.

Eine Abfrage verdeutlicht dies:

MariaDB [foo_db]> select foo_group, foo_id from foo_table;
+-----------+--------+
| foo_group | foo_id |
+-----------+--------+
|         1 |      1 |
|         1 |      2 |
|         1 |      3 |
|         2 |      1 |
|         2 |      2 |
|         3 |      1 |
|         3 |      2 |
|         3 |      3 |
+-----------+--------+
MariaDB [foo_db]>

Der Auto-Increment für foo_id erfolgt demnach nicht global, sondern nur für die jeweilige Gruppe, die durch foo_group definiert ist. Diese Funktionalität ist in InnoDb nicht direkt vorhanden, lässt sich aber mit einem Trigger nachbilden.

Bei einer Konvertierung nach InnoDB muss auch der Auto-Increment entfernt werden, indem foo_id ohne auto_increment neu definiert wird:

ALTER TABLE foo_table
CHANGE foo_id foo_id int(10) unsigned NOT NULL AFTER foo_group,
ENGINE='InnoDB';

Danach kann ein Trigger eingerichtet werden, der bei einem Insert für pro_id den bislang höchsten Wert der entsprechenden Gruppe um 1 erhöht, oder falls noch kein Wert für die Gruppe vorhanden eine 1 zuweist:

DELIMITER $$

CREATE TRIGGER foo_bi BEFORE INSERT ON foo_table
FOR EACH ROW BEGIN
  SET NEW.foo_id = (
    SELECT IFNULL(MAX(foo_id), 0) + 1
    FROM foo_table
    WHERE foo_group = NEW.foo_group
  );
END $$

DELIMITER ;

Beim Einfügen eines Datensatzes über das Datenbank-Tool Adminer gab es allerdings noch ein kleines Problem. Wenn ich das Eingabefeld foo_id überspringe, sendet Adminer einen leeren String, was zu einer Fehlermeldung führt:

Incorrect integer value: '' for column `test1`.`foo_table`.`foo_id` at row 1

Hier hilft ein Default-Wert 0 für foo_id:

ALTER TABLE foo_table
CHANGE foo_id foo_id int(10) unsigned NOT NULL DEFAULT 0 AFTER foo_group;

Der Trigger überschreibt die 0 dann mit dem korrekten Auto-Increment-Wert.

Update:

Jens T. hat mich in den Kommentaren darauf aufmerksam gemacht, dass ein nachträglicher Wechsel von foo_group so nicht möglich ist. Hierzu muss zusätzlich ein entsprechender Trigger für die Updates erstellt werden:

DELIMITER $$

CREATE TRIGGER foo_bu BEFORE UPDATE ON foo_table
FOR EACH ROW BEGIN
  SET NEW.foo_id = (
    SELECT IFNULL(MAX(foo_id), 0) + 1
    FROM foo_table
    WHERE foo_group = NEW.foo_group
  );
END $$

DELIMITER ;

]]>
https://blog.jkip.de/mariadb-autoincrement-bei-zusammengesetzten-primaerschluesseln/feed/ 3
Lighthouse: „Skip links are not focusable“ https://blog.jkip.de/lighthouse-skip-links-are-not-focusable/ https://blog.jkip.de/lighthouse-skip-links-are-not-focusable/#comments Tue, 10 Jun 2025 14:17:07 +0000 https://blog.jkip.de/?p=1378 Bei der Analyse der Barrierefreiheit einer Kundenseite zeigte das Entwickler-Tool Lighthouse in Google Chrome u. a. diesen Fehler an:

Skip links are not focusable

Lighhouse verwies hierbei auf folgenden Skip-Link:


<a class="skip-link screen-reader-text focusable" href="#main">↓ Skip to Main Content</a>

Ich rätselte eine Weile darüber, inwieweit dieser Skip-Link selbst nicht fokussierbar war. Das Problem lag aber woanders, nämlich am nicht vorhandenen Linkziel: ein HTML-Element mit der ID „main“ gab es schlichtweg nicht. Möglicherweise wurde das betreffende HTML-Element irgendwann bei einer Anpassung des Themes entfernt oder umbenannt. Eine Überprüfung auf Barrierefreiheit wurde dabei üblicherweise nicht unternommen. Mit dem Barrierefreiheitsstärkungsgesetz, welches in drei Wochen in Kraft tritt, wird auch die Zugänglichkeit von Webseiten inzwischen ernster genommen.

Nachdem das Linkziel auf den vorhandenen Inhalte-Container umgebogen wurde, hat auch Lighthouse diesen Punkt nicht mehr bemängelt.

]]>
https://blog.jkip.de/lighthouse-skip-links-are-not-focusable/feed/ 1
Firefox und Thunderbird fügen beim Pasten mit xdotool zusätzliches „>“ mit ein https://blog.jkip.de/firefox-und-thunderbird-fuegen-beim-pasten-mit-xdotool-zusaetzliches-mit-ein/ Tue, 03 Jun 2025 13:54:34 +0000 https://blog.jkip.de/?p=1375 Da auf einer ergomischen Maus das Scrollrad als mittlere Maustaste etwas schwerfällig reagierte, hatte ich die mittlere Maustaste mithilfe von xdotool auf eine Tastaturkombination gelegt. In den Tastatur-Einstellungen von Xfce hatte ich hierzu dem Befehl „xdotool click 2“ den Shortcut Ctrl + Insert zugeordnet (auf meiner US-amerikanischen Tastatur liegen diese beiden Tasten praktischerweise direkt nebeneinander). Das funktionierte soweit wie gewünscht: einen zuvor markierten Textabschnitt konnte ich statt mit der mittleren Maustaste auch mit der Tastaturkombination Ctrl + Insert in ein anderes Programm einfügen.

Nur Thunderbird und Firefox verhielten sich da merkwürdig: vor dem kopierten Textabschnitt wurde jeweils ein „> “ eingefügt. Bei anderen Programmen gab es dieses Problem jedoch nicht. Ich behalf mich damit, die überflüssigen Zeichen nach dem Pasten zu entfernen, auf Dauer nervte das Verhalten aber. Nach einiger Recherche kam ich dann auf die simple Ursache: xdotool übersetzt den Shortcurt nicht nur in einen Mausklick, sondern reicht auch die übersetzten Tastatureingaben weiter. Bei den jeweiligen Programmen kam also an: mittlerer Mausklick + Ctrl + Insert. Die beiden Mozilla-Anwendungen haben nun die Eigenart, dass bei einem Einfügen mit mittlerer Maustaste und gedrückter Ctrl- bzw. Strg-Taste ein „> “ mit eingefügt wird, um Zitate zu kennzeichnen.

Gelöst habe ich das Problem schließlich dadurch, dass ich in den Tastatur-Einstellungen von Xfce dem Befehl „xdotool click 2“ den einfachen Shortcut Insert (ohne Ctrl) zugewiesen habe. Da ich die Insert-Taste ansonsten nie in Gebrauch habe, war das für mich praktikabel.

]]>
DNS-Records für Domain ohne E-Mail-Empfang und -Versand https://blog.jkip.de/dns-records-fuer-domain-ohne-e-mail-empfang-und-versand/ Fri, 14 Feb 2025 14:20:55 +0000 https://blog.jkip.de/?p=1360 Nicht selten werden Domains nur als Web-Domain füs die eigenen Webseiten verwendet, jedoch nicht als E-Mail-Domain. Im Impressum wird dann beispielsweise die E-Mail-Adresse einer anderen Domain angegeben. Im Zonefile der Domain gibt es entsprechend keinen MX Record, welcher auf einen Server verweist, der Mails entgegennimmt. Allerdings probieren viele sendende Mailserver dann ersatzweise den Versand an den Server, welcher im A- bzw. im AAAA-Record aufgeführt ist.

Mit einem „Null MX Record“ im Zonefile kann klar zum Ausdruck gebracht werden, dass es keinen empfangenden Mailserver gibt, so dass solche überflüssigen Versuche an anderer Stelle künftig ausbleiben:

@		IN	MX	0 .

Wenn unter der betreffenden Domain keine Mails versendet werden, dann kann mit Einträgen im Zonefile auch das Absender-Spoofing durch Dritte effektiver unterbunden werden, sofern die folgenden Records von empfangenden Mailservern berücksichtigt werden. Mit einem SPF-Reford werden global alle Hosts als Sender ausgeschlossen:

@		IN	TXT	"v=spf1 -all"

Zusätzlich kann eine DMARC-Policy „reject“ klarstellen, dass Mails entsprechend dem SPF-Record und mangels DKIM-Record unbedingt zurückzuweisen sind.

_dmarc		IN	TXT	"v=DMARC1; p=reject"

]]>