From 999e965d2ee820128a3fd04f160ec78f22971fbe Mon Sep 17 00:00:00 2001
From: Julian Rother <julian@cccv.de>
Date: Tue, 26 Oct 2021 17:57:06 +0200
Subject: [PATCH] Debian packaging with fixed systemd unit files

Co-authored-by: nd <nd@cccv.de>
---
 .gitlab-ci.yml                                |  15 ++-
 README.md                                     |  29 ++++-
 cccv-archive-key.gpg                          | Bin 0 -> 1752 bytes
 debian/contrib/uffd-socketmap-postfix.conf    |   7 ++
 .../contrib/uffd-socketmap-postfix.service    |  14 ++-
 debian/contrib/uffd-socketmap-postfix.socket  |  11 ++
 debian/control                                |  16 +++
 debian/create_changelog.py                    | 106 ++++++++++++++++++
 debian/install                                |   4 +
 debian/links                                  |   1 +
 debian/postinst                               |  21 ++++
 debian/rules                                  |   3 +
 server.py                                     |   1 +
 uffd-socketmap@.socket                        |  12 --
 14 files changed, 214 insertions(+), 26 deletions(-)
 create mode 100644 cccv-archive-key.gpg
 create mode 100644 debian/contrib/uffd-socketmap-postfix.conf
 rename uffd-socketmap@.service => debian/contrib/uffd-socketmap-postfix.service (70%)
 create mode 100644 debian/contrib/uffd-socketmap-postfix.socket
 create mode 100644 debian/control
 create mode 100755 debian/create_changelog.py
 create mode 100644 debian/install
 create mode 100644 debian/links
 create mode 100755 debian/postinst
 create mode 100755 debian/rules
 mode change 100644 => 100755 server.py
 delete mode 100644 uffd-socketmap@.socket

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index a0eb5d3..10cafd6 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,7 +1,7 @@
 image: registry.git.cccv.de/uffd/docker-images/buster
 
 variables:
-  DEBIAN_FRONTEND: noninteractive 
+  DEBIAN_FRONTEND: noninteractive
   GIT_SUBMODULE_STRATEGY: normal
   PYLINT_PIN: pylint~=2.10.0
 
@@ -12,6 +12,17 @@ before_script:
   - python3 -m pylint --version
   - python3 -m coverage --version
 
