at 25.11-pre 4.9 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7 8let 9 inherit (lib) 10 mkIf 11 mkOption 12 mkEnableOption 13 mkPackageOption 14 mkDefault 15 types 16 concatMapStringsSep 17 generators 18 ; 19 cfg = config.services.open-web-calendar; 20 21 nixosSpec = calendarSettingsFormat.generate "nixos_specification.json" cfg.calendarSettings; 22 finalPackage = cfg.package.override { 23 # The calendarSettings need to be merged with the default_specification.yml 24 # in the source. This way we use upstreams default values but keep everything overridable. 25 defaultSpecificationFile = pkgs.runCommand "custom-default_specification.yml" { } '' 26 ${pkgs.yq}/bin/yq -s '.[0] * .[1]' ${cfg.package}/${cfg.package.defaultSpecificationPath} ${nixosSpec} > $out 27 ''; 28 }; 29 30 inherit (finalPackage) python; 31 pythonEnv = python.buildEnv.override { 32 extraLibs = [ 33 (python.pkgs.toPythonModule finalPackage) 34 # Allows Gunicorn to set a meaningful process name 35 python.pkgs.gunicorn.optional-dependencies.setproctitle 36 ]; 37 }; 38 39 settingsFormat = pkgs.formats.keyValue { }; 40 calendarSettingsFormat = pkgs.formats.json { }; 41in 42{ 43 options.services.open-web-calendar = { 44 45 enable = mkEnableOption "OpenWebCalendar service"; 46 47 package = mkPackageOption pkgs "open-web-calendar" { }; 48 49 domain = mkOption { 50 type = types.str; 51 description = "The domain under which open-web-calendar is made available"; 52 example = "open-web-calendar.example.org"; 53 }; 54 55 settings = mkOption { 56 type = types.submodule { 57 freeformType = settingsFormat.type; 58 options = { 59 ALLOWED_HOSTS = mkOption { 60 type = types.str; 61 readOnly = true; 62 description = '' 63 The hosts that the Open Web Calendar permits. This is required to 64 mitigate the Host Header Injection vulnerability. 65 66 We always set this to the empty list, as Nginx already checks the Host header. 67 ''; 68 default = ""; 69 }; 70 }; 71 }; 72 default = { }; 73 description = '' 74 Configuration for the server. These are set as environment variables to the gunicorn/flask service. 75 76 See the documentation options in <https://open-web-calendar.quelltext.eu/host/configure/#configuring-the-server>. 77 ''; 78 }; 79 80 calendarSettings = mkOption { 81 type = types.submodule { 82 freeformType = calendarSettingsFormat.type; 83 options = { }; 84 }; 85 default = { }; 86 description = '' 87 Configure the default calendar. 88 89 See the documentation options in <https://open-web-calendar.quelltext.eu/host/configure/#configuring-the-default-calendar> and <https://github.com/niccokunzmann/open-web-calendar/blob/master/open_web_calendar/default_specification.yml>. 90 91 Individual calendar instances can be further configured outside this module, by specifying the `specification_url` parameter. 92 ''; 93 }; 94 95 }; 96 97 config = mkIf cfg.enable { 98 99 assertions = [ 100 { 101 assertion = !cfg.settings ? "PORT"; 102 message = '' 103 services.open-web-calendar.settings.PORT can't be set, as the service uses a unix socket. 104 ''; 105 } 106 ]; 107 108 systemd.sockets.open-web-calendar = { 109 before = [ "nginx.service" ]; 110 wantedBy = [ "sockets.target" ]; 111 socketConfig = { 112 ListenStream = "/run/open-web-calendar/socket"; 113 SocketUser = "open-web-calendar"; 114 SocketGroup = "open-web-calendar"; 115 SocketMode = "770"; 116 }; 117 }; 118 119 systemd.services.open-web-calendar = { 120 description = "Open Web Calendar"; 121 after = [ "network.target" ]; 122 environment.PYTHONPATH = "${pythonEnv}/${python.sitePackages}/"; 123 serviceConfig = { 124 Type = "notify"; 125 NotifyAccess = "all"; 126 ExecStart = '' 127 ${pythonEnv.pkgs.gunicorn}/bin/gunicorn \ 128 --name=open-web-calendar \ 129 --bind='unix:///run/open-web-calendar/socket' \ 130 open_web_calendar.app:app 131 ''; 132 EnvironmentFile = settingsFormat.generate "open-web-calendar.env" cfg.settings; 133 ExecReload = "kill -s HUP $MAINPID"; 134 KillMode = "mixed"; 135 PrivateTmp = true; 136 RuntimeDirectory = "open-web-calendar"; 137 User = "open-web-calendar"; 138 Group = "open-web-calendar"; 139 }; 140 }; 141 142 users.users.open-web-calendar = { 143 isSystemUser = true; 144 group = "open-web-calendar"; 145 }; 146 147 services.nginx = { 148 enable = true; 149 virtualHosts."${cfg.domain}" = { 150 forceSSL = mkDefault true; 151 enableACME = mkDefault true; 152 locations."/".proxyPass = "http://unix:///run/open-web-calendar/socket"; 153 }; 154 }; 155 156 users.groups.open-web-calendar.members = [ config.services.nginx.user ]; 157 158 }; 159 160 meta.maintainers = with lib.maintainers; [ erictapen ]; 161 162}