{ config, lib, ... }: let inherit (lib.modules) mkIf mkMerge mkOptionDefault mkDefault; inherit (lib.options) mkOption mkEnableOption; inherit (lib.lists) any; inherit (config) networking; cfg = config.services.postgresql; ensureUserModule = { config, ... }: { options = with lib.types; { authentication = { enable = mkEnableOption "TCP connections" // { default = config.authentication.hosts != [ ]; }; hosts = mkOption { type = listOf str; default = [ ]; }; method = mkOption { type = str; default = "md5"; }; database = mkOption { type = str; }; tailscale = { allow = mkEnableOption "tailscale TCP connections"; }; local = { allow = mkEnableOption "local TCP connections"; }; authentication = mkOption { type = lines; default = ""; }; }; }; config = { authentication = { hosts = let inherit (networking.access) cidrForNetwork; in mkMerge [ (mkIf config.authentication.tailscale.allow cidrForNetwork.tail.all) (mkIf config.authentication.local.allow (cidrForNetwork.loopback.all ++ cidrForNetwork.local.all)) ]; authentication = mkMerge (map (host: '' host ${config.authentication.database} ${config.name} ${host} ${config.authentication.method} '') config.authentication.hosts); }; authentication.database = mkIf (config.ensureDBOwnership) ( mkOptionDefault config.name ); }; }; in { options.services.postgresql = with lib.types; { ensureUsers = mkOption { type = listOf (submodule ensureUserModule); }; }; config.services.postgresql = { enableTCPIP = mkIf (any (user: user.authentication.enable) cfg.ensureUsers) ( mkDefault true ); authentication = mkMerge (map (user: mkIf user.authentication.enable user.authentication.authentication ) cfg.ensureUsers); }; }