+build:apt:
+  script:
+  - ./debian/create_changelog.py uffd-socketmap > debian/changelog
+  - dpkg-buildpackage -us -uc
+  - mv ../*.deb ./
+  - dpkg-deb -I *.deb
+  - dpkg-deb -c *.deb
+  artifacts:
+    paths:
+    - ./*.deb
+
 linter:bullseye:
   image: registry.git.cccv.de/uffd/docker-images/bullseye
   stage: test
@@ -19,7 +30,7 @@ linter:bullseye:
   - pip3 install $PYLINT_PIN pylint-gitlab pylint-flask-sqlalchemy # this force-updates jinja2 and some other packages!
   - python3 -m pylint --exit-zero --rcfile .pylintrc --output-format=pylint_gitlab.GitlabCodeClimateReporter 'server.py' > codeclimate.json
   - python3 -m pylint --exit-zero --rcfile .pylintrc --output-format=pylint_gitlab.GitlabPagesHtmlReporter 'server.py' > pylint.html
-  - python3 -m pylint --rcfile .pylintrc --output-format=text 'server.py' 
+  - python3 -m pylint --rcfile .pylintrc --output-format=text 'server.py'
   artifacts:
     when: always
     paths:
diff --git a/README.md b/README.md
index a4083d6..670f8e3 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,29 @@
-Socketmap proxy for uffd mail alias lookup
-==========================================
+Socketmap server to integrate uffd mail aliases with postfix
+============================================================
+
+[uffd](https://git.cccv.de/uffd/uffd) has features that rely on mail aliases.
+To make those mail aliases work, it provides an API to lookup alias addresses
+for a given address. uffd-socketmap uses this API to integrate alias lookup
+with MTAs that support the socketmap protocol, like sendmail and postfix.
+
+uffd-socketmap can be run manually. For production deployments, use the
+provided debian packages. Add our package mirror to `/etc/sources.list`:
 
-Run it like this:
 ```
-SERVER_API_KEY=my_secret_api_key server.py --socket-path /var/run/uffd-socketmap.sock --api-url=https://sso.example.com
+deb https://packages.cccv.de/uffd bullseye main
 ```
+Then download [cccv-archive-key.gpg](cccv-archive-key.gpg) and add it to
+the trusted repository keys in `/etc/apt/trusted.gpg.d/`. Afterwards run
+`apt update && apt install uffd-socketmap` to install the package.
+
+Set the API url and secret in `/etc/uffd-socketmap-postfix.conf`, enable
+and start `uffd-socketmap-postfix.socket`. Then configure Postfix, e.g.
+by adding the following lines to `/etc/postfix/main.cf`:
 
-Configure Postfix to use it by setting `virtual_alias_maps` in `/etc/postfix/main.cf` like this:
 ```
-virtual_alias_maps = socketmap:unix:/var/run/uffd-socketmap.sock:virtual
+# Note that postfix runs in a chroot (/var/spool/postfix) and paths are
+# relative to that!
+virtual_alias_maps = socketmap:unix:/uffd-socketmap.sock:virtual
+# Defaults to $virtual_alias_maps, which does not work here, so unset it
+virtual_alias_domains =
 ```
diff --git a/cccv-archive-key.gpg b/cccv-archive-key.gpg
new file mode 100644
index 0000000000000000000000000000000000000000..b0ac4de43a0786a52060bade75c5150ac552ade7
GIT binary patch
literal 1752
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
N_@ZXs9flCkAOI7rD7ydv

literal 0
HcmV?d00001

diff --git a/debian/contrib/uffd-socketmap-postfix.conf b/debian/contrib/uffd-socketmap-postfix.conf
new file mode 100644
index 0000000..c427afa
--- /dev/null
+++ b/debian/contrib/uffd-socketmap-postfix.conf
@@ -0,0 +1,7 @@
+# Both options must be set
+#SERVER_API_URL="https://localhost"
+#SERVER_API_KEY="my_secret_api_token"
+
+# The socket path is hard-coded to "/var/spool/postfix/uffd-socketmap.sock"
+# ("/uffd-socketmap.sock" in the postfix sandbox). Use systemd overwrites
+# for uffd-socketmap-postfix.socket to change it.
diff --git a/uffd-socketmap@.service b/debian/contrib/uffd-socketmap-postfix.service
similarity index 70%
rename from uffd-socketmap@.service
rename to debian/contrib/uffd-socketmap-postfix.service
index 50344e7..65a8275 100644
--- a/uffd-socketmap@.service
+++ b/debian/contrib/uffd-socketmap-postfix.service
@@ -1,17 +1,19 @@
 [Unit]
-Description=Socketmap proxy for uffd mail alias lookup
+Description=Socketmap server to integrate uffd mail aliases with postfix
 After=network.target
 Before=postfix.service
+BindsTo=uffd-socketmap-postfix.socket
 
 [Service]
 ExecStart=/usr/bin/uffd-socketmap --socket-fd 3
 
 Restart=always
 RestartSec=10
-StandardOutput=syslog
-StandardError=syslog
-SyslogIdentifier=uffd-socketmap-%I
+StandardOutput=journal
+StandardError=journal
+SyslogIdentifier=uffd-socketmap-postfix
 
+DynamicUser=true
 PrivateUsers=true
 CapabilityBoundingSet=
 NoNewPrivileges=true
@@ -34,9 +36,9 @@ PrivateTmp=true
 PrivateDevices=true
 SystemCallArchitectures=native
 SystemCallFilter=@system-service
+MemoryDenyWriteExecute=true
 
-EnvironmentFile=/etc/uffd-socketmap/defaults
-EnvironmentFile=/etc/uffd-socketmap/$I.env
+EnvironmentFile=/etc/uffd-socketmap-postfix.conf
 
 [Install]
 WantedBy=default.target
diff --git a/debian/contrib/uffd-socketmap-postfix.socket b/debian/contrib/uffd-socketmap-postfix.socket
new file mode 100644
index 0000000..3c2e0a4
--- /dev/null
+++ b/debian/contrib/uffd-socketmap-postfix.socket
@@ -0,0 +1,11 @@
+[Unit]
+Description=Socketmap server to integrate uffd mail aliases with postfix
+
+[Socket]
+ListenStream=/var/spool/postfix/uffd-socketmap.sock
+SocketUser=postfix
+SocketGroup=postfix
+SocketMode=0640
+
+[Install]
+WantedBy=sockets.target
diff --git a/debian/control b/debian/control
new file mode 100644
index 0000000..22732be
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,16 @@
+Source: uffd-socketmap
+Section: python
+Priority: optional
+Maintainer: CCCV <it@cccv.de>
+Build-Depends:
+ debhelper-compat (= 12),
+Standards-Version: 4.5.0
+Homepage: https://git.cccv.de/uffd/socketmap-proxy
+Vcs-Git: https://git.cccv.de/uffd/socketmap-proxy.git
+
+Package: uffd-socketmap
+Architecture: all
+Depends:
+ ${misc:Depends},
+ python3-requests,
+Description: Socketmap server to integrate uffd mail aliases with postfix
diff --git a/debian/create_changelog.py b/debian/create_changelog.py
new file mode 100755
index 0000000..b62f211
--- /dev/null
+++ b/debian/create_changelog.py
@@ -0,0 +1,106 @@
+#!/usr/bin/python3
+import sys
+import re
+import textwrap
+import datetime
+import email.utils
+
+import git
+
+package_name = 'UNKNOWN'
+
+alias_names = {
+	'julian': 'Julian Rother',
+	'Julian': 'Julian Rother',
+}
+
+ignore_commit_regexes = [
+	'^fixup!',
+]
+
+def print_release(tag=None, commits=tuple(), last_tag=None):
+	release_version = '0.0.0'
+	release_author = git.objects.util.Actor('None', 'undefined@example.com')
+	release_date = 0
+	release_status = 'UNRELEASED'
+	message = ''
+
+	if tag:
+		release_status = 'unstable'
+		release_version = tag.name[1:] # strip leading "v"
+		if isinstance(tag.object, git.TagObject):
+			release_author = tag.object.tagger
+			release_date = tag.object.tagged_date
+			message = tag.object.message.split('-----BEGIN PGP SIGNATURE-----')[0].strip()
+		else:
+			release_author = tag.object.committer
+			release_date = tag.object.committed_date
+	elif commits:
+		release_author = commits[0].committer
+		release_date = commits[0].committed_date
+		date = datetime.datetime.fromtimestamp(release_date).strftime('%Y%m%dT%H%M%S')
+		last_version = '0.0.0'
+		if last_tag:
+			last_version = last_tag.name[1:] # strip leading "v"
+		release_version = f'{last_version}+git{date}-{commits[0].hexsha[:8]}'
+
+	print(f'{package_name} ({release_version}) {release_status}; urgency=medium')
+	print()
+	if message:
+		print(textwrap.indent(message, '  '))
+		print()
+	commit_authors = [] # list of (key, author), sorted by first commit date
+	commit_author_emails = {} # author email -> key
+	commit_author_names = {} # author name -> key
+	commit_author_commits = {} # key -> list of commits
+	for commit in commits:
+		if any(filter(lambda pattern: re.match(pattern, commit.summary), ignore_commit_regexes)):
+			continue
+		if len(commit.parents) > 1:
+			continue # Ignore merge commits
+		author_name = alias_names.get(commit.author.name, commit.author.name)
+		key = commit_author_emails.get(commit.author.email)
+		if key is None:
+			key = commit_author_names.get(author_name)
+		if key is None:
+			key = commit.author.email
+			commit_authors.append((key, author_name))
+		commit_author_emails[commit.author.email] = key
+		commit_author_names[author_name] = key
+		commit_author_commits[key] = commit_author_commits.get(key, []) + [commit]
+	commit_authors.sort(key=lambda args: len(commit_author_commits[args[0]]))
+	for key, author_name in commit_authors:
+		print(f'  [ {author_name} ]')
+		for commit in commit_author_commits[key]:
+			lines = '\n'.join(textwrap.wrap(commit.summary, 90))
+			lines = '  * ' + textwrap.indent(lines, '    ').strip()
+			print(lines)
+		print()
+	print(f' -- {alias_names.get(release_author.name, release_author.name)} <{release_author.email}>  {email.utils.formatdate(release_date)}')
+
+if __name__ == '__main__':
+	repo = git.Repo('.')
+	package_name = sys.argv[1]
+
+	version_commits = {}
+	for tag in repo.tags:
+		if not re.fullmatch('v[0-9]+[.][0-9]+[.][0-9]+.*', tag.name):
+			continue
+		if isinstance(tag.object, git.TagObject):
+			commit_hexsha = tag.object.object.hexsha
+		else:
+			commit_hexsha = tag.object.hexsha
+		version_commits[commit_hexsha] = tag
+
+	tag = None
+	commits = []
+	for commit in repo.iter_commits('HEAD'):
+		if commit.hexsha in version_commits:
+			prev_tag = version_commits[commit.hexsha]
+			if commits:
+				print_release(tag, commits, last_tag=prev_tag)
+				print()
+			tag = prev_tag
+			commits = []
+		commits.append(commit)
+	print_release(tag, commits)
diff --git a/debian/install b/debian/install
new file mode 100644
index 0000000..e886322
--- /dev/null
+++ b/debian/install
@@ -0,0 +1,4 @@
+server.py /usr/lib/uffd-socketmap/
+debian/contrib/uffd-socketmap-postfix.service /usr/lib/systemd/system/
+debian/contrib/uffd-socketmap-postfix.socket /usr/lib/systemd/system/
+debian/contrib/uffd-socketmap-postfix.conf /etc/
diff --git a/debian/links b/debian/links
new file mode 100644
index 0000000..5c199f3
--- /dev/null
+++ b/debian/links
@@ -0,0 +1 @@
+/usr/lib/uffd-socketmap/server.py /usr/bin/uffd-socketmap
diff --git a/debian/postinst b/debian/postinst
new file mode 100755
index 0000000..bdba6dc
--- /dev/null
+++ b/debian/postinst
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+set -e
+
+case "$1" in
+	configure)
+		chmod 0640 /etc/uffd-socketmap-postfix.conf
+	;;
+
+	abort-upgrade|abort-remove|abort-deconfigure)
+	;;
+
+	*)
+		echo "postinst called with unknown argument \`$1'" >&2
+		exit 1
+	;;
+esac
+
+#DEBHELPER#
+
+exit 0
diff --git a/debian/rules b/debian/rules
new file mode 100755
index 0000000..cbe925d
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,3 @@
+#!/usr/bin/make -f
+%:
+	dh $@
diff --git a/server.py b/server.py
old mode 100644
new mode 100755
index 3fbfc67..dd59646
--- a/server.py
+++ b/server.py
@@ -1,3 +1,4 @@
+#!/usr/bin/python3
 import os
 import sys
 import logging
diff --git a/uffd-socketmap@.socket b/uffd-socketmap@.socket
deleted file mode 100644
index dcff275..0000000
--- a/uffd-socketmap@.socket
+++ /dev/null
@@ -1,12 +0,0 @@
-[Unit]
-Description=Socket proxy for uffd mail alias lookup
-PartOf=uffd-socketmap@%i.service
-
-[Socket]
-ListenStream=/run/socketmap-proxy/%I.sock
-SocketUser=postfix
-SocketGroup=postfix
-SocketMode=0640
-
-[Install]
-WantedBy=sockets.target
-- 
GitLab