diff --git a/lib/types.nix b/lib/types.nix index 88fc90d0597..a334db5c724 100644 --- a/lib/types.nix +++ b/lib/types.nix @@ -256,6 +256,10 @@ rec { functor = (defaultFunctor name) // { wrapped = elemType; }; }; + nonEmptyListOf = elemType: + let list = addCheck (types.listOf elemType) (l: l != []); + in list // { description = "non-empty " + list.description; }; + attrsOf = elemType: mkOptionType rec { name = "attrsOf"; description = "attribute set of ${elemType.description}s"; diff --git a/nixos/modules/services/security/tor.nix b/nixos/modules/services/security/tor.nix index fa4aeb22ae9..fed91756e76 100644 --- a/nixos/modules/services/security/tor.nix +++ b/nixos/modules/services/security/tor.nix @@ -88,6 +88,9 @@ let ${flip concatMapStrings v.map (p: '' HiddenServicePort ${toString p.port} ${p.destination} '')} + ${optionalString (v.authorizeClient != null) '' + HiddenServiceAuthorizeClient ${v.authorizeClient.authType} ${concatStringsSep "," v.authorizeClient.clientNames} + ''} '')) + cfg.extraConfig; @@ -619,6 +622,33 @@ in })); }; + authorizeClient = mkOption { + default = null; + description = "If configured, the hidden service is accessible for authorized clients only."; + type = types.nullOr (types.submodule ({config, ...}: { + + options = { + + authType = mkOption { + type = types.enum [ "basic" "stealth" ]; + description = '' + Either "basic" for a general-purpose authorization protocol + or "stealth" for a less scalable protocol + that also hides service activity from unauthorized clients. + ''; + }; + + clientNames = mkOption { + type = types.nonEmptyListOf (types.strMatching "[A-Za-z0-9+-_]+"); + description = '' + Only clients that are listed here are authorized to access the hidden service. + Generated authorization data can be found in ${torDirectory}/onion/$name/hostname. + Clients need to put this authorization data in their configuration file using HidServAuth. + ''; + }; + }; + })); + }; }; config = {