+++ /dev/null
-{ pkgs, config, lib, ... }:
-let
- cfg = config.myServices.tools.cryptpad.farm;
- toService = name:
- let
- inherit (cfg.hosts.${name}) package config;
- in {
- description = "Cryptpad ${name} Service";
- wantedBy = [ "multi-user.target" ];
- after = [ "networking.target" ];
- serviceConfig = {
- User = "cryptpad";
- Group = "cryptpad";
- Environment = [
- "CRYPTPAD_CONFIG=${config}"
- "HOME=%S/cryptpad/${name}"
- ];
- ExecStart = "${package}/bin/cryptpad";
- PrivateTmp = true;
- Restart = "always";
- StateDirectory = "cryptpad/${name}";
- WorkingDirectory = "%S/cryptpad/${name}";
- };
- };
- toVhostRoot = name: "${cfg.hosts.${name}.package}/lib/node_modules/cryptpad";
- toVhost = name:
- let
- inherit (cfg.hosts.${name}) package domain port;
- api_domain = domain;
- files_domain = domain;
- in ''
- RewriteEngine On
-
- Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
- Header set X-XSS-Protection "1; mode=block"
- Header set X-Content-Type-Options "nosniff"
- Header set Access-Control-Allow-Origin "*"
- Header set Permissions-Policy "interest-cohort=()"
-
- Header set Cross-Origin-Resource-Policy "cross-origin"
- <If "%{REQUEST_URI} =~ m#^/(sheet|presentation|doc)/.*$#">
- Header set Cross-Origin-Opener-Policy "same-origin"
- </If>
- Header set Cross-Origin-Embedder-Policy "require-corp"
-
- ErrorDocument 404 /customize.dist/404.html
-
- <If "%{QUERY_STRING} =~ m#ver=.*?#">
- Header set Cache-Control "max-age=31536000"
- </If>
- <If "%{REQUEST_URI} =~ m#^/.*(\/|\.html)$#">
- Header set Cache-Control "no-cache"
- </If>
-
- SetEnv styleSrc "'unsafe-inline' 'self' ${domain}"
- SetEnv connectSrc "'self' https://${domain} ${domain} https://${api_domain} blob: wss://${api_domain} ${api_domain} ${files_domain}"
- SetEnv fontSrc "'self' data: ${domain}"
- SetEnv imgSrc "'self' data: * blob: ${domain}"
- SetEnv frameSrc "'self' blob:"
- SetEnv mediaSrc "'self' data: * blob: ${domain}"
- SetEnv childSrc "https://${domain}"
- SetEnv workerSrc "https://${domain}"
- SetEnv scriptSrc "'self' 'unsafe-eval' 'unsafe-inline' resource: ${domain}"
-
- Header set Content-Security-Policy "default-src 'none'; child-src %{childSrc}e; worker-src %{workerSrc}e; media-src %{mediaSrc}e; style-src %{styleSrc}e; script-src %{scriptSrc}e; connect-src %{connectSrc}e; font-src %{fontSrc}e; img-src %{imgSrc}e; frame-src %{frameSrc}e;"
-
- RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
- RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC]
- RewriteRule .* ws://localhost:${toString port}%{REQUEST_URI} [P,NE,QSA,L]
-
- RewriteRule ^/customize/(.*)$ /customize.dist/$1 [L]
-
- ProxyPassMatch "^/(api/(config|broadcast).*)$" "http://localhost:${toString port}/$1"
- ProxyPassReverse /api http://localhost:${toString port}/api
- ProxyPreserveHost On
- RequestHeader set X-Real-IP %{REMOTE_ADDR}s
-
- Alias /blob /var/lib/cryptpad/${name}/blob
- <Directory /var/lib/cryptpad/${name}/blob>
- Require all granted
- AllowOverride None
- </Directory>
- Alias /block /var/lib/cryptpad/${name}/block
- <Directory /var/lib/cryptpad/${name}/block>
- Require all granted
- AllowOverride None
- </Directory>
- <LocationMatch /blob/>
- Header set Cache-Control "max-age=31536000"
- Header set Access-Control-Allow-Origin "*"
- Header set Access-Control-Allow-Methods "GET, POST, OPTIONS"
- Header set Access-Control-Allow-Headers "DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range,Content-Length"
- Header set Access-Control-Expose-Headers "DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range,Content-Length"
-
- RewriteCond %{REQUEST_METHOD} OPTIONS
- RewriteRule ^(.*)$ $1 [R=204,L]
- </LocationMatch>
-
- <LocationMatch /block/>
- Header set Cache-Control "max-age=0"
- </locationMatch>
-
- RewriteRule ^/(register|login|settings|user|pad|drive|poll|slide|code|whiteboard|file|media|profile|contacts|todo|filepicker|debug|kanban|sheet|support|admin|notifications|teams|calendar|presentation|doc)$ $1/ [R=302,L]
-
- RewriteCond %{DOCUMENT_ROOT}/www/%{REQUEST_URI} -f
- RewriteRule (.*) /www/$1 [L]
-
- RewriteCond %{DOCUMENT_ROOT}/www/%{REQUEST_URI}/index.html -f
- RewriteRule (.*) /www/$1/index.html [L]
-
- RewriteCond %{DOCUMENT_ROOT}/customize.dist/%{REQUEST_URI} -f
- RewriteRule (.*) /customize.dist/$1 [L]
-
- <Directory ${package}/lib/node_modules/cryptpad/www>
- AllowOverride None
- Require all granted
- DirectoryIndex index.html
- </Directory>
- <Directory ${package}/lib/node_modules/cryptpad/customize.dist>
- AllowOverride None
- Require all granted
- DirectoryIndex index.html
- </Directory>
- '';
-in
-{
- options.myServices.tools.cryptpad.farm = {
- hosts = lib.mkOption {
- default = {};
- description = "Hosts to install";
- type = lib.types.attrsOf (lib.types.submodule {
- options = {
- port = lib.mkOption {
- type = lib.types.port;
- };
- package = lib.mkOption {
- type = lib.types.package;
- description = "Cryptpad package to use";
- default = pkgs.cryptpad;
- };
- domain = lib.mkOption {
- type = lib.types.str;
- description = "Domain for main host";
- };
- config = lib.mkOption {
- type = lib.types.path;
- description = "Path to configuration";
- };
- };
- });
- };
- vhosts = lib.mkOption {
- description = "Instance vhosts configs";
- readOnly = true;
- type = lib.types.attrsOf lib.types.str;
- default = lib.genAttrs (builtins.attrNames cfg.hosts) toVhost;
- };
- vhostRoots = lib.mkOption {
- description = "Instance vhosts document roots";
- readOnly = true;
- type = lib.types.attrsOf lib.types.path;
- default = lib.genAttrs (builtins.attrNames cfg.hosts) toVhostRoot;
- };
- };
- config = {
- users.users = lib.optionalAttrs (cfg.hosts != {}) {
- cryptpad = {
- uid = config.ids.uids.cryptpad;
- group = "cryptpad";
- description = "Cryptpad user";
- };
- };
- users.groups = lib.optionalAttrs (cfg.hosts != {}) {
- cryptpad = {
- gid = config.ids.gids.cryptpad;
- };
- };
- systemd.services = lib.listToAttrs (map (n: lib.nameValuePair "cryptpad-${n}" (toService n)) (builtins.attrNames cfg.hosts));
- };
-}