about summary refs log tree commit diff
path: root/nixos/modules/services/networking/soju.nix
blob: 810957be65f5763159ab53a298477b2429963393 (plain) (blame)
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
133
134
135
136
137
138
139
140
141
142
143
144
145
{ config, lib, pkgs, ... }:

with lib;

let
  cfg = config.services.soju;
  stateDir = "/var/lib/soju";
  runtimeDir = "/run/soju";
  listen = cfg.listen
    ++ optional cfg.adminSocket.enable "unix+admin://${runtimeDir}/admin";
  listenCfg = concatMapStringsSep "\n" (l: "listen ${l}") 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}
  '';

  sojuctl = pkgs.writeShellScriptBin "sojuctl" ''
    exec ${cfg.package}/bin/sojuctl --config ${configFile} "$@"
  '';
in
{
  ###### interface

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

    package = mkPackageOption pkgs "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.";
    };

    adminSocket.enable = mkOption {
      type = types.bool;
      default = true;
      description = lib.mdDoc ''
        Listen for admin connections from sojuctl at /run/soju/admin.
      '';
    };

    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.";
    };
  };

  ###### 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.
        '';
      }
    ];

    environment.systemPackages = [ sojuctl ];

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

  meta.maintainers = with maintainers; [ malte-v ];
}