1{
2 config,
3 lib,
4 pkgs,
5 ...
6}:
7
8let
9 cfg = config.services.wastebin;
10 inherit (lib)
11 mkEnableOption
12 mkPackageOption
13 mkIf
14 mkOption
15 types
16 mapAttrs
17 isBool
18 getExe
19 boolToString
20 optionalAttrs
21 ;
22in
23{
24
25 options.services.wastebin = {
26
27 enable = mkEnableOption "Wastebin, a pastebin service";
28
29 package = mkPackageOption pkgs "wastebin" { };
30
31 stateDir = mkOption {
32 type = types.path;
33 default = "/var/lib/wastebin";
34 description = "State directory of the daemon.";
35 };
36
37 secretFile = mkOption {
38 type = types.nullOr types.path;
39 default = null;
40 example = "/run/secrets/wastebin.env";
41 description = ''
42 Path to file containing sensitive environment variables.
43 Some variables that can be considered secrets are:
44
45 - WASTEBIN_PASSWORD_SALT:
46 salt used to hash user passwords used for encrypting pastes.
47
48 - WASTEBIN_SIGNING_KEY:
49 sets the key to sign cookies. If not set, a random key will be
50 generated which means cookies will become invalid after restarts and
51 paste creators will not be able to delete their pastes anymore.
52 '';
53 };
54
55 settings = mkOption {
56
57 description = ''
58 Additional configuration for wastebin, see
59 <https://github.com/matze/wastebin#usage> for supported values.
60 For secrets use secretFile option instead.
61 '';
62
63 type = types.submodule {
64
65 freeformType =
66 with types;
67 attrsOf (oneOf [
68 bool
69 int
70 str
71 ]);
72
73 options = {
74
75 WASTEBIN_ADDRESS_PORT = mkOption {
76 type = types.str;
77 default = "0.0.0.0:8088";
78 description = "Address and port to bind to";
79 };
80
81 WASTEBIN_BASE_URL = mkOption {
82 default = "http://localhost";
83 example = "https://myhost.tld";
84 type = types.str;
85 description = ''
86 Base URL for the QR code display. If not set, the user agent's Host
87 header field is used as an approximation.
88 '';
89 };
90
91 WASTEBIN_CACHE_SIZE = mkOption {
92 default = 128;
93 type = types.int;
94 description = "Number of rendered syntax highlight items to cache. Can be disabled by setting to 0.";
95 };
96
97 WASTEBIN_DATABASE_PATH = mkOption {
98 default = "/var/lib/wastebin/sqlite3.db"; # TODO make this default to stateDir/sqlite3.db
99 type = types.str;
100 description = "Path to the sqlite3 database file. If not set, an in-memory database is used.";
101 };
102
103 WASTEBIN_HTTP_TIMEOUT = mkOption {
104 default = 5;
105 type = types.int;
106 description = "Maximum number of seconds a request can be processed until wastebin responds with 408";
107 };
108
109 WASTEBIN_MAX_BODY_SIZE = mkOption {
110 default = 1024;
111 type = types.int;
112 description = "Number of bytes to accept for POST requests";
113 };
114
115 WASTEBIN_TITLE = mkOption {
116 default = "wastebin";
117 type = types.str;
118 description = "Overrides the HTML page title";
119 };
120
121 RUST_LOG = mkOption {
122 default = "info";
123 type = types.str;
124 description = ''
125 Influences logging. Besides the typical trace, debug, info etc.
126 keys, you can also set the tower_http key to some log level to get
127 additional information request and response logs.
128 '';
129 };
130 };
131 };
132
133 default = { };
134
135 example = {
136 WASTEBIN_TITLE = "My awesome pastebin";
137 };
138 };
139 };
140
141 config = mkIf cfg.enable {
142 systemd.services.wastebin = {
143 after = [ "network.target" ];
144 wantedBy = [ "multi-user.target" ];
145 environment = mapAttrs (_: v: if isBool v then boolToString v else toString v) cfg.settings;
146 serviceConfig =
147 {
148 DevicePolicy = "closed";
149 DynamicUser = true;
150 ExecStart = "${getExe cfg.package}";
151 LockPersonality = true;
152 MemoryDenyWriteExecute = true;
153 PrivateDevices = true;
154 PrivateUsers = true;
155 ProtectClock = true;
156 ProtectControlGroups = true;
157 ProtectHostname = true;
158 ProtectKernelLogs = true;
159 ProtectKernelModules = true;
160 ProtectKernelTunables = true;
161 ProtectProc = "invisible";
162 RestrictAddressFamilies = [
163 "AF_INET"
164 "AF_INET6"
165 ];
166 RestrictNamespaces = true;
167 RestrictRealtime = true;
168 SystemCallArchitectures = [ "native" ];
169 SystemCallFilter = [ "@system-service" ];
170 StateDirectory = baseNameOf cfg.stateDir;
171 ReadWritePaths = cfg.stateDir;
172 }
173 // optionalAttrs (cfg.secretFile != null) {
174 EnvironmentFile = cfg.secretFile;
175 };
176 };
177 };
178
179 meta.maintainers = with lib.maintainers; [ pinpox ];
180}