{ config, lib, pkgs, ... }: let inherit (lib) mkOption types; cfg = config.services.pizauth; in { meta.maintainers = [ lib.maintainers.swarsel ]; options.services.pizauth = { enable = lib.mkEnableOption '' Pizauth, a commandline OAuth2 authentication daemon ''; package = lib.mkPackageOption pkgs "pizauth" { }; extraConfig = mkOption { type = types.nullOr types.str; default = null; description = "Additional global configuration. See pizauth.conf(5) for a available options."; }; accounts = mkOption { type = types.attrsOf ( types.submodule { options = { name = mkOption { type = types.str; readOnly = true; description = '' Unique identifier of the account. This is set to the attribute name of the account configuration. ''; }; authUri = mkOption { type = types.str; description = '' The OAuth2 server's authentication URI. ''; }; tokenUri = mkOption { type = types.str; description = '' The OAuth2 server's token URI. ''; }; clientId = mkOption { type = types.str; description = '' The OAuth2 client ID. ''; }; clientSecret = mkOption { type = types.nullOr types.str; default = null; description = '' The OAuth2 client secret. ''; }; scopes = mkOption { type = types.nullOr (types.listOf types.str); description = '' The scopes which the OAuth2 token will give access to. Optional. Note that Office365 requires the non-standard "offline_access" scope to be specified in order for pizauth to be able to operate successfully. ''; default = [ ]; example = [ "https://outlook.office365.com/IMAP.AccessAsUser.All" "https://outlook.office365.com/SMTP.Send" "offline_access" ]; }; loginHint = mkOption { type = types.nullOr types.str; default = null; description = '' An optional login hint for the account provider. ''; }; extraConfig = mkOption { type = types.nullOr types.str; default = null; description = '' Additional configuration that will be added to the account configuration. See pizauth.conf(5) for available options. ''; }; }; } ); default = { }; description = "Pizauth accounts that should be configured"; }; }; config = lib.mkIf cfg.enable { assertions = [ (lib.hm.assertions.assertPlatform "services.pizauth" pkgs lib.platforms.linux) ]; home.packages = [ cfg.package ]; xdg.configFile."pizauth.conf".source = let indent = " "; renderScopes = scopes: let quoted = map (s: "\"${s}\"") scopes; joined = lib.concatStringsSep ",\n${indent}${indent}" quoted; in "[\n${indent}${indent}${joined}\n${indent}]"; renderAccount = name: acc: '' account "${name}" { ${indent}auth_uri = "${acc.authUri}"; ${indent}token_uri = "${acc.tokenUri}"; ${indent}client_id = "${acc.clientId}"; '' + lib.optionalString (acc.clientSecret != "" && acc.clientSecret != null) '' ${indent}client_secret = "${acc.clientSecret}"; '' + lib.optionalString (acc.scopes != [ ] && acc.scopes != null) '' ${indent}scopes = ${renderScopes acc.scopes}; '' + lib.optionalString (acc.loginHint != "" && acc.loginHint != null) '' ${indent}login_hint = "${acc.loginHint}"; '' + lib.optionalString (acc.extraConfig != "" && acc.extraConfig != null) ( let indentedExtraConfig = lib.concatMapStringsSep "\n" ( line: if line == "" then "" else "${indent}${line}" ) (lib.splitString "\n" acc.extraConfig); in indentedExtraConfig ) + '' } ''; renderedAccounts = lib.concatStringsSep "\n" ( lib.mapAttrsToList (name: acc: renderAccount name acc) cfg.accounts ); in pkgs.writeTextFile { name = "pizauth.conf"; text = lib.optionalString (cfg.extraConfig != null && cfg.extraConfig != "") "${cfg.extraConfig}\n" + renderedAccounts; }; systemd.user.services.pizauth = { Unit = { Description = "Pizauth OAuth2 token manager"; After = [ "network.target" ]; X-Restart-Triggers = [ "${config.xdg.configFile."pizauth.conf".source}" ]; }; Service = { Type = "simple"; ExecStart = "${lib.getExe cfg.package} server -vvvv -d"; ExecReload = "${lib.getExe cfg.package} reload"; ExecStop = "${lib.getExe cfg.package} shutdown"; Restart = "on-failure"; LockPersonality = true; MemoryDenyWriteExecute = true; NoNewPrivileges = true; PrivateUsers = true; RestrictNamespaces = true; SystemCallArchitectures = "native"; SystemCallFilter = "@system-service"; }; Install = { WantedBy = [ "default.target" ]; }; }; }; }