From 4bd28552bc9d4354f7ba8ebb50ae23cd392347f9 Mon Sep 17 00:00:00 2001 From: Love Billenius Date: Tue, 14 Apr 2026 17:53:35 +0200 Subject: [PATCH] small fixes --- .../mail-server/mobileconfig-generator.py | 41 +++++++++--------- modules/nixos/mail-server/mobileconfig.nix | 42 ++++++++++--------- 2 files changed, 45 insertions(+), 38 deletions(-) diff --git a/modules/nixos/mail-server/mobileconfig-generator.py b/modules/nixos/mail-server/mobileconfig-generator.py index 0bbcd46..7247c9b 100644 --- a/modules/nixos/mail-server/mobileconfig-generator.py +++ b/modules/nixos/mail-server/mobileconfig-generator.py @@ -1,15 +1,4 @@ #!/usr/bin/env python3 -"""Apple mobileconfig profile generator HTTP server. - -Example: - ./mobileconfig-generator.py \\ - --domain billenius.com \\ - --mail-host mail.billenius.com \\ - --radicale-host cal.billenius.com \\ - --account love:love@billenius.com:love_billenius.com \\ - --port 8426 -""" - import argparse import hashlib import re @@ -98,7 +87,9 @@ def resolve_account(params): def deterministic_uuid(seed): digest = hashlib.sha256(seed.encode("utf-8")).hexdigest() - return f"{digest[:8]}-{digest[8:12]}-{digest[12:16]}-{digest[16:20]}-{digest[20:32]}" + return ( + f"{digest[:8]}-{digest[8:12]}-{digest[12:16]}-{digest[16:20]}-{digest[20:32]}" + ) def mobileconfig_payload(email, full_name): @@ -219,7 +210,7 @@ def mobileconfig_payload(email, full_name): PayloadDescription Configures mail, calendar, and contacts for {values["email"]}. PayloadDisplayName - {values["domain"]} Mail + {values["email"]} PayloadIdentifier com.billenius.mobileconfig.{values["identifier"]} PayloadOrganization @@ -388,7 +379,10 @@ class Handler(BaseHTTPRequestHandler): payload = mobileconfig_payload(account["email"], full_name).encode("utf-8") self.send_response(200) self.send_header("Content-Type", "application/x-apple-aspen-config") - self.send_header("Content-Disposition", f'attachment; filename="{filename_base}.mobileconfig"') + self.send_header( + "Content-Disposition", + f'attachment; filename="{filename_base}.mobileconfig"', + ) self.send_header("Content-Length", str(len(payload))) self.end_headers() self.wfile.write(payload) @@ -409,7 +403,10 @@ class Handler(BaseHTTPRequestHandler): if parsed.path in ("/mobileconfig/", "/mobileconfig/index.html"): account = resolve_account(params) if account is None: - has_query = any(first(params.get(key)) for key in ("username", "user", "emailaddress")) + has_query = any( + first(params.get(key)) + for key in ("username", "user", "emailaddress") + ) if has_query: self.send_text("Unknown account", status=404) else: @@ -432,8 +429,10 @@ class Handler(BaseHTTPRequestHandler): self.send_profile(account, full_name, "billenius") return - if parsed.path.startswith("/mobileconfig/") and parsed.path.endswith(".mobileconfig"): - basename = parsed.path[len("/mobileconfig/"):-len(".mobileconfig")] + if parsed.path.startswith("/mobileconfig/") and parsed.path.endswith( + ".mobileconfig" + ): + basename = parsed.path[len("/mobileconfig/") : -len(".mobileconfig")] account = ACCOUNT_BY_PATH.get(basename) if account is None: self.send_text("Unknown account", status=404) @@ -455,7 +454,11 @@ if __name__ == "__main__": parser.add_argument("--radicale-host", required=True) parser.add_argument("--default-username", default=None) parser.add_argument("--port", type=int, default=8426) - parser.add_argument("--account", type=parse_account, action="append", - help="username:email:legacyPath (repeatable)") + parser.add_argument( + "--account", + type=parse_account, + action="append", + help="username:email:legacyPath (repeatable)", + ) init(parser.parse_args()) ThreadingHTTPServer(("127.0.0.1", PORT), Handler).serve_forever() diff --git a/modules/nixos/mail-server/mobileconfig.nix b/modules/nixos/mail-server/mobileconfig.nix index a4ffd58..5a1c756 100644 --- a/modules/nixos/mail-server/mobileconfig.nix +++ b/modules/nixos/mail-server/mobileconfig.nix @@ -17,22 +17,21 @@ lib.mkIf hasMailDiscoveryConfig ( safeLegacyPath = email: builtins.replaceStrings [ "@" "+" ] [ "_" "-" ] email; - accountEntries = - lib.filter (entry: entry.domain == domain) ( - lib.mapAttrsToList ( - email: _: - let - parts = lib.splitString "@" email; - username = builtins.head parts; - domainPart = lib.last parts; - in - { - inherit email username; - domain = domainPart; - legacyPath = safeLegacyPath email; - } - ) cfg.loginAccounts - ); + accountEntries = lib.filter (entry: entry.domain == domain) ( + lib.mapAttrsToList ( + email: _: + let + parts = lib.splitString "@" email; + username = builtins.head parts; + domainPart = lib.last parts; + in + { + inherit email username; + domain = domainPart; + legacyPath = safeLegacyPath email; + } + ) cfg.loginAccounts + ); usernames = map (entry: entry.username) accountEntries; defaultUsername = @@ -40,8 +39,8 @@ lib.mkIf hasMailDiscoveryConfig ( generatorScript = ./mobileconfig-generator.py; - accountArgs = lib.concatMapStrings (entry: - " --account ${entry.username}:${entry.email}:${entry.legacyPath}" + accountArgs = lib.concatMapStrings ( + entry: " --account ${entry.username}:${entry.email}:${entry.legacyPath}" ) accountEntries; defaultUsernameArg = @@ -61,7 +60,12 @@ lib.mkIf hasMailDiscoveryConfig ( wantedBy = [ "multi-user.target" ]; serviceConfig = { DynamicUser = true; - ExecStart = "${pkgs.python3}/bin/python3 ${generatorScript} --domain ${domain} --mail-host ${cfg.fqdn} --radicale-host ${radicaleHost} --port ${toString mobileconfigPort}${defaultUsernameArg}${accountArgs}"; + ExecStart = "${pkgs.python3}/bin/python3 \ + ${generatorScript} \ + --domain ${domain} \ + --mail-host ${cfg.fqdn} \ + --radicale-host ${radicaleHost} \ + --port ${toString mobileconfigPort}${defaultUsernameArg}${accountArgs}"; NoNewPrivileges = true; PrivateTmp = true; ProtectHome = true;