Mail server, forward non-spam mails only

Februar 25th, 2022

We are running a mail server and redirecting all mails for former users via an entry in the /etc/aliases file. Unfortunately, we appeared on some spam detection services. I checked our mail logs, there are no indication that some of our hosts are sending SPAM themselves, so this must be our forwards. When users get SPAM, this will be forwarded to their external address. So, we are not sending SPAM, we are relaying it.

To stop this, I invented the following solution:

In /etc/aliases, we do not set a forward for this user, but a pipe:

testuser: /usr/bin/procmail -t -m FORWARD=testuser /etc/procmailrc

The /etc/procmailrc contains the following:

:0
* X-Spam-Level: \*\*\*\*\*\*
{ EXITCODE=77 HOST }

:0
! `cat /etc/forwards/$FORWARD`

Now, we just have to create a file in /etc/forwards for each user, e.g. /etc/forwards/testuser:

new-address@example.com

Wikidata SPARQL – get name and values for specific items

Oktober 10th, 2021

Something which took me quite some time to find out: how to get the name and some values for items where I already know the ID via SPARQL – usually examples query all items which have something in common (e.g. all cats or so). The magic is the „VALUES“ keyword – it’s actually really easy:

select ?item ?itemLabel ?herisId where {
  ?item wdt:P9154 ?herisId.
  VALUES ?item {wd:Q1534177 wd:Q133495}.
  SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en". }
}

Try it yourself!

Creating a conference website with in Drupal 8 (Also: use views to summarize values of fields)

November 15th, 2020

I’m creating a Drupal website for an upcoming conference where we have sessions with a list of contributions (talks, workshops, …). A contribution will be shown in several sessions (actually streamed as the conference will be online due to COVID-19).

Structure

I designed my content-types like this (I removed all non-relevant fields):

Contribution

  • Duration (field_duration), Integer (time in minutes)

Session

  • Start Date (field_start_date), Date with time
  • Contributions (field_contributions), Entity reference to content type Contribution, multiple values

Tasks

In the display of a Contribution I want to show in which sessions it will be shown and at what exact time (which is the start time of the session plus the sum of all preceding contributions).

Also, in the display of a Session I want to list all contributions with the exact start time (and end time).

Views

I found the module Views Cumulative Field, but found it not sufficent, so I looked for a different solution.

I solved this with views using Views Data Export:

View „Contribution Duration“
  • Create a view „Session Contributions Duration“, type „Data Export“, accepted format: „CSV“
  • List content of type „Contribution“
  • Add contextual filter „Content: ID“ (if not available, show all), allow multiple values (under „More“)
  • Add field „Content: ID“ (nid)
  • Add field „Duration“ (field_duration)

Example output:

nid,field_duration
4,15
6,30
11,30
View „Session Contributions Duration“
  • Create a view „Session Contributions Duration“, type „Data Export“, accepted: „CSV“
  • List content of type „Session“
  • Add Contextual Filter „Content: ID“ (if not available, show all)
  • Add field „Start Date“ (field_start_date), formatter „Plain“
  • Add field „Contributions“ (field_contribution_durations), formatter „View“ (Contribution Duration), view arguments „Field value“, multiple, implode with „,“, override with custom text:
    {{ field_contribution_durations|split("\n")|slice(1)|map(c => c|split(",")|join(":"))|join("|") }}

Example output:

field_start_date,field_contribution_durations
2020-11-25T10:00:00,4:15|6:30
2020-11-25T12:00:00,11:30
2020-11-26T10:00:00,4:15|6:30

