summary refs log tree commit diff
path: root/nixos/modules/services/mail/postsrsd.nix
blob: 2ebc675ab10af4e8ffaad75d8cc73f5fa94d1b59 (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
{ config, lib, pkgs, ... }:

with lib;

let

  cfg = config.services.postsrsd;

in {

  ###### interface

  options = {

    services.postsrsd = {

      enable = mkOption {
        type = types.bool;
        default = false;
        description = "Whether to enable the postsrsd SRS server for Postfix.";
      };

      secretsFile = mkOption {
        type = types.path;
        default = "/var/lib/postsrsd/postsrsd.secret";
        description = "Secret keys used for signing and verification";
      };

      domain = mkOption {
        type = types.str;
        description = "Domain name for rewrite";
      };

      separator = mkOption {
        type = types.enum ["-" "=" "+"];
        default = "=";
        description = "First separator character in generated addresses";
      };

      # bindAddress = mkOption { # uncomment once 1.5 is released
      #   type = types.str;
      #   default = "127.0.0.1";
      #   description = "Socket listen address";
      # };

      forwardPort = mkOption {
        type = types.int;
        default = 10001;
        description = "Port for the forward SRS lookup";
      };

      reversePort = mkOption {
        type = types.int;
        default = 10002;
        description = "Port for the reverse SRS lookup";
      };

      timeout = mkOption {
        type = types.int;
        default = 1800;
        description = "Timeout for idle client connections in seconds";
      };

      excludeDomains = mkOption {
        type = types.listOf types.str;
        default = [];
        description = "Origin domains to exclude from rewriting in addition to primary domain";
      };

      user = mkOption {
        type = types.str;
        default = "postsrsd";
        description = "User for the daemon";
      };

      group = mkOption {
        type = types.str;
        default = "postsrsd";
        description = "Group for the daemon";
      };

    };

  };


  ###### implementation

  config = mkIf cfg.enable {

    services.postsrsd.domain = mkDefault config.networking.hostName;

    users.users = optionalAttrs (cfg.user == "postsrsd") {
      postsrsd = {
        group = cfg.group;
        uid = config.ids.uids.postsrsd;
      };
    };

    users.groups = optionalAttrs (cfg.group == "postsrsd") {
      postsrsd.gid = config.ids.gids.postsrsd;
    };

    systemd.services.postsrsd = {
      description = "PostSRSd SRS rewriting server";
      after = [ "network.target" ];
      before = [ "postfix.service" ];
      wantedBy = [ "multi-user.target" ];

      path = [ pkgs.coreutils ];

      serviceConfig = {
        ExecStart = ''${pkgs.postsrsd}/sbin/postsrsd "-s${cfg.secretsFile}" "-d${cfg.domain}" -a${cfg.separator} -f${toString cfg.forwardPort} -r${toString cfg.reversePort} -t${toString cfg.timeout} "-X${concatStringsSep "," cfg.excludeDomains}"'';
        User = cfg.user;
        Group = cfg.group;
        PermissionsStartOnly = true;
      };

      preStart = ''
        if [ ! -e "${cfg.secretsFile}" ]; then
          echo "WARNING: secrets file not found, autogenerating!"
          DIR="$(dirname "${cfg.secretsFile}")"
          if [ ! -d "$DIR" ]; then
            mkdir -p -m750 "$DIR"
            chown "${cfg.user}:${cfg.group}" "$DIR"
          fi
          dd if=/dev/random bs=18 count=1 | base64 > "${cfg.secretsFile}"
          chmod 600 "${cfg.secretsFile}"
        fi
        chown "${cfg.user}:${cfg.group}" "${cfg.secretsFile}"
      '';
    };

  };
}