#!/usr/bin/env python3 """Merge the auth-only patch into an existing, file-bind-mounted Element config.""" import argparse import copy import json from pathlib import Path def merge(current, patch): for key, value in patch.items(): if isinstance(value, dict): if not isinstance(current.get(key), dict): current[key] = {} merge(current[key], value) else: current[key] = value def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("config", type=Path) parser.add_argument("--write", action="store_true", help="write in place; otherwise print a preview") args = parser.parse_args() patch = json.loads(Path(__file__).with_name("auth-branding.patch.json").read_text()) # r+ intentionally retains the inode: replacing this file would leave an # existing Docker single-file bind mount serving the old config. with args.config.open("r+" if args.write else "r", encoding="utf-8") as config_file: current = json.load(config_file) if not isinstance(current, dict): raise ValueError("Element config must be a JSON object") original = copy.deepcopy(current) merge(current, patch) for key in ("setting_defaults", "default_theme", "default_server_config", "default_server_name"): assert current.get(key) == original.get(key), f"Auth patch must preserve {key}" output = json.dumps(current, indent=2, ensure_ascii=False) + "\n" if args.write: config_file.seek(0) config_file.write(output) config_file.truncate() else: print(output, end="") if __name__ == "__main__": main()