Transliter… what?

Every now and then I am challenged with modifying Unicode-strings. Whether by converting from any non-ASCII script to ASCII or handling differently normalized strings, all of these actions are called “Transliteration”

I first encountered that when I built an application that create PDF-Files on a Linux-Server that would then be overwritten from an application running on a mac that had the folder mounted via CIFS. Everything was working great. Until one of the people thought it would be a great idea to enter a filename with a german Umlaut. So the application created the file “example_ä.pdf” on the server. After some time we realized that there was a second file in that folder with the name “example_ä.pdf”.



Continue reading Transliter… what?

Farewell Enigmail

Thunderbird has End-to-End encryption right built into it’s very core. But at a price that was annoying to me. So I decided to keep the old 68 Version together with the enigmail plugin.

Until my system recently did an update and replaced the old thunderbird with the shiny new version 78. Which comes with its very own implementation of Pretty Good Privacy – better known as PGP.

Short recap: The Enigmail plugin used a system-installed GnuPG installation (Open Source PGP-Implementation). Thunderbird on the other hand uses a library called RNP.

This has 2 drawbacks. One is, that it is a bit harder to setup my current workflow which uses a private key located on a Yubikey that I have to unlock. The setup was not as easy as it was described in some of the descriptions on the internet. But that was mainly due to my own fault. A configuration setting that did work with Enigmail but didn’t with the new Version of Thunderbird.

The main issue is that RNP currently does not support hardware tokens. But luckily there is a flag that can delegate tasks that require private keys to a third party app. So I could setup the default GnuPG to handle the signing and the decryption process. One additional advantage is that I do not need to expose private keys to Thunderbird where they need to be secured by a single master password. But that is a different story.

RNP is not GnuPG

The – for me – more annoying part is, that RNP does not use the systemwide GnuPG keychain but its own one. So for me that means that I have to maintain two keychains with public keys.

I found that a bit awkward. So I looked for a way to automatically keep the two keychains in sync. And after a bit of digging I figured, that Thunderbird keeps a GnuPG compatible public keychain right in Thunderbirds profile folder. So all I have to do is write a cron-job that exports all the public keys from one keychain and moves them over to the respective other one. Already existing keys will not be imported, missing ones will be imported though.

So this is what I now have installed as cron-job:

gpg --no-default-keyring \
    --keyring=$THUNDERBIRD_PROFILE/pubring.gpg \
    --export \
    --armor | gpg --import --no
gpg --export --armor | gpg \
    --no-default-keyring \
    --keyring=$THUNDERBIRD_PROFILE/pubring.gpg \
    --import \

Optimization will follow soon by replacing the hard-coded path to the profile folder with a command that reads that from thunderbirds profile.ini file. But that is a different story.

The only drawback I have seen so far is that Thunderbird needs to be restarted after the script has actually imported one or more keys into the thunderbilrd keychain. Otherwise the new keys are not recognized.

But that is much less of a hassle and drawback than not being able to sign my outgoing email or decrypt my incoming mails.

Named Parameters

Currently an awesome RFC to introduce Named Parameters to PHP is in the voting phase. As I voted against this RFC and some people asked me about my reasoning I thought I share it here.

After this tweet I had some interesting conversations on and off twitter that made me think about my take on named parameters back and forth.

And as much as I like the idea of named parameters I still see one major issue in the currently proposed implementation: Changing Parameter names.

Continue reading Named Parameters

inspecting docker-networks

Or how not to handle a non-responsive docker container


Handle “Cannot start service XY: driver failed programming external connectivity on endpoint XY (ContainerID): Bind for failed: port is already allocated” by inspecting dockers network stack and force-disconnect containers from the network.

The Problem

Today we had a non-responsive docker container that we couldn’t restart. docker-compose stop and such didn’t work. The container was still running and – especially nasty – also not responding. The website it usually provides only returned a 503 – Gateway not responding.

What to do?

Well… not what we did!
Continue reading inspecting docker-networks

Handle self-signed certificates with PHPs LDAP-Extension

Often I see questions on StackOverflow stating that connecting to LDAP-Servers secured with self-signed certificates is difficult and troublesome. Very often the accepted answer or the one with the most votes is actually the worst answer, as usually it requires to completely ignore certificates. So basically swapping the certificate would not be noticed, leaving the connection wide open for a Man-in-the-Middle attack and therefore somehow defeating the purpose of secure connections.

But how does one connect securely to an LDAP-Server secured with a self-signed certificate?

I did some tests and summarized my findings in a github-repo.

In essence it boils down to retrieving the current certificate either from the admin of the LDAP-Server or via OpenSSL using this command:

$ echo \
| openssl s_client -connect openldap:636 2> /dev/null \
| openssl x509 -text \
> /path/to/cert.pem

And then – at least when you have a supported PHP-Version – add the following lines to your ldap-code:

ldap_set_option(null, LDAP_OPT_X_TLS_CACERTDIR, '/path/to');
ldap_set_option(null, LDAP_OPT_X_TLS_CACERTFILE, '/path/to/cert.pem');

// either
$ldap = ldap_connect('ldaps://');
// or
$ldap = ldap_connect('ldap://');

Note: It’s important to call ldap_set_option before the first LDAP-Command and use null as the first argument. Otherwise it will not work 😉

You want more info? Have a look at the Repos README