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;