about summary refs log tree commit diff
path: root/modules/services/soju/_soju-module.nix
blob: d14082ccfefd911675adcc852268139e1165fe6b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# Not an overlay, module replacement
{ config, lib, pkgs, ... }:

with lib;

let
  cfg = config.services.soju;
  stateDir = "/var/lib/soju";
  listenCfg = concatMapStringsSep "\n" (l: "listen ${l}") cfg.listen;
  tlsCfg = optionalString (cfg.tlsCertificate != null)
    "tls ${cfg.tlsCertificate} ${cfg.tlsCertificateKey}";
  logCfg = optionalString cfg.enableMessageLogging
    "log fs ${stateDir}/logs";

  configFile = pkgs.writeText "soju.conf" ''
    ${listenCfg}
    hostname ${cfg.hostName}
    ${tlsCfg}
    db sqlite3 ${stateDir}/soju.db
    ${logCfg}
    http-origin ${concatStringsSep " " cfg.httpOrigins}
    accept-proxy-ip ${concatStringsSep " " cfg.acceptProxyIP}

    ${cfg.extraConfig}
  '';
in
{
  ###### interface

  options.services.soju = {
    enable = mkEnableOption (lib.mdDoc "soju");

    listen = mkOption {
      type = types.listOf types.str;
      default = [ ":6697" ];
      description = lib.mdDoc ''
        Where soju should listen for incoming connections. See the
        `listen` directive in
        {manpage}`soju(1)`.
      '';
    };

    hostName = mkOption {
      type = types.str;
      default = config.networking.hostName;
      defaultText = literalExpression "config.networking.hostName";
      description = lib.mdDoc "Server hostname.";
    };

    tlsCertificate = mkOption {
      type = types.nullOr types.path;
      default = null;
      example = "/var/host.cert";
      description = lib.mdDoc "Path to server TLS certificate.";
    };

    tlsCertificateKey = mkOption {
      type = types.nullOr types.path;
      default = null;
      example = "/var/host.key";
      description = lib.mdDoc "Path to server TLS certificate key.";
    };

    enableMessageLogging = mkOption {
      type = types.bool;
      default = true;
      description = lib.mdDoc "Whether to enable message logging.";
    };

    httpOrigins = mkOption {
      type = types.listOf types.str;
      default = [ ];
      description = lib.mdDoc ''
        List of allowed HTTP origins for WebSocket listeners. The parameters are
        interpreted as shell patterns, see
        {manpage}`glob(7)`.
      '';
    };

    acceptProxyIP = mkOption {
      type = types.listOf types.str;
      default = [ ];
      description = lib.mdDoc ''
        Allow the specified IPs to act as a proxy. Proxys have the ability to
        overwrite the remote and local connection addresses (via the X-Forwarded-\*
        HTTP header fields). The special name "localhost" accepts the loopback
        addresses 127.0.0.0/8 and ::1/128. By default, all IPs are rejected.
      '';
    };

    extraConfig = mkOption {
      type = types.lines;
      default = "";
      description = lib.mdDoc "Lines added verbatim to the configuration file.";
    };

    extraGroups = mkOption {
      type = types.listOf types.str;
      default = [ ];
      description = lib.mdDoc "Extra groups for the dynamic user.";
    };
  };

  ###### implementation

  config = mkIf cfg.enable {
    assertions = [
      {
        assertion = (cfg.tlsCertificate != null) == (cfg.tlsCertificateKey != null);
        message = ''
          services.soju.tlsCertificate and services.soju.tlsCertificateKey
          must both be specified to enable TLS.
        '';
      }
    ];

    systemd.services.soju = {
      description = "soju IRC bouncer";
      wantedBy = [ "multi-user.target" ];
      after = [ "network-online.target" ];
      serviceConfig = {
        DynamicUser = true;
        SupplementaryGroups = cfg.extraGroups;
        Restart = "always";
        ExecStart = "${pkgs.soju}/bin/soju -config ${configFile}";
        StateDirectory = "soju";
      };
    };
  };

  meta.maintainers = with maintainers; [ malvo ];
}