nixpkgs/nixos/modules/services/networking/radicale.nix

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

205 lines
6.4 KiB
Nix
Raw Normal View History

{ config, lib, pkgs, ... }:
2014-05-27 20:27:31 +00:00
with lib;
let
cfg = config.services.radicale;
format = pkgs.formats.ini {
listToValue = concatMapStringsSep ", " (generators.mkValueStringDefault { });
};
2014-05-27 20:27:31 +00:00
pkg = if cfg.package == null then
pkgs.radicale
else
cfg.package;
confFile = if cfg.settings == { } then
pkgs.writeText "radicale.conf" cfg.config
else
format.generate "radicale.conf" cfg.settings;
rightsFile = format.generate "radicale.rights" cfg.rights;
2021-05-03 16:52:55 +00:00
bindLocalhost = cfg.settings != { } && !hasAttrByPath [ "server" "hosts" ] cfg.settings;
in {
options.services.radicale = {
enable = mkEnableOption "Radicale CalDAV and CardDAV server";
package = mkOption {
description = "Radicale package to use.";
# Default cannot be pkgs.radicale because non-null values suppress
# warnings about incompatible configuration and storage formats.
type = with types; nullOr package // { inherit (package) description; };
default = null;
defaultText = literalExpression "pkgs.radicale";
};
2014-05-27 20:27:31 +00:00
config = mkOption {
type = types.str;
default = "";
2014-05-27 20:27:31 +00:00
description = ''
Radicale configuration, this will set the service
configuration file.
This option is mutually exclusive with {option}`settings`.
This option is deprecated. Use {option}`settings` instead.
'';
};
settings = mkOption {
type = format.type;
default = { };
description = ''
Configuration for Radicale. See
<https://radicale.org/3.0.html#documentation/configuration>.
This option is mutually exclusive with {option}`config`.
'';
example = literalExpression ''
server = {
hosts = [ "0.0.0.0:5232" "[::]:5232" ];
};
auth = {
type = "htpasswd";
htpasswd_filename = "/etc/radicale/users";
htpasswd_encryption = "bcrypt";
};
storage = {
filesystem_folder = "/var/lib/radicale/collections";
};
2014-05-27 20:27:31 +00:00
'';
};
rights = mkOption {
type = format.type;
2014-05-27 20:27:31 +00:00
description = ''
Configuration for Radicale's rights file. See
<https://radicale.org/3.0.html#documentation/authentication-and-rights>.
This option only works in conjunction with {option}`settings`.
Setting this will also set {option}`settings.rights.type` and
2022-12-18 00:31:14 +00:00
{option}`settings.rights.file` to appropriate values.
'';
default = { };
example = literalExpression ''
root = {
user = ".+";
collection = "";
permissions = "R";
};
principal = {
user = ".+";
collection = "{user}";
permissions = "RW";
};
calendars = {
user = ".+";
collection = "{user}/[^/]+";
permissions = "rw";
};
2014-05-27 20:27:31 +00:00
'';
};
extraArgs = mkOption {
type = types.listOf types.str;
default = [];
description = "Extra arguments passed to the Radicale daemon.";
};
2014-05-27 20:27:31 +00:00
};
config = mkIf cfg.enable {
assertions = [
{
assertion = cfg.settings == { } || cfg.config == "";
message = ''
The options services.radicale.config and services.radicale.settings
are mutually exclusive.
'';
}
];
warnings = optional (cfg.package == null && versionOlder config.system.stateVersion "17.09") ''
The configuration and storage formats of your existing Radicale
installation might be incompatible with the newest version.
For upgrade instructions see
https://radicale.org/2.1.html#documentation/migration-from-1xx-to-2xx.
Set services.radicale.package to suppress this warning.
'' ++ optional (cfg.package == null && versionOlder config.system.stateVersion "20.09") ''
The configuration format of your existing Radicale installation might be
incompatible with the newest version. For upgrade instructions see
https://github.com/Kozea/Radicale/blob/3.0.6/NEWS.md#upgrade-checklist.
Set services.radicale.package to suppress this warning.
'' ++ optional (cfg.config != "") ''
The option services.radicale.config is deprecated.
Use services.radicale.settings instead.
'';
services.radicale.settings.rights = mkIf (cfg.rights != { }) {
type = "from_file";
file = toString rightsFile;
};
environment.systemPackages = [ pkg ];
2014-05-27 20:27:31 +00:00
users.users.radicale = {
isSystemUser = true;
group = "radicale";
};
users.groups.radicale = {};
2016-01-06 06:50:18 +00:00
systemd.services.radicale = {
2014-05-27 20:27:31 +00:00
description = "A Simple Calendar and Contact Server";
after = [ "network.target" ];
requires = [ "network.target" ];
2016-01-06 06:50:18 +00:00
wantedBy = [ "multi-user.target" ];
serviceConfig = {
ExecStart = concatStringsSep " " ([
"${pkg}/bin/radicale" "-C" confFile
] ++ (
map escapeShellArg cfg.extraArgs
));
User = "radicale";
Group = "radicale";
2021-05-03 16:52:55 +00:00
StateDirectory = "radicale/collections";
StateDirectoryMode = "0750";
# Hardening
CapabilityBoundingSet = [ "" ];
DeviceAllow = [ "/dev/stdin" "/dev/urandom" ];
2021-05-03 16:52:55 +00:00
DevicePolicy = "strict";
IPAddressAllow = mkIf bindLocalhost "localhost";
IPAddressDeny = mkIf bindLocalhost "any";
LockPersonality = true;
MemoryDenyWriteExecute = true;
NoNewPrivileges = true;
PrivateDevices = true;
PrivateTmp = true;
PrivateUsers = true;
ProcSubset = "pid";
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectProc = "invisible";
ProtectSystem = "strict";
ReadWritePaths = lib.optional
(hasAttrByPath [ "storage" "filesystem_folder" ] cfg.settings)
cfg.settings.storage.filesystem_folder;
RemoveIPC = true;
RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SystemCallArchitectures = "native";
SystemCallFilter = [ "@system-service" "~@privileged" "~@resources" ];
UMask = "0027";
WorkingDirectory = "/var/lib/radicale";
};
2014-05-27 20:27:31 +00:00
};
};
2017-03-20 16:13:27 +00:00
meta.maintainers = with lib.maintainers; [ dotlambda ];
2014-05-27 20:27:31 +00:00
}