style: alejandra $(fd -e nix)

This commit is contained in:
Kat Inskip 2024-03-13 15:08:42 -07:00
parent 97d9eecd3c
commit e63304937d
Signed by: kat
GPG key ID: 465E64DECEA8CF0F
91 changed files with 1422 additions and 1102 deletions

1
.gitignore vendored
View file

@ -6,3 +6,4 @@
.terraform .terraform
.DS_Store .DS_Store
.envrc.conf .envrc.conf
.idea

View file

@ -45,7 +45,7 @@ in {
cron = "0 0 * * *"; cron = "0 0 * * *";
} }
]; ];
workflow_dispatch = { }; workflow_dispatch = {};
}; };
}; };
@ -65,7 +65,7 @@ in {
displayName = "flake update build"; displayName = "flake update build";
environment = ["CACHIX_SIGNING_KEY" "GITHUB_REF"]; environment = ["CACHIX_SIGNING_KEY" "GITHUB_REF"];
command = let command = let
filteredHosts = [ "hakurei" "reimu" "aya" "tei" "litterbox" "mediabox" ]; filteredHosts = ["hakurei" "reimu" "aya" "tei" "litterbox" "mediabox"];
gcBetweenHosts = false; gcBetweenHosts = false;
nodeBuildString = concatMapStringsSep " && " (node: "nix build --show-trace -Lf . nixosConfigurations.${node}.config.system.build.toplevel -o result-${node}" + optionalString gcBetweenHosts " && nix-collect-garbage -d") filteredHosts; nodeBuildString = concatMapStringsSep " && " (node: "nix build --show-trace -Lf . nixosConfigurations.${node}.config.system.build.toplevel -o result-${node}" + optionalString gcBetweenHosts " && nix-collect-garbage -d") filteredHosts;
hostPath = builtins.getEnv "PATH"; hostPath = builtins.getEnv "PATH";

View file

@ -12,26 +12,28 @@
(hasSuffix ".adoc" path || baseNameOf path == "docinfo.html") (hasSuffix ".adoc" path || baseNameOf path == "docinfo.html")
|| type == "directory"; || type == "directory";
}; };
in stdenvNoCC.mkDerivation { in
pname = "genso-docs"; stdenvNoCC.mkDerivation {
version = "dev"; pname = "genso-docs";
inherit src; version = "dev";
inherit src;
ASCIIDOCTOR_OPTS = [ ASCIIDOCTOR_OPTS = [
"-a" "docinfo=shared" "-a"
]; "docinfo=shared"
];
nativeBuildInputs = [ asciidoctor ]; nativeBuildInputs = [asciidoctor];
passAsFile = [ "buildCommand" ]; passAsFile = ["buildCommand"];
buildCommand = '' buildCommand = ''
install -d "$out" install -d "$out"
ASCIIDOCTOR_SRCS=( ASCIIDOCTOR_SRCS=(
$(find "$src" -type f -name '*.adoc' -not -path "$src/inc/*") $(find "$src" -type f -name '*.adoc' -not -path "$src/inc/*")
) )
asciidoctor \ asciidoctor \
$ASCIIDOCTOR_OPTS \ $ASCIIDOCTOR_OPTS \
-a docinfodir="$src/" \ -a docinfodir="$src/" \
-a inc="$src/_inc/" \ -a inc="$src/_inc/" \
-b html -R "$src" -D "$out" "''${ASCIIDOCTOR_SRCS[@]}" -b html -R "$src" -D "$out" "''${ASCIIDOCTOR_SRCS[@]}"
''; '';
} }

View file

@ -10,16 +10,15 @@
templateUsers = filterAttrs (_: userIs "peeps") templateSystem.config.users.users; templateUsers = filterAttrs (_: userIs "peeps") templateSystem.config.users.users;
mkNodeUsers = users: let mkNodeUsers = users: let
nodeUsers = mapAttrsToList (_: mkNodeUser) templateUsers; nodeUsers = mapAttrsToList (_: mkNodeUser) templateUsers;
in sortOn (user: user.uid) nodeUsers; in
sortOn (user: user.uid) nodeUsers;
mkNodeUser = user: { mkNodeUser = user: {
inherit (user) name uid; inherit (user) name uid;
authorizedKeys = user.openssh.authorizedKeys.keys; authorizedKeys = user.openssh.authorizedKeys.keys;
}; };
mkNode = { mkNode = {name}: {
name,
}: {
users = mkNodeUsers templateUsers; users = mkNodeUsers templateUsers;
}; };
in { in {
reisen = mkNode { name = "reisen"; }; reisen = mkNode {name = "reisen";};
} }

View file