(First field is the start_date of the session, second is the list of contributions separated by „|“, where the „:“ separates the ID of the contribution and the duration.

View „Sessions of Contribution“
  • Create a view „Sessions of Contribution“, type HTML List of fields (or other, this is for display).
  • List content of type „Session“
  • Add Contextual Filter „Content: Contributions“ ((if not available, hide)
  • Add field „Contributions“ (field_contributions), formatter „View“, View „Session Contributions Duration“, multiple false, rewrite text:
    {% set start_date = field_contributions|split("\n")[1]|split(",")[0] %}
    {% set durations = field_contributions|split("\n")[1]|split(",")[1]|split("|")|map(d => d|split(":")) %}
    {% set not_found = true %}
    {% set offset = 0 %}
    {% for c in durations if not_found %}
    {% if c[0] == arguments.field_contributions_target_id %}
    {% set not_found = false %}
    {% else %}
    {% set offset = offset + c[1] %}
    {% endif %}
    {% endfor %}
    {{ date(start_date)|date_modify("+" ~ offset ~ "minutes")|date('Y-m-d H:i') }}
Content Type „Contribution“, Manage Display:
  • Using Display Field Copy, I created a copy of the Node ID called Sessions. Use the View „Sessions of Contribution“ to display this value, and pass the field value (the Node ID) as only argument.
View „Contributions in Session“
  • Create a view „Sessions of Contribution“, type HTML List of fields (or other, this is for real display).
  • List content of type „Contribution“
  • Add relationship „Content using field_contributions“
  • Add contextual filter „Content: ID“ (if not available, hide), Relationship none, allow multiple values
  • Add contextual filter „Content: ID“ (if not available, show all), Relationship field_contributions
  • Add field „Content: ID“ (nid), Relationship none, Exclude from display
  • Add field „Content: ID“ (nid_1), Relationship field_contributions, Formatter View, View „Session Contributions Duration“, View Arguments Field Value, rewrite text:
    {% set offset = 0 %}
    {% set not_found = true %}
    {% set durations = nid_1|split("\n")[1]|split(",")[1]|split("|")|map(d => d|split(":")) %}
    {% set start_date = nid_1|split("\n")[1]|split(",")[0] %}
    {% for c in durations if not_found %}
    {% if c[0] == nid %}
    {% set not_found = false %}
    {% else %}
    {% set offset = offset + c[1] %}
    {% endif %}
    {% endfor %}
    {{ date(session_start)|date_modify("+" ~ offset ~ "minutes")|date('Y-m-d H:i') }}

When previewing this view, use something like „1,2/3“ where 1 and 2 are the IDs of contributions of a session and 3 the session ID.

Content Type „Session“, Manage Display:
  • Field „Contributions“: Format „View“, View „Contributions in Session“, View Arguments: Field Value and Entity ID, multiple implode by „,“.
View „Sessions“ (optional)
  • Create a view „Sessions“, type HTML List of fields (or other, this is for real display).
  • List content of type „Session“
  • Add field „Contributions“, Formatter View, View „Contributions in Session“, View Arguments: Field Value and Entity ID, multiple implode by „,“.

Conclusion

Of course, most of these views (except of the Data Exports) have additional fields, because sessions have names, contributions have titles and presenters. And the contribution lists also add the end date. I hope, you can figure out how to add this yourself.

OpenStreetMap/Wikidata: How I map artwork and memorials

März 24th, 2020

I love mapping for the OpenStreetMap project, it’s a very pleasing thing to do. I especially like to do it as vacation activity, because then I’m exploring new places anyway, but I also like to do it at home.

Recently I’m concentrating on mapping artwork and memorials. Even in a well-mapped city like Vienna, Austria, there’s still plenty to do. For example, most social housing building complexes (Vienna is famous for it’s social housing) have some kind of artwork, e.g. some murals or statues in the gardens.

Some examples:

I think, having a map feature in OpenStreetMap is not enough though. I want to add pictures and meta data (who made the object, when was it created, …). This is done in cooperation with the Wikimedia Foundation. In this article, I want to explain how I map these objects.

1. Wikimedia Commons

Often these objects already have photos on Wikimedia Commons. If not, I upload one or a few photos (whatever is reasonable). If there are several photos of the picture (or the object seems important enough), I create a category for the object (if it does not exist yet).  Of course, the category should have the relevant categories for the location, the motive, the artist, etc.

2. Wikidata

Next, each object should have its own Wikidata entry. Haven’t heard of Wikidata yet? It’s a sister project to Wikipedia and Wikimedia Commons. As Wikimedia Commons is the platform for media (which is linked by Wikipedia), Wikidata is a platform for semantic and linked data. E.g. an entry for a city would have values for the population size at specific historic dates, links to the wikidata entry of current and former mayors, link to other data sources (Encyclopedia Brittanica, Library of Congress), link to its Wikimedia Commons category, and so on (e.g. Vienna). Most infoboxes in Wikipedia are now automatically created from Wikidata data.

So, each object should have its own Wikidata entry. Of course, you should check if a Wikidata entry already exists – if yes, check if the data is complete. It should have values for (if available):

  • label and description (at least in local language, preferred also in English)
  • instance of (e.g. memorial monument, sculpture, …)
  • depicts (the entity being depicted)
  • dedicated to
  • geographic coordinates
  • image (link to a Wikimedia Commons image)
  • commons category (link to the Wikimedia Commons category for this object)
  • country
  • administrative territorial entity
  • inception (start date; if possible the date of its inauguration)
  • material used

When done, edit the Wikimedia Commons category, and add the following line (replace „Q1234“ by the ID of the wikidata entry), so that the category gets a nice infobox on the side:

{{Wikidata Infobox|qid=Q1234}}

3. OpenStreetMap

Finally, the map feature in OpenStreetMap. This can be a node or an area. If the object is located on the wall of a building I make the node a part of the building contour. The entry should have the following tags:

Further tags like wikipedia=*, image=*, wikimedia_commons=* are not necessary, as this information can be read from the Wikidata entry. I do not remove these tags though, if I find them.

Often, map features already have a wikidata/wikipedia-tag which points to the person which it memorizes. This is wrong, because this should be a „subject:wikidata“ resp. „subject:wikipedia“ tag. Please change this.

Final

How can you test your entries? There’s a list of tools which let you explore wikidata tags. I recommend OpenStreetBrowser, which is an application for OpenStreetMap data written by myself. It will show images of the map features and excerpts of Wikipedia articles.

Examples

Here are some examples of such features:

Install OpenLDAP

Oktober 18th, 2019

A few things to memorize about installing OpenLDAP with Samba and LAM:

Enable SSL

# File: ldap-ssl.ldif
# ldapmodify -Y EXTERNAL -H ldapi:/// -f ldap-ssl.ldif
dn: cn=config
add: olcTLSCertificateKeyFile
olcTLSCertificateKeyFile: /etc/ssl/private/server.key
-
add: olcTLSCertificateFile
olcTLSCertificateFile: /etc/ssl/server.crt
-
add: olcTLSCACertificateFile
olcTLSCACertificateFile: /etc/ssl/DigiCertCA.crt

Make sure that OpenLDAP is allowed to read those files. Additionally, apparmor denied access to these files, so I had to allow this specifically for slapd.

After this, I updated the value SLAPD_SERVICES in /etc/default/slapd: SLAPD_SERVICES=“ldapi:/// ldaps:///“

Deny anonymous access

# File: ldap-ssl.ldif
# ldapmodify -Y EXTERNAL -H ldapi:/// -f ldap-ssl.ldif
dn: cn=config
changetype: modify
add: olcDisallows
olcDisallows: bind_anon

dn: cn=config
changetype: modify
add: olcRequires
olcRequires: authc

dn: olcDatabase={-1}frontend,cn=config
changetype: modify
add: olcRequires
olcRequires: authc

I created an additional organisational unit ou=services,dc=example,dc=com where all services are listed. This is also a great way of documenting which services exist in the network.

Secure access to sambaNTPassword (in the default installation, only access to userPassword is secured):

# File: updateOlcAcess.ldif
# ldapmodify -Y EXTERNAL -H ldapi:/// -f updateOlcAccess.ldif
dn: olcDatabase={1}mdb,cn=config
changetype: modify
replace: olcAccess
olcAccess: {0}to attrs=userPassword,sambaNTPassword by self write by anonymous auth by * none
olcAccess: {1}to attrs=shadowLastChange,sambaPwdLastSet by self write by * read
olcAccess: {2}to * by * read

Allow ‚otherMailbox‘ values

We want to save additional mail addresses (e.g. when we want to reach the user privately). For this we use the ‚otherMailbox‘ attribute, which is not available in the normal schemas. We use extensibleObject for this:

# File: otherMailbox.ldif
dn: cn=user,ou=people,dc=example,dc=com
changetype: modify
add: objectClass
objectClass: extensibleObject
-
add: otherMailbox
otherMailbox: user@external.com

Klimaschutz, Lebenswerte Stadt: Ausbau des Radnetzes in Wien

Juni 6th, 2019

Derzeit wird viel darüber geredet, dass ein Erreichen der Klimaziele nur mit einer massiven Reduktion des motorisierten Individualverkehrs erreichbar ist. Ein Umstellen auf Elektroautos verbessert die Situation nur marginal, da ein Großteil der  CO2-Emissionen schon beim Bau erfolgt. Außerdem wünschen sich Menschen lebenswertere Städte – Städte die nicht nur als Verkehrsräume für ineffiziente Fahrzeuge dienen.

Es gibt ein Fahrzeug, das unseren Planeten retten könnte: Das Fahrrad. (Beinahe) Emissionsfrei, Platzsparend, effizient. Und es macht die Bevölkerung gesund – erstens da keine giftigen Emissionen anfallen und zweitens weil Leute die Radfahren ihre täglichen Bewegungseinheiten bekommen und dadurch gesünder und produktiver sind.

Was fehlt, damit mehr Leute auf das Fahrrad steigen? Infrastruktur, auf der man sich sicher fühlt und sicher ist; wie sie z.B. in den Infrastrukturrichtlinien der Radlobby Wien definiert werden. Kurz zusammengefasst: Entweder im Mischverkehr auf verkehrsberuhigten Straßen (max. 30 km/h, kaum Durchzugsverkehr) oder baulich getrennte Radwege. Mehrzweckstreifen, die Radfahrende in die Türzone von parkenden Autos und toten Winkel von LKWs drängen, sind keine Option. Außerdem sollten Radfahrende und Zu-Fuss-gehende getrennt werden um Konflikte zu vermeiden (wie z.B. am Ring). Parkplatzverlust darf keine Radwege verhindern dürfen!

Die Stadt Wien hat dazugelernt, die in den letzten Jahren entstandenen Radinfrastrukturen entsprechen oft diesen Richtlinien. Der Ausbau geht aber viel zu langsam, obwohl ein solches bereits 2003 ein Hauptradverkehrsnetz definiert wurde. Es wäre wichtig, endlich ein durchgehendes Radnetz zu schaffen. Mein Wunsch an die nächste Wien-Regierung (spätestens im Herbst 2020 wird ja wieder gewählt) wäre, dass dieses endlich umgesetzt wird.

Ein paar konkrete Forderungen dazu:

  • Lückenschluss Gürtelradweg zwischen Eichenstraße und Hauptbahnhof
    Derzeit wird man hier durch Nebenstraßen geschickt – nicht attraktiv. Mein Wunsch wäre ein Zweirichtungsradweg auf der nördlichen Seite – damit die anwohnende Bevölkerung diesen gut nutzen kann.
  • Durchfahrten durch den ersten Bezirk
    Es sind einige Einbahnöffnungen notwendig, z.B. Habsburgergasse; außerdem gehören die Routen besser angeschrieben
  • Lückenschluss Margaretenstraße
    Nach der Einbahnöffnung heuer zwischen Spengergasse und Margeretenplatz fehlen nur noch wenige hundert Meter zum Gürtel. Angeblich ist eine Einbahnöffnung nicht geplant. Dabei würde hier eine super Radroute zwischen Zentrum und dem Herzen Meidlings entstehen, da die Arndtstraße bereits vollständig in beide Richtungen befahrbar ist. Die Infrastruktur zwischen Zentrum und Margaretenplatz gehört aber angepasst, da tw. Mehrzweckstreifen, tw. zu schmale Radwege die bereits jetzt am Kapazitätslimit sind.
  • Verbindung Karlsplatz -> Getreidemarkt, Karlsplatz -> Linke Wienzeile
    Vom Karlsplatz kommend sind die entsprechenden Radwege nur durch Umwege erreichbar. Ein Möglichkeit wäre ein Zweirichtungsradweg zwischen Treitlstraße und Getreidemarkt (bis Lehárgasse).
  • Karlsplatz: Radweg Rechte Wienzeile – Lothringerstraße
    Durch den Resselpark wird derzeit sehr viel Rad gefahren – eine Entlastung wäre eine Umwidmung einer der drei Fahrspuren um Radweg.
  • Ringradweg
    Hier ist eine Trennung zwischen Zu-Fuss-Gehenden und Radverkehr notwendig. Z.B. könnte auf eine Kfz-Fahrspur reduziert werden und der gewonnene Platz für Radwege genutzt werden.

Dies ist nur eine kleine Auswahl an Maßnahmen. Ein gut ausgebautes, verbundenes Radnetz wird viel genutzt werden – das zeigen die Erfahrungen aus anderen Städten. Es entlastet den öffentlichen Verkehr, besonders zu den Stoßzeiten und kann damit beitragen zu einer Reduktion des motorisierten Individualverkehrs. Die Errichtung kostet natürlich Geld – ist aber im Vergleich zu Alternativen sehr kostengünstig. Straßen für Kfz und Ausbau des öffentlichen Verkehrs kostet ein Vielfaches!

Ich hoffe, dass sich in Wien zukünftig mehr bewegt.

Installing Mailman3 on Ubuntu 18.04 with MariaDB

Mai 24th, 2019

Installing Mailman3 on Ubuntu 18.04 was surprisingly difficult, that’s why I want to share my experiences with the world. Here you are:

https://gist.github.com/plepe/dab22fdbfec63d8632709065890124a3

Vortrag Linuxwochen 2019: Overpass API – die Datenbank zur OpenStreetMap

Mai 2nd, 2019

Hier die Folien für meinen Vortrag auf den Linuxwochen 2019:

Auf Github gibt es denn Source code für die Folien (in Markdown).

PHP with webpage user permissions on Ubuntu 18.04 Bionic Beaver (using PHP-CGI and Apache2.4 with mod_fcgid)

März 4th, 2019

Usually, PHP runs with the permissions of the Webserver Apache2, which has several disadvantages. One, that files created by the webpage will have different user permissions as the user the webpage belongs to. Also there’s a security concern, as webpages of other users on the server could access your data and configuration.

With Ubuntu 16.04 we used the Apache2 FastCGI module, which is no longer available from this how to. This here are the updated instructions for Fcgid.

In our environment we wanted to have a webserver which runs PHP with the permissions of the user the webpage belongs to. This is what we did (starting from a blank Ubuntu 18.04 installation):

apt install libapache2-mod-fcgid apache2 php-cgi apache2-suexec-pristine
a2enmod userdir

Add the following to /etc/apache2/sites-available/default-ssl.conf:

<FilesMatch \.php$>
  AddHandler fcgid-script .php
</FilesMatch>

Allow ExecCGI for userdir in /etc/apache2/mods-enabled/userdir.conf:

Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec ExecCGI

In the user public_html directory create two files:

~USER/public_html/.htaccess:

FcgidWrapper /home/USER/public_html/.php-fastcgi.fcgi .php

~USER/public_html/.php-fastcgi.fcgi (must be executable and belong to the user):

#!/bin/sh
PHP_FCGI_CHILDREN=4
PHP_FCGI_MAX_REQUESTS=5000
export PHP_FCGI_CHILDREN PHP_FCGI_MAX_REQUESTS
exec php-cgi

Have fun! Please don’t hesitate to leave a comment :-)

Aktueller Stand Planung Radweg Linke Wienzeile

Februar 1st, 2019

Ich kann es ja immer noch fast nicht glauben, der Lückenschluss des Wientalradweges wird heuer gebaut. Fahrrad Wien hat heute den aktuellen Stand der Planung präsentiert. So ähnlich hatte ich das Ergebnis auch erwartet, mit Ladezonen, Verschwenkung beim Theater an der Wien, etc. Damit kann man sehr zufrieden sein.

Sehr spannend finde ich ja auch, dass heuer die Querung über den Gürtel zwischen Mollardgasse und Ullmannstraße gebaut werden soll. Damit entsteht eine Radroute Innenstadt – 6. Bezirk (Linke Wienzeile – Magdalenenstraße – Mollardgasse) – 15. Bezirk (Ullmannstraße via Sparkassaplatz) – Lobkowitzbrücke – 12. Bezirk (Meidling Hauptstraße) bzw. 14. Bezirk (Wientalradweg).

Ich sehe allerdings noch weiteren Verbesserungsbedarf:

  • Anschluss Oper: Ich war skeptisch, ob der Radweg tatsächlich bis zur Oper gebaut wird. Und tatsächlich, auf Höhe Café Museum muss man auf die Südostseite der Operngasse wechseln, was eine zusätzliche Ampelwartezeit verursacht.
  • Was noch mehr schmerzt: Der fehlende Anschluss an den Radweg Getreidemarkt nach Norden (wenn der kommen würde, wäre es sicher erwähnt worden) – Es wird weiterhin der Umweg durch die Nibelungengasse notwendig sein. Darum hatte ich schon vor Jahren dafür plädiert, den Getreidemarktradweg auf der westlichen Seite als Zweirichtungsradweg auszuführen. Die Stadtplanung wird sich nicht trauen, die Fahrbahn Getreidemarkt Richtung Norden auf eine Fahrspur zu reduzieren.
  • Weiteres Manko: wie befürchtet, fehlt die Verbindung vom Karlsplatz (Treitlstraße) zum neuen Radweg Linke Wienzeile. Der Radverkehr durch den Bärenmühldurchgang wird weiter zunehmen. So hätte man das bauen können (bzw. auch hier).
  • Was ich mir noch wünschen würde: Eine Einbahnöffnung der Girardigasse und der Lehárgasse. Dies würde eine wichtige Radroute zwischen 3., 4., 6. und 7. Bezirk ergeben (Schwarzenbergplatz – Gusshausstraße – Schleifmühlgasse – Linke Wienzeile – Girardigasse – Lehárgasse – Filigradergasse – Windmühlgasse – Mariahilfer Straße). Es ist nicht tragisch, wenn es jetzt nicht kommt, die aktuelle Planung verhindert eine solche Radroute nicht. (Auch eine alte Idee von mir)

Ich freue mich schon auf die Erstberadelung!