diff options
author | Ismaël Bouya <ismael.bouya@normalesup.org> | 2023-10-04 01:35:06 +0200 |
---|---|---|
committer | Ismaël Bouya <ismael.bouya@normalesup.org> | 2023-10-04 02:11:48 +0200 |
commit | 1a64deeb894dc95e2645a75771732c6cc53a79ad (patch) | |
tree | 1b9df4838f894577a09b9b260151756272efeb53 /systems/eldiron/tasks | |
parent | fa25ffd4583cc362075cd5e1b4130f33306103f0 (diff) | |
download | Nix-1a64deeb894dc95e2645a75771732c6cc53a79ad.tar.gz Nix-1a64deeb894dc95e2645a75771732c6cc53a79ad.tar.zst Nix-1a64deeb894dc95e2645a75771732c6cc53a79ad.zip |
Squash changes containing private information
There were a lot of changes since the previous commit, but a lot of them
contained personnal information about users. All thos changes got
stashed into a single commit (history is kept in a different place) and
private information was moved in a separate private repository
Diffstat (limited to 'systems/eldiron/tasks')
-rw-r--r-- | systems/eldiron/tasks/default.nix | 384 | ||||
-rw-r--r-- | systems/eldiron/tasks/www/index.php | 168 |
2 files changed, 552 insertions, 0 deletions
diff --git a/systems/eldiron/tasks/default.nix b/systems/eldiron/tasks/default.nix new file mode 100644 index 0000000..0772a5f --- /dev/null +++ b/systems/eldiron/tasks/default.nix | |||
@@ -0,0 +1,384 @@ | |||
1 | { lib, pkgs, config, taskwarrior-web, ... }: | ||
2 | let | ||
3 | cfg = config.myServices.tasks; | ||
4 | server_vardir = config.services.taskserver.dataDir; | ||
5 | fqdn = "task.immae.eu"; | ||
6 | user = config.services.taskserver.user; | ||
7 | env = config.myEnv.tools.task; | ||
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 "${server_vardir}/userkeys/$user.key.pem" | ||
26 | ${pkgs.gnused}/bin/sed -i -n -e '/^-----BEGIN RSA PRIVATE KEY-----$/,$p' "${server_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 "${server_vardir}/keys/ca.cert" \ | ||
36 | --load-ca-privkey "${server_vardir}/keys/ca.key" \ | ||
37 | --load-privkey "${server_vardir}/userkeys/$user.key.pem" \ | ||
38 | --outfile "${server_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 | socketsDir = "/run/taskwarrior-web"; | ||
44 | varDir = "/var/lib/taskwarrior-web"; | ||
45 | taskwebPages = let | ||
46 | uidPages = lib.attrsets.zipAttrs ( | ||
47 | lib.lists.flatten | ||
48 | (lib.attrsets.mapAttrsToList (k: c: map (v: { "${v}" = k; }) c.uid) env.taskwarrior-web) | ||
49 | ); | ||
50 | pages = lib.attrsets.mapAttrs (uid: items: | ||
51 | if lib.lists.length items == 1 then | ||
52 | '' | ||
53 | <html> | ||
54 | <head> | ||
55 | <meta http-equiv="refresh" content="0; url=/taskweb/${lib.lists.head items}/" /> | ||
56 | </head> | ||
57 | <body></body> | ||
58 | </html> | ||
59 | '' | ||
60 | else | ||
61 | '' | ||
62 | <html> | ||
63 | <head> | ||
64 | <title>To-do list disponibles</title> | ||
65 | <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | ||
66 | <meta name="viewport" content="width=device-width, initial-scale=1" /> | ||
67 | </head> | ||
68 | <body> | ||
69 | <ul> | ||
70 | ${builtins.concatStringsSep "\n" (map (item: "<li><a href='/taskweb/${item}'>${item}</a></li>") items)} | ||
71 | </ul> | ||
72 | </body> | ||
73 | </html> | ||
74 | '' | ||
75 | ) uidPages; | ||
76 | in | ||
77 | pkgs.runCommand "taskwerver-pages" {} '' | ||
78 | mkdir -p $out/ | ||
79 | ${builtins.concatStringsSep "\n" (lib.attrsets.mapAttrsToList (k: v: "cp ${pkgs.writeText k v} $out/${k}.html") pages)} | ||
80 | echo "Please login" > $out/index.html | ||
81 | ''; | ||
82 | in { | ||
83 | options.myServices.tasks = { | ||
84 | enable = lib.mkEnableOption "my tasks service"; | ||
85 | }; | ||
86 | |||
87 | config = lib.mkIf cfg.enable { | ||
88 | myServices.dns.zones."immae.eu".subdomains.task = | ||
89 | with config.myServices.dns.helpers; ips servers.eldiron.ips.main; | ||
90 | |||
91 | myServices.chatonsProperties.services.taskwarrior = { | ||
92 | file.datetime = "2022-08-22T00:00:00"; | ||
93 | service = { | ||
94 | name = "Taskwarrior"; | ||
95 | description = "Taskwarrior is Free and Open Source Software that manages your TODO list from the command line. Web interface and synchronization server"; | ||
96 | website = "https://task.immae.eu/"; | ||
97 | logo = "https://taskwarrior.org/favicon.ico"; | ||
98 | status.level = "OK"; | ||
99 | status.description = "OK"; | ||
100 | registration."" = ["MEMBER" "CLIENT"]; | ||
101 | registration.load = "OPEN"; | ||
102 | install.type = "PACKAGE"; | ||
103 | }; | ||
104 | software = { | ||
105 | name = "Taskwarrior"; | ||
106 | website = "https://taskwarrior.org/"; | ||
107 | license.url = "https://github.com/GothenburgBitFactory/taskwarrior/blob/develop/LICENSE"; | ||
108 | license.name = "MIT License"; | ||
109 | version = taskwarrior-web.version; | ||
110 | source.url = "https://taskwarrior.org/download/"; | ||
111 | }; | ||
112 | }; | ||
113 | secrets.keys = { | ||
114 | "webapps/tools-taskwarrior-web" = { | ||
115 | user = "wwwrun"; | ||
116 | group = "wwwrun"; | ||
117 | permissions = "0400"; | ||
118 | text = '' | ||
119 | SetEnv TASKD_HOST "${fqdn}:${toString config.services.taskserver.listenPort}" | ||
120 | SetEnv TASKD_VARDIR "${server_vardir}" | ||
121 | SetEnv TASKD_LDAP_HOST "ldaps://${env.ldap.host}" | ||
122 | SetEnv TASKD_LDAP_DN "${env.ldap.dn}" | ||
123 | SetEnv TASKD_LDAP_PASSWORD "${env.ldap.password}" | ||
124 | SetEnv TASKD_LDAP_BASE "${env.ldap.base}" | ||
125 | SetEnv TASKD_LDAP_FILTER "${env.ldap.filter}" | ||
126 | ''; | ||
127 | }; | ||
128 | } // (lib.mapAttrs' (name: userConfig: lib.nameValuePair "webapps/tools-taskwarrior/${name}-taskrc" ( | ||
129 | let | ||
130 | credentials = "${userConfig.org}/${name}/${userConfig.key}"; | ||
131 | dateFormat = userConfig.date; | ||
132 | cacert = pkgs.writeText "ca.cert" '' | ||
133 | -----BEGIN CERTIFICATE----- | ||
134 | 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 | ||
163 | -----END CERTIFICATE-----''; | ||
164 | in { | ||
165 | inherit user group; | ||
166 | permissions = "0400"; | ||
167 | text = '' | ||
168 | data.location=${varDir}/${name} | ||
169 | taskd.certificate=${server_vardir}/userkeys/taskwarrior-web.cert.pem | ||
170 | taskd.key=${server_vardir}/userkeys/taskwarrior-web.key.pem | ||
171 | # IdenTrust DST Root CA X3 | ||
172 | # obtained here: https://letsencrypt.org/fr/certificates/ | ||
173 | taskd.ca=${cacert} | ||
174 | taskd.server=${fqdn}:${toString config.services.taskserver.listenPort} | ||
175 | taskd.credentials=${credentials} | ||
176 | dateformat=${dateFormat} | ||
177 | ''; | ||
178 | keyDependencies = [ cacert ]; | ||
179 | })) env.taskwarrior-web); | ||
180 | security.acme.certs.eldiron.extraDomainNames = [ "task.immae.eu" ]; | ||
181 | services.websites.env.tools.watchPaths = [ config.secrets.fullPaths."webapps/tools-taskwarrior-web" ]; | ||
182 | services.websites.env.tools.modules = [ "proxy_fcgi" "sed" ]; | ||
183 | services.websites.env.tools.vhostConfs.task = { | ||
184 | certName = "eldiron"; | ||
185 | hosts = [ "task.immae.eu" ]; | ||
186 | root = ./www; | ||
187 | extraConfig = [ '' | ||
188 | <Directory ${./www}> | ||
189 | DirectoryIndex index.php | ||
190 | Use LDAPConnect | ||
191 | Require ldap-group cn=users,cn=taskwarrior,ou=services,dc=immae,dc=eu | ||
192 | <FilesMatch "\.php$"> | ||
193 | SetHandler "proxy:unix:${config.services.phpfpm.pools.tasks.socket}|fcgi://localhost" | ||
194 | </FilesMatch> | ||
195 | Include ${config.secrets.fullPaths."webapps/tools-taskwarrior-web"} | ||
196 | </Directory> | ||
197 | '' | ||
198 | '' | ||
199 | <Macro Taskwarrior %{folderName}> | ||
200 | ProxyPass "unix://${socketsDir}/%{folderName}.sock|http://localhost-%{folderName}/" | ||
201 | ProxyPassReverse "unix://${socketsDir}/%{folderName}.sock|http://localhost-%{folderName}/" | ||
202 | ProxyPassReverse http://${fqdn}/ | ||
203 | |||
204 | SetOutputFilter Sed | ||
205 | OutputSed "s|/ajax|/taskweb/%{folderName}/ajax|g" | ||
206 | OutputSed "s|\([^x]\)/tasks|\1/taskweb/%{folderName}/tasks|g" | ||
207 | OutputSed "s|\([^x]\)/projects|\1/taskweb/%{folderName}/projects|g" | ||
208 | OutputSed "s|http://${fqdn}/|/taskweb/%{folderName}/|g" | ||
209 | OutputSed "s|/img/relax.jpg|/taskweb/%{folderName}/img/relax.jpg|g" | ||
210 | </Macro> | ||
211 | '' | ||
212 | '' | ||
213 | Alias /taskweb ${taskwebPages} | ||
214 | <Directory "${taskwebPages}"> | ||
215 | DirectoryIndex index.html | ||
216 | Require all granted | ||
217 | </Directory> | ||
218 | |||
219 | RewriteEngine on | ||
220 | RewriteRule ^/taskweb$ /taskweb/ [R=301,L] | ||
221 | RedirectMatch permanent ^/taskweb/([^/]+)$ /taskweb/$1/ | ||
222 | |||
223 | RewriteCond %{LA-U:REMOTE_USER} !="" | ||
224 | RewriteCond ${taskwebPages}/%{LA-U:REMOTE_USER}.html -f | ||
225 | RewriteRule ^/taskweb/?$ ${taskwebPages}/%{LA-U:REMOTE_USER}.html [L] | ||
226 | |||
227 | <Location /taskweb/> | ||
228 | Use LDAPConnect | ||
229 | Require ldap-group cn=users,cn=taskwarrior,ou=services,dc=immae,dc=eu | ||
230 | </Location> | ||
231 | '' | ||
232 | ] ++ (lib.attrsets.mapAttrsToList (k: v: '' | ||
233 | <Location /taskweb/${k}/> | ||
234 | ${builtins.concatStringsSep "\n" (map (uid: "Require ldap-attribute uid=${uid}") v.uid)} | ||
235 | |||
236 | Use Taskwarrior ${k} | ||
237 | </Location> | ||
238 | '') env.taskwarrior-web); | ||
239 | }; | ||
240 | services.phpfpm.pools = { | ||
241 | tasks = { | ||
242 | user = user; | ||
243 | group = group; | ||
244 | settings = { | ||
245 | "listen.owner" = "wwwrun"; | ||
246 | "listen.group" = "wwwrun"; | ||
247 | "pm" = "dynamic"; | ||
248 | "pm.max_children" = "60"; | ||
249 | "pm.start_servers" = "2"; | ||
250 | "pm.min_spare_servers" = "1"; | ||
251 | "pm.max_spare_servers" = "10"; | ||
252 | |||
253 | # Needed to avoid clashes in browser cookies (same domain) | ||
254 | "php_value[session.name]" = "TaskPHPSESSID"; | ||
255 | "php_admin_value[session.save_handler]" = "redis"; | ||
256 | "php_admin_value[session.save_path]" = "'unix:///run/redis-php-sessions/redis.sock?persistent=1&prefix=Tools:Task:'"; | ||
257 | "php_admin_value[open_basedir]" = "${./www}:/tmp:${server_vardir}:/etc/profiles/per-user/${user}/bin/"; | ||
258 | }; | ||
259 | phpEnv = { | ||
260 | PATH = "/etc/profiles/per-user/${user}/bin"; | ||
261 | }; | ||
262 | phpPackage = pkgs.php72.withExtensions({ enabled, all }: enabled ++ [ all.redis ]); | ||
263 | }; | ||
264 | }; | ||
265 | |||
266 | security.acme.certs."task" = { | ||
267 | inherit group; | ||
268 | domain = fqdn; | ||
269 | postRun = '' | ||
270 | systemctl restart taskserver.service | ||
271 | ''; | ||
272 | }; | ||
273 | |||
274 | users.users.${user} = { | ||
275 | extraGroups = [ "keys" ]; | ||
276 | packages = [ taskserver-user-certs ]; | ||
277 | }; | ||
278 | |||
279 | system.activationScripts.taskserver = { | ||
280 | deps = [ "users" ]; | ||
281 | text = '' | ||
282 | install -m 0750 -o ${user} -g ${group} -d ${server_vardir} | ||
283 | install -m 0750 -o ${user} -g ${group} -d ${server_vardir}/userkeys | ||
284 | install -m 0750 -o ${user} -g ${group} -d ${server_vardir}/keys | ||
285 | |||
286 | if [ ! -e "${server_vardir}/keys/ca.key" ]; then | ||
287 | silent_certtool() { | ||
288 | if ! output="$("${pkgs.gnutls.bin}/bin/certtool" "$@" 2>&1)"; then | ||
289 | echo "GNUTLS certtool invocation failed with output:" >&2 | ||
290 | echo "$output" >&2 | ||
291 | fi | ||
292 | } | ||
293 | |||
294 | silent_certtool -p \ | ||
295 | --bits 4096 \ | ||
296 | --outfile "${server_vardir}/keys/ca.key" | ||
297 | |||
298 | silent_certtool -s \ | ||
299 | --template "${pkgs.writeText "taskserver-ca.template" '' | ||
300 | cn = ${fqdn} | ||
301 | expiration_days = -1 | ||
302 | cert_signing_key | ||
303 | ca | ||
304 | ''}" \ | ||
305 | --load-privkey "${server_vardir}/keys/ca.key" \ | ||
306 | --outfile "${server_vardir}/keys/ca.cert" | ||
307 | |||
308 | chown :${group} "${server_vardir}/keys/ca.key" | ||
309 | chmod g+r "${server_vardir}/keys/ca.key" | ||
310 | fi | ||
311 | ''; | ||
312 | }; | ||
313 | |||
314 | services.taskserver = { | ||
315 | enable = true; | ||
316 | allowedClientIDs = [ "^task [2-9]" "^Mirakel [1-9]" ]; | ||
317 | inherit fqdn; | ||
318 | listenHost = "::"; | ||
319 | pki.manual.ca.cert = "${server_vardir}/keys/ca.cert"; | ||
320 | pki.manual.server.cert = "${config.security.acme.certs.task.directory}/fullchain.pem"; | ||
321 | pki.manual.server.crl = "${config.security.acme.certs.task.directory}/invalid.crl"; | ||
322 | pki.manual.server.key = "${config.security.acme.certs.task.directory}/key.pem"; | ||
323 | requestLimit = 104857600; | ||
324 | }; | ||
325 | |||
326 | system.activationScripts.taskwarrior-web = { | ||
327 | deps = [ "users" ]; | ||
328 | text = '' | ||
329 | if [ ! -f ${server_vardir}/userkeys/taskwarrior-web.cert.pem ]; then | ||
330 | ${taskserver-user-certs}/bin/taskserver-user-certs taskwarrior-web | ||
331 | chown taskd:taskd ${server_vardir}/userkeys/taskwarrior-web.cert.pem ${server_vardir}/userkeys/taskwarrior-web.key.pem | ||
332 | fi | ||
333 | ''; | ||
334 | }; | ||
335 | |||
336 | systemd.slices.taskwarrior = { | ||
337 | description = "Taskwarrior slice"; | ||
338 | }; | ||
339 | |||
340 | systemd.services = (lib.attrsets.mapAttrs' (name: userConfig: | ||
341 | lib.attrsets.nameValuePair "taskwarrior-web-${name}" { | ||
342 | description = "Taskwarrior webapp for ${name}"; | ||
343 | wantedBy = [ "multi-user.target" ]; | ||
344 | after = [ "network.target" ]; | ||
345 | path = [ pkgs.taskwarrior ]; | ||
346 | |||
347 | environment.TASKRC = config.secrets.fullPaths."webapps/tools-taskwarrior/${name}-taskrc"; | ||
348 | environment.BUNDLE_PATH = "${taskwarrior-web.gems}/${taskwarrior-web.gems.ruby.gemPath}"; | ||
349 | environment.BUNDLE_GEMFILE = "${taskwarrior-web.gems.confFiles}/Gemfile"; | ||
350 | environment.LC_ALL = "fr_FR.UTF-8"; | ||
351 | |||
352 | script = '' | ||
353 | exec ${taskwarrior-web.gems}/${taskwarrior-web.gems.ruby.gemPath}/bin/bundle exec thin start -R config.ru -S ${socketsDir}/${name}.sock | ||
354 | ''; | ||
355 | |||
356 | serviceConfig = { | ||
357 | Slice = "taskwarrior.slice"; | ||
358 | User = user; | ||
359 | PrivateTmp = true; | ||
360 | Restart = "always"; | ||
361 | TimeoutSec = 60; | ||
362 | Type = "simple"; | ||
363 | WorkingDirectory = taskwarrior-web; | ||
364 | StateDirectoryMode = 0750; | ||
365 | StateDirectory = assert lib.strings.hasPrefix "/var/lib/" varDir; | ||
366 | (lib.strings.removePrefix "/var/lib/" varDir + "/${name}"); | ||
367 | RuntimeDirectoryPreserve = "yes"; | ||
368 | RuntimeDirectory = assert lib.strings.hasPrefix "/run/" socketsDir; | ||
369 | lib.strings.removePrefix "/run/" socketsDir; | ||
370 | }; | ||
371 | |||
372 | unitConfig.RequiresMountsFor = varDir; | ||
373 | }) env.taskwarrior-web) // { | ||
374 | taskserver-ca.postStart = '' | ||
375 | chown :${group} "${server_vardir}/keys/ca.key" | ||
376 | chmod g+r "${server_vardir}/keys/ca.key" | ||
377 | ''; | ||
378 | taskserver-ca.serviceConfig.Slice = "taskwarrior.slice"; | ||
379 | taskserver-init.serviceConfig.Slice = "taskwarrior.slice"; | ||
380 | taskserver.serviceConfig.Slice = "taskwarrior.slice"; | ||
381 | }; | ||
382 | |||
383 | }; | ||
384 | } | ||
diff --git a/systems/eldiron/tasks/www/index.php b/systems/eldiron/tasks/www/index.php new file mode 100644 index 0000000..bde773d --- /dev/null +++ b/systems/eldiron/tasks/www/index.php | |||
@@ -0,0 +1,168 @@ | |||
1 | <?php | ||
2 | if (!isset($_SERVER["REMOTE_USER"])) { | ||
3 | die("please login"); | ||
4 | } | ||
5 | $ldap_user = $_SERVER["REMOTE_USER"]; | ||
6 | $ldap_host = getenv("TASKD_LDAP_HOST"); | ||
7 | $ldap_dn = getenv('TASKD_LDAP_DN'); | ||
8 | $ldap_password = getenv('TASKD_LDAP_PASSWORD'); | ||
9 | $ldap_base = getenv('TASKD_LDAP_BASE'); | ||
10 | $ldap_filter = getenv('TASKD_LDAP_FILTER'); | ||
11 | $host = getenv('TASKD_HOST'); | ||
12 | $vardir = getenv('TASKD_VARDIR'); | ||
13 | |||
14 | $connect = ldap_connect($ldap_host); | ||
15 | ldap_set_option($connect, LDAP_OPT_PROTOCOL_VERSION, 3); | ||
16 | if (!$connect || !ldap_bind($connect, $ldap_dn, $ldap_password)) { | ||
17 | die("impossible to connect to LDAP"); | ||
18 | } | ||
19 | |||
20 | $search_query = str_replace('%login%', ldap_escape($ldap_user), $ldap_filter); | ||
21 | |||
22 | $search = ldap_search($connect, $ldap_base, $search_query); | ||
23 | $info = ldap_get_entries($connect, $search); | ||
24 | |||
25 | if (ldap_count_entries($connect, $search) != 1) { | ||
26 | die("Impossible to find user in LDAP"); | ||
27 | } | ||
28 | |||
29 | $entries = []; | ||
30 | foreach($info[0]["immaetaskid"] as $key => $value) { | ||
31 | if ($key !== "count") { | ||
32 | $entries[] = explode(":", $value); | ||
33 | } | ||
34 | } | ||
35 | |||
36 | if (isset($_GET["file"])) { | ||
37 | $basecert = $vardir . "/userkeys/" . $ldap_user; | ||
38 | if (!file_exists($basecert . ".cert.pem")) { | ||
39 | exec("taskserver-user-certs $ldap_user"); | ||
40 | } | ||
41 | $certificate = file_get_contents($basecert . ".cert.pem"); | ||
42 | $cert_key = file_get_contents($basecert . ".key.pem"); | ||
43 | |||
44 | // IdenTrust DST Root CA X3 | ||
45 | // obtained here: https://letsencrypt.org/fr/certificates/ | ||
46 | $server_cert = "-----BEGIN CERTIFICATE----- | ||
47 | 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 | ||
76 | -----END CERTIFICATE-----"; | ||
77 | |||
78 | $file = $_GET["file"]; | ||
79 | switch($file) { | ||
80 | case "ca.cert.pem": | ||
81 | $content = $server_cert; | ||
82 | $name = "ca.cert.pem"; | ||
83 | $type = "application/x-x509-ca-cert"; | ||
84 | break; | ||
85 | case "cert.pem": | ||
86 | $content = $certificate; | ||
87 | $name = $ldap_user . ".cert.pem"; | ||
88 | $type = "application/x-x509-ca-cert"; | ||
89 | break; | ||
90 | case "key.pem": | ||
91 | $content = $cert_key; | ||
92 | $name = $ldap_user . ".key.pem"; | ||
93 | $type = "application/x-x509-ca-cert"; | ||
94 | break; | ||
95 | case "mirakel"; | ||
96 | foreach ($entries as $entry) { | ||
97 | list($org, $user, $key) = $entry; | ||
98 | if ($key == $_GET["key"]) { break; } | ||
99 | } | ||
100 | $name = $user . ".mirakel"; | ||
101 | $type = "text/plain"; | ||
102 | $content = "username: $user | ||
103 | org: $org | ||
104 | user key: $key | ||
105 | server: $host | ||
106 | client.cert: | ||
107 | $certificate | ||
108 | Client.key: | ||
109 | $cert_key | ||
110 | ca.cert: | ||
111 | $server_cert | ||
112 | "; | ||
113 | break; | ||
114 | default: | ||
115 | die("invalid file name"); | ||
116 | break; | ||
117 | } | ||
118 | |||
119 | header("Content-Type: $type"); | ||
120 | header('Content-Disposition: attachment; filename="' . $name . '"'); | ||
121 | header('Content-Transfer-Encoding: binary'); | ||
122 | header('Accept-Ranges: bytes'); | ||
123 | header('Cache-Control: private'); | ||
124 | header('Pragma: private'); | ||
125 | echo $content; | ||
126 | exit; | ||
127 | } | ||
128 | ?> | ||
129 | <html> | ||
130 | <header> | ||
131 | <title>Taskwarrior configuration</title> | ||
132 | </header> | ||
133 | <body> | ||
134 | <ul> | ||
135 | <li><a href="?file=ca.cert.pem">ca.cert.pem</a></li> | ||
136 | <li><a href="?file=cert.pem"><?php echo $ldap_user; ?>.cert.pem</a></li> | ||
137 | <li><a href="?file=key.pem"><?php echo $ldap_user; ?>.key.pem</a></li> | ||
138 | </ul> | ||
139 | For command line interface, download the files, put them near your Taskwarrior | ||
140 | configuration files, and add that to your Taskwarrior configuration: | ||
141 | <pre> | ||
142 | taskd.certificate=/path/to/<?php echo $ldap_user; ?>.cert.pem | ||
143 | taskd.key=/path/to/<?php echo $ldap_user; ?>.key.pem | ||
144 | taskd.server=<?php echo $host ."\n"; ?> | ||
145 | taskd.ca=/path/to/ca.cert.pem | ||
146 | <?php if (count($entries) > 1) { | ||
147 | echo "# Chose one of them\n"; | ||
148 | foreach($entries as $entry) { | ||
149 | list($org, $user, $key) = $entry; | ||
150 | echo "# taskd.credentials=$org/$user/$key\n"; | ||
151 | } | ||
152 | } else { ?> | ||
153 | taskd.credentials=<?php echo $entries[0][0]; ?>/<?php echo $entries[0][1]; ?>/<?php echo $entries[0][2]; ?> | ||
154 | <?php } ?> | ||
155 | </pre> | ||
156 | For Mirakel, download and import the file: | ||
157 | <ul> | ||
158 | <?php | ||
159 | foreach ($entries as $entry) { | ||
160 | list($org, $user, $key) = $entry; | ||
161 | echo '<li><a href="?file=mirakel&key='.$key.'">' . $user . '.mirakel</a></li>'; | ||
162 | } | ||
163 | ?> | ||
164 | </ul> | ||
165 | For Android Taskwarrior app, see instructions <a href="https://bitbucket.org/kvorobyev/taskwarriorandroid/wiki/Configuration">here</a>. | ||
166 | </body> | ||
167 | </html> | ||
168 | |||