<commit_before>{ config, lib, pkgs, ... }:

with lib;

let

  cfg = config.services.stunnel;
  yesNo = val: if val then "yes" else "no";

  verifyChainPathAssert = n: c: {
    assertion = c.verifyHostname == null || (c.verifyChain || c.verifyPeer);
    message =  "stunnel: \"${n}\" client configuration - hostname verification " +
      "is not possible without either verifyChain or verifyPeer enabled";
  };

  serverConfig = {
    options = {
      accept = mkOption {
        type = types.int;
        description = "On which port stunnel should listen for incoming TLS connections.";
      };

      connect = mkOption {
        type = types.int;
        description = "To which port the decrypted connection should be forwarded.";
      };

      cert = mkOption {
        type = types.path;
        description = "File containing both the private and public keys.";
      };
    };
  };

  clientConfig = {
    options = {
      accept = mkOption {
        type = types.str;
        description = "IP:Port on which connections should be accepted.";
      };

      connect = mkOption {
        type = types.str;
        description = "IP:Port destination to connect to.";
      };

      verifyChain = mkOption {
        type = types.bool;
        default = true;
        description = "Check if the provided certificate has a valid certificate chain (against CAPath).";
      };

      verifyPeer = mkOption {
        type = types.bool;
        default = false;
        description = "Check if the provided certificate is contained in CAPath.";
      };

      CAPath = mkOption {
        type = types.nullOr types.path;
        default = null;
        description = "Path to a directory containing certificates to validate against.";
      };

      CAFile = mkOption {
        type = types.nullOr types.path;
        default = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
        description = "Path to a file containing certificates to validate against.";
      };

      verifyHostname = mkOption {
        type = with types; nullOr str;
        default = null;
        description = "If set, stunnel checks if the provided certificate is valid for the given hostname.";
      };
    };
  };


in

{

  ###### interface

  options = {

    services.stunnel = {

      enable = mkOption {
        type = types.bool;
        default = false;
        description = "Whether to enable the stunnel TLS tunneling service.";
      };

      user = mkOption {
        type = with types; nullOr str;
        default = "nobody";
        description = "The user under which stunnel runs.";
      };

      group = mkOption {
        type = with types; nullOr str;
        default = "nogroup";
        description = "The group under which stunnel runs.";
      };

      logLevel = mkOption {
        type = types.enum [ "emerg" "alert" "crit" "err" "warning" "notice" "info" "debug" ];
        default = "info";
        description = "Verbosity of stunnel output.";
      };

      fipsMode = mkOption {
        type = types.bool;
        default = false;
        description = "Enable FIPS 140-2 mode required for compliance.";
      };

      enableInsecureSSLv3 = mkOption {
        type = types.bool;
        default = false;
        description = "Enable support for the insecure SSLv3 protocol.";
      };


      servers = mkOption {
        description = "Define the server configuations.";
        type = with types; attrsOf (submodule serverConfig);
        example = {
          fancyWebserver = {
            enable = true;
            accept = 443;
            connect = 8080;
            cert = "/path/to/pem/file";
          };
        };
        default = { };
      };

      clients = mkOption {
        description = "Define the client configurations.";
        type = with types; attrsOf (submodule clientConfig);<commit_msg>stunnel service: fix servers example<commit_after>{ config, lib, pkgs, ... }:

with lib;

let

  cfg = config.services.stunnel;
  yesNo = val: if val then "yes" else "no";

  verifyChainPathAssert = n: c: {
    assertion = c.verifyHostname == null || (c.verifyChain || c.verifyPeer);
    message =  "stunnel: \"${n}\" client configuration - hostname verification " +
      "is not possible without either verifyChain or verifyPeer enabled";
  };

  serverConfig = {
    options = {
      accept = mkOption {
        type = types.int;
        description = "On which port stunnel should listen for incoming TLS connections.";
      };

      connect = mkOption {
        type = types.int;
        description = "To which port the decrypted connection should be forwarded.";
      };

      cert = mkOption {
        type = types.path;
        description = "File containing both the private and public keys.";
      };
    };
  };

  clientConfig = {
    options = {
      accept = mkOption {
        type = types.str;
        description = "IP:Port on which connections should be accepted.";
      };

      connect = mkOption {
        type = types.str;
        description = "IP:Port destination to connect to.";
      };

      verifyChain = mkOption {
        type = types.bool;
        default = true;
        description = "Check if the provided certificate has a valid certificate chain (against CAPath).";
      };

      verifyPeer = mkOption {
        type = types.bool;
        default = false;
        description = "Check if the provided certificate is contained in CAPath.";
      };

      CAPath = mkOption {
        type = types.nullOr types.path;
        default = null;
        description = "Path to a directory containing certificates to validate against.";
      };

      CAFile = mkOption {
        type = types.nullOr types.path;
        default = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
        description = "Path to a file containing certificates to validate against.";
      };

      verifyHostname = mkOption {
        type = with types; nullOr str;
        default = null;
        description = "If set, stunnel checks if the provided certificate is valid for the given hostname.";
      };
    };
  };


in

{

  ###### interface

  options = {

    services.stunnel = {

      enable = mkOption {
        type = types.bool;
        default = false;
        description = "Whether to enable the stunnel TLS tunneling service.";
      };

      user = mkOption {
        type = with types; nullOr str;
        default = "nobody";
        description = "The user under which stunnel runs.";
      };

      group = mkOption {
        type = with types; nullOr str;
        default = "nogroup";
        description = "The group under which stunnel runs.";
      };

      logLevel = mkOption {
        type = types.enum [ "emerg" "alert" "crit" "err" "warning" "notice" "info" "debug" ];
        default = "info";
        description = "Verbosity of stunnel output.";
      };

      fipsMode = mkOption {
        type = types.bool;
        default = false;
        description = "Enable FIPS 140-2 mode required for compliance.";
      };

      enableInsecureSSLv3 = mkOption {
        type = types.bool;
        default = false;
        description = "Enable support for the insecure SSLv3 protocol.";
      };


      servers = mkOption {
        description = "Define the server configuations.";
        type = with types; attrsOf (submodule serverConfig);
        example = {
          fancyWebserver = {
            accept = 443;
            connect = 8080;
            cert = "/path/to/pem/file";
          };
        };
        default = { };
      };

      clients = mkOption {
        description = "Define the client configurations.";
        type = with types; attrsOf (submodule clientConfig);
{'fraction_non_alphanumeric': 0.1030941237649506, 'fraction_numerical': 0.0033801352054082163, 'mean_word_length': 1.9634052388289676, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5098677', 'n_tokens_mistral': 2095, 'n_tokens_neox': 2006, 'n_words': 675}