@ -11,7 +11,7 @@
inherit (config.services) tailscale; inherit (config.services) tailscale;
inherit (config) networking; inherit (config) networking;
cfg = config.networking.access; cfg = config.networking.access;
cidrModule = { config, ... }: { cidrModule = {config, ...}: {
options = with lib.types; { options = with lib.types; {
all = mkOption { all = mkOption {
type = listOf str; type = listOf str;
@ -19,11 +19,11 @@
}; };
v4 = mkOption { v4 = mkOption {
type = listOf str; type = listOf str;
default = [ ]; default = [];
}; };
v6 = mkOption { v6 = mkOption {
type = listOf str; type = listOf str;
default = [ ]; default = [];
}; };
}; };
config.all = mkOptionDefault ( config.all = mkOptionDefault (
@ -35,12 +35,14 @@ in {
options.networking.access = with lib.types; { options.networking.access = with lib.types; {
cidrForNetwork = mkOption { cidrForNetwork = mkOption {
type = attrsOf (submodule cidrModule); type = attrsOf (submodule cidrModule);
default = { }; default = {};
}; };
localaddrs = { localaddrs = {
enable = mkEnableOption "localaddrs" // { enable =
default = networking.firewall.interfaces.local.nftables.enable; mkEnableOption "localaddrs"
}; // {
default = networking.firewall.interfaces.local.nftables.enable;
};
stateDir = mkOption { stateDir = mkOption {
type = path; type = path;
default = "/var/lib/localaddrs"; default = "/var/lib/localaddrs";
@ -87,10 +89,11 @@ in {
}; };
localaddrs = { localaddrs = {
nftablesInclude = mkBefore ('' nftablesInclude = mkBefore (''
define localrange6 = 2001:568::/29 define localrange6 = 2001:568::/29
'' + optionalString cfg.localaddrs.enable '' ''
include "${cfg.localaddrs.stateDir}/*.nft" + optionalString cfg.localaddrs.enable ''
''); include "${cfg.localaddrs.stateDir}/*.nft"
'');
reloadScript = let reloadScript = let
localaddrs-reload = pkgs.writeShellScript "localaddrs-reload" '' localaddrs-reload = pkgs.writeShellScript "localaddrs-reload" ''
${config.systemd.package}/bin/systemctl reload localaddrs 2>/dev/null || ${config.systemd.package}/bin/systemctl reload localaddrs 2>/dev/null ||
@ -101,7 +104,7 @@ in {
}; };
moduleArgAttrs = { moduleArgAttrs = {
inherit (cfg) cidrForNetwork localaddrs; inherit (cfg) cidrForNetwork localaddrs;
mkSnakeOil = pkgs.callPackage ../../packages/snakeoil.nix { }; mkSnakeOil = pkgs.callPackage ../../packages/snakeoil.nix {};
}; };
}; };
@ -111,7 +114,8 @@ in {
interfaces.local = { interfaces.local = {
nftables.conditions = [ nftables.conditions = [
"ip saddr { ${concatStringsSep ", " cfg.cidrForNetwork.local.v4} }" "ip saddr { ${concatStringsSep ", " cfg.cidrForNetwork.local.v4} }"
(mkIf networking.enableIPv6 (
mkIf networking.enableIPv6
"ip6 saddr { $localrange6, ${concatStringsSep ", " cfg.cidrForNetwork.local.v6} }" "ip6 saddr { $localrange6, ${concatStringsSep ", " cfg.cidrForNetwork.local.v6} }"
) )
]; ];
@ -169,12 +173,12 @@ in {
in { in {
localaddrs = mkIf cfg.localaddrs.enable { localaddrs = mkIf cfg.localaddrs.enable {
unitConfig = { unitConfig = {
After = [ "network-online.target" ]; After = ["network-online.target"];
}; };
serviceConfig = rec { serviceConfig = rec {
StateDirectory = "localaddrs"; StateDirectory = "localaddrs";
ExecStart = mkMerge [ ExecStart = mkMerge [
[ "${localaddrs}" ] ["${localaddrs}"]
(mkIf networking.nftables.enable (mkAfter [ (mkIf networking.nftables.enable (mkAfter [
"${localaddrs-nftables}" "${localaddrs-nftables}"
])) ]))
@ -188,7 +192,7 @@ in {
}; };
}; };
nftables = mkIf (networking.nftables.enable && cfg.localaddrs.enable) rec { nftables = mkIf (networking.nftables.enable && cfg.localaddrs.enable) rec {
wants = [ "localaddrs.service" ]; wants = ["localaddrs.service"];
serviceConfig = { serviceConfig = {
ExecReload = mkBefore [ ExecReload = mkBefore [
"+${cfg.localaddrs.reloadScript}" "+${cfg.localaddrs.reloadScript}"
@ -196,7 +200,7 @@ in {
}; };
}; };
nginx = mkIf (config.services.nginx.enable && cfg.localaddrs.enable) rec { nginx = mkIf (config.services.nginx.enable && cfg.localaddrs.enable) rec {
wants = [ "localaddrs.service" ]; wants = ["localaddrs.service"];
after = wants; after = wants;
serviceConfig = { serviceConfig = {
ExecReload = mkBefore [ ExecReload = mkBefore [

View file

@ -1,64 +1,79 @@
{ pkgs, config, utils, lib, ... }: let {
pkgs,
config,
utils,
lib,
...
}: let
inherit (lib.attrsets) mapAttrsToList mapAttrs' nameValuePair filterAttrsRecursive; inherit (lib.attrsets) mapAttrsToList mapAttrs' nameValuePair filterAttrsRecursive;
inherit (lib.lists) singleton; inherit (lib.lists) singleton;
inherit (lib.modules) mkIf mkMerge mkForce; inherit (lib.modules) mkIf mkMerge mkForce;
inherit (lib.options) mkOption mkEnableOption; inherit (lib.options) mkOption mkEnableOption;
cfg = config.services.cloudflared; cfg = config.services.cloudflared;
settingsFormat = pkgs.formats.json { }; settingsFormat = pkgs.formats.json {};
in { in {
options.services.cloudflared = with lib.types; { options.services.cloudflared = with lib.types; {
tunnels = let tunnels = let
tunnelModule = { config, ... }: { tunnelModule = {config, ...}: {
options = { options = {
extraTunnel = { extraTunnel = {
enable = mkEnableOption "extra tunnels" // { enable =
default = config.extraTunnel.ingress != { }; mkEnableOption "extra tunnels"
}; // {
default = config.extraTunnel.ingress != {};
};
ingress = mkOption { ingress = mkOption {
inherit (settingsFormat) type; inherit (settingsFormat) type;
default = { }; default = {};
}; };
}; };
}; };
}; };
in mkOption { in
type = attrsOf (submodule tunnelModule); mkOption {
}; type = attrsOf (submodule tunnelModule);
};
}; };
config.systemd.services = let config.systemd.services = let
filterConfig = filterAttrsRecursive (_: v: ! builtins.elem v [ null [ ] { } ]); filterConfig = filterAttrsRecursive (_: v: ! builtins.elem v [null [] {}]);
mapIngress = hostname: ingress: { mapIngress = hostname: ingress:
inherit hostname; {
} // filterConfig (filterConfig ingress); inherit hostname;
in mkIf cfg.enable (mapAttrs' (uuid: tunnel: let }
RuntimeDirectory = "cloudflared-tunnel-${uuid}"; // filterConfig (filterConfig ingress);
configPath = "/run/${RuntimeDirectory}/config.yml"; in
settings = { mkIf cfg.enable (mapAttrs' (uuid: tunnel: let
tunnel = uuid; RuntimeDirectory = "cloudflared-tunnel-${uuid}";
credentials-file = tunnel.credentialsFile; configPath = "/run/${RuntimeDirectory}/config.yml";
ingress = mapAttrsToList mapIngress tunnel.ingress settings = {
++ mapAttrsToList mapIngress tunnel.extraTunnel.ingress tunnel = uuid;
++ singleton { service = tunnel.default; }; credentials-file = tunnel.credentialsFile;
}; ingress =
in nameValuePair "cloudflared-tunnel-${uuid}" (mkMerge [ mapAttrsToList mapIngress tunnel.ingress
{ ++ mapAttrsToList mapIngress tunnel.extraTunnel.ingress
after = mkIf config.services.tailscale.enable [ "tailscale-autoconnect.service" ]; ++ singleton {service = tunnel.default;};
serviceConfig = {
RestartSec = 10;
}; };
} in
(mkIf tunnel.extraTunnel.enable { nameValuePair "cloudflared-tunnel-${uuid}" (mkMerge [
serviceConfig = { {
inherit RuntimeDirectory; after = mkIf config.services.tailscale.enable ["tailscale-autoconnect.service"];
ExecStart = mkForce [ serviceConfig = {
"${cfg.package}/bin/cloudflared tunnel --config=${configPath} --no-autoupdate run" RestartSec = 10;
]; };
ExecStartPre = [ }
(pkgs.writeShellScript "cloudflared-tunnel-${uuid}-prepare" '' (mkIf tunnel.extraTunnel.enable {
${utils.genJqSecretsReplacementSnippet settings configPath} serviceConfig = {
'') inherit RuntimeDirectory;
]; ExecStart = mkForce [
}; "${cfg.package}/bin/cloudflared tunnel --config=${configPath} --no-autoupdate run"
}) ];
])) cfg.tunnels); ExecStartPre = [
(pkgs.writeShellScript "cloudflared-tunnel-${uuid}-prepare" ''
${utils.genJqSecretsReplacementSnippet settings configPath}
'')
];
};
})
]))
cfg.tunnels);
} }

View file

@ -11,7 +11,7 @@
cfg = config.services.github-runners; cfg = config.services.github-runners;
nixosConfig = config; nixosConfig = config;
enabledRunners = filterAttrs (_: runner: runner.enable) cfg; enabledRunners = filterAttrs (_: runner: runner.enable) cfg;
runnerModule = { config, ... }: { runnerModule = {config, ...}: {
options = with lib.types; { options = with lib.types; {
networkNamespace.name = mkOption { networkNamespace.name = mkOption {
type = nullOr str; type = nullOr str;
@ -19,7 +19,7 @@
}; };
serviceSettings = mkOption { serviceSettings = mkOption {
type = unmerged.type; type = unmerged.type;
default = { }; default = {};
}; };
}; };
config = { config = {
@ -58,8 +58,10 @@ in {
}; };
}; };
config = { config = {
systemd.services = mapAttrs' (name: runner: nameValuePair "github-runner-${name}" ( systemd.services = mapAttrs' (name: runner:
unmerged.merge runner.serviceSettings nameValuePair "github-runner-${name}" (
)) enabledRunners; unmerged.merge runner.serviceSettings
))
enabledRunners;
}; };
} }

View file

@ -17,29 +17,43 @@ in {
default = config.networking.domain; default = config.networking.domain;
}; };
homekit = { homekit = {
enable = mkEnableOption "homekit" // { enable =
default = cfg.config.homekit or [ ] != [ ]; mkEnableOption "homekit"
// {
default = cfg.config.homekit or [] != [];
};
openFirewall =
mkEnableOption "homekit ports"
// {
default = cfg.openFirewall;
};
};
googleAssistant.enable =
mkEnableOption "Google Assistant"
// {
default = cfg.config.google_assistant or {} != {};
}; };
openFirewall = mkEnableOption "homekit ports" // { androidTv.enable =
default = cfg.openFirewall; mkEnableOption "Android TV"
// {
default = elem "androidtv" cfg.extraComponents;
};
brother.enable =
mkEnableOption "brother"
// {
default = elem "brother" cfg.extraComponents;
}; };
};
googleAssistant.enable = mkEnableOption "Google Assistant" // {
default = cfg.config.google_assistant or { } != { };
};
androidTv.enable = mkEnableOption "Android TV" // {
default = elem "androidtv" cfg.extraComponents;
};
brother.enable = mkEnableOption "brother" // {
default = elem "brother" cfg.extraComponents;
};
cast = { cast = {
enable = mkEnableOption "Chromecast" // { enable =
default = elem "cast" cfg.extraComponents; mkEnableOption "Chromecast"
}; // {
openFirewall = mkEnableOption "Chromecast ports" // { default = elem "cast" cfg.extraComponents;
default = cfg.openFirewall; };
}; openFirewall =
mkEnableOption "Chromecast ports"
// {
default = cfg.openFirewall;
};
}; };
finalPackage = mkOption { finalPackage = mkOption {
type = types.path; type = types.path;
@ -50,7 +64,7 @@ in {
config = { config = {
networking.firewall = let networking.firewall = let
homekitTcp = mkIf cfg.homekit.enable ( homekitTcp = mkIf cfg.homekit.enable (
map ({ port, ... }: port) cfg.config.homekit or [ ] map ({port, ...}: port) cfg.config.homekit or []
); );
castUdpRanges = mkIf cfg.cast.enable [ castUdpRanges = mkIf cfg.cast.enable [
@ -59,21 +73,23 @@ in {
to = 60999; to = 60999;
} }
]; ];
in mkIf cfg.enable { in
interfaces.local = { mkIf cfg.enable {
allowedTCPPorts = mkIf (!cfg.homekit.openFirewall) homekitTcp; interfaces.local = {
allowedUDPPortRanges = mkIf (!cfg.cast.openFirewall) castUdpRanges; allowedTCPPorts = mkIf (!cfg.homekit.openFirewall) homekitTcp;
allowedUDPPortRanges = mkIf (!cfg.cast.openFirewall) castUdpRanges;
};
allowedTCPPorts = mkIf cfg.homekit.openFirewall homekitTcp;
allowedUDPPortRanges = mkIf cfg.cast.openFirewall castUdpRanges;
}; };
allowedTCPPorts = mkIf cfg.homekit.openFirewall homekitTcp;
allowedUDPPortRanges = mkIf cfg.cast.openFirewall castUdpRanges;
};
# MDNS # MDNS
services.avahi = mkIf (cfg.enable && cfg.homekit.enable) { services.avahi = mkIf (cfg.enable && cfg.homekit.enable) {
enable = mkDefault true; enable = mkDefault true;
publish.enable = let publish.enable = let
homekitNames = map (homekit: toLower homekit.name) cfg.config.homekit or [ ]; homekitNames = map (homekit: toLower homekit.name) cfg.config.homekit or [];
in mkIf (elem config.networking.hostName homekitNames) false; in
mkIf (elem config.networking.hostName homekitNames) false;
}; };
systemd.services.home-assistant = mkIf (cfg.enable && cfg.mutableUiConfig) { systemd.services.home-assistant = mkIf (cfg.enable && cfg.mutableUiConfig) {
@ -101,12 +117,13 @@ in {
use_x_forwarded_for = "true"; use_x_forwarded_for = "true";
trusted_proxies = let trusted_proxies = let
inherit (config.networking.access) cidrForNetwork; inherit (config.networking.access) cidrForNetwork;
in cidrForNetwork.loopback.all in
++ cidrForNetwork.local.all cidrForNetwork.loopback.all
++ optionals config.services.tailscale.enable cidrForNetwork.tail.all ++ cidrForNetwork.local.all
++ [ ++ optionals config.services.tailscale.enable cidrForNetwork.tail.all
"200::/7" ++ [
]; "200::/7"
];
}; };
recorder = { recorder = {
db_url = mkIf config.services.postgresql.enable (mkDefault "postgresql://@/hass"); db_url = mkIf config.services.postgresql.enable (mkDefault "postgresql://@/hass");
@ -157,61 +174,75 @@ in {
package = let package = let
inherit (cfg.package) python; inherit (cfg.package) python;
# https://github.com/pysnmp/pysnmp/issues/51 # https://github.com/pysnmp/pysnmp/issues/51
needsPyasn1pin = if lib.versionOlder python.pkgs.pysnmplib.version "6.0" needsPyasn1pin =
if lib.versionOlder python.pkgs.pysnmplib.version "6.0"
then true then true
else lib.warn "pyasn1 pin likely no longer needed" false; else lib.warn "pyasn1 pin likely no longer needed" false;
pyasn1prefix = "${python.pkgs.pysnmp-pyasn1}/${python.sitePackages}"; pyasn1prefix = "${python.pkgs.pysnmp-pyasn1}/${python.sitePackages}";
home-assistant = pkgs.home-assistant.override { home-assistant = pkgs.home-assistant.override {
packageOverrides = self: super: { packageOverrides = self: super: {
brother = super.brother.overridePythonAttrs (old: { brother = super.brother.overridePythonAttrs (old: {
dontCheckRuntimeDeps = if old.dontCheckRuntimeDeps or false dontCheckRuntimeDeps =
if old.dontCheckRuntimeDeps or false
then lib.warn "brother override no longer needed" true then lib.warn "brother override no longer needed" true
else true; else true;
}); });
mpd2 = super.mpd2.overridePythonAttrs (old: { mpd2 = super.mpd2.overridePythonAttrs (old: {
patches = old.patches or [ ] ++ [ patches =
../../packages/mpd2-skip-flaky-test.patch old.patches
]; or []
disabledTests = unique (old.disabledTests or [ ] ++ [ ++ [
"test_idle_timeout" ../../packages/mpd2-skip-flaky-test.patch
]); ];
disabledTests = unique (old.disabledTests
or []
++ [
"test_idle_timeout"
]);
}); });
}; };
}; };
in home-assistant.overrideAttrs (old: { in
makeWrapperArgs = old.makeWrapperArgs ++ optional (cfg.brother.enable && needsPyasn1pin) "--prefix PYTHONPATH : ${pyasn1prefix}"; home-assistant.overrideAttrs (old: {
disabledTests = unique (old.disabledTests or [ ] ++ [ makeWrapperArgs = old.makeWrapperArgs ++ optional (cfg.brother.enable && needsPyasn1pin) "--prefix PYTHONPATH : ${pyasn1prefix}";
"test_check_config" disabledTests = unique (old.disabledTests
]); or []
}); ++ [
"test_check_config"
]);
});
finalPackage = let finalPackage = let
inherit (lib.strings) hasSuffix removeSuffix splitString; inherit (lib.strings) hasSuffix removeSuffix splitString;
inherit (lib.lists) head; inherit (lib.lists) head;
inherit (lib.attrsets) attrNames filterAttrs; inherit (lib.attrsets) attrNames filterAttrs;
inherit (config.systemd.services.home-assistant.serviceConfig) ExecStart; inherit (config.systemd.services.home-assistant.serviceConfig) ExecStart;
isHassDrv = drv: context: hasSuffix "-${cfg.package.name}.drv" drv && context.outputs or [ ] == [ "out" ]; isHassDrv = drv: context: hasSuffix "-${cfg.package.name}.drv" drv && context.outputs or [] == ["out"];
drvs = filterAttrs isHassDrv (builtins.getContext ExecStart); drvs = filterAttrs isHassDrv (builtins.getContext ExecStart);
isImpure = builtins ? currentSystem; isImpure = builtins ? currentSystem;
in mkIf cfg.enable (mkOptionDefault ( in
if isImpure then import (head (attrNames drvs)) mkIf cfg.enable (mkOptionDefault (
else removeSuffix "/bin/hass" (head (splitString " " ExecStart)) if isImpure
)); then import (head (attrNames drvs))
extraPackages = python3Packages: with python3Packages; mkMerge [ else removeSuffix "/bin/hass" (head (splitString " " ExecStart))
[ ));
psycopg2 extraPackages = python3Packages:
securetar with python3Packages;
getmac # for upnp integration mkMerge [
python-otbr-api [
(aiogithubapi.overrideAttrs (_: {doInstallCheck = false;})) psycopg2
] securetar
(mkIf cfg.homekit.enable [ getmac # for upnp integration
aiohomekit python-otbr-api
]) (aiogithubapi.overrideAttrs (_: {doInstallCheck = false;}))
(mkIf cfg.androidTv.enable [ ]
adb-shell (mkIf cfg.homekit.enable [
androidtvremote2 aiohomekit
]) ])
]; (mkIf cfg.androidTv.enable [
adb-shell
androidtvremote2
])
];
extraComponents = mkMerge [ extraComponents = mkMerge [
[ [
"automation" "automation"
@ -232,8 +263,8 @@ in {
"google_assistant" "google_assistant"
"google_cloud" "google_cloud"
]) ])
(map ({ platform, ... }: platform) cfg.config.media_player or [ ]) (map ({platform, ...}: platform) cfg.config.media_player or [])
(map ({ platform, ... }: platform) cfg.config.tts or [ ]) (map ({platform, ...}: platform) cfg.config.tts or [])
]; ];
}; };
} }

View file

@ -1,7 +1,4 @@
{ {lib, ...}: let
lib,
...
}: let
inherit (lib.options) mkOption; inherit (lib.options) mkOption;
in { in {
options.services.jackett = with lib.types; { options.services.jackett = with lib.types; {

View file

@ -60,13 +60,14 @@ in {
services.kanidm = { services.kanidm = {
server.unencrypted = { server.unencrypted = {
domain = mkBefore [ cfg.server.frontend.domain ]; domain = mkBefore [cfg.server.frontend.domain];
package = let package = let
cert = mkSnakeOil { cert = mkSnakeOil {
name = "kanidm-cert"; name = "kanidm-cert";
inherit (cfg.server.unencrypted) domain; inherit (cfg.server.unencrypted) domain;
}; };
in mkOptionDefault cert; in
mkOptionDefault cert;
}; };
clientSettings = mkIf cfg.enableServer { clientSettings = mkIf cfg.enableServer {
uri = mkDefault cfg.serverSettings.origin; uri = mkDefault cfg.serverSettings.origin;

View file

@ -1,7 +1,4 @@
{ {lib, ...}: let
lib,
...
}: let
inherit (lib.options) mkOption; inherit (lib.options) mkOption;
in { in {
options.services.lidarr = with lib.types; { options.services.lidarr = with lib.types; {

View file

@ -8,7 +8,7 @@
inherit (lib.modules) mkIf mkMerge mkDefault mkOptionDefault; inherit (lib.modules) mkIf mkMerge mkDefault mkOptionDefault;
inherit (lib.lists) singleton; inherit (lib.lists) singleton;
cfg = config.services.mediatomb; cfg = config.services.mediatomb;
mediaDirModule = { config, ... }: { mediaDirModule = {config, ...}: {
options = with lib.types; { options = with lib.types; {
mountPoint = mkOption { mountPoint = mkOption {
type = nullOr str; type = nullOr str;
@ -26,16 +26,23 @@
paths = let paths = let
paths = map (path: "${config.path}/${path}") config.subdirectories; paths = map (path: "${config.path}/${path}") config.subdirectories;
path = singleton config.path; path = singleton config.path;
in mkOptionDefault (if config.subdirectories != null then paths else path); in
mkOptionDefault (
if config.subdirectories != null
then paths
else path
);
recursive = mkDefault true; recursive = mkDefault true;
hidden-files = mkDefault false; hidden-files = mkDefault false;
}; };
}; };
in { in {
options.services.mediatomb = with lib.types; { options.services.mediatomb = with lib.types; {
confine = mkEnableOption "containment" // { confine =
default = true; mkEnableOption "containment"
}; // {
default = true;
};
mediaDirectories = mkOption { mediaDirectories = mkOption {
type = listOf (submodule mediaDirModule); type = listOf (submodule mediaDirModule);
}; };
@ -47,9 +54,13 @@ in {
}; };
config.systemd.services.mediatomb = mkIf cfg.enable { config.systemd.services.mediatomb = mkIf cfg.enable {
confinement.enable = mkIf cfg.confine (mkDefault true); confinement.enable = mkIf cfg.confine (mkDefault true);
bindsTo = map (dir: mkIf (dir.mountPoint != null) bindsTo =
"${utils.escapeSystemdPath dir.mountPoint}.mount" map (
) cfg.mediaDirectories; dir:
mkIf (dir.mountPoint != null)
"${utils.escapeSystemdPath dir.mountPoint}.mount"
)
cfg.mediaDirectories;
unitConfig.RequiresMountsFor = mkMerge ( unitConfig.RequiresMountsFor = mkMerge (
map (dir: dir.paths) cfg.mediaDirectories map (dir: dir.paths) cfg.mediaDirectories
); );

View file

@ -8,18 +8,19 @@
in { in {
options.services.mosquitto = with lib.types; { options.services.mosquitto = with lib.types; {
listeners = let listeners = let
listenerModule = { ... }: { listenerModule = {...}: {
options = { options = {
openFirewall = mkEnableOption "firewall"; openFirewall = mkEnableOption "firewall";
}; };
}; };
in mkOption { in
type = listOf (submodule listenerModule); mkOption {
}; type = listOf (submodule listenerModule);
};
}; };
config = { config = {
networking.firewall.allowedTCPPorts = mkIf cfg.enable (mkMerge ( networking.firewall.allowedTCPPorts = mkIf cfg.enable (mkMerge (
map (listener: mkIf listener.openFirewall [ listener.port ]) cfg.listeners map (listener: mkIf listener.openFirewall [listener.port]) cfg.listeners
)); ));
}; };
} }

View file

@ -19,7 +19,12 @@
enabledNamespaces = filter (ns: ns.enable) (attrValues networking.namespaces); enabledNamespaces = filter (ns: ns.enable) (attrValues networking.namespaces);
ip = "${pkgs.iproute2}/bin/ip"; ip = "${pkgs.iproute2}/bin/ip";
ip-n = namespace: "${ip} -n ${escapeShellArg namespace.name}"; ip-n = namespace: "${ip} -n ${escapeShellArg namespace.name}";
namespaceInterfaceModule = { config, namespace, name, ... }: { namespaceInterfaceModule = {
config,
namespace,
name,
...
}: {
options = with lib.types; { options = with lib.types; {
name = mkOption { name = mkOption {
type = str; type = str;
@ -41,8 +46,8 @@
}; };
config = { config = {
serviceSettings = rec { serviceSettings = rec {
bindsTo = [ "${namespace.unitName}.service" ]; bindsTo = ["${namespace.unitName}.service"];
partOf = [ "${namespace.unitName}.target" ]; partOf = ["${namespace.unitName}.target"];
after = bindsTo; after = bindsTo;
stopIfChanged = false; stopIfChanged = false;
restartIfChanged = false; restartIfChanged = false;
@ -63,7 +68,11 @@
}; };
}; };
}; };
groupModule = { config, namespace, ... }: { groupModule = {
config,
namespace,
...
}: {
options = with lib.types; { options = with lib.types; {
id = mkOption { id = mkOption {
type = int; type = int;
@ -78,8 +87,8 @@
}; };
config = { config = {
serviceSettings = rec { serviceSettings = rec {
bindsTo = [ "${namespace.unitName}.service" ]; bindsTo = ["${namespace.unitName}.service"];
partOf = [ "${namespace.unitName}.target" ]; partOf = ["${namespace.unitName}.target"];
after = bindsTo; after = bindsTo;
stopIfChanged = false; stopIfChanged = false;
restartIfChanged = false; restartIfChanged = false;
@ -100,17 +109,23 @@
}; };
}; };
}; };
namespaceModule = { config, name, ... }: let namespaceModule = {
config,
name,
...
}: let
linkGroupServices = optional (config.linkGroup != null) "${config.linkGroup.serviceName}.service"; linkGroupServices = optional (config.linkGroup != null) "${config.linkGroup.serviceName}.service";
interfaceServices = mapAttrsToList (_: interface: "${interface.serviceName}.service") config.interfaces; interfaceServices = mapAttrsToList (_: interface: "${interface.serviceName}.service") config.interfaces;
submoduleArgs = { ... }: { submoduleArgs = {...}: {
config._module.args.namespace = config; config._module.args.namespace = config;
}; };
in { in {
options = with lib.types; { options = with lib.types; {
enable = mkEnableOption "network namespace" // { enable =
default = true; mkEnableOption "network namespace"
}; // {
default = true;
};
resolvConf = mkOption { resolvConf = mkOption {
type = lines; type = lines;
default = '' default = ''
@ -186,8 +201,9 @@
groupModule groupModule
submoduleArgs submoduleArgs
]; ];
idOrModule = coercedTo int (id: { inherit id; }) module; idOrModule = coercedTo int (id: {inherit id;}) module;
in nullOr idOrModule; in
nullOr idOrModule;
default = null; default = null;
}; };
interfaces = mkOption { interfaces = mkOption {
@ -195,7 +211,7 @@
namespaceInterfaceModule namespaceInterfaceModule
submoduleArgs submoduleArgs
]); ]);
default = { }; default = {};
}; };
path = mkOption { path = mkOption {
type = path; type = path;
@ -226,8 +242,8 @@
}; };
config = { config = {
serviceSettings = { serviceSettings = {
wants = [ "network.target" ]; wants = ["network.target"];
after = [ "network.target" ]; after = ["network.target"];
stopIfChanged = false; stopIfChanged = false;
restartIfChanged = false; restartIfChanged = false;
serviceConfig = { serviceConfig = {
@ -245,12 +261,12 @@
}; };
}; };
targetSettings = { targetSettings = {
wantedBy = [ "multi-user.target" ]; wantedBy = ["multi-user.target"];
bindsTo = [ "${config.unitName}.service" ]; bindsTo = ["${config.unitName}.service"];
requires = linkGroupServices ++ interfaceServices; requires = linkGroupServices ++ interfaceServices;
wants = mkMerge [ wants = mkMerge [
(mkIf config.dhcpcd.enable [ "${config.dhcpcd.serviceName}.service" ]) (mkIf config.dhcpcd.enable ["${config.dhcpcd.serviceName}.service"])
(mkIf config.nftables.enable [ "${config.nftables.serviceName}.service" ]) (mkIf config.nftables.enable ["${config.nftables.serviceName}.service"])
]; ];
}; };
configFiles = { configFiles = {
@ -312,21 +328,22 @@
addrs6 = access.cidrForNetwork.local.v6 ++ optionals tailscale.enable access.cidrForNetwork.tail.v6; addrs6 = access.cidrForNetwork.local.v6 ++ optionals tailscale.enable access.cidrForNetwork.tail.v6;
daddr4 = ''{ ${concatStringsSep ", " addrs4} }''; daddr4 = ''{ ${concatStringsSep ", " addrs4} }'';
daddr6 = ''{ ${concatStringsSep ", " addrs6} }''; daddr6 = ''{ ${concatStringsSep ", " addrs6} }'';
in mkIf config.nftables.rejectLocaladdrs (mkMerge [ in
''ct state { established, related } accept'' mkIf config.nftables.rejectLocaladdrs (mkMerge [
'' ''ct state { established, related } accept''
ip daddr ${daddr4} ip protocol tcp reject with tcp reset ''
ip daddr ${daddr4} drop ip daddr ${daddr4} ip protocol tcp reject with tcp reset
'' ip daddr ${daddr4} drop
(mkIf networking.enableIPv6 '' ''
ip6 daddr ${daddr6} ip6 nexthdr tcp reject with tcp reset (mkIf networking.enableIPv6 ''
ip6 daddr ${daddr6} drop ip6 daddr ${daddr6} ip6 nexthdr tcp reject with tcp reset
'') ip6 daddr ${daddr6} drop
]); '')
]);
serviceSettings = rec { serviceSettings = rec {
bindsTo = [ "${config.unitName}.service" ]; bindsTo = ["${config.unitName}.service"];
partOf = [ "${config.unitName}.target" ]; partOf = ["${config.unitName}.target"];
wants = mkIf config.nftables.rejectLocaladdrs [ "localaddrs.service" ]; wants = mkIf config.nftables.rejectLocaladdrs ["localaddrs.service"];
after = mkMerge [ after = mkMerge [
bindsTo bindsTo
wants wants
@ -346,7 +363,7 @@
"${pkgs.nftables}/bin/nft -f ${config.configPath}/rules.nft" "${pkgs.nftables}/bin/nft -f ${config.configPath}/rules.nft"
]; ];
ExecReload = mkMerge [ ExecReload = mkMerge [
(mkIf config.nftables.rejectLocaladdrs [ "+${access.localaddrs.reloadScript}" ]) (mkIf config.nftables.rejectLocaladdrs ["+${access.localaddrs.reloadScript}"])
[ [
"${pkgs.nftables}/bin/nft flush ruleset" "${pkgs.nftables}/bin/nft flush ruleset"
"${pkgs.nftables}/bin/nft -f ${config.configPath}/rules.nft" "${pkgs.nftables}/bin/nft -f ${config.configPath}/rules.nft"
@ -360,12 +377,15 @@
}; };
dhcpcd = { dhcpcd = {
serviceSettings = rec { serviceSettings = rec {
bindsTo = [ "${config.unitName}.service" ]; bindsTo = ["${config.unitName}.service"];
partOf = [ "${config.unitName}.target" ]; partOf = ["${config.unitName}.target"];
wants = linkGroupServices ++ interfaceServices; wants = linkGroupServices ++ interfaceServices;
after = bindsTo ++ wants ++ [ after =
(mkIf config.nftables.enable "${config.nftables.serviceName}.service") bindsTo
]; ++ wants
++ [
(mkIf config.nftables.enable "${config.nftables.serviceName}.service")
];
stopIfChanged = false; stopIfChanged = false;
unitConfig.ConditionCapability = "CAP_NET_ADMIN"; unitConfig.ConditionCapability = "CAP_NET_ADMIN";
serviceConfig = { serviceConfig = {
@ -407,15 +427,21 @@
}; };
}; };
}; };
serviceModule = { config, name, ... }: let serviceModule = {
config,
name,
...
}: let
cfg = config.networkNamespace; cfg = config.networkNamespace;
hasNs = cfg.name != null; hasNs = cfg.name != null;
ns = networking.namespaces.${cfg.name}; ns = networking.namespaces.${cfg.name};
in { in {
options.networkNamespace = with lib.types; { options.networkNamespace = with lib.types; {
enable = mkEnableOption "netns" // { enable =
default = cfg.name != null; mkEnableOption "netns"
}; // {
default = cfg.name != null;
};
bindResolvConf = mkOption { bindResolvConf = mkOption {
type = nullOr path; type = nullOr path;
}; };
@ -446,15 +472,13 @@
path = mkDefault ( path = mkDefault (
ns.path ns.path
); );
bindResolvConf = mkDefault ( bindResolvConf = mkDefault "${ns.configPath}/resolv.conf";
"${ns.configPath}/resolv.conf"
);
}) })
]; ];
} }
(mkIf cfg.enable rec { (mkIf cfg.enable rec {
wants = mkIf hasNs [ "${ns.unitName}.target" ]; wants = mkIf hasNs ["${ns.unitName}.target"];
bindsTo = mkIf hasNs [ "${ns.unitName}.service" ]; bindsTo = mkIf hasNs ["${ns.unitName}.service"];
after = mkMerge [ after = mkMerge [
bindsTo bindsTo
(mkIf (hasNs && cfg.afterOnline) [ (mkIf (hasNs && cfg.afterOnline) [
@ -475,7 +499,7 @@ in {
options = with lib.types; { options = with lib.types; {
networking.namespaces = mkOption { networking.namespaces = mkOption {
type = attrsOf (submodule namespaceModule); type = attrsOf (submodule namespaceModule);
default = { }; default = {};
}; };
systemd.services = mkOption { systemd.services = mkOption {
type = attrsOf (submodule serviceModule); type = attrsOf (submodule serviceModule);
@ -483,19 +507,25 @@ in {
}; };
config = { config = {
systemd = { systemd = {
services = listToAttrs (concatMap (ns: services = listToAttrs (concatMap (
singleton (nameValuePair ns.unitName (unmerged.merge ns.serviceSettings)) ns:
++ optional (ns.linkGroup != null) (nameValuePair ns.linkGroup.serviceName (unmerged.merge ns.linkGroup.serviceSettings)) singleton (nameValuePair ns.unitName (unmerged.merge ns.serviceSettings))
++ mapAttrsToList (_: interface: nameValuePair interface.serviceName (unmerged.merge interface.serviceSettings)) ns.interfaces ++ optional (ns.linkGroup != null) (nameValuePair ns.linkGroup.serviceName (unmerged.merge ns.linkGroup.serviceSettings))
++ optional ns.dhcpcd.enable (nameValuePair ns.dhcpcd.serviceName (unmerged.merge ns.dhcpcd.serviceSettings)) ++ mapAttrsToList (_: interface: nameValuePair interface.serviceName (unmerged.merge interface.serviceSettings)) ns.interfaces
++ optional ns.nftables.enable (nameValuePair ns.nftables.serviceName (unmerged.merge ns.nftables.serviceSettings)) ++ optional ns.dhcpcd.enable (nameValuePair ns.dhcpcd.serviceName (unmerged.merge ns.dhcpcd.serviceSettings))
) enabledNamespaces); ++ optional ns.nftables.enable (nameValuePair ns.nftables.serviceName (unmerged.merge ns.nftables.serviceSettings))
targets = listToAttrs (map (ns: nameValuePair ns.unitName ( )
unmerged.merge ns.targetSettings enabledNamespaces);
)) enabledNamespaces); targets = listToAttrs (map (ns:
nameValuePair ns.unitName (
unmerged.merge ns.targetSettings
))
enabledNamespaces);
}; };
environment.etc = mkMerge (map (ns: environment.etc = mkMerge (map (
mapAttrs' (name: file: nameValuePair "${ns.configDir}/${name}" (unmerged.merge file)) ns.configFiles ns:
) enabledNamespaces); mapAttrs' (name: file: nameValuePair "${ns.configDir}/${name}" (unmerged.merge file)) ns.configFiles
)
enabledNamespaces);
}; };
} }

View file

@ -8,17 +8,21 @@
inherit (lib.modules) mkIf mkMerge mkOptionDefault; inherit (lib.modules) mkIf mkMerge mkOptionDefault;
inherit (inputs.self.lib.lib) eui64; inherit (inputs.self.lib.lib) eui64;
inherit (config) networking services; inherit (config) networking services;
networkModule = { config, ... }: { networkModule = {config, ...}: {
options = with lib.types; { options = with lib.types; {
mdns = { mdns = {
enable = mkEnableOption "SLAAC" // { enable =
default = config.matchConfig.Type or null == "ether" && services.resolved.enable; mkEnableOption "SLAAC"
}; // {
default = config.matchConfig.Type or null == "ether" && services.resolved.enable;
};
}; };
slaac = { slaac = {
enable = mkEnableOption "SLAAC" // { enable =
default = config.matchConfig.Type or null == "ether" && networking.enableIPv6; mkEnableOption "SLAAC"
}; // {
default = config.matchConfig.Type or null == "ether" && networking.enableIPv6;
};
postfix = mkOption { postfix = mkOption {
type = str; type = str;
}; };

View file

@ -1,6 +1,8 @@
{ lib, config, ... }: {
lib,
let config,
...
}: let
inherit (lib) types; inherit (lib) types;
inherit (lib.options) mkOption mkEnableOption; inherit (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf; inherit (lib.modules) mkIf;
@ -13,11 +15,13 @@ let
doDocker = config.virtualisation.docker.enable && cfg.generateDockerRules; doDocker = config.virtualisation.docker.enable && cfg.generateDockerRules;
mkPorts = cond: ports: ranges: action: let mkPorts = cond: ports: ranges: action: let
portStrings = (map (range: "${toString range.from}-${toString range.to}") ranges) portStrings =
++ (map toString ports); (map (range: "${toString range.from}-${toString range.to}") ranges)
in optionalString (portStrings != []) '' ++ (map toString ports);
${cond} dport { ${concatStringsSep "," portStrings} } ${action} in
''; optionalString (portStrings != []) ''
${cond} dport { ${concatStringsSep "," portStrings} } ${action}
'';
ruleset = '' ruleset = ''
table inet filter { table inet filter {
@ -32,18 +36,21 @@ let
ct state established,related accept ct state established,related accept
iifname { ${ iifname { ${
concatStringsSep "," (["lo"] ++ fwcfg.trustedInterfaces) concatStringsSep "," (["lo"] ++ fwcfg.trustedInterfaces)
} } accept } } accept
${mkPorts "tcp" fwcfg.allowedTCPPorts fwcfg.allowedTCPPortRanges "accept"} ${mkPorts "tcp" fwcfg.allowedTCPPorts fwcfg.allowedTCPPortRanges "accept"}
${mkPorts "udp" fwcfg.allowedUDPPorts fwcfg.allowedUDPPortRanges "accept"} ${mkPorts "udp" fwcfg.allowedUDPPorts fwcfg.allowedUDPPortRanges "accept"}
${ ${
concatStringsSep "\n" (mapAttrsToList (name: ifcfg: concatMapStringsSep "\n" (cond: concatStringsSep "\n" (mapAttrsToList (name: ifcfg:
mkPorts "${cond} tcp" ifcfg.allowedTCPPorts ifcfg.allowedTCPPortRanges "accept" concatMapStringsSep "\n" (
cond:
mkPorts "${cond} tcp" ifcfg.allowedTCPPorts ifcfg.allowedTCPPortRanges "accept"
+ mkPorts "${cond} udp" ifcfg.allowedUDPPorts ifcfg.allowedUDPPortRanges "accept" + mkPorts "${cond} udp" ifcfg.allowedUDPPorts ifcfg.allowedUDPPortRanges "accept"
) (optionals ifcfg.nftables.enable ifcfg.nftables.conditions)) fwcfg.interfaces) ) (optionals ifcfg.nftables.enable ifcfg.nftables.conditions))
} fwcfg.interfaces)
}
# DHCPv6 # DHCPv6
ip6 daddr fe80::/64 udp dport 546 accept ip6 daddr fe80::/64 udp dport 546 accept
@ -65,10 +72,10 @@ let
policy ${cfg.forwardPolicy} policy ${cfg.forwardPolicy}
${optionalString doDocker '' ${optionalString doDocker ''
oifname docker0 ct state invalid drop oifname docker0 ct state invalid drop
oifname docker0 ct state established,related accept oifname docker0 ct state established,related accept
iifname docker0 accept iifname docker0 accept
''} ''}
${cfg.extraForward} ${cfg.extraForward}
@ -85,14 +92,23 @@ let
''} ''}
${cfg.extraConfig} ${cfg.extraConfig}
''; '';
interfaceModule = { config, name, ... }: { interfaceModule = {
config,
name,
...
}: {
options = { options = {
nftables = { nftables = {
enable = mkEnableOption "nftables firewall" // { enable =
default = mkEnableOption "nftables firewall"
config.allowedTCPPorts != [ ] || config.allowedTCPPortRanges != [ ] // {
|| config.allowedUDPPorts != [ ] || config.allowedUDPPortRanges != [ ]; default =
}; config.allowedTCPPorts
!= []
|| config.allowedTCPPortRanges != []
|| config.allowedUDPPorts != []
|| config.allowedUDPPortRanges != [];
};
conditions = mkOption { conditions = mkOption {
type = types.listOf types.str; type = types.listOf types.str;
default = "iifname ${name}"; default = "iifname ${name}";
@ -100,7 +116,6 @@ let
}; };
}; };
}; };
in { in {
options = { options = {
networking.nftables = { networking.nftables = {

View file

@ -9,7 +9,7 @@
inherit (lib.lists) optionals; inherit (lib.lists) optionals;
inherit (config.services) tailscale; inherit (config.services) tailscale;
inherit (config.networking.access) cidrForNetwork localaddrs; inherit (config.networking.access) cidrForNetwork localaddrs;
localModule = { config, ... }: { localModule = {config, ...}: {
options.local = with lib.types; { options.local = with lib.types; {
enable = mkOption { enable = mkOption {
type = bool; type = bool;
@ -37,16 +37,23 @@
cidrForNetwork.loopback.all cidrForNetwork.loopback.all
++ cidrForNetwork.local.all ++ cidrForNetwork.local.all
++ optionals tailscale.enable cidrForNetwork.tail.all; ++ optionals tailscale.enable cidrForNetwork.tail.all;
allows = concatMapStringsSep "\n" mkAllow allowAddresses + optionalString localaddrs.enable '' allows =
include ${localaddrs.stateDir}/*.nginx.conf; concatMapStringsSep "\n" mkAllow allowAddresses
+ optionalString localaddrs.enable ''
include ${localaddrs.stateDir}/*.nginx.conf;
'';
in
mkBefore ''
${allows}
deny all;
''; '';
in mkBefore ''
${allows}
deny all;
'';
}; };
}; };
locationModule = { config, virtualHost, ... }: { locationModule = {
config,
virtualHost,
...
}: {
imports = [ imports = [
localModule localModule
]; ];
@ -58,13 +65,13 @@
emitDenyGlobal = virtualHost.local.emitDenyGlobal; emitDenyGlobal = virtualHost.local.emitDenyGlobal;
}; };
}; };
hostModule = { config, ... }: { hostModule = {config, ...}: {
imports = [ localModule ]; imports = [localModule];
options = with lib.types; { options = with lib.types; {
locations = mkOption { locations = mkOption {
type = attrsOf (submoduleWith { type = attrsOf (submoduleWith {
modules = [ locationModule ]; modules = [locationModule];
shorthandOnlyDefinesConfig = true; shorthandOnlyDefinesConfig = true;
specialArgs = { specialArgs = {
virtualHost = config; virtualHost = config;
@ -83,7 +90,7 @@ in {
options = with lib.types; { options = with lib.types; {
services.nginx.virtualHosts = mkOption { services.nginx.virtualHosts = mkOption {
type = attrsOf (submoduleWith { type = attrsOf (submoduleWith {
modules = [ hostModule ]; modules = [hostModule];
shorthandOnlyDefinesConfig = true; shorthandOnlyDefinesConfig = true;
specialArgs = { specialArgs = {
nixosConfig = config; nixosConfig = config;

View file

@ -2,13 +2,12 @@
config, config,
lib, lib,
... ...
}: }: let
let
inherit (lib.options) mkOption mkEnableOption; inherit (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkMerge mkBefore mkDefault; inherit (lib.modules) mkIf mkMerge mkBefore mkDefault;
inherit (config) networking; inherit (config) networking;
inherit (config.services) vouch-proxy tailscale; inherit (config.services) vouch-proxy tailscale;
vouchModule = { config, ... }: { vouchModule = {config, ...}: {
options = with lib.types; { options = with lib.types; {
vouch = { vouch = {
enable = mkEnableOption "vouch auth proxy"; enable = mkEnableOption "vouch auth proxy";
@ -49,15 +48,20 @@ let
vouch = mkIf vouch-proxy.enable { vouch = mkIf vouch-proxy.enable {
proxyOrigin = let proxyOrigin = let
inherit (vouch-proxy.settings.vouch) listen port; inherit (vouch-proxy.settings.vouch) listen port;
host = if listen == "0.0.0.0" || listen == "[::]" then "localhost" else listen; host =
in mkDefault "http://${host}:${toString port}"; if listen == "0.0.0.0" || listen == "[::]"
then "localhost"
else listen;
in
mkDefault "http://${host}:${toString port}";
authUrl = mkDefault vouch-proxy.authUrl; authUrl = mkDefault vouch-proxy.authUrl;
url = mkDefault vouch-proxy.url; url = mkDefault vouch-proxy.url;
doubleProxy = mkDefault false; doubleProxy = mkDefault false;
}; };
} }
{ {
vouch.proxyOrigin = mkIf (tailscale.enable && !vouch-proxy.enable) (mkDefault vouch.proxyOrigin = mkIf (tailscale.enable && !vouch-proxy.enable) (
mkDefault
"http://login.tail.${networking.domain}" "http://login.tail.${networking.domain}"
); );
} }
@ -96,22 +100,23 @@ let
set $vouch_url $vouch_scheme://${config.vouch.tailDomain}; set $vouch_url $vouch_scheme://${config.vouch.tailDomain};
} }
''; '';
in mkMerge [ in
(mkBefore '' mkMerge [
set $vouch_url ${config.vouch.url}; (mkBefore ''
set $vouch_scheme $scheme; set $vouch_url ${config.vouch.url};
'') set $vouch_scheme $scheme;
(mkIf config.local.trusted (mkBefore '' '')
if ($http_x_forwarded_proto) { (mkIf config.local.trusted (mkBefore ''
set $vouch_scheme $http_x_forwarded_proto; if ($http_x_forwarded_proto) {
} set $vouch_scheme $http_x_forwarded_proto;
'')) }
(mkIf (config.local.enable or false) localVouchUrl) ''))
(mkIf (config.local.enable or false && tailscale.enable) tailVouchUrl) (mkIf (config.local.enable or false) localVouchUrl)
'' (mkIf (config.local.enable or false && tailscale.enable) tailVouchUrl)
return 302 $vouch_url/login?url=$vouch_scheme://$http_host$request_uri&vouch-failcount=$auth_resp_failcount&X-Vouch-Token=$auth_resp_jwt&error=$auth_resp_err; ''
'' return 302 $vouch_url/login?url=$vouch_scheme://$http_host$request_uri&vouch-failcount=$auth_resp_failcount&X-Vouch-Token=$auth_resp_jwt&error=$auth_resp_err;
]; ''
];
}; };
"/validate" = { "/validate" = {
recommendedProxySettings = false; recommendedProxySettings = false;

View file

@ -1,10 +1,7 @@
{ {lib, ...}: let
lib,
...
}: let
inherit (lib.modules) mkIf; inherit (lib.modules) mkIf;
inherit (lib.options) mkOption mkEnableOption; inherit (lib.options) mkOption mkEnableOption;
wsModule = { config, ... }: { wsModule = {config, ...}: {
options = with lib.types; { options = with lib.types; {
proxy.websocket.enable = mkEnableOption "websocket proxy"; proxy.websocket.enable = mkEnableOption "websocket proxy";
}; };
@ -16,8 +13,8 @@
''; '';
}; };
}; };
hostModule = { config, ... }: { hostModule = {config, ...}: {
imports = [ wsModule ]; imports = [wsModule];
options = with lib.types; { options = with lib.types; {
locations = mkOption { locations = mkOption {

View file

@ -1,7 +1,4 @@
{ {lib, ...}: let
lib,
...
}: let
inherit (lib.options) mkOption; inherit (lib.options) mkOption;
in { in {
options.services.plex = with lib.types; { options.services.plex = with lib.types; {

View file

@ -1,11 +1,12 @@
{ config, lib, ... }: {
config,
with lib; lib,
...
let }:
with lib; let
cfg = config.networking.policyrouting; cfg = config.networking.policyrouting;
ruleOpts = { ... }: { ruleOpts = {...}: {
options = { options = {
prio = mkOption { prio = mkOption {
type = types.int; type = types.int;
@ -15,37 +16,44 @@ let
}; };
}; };
}; };
in {
in
{
options = { options = {
networking.policyrouting = { networking.policyrouting = {
enable = mkEnableOption "Declarative Policy-Routing"; enable = mkEnableOption "Declarative Policy-Routing";
rules = mkOption { rules = mkOption {
type = with types; listOf (submodule ruleOpts); type = with types; listOf (submodule ruleOpts);
default = [ ]; default = [];
}; };
rules6 = mkOption { rules6 = mkOption {
type = with types; listOf (submodule ruleOpts); type = with types; listOf (submodule ruleOpts);
default = [ ]; default = [];
}; };
rules4 = mkOption { rules4 = mkOption {
type = with types; listOf (submodule ruleOpts); type = with types; listOf (submodule ruleOpts);
default = [ ]; default = [];
}; };
}; };
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
networking.policyrouting.rules = [ networking.policyrouting.rules = [
{ rule = "lookup main"; prio = 32000; } {
rule = "lookup main";
prio = 32000;
}
]; ];
networking.localCommands = '' networking.localCommands = ''
set -x set -x
ip -6 rule flush ip -6 rule flush
ip -4 rule flush ip -4 rule flush
${concatMapStringsSep "\n" ({ prio, rule }: "ip -6 rule add ${rule} prio ${toString prio}") (cfg.rules ++ cfg.rules6)} ${concatMapStringsSep "\n" ({
${concatMapStringsSep "\n" ({ prio, rule }: "ip -4 rule add ${rule} prio ${toString prio}") (cfg.rules ++ cfg.rules4)} prio,
rule,
}: "ip -6 rule add ${rule} prio ${toString prio}") (cfg.rules ++ cfg.rules6)}
${concatMapStringsSep "\n" ({
prio,
rule,
}: "ip -4 rule add ${rule} prio ${toString prio}") (cfg.rules ++ cfg.rules4)}
''; '';
}; };
} }

View file

@ -10,19 +10,24 @@
inherit (config) networking; inherit (config) networking;
cfg = config.services.postgresql; cfg = config.services.postgresql;
formatHost = host: formatHost = host:
if hasInfix "/" host then host if hasInfix "/" host
else if hasInfix ":" host then "${host}/128" then host
else if hasInfix "." host then "${host}/32" else if hasInfix ":" host
then "${host}/128"
else if hasInfix "." host
then "${host}/32"
else throw "unsupported IP address ${host}"; else throw "unsupported IP address ${host}";
ensureUserModule = { config, ... }: { ensureUserModule = {config, ...}: {
options = with lib.types; { options = with lib.types; {
authentication = { authentication = {
enable = mkEnableOption "TCP connections" // { enable =
default = config.authentication.hosts != [ ]; mkEnableOption "TCP connections"
}; // {
default = config.authentication.hosts != [];
};
hosts = mkOption { hosts = mkOption {
type = listOf str; type = listOf str;
default = [ ]; default = [];
}; };
method = mkOption { method = mkOption {
type = str; type = str;
@ -47,13 +52,15 @@
authentication = { authentication = {
hosts = let hosts = let
inherit (networking.access) cidrForNetwork; inherit (networking.access) cidrForNetwork;
in mkMerge [ in
(mkIf config.authentication.tailscale.allow cidrForNetwork.tail.all) mkMerge [
(mkIf config.authentication.local.allow (cidrForNetwork.loopback.all ++ cidrForNetwork.local.all)) (mkIf config.authentication.tailscale.allow cidrForNetwork.tail.all)
]; (mkIf config.authentication.local.allow (cidrForNetwork.loopback.all ++ cidrForNetwork.local.all))
];
authentication = mkMerge (map (host: '' authentication = mkMerge (map (host: ''
host ${config.authentication.database} ${config.name} ${formatHost host} ${config.authentication.method} host ${config.authentication.database} ${config.name} ${formatHost host} ${config.authentication.method}
'') config.authentication.hosts); '')
config.authentication.hosts);
}; };
authentication.database = mkIf config.ensureDBOwnership ( authentication.database = mkIf config.ensureDBOwnership (
mkOptionDefault config.name mkOptionDefault config.name
@ -70,11 +77,13 @@ in {
enableTCPIP = mkIf (any (user: user.authentication.enable) cfg.ensureUsers) ( enableTCPIP = mkIf (any (user: user.authentication.enable) cfg.ensureUsers) (
mkDefault true mkDefault true
); );
authentication = mkMerge (map (user: authentication = mkMerge (map (
mkIf user.authentication.enable user.authentication.authentication user:
) cfg.ensureUsers); mkIf user.authentication.enable user.authentication.authentication
)
cfg.ensureUsers);
}; };
config.networking.firewall.interfaces.local = mkIf cfg.enable { config.networking.firewall.interfaces.local = mkIf cfg.enable {
allowedTCPPorts = mkIf (any (user: user.authentication.local.allow) cfg.ensureUsers) [ cfg.port ]; allowedTCPPorts = mkIf (any (user: user.authentication.local.allow) cfg.ensureUsers) [cfg.port];
}; };
} }

View file

@ -1,7 +1,4 @@
{ {lib, ...}: let
lib,
...
}: let
inherit (lib.options) mkOption; inherit (lib.options) mkOption;
in { in {
options.services.prowlarr = with lib.types; { options.services.prowlarr = with lib.types; {

View file

@ -1,7 +1,4 @@
{ {lib, ...}: let
lib,
...
}: let
inherit (lib.options) mkOption; inherit (lib.options) mkOption;
in { in {
options.services.radarr = with lib.types; { options.services.radarr = with lib.types; {

View file

@ -1,7 +1,4 @@
{ {lib, ...}: let
lib,
...
}: let
inherit (lib.options) mkOption; inherit (lib.options) mkOption;
in { in {
options.services.readarr = with lib.types; { options.services.readarr = with lib.types; {

View file

@ -11,14 +11,17 @@
inherit (config.services) samba-wsdd; inherit (config.services) samba-wsdd;
cfg = config.services.samba; cfg = config.services.samba;
settingValue = value: settingValue = value:
if builtins.isList value then concatMapStringsSep ", " settingValue value if builtins.isList value
else if value == true then "yes" then concatMapStringsSep ", " settingValue value
else if value == false then "no" else if value == true
then "yes"
else if value == false
then "no"
else toString value; else toString value;
in { in {
options.services.samba = with lib.types; let options.services.samba = with lib.types; let
settingPrimitive = oneOf [ str int bool ]; settingPrimitive = oneOf [str int bool];
settingType = oneOf [ settingPrimitive (listOf settingPrimitive) ]; settingType = oneOf [settingPrimitive (listOf settingPrimitive)];
in { in {
ldap = { ldap = {
enable = mkEnableOption "LDAP"; enable = mkEnableOption "LDAP";
@ -64,7 +67,11 @@ in {
}; };
}; };
idmap = let idmap = let
idmapModule = { config, name, ... }: { idmapModule = {
config,
name,
...
}: {
options = { options = {
backend = mkOption { backend = mkOption {
type = str; type = str;
@ -89,7 +96,7 @@ in {
}; };
settings = mkOption { settings = mkOption {
type = attrsOf settingType; type = attrsOf settingType;
default = { }; default = {};
}; };
}; };
config = { config = {
@ -117,7 +124,7 @@ in {
}; };
settings = mkOption { settings = mkOption {
type = attrsOf settingType; type = attrsOf settingType;
default = { }; default = {};
}; };
}; };
@ -139,35 +146,36 @@ in {
}) })
]; ];
settings = mkMerge ([ settings = mkMerge ([
{ {
"use sendfile" = mkOptionDefault true; "use sendfile" = mkOptionDefault true;
} }
(mkIf (cfg.passdb.smbpasswd.path != null) { (mkIf (cfg.passdb.smbpasswd.path != null) {
"passdb backend" = mkOptionDefault "smbpasswd:${cfg.passdb.smbpasswd.path}"; "passdb backend" = mkOptionDefault "smbpasswd:${cfg.passdb.smbpasswd.path}";
}) })
(mkIf cfg.ldap.enable { (mkIf cfg.ldap.enable {
"passdb backend" = mkOptionDefault ''ldapsam:"${cfg.ldap.url}"''; "passdb backend" = mkOptionDefault ''ldapsam:"${cfg.ldap.url}"'';
"ldap ssl" = mkIf (hasPrefix "ldaps://" cfg.ldap.url) (mkOptionDefault "off"); "ldap ssl" = mkIf (hasPrefix "ldaps://" cfg.ldap.url) (mkOptionDefault "off");
"ldap admin dn" = mkOptionDefault "name=anonymous,${cfg.ldap.baseDn}"; "ldap admin dn" = mkOptionDefault "name=anonymous,${cfg.ldap.baseDn}";
"ldap suffix" = mkOptionDefault cfg.ldap.baseDn; "ldap suffix" = mkOptionDefault cfg.ldap.baseDn;
}) })
(mkIf (cfg.ldap.enable && true) { (mkIf (cfg.ldap.enable && true) {
"ntlm auth" = mkOptionDefault "disabled"; "ntlm auth" = mkOptionDefault "disabled";
"encrypt passwords" = mkOptionDefault false; "encrypt passwords" = mkOptionDefault false;
}) })
(mkIf cfg.usershare.enable { (mkIf cfg.usershare.enable {
"usershare allow guests" = mkOptionDefault true; "usershare allow guests" = mkOptionDefault true;
"usershare max shares" = mkOptionDefault 16; "usershare max shares" = mkOptionDefault 16;
"usershare owner only" = mkOptionDefault true; "usershare owner only" = mkOptionDefault true;
"usershare template share" = mkOptionDefault cfg.usershare.templateShare; "usershare template share" = mkOptionDefault cfg.usershare.templateShare;
"usershare path" = mkOptionDefault cfg.usershare.path; "usershare path" = mkOptionDefault cfg.usershare.path;
"usershare prefix allow list" = mkOptionDefault [ cfg.usershare.path ]; "usershare prefix allow list" = mkOptionDefault [cfg.usershare.path];
}) })
(mkIf cfg.guest.enable { (mkIf cfg.guest.enable {
"map to guest" = mkOptionDefault "Bad User"; "map to guest" = mkOptionDefault "Bad User";
"guest account" = mkOptionDefault cfg.guest.user; "guest account" = mkOptionDefault cfg.guest.user;
}) })
] ++ mapAttrsToList (_: idmap: mapAttrs' (key: value: nameValuePair "idmap config ${idmap.domain} : ${key}" (mkOptionDefault value)) idmap.settings) cfg.idmap.domains); ]
++ mapAttrsToList (_: idmap: mapAttrs' (key: value: nameValuePair "idmap config ${idmap.domain} : ${key}" (mkOptionDefault value)) idmap.settings) cfg.idmap.domains);
extraConfig = mkMerge (mapAttrsToList (key: value: ''${key} = ${settingValue value}'') cfg.settings); extraConfig = mkMerge (mapAttrsToList (key: value: ''${key} = ${settingValue value}'') cfg.settings);
shares.${cfg.usershare.templateShare} = mkIf cfg.usershare.enable { shares.${cfg.usershare.templateShare} = mkIf cfg.usershare.enable {
"-valid" = false; "-valid" = false;
@ -194,12 +202,12 @@ in {
networking.firewall.interfaces.local = { networking.firewall.interfaces.local = {
allowedTCPPorts = mkMerge [ allowedTCPPorts = mkMerge [
(mkIf (cfg.enable && !cfg.openFirewall) [ 139 445 ]) (mkIf (cfg.enable && !cfg.openFirewall) [139 445])
(mkIf (samba-wsdd.enable && !samba-wsdd.openFirewall) [ 5357 ]) (mkIf (samba-wsdd.enable && !samba-wsdd.openFirewall) [5357])
]; ];
allowedUDPPorts = mkMerge [ allowedUDPPorts = mkMerge [
(mkIf (cfg.enable && !cfg.openFirewall) [ 137 138 ]) (mkIf (cfg.enable && !cfg.openFirewall) [137 138])
(mkIf (samba-wsdd.enable && !samba-wsdd.openFirewall) [ 3702 ]) (mkIf (samba-wsdd.enable && !samba-wsdd.openFirewall) [3702])
]; ];
}; };
}; };

View file

@ -1,7 +1,4 @@
{ {lib, ...}: let
lib,
...
}: let
inherit (lib.options) mkOption; inherit (lib.options) mkOption;
in { in {
options.services.sonarr = with lib.types; { options.services.sonarr = with lib.types; {

View file

@ -76,30 +76,35 @@ in {
inherit owner; inherit owner;
inherit (shared) group mode; inherit (shared) group mode;
}; };
setupFiles = singleton { setupFiles =
${cfg.rootDir} = toplevel; singleton {
${cfg.binDir} = toplevel; ${cfg.rootDir} = toplevel;
${cfg.binDir + "/users"} = shared; ${cfg.binDir} = toplevel;
${cfg.dataDir} = toplevel; ${cfg.binDir + "/users"} = shared;
${cfg.sharedDataDir} = shared; ${cfg.dataDir} = toplevel;
${cfg.workingDir} = toplevel; ${cfg.sharedDataDir} = shared;
${cfg.sharedWorkingDir} = shared; ${cfg.workingDir} = toplevel;
} ++ map (owner: { ${cfg.sharedWorkingDir} = shared;
${cfg.dataDir + "/${owner}"} = personal owner; }
${cfg.workingDir + "/${owner}"} = personal owner; ++ map (owner: {
}) cfg.users; ${cfg.dataDir + "/${owner}"} = personal owner;
userBinFiles = listToAttrs (map (user: nameValuePair "${cfg.binDir}/users/${user}.bat" { ${cfg.workingDir + "/${owner}"} = personal owner;
inherit (toplevel) owner group; })
mode = "0755"; cfg.users;
type = "copy"; userBinFiles = listToAttrs (map (user:
src = pkgs.writeTextFile { nameValuePair "${cfg.binDir}/users/${user}.bat" {
name = "steam-${user}.bat"; inherit (toplevel) owner group;
executable = true; mode = "0755";
text = '' type = "copy";
setx GENSO_STEAM_USER ${user} src = pkgs.writeTextFile {
''; name = "steam-${user}.bat";
}; executable = true;
}) cfg.users); text = ''
setx GENSO_STEAM_USER ${user}
'';
};
})
cfg.users);
in { in {
enable = mkIf (cfg.enable || cfg.setup) true; enable = mkIf (cfg.enable || cfg.setup) true;
files = mkMerge [ files = mkMerge [

View file

@ -14,7 +14,11 @@
inherit (lib.meta) getExe; inherit (lib.meta) getExe;
inherit (config.services.steam) accountSwitch; inherit (config.services.steam) accountSwitch;
cfg = config.services.steam.beatsaber; cfg = config.services.steam.beatsaber;
versionModule = { config, name, ... }: { versionModule = {
config,
name,
...
}: {
options = with lib.types; { options = with lib.types; {
version = mkOption { version = mkOption {
type = str; type = str;
@ -23,11 +27,12 @@
}; };
}; };
mkSharePath = path: mkWinPath ( mkSharePath = path:
"%GENSO_SMB_SHARED_MOUNT%" mkWinPath (
+ "/${accountSwitch.sharePath}" "%GENSO_SMB_SHARED_MOUNT%"
+ "/${removePrefix (accountSwitch.rootDir + "/") path}" + "/${accountSwitch.sharePath}"
); + "/${removePrefix (accountSwitch.rootDir + "/") path}"
);
vars = '' vars = ''
if "%GENSO_STEAM_INSTALL%" == "" set "GENSO_STEAM_INSTALL=C:\Program Files (x86)\Steam" if "%GENSO_STEAM_INSTALL%" == "" set "GENSO_STEAM_INSTALL=C:\Program Files (x86)\Steam"
if "%GENSO_STEAM_LIBRARY_BS%" == "" set "GENSO_STEAM_LIBRARY_BS=%GENSO_STEAM_INSTALL%" if "%GENSO_STEAM_LIBRARY_BS%" == "" set "GENSO_STEAM_LIBRARY_BS=%GENSO_STEAM_INSTALL%"
@ -102,9 +107,11 @@
in { in {
options.services.steam.beatsaber = with lib.types; { options.services.steam.beatsaber = with lib.types; {
enable = mkEnableOption "beatsaber scripts"; enable = mkEnableOption "beatsaber scripts";
setup = mkEnableOption "beatsaber data" // { setup =
default = accountSwitch.setup; mkEnableOption "beatsaber data"
}; // {
default = accountSwitch.setup;
};
group = mkOption { group = mkOption {
type = str; type = str;
default = "beatsaber"; default = "beatsaber";
@ -114,7 +121,7 @@ in {
}; };
versions = mkOption { versions = mkOption {
type = attrsOf (submodule versionModule); type = attrsOf (submodule versionModule);
default = { }; default = {};
}; };
users = mkOption { users = mkOption {
type = listOf str; type = listOf str;
@ -127,7 +134,7 @@ in {
bsUsers = filterAttrs (_: userIs cfg.group) config.users.users; bsUsers = filterAttrs (_: userIs cfg.group) config.users.users;
allVersions = mapAttrsToList (_: version: version.version) cfg.versions; allVersions = mapAttrsToList (_: version: version.version) cfg.versions;
in { in {
defaultVersion = mkIf (allVersions != [ ]) (mkOptionDefault ( defaultVersion = mkIf (allVersions != []) (mkOptionDefault (
head allVersions head allVersions
)); ));
users = mkOptionDefault ( users = mkOptionDefault (
@ -140,24 +147,27 @@ in {
mkbeatsabersh mkbeatsabersh
]; ];
}; };
systemd.services = mkIf cfg.setup (listToAttrs (map (user: nameValuePair "steam-setup-beatsaber-${user}" { systemd.services = mkIf cfg.setup (listToAttrs (map (user:
script = mkMerge (mapAttrsToList (_: version: '' nameValuePair "steam-setup-beatsaber-${user}" {
${getExe mkbeatsaber} ${version.version} ${user} script = mkMerge (mapAttrsToList (_: version: ''
'') cfg.versions); ${getExe mkbeatsaber} ${version.version} ${user}
path = [ '')
pkgs.coreutils cfg.versions);
]; path = [
wantedBy = [ pkgs.coreutils
"multi-user.target" ];
]; wantedBy = [
after = [ "multi-user.target"
"tmpfiles.service" ];
]; after = [
serviceConfig = { "tmpfiles.service"
RemainAfterExit = mkOptionDefault true; ];
User = mkOptionDefault user; serviceConfig = {
}; RemainAfterExit = mkOptionDefault true;
}) cfg.users)); User = mkOptionDefault user;
};
})
cfg.users));
services.tmpfiles = let services.tmpfiles = let
toplevel = { toplevel = {
owner = mkDefault "admin"; owner = mkDefault "admin";
@ -187,77 +197,92 @@ in {
"AppData" "AppData"
"UserData" "UserData"
]; ];
setupFiles = [ setupFiles =
[
{
"${accountSwitch.sharedDataDir}/BeatSaber" = toplevel;
"${accountSwitch.binDir}/beatsaber" = shared;
}
(listToAttrs (
map (
folder:
nameValuePair "${accountSwitch.sharedDataDir}/BeatSaber/${folder}" shared
)
sharedFolders
))
]
++ concatMap (
owner:
singleton {
"${accountSwitch.dataDir}/${owner}/BeatSaber" = personal owner;
"${accountSwitch.dataDir}/${owner}/BeatSaber/AppData" = personal owner;
"${accountSwitch.dataDir}/${owner}/BeatSaber/UserData" = personal owner;
}
++ mapAttrsToList (_: version: {
"${accountSwitch.dataDir}/${owner}/BeatSaber/${version.version}" = personal owner;
})
cfg.versions
)
accountSwitch.users
++ mapAttrsToList (_: version: {
"${accountSwitch.sharedDataDir}/BeatSaber/${version.version}" = shared;
})
cfg.versions;
versionBinFiles =
mapAttrs' (
_: version:
nameValuePair
"${accountSwitch.binDir}/beatsaber/${replaceStrings ["."] ["_"] version.version}.bat"
{
inherit (bin) owner group mode type;
src = pkgs.writeTextFile {
name = "beatsaber-${version.version}.bat";
executable = true;
text = ''
setx GENSO_STEAM_BS_VERSION ${version.version}
'';
};
}
)
cfg.versions;
binFiles =
{ {
"${accountSwitch.sharedDataDir}/BeatSaber" = toplevel; "${accountSwitch.binDir}/beatsaber/mount.bat" = {
"${accountSwitch.binDir}/beatsaber" = shared; inherit (bin) owner group mode type;
} src = pkgs.writeTextFile {
(listToAttrs ( name = "beatsaber-mount.bat";
map (folder: executable = true;
nameValuePair "${accountSwitch.sharedDataDir}/BeatSaber/${folder}" shared text = mountbeatsaber;
) sharedFolders };
)) };
] ++ concatMap (owner: "${accountSwitch.binDir}/beatsaber/launch.bat" = {
singleton { inherit (bin) owner group mode type;
"${accountSwitch.dataDir}/${owner}/BeatSaber" = personal owner; src = pkgs.writeTextFile {
"${accountSwitch.dataDir}/${owner}/BeatSaber/AppData" = personal owner; name = "beatsaber-launch.bat";
"${accountSwitch.dataDir}/${owner}/BeatSaber/UserData" = personal owner; executable = true;
} ++ mapAttrsToList (_: version: { text = launchbeatsaber;
"${accountSwitch.dataDir}/${owner}/BeatSaber/${version.version}" = personal owner; };
}) cfg.versions };
) accountSwitch.users "${accountSwitch.binDir}/beatsaber/fpfc.bat" = {
++ mapAttrsToList (_: version: { inherit (bin) owner group mode type;
"${accountSwitch.sharedDataDir}/BeatSaber/${version.version}" = shared; src = pkgs.writeTextFile {
}) cfg.versions; name = "beatsaber-fpfc.bat";
versionBinFiles = mapAttrs' (_: version: nameValuePair executable = true;
"${accountSwitch.binDir}/beatsaber/${replaceStrings [ "." ] [ "_" ] version.version}.bat" text = fpfcbeatsaber;
{ };
inherit (bin) owner group mode type; };
src = pkgs.writeTextFile { "${accountSwitch.binDir}/beatsaber/ModAssistant.exe" = {
name = "beatsaber-${version.version}.bat"; inherit (toplevel) owner group;
executable = true; mode = "0755";
text = '' type = "copy";
setx GENSO_STEAM_BS_VERSION ${version.version} src = pkgs.fetchurl {
''; url = "https://github.com/Assistant/ModAssistant/releases/download/v1.1.32/ModAssistant.exe";
hash = "sha256-ozu2gYFiz+2BjptqL80DmUopbahbyGKFO1IPd7BhVPM=";
executable = true;
};
}; };
} }
) cfg.versions; // versionBinFiles;
binFiles = {
"${accountSwitch.binDir}/beatsaber/mount.bat" = {
inherit (bin) owner group mode type;
src = pkgs.writeTextFile {
name = "beatsaber-mount.bat";
executable = true;
text = mountbeatsaber;
};
};
"${accountSwitch.binDir}/beatsaber/launch.bat" = {
inherit (bin) owner group mode type;
src = pkgs.writeTextFile {
name = "beatsaber-launch.bat";
executable = true;
text = launchbeatsaber;
};
};
"${accountSwitch.binDir}/beatsaber/fpfc.bat" = {
inherit (bin) owner group mode type;
src = pkgs.writeTextFile {
name = "beatsaber-fpfc.bat";
executable = true;
text = fpfcbeatsaber;
};
};
"${accountSwitch.binDir}/beatsaber/ModAssistant.exe" = {
inherit (toplevel) owner group;
mode = "0755";
type = "copy";
src = pkgs.fetchurl {
url = "https://github.com/Assistant/ModAssistant/releases/download/v1.1.32/ModAssistant.exe";
hash = "sha256-ozu2gYFiz+2BjptqL80DmUopbahbyGKFO1IPd7BhVPM=";
executable = true;
};
};
} // versionBinFiles;
in { in {
enable = mkIf (cfg.enable || cfg.setup) true; enable = mkIf (cfg.enable || cfg.setup) true;
files = mkMerge [ files = mkMerge [

View file

@ -18,11 +18,17 @@
systemdFiles = filter (file: file.systemd.enable) files; systemdFiles = filter (file: file.systemd.enable) files;
setupFiles = filter (file: !file.systemd.enable) files; setupFiles = filter (file: !file.systemd.enable) files;
bindFiles = filter (file: file.type == "bind") files; bindFiles = filter (file: file.type == "bind") files;
fileModule = { config, name, ... }: { fileModule = {
config,
name,
...
}: {
options = with lib.types; { options = with lib.types; {
enable = mkEnableOption "file" // { enable =
default = true; mkEnableOption "file"
}; // {
default = true;
};
mkdirParent = mkEnableOption "mkdir"; mkdirParent = mkEnableOption "mkdir";
bindReadOnly = mkEnableOption "mount -oro"; bindReadOnly = mkEnableOption "mount -oro";
relativeSymlink = mkEnableOption "ln -sr"; relativeSymlink = mkEnableOption "ln -sr";
@ -32,8 +38,11 @@
default = name; default = name;
}; };
type = mkOption { type = mkOption {
type = enum [ "directory" "symlink" "link" "copy" "bind" ]; type = enum ["directory" "symlink" "link" "copy" "bind"];
default = if config.src != null then "symlink" else "directory"; default =
if config.src != null
then "symlink"
else "directory";
}; };
mode = mkOption { mode = mkOption {
type = str; type = str;
@ -71,7 +80,7 @@
}; };
config = let config = let
acls = concatStringsSep "," config.acls; acls = concatStringsSep "," config.acls;
enableAcls = config.type == "directory" && config.acls != [ ]; enableAcls = config.type == "directory" && config.acls != [];
systemdAclRule = "a+ ${config.path} - - - - ${acls}"; systemdAclRule = "a+ ${config.path} - - - - ${acls}";
systemdRule = { systemdRule = {
directory = [ directory = [
@ -168,7 +177,7 @@
systemd = { systemd = {
rules = mkMerge [ rules = mkMerge [
systemdRule.${config.type} systemdRule.${config.type}
(mkIf enableAcls [ systemdAclRule ]) (mkIf enableAcls [systemdAclRule])
]; ];
mountSettings = mkIf (config.type == "bind") { mountSettings = mkIf (config.type == "bind") {
enable = mkDefault config.enable; enable = mkDefault config.enable;
@ -191,16 +200,21 @@
}; };
in { in {
options.services.tmpfiles = with lib.types; { options.services.tmpfiles = with lib.types; {
enable = mkEnableOption "extended tmpfiles" // { enable =
default = cfg.files != { }; mkEnableOption "extended tmpfiles"
}; // {
default = cfg.files != {};
};
user = mkOption { user = mkOption {
type = str; type = str;
default = if config.proxmoxLXC.privileged or true then "root" else "admin"; default =
if config.proxmoxLXC.privileged or true
then "root"
else "admin";
}; };
files = mkOption { files = mkOption {
type = attrsOf (submodule fileModule); type = attrsOf (submodule fileModule);
default = { }; default = {};
}; };
}; };
config = { config = {
@ -209,15 +223,19 @@ in {
map (file: file.systemd.rules) systemdFiles map (file: file.systemd.rules) systemdFiles
); );
services.tmpfiles = { services.tmpfiles = {
path = [ pkgs.coreutils pkgs.acl ]; path = [pkgs.coreutils pkgs.acl];
script = mkMerge ( script = mkMerge (
[ '' [
EXITCODE=0 ''
'' ] EXITCODE=0
''
]
++ map (file: file.setup.script) setupFiles ++ map (file: file.setup.script) setupFiles
++ [ '' ++ [
exit $EXITCODE ''
'' ] exit $EXITCODE
''
]
); );
wantedBy = [ wantedBy = [
"sysinit.target" "sysinit.target"

View file

@ -13,28 +13,33 @@
userMatchBlock = user: let userMatchBlock = user: let
inherit (user.openssh) matchBlock; inherit (user.openssh) matchBlock;
criteria = mapAttrsToList toSshdCriteria matchBlock.criteria; criteria = mapAttrsToList toSshdCriteria matchBlock.criteria;
in mkAfter '' in
Match ${concatStringsSep " " criteria} mkAfter ''
${matchBlock.settingsConfig} Match ${concatStringsSep " " criteria}
''; ${matchBlock.settingsConfig}
userModule = { config, ... }: let '';
userModule = {config, ...}: let
toSshdValue = value: toSshdValue = value:
if value == true then "yes" if value == true
else if value == false then "no" then "yes"
else if value == false
then "no"
else toString value; else toString value;
toSshdConf = key: value: "${key} ${toSshdValue value}"; toSshdConf = key: value: "${key} ${toSshdValue value}";
in { in {
options = with lib.types; { options = with lib.types; {
openssh.matchBlock = { openssh.matchBlock = {
enable = mkEnableOption "match block" // { enable =
default = config.openssh.matchBlock.settings != { }; mkEnableOption "match block"
}; // {
default = config.openssh.matchBlock.settings != {};
};
criteria = mkOption { criteria = mkOption {
type = attrsOf str; type = attrsOf str;
}; };
settings = mkOption { settings = mkOption {
type = attrsOf (oneOf [ str path bool int ]); type = attrsOf (oneOf [str path bool int]);
default = { }; default = {};
}; };
settingsConfig = mkOption { settingsConfig = mkOption {
type = lines; type = lines;

View file

@ -5,11 +5,20 @@
lib, lib,
... ...
}: let }: let
inherit (lib) mkIf mkMerge mkDefault mkOptionDefault mkOption mkEnableOption types inherit
getExe; (lib)
mkIf
mkMerge
mkDefault
mkOptionDefault
mkOption
mkEnableOption
types
getExe
;
nixosConfig = config; nixosConfig = config;
cfg = config.services.vouch-proxy; cfg = config.services.vouch-proxy;
settingsFormat = pkgs.formats.json { }; settingsFormat = pkgs.formats.json {};
in { in {
options.services.vouch-proxy = with types; { options.services.vouch-proxy = with types; {
enable = mkEnableOption "vouch"; enable = mkEnableOption "vouch";
@ -35,7 +44,7 @@ in {
}; };
enableSettingsSecrets = mkEnableOption "genJqSecretsReplacementSnippet"; enableSettingsSecrets = mkEnableOption "genJqSecretsReplacementSnippet";
settings = let settings = let
settingsModule = { ... }: { settingsModule = {...}: {
freeformType = settingsFormat.type; freeformType = settingsFormat.type;
options = { options = {
vouch = { vouch = {
@ -98,13 +107,14 @@ in {
}; };
}; };
}; };
in mkOption { in
type = submodule settingsModule; mkOption {
default = { }; type = submodule settingsModule;
}; default = {};
};
extraSettings = mkOption { extraSettings = mkOption {
inherit (settingsFormat) type; inherit (settingsFormat) type;
default = { }; default = {};
}; };
settingsPath = mkOption { settingsPath = mkOption {
type = path; type = path;
@ -116,48 +126,51 @@ in {
cfg.settings cfg.settings
cfg.extraSettings cfg.extraSettings
]; ];
settingsPath = if cfg.enableSettingsSecrets settingsPath =
if cfg.enableSettingsSecrets
then "/run/vouch-proxy/vouch-config.json" then "/run/vouch-proxy/vouch-config.json"
else settingsFormat.generate "vouch-config.json" settings; else settingsFormat.generate "vouch-config.json" settings;
in mkMerge [ in
{ mkMerge [
services.vouch-proxy = { {
settingsPath = mkOptionDefault settingsPath; services.vouch-proxy = {
}; settingsPath = mkOptionDefault settingsPath;
} };
(mkIf cfg.enable { }
systemd.services.vouch-proxy = { (mkIf cfg.enable {
description = "Vouch-proxy"; systemd.services.vouch-proxy = {
after = [ "network.target" ]; description = "Vouch-proxy";
wantedBy = [ "multi-user.target" ]; after = ["network.target"];
serviceConfig = { wantedBy = ["multi-user.target"];
ExecStartPre = let serviceConfig = {
preprocess = pkgs.writeShellScript "vouch-proxy-prestart" ( ExecStartPre = let
utils.genJqSecretsReplacementSnippet settings cfg.settingsPath preprocess = pkgs.writeShellScript "vouch-proxy-prestart" (
); utils.genJqSecretsReplacementSnippet settings cfg.settingsPath
in mkIf cfg.enableSettingsSecrets [ );
"${preprocess}" in
]; mkIf cfg.enableSettingsSecrets [
ExecStart = [ "${preprocess}"
"${getExe pkgs.vouch-proxy} -config ${cfg.settingsPath}" ];
]; ExecStart = [
Restart = "on-failure"; "${getExe pkgs.vouch-proxy} -config ${cfg.settingsPath}"
RestartSec = mkDefault 5; ];
WorkingDirectory = "/var/lib/vouch-proxy"; Restart = "on-failure";
StateDirectory = "vouch-proxy"; RestartSec = mkDefault 5;
RuntimeDirectory = "vouch-proxy"; WorkingDirectory = "/var/lib/vouch-proxy";
User = cfg.user; StateDirectory = "vouch-proxy";
Group = cfg.group; RuntimeDirectory = "vouch-proxy";
StartLimitBurst = mkDefault 3; User = cfg.user;
Group = cfg.group;
StartLimitBurst = mkDefault 3;
};
}; };
};
users.users.${cfg.user} = { users.users.${cfg.user} = {
inherit (cfg) group; inherit (cfg) group;
isSystemUser = true; isSystemUser = true;
}; };
users.groups.${cfg.group} = {}; users.groups.${cfg.group} = {};
}) })
]; ];
} }

View file

@ -3,8 +3,7 @@
meta, meta,
lib, lib,
... ...
}: }: let
let
inherit (lib.options) mkOption mkEnableOption; inherit (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkMerge mkBefore mkDefault; inherit (lib.modules) mkIf mkMerge mkBefore mkDefault;
inherit (lib.strings) optionalString concatStringsSep; inherit (lib.strings) optionalString concatStringsSep;
@ -56,18 +55,22 @@ in {
type = str; type = str;
}; };
preread = { preread = {
enable = mkEnableOption "ssl preread" // { enable =
default = true; mkEnableOption "ssl preread"
}; // {
default = true;
};
port = mkOption { port = mkOption {
type = port; type = port;
default = 444; default = 444;
}; };
}; };
kerberos = { kerberos = {
enable = mkEnableOption "proxy kerberos" // { enable =
default = true; mkEnableOption "proxy kerberos"
}; // {
default = true;
};
ports = { ports = {
ticket = mkOption { ticket = mkOption {
type = port; type = port;
@ -86,7 +89,10 @@ in {
proxyPass = mkOption { proxyPass = mkOption {
type = str; type = str;
default = let default = let
scheme = if access.port == 443 then "https" else "http"; scheme =
if access.port == 443
then "https"
else "http";
in "${scheme}://${access.host}:${toString access.port}"; in "${scheme}://${access.host}:${toString access.port}";
}; };
domain = mkOption { domain = mkOption {
@ -130,7 +136,7 @@ in {
port = mkDefault access.ldapPort; port = mkDefault access.ldapPort;
useACMEHost = mkDefault access.useACMEHost; useACMEHost = mkDefault access.useACMEHost;
}; };
resolver.addresses = mkIf access.preread.enable [ "[::1]" "127.0.0.1:5353" ]; resolver.addresses = mkIf access.preread.enable ["[::1]" "127.0.0.1:5353"];
defaultSSLListenPort = mkIf access.preread.enable access.preread.port; defaultSSLListenPort = mkIf access.preread.enable access.preread.port;
streamConfig = let streamConfig = let
preread = '' preread = ''
@ -174,10 +180,11 @@ in {
proxy_pass ${access.host}:${toString access.kerberos.ports.kpasswd}; proxy_pass ${access.host}:${toString access.kerberos.ports.kpasswd};
} }
''; '';
in mkMerge [ in
(mkIf access.preread.enable preread) mkMerge [
(mkIf access.kerberos.enable kerberos) (mkIf access.preread.enable preread)
]; (mkIf access.kerberos.enable kerberos)
];
virtualHosts = { virtualHosts = {
${access.domain} = { ${access.domain} = {
inherit locations extraConfig; inherit locations extraConfig;
@ -207,7 +214,7 @@ in {
local.enable = true; local.enable = true;
inherit locations; inherit locations;
}; };
${ldap.domain} = { config, ... }: { ${ldap.domain} = {config, ...}: {
useACMEHost = mkDefault virtualHosts.${access.domain}.useACMEHost; useACMEHost = mkDefault virtualHosts.${access.domain}.useACMEHost;
addSSL = mkDefault (config.useACMEHost != null); addSSL = mkDefault (config.useACMEHost != null);
globalRedirect = access.domain; globalRedirect = access.domain;

View file

@ -12,9 +12,11 @@
freepbx = config.lib.access.systemFor "freepbx"; freepbx = config.lib.access.systemFor "freepbx";
in { in {
options.services.nginx.access.freepbx = with lib.types; { options.services.nginx.access.freepbx = with lib.types; {
global.enable = mkEnableOption "global access" // { global.enable =
default = access.useACMEHost != null; mkEnableOption "global access"
}; // {
default = access.useACMEHost != null;
};
host = mkOption { host = mkOption {
type = str; type = str;
default = freepbx.access.hostnameForNetwork.local; default = freepbx.access.hostnameForNetwork.local;
@ -94,17 +96,19 @@ in {
}; };
"${access.domain}@ucp" = { "${access.domain}@ucp" = {
serverName = access.domain; serverName = access.domain;
listen = concatMap (addr: [ listen =
{ concatMap (addr: [
inherit addr; {
port = access.ucpPort; inherit addr;
} port = access.ucpPort;
(mkIf (access.useACMEHost != null) { }
inherit addr; (mkIf (access.useACMEHost != null) {
port = access.ucpSslPort; inherit addr;
ssl = true; port = access.ucpSslPort;
}) ssl = true;
]) nginx.defaultListenAddresses; })
])
nginx.defaultListenAddresses;
proxy.websocket.enable = true; proxy.websocket.enable = true;
local.enable = mkDefault (!access.global.enable); local.enable = mkDefault (!access.global.enable);
addSSL = mkDefault (access.useACMEHost != null); addSSL = mkDefault (access.useACMEHost != null);
@ -116,27 +120,29 @@ in {
inherit extraConfig; inherit extraConfig;
}; };
${access.localDomain} = { ${access.localDomain} = {
listen = concatMap (addr: [ listen =
{ concatMap (addr: [
inherit addr; {
port = nginx.defaultHTTPListenPort; inherit addr;
} port = nginx.defaultHTTPListenPort;
{ }
inherit addr; {
port = access.ucpPort; inherit addr;
} port = access.ucpPort;
(mkIf (access.useACMEHost != null) { }
inherit addr; (mkIf (access.useACMEHost != null) {
port = nginx.defaultSSLListenPort; inherit addr;
ssl = true; port = nginx.defaultSSLListenPort;
}) ssl = true;
(mkIf (access.useACMEHost != null) { })
inherit addr; (mkIf (access.useACMEHost != null) {
port = access.ucpSslPort; inherit addr;
ssl = true; port = access.ucpSslPort;
}) ssl = true;
]) nginx.defaultListenAddresses; })
serverAliases = mkIf tailscale.enable [ access.tailDomain ]; ])
nginx.defaultListenAddresses;
serverAliases = mkIf tailscale.enable [access.tailDomain];
useACMEHost = mkDefault access.useACMEHost; useACMEHost = mkDefault access.useACMEHost;
addSSL = mkDefault (access.useACMEHost != null); addSSL = mkDefault (access.useACMEHost != null);
kTLS = mkDefault true; kTLS = mkDefault true;
@ -146,7 +152,7 @@ in {
}; };
}; };
config.networking.firewall = let config.networking.firewall = let
websocketPorts = [ access.ucpPort ] ++ optional (access.useACMEHost != null) access.ucpSslPort; websocketPorts = [access.ucpPort] ++ optional (access.useACMEHost != null) access.ucpSslPort;
in { in {
interfaces.local.allowedTCPPorts = websocketPorts; interfaces.local.allowedTCPPorts = websocketPorts;
allowedTCPPorts = mkIf access.global.enable websocketPorts; allowedTCPPorts = mkIf access.global.enable websocketPorts;

View file

@ -1,7 +1,4 @@
{ {lib, ...}: let
lib,
...
}: let
inherit (lib.modules) mkDefault; inherit (lib.modules) mkDefault;
in { in {
networking = { networking = {

View file

@ -34,12 +34,14 @@ in {
url = mkOptionDefault "http://localhost:${toString cfg.port}"; url = mkOptionDefault "http://localhost:${toString cfg.port}";
}; };
virtualHosts = let virtualHosts = let
invidiousDomains = [ invidiousDomains =
access.domain [
access.localDomain access.domain
] ++ optional tailscale.enable access.tailDomain; access.localDomain
]
++ optional tailscale.enable access.tailDomain;
contentSecurityPolicy' = "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; connect-src 'self'; manifest-src 'self'; media-src 'self' blob: https://*.googlevideo.com:443 https://*.youtube.com:443; child-src 'self' blob:; frame-src 'self'; frame-ancestors 'none'"; contentSecurityPolicy' = "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; connect-src 'self'; manifest-src 'self'; media-src 'self' blob: https://*.googlevideo.com:443 https://*.youtube.com:443; child-src 'self' blob:; frame-src 'self'; frame-ancestors 'none'";
contentSecurityPolicy = replaceStrings [ "'self'" ] [ "'self' ${concatStringsSep " " invidiousDomains}" ] contentSecurityPolicy'; contentSecurityPolicy = replaceStrings ["'self'"] ["'self' ${concatStringsSep " " invidiousDomains}"] contentSecurityPolicy';
extraConfig = '' extraConfig = ''
# Some players don't reopen a socket and playback stops totally instead of resuming after an extended pause # Some players don't reopen a socket and playback stops totally instead of resuming after an extended pause
send_timeout 100m; send_timeout 100m;
@ -56,14 +58,14 @@ in {
''; '';
}; };
in { in {
${access.domain} = { config, ... }: { ${access.domain} = {config, ...}: {
vouch.enable = true; vouch.enable = true;
locations."/" = location; locations."/" = location;
kTLS = mkDefault true; kTLS = mkDefault true;
inherit extraConfig; inherit extraConfig;
}; };
${access.localDomain} = { config, ... }: { ${access.localDomain} = {config, ...}: {
serverAliases = mkIf tailscale.enable [ access.tailDomain ]; serverAliases = mkIf tailscale.enable [access.tailDomain];
local.enable = true; local.enable = true;
locations."/" = mkMerge [ locations."/" = mkMerge [
location location

View file

@ -3,8 +3,7 @@
meta, meta,
lib, lib,
... ...
}: }: let
let
inherit (lib.options) mkOption; inherit (lib.options) mkOption;
inherit (lib.modules) mkIf mkMerge mkDefault mkOptionDefault; inherit (lib.modules) mkIf mkMerge mkDefault mkOptionDefault;
inherit (config) networking; inherit (config) networking;

View file

@ -64,39 +64,47 @@ in {
inherit extraConfig; inherit extraConfig;
}; };
}; };
streamListen = { config, ... }: { streamListen = {config, ...}: {
listen = concatMap (addr: [ listen =
(mkIf config.addSSL { concatMap (addr: [
inherit addr; (mkIf config.addSSL {
port = nginx.defaultSSLListenPort; inherit addr;
ssl = true; port = nginx.defaultSSLListenPort;
}) ssl = true;
{ })
inherit addr; {
port = nginx.defaultHTTPListenPort; inherit addr;
} port = nginx.defaultHTTPListenPort;
{ }
inherit addr; {
port = access.streamPort; inherit addr;
} port = access.streamPort;
]) nginx.defaultListenAddresses; }
])
nginx.defaultListenAddresses;
}; };
in { in {
${access.domain} = mkMerge [ { ${access.domain} = mkMerge [
vouch.enable = true; {
kTLS = mkDefault true; vouch.enable = true;
inherit (access) useACMEHost; kTLS = mkDefault true;
addSSL = mkDefault (access.useACMEHost != null); inherit (access) useACMEHost;
inherit locations; addSSL = mkDefault (access.useACMEHost != null);
} streamListen ]; inherit locations;
${access.localDomain} = mkMerge [ { }
serverAliases = mkIf config.services.tailscale.enable [ access.tailDomain ]; streamListen
inherit (virtualHosts.${access.domain}) useACMEHost; ];
addSSL = mkDefault addSSL; ${access.localDomain} = mkMerge [
kTLS = mkDefault true; {
local.enable = true; serverAliases = mkIf config.services.tailscale.enable [access.tailDomain];
inherit locations; inherit (virtualHosts.${access.domain}) useACMEHost;
} streamListen ]; addSSL = mkDefault addSSL;
kTLS = mkDefault true;
local.enable = true;
inherit locations;
}
streamListen
];
}; };
}; };
config.networking.firewall.allowedTCPPorts = [ config.networking.firewall.allowedTCPPorts = [

View file

@ -2,8 +2,7 @@
config, config,
lib, lib,
... ...
}: }: let
let
inherit (lib.options) mkOption mkEnableOption; inherit (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkMerge; inherit (lib.modules) mkIf mkMerge;
inherit (lib.strings) concatMapStringsSep optionalString; inherit (lib.strings) concatMapStringsSep optionalString;
@ -18,9 +17,11 @@ let
cidrForNetwork.loopback.all cidrForNetwork.loopback.all
++ cidrForNetwork.local.all ++ cidrForNetwork.local.all
++ optionals tailscale.enable cidrForNetwork.tail.all; ++ optionals tailscale.enable cidrForNetwork.tail.all;
allows = concatMapStringsSep "\n" mkAllow allowAddresses + optionalString localaddrs.enable '' allows =
include ${localaddrs.stateDir}/*.nginx.conf; concatMapStringsSep "\n" mkAllow allowAddresses
''; + optionalString localaddrs.enable ''
include ${localaddrs.stateDir}/*.nginx.conf;
'';
in '' in ''
${allows} ${allows}
deny all; deny all;
@ -61,28 +62,29 @@ in {
proxy_ssl on; proxy_ssl on;
proxy_ssl_verify off; proxy_ssl_verify off;
''; '';
in mkIf access.enable (mkMerge [ in
'' mkIf access.enable (mkMerge [
server { ''
listen 0.0.0.0:389; server {
listen [::]:389; listen 0.0.0.0:389;
${allows} listen [::]:389;
proxy_pass ${proxyPass}; ${allows}
${proxySsl} proxy_pass ${proxyPass};
} ${proxySsl}
'' }
(mkIf (access.useACMEHost != null) '' ''
server { (mkIf (access.useACMEHost != null) ''
listen 0.0.0.0:636 ssl; server {
listen [::]:636 ssl; listen 0.0.0.0:636 ssl;
ssl_certificate ${cert.directory}/fullchain.pem; listen [::]:636 ssl;
ssl_certificate_key ${cert.directory}/key.pem; ssl_certificate ${cert.directory}/fullchain.pem;
ssl_trusted_certificate ${cert.directory}/chain.pem; ssl_certificate_key ${cert.directory}/key.pem;
proxy_pass ${proxyPass}; ssl_trusted_certificate ${cert.directory}/chain.pem;
${proxySsl} proxy_pass ${proxyPass};
} ${proxySsl}
'') }
]); '')
]);
}; };
networking.firewall = { networking.firewall = {

View file

@ -70,10 +70,12 @@ in {
plex-external = mkIf (access.externalPort != null) { plex-external = mkIf (access.externalPort != null) {
serverName = mkDefault access.domain; serverName = mkDefault access.domain;
default = mkDefault true; default = mkDefault true;
listen = map (addr: { listen =
inherit addr; map (addr: {
port = access.externalPort; inherit addr;
}) nginx.defaultListenAddresses; port = access.externalPort;
})
nginx.defaultListenAddresses;
locations."/" = location; locations."/" = location;
inherit extraConfig; inherit extraConfig;
}; };

View file

@ -14,10 +14,11 @@
proxyPass = "https://reisen.local.${config.networking.domain}:8006/"; proxyPass = "https://reisen.local.${config.networking.domain}:8006/";
unencrypted = mkSnakeOil { unencrypted = mkSnakeOil {
name = "prox-local-cert"; name = "prox-local-cert";
domain = singleton "prox.local.${config.networking.domain}" domain =
singleton "prox.local.${config.networking.domain}"
++ optional tailscale.enable "prox.tail.${config.networking.domain}"; ++ optional tailscale.enable "prox.tail.${config.networking.domain}";
}; };
sslHost = { config, ... }: { sslHost = {config, ...}: {
sslCertificate = mkIf (!config.enableACME && config.useACMEHost == null) unencrypted.fullchain; sslCertificate = mkIf (!config.enableACME && config.useACMEHost == null) unencrypted.fullchain;
sslCertificateKey = mkIf (!config.enableACME && config.useACMEHost == null) unencrypted.key; sslCertificateKey = mkIf (!config.enableACME && config.useACMEHost == null) unencrypted.key;
}; };
@ -91,24 +92,30 @@ in {
${access.domain} = { ${access.domain} = {
inherit locations extraConfig; inherit locations extraConfig;
}; };
${access.localDomain} = mkMerge [ { ${access.localDomain} = mkMerge [
inherit (virtualHosts.${access.domain}) useACMEHost; {
local.enable = mkDefault true; inherit (virtualHosts.${access.domain}) useACMEHost;
forceSSL = mkDefault true; local.enable = mkDefault true;
locations."/" = { forceSSL = mkDefault true;
proxy.websocket.enable = true; locations."/" = {
inherit proxyPass extraConfig; proxy.websocket.enable = true;
}; inherit proxyPass extraConfig;
} sslHost ]; };
${access.tailDomain} = mkIf tailscale.enable (mkMerge [ { }
inherit (virtualHosts.${access.domain}) useACMEHost; sslHost
addSSL = mkDefault true; ];
local.enable = mkDefault true; ${access.tailDomain} = mkIf tailscale.enable (mkMerge [
locations."/" = { {
proxy.websocket.enable = true; inherit (virtualHosts.${access.domain}) useACMEHost;
inherit proxyPass extraConfig; addSSL = mkDefault true;
}; local.enable = mkDefault true;
} sslHost ]); locations."/" = {
proxy.websocket.enable = true;
inherit proxyPass extraConfig;
};
}
sslHost
]);
}; };
config.sops.secrets.access-proxmox = { config.sops.secrets.access-proxmox = {

View file

@ -10,9 +10,11 @@
in { in {
options.services.nginx.access.unifi = with lib.types; { options.services.nginx.access.unifi = with lib.types; {
global = { global = {
enable = mkEnableOption "global access" // { enable =
default = access.useACMEHost != null; mkEnableOption "global access"
}; // {
default = access.useACMEHost != null;
};
management = mkEnableOption "global management port access"; management = mkEnableOption "global management port access";
}; };
host = mkOption { host = mkOption {
@ -59,11 +61,13 @@ in {
}; };
in { in {
"${access.domain}@management" = mkIf access.global.management { "${access.domain}@management" = mkIf access.global.management {
listen = map (addr: { listen =
inherit addr; map (addr: {
port = access.managementPort; inherit addr;
ssl = true; port = access.managementPort;
}) nginx.defaultListenAddresses; ssl = true;
})
nginx.defaultListenAddresses;
serverName = access.domain; serverName = access.domain;
default = mkDefault true; default = mkDefault true;
forceSSL = mkDefault true; forceSSL = mkDefault true;
@ -81,7 +85,7 @@ in {
inherit locations extraConfig; inherit locations extraConfig;
}; };
${access.localDomain} = { ${access.localDomain} = {
serverAliases = mkIf tailscale.enable [ access.tailDomain ]; serverAliases = mkIf tailscale.enable [access.tailDomain];
useACMEHost = mkDefault access.useACMEHost; useACMEHost = mkDefault access.useACMEHost;
addSSL = mkDefault (access.useACMEHost != null); addSSL = mkDefault (access.useACMEHost != null);
kTLS = mkDefault true; kTLS = mkDefault true;
@ -91,7 +95,7 @@ in {
}; };
}; };
config.networking.firewall = { config.networking.firewall = {
interfaces.local.allowedTCPPorts = [ access.managementPort ]; interfaces.local.allowedTCPPorts = [access.managementPort];
allowedTCPPorts = mkIf access.global.management [ access.managementPort ]; allowedTCPPorts = mkIf access.global.management [access.managementPort];
}; };
} }

View file

@ -35,8 +35,12 @@ in {
access.vouch = mkIf cfg.enable { access.vouch = mkIf cfg.enable {
url = let url = let
inherit (cfg.settings.vouch) listen; inherit (cfg.settings.vouch) listen;
host = if listen == "0.0.0.0" || listen == "[::]" then "localhost" else listen; host =
in mkOptionDefault "http://${host}:${toString cfg.port}"; if listen == "0.0.0.0" || listen == "[::]"
then "localhost"
else listen;
in
mkOptionDefault "http://${host}:${toString cfg.port}";
}; };
virtualHosts = let virtualHosts = let
locations = { locations = {
@ -46,17 +50,20 @@ in {
proxy_redirect default; proxy_redirect default;
''; '';
}; };
"/validate" = { config, ... }: { "/validate" = {config, ...}: {
proxyPass = mkDefault (access.url + "/validate"); proxyPass = mkDefault (access.url + "/validate");
recommendedProxySettings = mkDefault false; recommendedProxySettings = mkDefault false;
extraConfig = if config.local.trusted then '' extraConfig =
if ($http_x_host = ''') { if config.local.trusted
set $http_x_host $host; then ''
} if ($http_x_host = ''') {
proxy_set_header Host $http_x_host; set $http_x_host $host;
'' else '' }
proxy_set_header Host $host; proxy_set_header Host $http_x_host;
''; ''
else ''
proxy_set_header Host $host;
'';
}; };
}; };
localLocations = kanidmDomain: { localLocations = kanidmDomain: {

View file

@ -2,8 +2,7 @@
config, config,
lib, lib,
... ...
}: }: let
let
inherit (lib.options) mkOption; inherit (lib.options) mkOption;
inherit (lib.modules) mkIf mkDefault mkOptionDefault; inherit (lib.modules) mkIf mkDefault mkOptionDefault;
cfg = config.services.zigbee2mqtt; cfg = config.services.zigbee2mqtt;
@ -46,7 +45,7 @@ in {
locations."/" = location; locations."/" = location;
}; };
${access.localDomain} = { ${access.localDomain} = {
serverAliases = mkIf config.services.tailscale.enable [ access.tailDomain ]; serverAliases = mkIf config.services.tailscale.enable [access.tailDomain];
local.enable = true; local.enable = true;
locations."/" = location; locations."/" = location;
}; };

View file

@ -8,18 +8,30 @@
inherit (lib.lists) head optional; inherit (lib.lists) head optional;
cfg = config.security.acme; cfg = config.security.acme;
mkHash = with builtins; val: substring 0 20 (hashString "sha256" val); mkHash = with builtins; val: substring 0 20 (hashString "sha256" val);
mkAccountHash = { server ? null, keyType, email }: mkHash "${toString server} ${keyType} ${email}"; mkAccountHash = {
server ? null,
keyType,
email,
}:
mkHash "${toString server} ${keyType} ${email}";
mkHost = server: head (splitString "/" (removePrefix "https://" server)); mkHost = server: head (splitString "/" (removePrefix "https://" server));
mkAccountDir = { server ? null, email, keyType }: concatStringsSep "/" ([ mkAccountDir = {
accountDirRoot server ? null,
(mkAccountHash { inherit server email keyType; }) email,
] ++ optional (server != null) ( keyType,
mkHost server }:
) ++ [ concatStringsSep "/" ([
cfg.defaults.email accountDirRoot
]); (mkAccountHash {inherit server email keyType;})
]
++ optional (server != null) (
mkHost server
)
++ [
cfg.defaults.email
]);
accountDirRoot = "/var/lib/acme/.lego/accounts"; accountDirRoot = "/var/lib/acme/.lego/accounts";
addr = concatStringsSep "@" [ "gensokyo" "arcn.mx" ]; addr = concatStringsSep "@" ["gensokyo" "arcn.mx"];
in { in {
security.acme = { security.acme = {
acceptTerms = true; acceptTerms = true;
@ -35,16 +47,19 @@ in {
}; };
}; };
sops.secrets = let sops.secrets = let
accountDir = mkAccountDir { inherit (cfg.defaults) server email keyType; }; accountDir = mkAccountDir {inherit (cfg.defaults) server email keyType;};
acmeSecret = { acmeSecret = {
sopsFile = mkDefault ./secrets/acme.yaml; sopsFile = mkDefault ./secrets/acme.yaml;
owner = "acme"; owner = "acme";
group = "nginx"; group = "nginx";
}; };
in { in {
acme_account_key = mkMerge [ acmeSecret { acme_account_key = mkMerge [
path = accountDir + "/keys/${cfg.defaults.email}.key"; acmeSecret
} ]; {
path = accountDir + "/keys/${cfg.defaults.email}.key";
}
];
acme_cloudflare_email = acmeSecret; acme_cloudflare_email = acmeSecret;
acme_cloudflare_token = acmeSecret; acme_cloudflare_token = acmeSecret;
}; };

View file

@ -26,7 +26,7 @@ in {
daemon = "avahi-daemon.service"; daemon = "avahi-daemon.service";
avahi-daemon-watchdog = pkgs.writeShellScript "avahi-daemon-watchdog" '' avahi-daemon-watchdog = pkgs.writeShellScript "avahi-daemon-watchdog" ''
set -eu set -eu
export PATH="$PATH:${makeBinPath [ config.systemd.package pkgs.coreutils pkgs.gnugrep ]}" export PATH="$PATH:${makeBinPath [config.systemd.package pkgs.coreutils pkgs.gnugrep]}"
while read -r line; do while read -r line; do
if [[ $line = *"Host name conflict"* ]]; then if [[ $line = *"Host name conflict"* ]]; then
if systemctl is-active ${daemon} > /dev/null; then if systemctl is-active ${daemon} > /dev/null; then
@ -38,22 +38,23 @@ in {
fi fi
done < <(journalctl -o cat -feu ${daemon} | grep -F 'Host name conflict, retrying with ') done < <(journalctl -o cat -feu ${daemon} | grep -F 'Host name conflict, retrying with ')
''; '';
in mkIf (cfg.enable && cfg.publish.enable) { in
avahi-daemon = { mkIf (cfg.enable && cfg.publish.enable) {
serviceConfig = { avahi-daemon = {
inherit RestartSec; serviceConfig = {
inherit RestartSec;
};
};
avahi-daemon-watchdog = {
wantedBy = [daemon];
serviceConfig = {
Type = mkOptionDefault "exec";
ExecStart = [
"${avahi-daemon-watchdog}"
];
Restart = mkOptionDefault "on-failure";
RestartSec = mkOptionDefault RestartSec;
};
}; };
}; };
avahi-daemon-watchdog = {
wantedBy = [ daemon ];
serviceConfig = {
Type = mkOptionDefault "exec";
ExecStart = [
"${avahi-daemon-watchdog}"
];
Restart = mkOptionDefault "on-failure";
RestartSec = mkOptionDefault RestartSec;
};
};
};
} }

View file

@ -28,12 +28,11 @@
users.users.root = { users.users.root = {
hashedPassword = "$6$i28yOXoo$/WokLdKds5ZHtJHcuyGrH2WaDQQk/2Pj0xRGLgS8UcmY2oMv3fw2j/85PRpsJJwCB2GBRYRK5LlvdTleHd3mB."; hashedPassword = "$6$i28yOXoo$/WokLdKds5ZHtJHcuyGrH2WaDQQk/2Pj0xRGLgS8UcmY2oMv3fw2j/85PRpsJJwCB2GBRYRK5LlvdTleHd3mB.";
openssh.authorizedKeys.keys = with pkgs.lib; openssh.authorizedKeys.keys = with pkgs.lib; (concatLists (mapAttrsToList
(concatLists (mapAttrsToList (name: user:
(name: user: if elem "wheel" user.extraGroups
if elem "wheel" user.extraGroups then user.openssh.authorizedKeys.keys
then user.openssh.authorizedKeys.keys else [])
else []) config.users.users));
config.users.users));
}; };
} }

View file

@ -1,3 +1,3 @@
{ config, ... }: { {config, ...}: {
documentation.nixos.enable = false; documentation.nixos.enable = false;
} }

View file

@ -1,5 +1,7 @@
{ config, pkgs, ... }:
{ {
environment.systemPackages = [ pkgs.buildPackages.buildPackages.kitty.terminfo ]; config,
pkgs,
...
}: {
environment.systemPackages = [pkgs.buildPackages.buildPackages.kitty.terminfo];
} }

View file

@ -1,4 +1,10 @@
{ config, options, lib, inputs, ... }: let {
config,
options,
lib,
inputs,
...
}: let
inherit (lib.modules) mkIf mkDefault; inherit (lib.modules) mkIf mkDefault;
hasSops = options ? sops; hasSops = options ? sops;
in { in {
@ -25,7 +31,8 @@ in {
experimental-features = lib.optional (lib.versionAtLeast config.nix.package.version "2.4") "nix-command flakes"; experimental-features = lib.optional (lib.versionAtLeast config.nix.package.version "2.4") "nix-command flakes";
substituters = [ substituters = [
"https://gensokyo-infrastructure.cachix.org" "https://gensokyo-infrastructure.cachix.org"
"https://arc.cachix.org" "https://kittywitch.cachix.org" "https://arc.cachix.org"
"https://kittywitch.cachix.org"
"https://nix-community.cachix.org" "https://nix-community.cachix.org"
]; ];
trusted-public-keys = [ trusted-public-keys = [
@ -36,7 +43,7 @@ in {
"ryantrinkle.com-1:JJiAKaRv9mWgpVAz8dwewnZe0AzzEAzPkagE9SP5NWI=" "ryantrinkle.com-1:JJiAKaRv9mWgpVAz8dwewnZe0AzzEAzPkagE9SP5NWI="
]; ];
auto-optimise-store = true; auto-optimise-store = true;
trusted-users = [ "root" "@wheel" ]; trusted-users = ["root" "@wheel"];
}; };
extraOptions = mkIf hasSops '' extraOptions = mkIf hasSops ''
!include ${config.sops.secrets.github-access-token-public.path} !include ${config.sops.secrets.github-access-token-public.path}
@ -47,7 +54,11 @@ in {
options = mkDefault "--delete-older-than 7d"; options = mkDefault "--delete-older-than 7d";
}; };
}; };
${if hasSops then "sops" else null}.secrets.github-access-token-public = { ${
if hasSops
then "sops"
else null
}.secrets.github-access-token-public = {
sopsFile = mkDefault ../secrets/nix.yaml; sopsFile = mkDefault ../secrets/nix.yaml;
group = mkDefault "users"; group = mkDefault "users";
mode = mkDefault "0644"; mode = mkDefault "0644";

View file

@ -1,7 +1,4 @@
{ {inputs, ...}: {
inputs,
...
}: {
nixpkgs = { nixpkgs = {
overlays = [ overlays = [
inputs.arcexprs.overlays.default inputs.arcexprs.overlays.default

View file

@ -1,11 +1,16 @@
{ config, lib, pkgs, ... }:
{ {
environment.systemPackages = with pkgs; [ config,
neofetch lib,
smartmontools pkgs,
hddtemp ...
lm_sensors }: {
gnupg environment.systemPackages = with pkgs;
] ++ (lib.optional config.programs.gnupg.agent.enable pinentry-curses); [
neofetch
smartmontools
hddtemp
lm_sensors
gnupg
]
++ (lib.optional config.programs.gnupg.agent.enable pinentry-curses);
} }

View file

@ -1,6 +1,4 @@
{ config, ... }: {config, ...}: {
{
programs.zsh = { programs.zsh = {
enable = true; enable = true;
enableCompletion = true; enableCompletion = true;

View file

@ -29,7 +29,7 @@ in {
}; };
networking.firewall = { networking.firewall = {
allowedTCPPorts = [publicPort]; allowedTCPPorts = [publicPort];
interfaces.local.allowedTCPPorts = [ 22 ]; interfaces.local.allowedTCPPorts = [22];
}; };
programs.mosh.enable = true; programs.mosh.enable = true;

View file

@ -1,3 +1,3 @@
{ config, ... }: { {config, ...}: {
services.tzupdate.enable = true; services.tzupdate.enable = true;
} }

View file

@ -1,6 +1,4 @@
{ pkgs, ... }: {pkgs, ...}: {
{
environment.systemPackages = [ environment.systemPackages = [
pkgs.buildPackages.rxvt-unicode-unwrapped.terminfo pkgs.buildPackages.rxvt-unicode-unwrapped.terminfo
]; ];

View file

@ -1,12 +1,9 @@
{ {lib, ...}: let
lib,
...
}: let
inherit (lib.modules) mkDefault; inherit (lib.modules) mkDefault;
in { in {
services.bazarr = { services.bazarr = {
enable = mkDefault true; enable = mkDefault true;
listenPort = mkDefault 6767; listenPort = mkDefault 6767;
}; };
users.users.bazarr.extraGroups = [ "kyuuto" ]; users.users.bazarr.extraGroups = ["kyuuto"];
} }

View file

@ -14,26 +14,30 @@ in {
protocol = mkDefault "cloudflare"; protocol = mkDefault "cloudflare";
zone = mkDefault config.networking.domain; zone = mkDefault config.networking.domain;
use = "no"; use = "no";
domains = [ ]; domains = [];
extraConfig = mkMerge [ (mkIf config.networking.enableIPv6 '' extraConfig = mkMerge [
usev6=webv6, webv6=https://ipv6.nsupdate.info/myip (mkIf config.networking.enableIPv6 ''
'') '' usev6=webv6, webv6=https://ipv6.nsupdate.info/myip
usev4=webv4, webv4=https://ipv4.nsupdate.info/myip '')
max-interval=1d ''
'' ]; usev4=webv4, webv4=https://ipv4.nsupdate.info/myip
max-interval=1d
''
];
passwordFile = config.sops.secrets.dyndns_cloudflare_token.path; passwordFile = config.sops.secrets.dyndns_cloudflare_token.path;
}; };
systemd.services.ddclient = mkIf cfg.enable rec { systemd.services.ddclient = mkIf cfg.enable rec {
wants = [ "network-online.target" ]; wants = ["network-online.target"];
after = wants; after = wants;
wantedBy = mkForce [ ]; wantedBy = mkForce [];
serviceConfig = { serviceConfig = {
ExecStartPre = let ExecStartPre = let
inherit (config.systemd.services.ddclient.serviceConfig) RuntimeDirectory; inherit (config.systemd.services.ddclient.serviceConfig) RuntimeDirectory;
prestart-domains = pkgs.writeShellScript "ddclient-prestart-domains" '' prestart-domains = pkgs.writeShellScript "ddclient-prestart-domains" ''
cat ${config.sops.secrets.dyndns_ddclient_domains.path} >> /run/${RuntimeDirectory}/ddclient.conf cat ${config.sops.secrets.dyndns_ddclient_domains.path} >> /run/${RuntimeDirectory}/ddclient.conf
''; '';
in mkAfter [ "!${prestart-domains}" ]; in
mkAfter ["!${prestart-domains}"];
TimeoutStartSec = 90; TimeoutStartSec = 90;
LogFilterPatterns = [ LogFilterPatterns = [
"~WARNING" "~WARNING"

View file

@ -42,28 +42,32 @@ in {
parent = builtins.dirOf downloadDir; parent = builtins.dirOf downloadDir;
hasCompletedSubdir = completedDir != null && hasPrefix parent completedDir; hasCompletedSubdir = completedDir != null && hasPrefix parent completedDir;
completedSubdir = removePrefix parent completedDir; completedSubdir = removePrefix parent completedDir;
download = if hasCompletedSubdir then { download =
path = parent; if hasCompletedSubdir
subdirectories = [ then {
(builtins.baseNameOf downloadDir) path = parent;
completedSubdir subdirectories = [
]; (builtins.baseNameOf downloadDir)
} else { completedSubdir
path = downloadDir; ];
}; }
else {
path = downloadDir;
};
completed = { completed = {
path = cfg.config.move_completed_path; path = cfg.config.move_completed_path;
}; };
in mkIf cfg.enable (mkAfter [ in
download mkIf cfg.enable (mkAfter [
(mkIf (completedDir != null && !hasCompletedSubdir) completed) download
]); (mkIf (completedDir != null && !hasCompletedSubdir) completed)
]);
users.users = mkIf cfg.enable (mkMerge [ users.users = mkIf cfg.enable (mkMerge [
{ {
deluge.extraGroups = [ "kyuuto" ]; deluge.extraGroups = ["kyuuto"];
} }
(mkIf mediatomb.enable { (mkIf mediatomb.enable {
${mediatomb.user}.extraGroups = [ cfg.group ]; ${mediatomb.user}.extraGroups = [cfg.group];
}) })
]); ]);
} }

View file

@ -14,9 +14,11 @@
genZoneAttrs = prefix: f: listToAttrs (genZone (i: nameValuePair "${prefix}${toString i}" (f i))); genZoneAttrs = prefix: f: listToAttrs (genZone (i: nameValuePair "${prefix}${toString i}" (f i)));
in { in {
options.services.github-runner-zone = with lib.types; { options.services.github-runner-zone = with lib.types; {
enable = mkEnableOption "github-runners.zone" // { enable =
default = true; mkEnableOption "github-runners.zone"
}; // {
default = true;
};
targetName = mkOption { targetName = mkOption {
type = str; type = str;
default = "github-runner-zone"; default = "github-runner-zone";
@ -64,7 +66,7 @@ in {
enable = mkDefault true; enable = mkDefault true;
ephemeral = mkDefault cfg.ephemeral; ephemeral = mkDefault cfg.ephemeral;
replace = mkDefault true; replace = mkDefault true;
extraLabels = [ "ubuntu-latest" ]; extraLabels = ["ubuntu-latest"];
tokenFile = mkDefault config.sops.secrets.github-runner-gensokyo-zone-token.path; tokenFile = mkDefault config.sops.secrets.github-runner-gensokyo-zone-token.path;
url = mkDefault "https://github.com/gensokyo-zone"; url = mkDefault "https://github.com/gensokyo-zone";
group = mkDefault cfg.group; group = mkDefault cfg.group;
@ -73,9 +75,9 @@ in {
}; };
networkNamespace.name = mkIf (cfg.networkNamespace.name != null) (mkDefault cfg.networkNamespace.name); networkNamespace.name = mkIf (cfg.networkNamespace.name != null) (mkDefault cfg.networkNamespace.name);
serviceSettings = { serviceSettings = {
wantedBy = [ "${cfg.targetName}.target" ]; wantedBy = ["${cfg.targetName}.target"];
unitConfig = { unitConfig = {
StopPropagatedFrom = [ "${cfg.targetName}.target" ]; StopPropagatedFrom = ["${cfg.targetName}.target"];
}; };
}; };
serviceOverrides = mkIf (!cfg.dynamicUser) { serviceOverrides = mkIf (!cfg.dynamicUser) {
@ -88,15 +90,16 @@ in {
}; };
}; };
services.github-runners = genZoneAttrs cfg.keyPrefix (i: mkMerge [ services.github-runners = genZoneAttrs cfg.keyPrefix (i:
(unmerged.merge cfg.runnerSettings) mkMerge [
{ (unmerged.merge cfg.runnerSettings)
name = mkDefault "${cfg.namePrefix}${toString i}"; {
user = mkIf (cfg.userPrefix != null) ( name = mkDefault "${cfg.namePrefix}${toString i}";
mkDefault "${cfg.userPrefix}${toString i}" user = mkIf (cfg.userPrefix != null) (
); mkDefault "${cfg.userPrefix}${toString i}"
} );
]); }
]);
systemd = mkIf cfg.enable { systemd = mkIf cfg.enable {
services.nix-daemon = mkIf cfg.enable { services.nix-daemon = mkIf cfg.enable {
@ -106,13 +109,13 @@ in {
}; };
}; };
targets.${cfg.targetName} = { targets.${cfg.targetName} = {
wantedBy = [ "multi-user.target" ]; wantedBy = ["multi-user.target"];
}; };
}; };
users = mkIf cfg.enable { users = mkIf cfg.enable {
groups = mkIf (cfg.group != null) { groups = mkIf (cfg.group != null) {
${toString cfg.group} = { }; ${toString cfg.group} = {};
}; };
users = mkMerge [ users = mkMerge [
(mkIf (!cfg.dynamicUser) (genZoneAttrs cfg.userPrefix (i: { (mkIf (!cfg.dynamicUser) (genZoneAttrs cfg.userPrefix (i: {

View file

@ -85,17 +85,19 @@ in {
]; ];
entity_config = {}; entity_config = {};
}; };
homekit = [ { homekit = [
name = "Tewi"; {
port = 21063; name = "Tewi";
filter = let port = 21063;
inherit (cfg.config) google_assistant; filter = let
in { inherit (cfg.config) google_assistant;
include_domains = google_assistant.exposed_domains; in {
include_entities = "!include homekit_include_entities.yaml"; include_domains = google_assistant.exposed_domains;
}; include_entities = "!include homekit_include_entities.yaml";
entity_config = "!include homekit_entity_config.yaml"; };
} ]; entity_config = "!include homekit_entity_config.yaml";
}
];
tts = [ tts = [
{ {
platform = "google_translate"; platform = "google_translate";

View file

@ -1,4 +1,8 @@
{ config, lib, ... }: let {
config,
lib,
...
}: let
inherit (lib.modules) mkIf mkDefault mkForce; inherit (lib.modules) mkIf mkDefault mkForce;
cfg = config.services.invidious; cfg = config.services.invidious;
in { in {
@ -6,12 +10,13 @@ in {
commonSecret = { commonSecret = {
sopsFile = ./secrets/invidious.yaml; sopsFile = ./secrets/invidious.yaml;
owner = "invidious"; owner = "invidious";
}; in { };
in {
invidious_db_password = commonSecret; invidious_db_password = commonSecret;
invidious_hmac_key = commonSecret; invidious_hmac_key = commonSecret;
}; };
networking.firewall.interfaces.local.allowedTCPPorts = [ cfg.port ]; networking.firewall.interfaces.local.allowedTCPPorts = [cfg.port];
users.groups.invidious = {}; users.groups.invidious = {};
users.users.invidious = { users.users.invidious = {
isSystemUser = true; isSystemUser = true;

View file

@ -34,7 +34,7 @@ in {
}; };
gameLibraries = mkOption { gameLibraries = mkOption {
type = listOf str; type = listOf str;
default = [ "PC" ]; default = ["PC"];
}; };
}; };
@ -42,10 +42,19 @@ in {
kyuuto = { kyuuto = {
gameLibraries = [ gameLibraries = [
"PC" "PC"
"Wii" "Gamecube" "N64" "SNES" "NES" "Wii"
"NDS" "GBA" "GBC" "Gamecube"
"PS3" "PS2" "PS1" "N64"
"PSVita" "PSP" "SNES"
"NES"
"NDS"
"GBA"
"GBC"
"PS3"
"PS2"
"PS1"
"PSVita"
"PSP"
"Genesis" "Genesis"
]; ];
}; };
@ -74,7 +83,7 @@ in {
{ {
${cfg.shareDir} = mkMerge [ ${cfg.shareDir} = mkMerge [
shared shared
{ group = "peeps"; } {group = "peeps";}
]; ];
${cfg.transferDir} = shared; ${cfg.transferDir} = shared;
${cfg.libraryDir} = shared; ${cfg.libraryDir} = shared;
@ -108,28 +117,34 @@ in {
}; };
users = let users = let
mapId = id: if config.proxmoxLXC.privileged or true then 100000 + id else id; mapId = id:
if config.proxmoxLXC.privileged or true
then 100000 + id
else id;
mkDummyUsers = { mkDummyUsers = {
name, name,
group ? name, group ? name,
enable ? !config.services.${serviceName}.enable, serviceName ? name, enable ? !config.services.${serviceName}.enable,
serviceName ? name,
uid ? config.ids.uids.${name}, uid ? config.ids.uids.${name},
gid ? config.ids.gids.${group}, gid ? config.ids.gids.${group},
}: mkIf enable { }:
users.${name} = { mkIf enable {
group = mkIf (group != null) group; users.${name} = {
uid = mapId uid; group = mkIf (group != null) group;
isSystemUser = true; uid = mapId uid;
isSystemUser = true;
};
groups.${group} = {
gid = mapId gid;
};
}; };
groups.${group} = { in
gid = mapId gid; mkMerge [
}; (mkDummyUsers {name = "deluge";})
}; (mkDummyUsers {name = "radarr";})
in mkMerge [ (mkDummyUsers {name = "sonarr";})
(mkDummyUsers { name = "deluge"; }) (mkDummyUsers {name = "lidarr";})
(mkDummyUsers { name = "radarr"; }) ];
(mkDummyUsers { name = "sonarr"; })
(mkDummyUsers { name = "lidarr"; })
];
}; };
} }

View file

@ -1,4 +1,3 @@
{ {
config, config,
lib, lib,

View file

@ -10,9 +10,11 @@
cfg = kyuuto.opl; cfg = kyuuto.opl;
in { in {
options.kyuuto.opl = with lib.types; { options.kyuuto.opl = with lib.types; {
enable = mkEnableOption "hosting" // { enable =
default = config.services.samba.enable; mkEnableOption "hosting"
}; // {
default = config.services.samba.enable;
};
user = mkOption { user = mkOption {
type = str; type = str;
default = "opl"; default = "opl";
@ -39,22 +41,25 @@ in {
}; };
shares.opl = let shares.opl = let
inherit (config.networking.access) cidrForNetwork; inherit (config.networking.access) cidrForNetwork;
localAddrs = cidrForNetwork.loopback.all ++ cidrForNetwork.local.all localAddrs =
cidrForNetwork.loopback.all
++ cidrForNetwork.local.all
++ lib.optionals config.services.tailscale.enable cidrForNetwork.tail.all; ++ lib.optionals config.services.tailscale.enable cidrForNetwork.tail.all;
in mkIf cfg.enable { in
comment = "Kyuuto Media OPL"; mkIf cfg.enable {
path = cfg.rootDir; comment = "Kyuuto Media OPL";
writeable = true; path = cfg.rootDir;
browseable = true; writeable = true;
public = false; browseable = true;
"valid users" = [ public = false;
cfg.user "valid users" = [
"@kyuuto-peeps" cfg.user
]; "@kyuuto-peeps"
"strict sync" = false; ];
"keepalive" = 0; "strict sync" = false;
"hosts allow" = localAddrs; "keepalive" = 0;
}; "hosts allow" = localAddrs;
};
}; };
services.tmpfiles = let services.tmpfiles = let
setupFiles = { setupFiles = {

View file

@ -1,4 +1,3 @@
{ {
config, config,
lib, lib,
@ -9,17 +8,21 @@
inherit (config.networking.access) cidrForNetwork; inherit (config.networking.access) cidrForNetwork;
inherit (config) kyuuto; inherit (config) kyuuto;
cfg = config.services.samba; cfg = config.services.samba;
localAddrs = cidrForNetwork.loopback.all ++ cidrForNetwork.local.all localAddrs =
cidrForNetwork.loopback.all
++ cidrForNetwork.local.all
++ optionals config.services.tailscale.enable cidrForNetwork.tail.all; ++ optionals config.services.tailscale.enable cidrForNetwork.tail.all;
guestUsers = mkIf cfg.guest.enable [ cfg.guest.user ]; guestUsers = mkIf cfg.guest.enable [cfg.guest.user];
kyuuto-media = { kyuuto-media = {
"create mask" = "0664"; "create mask" = "0664";
"force directory mode" = "3000"; "force directory mode" = "3000";
"directory mask" = "7775"; "directory mask" = "7775";
}; };
kyuuto-library = kyuuto-media // { kyuuto-library =
"acl group control" = true; kyuuto-media
}; // {
"acl group control" = true;
};
in { in {
services.samba = { services.samba = {
usershare = { usershare = {
@ -35,7 +38,7 @@ in {
public = true; public = true;
"valid users" = mkMerge [ "valid users" = mkMerge [
guestUsers guestUsers
[ "@peeps" ] ["@peeps"]
]; ];
#"guest only" = true; #"guest only" = true;
"hosts allow" = localAddrs; "hosts allow" = localAddrs;
@ -54,10 +57,10 @@ in {
public = true; public = true;
"valid users" = mkMerge [ "valid users" = mkMerge [
guestUsers guestUsers
[ "@kyuuto-peeps" ] ["@kyuuto-peeps"]
]; ];
"read list" = guestUsers; "read list" = guestUsers;
"write list" = [ "@kyuuto-peeps" ]; "write list" = ["@kyuuto-peeps"];
"hosts allow" = localAddrs; "hosts allow" = localAddrs;
} }
]; ];
@ -69,7 +72,7 @@ in {
writeable = true; writeable = true;
public = false; public = false;
browseable = false; browseable = false;
"valid users" = [ "@kyuuto-peeps" ]; "valid users" = ["@kyuuto-peeps"];
} }
]; ];
kyuuto-media = mkMerge [ kyuuto-media = mkMerge [
@ -80,7 +83,7 @@ in {
writeable = true; writeable = true;
public = false; public = false;
browseable = false; browseable = false;
"valid users" = [ "@kyuuto-peeps" ]; "valid users" = ["@kyuuto-peeps"];
} }
]; ];
shared = { shared = {
@ -89,7 +92,7 @@ in {
writeable = true; writeable = true;
public = false; public = false;
browseable = false; browseable = false;
"valid users" = [ "@peeps" ]; "valid users" = ["@peeps"];
"create mask" = "0775"; "create mask" = "0775";
"force create mode" = "0010"; "force create mode" = "0010";
"force directory mode" = "2000"; "force directory mode" = "2000";
@ -99,7 +102,7 @@ in {
writeable = true; writeable = true;
browseable = true; browseable = true;
public = false; public = false;
"valid users" = [ "@peeps" ]; "valid users" = ["@peeps"];
"create mask" = "0664"; "create mask" = "0664";
"force directory mode" = "5000"; "force directory mode" = "5000";
"directory mask" = "7775"; "directory mask" = "7775";
@ -108,5 +111,5 @@ in {
}; };
# give guest users proper access to the transfer share # give guest users proper access to the transfer share
users.users.guest.extraGroups = [ "kyuuto" ]; users.users.guest.extraGroups = ["kyuuto"];
} }

View file

@ -2,5 +2,5 @@ _: {
services.lidarr = { services.lidarr = {
enable = true; enable = true;
}; };
users.users.lidarr.extraGroups = [ "kyuuto" ]; users.users.lidarr.extraGroups = ["kyuuto"];
} }

View file

@ -12,6 +12,6 @@ in {
uuid = mkDefault "082fd344-bf69-5b72-a68f-a5a4d88e76b2"; uuid = mkDefault "082fd344-bf69-5b72-a68f-a5a4d88e76b2";
}; };
config.users.users = mkIf cfg.enable { config.users.users = mkIf cfg.enable {
${cfg.user}.extraGroups = [ "kyuuto" ]; ${cfg.user}.extraGroups = ["kyuuto"];
}; };
} }

View file

@ -29,9 +29,9 @@ in {
idmapd.settings = { idmapd.settings = {
General.Domain = mkDefault config.networking.domain; General.Domain = mkDefault config.networking.domain;
Translation.GSS-Methods = concatStringsSep "," ( Translation.GSS-Methods = concatStringsSep "," (
[ "static" ] ["static"]
++ optional enableLdap "umich_ldap" ++ optional enableLdap "umich_ldap"
++ [ "nsswitch" ] ++ ["nsswitch"]
); );
Static = { Static = {
}; };

View file

@ -1,7 +1,4 @@
{ {lib, ...}: let
lib,
...
}: let
inherit (lib.modules) mkDefault; inherit (lib.modules) mkDefault;
in { in {
services.ombi = { services.ombi = {

View file

@ -1,4 +1,9 @@
{config, lib, pkgs, ...}: let {
config,
lib,
pkgs,
...
}: let
inherit (lib.modules) mkIf mkForce mkDefault; inherit (lib.modules) mkIf mkForce mkDefault;
inherit (lib.strings) escapeShellArg; inherit (lib.strings) escapeShellArg;
cfg = config.services.plex; cfg = config.services.plex;
@ -21,9 +26,10 @@ in {
fi fi
${pkgs.coreutils}/bin/ln -sfT ../Cache "$PLEX_DATADIR/Plex Media Server/Cache" ${pkgs.coreutils}/bin/ln -sfT ../Cache "$PLEX_DATADIR/Plex Media Server/Cache"
''; '';
in mkForce [ in
''!${preStartScript}'' mkForce [
]; ''!${preStartScript}''
];
# KillMode = "mixed" doesn't behave as expected... # KillMode = "mixed" doesn't behave as expected...
TimeoutStopSec = 5; TimeoutStopSec = 5;
}; };

View file

@ -8,7 +8,7 @@
in { in {
services.postgresql = { services.postgresql = {
enable = mkDefault true; enable = mkDefault true;
ensureDatabases = ["hass" "invidious" "dex"]; ensureDatabases = ["hass" "invidious" "dex" "keycloak"];
ensureUsers = [ ensureUsers = [
{ {
name = "hass"; name = "hass";
@ -25,6 +25,11 @@ in {
ensureDBOwnership = true; ensureDBOwnership = true;
authentication.local.allow = true; authentication.local.allow = true;
} }
{
name = "keycloak";
ensureDBOwnership = true;
authentication.local.allow = true;
}
]; ];
}; };

View file

@ -3,5 +3,5 @@ _: {
enable = true; enable = true;
}; };
users.users.radarr.extraGroups = [ "kyuuto" ]; users.users.radarr.extraGroups = ["kyuuto"];
} }

View file

@ -2,5 +2,5 @@ _: {
services.readarr = { services.readarr = {
enable = true; enable = true;
}; };
users.users.readarr.extraGroups = [ "kyuuto" ]; users.users.readarr.extraGroups = ["kyuuto"];
} }

View file

@ -1,7 +1,4 @@
{ {lib, ...}: let
lib,
...
}: let
inherit (lib) mkDefault; inherit (lib) mkDefault;
in { in {
services.kanidm.serverSettings.db_fs_type = mkDefault "zfs"; services.kanidm.serverSettings.db_fs_type = mkDefault "zfs";

View file

@ -6,8 +6,8 @@
inherit (lib.modules) mkIf mkDefault; inherit (lib.modules) mkIf mkDefault;
inherit (lib.lists) any; inherit (lib.lists) any;
inherit (lib.strings) hasInfix concatMapStringsSep splitString; inherit (lib.strings) hasInfix concatMapStringsSep splitString;
cfg = config.services.samba; cfg = config.services.samba;
hasIpv4 = any (hasInfix ".") config.systemd.network.networks.eth0.address or [ ]; hasIpv4 = any (hasInfix ".") config.systemd.network.networks.eth0.address or [];
in { in {
services.samba = { services.samba = {
enable = mkDefault true; enable = mkDefault true;

View file

@ -1,4 +1,4 @@
postgresql-init: ENC[AES256_GCM,data:fW9g0WKVHTO9blqlEXLJejyQUqC3na/Xh6Il2GNfuX6c2LfRjfFSeour4qt2envtPO+WanGl+ueE1AMck5t02TjqrN4a6DsQpAIGFVE7L4ajp/13Gp308pY4Xu7OKHjkGpzVBATKgLDZkoU8yAkqKZCBEU3d4xegp8pgnsLSpb/LndKiITjhTe2IJOSkIJd9twSsra8JQWRYCW8WjZZ9YOe5nqtU+56b/zb0CxVhhln0jU/3e5s7pfblfou2TnvnFezswjNTIGftNU1wOaxSCA==,iv:hjKNZ4EbPpl5YIcaWJYLKJzxuOmMjL4AtfUeL4vm5QA=,tag:mYcu4cRUnZeLgeISfaxXPQ==,type:str] postgresql-init: ENC[AES256_GCM,data:lbkeMv6PZgB7tEl4VbIYX9VUAgJ6Kcj0jLNyyqxJJcVJPjo1lF2d/i5bFnU1/6aJ2T7ftMW4hefYgrnIMdKXxPPfrHftaEMhl9bfJIsuX2I1CXAasZOhpsmg9Wf2cvXuVYIlqTVssg+3EKW0ejCMdX6OfGdAXvBlio1DQs7YrUc+BjDiEuAUAaaYbz67EYY3dpYQixQGl/8G2w7S897uCXpc1oOh6vbGY4Nl+GGQ7B5xrrbYcdATwfGyYlZYSlIv8feDsLv7Rt+w3o4tTAxcz+8qZ7KZ6sIsu/nUoYeqoT9MJ8uRpWccXKcBVAFSEooUIHUEBA/QsGizAXBgzCnyLDvuv3DOquo2xeMg0kWM8zsF1f9YRyUKqQ==,iv:RKIvggRZlPocygabF0iKNBThBRFG5rlzrIvGjjt7s0o=,tag:U/XUDJs5J8lHB9BJ5/0fFA==,type:str]
sops: sops:
shamir_threshold: 1 shamir_threshold: 1
kms: [] kms: []
@ -33,8 +33,8 @@ sops:
a3l3bUx5NzdqUGd1TEpGY3UvQWt4TU0KB4MAjvI43FaOiGhWTkwPpeMMiAnX4v3L a3l3bUx5NzdqUGd1TEpGY3UvQWt4TU0KB4MAjvI43FaOiGhWTkwPpeMMiAnX4v3L
rLZDdc/vegF10FKTNJdxdq1E7ccMaV1KwjQkJoOJnWe6teKLjGOFkA== rLZDdc/vegF10FKTNJdxdq1E7ccMaV1KwjQkJoOJnWe6teKLjGOFkA==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
lastmodified: "2024-02-19T03:46:45Z" lastmodified: "2024-03-13T21:46:56Z"
mac: ENC[AES256_GCM,data:FMzWnFllHDpgIoDJIKS7aWpUSVNH0+ij0+AIzl3qtjeuzmUUluDtEes6yAR8g/Daq+nxiMRnsse0HfUqZeT0rVVEpqvQB4Wsoq+G9qj8mmEUrHJzjU5rSDWV8uf5F1BsZbvF13VBulh/RWsmWjps+z6vyJ7uM1QjS3hSF2k3hSM=,iv:tpH8XjoTtNzPOOIosObpsvOAzZO7ywK9xjow3xTOJqY=,tag:BTzezbH9zZDZBzy1x+AJ1w==,type:str] mac: ENC[AES256_GCM,data:rEtRHX3PH1B+uoR82lDH3ACKHPbhxy+y7B9YgR6TzPSU4yIaTSqSK51eLJZoUtW6UTl6QDcTrsKDA8lGu9M/Ohfx8ayp6rkX63H/hkl0h6YaQmWDAQoNAAEWqfJ9r8O8tKKpE6qF/rw4c4KpuA5ONufOl9qj1KSgFzz0WHaKtWk=,iv:TUBAe62dmF6FAjZOPaxwzQjWL21TdWQG0YyuXJGgtk8=,tag:dewWivfnZO30Np2gajwLIw==,type:str]
pgp: pgp:
- created_at: "2024-01-19T19:08:55Z" - created_at: "2024-01-19T19:08:55Z"
enc: |- enc: |-

View file

@ -2,5 +2,5 @@ _: {
services.sonarr = { services.sonarr = {
enable = true; enable = true;
}; };
users.users.sonarr.extraGroups = [ "kyuuto" ]; users.users.sonarr.extraGroups = ["kyuuto"];
} }

View file

@ -1,8 +1,13 @@
{ lib, inputs, ... }: with lib; { {
lib,
inputs,
...
}:
with lib; {
imports = [ imports = [
inputs.sops-nix.nixosModules.sops inputs.sops-nix.nixosModules.sops
]; ];
sops = { sops = {
age.sshKeyPaths = mkDefault [ "/etc/ssh/ssh_host_ed25519_key" ]; age.sshKeyPaths = mkDefault ["/etc/ssh/ssh_host_ed25519_key"];
}; };
} }

View file

@ -1,7 +1,4 @@
{ {lib, ...}: let
lib,
...
}: let
inherit (lib.modules) mkDefault; inherit (lib.modules) mkDefault;
in { in {
services.steam.accountSwitch = { services.steam.accountSwitch = {

View file

@ -1,15 +1,12 @@
{ {lib, ...}: let
lib,
...
}: let
inherit (lib.modules) mkDefault; inherit (lib.modules) mkDefault;
in { in {
services.steam.beatsaber = { services.steam.beatsaber = {
enable = mkDefault true; enable = mkDefault true;
defaultVersion = mkDefault "1.29.0"; defaultVersion = mkDefault "1.29.0";
versions = { versions = {
"1.29.0" = { }; "1.29.0" = {};
"1.34.2" = { }; "1.34.2" = {};
}; };
}; };
} }

View file

@ -1,4 +1,4 @@
{ config, ... }: { {config, ...}: {
services.syncthing = { services.syncthing = {
enable = true; enable = true;
relay.enable = true; relay.enable = true;

View file

@ -10,7 +10,8 @@ in {
enable = mkDefault true; enable = mkDefault true;
user = mkDefault "root"; user = mkDefault "root";
mqtt = { mqtt = {
url = mkDefault (if config.services.mosquitto.enable url = mkDefault (
if config.services.mosquitto.enable
then "tcp://localhost:1883" then "tcp://localhost:1883"
else "tcp://mqtt.local.${config.networking.domain}:1883" else "tcp://mqtt.local.${config.networking.domain}:1883"
); );

View file

@ -1,4 +1,8 @@
{config, lib, ...}: let {
config,
lib,
...
}: let
inherit (lib.modules) mkIf mkDefault; inherit (lib.modules) mkIf mkDefault;
cfg = config.services.tautulli; cfg = config.services.tautulli;
in { in {

View file

@ -1,22 +1,22 @@
{ config, ... }: {config, ...}: {
users.users.arc = {name, ...}: {
{
users.users.arc = { name, ... }: {
uid = 8001; uid = 8001;
isNormalUser = true; isNormalUser = true;
autoSubUidGidRange = false; autoSubUidGidRange = false;
group = name; group = name;
extraGroups = [ extraGroups = [
"users" "peeps" "users"
"peeps"
"kyuuto" "kyuuto"
"steamaccount" "beatsaber" "steamaccount"
"beatsaber"
"wheel" "wheel"
]; ];
openssh.authorizedKeys.keys = [ openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJ8Z6briIboxIdedPGObEWB6QEQkvxKvnMW/UVU9t/ac mew-pgp" "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJ8Z6briIboxIdedPGObEWB6QEQkvxKvnMW/UVU9t/ac mew-pgp"
]; ];
}; };
users.groups.arc = { name, ... }: { users.groups.arc = {name, ...}: {
gid = config.users.users.${name}.uid; gid = config.users.users.${name}.uid;
}; };
} }

View file

@ -1,17 +1,16 @@
{ config, ... }: {config, ...}: {
users.users.connieallure = {name, ...}: {
{
users.users.connieallure = { name, ... }: {
uid = 8003; uid = 8003;
isNormalUser = true; isNormalUser = true;
autoSubUidGidRange = false; autoSubUidGidRange = false;
group = name; group = name;
extraGroups = [ extraGroups = [
"users" "peeps" "users"
"peeps"
"kyuuto" "kyuuto"
]; ];
}; };
users.groups.connieallure = { name, ... }: { users.groups.connieallure = {name, ...}: {
gid = config.users.users.${name}.uid; gid = config.users.users.${name}.uid;
}; };
} }

View file

@ -1,18 +1,18 @@
{ config, ... }: {config, ...}: {
users.users.kaosubaloo = {name, ...}: {
{
users.users.kaosubaloo = { name, ... }: {
uid = 8002; uid = 8002;
isNormalUser = true; isNormalUser = true;
autoSubUidGidRange = false; autoSubUidGidRange = false;
group = name; group = name;
extraGroups = [ extraGroups = [
"users" "peeps" "users"
"peeps"
"kyuuto" "kyuuto"
"steamaccount" "beatsaber" "steamaccount"
"beatsaber"
]; ];
}; };
users.groups.kaosubaloo = { name, ... }: { users.groups.kaosubaloo = {name, ...}: {
gid = config.users.users.${name}.uid; gid = config.users.users.${name}.uid;
}; };
} }

View file

@ -1,25 +1,25 @@
{ config, ... }: {config, ...}: {
users.users.kat = {name, ...}: {
{
users.users.kat = { name, ... }: {
uid = 8000; uid = 8000;
isNormalUser = true; isNormalUser = true;
autoSubUidGidRange = false; autoSubUidGidRange = false;
group = name; group = name;
extraGroups = [ extraGroups = [
"users" "peeps" "users"
"peeps"
"kyuuto" "kyuuto"
"steamaccount" "beatsaber" "steamaccount"
"beatsaber"
"wheel" "wheel"
]; ];
openssh.authorizedKeys.keys = [ openssh.authorizedKeys.keys = [
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCocjQqiDIvzq+Qu3jkf7FXw5piwtvZ1Mihw9cVjdVcsra3U2c9WYtYrA3rS50N3p00oUqQm9z1KUrvHzdE+03ZCrvaGdrtYVsaeoCuuvw7qxTQRbItTAEsfRcZLQ5c1v/57HNYNEsjVrt8VukMPRXWgl+lmzh37dd9w45cCY1QPi+JXQQ/4i9Vc3aWSe4X6PHOEMSBHxepnxm5VNHm4PObGcVbjBf0OkunMeztd1YYA9sEPyEK3b8IHxDl34e5t6NDLCIDz0N/UgzCxSxoz+YJ0feQuZtud/YLkuQcMxW2dSGvnJ0nYy7SA5DkW1oqcy6CGDndHl5StOlJ1IF9aGh0gGkx5SRrV7HOGvapR60RphKrR5zQbFFka99kvSQgOZqSB3CGDEQGHv8dXKXIFlzX78jjWDOBT67vA/M9BK9FS2iNnBF5x6shJ9SU5IK4ySxq8qvN7Us8emkN3pyO8yqgsSOzzJT1JmWUAx0tZWG/BwKcFBHfceAPQl6pwxx28TM3BTBRYdzPJLTkAy48y6iXW6UYdfAPlShy79IYjQtEThTuIiEzdzgYdros0x3PDniuAP0KOKMgbikr0gRa6zahPjf0qqBnHeLB6nHAfaVzI0aNbhOg2bdOueE1FX0x48sjKqjOpjlIfq4WeZp9REr2YHEsoLFOBfgId5P3BPtpBQ== yubikey5" "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCocjQqiDIvzq+Qu3jkf7FXw5piwtvZ1Mihw9cVjdVcsra3U2c9WYtYrA3rS50N3p00oUqQm9z1KUrvHzdE+03ZCrvaGdrtYVsaeoCuuvw7qxTQRbItTAEsfRcZLQ5c1v/57HNYNEsjVrt8VukMPRXWgl+lmzh37dd9w45cCY1QPi+JXQQ/4i9Vc3aWSe4X6PHOEMSBHxepnxm5VNHm4PObGcVbjBf0OkunMeztd1YYA9sEPyEK3b8IHxDl34e5t6NDLCIDz0N/UgzCxSxoz+YJ0feQuZtud/YLkuQcMxW2dSGvnJ0nYy7SA5DkW1oqcy6CGDndHl5StOlJ1IF9aGh0gGkx5SRrV7HOGvapR60RphKrR5zQbFFka99kvSQgOZqSB3CGDEQGHv8dXKXIFlzX78jjWDOBT67vA/M9BK9FS2iNnBF5x6shJ9SU5IK4ySxq8qvN7Us8emkN3pyO8yqgsSOzzJT1JmWUAx0tZWG/BwKcFBHfceAPQl6pwxx28TM3BTBRYdzPJLTkAy48y6iXW6UYdfAPlShy79IYjQtEThTuIiEzdzgYdros0x3PDniuAP0KOKMgbikr0gRa6zahPjf0qqBnHeLB6nHAfaVzI0aNbhOg2bdOueE1FX0x48sjKqjOpjlIfq4WeZp9REr2YHEsoLFOBfgId5P3BPtpBQ== yubikey5"
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDPsu3vNsvBb/G+wALpstD/DnoRZ3fipAs00jtl8rzDuv96RlS7AJr4aNvG6Pt2D9SYn2wVLaiw+76mz2gOycH9/N+VCvL4/0MN9uqj+7XIcxNRo0gHVOblmi2bOXcmGKh3eRwHj1xyDwRxo9WIuBEP2bPpDPz75OXRtEdlTgvky7siSguQxJu03cb0p9hNAYhUoohNXyWW2CjDCLUQVE1+QRVUzsKq3KkPy0cHYgmZC1gRSMQyKpMt72L5tayLz3Tp/zrshucc+QO5IJeZdqMxsNAcvALsysT1J5EqxZoYH9VpWLRhSgVD6Nvn853pycJAlXQxgOCpSD3/v/JbgUe5NE+ci0o7NMy5IiHUv2gQMRIEhwBHlRGwokUPL9upx0lsjaEiPya5xQqqDKRom87xytM778ANS5CuMdQMWg9qVbpHZUHMjA0QmNkjPgq71pUDXHk5L4mZuS8wVjyjnvlw68yIJuHEc8P7QiLcjvRHFS2L9Ck8NRmPDTQXlQi9kk6LmMyu6fdevR/kZL21b+xO1e2DMyxBbNDTot8luppiiL8adgUDMwptpIne7JCWB1o9NFCbXUVgwuCCYBif6pOGSc6bGo1JTAKMflRlcy6Mi3t5H0mR2lj/sCSTWwTlP5FM4aPIq08NvW6PeuK1bFJY9fIgTwVsUnbAKOhmsMt62w== cardno:12 078 454" "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDPsu3vNsvBb/G+wALpstD/DnoRZ3fipAs00jtl8rzDuv96RlS7AJr4aNvG6Pt2D9SYn2wVLaiw+76mz2gOycH9/N+VCvL4/0MN9uqj+7XIcxNRo0gHVOblmi2bOXcmGKh3eRwHj1xyDwRxo9WIuBEP2bPpDPz75OXRtEdlTgvky7siSguQxJu03cb0p9hNAYhUoohNXyWW2CjDCLUQVE1+QRVUzsKq3KkPy0cHYgmZC1gRSMQyKpMt72L5tayLz3Tp/zrshucc+QO5IJeZdqMxsNAcvALsysT1J5EqxZoYH9VpWLRhSgVD6Nvn853pycJAlXQxgOCpSD3/v/JbgUe5NE+ci0o7NMy5IiHUv2gQMRIEhwBHlRGwokUPL9upx0lsjaEiPya5xQqqDKRom87xytM778ANS5CuMdQMWg9qVbpHZUHMjA0QmNkjPgq71pUDXHk5L4mZuS8wVjyjnvlw68yIJuHEc8P7QiLcjvRHFS2L9Ck8NRmPDTQXlQi9kk6LmMyu6fdevR/kZL21b+xO1e2DMyxBbNDTot8luppiiL8adgUDMwptpIne7JCWB1o9NFCbXUVgwuCCYBif6pOGSc6bGo1JTAKMflRlcy6Mi3t5H0mR2lj/sCSTWwTlP5FM4aPIq08NvW6PeuK1bFJY9fIgTwVsUnbAKOhmsMt62w== cardno:12 078 454"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII74JrgGsDQ6r7tD7+k3ykxXV7DpeeFRscPMxrBsDPhz kat@goliath" "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII74JrgGsDQ6r7tD7+k3ykxXV7DpeeFRscPMxrBsDPhz kat@goliath"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDkeBFF4xxZgeURLzNHcvUFxImmkQ3pxXtpj3mtSyHXB kat@koishi" "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDkeBFF4xxZgeURLzNHcvUFxImmkQ3pxXtpj3mtSyHXB kat@koishi"
]; ];
}; };
users.groups.kat = { name, ... }: { users.groups.kat = {name, ...}: {
gid = config.users.users.${name}.uid; gid = config.users.users.${name}.uid;
}; };
} }

View file

@ -1,17 +1,19 @@
{inputs, system}: { {
inputs,
system,
}: {
pkgs = import inputs.nixpkgs { pkgs = import inputs.nixpkgs {
inherit system; inherit system;
overlays = overlays = [
[ inputs.deploy-rs.overlay
inputs.deploy-rs.overlay inputs.arcexprs.overlays.default
inputs.arcexprs.overlays.default (final: prev: {
(final: prev: { jemalloc =
jemalloc = if final.hostPlatform != "aarch64-darwin"
if final.hostPlatform != "aarch64-darwin" then prev.jemalloc
then prev.jemalloc else null;
else null; })
}) ];
];
config = { config = {
allowUnfree = true; allowUnfree = true;
allowBroken = true; allowBroken = true;

View file

@ -12,7 +12,7 @@
export NF_CONFIG_ROOT=''${NF_CONFIG_ROOT-${toString ../.}} export NF_CONFIG_ROOT=''${NF_CONFIG_ROOT-${toString ../.}}
''; '';
exportsSsh = '' exportsSsh = ''
export PATH="${makeBinPath [ packages.nf-hostname packages.nf-sshopts ]}:$PATH" export PATH="${makeBinPath [packages.nf-hostname packages.nf-sshopts]}:$PATH"
''; '';
exportsFmtNix = '' exportsFmtNix = ''
NF_NIX_BLACKLIST_DIRS=(${string.concatMapSep " " string.escapeShellArg fmt.nix.blacklistDirs}) NF_NIX_BLACKLIST_DIRS=(${string.concatMapSep " " string.escapeShellArg fmt.nix.blacklistDirs})
@ -20,11 +20,16 @@
NF_NIX_WHITELIST_FILES=(${string.concatMapSep " " string.escapeShellArg fmt.nix.whitelist}) NF_NIX_WHITELIST_FILES=(${string.concatMapSep " " string.escapeShellArg fmt.nix.whitelist})
''; '';
output = { output = {
inherit (pkgs.buildPackages) inherit
terraform tflint (pkgs.buildPackages)
alejandra deadnix statix terraform
ssh-to-age jq tflint
; alejandra
deadnix
statix
ssh-to-age
jq
;
inherit (inputs.deploy-rs.packages.${system}) deploy-rs; inherit (inputs.deploy-rs.packages.${system}) deploy-rs;
nf-deploy = pkgs.writeShellScriptBin "nf-deploy" '' nf-deploy = pkgs.writeShellScriptBin "nf-deploy" ''
${exports} ${exports}
@ -52,26 +57,27 @@
INPUT_INFRA_CT_CONFIG = reisen + "/bin/ct-config.sh"; INPUT_INFRA_CT_CONFIG = reisen + "/bin/ct-config.sh";
}; };
inputVars = set.mapToValues (key: path: ''${key}="$(base64 -w0 < ${path})"'') inputAttrs; inputVars = set.mapToValues (key: path: ''${key}="$(base64 -w0 < ${path})"'') inputAttrs;
in pkgs.writeShellScriptBin "nf-setup-node" '' in
${exports} pkgs.writeShellScriptBin "nf-setup-node" ''
NF_SETUP_INPUTS=( ${exports}
${string.intercalate "\n" inputVars} NF_SETUP_INPUTS=(
) ${string.intercalate "\n" inputVars}
source ${../ci/setup.sh} )
''; source ${../ci/setup.sh}
'';
nf-hostname = pkgs.writeShellScriptBin "nf-hostname" '' nf-hostname = pkgs.writeShellScriptBin "nf-hostname" ''
${exports} ${exports}
source ${../ci/hostname.sh} source ${../ci/hostname.sh}
''; '';
nf-sshopts = pkgs.writeShellScriptBin "nf-sshopts" '' nf-sshopts = pkgs.writeShellScriptBin "nf-sshopts" ''
${exports} ${exports}
export PATH="$PATH:${makeBinPath [ pkgs.jq ]}" export PATH="$PATH:${makeBinPath [pkgs.jq]}"
source ${../ci/sshopts.sh} source ${../ci/sshopts.sh}
''; '';
nf-sops-keyscan = pkgs.writeShellScriptBin "nf-sops-keyscan" '' nf-sops-keyscan = pkgs.writeShellScriptBin "nf-sops-keyscan" ''
${exports} ${exports}
${exportsSsh} ${exportsSsh}
export PATH="$PATH:${makeBinPath [ pkgs.ssh-to-age ]}" export PATH="$PATH:${makeBinPath [pkgs.ssh-to-age]}"
source ${../ci/sops-keyscan.sh} source ${../ci/sops-keyscan.sh}
''; '';
nf-ssh = pkgs.writeShellScriptBin "nf-ssh" '' nf-ssh = pkgs.writeShellScriptBin "nf-ssh" ''
@ -94,39 +100,39 @@
''; '';
nf-generate = pkgs.writeShellScriptBin "nf-generate" '' nf-generate = pkgs.writeShellScriptBin "nf-generate" ''
${exports} ${exports}
export PATH="$PATH:${makeBinPath [ pkgs.jq ]}" export PATH="$PATH:${makeBinPath [pkgs.jq]}"
source ${../ci/generate.sh} source ${../ci/generate.sh}
''; '';
nf-statix = pkgs.writeShellScriptBin "nf-statix" '' nf-statix = pkgs.writeShellScriptBin "nf-statix" ''
${exports} ${exports}
export PATH="${makeBinPath [ packages.statix ]}:$PATH" export PATH="${makeBinPath [packages.statix]}:$PATH"
source ${../ci/statix.sh} source ${../ci/statix.sh}
''; '';
nf-deadnix = pkgs.writeShellScriptBin "nf-deadnix" '' nf-deadnix = pkgs.writeShellScriptBin "nf-deadnix" ''
${exports} ${exports}
${exportsFmtNix} ${exportsFmtNix}
export PATH="${makeBinPath [ packages.deadnix pkgs.findutils ]}:$PATH" export PATH="${makeBinPath [packages.deadnix pkgs.findutils]}:$PATH"
source ${../ci/deadnix.sh} source ${../ci/deadnix.sh}
''; '';
nf-alejandra = pkgs.writeShellScriptBin "nf-alejandra" '' nf-alejandra = pkgs.writeShellScriptBin "nf-alejandra" ''
${exports} ${exports}
${exportsFmtNix} ${exportsFmtNix}
export PATH="${makeBinPath [ packages.alejandra ]}:$PATH" export PATH="${makeBinPath [packages.alejandra]}:$PATH"
source ${../ci/alejandra.sh} source ${../ci/alejandra.sh}
''; '';
nf-lint-tf = pkgs.writeShellScriptBin "nf-lint-tf" '' nf-lint-tf = pkgs.writeShellScriptBin "nf-lint-tf" ''
${exports} ${exports}
export PATH="$PATH:${makeBinPath [ packages.tflint ]}" export PATH="$PATH:${makeBinPath [packages.tflint]}"
source ${../ci/lint-tf.sh} source ${../ci/lint-tf.sh}
''; '';
nf-lint-nix = pkgs.writeShellScriptBin "nf-lint-nix" '' nf-lint-nix = pkgs.writeShellScriptBin "nf-lint-nix" ''
${exports} ${exports}
export PATH="${makeBinPath [ packages.nf-statix packages.nf-deadnix ]}:$PATH" export PATH="${makeBinPath [packages.nf-statix packages.nf-deadnix]}:$PATH"
source ${../ci/lint-nix.sh} source ${../ci/lint-nix.sh}
''; '';
nf-fmt-tf = pkgs.writeShellScriptBin "nf-fmt-tf" '' nf-fmt-tf = pkgs.writeShellScriptBin "nf-fmt-tf" ''
${exports} ${exports}
export PATH="${makeBinPath [ packages.terraform ]}:$PATH" export PATH="${makeBinPath [packages.terraform]}:$PATH"
source ${../ci/fmt-tf.sh} source ${../ci/fmt-tf.sh}
''; '';
nf-fmt-nix = pkgs.writeShellScriptBin "nf-fmt-nix" '' nf-fmt-nix = pkgs.writeShellScriptBin "nf-fmt-nix" ''
@ -144,4 +150,5 @@
inherit (inputs) self; inherit (inputs) self;
}; };
}; };
in output in
output

View file

@ -5,26 +5,31 @@
}: let }: let
inherit (lib.strings) concatStringsSep; inherit (lib.strings) concatStringsSep;
inherit (lib.lists) toList head; inherit (lib.lists) toList head;
in { domain, name }: runCommand name { in
domains = concatStringsSep "," (toList domain); {
domain = head (toList domain); domain,
nativeBuildInputs = [ buildPackages.minica ]; name,
outputs = [ "out" "key" "cakey" "ca" "cert" "fullchain" ]; }:
} '' runCommand name {
install -d $out domains = concatStringsSep "," (toList domain);
minica \ domain = head (toList domain);
--ca-key ca.key.pem \ nativeBuildInputs = [buildPackages.minica];
--ca-cert ca.pem \ outputs = ["out" "key" "cakey" "ca" "cert" "fullchain"];
--domains "$domains" } ''
mv ca.pem $ca install -d $out
mv ca.key.pem $cakey minica \
mv $domain/cert.pem $cert --ca-key ca.key.pem \
mv $domain/key.pem $key --ca-cert ca.pem \
cat $cert $ca > $fullchain --domains "$domains"
mv ca.pem $ca
mv ca.key.pem $cakey
mv $domain/cert.pem $cert
mv $domain/key.pem $key
cat $cert $ca > $fullchain
ln -s $fullchain $out/fullchain.pem ln -s $fullchain $out/fullchain.pem
ln -s $key $out/key.pem ln -s $key $out/key.pem
ln -s $cakey $out/ca.key.pem ln -s $cakey $out/ca.key.pem
ln -s $cert $out/cert.pem ln -s $cert $out/cert.pem
ln -s $ca $out/ca.pem ln -s $ca $out/ca.pem
'' ''