mirror of
https://github.com/NixOS/nixpkgs.git
synced 2026-08-27 02:34:53 +00:00
Since asserts do not tell you where they are coming from, this message at first appeared to be some sort of issue with system user accounts.
145 lines
4.6 KiB
Nix
145 lines
4.6 KiB
Nix
{
|
|
config,
|
|
lib,
|
|
pkgs,
|
|
...
|
|
}:
|
|
with lib;
|
|
let
|
|
cfg = config.services.anki-sync-server;
|
|
name = "anki-sync-server";
|
|
specEscape = replaceStrings [ "%" ] [ "%%" ];
|
|
usersWithIndexes = lists.imap1 (i: user: {
|
|
i = i;
|
|
user = user;
|
|
}) cfg.users;
|
|
usersWithIndexesFile = filter (x: x.user.passwordFile != null) usersWithIndexes;
|
|
usersWithIndexesNoFile = filter (
|
|
x: x.user.passwordFile == null && x.user.password != null
|
|
) usersWithIndexes;
|
|
anki-sync-server-run = pkgs.writeShellScript "anki-sync-server-run" ''
|
|
# When services.anki-sync-server.users.passwordFile is set,
|
|
# each password file is passed as a systemd credential, which is mounted in
|
|
# a file system exposed to the service. Here we read the passwords from
|
|
# the credential files to pass them as environment variables to the Anki
|
|
# sync server.
|
|
${concatMapStringsSep "\n" (x: ''
|
|
read -r pass < "''${CREDENTIALS_DIRECTORY}/"${escapeShellArg x.user.username}
|
|
export SYNC_USER${toString x.i}=${escapeShellArg x.user.username}:"$pass"
|
|
'') usersWithIndexesFile}
|
|
# For users where services.anki-sync-server.users.password isn't set,
|
|
# export passwords in environment variables in plaintext.
|
|
${concatMapStringsSep "\n" (
|
|
x:
|
|
"export SYNC_USER${toString x.i}=${escapeShellArg x.user.username}:${escapeShellArg x.user.password}"
|
|
) usersWithIndexesNoFile}
|
|
exec ${lib.getExe cfg.package}
|
|
'';
|
|
in
|
|
{
|
|
options.services.anki-sync-server = {
|
|
enable = mkEnableOption "anki-sync-server";
|
|
|
|
package = mkPackageOption pkgs "anki-sync-server" { };
|
|
|
|
address = mkOption {
|
|
type = types.str;
|
|
default = "::1";
|
|
description = ''
|
|
IP address anki-sync-server listens to.
|
|
Note host names are not resolved.
|
|
'';
|
|
};
|
|
|
|
port = mkOption {
|
|
type = types.port;
|
|
default = 27701;
|
|
description = "Port number anki-sync-server listens to.";
|
|
};
|
|
|
|
baseDirectory = mkOption {
|
|
type = types.str;
|
|
default = "%S/%N";
|
|
description = "Base directory where user(s) synchronized data will be stored.";
|
|
};
|
|
|
|
openFirewall = mkOption {
|
|
default = false;
|
|
type = types.bool;
|
|
description = "Whether to open the firewall for the specified port.";
|
|
};
|
|
|
|
users = mkOption {
|
|
type =
|
|
with types;
|
|
listOf (submodule {
|
|
options = {
|
|
username = mkOption {
|
|
type = str;
|
|
description = "User name accepted by anki-sync-server.";
|
|
};
|
|
password = mkOption {
|
|
type = nullOr str;
|
|
default = null;
|
|
description = ''
|
|
Password accepted by anki-sync-server for the associated username.
|
|
**WARNING**: This option is **not secure**. This password will
|
|
be stored in *plaintext* and will be visible to *all users*.
|
|
See {option}`services.anki-sync-server.users.passwordFile` for
|
|
a more secure option.
|
|
'';
|
|
};
|
|
passwordFile = mkOption {
|
|
type = nullOr path;
|
|
default = null;
|
|
description = ''
|
|
File containing the password accepted by anki-sync-server for
|
|
the associated username. Make sure to make readable only by
|
|
root.
|
|
'';
|
|
};
|
|
};
|
|
});
|
|
description = "List of user-password pairs to provide to the sync server.";
|
|
};
|
|
};
|
|
|
|
config = mkIf cfg.enable {
|
|
assertions = [
|
|
{
|
|
assertion = (builtins.length usersWithIndexesFile) + (builtins.length usersWithIndexesNoFile) > 0;
|
|
message = "At least one username-password pair must be set in services.anki-sync-server.users.";
|
|
}
|
|
];
|
|
networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.port ];
|
|
|
|
systemd.services.anki-sync-server = {
|
|
description = "anki-sync-server: Anki sync server built into Anki";
|
|
after = [ "network.target" ];
|
|
wantedBy = [ "multi-user.target" ];
|
|
path = [ cfg.package ];
|
|
environment = {
|
|
SYNC_BASE = cfg.baseDirectory;
|
|
SYNC_HOST = specEscape cfg.address;
|
|
SYNC_PORT = toString cfg.port;
|
|
};
|
|
|
|
serviceConfig = {
|
|
Type = "simple";
|
|
DynamicUser = true;
|
|
StateDirectory = name;
|
|
ExecStart = anki-sync-server-run;
|
|
Restart = "always";
|
|
LoadCredential = map (
|
|
x: "${specEscape x.user.username}:${specEscape (toString x.user.passwordFile)}"
|
|
) usersWithIndexesFile;
|
|
};
|
|
};
|
|
};
|
|
|
|
meta = {
|
|
maintainers = with maintainers; [ telotortium ];
|
|
doc = ./anki-sync-server.md;
|
|
};
|
|
}
|