diff options
author | Ismaël Bouya <ismael.bouya@normalesup.org> | 2019-03-06 16:43:44 +0100 |
---|---|---|
committer | Ismaël Bouya <ismael.bouya@normalesup.org> | 2019-03-06 16:43:44 +0100 |
commit | 99b0b74ac87c77b5f39e21c65141d8fcc6753ca2 (patch) | |
tree | 476753a86702e468c8dc4f6dca677618ec07518d /nixops/modules/task/default.nix | |
parent | 55fd3780b5c40664233cd3f9b8cf280bd530fdd1 (diff) | |
download | Nix-99b0b74ac87c77b5f39e21c65141d8fcc6753ca2.tar.gz Nix-99b0b74ac87c77b5f39e21c65141d8fcc6753ca2.tar.zst Nix-99b0b74ac87c77b5f39e21c65141d8fcc6753ca2.zip |
Add taskwarrior-web
Fixes https://git.immae.eu/mantisbt/view.php?id=67
Diffstat (limited to 'nixops/modules/task/default.nix')
-rw-r--r-- | nixops/modules/task/default.nix | 224 |
1 files changed, 181 insertions, 43 deletions
diff --git a/nixops/modules/task/default.nix b/nixops/modules/task/default.nix index 3dc3299..2fd61aa 100644 --- a/nixops/modules/task/default.nix +++ b/nixops/modules/task/default.nix | |||
@@ -6,6 +6,81 @@ let | |||
6 | user = config.services.taskserver.user; | 6 | user = config.services.taskserver.user; |
7 | env = myconfig.env.tools.task; | 7 | env = myconfig.env.tools.task; |
8 | group = config.services.taskserver.group; | 8 | group = config.services.taskserver.group; |
9 | taskserver-user-certs = pkgs.runCommand "taskserver-user-certs" {} '' | ||
10 | mkdir -p $out/bin | ||
11 | cat > $out/bin/taskserver-user-certs <<"EOF" | ||
12 | #!/usr/bin/env bash | ||
13 | |||
14 | user=$1 | ||
15 | |||
16 | silent_certtool() { | ||
17 | if ! output="$("${pkgs.gnutls.bin}/bin/certtool" "$@" 2>&1)"; then | ||
18 | echo "GNUTLS certtool invocation failed with output:" >&2 | ||
19 | echo "$output" >&2 | ||
20 | fi | ||
21 | } | ||
22 | |||
23 | silent_certtool -p \ | ||
24 | --bits 4096 \ | ||
25 | --outfile "${vardir}/userkeys/$user.key.pem" | ||
26 | ${pkgs.gnused}/bin/sed -i -n -e '/^-----BEGIN RSA PRIVATE KEY-----$/,$p' "${vardir}/userkeys/$user.key.pem" | ||
27 | |||
28 | silent_certtool -c \ | ||
29 | --template "${pkgs.writeText "taskserver-ca.template" '' | ||
30 | tls_www_client | ||
31 | encryption_key | ||
32 | signing_key | ||
33 | expiration_days = 3650 | ||
34 | ''}" \ | ||
35 | --load-ca-certificate "${vardir}/keys/ca.cert" \ | ||
36 | --load-ca-privkey "${vardir}/keys/ca.key" \ | ||
37 | --load-privkey "${vardir}/userkeys/$user.key.pem" \ | ||
38 | --outfile "${vardir}/userkeys/$user.cert.pem" | ||
39 | EOF | ||
40 | chmod a+x $out/bin/taskserver-user-certs | ||
41 | patchShebangs $out/bin/taskserver-user-certs | ||
42 | ''; | ||
43 | taskwarrior-web = pkgs.callPackage ./taskwarrior-web.nix { | ||
44 | inherit (mylibs) fetchedGithub; | ||
45 | inherit env; | ||
46 | }; | ||
47 | taskwebPages = let | ||
48 | uidPages = lib.attrsets.zipAttrs ( | ||
49 | lib.lists.flatten | ||
50 | (lib.attrsets.mapAttrsToList (k: c: map (v: { "${v}" = k; }) c.uid) env.taskwarrior-web) | ||
51 | ); | ||
52 | pages = lib.attrsets.mapAttrs (uid: items: | ||
53 | if lib.lists.length items == 1 then | ||
54 | '' | ||
55 | <html> | ||
56 | <head> | ||
57 | <meta http-equiv="refresh" content="0; url=/taskweb/${lib.lists.head items}/" /> | ||
58 | </head> | ||
59 | <body></body> | ||
60 | </html> | ||
61 | '' | ||
62 | else | ||
63 | '' | ||
64 | <html> | ||
65 | <head> | ||
66 | <title>To-do list disponibles</title> | ||
67 | <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | ||
68 | <meta name="viewport" content="width=device-width, initial-scale=1" /> | ||
69 | </head> | ||
70 | <body> | ||
71 | <ul> | ||
72 | ${builtins.concatStringsSep "\n" (map (item: "<li><a href='/taskweb/${item}'>${item}</a></li>") items)} | ||
73 | </ul> | ||
74 | </body> | ||
75 | </html> | ||
76 | '' | ||
77 | ) uidPages; | ||
78 | in | ||
79 | pkgs.runCommand "taskwerver-pages" {} '' | ||
80 | mkdir -p $out/ | ||
81 | ${builtins.concatStringsSep "\n" (lib.attrsets.mapAttrsToList (k: v: "cp ${pkgs.writeText k v} $out/${k}.html") pages)} | ||
82 | echo "Please login" > $out/index.html | ||
83 | ''; | ||
9 | in { | 84 | in { |
10 | options.services.myTasks = { | 85 | options.services.myTasks = { |
11 | enable = lib.mkEnableOption "my tasks service"; | 86 | enable = lib.mkEnableOption "my tasks service"; |
@@ -13,7 +88,7 @@ in { | |||
13 | 88 | ||
14 | config = lib.mkIf cfg.enable { | 89 | config = lib.mkIf cfg.enable { |
15 | security.acme.certs."eldiron".extraDomains.${fqdn} = null; | 90 | security.acme.certs."eldiron".extraDomains.${fqdn} = null; |
16 | services.myWebsites.tools.modules = [ "proxy_fcgi" ]; | 91 | services.myWebsites.tools.modules = [ "proxy_fcgi" "sed" ]; |
17 | services.myWebsites.tools.vhostConfs.task = { | 92 | services.myWebsites.tools.vhostConfs.task = { |
18 | certName = "eldiron"; | 93 | certName = "eldiron"; |
19 | hosts = [ "task.immae.eu" ]; | 94 | hosts = [ "task.immae.eu" ]; |
@@ -34,7 +109,48 @@ in { | |||
34 | SetEnv TASKD_LDAP_BASE "${env.ldap.base}" | 109 | SetEnv TASKD_LDAP_BASE "${env.ldap.base}" |
35 | SetEnv TASKD_LDAP_FILTER "${env.ldap.search}" | 110 | SetEnv TASKD_LDAP_FILTER "${env.ldap.search}" |
36 | </Directory> | 111 | </Directory> |
37 | '' ]; | 112 | '' |
113 | '' | ||
114 | <Macro Taskwarrior %{folderName}> | ||
115 | ProxyPass "unix://${taskwarrior-web.socketsDir}/%{folderName}.sock|http://localhost-%{folderName}/" | ||
116 | ProxyPassReverse "unix://${taskwarrior-web.socketsDir}/%{folderName}.sock|http://localhost-%{folderName}/" | ||
117 | ProxyPassReverse http://${fqdn}/ | ||
118 | |||
119 | SetOutputFilter Sed | ||
120 | OutputSed "s|/ajax|/taskweb/%{folderName}/ajax|g" | ||
121 | OutputSed "s|\([^x]\)/tasks|\1/taskweb/%{folderName}/tasks|g" | ||
122 | OutputSed "s|\([^x]\)/projects|\1/taskweb/%{folderName}/projects|g" | ||
123 | OutputSed "s|http://${fqdn}/|/taskweb/%{folderName}/|g" | ||
124 | OutputSed "s|/img/relax.jpg|/taskweb/%{folderName}/img/relax.jpg|g" | ||
125 | </Macro> | ||
126 | '' | ||
127 | '' | ||
128 | Alias /taskweb ${taskwebPages} | ||
129 | <Directory "${taskwebPages}"> | ||
130 | DirectoryIndex index.html | ||
131 | Require all granted | ||
132 | </Directory> | ||
133 | |||
134 | RewriteEngine on | ||
135 | RewriteRule ^/taskweb$ /taskweb/ [R=301,L] | ||
136 | RedirectMatch permanent ^/taskweb/([^/]+)$ /taskweb/$1/ | ||
137 | |||
138 | RewriteCond %{LA-U:REMOTE_USER} !="" | ||
139 | RewriteCond ${taskwebPages}/%{LA-U:REMOTE_USER}.html -f | ||
140 | RewriteRule ^/taskweb/?$ ${taskwebPages}/%{LA-U:REMOTE_USER}.html [L] | ||
141 | |||
142 | <Location /taskweb/> | ||
143 | Use LDAPConnect | ||
144 | Require ldap-group cn=users,cn=taskwarrior,ou=services,dc=immae,dc=eu | ||
145 | </Location> | ||
146 | '' | ||
147 | ] ++ (lib.attrsets.mapAttrsToList (k: v: '' | ||
148 | <Location /taskweb/${k}/> | ||
149 | ${builtins.concatStringsSep "\n" (map (uid: "Require ldap-attribute uid=${uid}") v.uid)} | ||
150 | |||
151 | Use Taskwarrior ${k} | ||
152 | </Location> | ||
153 | '') env.taskwarrior-web); | ||
38 | }; | 154 | }; |
39 | services.myPhpfpm.poolConfigs = { | 155 | services.myPhpfpm.poolConfigs = { |
40 | tasks = '' | 156 | tasks = '' |
@@ -69,47 +185,7 @@ in { | |||
69 | ''; | 185 | ''; |
70 | }; | 186 | }; |
71 | 187 | ||
72 | users.users.${user}.packages = [ | 188 | users.users.${user}.packages = [ taskserver-user-certs ]; |
73 | (pkgs.runCommand "taskserver-user-certs" {} '' | ||
74 | mkdir -p $out/bin | ||
75 | cat > $out/bin/taskserver-user-certs <<"EOF" | ||
76 | #!/usr/bin/env bash | ||
77 | |||
78 | user=$1 | ||
79 | |||
80 | silent_certtool() { | ||
81 | if ! output="$("${pkgs.gnutls.bin}/bin/certtool" "$@" 2>&1)"; then | ||
82 | echo "GNUTLS certtool invocation failed with output:" >&2 | ||
83 | echo "$output" >&2 | ||
84 | fi | ||
85 | } | ||
86 | |||
87 | silent_certtool -p \ | ||
88 | --bits 4096 \ | ||
89 | --outfile "${vardir}/userkeys/$user.key.pem" | ||
90 | ${pkgs.gnused}/bin/sed -i -n -e '/^-----BEGIN RSA PRIVATE KEY-----$/,$p' "${vardir}/userkeys/$user.key.pem" | ||
91 | |||
92 | silent_certtool -c \ | ||
93 | --template "${pkgs.writeText "taskserver-ca.template" '' | ||
94 | tls_www_client | ||
95 | encryption_key | ||
96 | signing_key | ||
97 | expiration_days = 3650 | ||
98 | ''}" \ | ||
99 | --load-ca-certificate "${vardir}/keys/ca.cert" \ | ||
100 | --load-ca-privkey "${vardir}/keys/ca.key" \ | ||
101 | --load-privkey "${vardir}/userkeys/$user.key.pem" \ | ||
102 | --outfile "${vardir}/userkeys/$user.cert.pem" | ||
103 | EOF | ||
104 | chmod a+x $out/bin/taskserver-user-certs | ||
105 | patchShebangs $out/bin/taskserver-user-certs | ||
106 | '') | ||
107 | ]; | ||
108 | |||
109 | systemd.services.taskserver-ca.postStart = '' | ||
110 | chown :${group} "${vardir}/keys/ca.key" | ||
111 | chmod g+r "${vardir}/keys/ca.key" | ||
112 | ''; | ||
113 | 189 | ||
114 | system.activationScripts.taskserver = { | 190 | system.activationScripts.taskserver = { |
115 | deps = [ "users" ]; | 191 | deps = [ "users" ]; |
@@ -127,5 +203,67 @@ in { | |||
127 | listenHost = "::"; | 203 | listenHost = "::"; |
128 | requestLimit = 104857600; | 204 | requestLimit = 104857600; |
129 | }; | 205 | }; |
206 | |||
207 | system.activationScripts.taskwarrior-web = { | ||
208 | deps = [ "users" ]; | ||
209 | text = '' | ||
210 | install -m 0755 -o ${user} -g ${group} -d ${taskwarrior-web.socketsDir} | ||
211 | install -m 0750 -o ${user} -g ${group} -d ${taskwarrior-web.varDir} | ||
212 | ${builtins.concatStringsSep "\n" (lib.attrsets.mapAttrsToList | ||
213 | (k: v: "install -m 0750 -o ${user} -g ${group} -d ${taskwarrior-web.varDir}/${k}") | ||
214 | env.taskwarrior-web | ||
215 | )} | ||
216 | if [ ! -f ${vardir}/userkeys/taskwarrior-web.cert.pem ]; then | ||
217 | ${taskserver-user-certs}/bin/taskserver-user-certs taskwarrior-web | ||
218 | chown taskd:taskd ${vardir}/userkeys/taskwarrior-web.cert.pem ${vardir}/userkeys/taskwarrior-web.key.pem | ||
219 | fi | ||
220 | ''; | ||
221 | }; | ||
222 | |||
223 | systemd.services = (lib.attrsets.mapAttrs' (name: userConfig: | ||
224 | let | ||
225 | credentials = "${userConfig.org}/${name}/${userConfig.key}"; | ||
226 | dateFormat = userConfig.date; | ||
227 | taskrc = pkgs.writeText "taskrc" '' | ||
228 | data.location=${taskwarrior-web.varDir}/${name} | ||
229 | taskd.certificate=${vardir}/userkeys/taskwarrior-web.cert.pem | ||
230 | taskd.key=${vardir}/userkeys/taskwarrior-web.key.pem | ||
231 | taskd.ca=${vardir}/keys/server.cert | ||
232 | taskd.server=${fqdn}:${toString config.services.taskserver.listenPort} | ||
233 | taskd.credentials=${credentials} | ||
234 | dateformat=${dateFormat} | ||
235 | ''; | ||
236 | in lib.attrsets.nameValuePair "taskwarrior-web-${name}" { | ||
237 | description = "Taskwarrior webapp for ${name}"; | ||
238 | wantedBy = [ "multi-user.target" ]; | ||
239 | after = [ "network.target" ]; | ||
240 | path = [ pkgs.taskwarrior ]; | ||
241 | |||
242 | environment.TASKRC = taskrc; | ||
243 | environment.BUNDLE_PATH = "${taskwarrior-web.gems}/lib/ruby/gems/2.5.0"; | ||
244 | environment.BUNDLE_GEMFILE = "${taskwarrior-web.gems.confFiles}/Gemfile"; | ||
245 | environment.LC_ALL = "fr_FR.UTF-8"; | ||
246 | |||
247 | script = '' | ||
248 | exec ${taskwarrior-web.gems}/lib/ruby/gems/2.5.0/bin/bundle exec thin start -R config.ru -S ${taskwarrior-web.socketsDir}/${name}.sock | ||
249 | ''; | ||
250 | |||
251 | serviceConfig = { | ||
252 | User = user; | ||
253 | PrivateTmp = true; | ||
254 | Restart = "always"; | ||
255 | TimeoutSec = 60; | ||
256 | Type = "simple"; | ||
257 | WorkingDirectory = taskwarrior-web.rubyRoot; | ||
258 | }; | ||
259 | |||
260 | unitConfig.RequiresMountsFor = taskwarrior-web.varDir; | ||
261 | }) env.taskwarrior-web) // { | ||
262 | taskserver-ca.postStart = '' | ||
263 | chown :${group} "${vardir}/keys/ca.key" | ||
264 | chmod g+r "${vardir}/keys/ca.key" | ||
265 | ''; | ||
266 | }; | ||
267 | |||
130 | }; | 268 | }; |
131 | } | 269 | } |