1
0
Fork 0
mirror of https://github.com/NixOS/nixpkgs.git synced 2025-06-19 16:09:19 +03:00
nixpkgs/nixos/modules/services/misc/anki-sync-server.nix
Silvan Mosberger 374e6bcc40 treewide: Format all Nix files
Format all Nix files using the officially approved formatter,
making the CI check introduced in the previous commit succeed:

  nix-build ci -A fmt.check

This is the next step of the of the [implementation](https://github.com/NixOS/nixfmt/issues/153)
of the accepted [RFC 166](https://github.com/NixOS/rfcs/pull/166).

This commit will lead to merge conflicts for a number of PRs,
up to an estimated ~1100 (~33%) among the PRs with activity in the past 2
months, but that should be lower than what it would be without the previous
[partial treewide format](https://github.com/NixOS/nixpkgs/pull/322537).

Merge conflicts caused by this commit can now automatically be resolved while rebasing using the
[auto-rebase script](8616af08d9/maintainers/scripts/auto-rebase).

If you run into any problems regarding any of this, please reach out to the
[formatting team](https://nixos.org/community/teams/formatting/) by
pinging @NixOS/nix-formatting.
2025-04-01 20:10:43 +02:00

144 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.";
}
];
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;
};
}