chore: nf-fmt-nix

This commit is contained in:
arcnmx 2024-05-13 15:13:58 -07:00
parent 7486517713
commit 9903866044
160 changed files with 4570 additions and 3019 deletions

View file

@ -3,19 +3,25 @@
whitelist = [ whitelist = [
"overlays/default.nix" "overlays/default.nix"
"ci/fmt.nix" "ci/fmt.nix"
"docs/derivation.nix"
"devShells.nix" "devShells.nix"
"shell.nix" "shell.nix"
"generate.nix"
"lib.nix" "lib.nix"
"outputs.nix" "outputs.nix"
"tree.nix" "tree.nix"
]; ];
whitelistDirs = [ whitelistDirs = [
"modules/extern" "modules/extern"
"modules/nixos"
"modules/system" "modules/system"
"nixos"
"overlays"
"packages"
"systems" "systems"
]; ];
blacklistDirs = [ blacklistDirs = [
"overlays" "modules/nixos/ldap"
"ci" "ci"
]; ];
}; };

View file

@ -151,11 +151,15 @@
LDAPSASL_NOCANON = "on"; LDAPSASL_NOCANON = "on";
}; };
arc = let arc = let
ldapdm = cmd: pkgs.writeShellScriptBin "dm-${cmd}" '' ldapdm = cmd:
pkgs.writeShellScriptBin "dm-${cmd}" ''
${cmd} -D 'cn=Directory Manager' -y <(bitw get -f password ldap-directory-manager) "$@" ${cmd} -D 'cn=Directory Manager' -y <(bitw get -f password ldap-directory-manager) "$@"
''; '';
in default.overrideAttrs (default: { in
nativeBuildInputs = default.nativeBuildInputs ++ [ default.overrideAttrs (default: {
nativeBuildInputs =
default.nativeBuildInputs
++ [
(ldapdm "ldapwhoami") (ldapdm "ldapwhoami")
(ldapdm "ldappasswd") (ldapdm "ldappasswd")
(ldapdm "ldapsearch") (ldapdm "ldapsearch")

View file

@ -19,23 +19,33 @@
}; };
nodeSystems = let nodeSystems = let
matchesNode = nodeName: system: system.config.proxmox.enabled && system.config.proxmox.node.name == nodeName; matchesNode = nodeName: system: system.config.proxmox.enabled && system.config.proxmox.node.name == nodeName;
in nodeName: filterAttrs (_: matchesNode nodeName) systems; in
nodeName: filterAttrs (_: matchesNode nodeName) systems;
mkNodeSystem = system: { mkNodeSystem = system: {
inherit (system.config.access) hostName; inherit (system.config.access) hostName;
network = let network = let
inherit (system.config.network) networks; inherit (system.config.network) networks;
in { in {
networks = { networks = {
int = if networks.int.enable or false then { int =
if networks.int.enable or false
then {
inherit (networks.int) macAddress address4 address6; inherit (networks.int) macAddress address4 address6;
} else null; }
local = if networks.local.enable or false then { else null;
local =
if networks.local.enable or false
then {
inherit (networks.local) macAddress address4 address6; inherit (networks.local) macAddress address4 address6;
} else null; }
tail = if networks.tail.enable or false then { else null;
tail =
if networks.tail.enable or false
then {
inherit (networks.tail) address4 address6; inherit (networks.tail) address4 address6;
macAddress = null; macAddress = null;
} else null; }
else null;
}; };
}; };
}; };
@ -43,10 +53,12 @@
mkExtern = system: let mkExtern = system: let
enabledFiles = filterAttrs (_: file: file.enable) system.extern.files; enabledFiles = filterAttrs (_: file: file.enable) system.extern.files;
in { in {
files = mapAttrs' (_: file: nameValuePair file.path { files = mapAttrs' (_: file:
nameValuePair file.path {
source = assert file.relativeSource != null; file.relativeSource; source = assert file.relativeSource != null; file.relativeSource;
inherit (file) owner group mode; inherit (file) owner group mode;
}) enabledFiles; })
enabledFiles;
}; };
mkNode = system: { mkNode = system: {
users = mkNodeUsers templateUsers; users = mkNodeUsers templateUsers;
@ -58,13 +70,17 @@
}; };
mkNetwork = system: { mkNetwork = system: {
inherit (system.config.access) hostName; inherit (system.config.access) hostName;
networks = { networks =
{
int = null; int = null;
local = null; local = null;
tail = null; tail = null;
} // mapAttrs' (_: network: nameValuePair network.name { }
// mapAttrs' (_: network:
nameValuePair network.name {
inherit (network) macAddress address4 address6; inherit (network) macAddress address4 address6;
}) system.config.network.networks; })
system.config.network.networks;
}; };
mkSystem = name: system: { mkSystem = name: system: {
network = mkNetwork system; network = mkNetwork system;
@ -72,6 +88,7 @@
in { in {
nodes = let nodes = let
nodes = filterAttrs (_: node: node.config.proxmox.node.enable) systems; nodes = filterAttrs (_: node: node.config.proxmox.node.enable) systems;
in mapAttrs (_: mkNode) nodes; in
mapAttrs (_: mkNode) nodes;
systems = mapAttrs mkSystem systems; systems = mapAttrs mkSystem systems;
} }

57
lib.nix
View file

@ -23,11 +23,15 @@
parts' = Regex.match ''^([^:]+)://(\[[0-9a-fA-F:]+]|[^/:\[]+)(|:[0-9]+)(|/.*)$'' url; parts' = Regex.match ''^([^:]+)://(\[[0-9a-fA-F:]+]|[^/:\[]+)(|:[0-9]+)(|/.*)$'' url;
parts = parts'.value; parts = parts'.value;
port' = List.index parts 2; port' = List.index parts 2;
in assert Opt.isJust parts'; rec { in
assert Opt.isJust parts'; rec {
inherit url parts; inherit url parts;
scheme = List.index parts 0; scheme = List.index parts 0;
host = List.index parts 1; host = List.index parts 1;
port = if port' != "" then UInt.Parse (Str.removePrefix ":" port') else null; port =
if port' != ""
then UInt.Parse (Str.removePrefix ":" port')
else null;
hostport = host + port'; hostport = host + port';
path = List.index parts 3; path = List.index parts 3;
}; };
@ -36,7 +40,10 @@
mkWinPath = Str.replace ["/"] ["\\"]; mkWinPath = Str.replace ["/"] ["\\"];
mkBaseDn = domain: Str.concatMapSep "," (part: "dc=${part}") (Regex.splitOn "\\." domain); mkBaseDn = domain: Str.concatMapSep "," (part: "dc=${part}") (Regex.splitOn "\\." domain);
mkAddress6 = addr: if Str.hasInfix ":" addr && ! Str.hasPrefix "[" addr then "[${addr}]" else addr; mkAddress6 = addr:
if Str.hasInfix ":" addr && ! Str.hasPrefix "[" addr
then "[${addr}]"
else addr;
coalesce = values: Opt.default null (List.find (v: v != null) values); coalesce = values: Opt.default null (List.find (v: v != null) values);
mapListToAttrs = f: l: listToAttrs (map f l); mapListToAttrs = f: l: listToAttrs (map f l);
@ -85,13 +92,43 @@ in {
Std = inputs.std-fl.lib; Std = inputs.std-fl.lib;
lib = { lib = {
domain = "gensokyo.zone"; domain = "gensokyo.zone";
inherit treeToModulesOutput userIs inherit
eui64 parseUrl mkWinPath mkBaseDn mkAddress6 treeToModulesOutput
mapListToAttrs coalesce userIs
mkAlmostOptionDefault mkAlmostDefault mkAlmostForce mapOverride mapOptionDefaults mapAlmostOptionDefaults mapDefaults eui64
overrideOptionDefault overrideAlmostOptionDefault overrideDefault overrideAlmostDefault overrideNone overrideAlmostForce overrideForce overrideVM parseUrl
orderJustBefore orderBefore orderAlmostBefore orderNone orderAfter orderAlmostAfter orderJustAfter mkWinPath
mkJustBefore mkAlmostBefore mkAlmostAfter mkJustAfter; mkBaseDn
mkAddress6
mapListToAttrs
coalesce
mkAlmostOptionDefault
mkAlmostDefault
mkAlmostForce
mapOverride
mapOptionDefaults
mapAlmostOptionDefaults
mapDefaults
overrideOptionDefault
overrideAlmostOptionDefault
overrideDefault
overrideAlmostDefault
overrideNone
overrideAlmostForce
overrideForce
overrideVM
orderJustBefore
orderBefore
orderAlmostBefore
orderNone
orderAfter
orderAlmostAfter
orderJustAfter
mkJustBefore
mkAlmostBefore
mkAlmostAfter
mkJustAfter
;
inherit (inputs.arcexprs.lib) unmerged json; inherit (inputs.arcexprs.lib) unmerged json;
}; };
gensokyo-zone = { gensokyo-zone = {

View file

@ -1,4 +1,8 @@
{inputs, ...}: {lib, osConfig, ...}: let {inputs, ...}: {
lib,
osConfig,
...
}: let
inherit (inputs.self.lib) meta; inherit (inputs.self.lib) meta;
inherit (lib.modules) mkIf; inherit (lib.modules) mkIf;
in { in {

View file

@ -19,16 +19,23 @@ let
system = gensokyo-zone.systems.${config.systemName}.config; system = gensokyo-zone.systems.${config.systemName}.config;
networks = let networks = let
fallbackNetwork = fallbackNetwork =
if system.network.networks.local.enable or false && access.local.enable then "local" if system.network.networks.local.enable or false && access.local.enable
else if system.access.global.enable then null then "local"
else if system.network.networks.int.enable or false then "int" else if system.access.global.enable
else if system.network.networks.local.enable or false then "local" then null
else if system.network.networks.int.enable or false
then "int"
else if system.network.networks.local.enable or false
then "local"
else null; else null;
networks = map (name: coalesce [name fallbackNetwork]) config.networks; networks = map (name: coalesce [name fallbackNetwork]) config.networks;
in unique networks; in
unique networks;
in { in {
options = with lib.types; { options = with lib.types; {
enable = mkEnableOption "ssh client configuration" // { enable =
mkEnableOption "ssh client configuration"
// {
default = true; default = true;
}; };
name = mkOption { name = mkOption {
@ -66,12 +73,17 @@ let
enabledNetworks = filterAttrs (_: net: net.enable) system.network.networks; enabledNetworks = filterAttrs (_: net: net.enable) system.network.networks;
networkNames = mapAttrsToList (_: net: net.name) enabledNetworks; networkNames = mapAttrsToList (_: net: net.name) enabledNetworks;
networks = filter (name: name == null || elem name networkNames) cfg.networks; networks = filter (name: name == null || elem name networkNames) cfg.networks;
in mkOptionDefault networks; in
mkOptionDefault networks;
set = { set = {
matchBlocksSettings = let matchBlocksSettings = let
canonNetworkName' = intersectLists networks [null "int" "local"]; canonNetworkName' = intersectLists networks [null "int" "local"];
canonNetworkName = if canonNetworkName' != [ ] then head canonNetworkName' else null; canonNetworkName =
in mapListToAttrs (network: let if canonNetworkName' != []
then head canonNetworkName'
else null;
in
mapListToAttrs (network: let
name = config.name + optionalString (network != canonNetworkName) "-${network}"; name = config.name + optionalString (network != canonNetworkName) "-${network}";
inherit (system.exports.services) sshd; inherit (system.exports.services) sshd;
port = head ( port = head (
@ -80,9 +92,11 @@ let
++ [sshd.ports.standard.port] ++ [sshd.ports.standard.port]
); );
needsProxy = network == "int" || (network == "local" && !access.local.enable); needsProxy = network == "int" || (network == "local" && !access.local.enable);
in nameValuePair name { in
nameValuePair name {
hostname = mkDefault ( hostname = mkDefault (
if network == null then system.access.fqdn if network == null
then system.access.fqdn
else system.network.networks.${network}.fqdn else system.network.networks.${network}.fqdn
); );
user = mkIf (config.user != null) (mkDefault config.user); user = mkIf (config.user != null) (mkDefault config.user);
@ -97,7 +111,8 @@ let
HostKeyAlias = mkIf (config.hostName != null && network != null) (mkOptionDefault system.access.fqdn); HostKeyAlias = mkIf (config.hostName != null && network != null) (mkOptionDefault system.access.fqdn);
} }
]; ];
}) networks; })
networks;
}; };
}; };
}; };
@ -150,7 +165,8 @@ let
}; };
config = { config = {
proxyJump = mkOptionDefault ( proxyJump = mkOptionDefault (
if config.hosts.hakurei.enable then config.hosts.hakurei.name if config.hosts.hakurei.enable
then config.hosts.hakurei.name
else gensokyo-zone.systems.hakurei.config.access.fqdn else gensokyo-zone.systems.hakurei.config.access.fqdn
); );
networks = mkOptionDefault [ networks = mkOptionDefault [
@ -159,19 +175,23 @@ let
]; ];
hosts = mapAttrs (name: system: let hosts = mapAttrs (name: system: let
enabled = system.config.access.online.enable && system.config.exports.services.sshd.enable; enabled = system.config.access.online.enable && system.config.exports.services.sshd.enable;
in mkIf enabled { in
mkIf enabled {
systemName = mkOptionDefault name; systemName = mkOptionDefault name;
}) gensokyo-zone.systems; })
gensokyo-zone.systems;
set = { set = {
matchBlocksSettings = let matchBlocksSettings = let
mkMatchBlocksHost = host: mkIf host.enable (unmerged.mergeAttrs host.set.matchBlocksSettings); mkMatchBlocksHost = host: mkIf host.enable (unmerged.mergeAttrs host.set.matchBlocksSettings);
in mkMerge ( in
mkMerge (
mapAttrsToList (_: mkMatchBlocksHost) config.hosts mapAttrsToList (_: mkMatchBlocksHost) config.hosts
); );
}; };
}; };
}; };
in { in
{
config, config,
osConfig, osConfig,
lib, lib,

View file

@ -67,7 +67,8 @@
]; ];
nameservers = let nameservers = let
inherit (gensokyo-zone.systems) utsuho hakurei; inherit (gensokyo-zone.systems) utsuho hakurei;
in mkMerge [ in
mkMerge [
(mkOptionDefault []) (mkOptionDefault [])
(mkIf access.local.enable [ (mkIf access.local.enable [
(mkIf enableIPv6 utsuho.config.access.address6ForNetwork.local) (mkIf enableIPv6 utsuho.config.access.address6ForNetwork.local)
@ -79,20 +80,25 @@
hakurei.config.access.address4ForNetwork.tail hakurei.config.access.address4ForNetwork.tail
]) ])
]; ];
fallbackNameservers = mkOptionDefault { fallbackNameservers =
mkOptionDefault
{
cloudflare = [ cloudflare = [
"1.1.1.1#cloudflare-dns.com" "1.1.1.1#cloudflare-dns.com"
"1.0.0.1#cloudflare-dns.com" "1.0.0.1#cloudflare-dns.com"
]; ];
google = optionals enableIPv6 [ google =
optionals enableIPv6 [
"[2001:4860:4860::8888]#dns.google" "[2001:4860:4860::8888]#dns.google"
"[2001:4860:4860::8844]#dns.google" "[2001:4860:4860::8844]#dns.google"
] ++ [ ]
++ [
"8.8.8.8#dns.google" "8.8.8.8#dns.google"
"8.8.4.4#dns.google" "8.8.4.4#dns.google"
]; ];
${toString null} = []; ${toString null} = [];
}.${toString config.fallback}; }
.${toString config.fallback};
set = { set = {
nssSettings = { nssSettings = {
hosts = mkMerge [ hosts = mkMerge [

View file

@ -40,7 +40,9 @@
default = toUpper config.domain; default = toUpper config.domain;
}; };
ca = { ca = {
trust = mkEnableOption "trust CA" // { trust =
mkEnableOption "trust CA"
// {
default = true; default = true;
}; };
pem = mkOption { pem = mkOption {
@ -109,14 +111,18 @@
pam.enable = mkEnableOption "PAM"; pam.enable = mkEnableOption "PAM";
backend = mkOption { backend = mkOption {
type = enum ["ipa" "ldap"]; type = enum ["ipa" "ldap"];
default = { default =
{
ipa = "ipa"; ipa = "ipa";
kldap = "ldap"; kldap = "ldap";
}.${config.db.backend}; }
.${config.db.backend};
}; };
}; };
ntp = { ntp = {
enable = mkEnableOption "ntp" // { enable =
mkEnableOption "ntp"
// {
default = true; default = true;
}; };
servers = mkOption { servers = mkOption {
@ -185,7 +191,8 @@
url = "https://${config.ipa.httpHost}/ipa/config/ca.crt"; url = "https://${config.ipa.httpHost}/ipa/config/ca.crt";
sha256 = "sha256-PKjnjn1jIq9x4BX8+WGkZfj4HQtmnHqmFSALqggo91o="; sha256 = "sha256-PKjnjn1jIq9x4BX8+WGkZfj4HQtmnHqmFSALqggo91o=";
}; };
in mkOptionDefault caPem; in
mkOptionDefault caPem;
ldap = { ldap = {
urls = mkMerge [ urls = mkMerge [
(mkIf access.local.enable (mkOptionDefault (mkBefore [ (mkIf access.local.enable (mkOptionDefault (mkBefore [
@ -200,7 +207,8 @@
]; ];
bind = let bind = let
inherit (nixosConfig.sops) secrets; inherit (nixosConfig.sops) secrets;
in mkIf (nixosOptions ? sops.secrets && secrets ? gensokyo-zone-krb5-passwords) { in
mkIf (nixosOptions ? sops.secrets && secrets ? gensokyo-zone-krb5-passwords) {
passwordFileKrb5 = mkOptionDefault nixosConfig.sops.secrets.gensokyo-zone-krb5-passwords.path; passwordFileKrb5 = mkOptionDefault nixosConfig.sops.secrets.gensokyo-zone-krb5-passwords.path;
passwordFile = mkOptionDefault nixosConfig.sops.secrets.gensokyo-zone-krb5-peep-password.path; passwordFile = mkOptionDefault nixosConfig.sops.secrets.gensokyo-zone-krb5-peep-password.path;
passwordFileSssdEnv = mkOptionDefault nixosConfig.sops.secrets.gensokyo-zone-sssd-passwords.path; passwordFileSssdEnv = mkOptionDefault nixosConfig.sops.secrets.gensokyo-zone-sssd-passwords.path;
@ -243,13 +251,15 @@
}; };
}; };
sssdSettings = let sssdSettings = let
servers = optional access.local.enable "idp.local.${config.domain}" servers =
optional access.local.enable "idp.local.${config.domain}"
++ ["_srv"]; ++ ["_srv"];
backups = mkMerge [ backups = mkMerge [
(mkIf access.tail.enabled (mkAlmostOptionDefault ["ipa.tail.${config.domain}"])) (mkIf access.tail.enabled (mkAlmostOptionDefault ["ipa.tail.${config.domain}"]))
(mkIf access.local.enable (mkAlmostOptionDefault ["ipa.local.${config.domain}"])) (mkIf access.local.enable (mkAlmostOptionDefault ["ipa.local.${config.domain}"]))
]; ];
in mkIf config.sssd.enable { in
mkIf config.sssd.enable {
enable = mkAlmostOptionDefault true; enable = mkAlmostOptionDefault true;
gensokyo-zone = { gensokyo-zone = {
backend = mkAlmostOptionDefault config.sssd.backend; backend = mkAlmostOptionDefault config.sssd.backend;
@ -268,7 +278,8 @@
])); ]));
}; };
}; };
environmentFile = mkIf (config.sssd.backend == "ldap") (mkAlmostOptionDefault environmentFile = mkIf (config.sssd.backend == "ldap") (
mkAlmostOptionDefault
config.ldap.bind.passwordFileSssdEnv config.ldap.bind.passwordFileSssdEnv
); );
services = { services = {
@ -284,14 +295,19 @@
realm = config.realm; realm = config.realm;
server = config.ipa.server; server = config.ipa.server;
# TODO: dyndns? # TODO: dyndns?
} // { }
// {
overrideConfigs = mapAlmostOptionDefaults { overrideConfigs = mapAlmostOptionDefaults {
sssd = false; sssd = false;
krb5 = false; krb5 = false;
}; };
}); });
nfsSettings = mkIf config.nfs.enable { nfsSettings = mkIf config.nfs.enable {
${if nixosOptions ? services.nfs.settings then "settings" else null} = mkMerge [ ${
if nixosOptions ? services.nfs.settings
then "settings"
else null
} = mkMerge [
{ {
gssd = mapOptionDefaults { gssd = mapOptionDefaults {
#use-machine-creds = false; #use-machine-creds = false;
@ -314,7 +330,11 @@
}; };
}) })
]; ];
${if nixosOptions ? services.nfs.settings then null else "extraConfig"} = mkMerge [ ${
if nixosOptions ? services.nfs.settings
then null
else "extraConfig"
} = mkMerge [
'' ''
[gssd] [gssd]
#use-machine-creds = false #use-machine-creds = false
@ -413,7 +433,8 @@ in {
hosts = let hosts = let
inherit (gensokyo-zone.systems) freeipa; inherit (gensokyo-zone.systems) freeipa;
# TODO: consider hakurei instead... # TODO: consider hakurei instead...
in mkIf (cfg.enable && !config.gensokyo-zone.dns.enable or false && config.gensokyo-zone.access.local.enable) { in
mkIf (cfg.enable && !config.gensokyo-zone.dns.enable or false && config.gensokyo-zone.access.local.enable) {
${freeipa.config.access.address6ForNetwork.local} = mkIf config.networking.enableIPv6 (mkBefore [cfg.host]); ${freeipa.config.access.address6ForNetwork.local} = mkIf config.networking.enableIPv6 (mkBefore [cfg.host]);
${freeipa.config.access.address4ForNetwork.local} = mkBefore [cfg.host]; ${freeipa.config.access.address4ForNetwork.local} = mkBefore [cfg.host];
}; };
@ -425,14 +446,20 @@ in {
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${config.system.nssModules.path}" export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${config.system.nssModules.path}"
exec ${cfg.nfs.package}/bin/nfsidmap "$@" exec ${cfg.nfs.package}/bin/nfsidmap "$@"
''; '';
in mkForce (pkgs.writeText "request-key.conf" '' in
mkForce (pkgs.writeText "request-key.conf" ''
create id_resolver * * ${nfsidmap} -t 600 %k %d create id_resolver * * ${nfsidmap} -t 600 %k %d
''); '');
}; };
}; };
${if options ? sops.secrets then "sops" else null}.secrets = let ${
if options ? sops.secrets
then "sops"
else null
}.secrets = let
sopsFile = mkDefault ../secrets/krb5.yaml; sopsFile = mkDefault ../secrets/krb5.yaml;
in mkIf cfg.enable { in
mkIf cfg.enable {
gensokyo-zone-krb5-passwords = mkIf (cfg.db.backend == "kldap") { gensokyo-zone-krb5-passwords = mkIf (cfg.db.backend == "kldap") {
inherit sopsFile; inherit sopsFile;
}; };

View file

@ -33,18 +33,26 @@
options = with lib.types; { options = with lib.types; {
enable = mkEnableOption "kyuuto"; enable = mkEnableOption "kyuuto";
media = { media = {
enable = mkEnableOption "/mnt/kyuuto-media" // { enable =
mkEnableOption "/mnt/kyuuto-media"
// {
default = true; default = true;
}; };
krb5.enable = mkEnableOption "krb5" // { krb5.enable =
mkEnableOption "krb5"
// {
default = enabled.krb5; default = enabled.krb5;
}; };
}; };
transfer = { transfer = {
enable = mkEnableOption "/mnt/kyuuto-transfer" // { enable =
mkEnableOption "/mnt/kyuuto-transfer"
// {
default = true; default = true;
}; };
krb5.enable = mkEnableOption "krb5" // { krb5.enable =
mkEnableOption "krb5"
// {
default = enabled.krb5; default = enabled.krb5;
}; };
}; };
@ -135,7 +143,8 @@
(mkIf config.nfs.enable "nfs4") (mkIf config.nfs.enable "nfs4")
(mkIf config.smb.enable "smb3") (mkIf config.smb.enable "smb3")
]; ];
options = mkMerge (setFilesystemOptions ++ [ options = mkMerge (setFilesystemOptions
++ [
(mkIf config.media.krb5.enable [ (mkIf config.media.krb5.enable [
"sec=krb5" "sec=krb5"
(mkIf config.nfs.enable "nfsvers=4") (mkIf config.nfs.enable "nfsvers=4")
@ -151,9 +160,14 @@
(mkIf config.nfs.enable "nfs4") (mkIf config.nfs.enable "nfs4")
(mkIf config.smb.enable "smb3") (mkIf config.smb.enable "smb3")
]; ];
options = mkMerge (setFilesystemOptions ++ [ options = mkMerge (setFilesystemOptions
++ [
(mkIf config.media.krb5.enable [ (mkIf config.media.krb5.enable [
(if access.local.enable || access.tail.enabled then "sec=sys:krb5" else "sec=krb5") (
if access.local.enable || access.tail.enabled
then "sec=sys:krb5"
else "sec=krb5"
)
#(mkIf config.nfs.enable "nfsvers=3") #(mkIf config.nfs.enable "nfsvers=3")
]) ])
]); ]);

View file

@ -46,7 +46,9 @@
default = "ssh"; default = "ssh";
}; };
ssh = { ssh = {
commonKey = mkEnableOption "shared secret nixbld key" // { commonKey =
mkEnableOption "shared secret nixbld key"
// {
default = true; default = true;
}; };
user = mkOption { user = mkOption {
@ -114,7 +116,9 @@
]; ];
ssh.key = let ssh.key = let
inherit (nixosConfig.sops) secrets; inherit (nixosConfig.sops) secrets;
in mkIf (nixosOptions ? sops.secrets && secrets ? gensokyo-zone-nix-bld-key) (mkAlmostOptionDefault in
mkIf (nixosOptions ? sops.secrets && secrets ? gensokyo-zone-nix-bld-key) (
mkAlmostOptionDefault
nixosConfig.sops.secrets.gensokyo-zone-nix-bld-key.path nixosConfig.sops.secrets.gensokyo-zone-nix-bld-key.path
); );
setBuildMachine = { setBuildMachine = {
@ -153,9 +157,14 @@ in {
settings = unmerged.merge cfg.setNixSettings; settings = unmerged.merge cfg.setNixSettings;
buildMachines = unmerged.merge cfg.setNixBuildMachines; buildMachines = unmerged.merge cfg.setNixBuildMachines;
}; };
${if options ? sops.secrets then "sops" else null}.secrets = let ${
if options ? sops.secrets
then "sops"
else null
}.secrets = let
sopsFile = mkDefault ../secrets/nix.yaml; sopsFile = mkDefault ../secrets/nix.yaml;
in mkIf cfg.enable { in
mkIf cfg.enable {
gensokyo-zone-nix-bld-key = mkIf cfg.builder.ssh.commonKey { gensokyo-zone-nix-bld-key = mkIf cfg.builder.ssh.commonKey {
inherit sopsFile; inherit sopsFile;
}; };

View file

@ -76,10 +76,12 @@ in {
]; ];
}; };
allLan = { allLan = {
v4 = cfg.cidrForNetwork.loopback.v4 v4 =
cfg.cidrForNetwork.loopback.v4
++ cfg.cidrForNetwork.local.v4 ++ cfg.cidrForNetwork.local.v4
++ cfg.cidrForNetwork.int.v4; ++ cfg.cidrForNetwork.int.v4;
v6 = cfg.cidrForNetwork.loopback.v6 v6 =
cfg.cidrForNetwork.loopback.v6
++ cfg.cidrForNetwork.local.v6 ++ cfg.cidrForNetwork.local.v6
++ cfg.cidrForNetwork.int.v6; ++ cfg.cidrForNetwork.int.v6;
}; };

View file

@ -25,18 +25,27 @@ in {
default = "/run/access/peeps"; default = "/run/access/peeps";
}; };
}; };
config.${if hasSops then "sops" else null}.secrets = let config.${
if hasSops
then "sops"
else null
}.secrets = let
sopsFile = mkDefault ../../../nixos/secrets/access.yaml; sopsFile = mkDefault ../../../nixos/secrets/access.yaml;
sopsSecrets = mapAttrs' (name: _: nameValuePair (mkSopsName name) { sopsSecrets = mapAttrs' (name: _:
nameValuePair (mkSopsName name) {
inherit sopsFile; inherit sopsFile;
path = mkDefault "${cfg.stateDir}/${name}.nft"; path = mkDefault "${cfg.stateDir}/${name}.nft";
}) cfg.ranges; })
in mkIf cfg.enable sopsSecrets; cfg.ranges;
in
mkIf cfg.enable sopsSecrets;
config.networking = let config.networking = let
nftRanges = mapAttrsToList (name: range: let nftRanges = mapAttrsToList (name: range: let
nft = "define ${mkNftName name} = ${range}"; nft = "define ${mkNftName name} = ${range}";
in mkBefore nft) cfg.ranges; in
mkBefore nft)
cfg.ranges;
condition = "ip6 saddr { ${concatStringsSep "," (mapAttrsToList (name: _: "$" + mkNftName name) cfg.ranges)} }"; condition = "ip6 saddr { ${concatStringsSep "," (mapAttrsToList (name: _: "$" + mkNftName name) cfg.ranges)} }";
in { in {
nftables.ruleset = mkIf cfg.enable (mkMerge ( nftables.ruleset = mkIf cfg.enable (mkMerge (

View file

@ -1,4 +1,10 @@
{ config, lib, gensokyo-zone, pkgs, ... }: let {
config,
lib,
gensokyo-zone,
pkgs,
...
}: let
inherit (gensokyo-zone.lib) mkAlmostOptionDefault mapOptionDefaults unmerged; inherit (gensokyo-zone.lib) mkAlmostOptionDefault mapOptionDefaults unmerged;
inherit (lib.options) mkOption mkEnableOption mkPackageOption; inherit (lib.options) mkOption mkEnableOption mkPackageOption;
inherit (lib.modules) mkIf mkMerge mkDefault mkOptionDefault; inherit (lib.modules) mkIf mkMerge mkDefault mkOptionDefault;
@ -8,9 +14,12 @@
cfg = config.services.barcodebuddy; cfg = config.services.barcodebuddy;
toEnvName = key: "BBUDDY_" + key; toEnvName = key: "BBUDDY_" + key;
toEnvValue = value: toEnvValue = value:
if value == true then "true" if value == true
else if value == false then "false" then "true"
else if isList value then concatStringsSep ";" (imap0 (i: v: "${toString i}=${toEnvValue v}") value) else if value == false
then "false"
else if isList value
then concatStringsSep ";" (imap0 (i: v: "${toString i}=${toEnvValue v}") value)
else toString value; else toString value;
toEnvPair = key: value: nameValuePair (toEnvName key) (toEnvValue value); toEnvPair = key: value: nameValuePair (toEnvName key) (toEnvValue value);
toPhpEnvPair = key: value: nameValuePair (toEnvName key) ''"${toEnvValue value}"''; toPhpEnvPair = key: value: nameValuePair (toEnvName key) ''"${toEnvValue value}"'';
@ -65,10 +74,12 @@ in {
type = nullOr str; type = nullOr str;
default = null; default = null;
}; };
/* TODO: passwordFile = mkOption { /*
TODO: passwordFile = mkOption {
type = nullOr path; type = nullOr path;
default = null; default = null;
};*/ };
*/
}; };
settings = mkOption { settings = mkOption {
type = attrsOf (oneOf [str bool int (listOf str)]); type = attrsOf (oneOf [str bool int (listOf str)]);
@ -95,9 +106,19 @@ in {
bbuddyConfig.services.barcodebuddy = { bbuddyConfig.services.barcodebuddy = {
settings = let settings = let
defaults = mapOptionDefaults { defaults = mapOptionDefaults {
${if cfg.screen.enable then "PORT_WEBSOCKET_SERVER" else null} = cfg.screen.websocketPort; ${
if cfg.screen.enable
then "PORT_WEBSOCKET_SERVER"
else null
} =
cfg.screen.websocketPort;
SEARCH_ENGINE = "https://google.com/search?q="; SEARCH_ENGINE = "https://google.com/search?q=";
${if cfg.reverseProxy.enable then "TRUSTED_PROXIES" else null} = cfg.reverseProxy.trustedAddresses; ${
if cfg.reverseProxy.enable
then "TRUSTED_PROXIES"
else null
} =
cfg.reverseProxy.trustedAddresses;
DISABLE_AUTHENTICATION = false; DISABLE_AUTHENTICATION = false;
DATABASE_PATH = cfg.databasePath; DATABASE_PATH = cfg.databasePath;
AUTHDB_PATH = cfg.authDatabasePath; AUTHDB_PATH = cfg.authDatabasePath;
@ -109,7 +130,8 @@ in {
REDIS_PORT = cfg.redis.port; REDIS_PORT = cfg.redis.port;
REDIS_PW = toString cfg.redis.password; REDIS_PW = toString cfg.redis.password;
}; };
in mkMerge [ defaults (mkIf cfg.redis.enable redis) ]; in
mkMerge [defaults (mkIf cfg.redis.enable redis)];
nginxConfig = '' nginxConfig = ''
index index.php index.html index.htm; index index.php index.html index.htm;
''; '';
@ -125,9 +147,14 @@ in {
}; };
redis = let redis = let
redis = config.services.redis.servers.${cfg.redis.server}; redis = config.services.redis.servers.${cfg.redis.server};
in mkIf (cfg.redis.server != null) { in
mkIf (cfg.redis.server != null) {
enable = mkAlmostOptionDefault redis.enable; enable = mkAlmostOptionDefault redis.enable;
ip = mkOptionDefault (if redis.bind == null then "localhost" else redis.bind); ip = mkOptionDefault (
if redis.bind == null
then "localhost"
else redis.bind
);
port = mkIf (redis.port != 0) (mkOptionDefault redis.port); port = mkIf (redis.port != 0) (mkOptionDefault redis.port);
password = mkAlmostOptionDefault redis.requirePass; password = mkAlmostOptionDefault redis.requirePass;
# TODO: passwordFile = mkAlmostOptionDefault redis.requirePassFile; # TODO: passwordFile = mkAlmostOptionDefault redis.requirePassFile;
@ -146,7 +173,10 @@ in {
user = "barcodebuddy"; user = "barcodebuddy";
inherit (config.services.nginx) group; inherit (config.services.nginx) group;
phpPackage = cfg.phpPackageUnwrapped.withExtensions ({ enabled, all }: [ phpPackage = cfg.phpPackageUnwrapped.withExtensions ({
enabled,
all,
}: [
all.curl all.curl
all.mbstring all.mbstring
all.sqlite3 all.sqlite3
@ -202,5 +232,6 @@ in {
User = "barcodebuddy"; User = "barcodebuddy";
}; };
}; };
in mkMerge [ bbuddyConfig (mkIf cfg.enable conf) ]; in
mkMerge [bbuddyConfig (mkIf cfg.enable conf)];
} }

View file

@ -36,7 +36,8 @@ in {
config.services.sssd = let config.services.sssd = let
inherit (config.services) sssd; inherit (config.services) sssd;
ipaDebugLevel = 65510; ipaDebugLevel = 65510;
in mkIf cfg.enable { in
mkIf cfg.enable {
debugLevel = mkAlmostOptionDefault ipaDebugLevel; debugLevel = mkAlmostOptionDefault ipaDebugLevel;
domains = { domains = {
${cfg.domain} = { ${cfg.domain} = {
@ -47,7 +48,8 @@ in {
telephoneNumber = "telephoneNumber"; telephoneNumber = "telephoneNumber";
lock = "nsaccountlock"; lock = "nsaccountlock";
}; };
settings = mapOptionDefaults { settings =
mapOptionDefaults {
id_provider = "ipa"; id_provider = "ipa";
auth_provider = "ipa"; auth_provider = "ipa";
access_provider = "ipa"; access_provider = "ipa";
@ -67,7 +69,8 @@ in {
dyndns_iface = cfg.dyndns.interface; dyndns_iface = cfg.dyndns.interface;
ldap_tls_cacert = "/etc/ipa/ca.crt"; ldap_tls_cacert = "/etc/ipa/ca.crt";
} // { }
// {
krb5_realm = mkIf (toLower cfg.domain != toLower cfg.realm) (mkOptionDefault cfg.realm); krb5_realm = mkIf (toLower cfg.domain != toLower cfg.realm) (mkOptionDefault cfg.realm);
}; };
}; };
@ -137,7 +140,8 @@ in {
config.environment.etc."krb5.conf" = let config.environment.etc."krb5.conf" = let
inherit (config.security) krb5; inherit (config.security) krb5;
format = import (modulesPath + "/security/krb5/krb5-conf-format.nix") {inherit pkgs lib;} {}; format = import (modulesPath + "/security/krb5/krb5-conf-format.nix") {inherit pkgs lib;} {};
in mkIf (cfg.enable && !cfg.overrideConfigs.krb5) { in
mkIf (cfg.enable && !cfg.overrideConfigs.krb5) {
text = mkForce (format.generate "krb5.conf" krb5.settings).text; text = mkForce (format.generate "krb5.conf" krb5.settings).text;
}; };
} }

View file

@ -1,4 +1,8 @@
{config, lib, ...}: let {
config,
lib,
...
}: let
inherit (lib.options) mkOption; inherit (lib.options) mkOption;
inherit (lib.modules) mkOptionDefault; inherit (lib.modules) mkOptionDefault;
cfg = config.services.keycloak; cfg = config.services.keycloak;
@ -14,7 +18,11 @@ in {
}; };
}; };
config.services.keycloak = { config.services.keycloak = {
protocol = mkOptionDefault (if cfg.sslCertificate != null then "https" else "http"); protocol = mkOptionDefault (
if cfg.sslCertificate != null
then "https"
else "http"
);
port = mkOptionDefault cfg.settings."${cfg.protocol}-port"; port = mkOptionDefault cfg.settings."${cfg.protocol}-port";
}; };
} }

View file

@ -1,4 +1,10 @@
{ gensokyo-zone, pkgs, config, lib, ... }: let {
gensokyo-zone,
pkgs,
config,
lib,
...
}: let
inherit (gensokyo-zone.lib) mkBaseDn mapDefaults mkAlmostOptionDefault mapOptionDefaults domain; inherit (gensokyo-zone.lib) mkBaseDn mapDefaults mkAlmostOptionDefault mapOptionDefaults domain;
inherit (lib.options) mkOption mkEnableOption; inherit (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkDefault mkOptionDefault mkForce; inherit (lib.modules) mkIf mkDefault mkOptionDefault mkForce;
@ -64,7 +70,8 @@ in {
krb5-ldap = pkgs.krb5.override { krb5-ldap = pkgs.krb5.override {
withLdap = true; withLdap = true;
}; };
in mkIf (cfg.enable && cfg.db.backend == "kldap") (mkDefault pkgs.krb5-ldap or krb5-ldap); in
mkIf (cfg.enable && cfg.db.backend == "kldap") (mkDefault pkgs.krb5-ldap or krb5-ldap);
settings = mkIf cfg.enable { settings = mkIf cfg.enable {
dbmodules = { dbmodules = {
genso-kldap = mkIf (cfg.db.backend == "kldap") (mapDefaults { genso-kldap = mkIf (cfg.db.backend == "kldap") (mapDefaults {
@ -72,7 +79,8 @@ in {
ldap_servers = concatStringsSep " " cfg.ldap.urls; ldap_servers = concatStringsSep " " cfg.ldap.urls;
ldap_kdc_dn = cfg.ldap.bind.dn; ldap_kdc_dn = cfg.ldap.bind.dn;
ldap_kerberos_container_dn = cfg.ldap.baseDn; ldap_kerberos_container_dn = cfg.ldap.baseDn;
} // { }
// {
ldap_service_password_file = mkIf (cfg.ldap.bind.passwordFile != null) (mkDefault cfg.ldap.bind.passwordFile); ldap_service_password_file = mkIf (cfg.ldap.bind.passwordFile != null) (mkDefault cfg.ldap.bind.passwordFile);
}); });
genso-ipa = mkIf (cfg.db.backend == "ipa") (mapDefaults { genso-ipa = mkIf (cfg.db.backend == "ipa") (mapDefaults {
@ -80,13 +88,15 @@ in {
}); });
${cfg.realm} = mkIf ipa.enable (mkForce {}); ${cfg.realm} = mkIf ipa.enable (mkForce {});
}; };
realms.${cfg.realm} = mapDefaults { realms.${cfg.realm} =
mapDefaults {
kdc = "${cfg.host}:88"; kdc = "${cfg.host}:88";
master_kdc = "${cfg.host}:88"; master_kdc = "${cfg.host}:88";
admin_server = "${cfg.host}:749"; admin_server = "${cfg.host}:749";
default_domain = cfg.domain; default_domain = cfg.domain;
pkinit_anchors = ["FILE:${cfg.ca.cert}"]; pkinit_anchors = ["FILE:${cfg.ca.cert}"];
} // { }
// {
database_module = mkOptionDefault "genso-${cfg.db.backend}"; database_module = mkOptionDefault "genso-${cfg.db.backend}";
auth_to_local_names = mkIf (cfg.authToLocalNames != {}) (mkDefault (subsection cfg.authToLocalNames)); auth_to_local_names = mkIf (cfg.authToLocalNames != {}) (mkDefault (subsection cfg.authToLocalNames));
}; };
@ -112,7 +122,8 @@ in {
url = "https://ipa.${cfg.domain}/ipa/config/ca.crt"; url = "https://ipa.${cfg.domain}/ipa/config/ca.crt";
sha256 = "sha256-PKjnjn1jIq9x4BX8+WGkZfj4HQtmnHqmFSALqggo91o="; sha256 = "sha256-PKjnjn1jIq9x4BX8+WGkZfj4HQtmnHqmFSALqggo91o=";
}; };
in mkOptionDefault caPem; in
mkOptionDefault caPem;
db.backend = mkIf ipa.enable (mkAlmostOptionDefault "ipa"); db.backend = mkIf ipa.enable (mkAlmostOptionDefault "ipa");
ldap.urls = mkOptionDefault [ ldap.urls = mkOptionDefault [
"ldaps://ldap.${cfg.domain}" "ldaps://ldap.${cfg.domain}"
@ -127,9 +138,11 @@ in {
domain = mkDefault cfg.domain; domain = mkDefault cfg.domain;
realm = mkDefault cfg.realm; realm = mkDefault cfg.realm;
server = mkDefault cfg.canonHost; server = mkDefault cfg.canonHost;
ifpAllowedUids = [ ifpAllowedUids =
[
"root" "root"
] ++ config.users.groups.wheel.members; ]
++ config.users.groups.wheel.members;
dyndns.enable = mkDefault false; dyndns.enable = mkDefault false;
}; };
}; };

View file

@ -1,5 +1,11 @@
let let
allowListModule = {config, name, gensokyo-zone, lib, ...}: let allowListModule = {
config,
name,
gensokyo-zone,
lib,
...
}: let
inherit (gensokyo-zone.Std) UInt; inherit (gensokyo-zone.Std) UInt;
inherit (lib.options) mkOption; inherit (lib.options) mkOption;
inherit (lib.modules) mkOptionDefault; inherit (lib.modules) mkOptionDefault;
@ -25,10 +31,12 @@ let
}; };
}; };
config = let config = let
xuid = { xuid =
{
string = toString (UInt.FromHex config.xuid); string = toString (UInt.FromHex config.xuid);
int = toString config.xuid; int = toString config.xuid;
}.${typeOf config.xuid}; }
.${typeOf config.xuid};
in { in {
settings = { settings = {
name = mkOptionDefault config.name; name = mkOptionDefault config.name;
@ -41,14 +49,20 @@ let
}; };
}; };
}; };
packModule = {config, lib, ...}: let packModule = {
config,
lib,
...
}: let
inherit (lib.options) mkOption mkEnableOption; inherit (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkOptionDefault; inherit (lib.modules) mkIf mkOptionDefault;
inherit (lib.strings) splitString; inherit (lib.strings) splitString;
inherit (builtins) typeOf; inherit (builtins) typeOf;
in { in {
options = with lib.types; { options = with lib.types; {
enable = mkEnableOption "pack" // { enable =
mkEnableOption "pack"
// {
default = true; default = true;
}; };
package = mkOption { package = mkOption {
@ -72,28 +86,42 @@ let
}; };
}; };
config = { config = {
packId = mkIf (config.package != null && config.package ? minecraft-bedrock.pack.pack_id) (mkOptionDefault packId = mkIf (config.package != null && config.package ? minecraft-bedrock.pack.pack_id) (
mkOptionDefault
config.package.minecraft-bedrock.pack.pack_id config.package.minecraft-bedrock.pack.pack_id
); );
packType = mkIf (config.package != null && config.package ? minecraft-bedrock.pack.type) (mkOptionDefault packType = mkIf (config.package != null && config.package ? minecraft-bedrock.pack.type) (
mkOptionDefault
config.package.minecraft-bedrock.pack.type config.package.minecraft-bedrock.pack.type
); );
version = mkIf (config.package != null && config.package ? minecraft-bedrock.pack.version) (mkOptionDefault version = mkIf (config.package != null && config.package ? minecraft-bedrock.pack.version) (
mkOptionDefault
config.package.minecraft-bedrock.pack.version config.package.minecraft-bedrock.pack.version
); );
packDir = mkIf (config.package != null && config.package ? minecraft-bedrock.pack.dir) (mkOptionDefault packDir = mkIf (config.package != null && config.package ? minecraft-bedrock.pack.dir) (
mkOptionDefault
config.package.minecraft-bedrock.pack.dir config.package.minecraft-bedrock.pack.dir
); );
settings = { settings = {
pack_id = mkOptionDefault config.packId; pack_id = mkOptionDefault config.packId;
version = mkOptionDefault { version =
mkOptionDefault
{
string = splitString "." config.version; string = splitString "." config.version;
list = config.version; list = config.version;
}.${typeOf config.version}; }
.${typeOf config.version};
}; };
}; };
}; };
in { config, gensokyo-zone, lib, pkgs, ... }: let in
{
config,
gensokyo-zone,
lib,
pkgs,
...
}: let
# see https://gist.github.com/datakurre/cfdf627fb23ed8ff62bb7b3520b92674 # see https://gist.github.com/datakurre/cfdf627fb23ed8ff62bb7b3520b92674
inherit (gensokyo-zone.lib) mapOptionDefaults; inherit (gensokyo-zone.lib) mapOptionDefaults;
inherit (lib.options) mkOption mkPackageOption; inherit (lib.options) mkOption mkPackageOption;
@ -106,12 +134,17 @@ in { config, gensokyo-zone, lib, pkgs, ... }: let
inherit (builtins) toJSON; inherit (builtins) toJSON;
cfg = config.services.minecraft-bedrock-server; cfg = config.services.minecraft-bedrock-server;
cfgToString = v: if builtins.isBool v then boolToString v else toString v; cfgToString = v:
if builtins.isBool v
then boolToString v
else toString v;
serverPropertiesFile = pkgs.writeText "server.properties" ('' serverPropertiesFile = pkgs.writeText "server.properties" (''
# server.properties managed by NixOS configuration # server.properties managed by NixOS configuration
'' + concatStringsSep "\n" (mapAttrsToList ''
(n: v: "${n}=${cfgToString v}") cfg.serverProperties)); + concatStringsSep "\n" (mapAttrsToList
(n: v: "${n}=${cfgToString v}")
cfg.serverProperties));
in { in {
options.services.minecraft-bedrock-server = with lib.types; { options.services.minecraft-bedrock-server = with lib.types; {
enable = mkOption { enable = mkOption {
@ -167,7 +200,9 @@ in {
''; '';
}; };
package = mkPackageOption pkgs "minecraft-bedrock-server" { }// { package =
mkPackageOption pkgs "minecraft-bedrock-server" {}
// {
description = "Version of minecraft-bedrock-server to run."; description = "Version of minecraft-bedrock-server to run.";
}; };
@ -249,8 +284,10 @@ in {
allowListJson = pkgs.writeText "minecraft-bedrock-server-allowlist.json" ( allowListJson = pkgs.writeText "minecraft-bedrock-server-allowlist.json" (
toJSON allowPlayers toJSON allowPlayers
); );
in mkOptionDefault ( in
if cfg.allowPlayers != null then allowListJson mkOptionDefault (
if cfg.allowPlayers != null
then allowListJson
else null else null
); );
permissions = let permissions = let
@ -258,8 +295,10 @@ in {
permissionsJson = pkgs.writeText "minecraft-bedrock-server-permissions.json" ( permissionsJson = pkgs.writeText "minecraft-bedrock-server-permissions.json" (
toJSON permissions toJSON permissions
); );
in mkOptionDefault ( in
if cfg.allowPlayers != null then permissionsJson mkOptionDefault (
if cfg.allowPlayers != null
then permissionsJson
else null else null
); );
}; };
@ -292,13 +331,15 @@ in {
"config/default" "config/default"
"bedrock_server_symbols.debug" "bedrock_server_symbols.debug"
"env-vars" "env-vars"
] ++ optional (cfg.permissions == null) "permissions.json"); ]
++ optional (cfg.permissions == null) "permissions.json");
mkWorldPacks = type: let mkWorldPacks = type: let
enabledPacks = filterAttrs (_: pack: pack.enable && pack.packType == "${type}_packs") cfg.packs; enabledPacks = filterAttrs (_: pack: pack.enable && pack.packType == "${type}_packs") cfg.packs;
jsonName = "world_${type}_packs.json"; jsonName = "world_${type}_packs.json";
packsJson = mapAttrsToList (_: pack: pack.settings) enabledPacks; packsJson = mapAttrsToList (_: pack: pack.settings) enabledPacks;
packsJsonPath = pkgs.writeText jsonName (toJSON packsJson); packsJsonPath = pkgs.writeText jsonName (toJSON packsJson);
in mkIf (enabledPacks != { }) [ in
mkIf (enabledPacks != {}) [
"${packsJsonPath}:${cfg.dataDir}/worlds/${cfg.serverProperties.level-name}/${jsonName}" "${packsJsonPath}:${cfg.dataDir}/worlds/${cfg.serverProperties.level-name}/${jsonName}"
]; ];
mapWorldPacks = packs: let mapWorldPacks = packs: let
@ -306,13 +347,15 @@ in {
mapPackPath = _: pack: let mapPackPath = _: pack: let
subDir = "${pack.packType}/${pack.packDir}"; subDir = "${pack.packType}/${pack.packDir}";
in "${pack.package}/${cfg.package.dataDir}/${subDir}:${cfg.dataDir}/${subDir}"; in "${pack.package}/${cfg.package.dataDir}/${subDir}:${cfg.dataDir}/${subDir}";
in mapAttrsToList mapPackPath enabledPacks; in
mapAttrsToList mapPackPath enabledPacks;
packsPaths = mkMerge [ packsPaths = mkMerge [
(mkWorldPacks "behavior") (mkWorldPacks "behavior")
(mkWorldPacks "resource") (mkWorldPacks "resource")
(mapWorldPacks cfg.packs) (mapWorldPacks cfg.packs)
]; ];
in mkMerge [ in
mkMerge [
packageResources packageResources
(mkIf (cfg.allowList != null) ["${cfg.allowList}:${cfg.dataDir}/allowlist.json"]) (mkIf (cfg.allowList != null) ["${cfg.allowList}:${cfg.dataDir}/allowlist.json"])
(mkIf (cfg.permissions != null) ["${cfg.permissions}:${cfg.dataDir}/permissions.json"]) (mkIf (cfg.permissions != null) ["${cfg.permissions}:${cfg.dataDir}/permissions.json"])
@ -340,10 +383,12 @@ in {
conf.networking.firewall = let conf.networking.firewall = let
ports = [cfg.serverProperties.server-port cfg.serverProperties.server-portv6]; ports = [cfg.serverProperties.server-port cfg.serverProperties.server-portv6];
in mkIf cfg.openFirewall { in
mkIf cfg.openFirewall {
allowedUDPPorts = ports; allowedUDPPorts = ports;
}; };
in mkMerge [ in
mkMerge [
confService confService
(mkIf cfg.enable conf) (mkIf cfg.enable conf)
]; ];

View file

@ -9,7 +9,11 @@
inherit (lib.strings) concatStringsSep; inherit (lib.strings) concatStringsSep;
inherit (config.system) nssDatabases; inherit (config.system) nssDatabases;
inherit (config) networking; inherit (config) networking;
netgroupMemberModule = { config, name, ... }: { netgroupMemberModule = {
config,
name,
...
}: {
options = with lib.types; { options = with lib.types; {
hostname = mkOption { hostname = mkOption {
type = str; type = str;
@ -32,7 +36,11 @@
triple = mkOptionDefault "(${config.hostname},${toString config.user},${config.domain})"; triple = mkOptionDefault "(${config.hostname},${toString config.user},${config.domain})";
}; };
}; };
netgroupModule = { config, name, ... }: { netgroupModule = {
config,
name,
...
}: {
options = with lib.types; { options = with lib.types; {
name = mkOption { name = mkOption {
type = str; type = str;

View file

@ -1,4 +1,8 @@
{config, lib, ...}: let {
config,
lib,
...
}: let
inherit (lib.options) mkOption mkEnableOption; inherit (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkOptionDefault; inherit (lib.modules) mkIf mkOptionDefault;
inherit (lib.lists) filter optional; inherit (lib.lists) filter optional;
@ -7,11 +11,20 @@
enabledNameservers = filter (ns: ns.enable) (config.networking.nameservers'); enabledNameservers = filter (ns: ns.enable) (config.networking.nameservers');
nameserverModule = {config, ...}: let nameserverModule = {config, ...}: let
dnsPort = 53; dnsPort = 53;
mkResolvedValue = { address, port, interface ? null, host ? null }: let mkResolvedValue = {
address,
port,
interface ? null,
host ? null,
}: let
isIpv6 = hasInfix ":" address; isIpv6 = hasInfix ":" address;
isPlain = port == dnsPort && interface == null && host == null; isPlain = port == dnsPort && interface == null && host == null;
addr = if isIpv6 && !isPlain then "[${address}]" else address; addr =
in concatStrings ( if isIpv6 && !isPlain
then "[${address}]"
else address;
in
concatStrings (
[addr] [addr]
++ optional (port != dnsPort) ":${toString port}" ++ optional (port != dnsPort) ":${toString port}"
++ optional (interface != null) "%${interface}" ++ optional (interface != null) "%${interface}"
@ -19,7 +32,9 @@
); );
in { in {
options = with lib.types; { options = with lib.types; {
enable = mkEnableOption "nameserver" // { enable =
mkEnableOption "nameserver"
// {
default = true; default = true;
}; };
address = mkOption { address = mkOption {
@ -64,7 +79,11 @@ in {
}; };
config = { config = {
networking.nameservers = mkIf (config.networking.nameservers' != []) ( networking.nameservers = mkIf (config.networking.nameservers' != []) (
map (ns: if resolved.enable then ns.resolvedValue else ns.value) enabledNameservers map (ns:
if resolved.enable
then ns.resolvedValue
else ns.value)
enabledNameservers
); );
}; };
} }

View file

@ -21,7 +21,11 @@
(mkIf (cfg.server.mountdPort != null) cfg.server.mountdPort) (mkIf (cfg.server.mountdPort != null) cfg.server.mountdPort)
]; ];
concatFlags = concatStringsSep ","; concatFlags = concatStringsSep ",";
clientModule = { config, name, ... }: { clientModule = {
config,
name,
...
}: {
options = with lib.types; { options = with lib.types; {
machine = mkOption { machine = mkOption {
type = oneOf [str (listOf str)]; type = oneOf [str (listOf str)];
@ -40,10 +44,15 @@
entry = let entry = let
flags = optionalString (config.flags != []) "(${concatFlags config.flags})"; flags = optionalString (config.flags != []) "(${concatFlags config.flags})";
machines = toList config.machine; machines = toList config.machine;
in mkOptionDefault (concatMapStringsSep " " (machine: machine + flags) machines); in
mkOptionDefault (concatMapStringsSep " " (machine: machine + flags) machines);
}; };
}; };
exportModule = { config, name, ... }: { exportModule = {
config,
name,
...
}: {
options = with lib.types; { options = with lib.types; {
path = mkOption { path = mkOption {
type = path; type = path;
@ -62,10 +71,12 @@
config = { config = {
flags = mkOptionDefault (cfg.export.flagSets.common or []); flags = mkOptionDefault (cfg.export.flagSets.common or []);
fileLine = let fileLine = let
parts = [ config.path ] parts =
[config.path]
++ optional (config.flags != []) "-${concatFlags config.flags}" ++ optional (config.flags != []) "-${concatFlags config.flags}"
++ mapAttrsToList (_: client: client.entry) config.clients; ++ mapAttrsToList (_: client: client.entry) config.clients;
in mkOptionDefault (concatStringsSep " " parts); in
mkOptionDefault (concatStringsSep " " parts);
}; };
}; };
in { in {

View file

@ -1,13 +1,16 @@
{ {lib, ...}: let
lib,
...
}: let
inherit (lib.options) mkOption mkEnableOption; inherit (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkOverride; inherit (lib.modules) mkIf mkOverride;
mkExtraForce = mkOverride 25; mkExtraForce = mkOverride 25;
locationModule = { config, virtualHost, ... }: { locationModule = {
config,
virtualHost,
...
}: {
options = with lib.types; { options = with lib.types; {
enable = mkEnableOption "enable location" // { enable =
mkEnableOption "enable location"
// {
default = true; default = true;
}; };
}; };
@ -17,7 +20,9 @@
}; };
hostModule = {config, ...}: { hostModule = {config, ...}: {
options = with lib.types; { options = with lib.types; {
enable = mkEnableOption "enable server" // { enable =
mkEnableOption "enable server"
// {
default = true; default = true;
}; };
locations = mkOption { locations = mkOption {

View file

@ -43,7 +43,8 @@ let
config = { config = {
fastcgi = { fastcgi = {
socket = mkIf (cfg.phpfpmPool != null) (mkAlmostOptionDefault socket = mkIf (cfg.phpfpmPool != null) (
mkAlmostOptionDefault
nixosConfig.services.phpfpm.pools.${cfg.phpfpmPool}.socket nixosConfig.services.phpfpm.pools.${cfg.phpfpmPool}.socket
); );
params = mapOptionDefaults { params = mapOptionDefaults {
@ -60,18 +61,24 @@ let
extraConfig = let extraConfig = let
passHeadersConfig = map (header: "fastcgi_pass_header ${xvars.escapeString header};") passHeaders; passHeadersConfig = map (header: "fastcgi_pass_header ${xvars.escapeString header};") passHeaders;
paramsConfig = mapAttrsToList (param: value: mkJustAfter "fastcgi_param ${param} ${xvars.escapeString value};") params; paramsConfig = mapAttrsToList (param: value: mkJustAfter "fastcgi_param ${param} ${xvars.escapeString value};") params;
in mkIf cfg.enable (mkMerge ([ in
mkIf cfg.enable (mkMerge ([
(mkIf cfg.includeDefaults (mkAlmostBefore '' (mkIf cfg.includeDefaults (mkAlmostBefore ''
include ${nginx.package}/conf/fastcgi.conf; include ${nginx.package}/conf/fastcgi.conf;
'')) ''))
(mkIf (cfg.socket != null) (mkJustAfter '' (mkIf (cfg.socket != null) (mkJustAfter ''
fastcgi_pass unix:${cfg.socket}; fastcgi_pass unix:${cfg.socket};
'')) ''))
] ++ passHeadersConfig ]
++ passHeadersConfig
++ paramsConfig)); ++ paramsConfig));
}; };
}; };
hostModule = {config, lib, ...}: let hostModule = {
config,
lib,
...
}: let
inherit (lib.options) mkOption; inherit (lib.options) mkOption;
in { in {
options = with lib.types; { options = with lib.types; {
@ -80,10 +87,8 @@ let
}; };
}; };
}; };
in { in
lib, {lib, ...}: let
...
}: let
inherit (lib.options) mkOption; inherit (lib.options) mkOption;
in { in {
options = with lib.types; { options = with lib.types; {

View file

@ -1,5 +1,12 @@
let let
locationModule = { config, virtualHost, xvars, gensokyo-zone, lib, ... }: let locationModule = {
config,
virtualHost,
xvars,
gensokyo-zone,
lib,
...
}: let
inherit (gensokyo-zone.lib) mapOptionDefaults; inherit (gensokyo-zone.lib) mapOptionDefaults;
inherit (lib.options) mkOption; inherit (lib.options) mkOption;
inherit (lib.modules) mkIf mkMerge mkAfter mkOptionDefault; inherit (lib.modules) mkIf mkMerge mkAfter mkOptionDefault;
@ -18,7 +25,8 @@ let
}; };
config = let config = let
mkHeader = name: value: mkHeader = name: value:
if isList value then mkMerge (map (mkHeader name) value) if isList value
then mkMerge (map (mkHeader name) value)
else mkAfter "add_header ${name} ${xvars.escapeString value};"; else mkAfter "add_header ${name} ${xvars.escapeString value};";
setHeaders = mapAttrsToList (name: value: mkIf (value != null) (mkHeader name value)) cfg.set; setHeaders = mapAttrsToList (name: value: mkIf (value != null) (mkHeader name value)) cfg.set;
in { in {
@ -31,7 +39,13 @@ let
extraConfig = mkMerge setHeaders; extraConfig = mkMerge setHeaders;
}; };
}; };
hostModule = { config, nixosConfig, gensokyo-zone, lib, ... }: let hostModule = {
config,
nixosConfig,
gensokyo-zone,
lib,
...
}: let
inherit (gensokyo-zone.lib) mapOptionDefaults; inherit (gensokyo-zone.lib) mapOptionDefaults;
inherit (lib.options) mkOption; inherit (lib.options) mkOption;
inherit (nixosConfig.services) nginx; inherit (nixosConfig.services) nginx;
@ -55,10 +69,8 @@ let
}; };
}; };
}; };
in { in
lib, {lib, ...}: let
...
}: let
inherit (lib.options) mkOption; inherit (lib.options) mkOption;
in { in {
options.services.nginx = with lib.types; { options.services.nginx = with lib.types; {

View file

@ -10,9 +10,16 @@
inherit (lib.attrsets) attrValues mapAttrs; inherit (lib.attrsets) attrValues mapAttrs;
inherit (lib.lists) optional filter concatMap; inherit (lib.lists) optional filter concatMap;
inherit (config.services) nginx; inherit (config.services) nginx;
listenModule = { config, virtualHost, listenKind, ... }: { listenModule = {
config,
virtualHost,
listenKind,
...
}: {
options = with lib.types; { options = with lib.types; {
enable = mkEnableOption "this port" // { enable =
mkEnableOption "this port"
// {
default = true; default = true;
}; };
addr = mkOption { addr = mkOption {
@ -59,7 +66,9 @@
(mkIf (listenKind == "streamServer" && !config.ssl && virtualHost.ssl.enable && virtualHost.ssl.force != false) (mkForce false)) (mkIf (listenKind == "streamServer" && !config.ssl && virtualHost.ssl.enable && virtualHost.ssl.force != false) (mkForce false))
]; ];
port = mkIf (listenKind == "virtualHost") (mkOptionDefault ( port = mkIf (listenKind == "virtualHost") (mkOptionDefault (
if config.ssl then nginx.defaultSSLListenPort else nginx.defaultHTTPListenPort if config.ssl
then nginx.defaultSSLListenPort
else nginx.defaultHTTPListenPort
)); ));
addresses = mkMerge [ addresses = mkMerge [
(mkOptionDefault virtualHost.listenAddresses') (mkOptionDefault virtualHost.listenAddresses')
@ -74,26 +83,44 @@
); );
listenConfigs = let listenConfigs = let
# TODO: handle quic listener..? # TODO: handle quic listener..?
mkListenHost = { addr, port }: let mkListenHost = {
addr,
port,
}: let
host = host =
if addr != null then "${mkAddress6 addr}:${toString port}" if addr != null
then "${mkAddress6 addr}:${toString port}"
else toString port; else toString port;
in assert port != null; host; in
assert port != null; host;
mkDirective = addr: let mkDirective = addr: let
host = mkListenHost { inherit addr; inherit (config) port; }; host = mkListenHost {
in mkMerge ( inherit addr;
inherit (config) port;
};
in
mkMerge (
[(mkBefore host)] [(mkBefore host)]
++ config.listenParameters ++ config.listenParameters
); );
in mkOptionDefault (map (mkDirective) config.addresses); in
mkOptionDefault (map mkDirective config.addresses);
listenDirectives = mkMerge (map (conf: mkOptionDefault "listen ${conf};") config.listenConfigs); listenDirectives = mkMerge (map (conf: mkOptionDefault "listen ${conf};") config.listenConfigs);
}; };
}; };
listenType = { specialArgs, modules ? [ ] }: lib.types.submoduleWith { listenType = {
specialArgs,
modules ? [],
}:
lib.types.submoduleWith {
inherit specialArgs; inherit specialArgs;
modules = [listenModule] ++ modules; modules = [listenModule] ++ modules;
}; };
hostModule = { nixosConfig, config, ... }: let hostModule = {
nixosConfig,
config,
...
}: let
cfg = attrValues config.listen'; cfg = attrValues config.listen';
enabledCfg = filter (port: port.enable) cfg; enabledCfg = filter (port: port.enable) cfg;
mkListen = listen: addr: let mkListen = listen: addr: let
@ -101,7 +128,8 @@
inherit addr; inherit addr;
inherit (listen) port ssl extraParameters proxyProtocol; inherit (listen) port ssl extraParameters proxyProtocol;
}; };
in mapAttrs (_: mkAlmostOptionDefault) listenAttrs; in
mapAttrs (_: mkAlmostOptionDefault) listenAttrs;
mkListens = listen: map (mkListen listen) listen.addresses; mkListens = listen: map (mkListen listen) listen.addresses;
in { in {
options = with lib.types; { options = with lib.types; {
@ -124,14 +152,20 @@
config = { config = {
enable = mkIf (cfg != [] && enabledCfg == []) (mkForce false); enable = mkIf (cfg != [] && enabledCfg == []) (mkForce false);
listenAddresses' = mkOptionDefault ( listenAddresses' = mkOptionDefault (
if config.listenAddresses != [ ] then config.listenAddresses else nginx.defaultListenAddresses if config.listenAddresses != []
then config.listenAddresses
else nginx.defaultListenAddresses
); );
listen = mkIf (cfg != {}) (mkAlmostOptionDefault ( listen = mkIf (cfg != {}) (mkAlmostOptionDefault (
concatMap (mkListens) enabledCfg concatMap mkListens enabledCfg
)); ));
}; };
}; };
streamServerModule = { nixosConfig, config, ... }: let streamServerModule = {
nixosConfig,
config,
...
}: let
enabledListen = filter (port: port.enable) (attrValues config.listen); enabledListen = filter (port: port.enable) (attrValues config.listen);
in { in {
options = with lib.types; { options = with lib.types; {
@ -165,7 +199,9 @@
config = { config = {
enable = mkIf (config.listen != {} && enabledListen == []) (mkForce false); enable = mkIf (config.listen != {} && enabledListen == []) (mkForce false);
listenAddresses' = mkOptionDefault ( listenAddresses' = mkOptionDefault (
if config.listenAddresses != null then config.listenAddresses else nginx.defaultListenAddresses if config.listenAddresses != null
then config.listenAddresses
else nginx.defaultListenAddresses
); );
streamConfig = mkIf (config.listen != {}) (mkMerge ( streamConfig = mkIf (config.listen != {}) (mkMerge (
map (listen: mkBefore listen.listenDirectives) enabledListen map (listen: mkBefore listen.listenDirectives) enabledListen

View file

@ -8,16 +8,19 @@
inherit (lib.strings) concatMapStringsSep optionalString; inherit (lib.strings) concatMapStringsSep optionalString;
inherit (config.services) tailscale; inherit (config.services) tailscale;
inherit (config.networking.access) cidrForNetwork localaddrs; inherit (config.networking.access) cidrForNetwork localaddrs;
mkAddrVar = remoteAddr: varPrefix: '' mkAddrVar = remoteAddr: varPrefix:
''
set ${varPrefix}tailscale 0; set ${varPrefix}tailscale 0;
'' + optionalString tailscale.enable '' ''
+ optionalString tailscale.enable ''
if (${remoteAddr} ~ "^fd7a:115c:a1e0:(:|ab12:)") { if (${remoteAddr} ~ "^fd7a:115c:a1e0:(:|ab12:)") {
set ${varPrefix}tailscale 1; set ${varPrefix}tailscale 1;
} }
if (${remoteAddr} ~ "^100\.(6[4-9]|([7-9]|1[01])[0-9]|12[0-7])\.[0-9]+\.[0-9]+") { if (${remoteAddr} ~ "^100\.(6[4-9]|([7-9]|1[01])[0-9]|12[0-7])\.[0-9]+\.[0-9]+") {
set ${varPrefix}tailscale 1; set ${varPrefix}tailscale 1;
} }
'' + '' ''
+ ''
set ${varPrefix}lan 0; set ${varPrefix}lan 0;
if (${remoteAddr} ~ "^10\.1\.1\.[0-9]+") { if (${remoteAddr} ~ "^10\.1\.1\.[0-9]+") {
set ${varPrefix}lan 1; set ${varPrefix}lan 1;
@ -56,7 +59,11 @@
set ${varPrefix}client 1; set ${varPrefix}client 1;
} }
''; '';
localModule = {config, xvars, ...}: let localModule = {
config,
xvars,
...
}: let
cfg = config.local; cfg = config.local;
in { in {
options.local = with lib.types; { options.local = with lib.types; {
@ -97,7 +104,8 @@
${allows} ${allows}
deny all; deny all;
''; '';
in mkMerge [ in
mkMerge [
(mkIf cfg.emitDenyGlobal (mkBefore allowDirectives)) (mkIf cfg.emitDenyGlobal (mkBefore allowDirectives))
(mkIf cfg.emitVars (mkBefore (mkAddrVar "$remote_addr" "$local_"))) (mkIf cfg.emitVars (mkBefore (mkAddrVar "$remote_addr" "$local_")))
(mkIf (cfg.emitVars && config.xvars.enable) (mkBefore (mkAddrVar (xvars.remote_addr.get) "$x_local_"))) (mkIf (cfg.emitVars && config.xvars.enable) (mkBefore (mkAddrVar (xvars.remote_addr.get) "$x_local_")))

View file

@ -1,4 +1,9 @@
{pkgs, config, lib, ...}: let {
pkgs,
config,
lib,
...
}: let
inherit (lib.options) mkOption mkEnableOption; inherit (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkMerge mkAfter mkOptionDefault; inherit (lib.modules) mkIf mkMerge mkAfter mkOptionDefault;
inherit (lib.strings) hasPrefix; inherit (lib.strings) hasPrefix;
@ -10,7 +15,8 @@
luaModule = {config, ...}: let luaModule = {config, ...}: let
cfg = config.lua; cfg = config.lua;
mkSetBy = var: value: mkSetBy = var: value:
if hasPrefix "/" "${value}" then "set_by_lua_file \$${var} ${value};" if hasPrefix "/" "${value}"
then "set_by_lua_file \$${var} ${value};"
else '' else ''
set_by_lua_block ''$${var} { set_by_lua_block ''$${var} {
${value} ${value}
@ -40,10 +46,12 @@
${cfg.access.block} ${cfg.access.block}
} }
'')) ''))
(mkIf (cfg.access.files != [ ]) (assert lua.http.enable; mkMerge ( (mkIf (cfg.access.files != []) (assert lua.http.enable;
mkMerge (
map (file: "access_by_lua_file ${file};") cfg.access.files map (file: "access_by_lua_file ${file};") cfg.access.files
))) )))
(mkIf (cfg.set != { }) (assert lua.http.enable && lua.ndk.enable; mkMerge ( (mkIf (cfg.set != {}) (assert lua.http.enable && lua.ndk.enable;
mkMerge (
mapAttrsToList mkSetBy cfg.set mapAttrsToList mkSetBy cfg.set
))) )))
]; ];
@ -92,9 +100,11 @@ in {
config = { config = {
services.nginx = { services.nginx = {
lua = { lua = {
modules = [ modules =
[
cfg.luaPackage.pkgs.lua-resty-core cfg.luaPackage.pkgs.lua-resty-core
] ++ cfg.luaPackage.pkgs.lua-resty-core.propagatedBuildInputs; ]
++ cfg.luaPackage.pkgs.lua-resty-core.propagatedBuildInputs;
luaPath = mkMerge ( luaPath = mkMerge (
map luaPkgPath cfg.modules map luaPkgPath cfg.modules
++ [(mkAfter ";")] ++ [(mkAfter ";")]

View file

@ -46,18 +46,21 @@
config = { config = {
name = { name = {
qualifier = mkOptionDefault ( qualifier = mkOptionDefault (
if config.local.enable then "local" if config.local.enable
then "local"
else null else null
); );
includeTailscale = mkOptionDefault ( includeTailscale = mkOptionDefault (
config.local.enable && tailscale.enable && cfg.qualifier != "tail" config.local.enable && tailscale.enable && cfg.qualifier != "tail"
); );
localName = mkOptionDefault ( localName = mkOptionDefault (
if cfg.includeLocal then "${cfg.shortServer}.local.${networking.domain}" if cfg.includeLocal
then "${cfg.shortServer}.local.${networking.domain}"
else null else null
); );
tailscaleName = mkOptionDefault ( tailscaleName = mkOptionDefault (
if cfg.includeTailscale then "${cfg.shortServer}.tail.${networking.domain}" if cfg.includeTailscale
then "${cfg.shortServer}.tail.${networking.domain}"
else null else null
); );
}; };

View file

@ -1,5 +1,12 @@
let let
serverModule = {config, nixosConfig, name, gensokyo-zone, lib, ...}: let serverModule = {
config,
nixosConfig,
name,
gensokyo-zone,
lib,
...
}: let
inherit (gensokyo-zone.lib) mkAlmostOptionDefault; inherit (gensokyo-zone.lib) mkAlmostOptionDefault;
inherit (lib.options) mkOption mkEnableOption; inherit (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkBefore mkOptionDefault; inherit (lib.modules) mkIf mkBefore mkOptionDefault;
@ -26,7 +33,8 @@ let
inherit (nginx.stream) upstreams; inherit (nginx.stream) upstreams;
mkUpstream = host: upstream: "${host} ${upstreams.${upstream}.name};"; mkUpstream = host: upstream: "${host} ${upstreams.${upstream}.name};";
upstreams' = removeAttrs cfg.upstreams ["default"]; upstreams' = removeAttrs cfg.upstreams ["default"];
upstreamLines = mapAttrsToList mkUpstream upstreams' upstreamLines =
mapAttrsToList mkUpstream upstreams'
++ optional (cfg.upstreams ? default) (mkUpstream "default" cfg.upstreams.default); ++ optional (cfg.upstreams ? default) (mkUpstream "default" cfg.upstreams.default);
in { in {
ssl.preread = { ssl.preread = {
@ -46,7 +54,13 @@ let
serverBlock = mkIf cfg.enable (mkOptionDefault (mkBefore cfg.streamConfig)); serverBlock = mkIf cfg.enable (mkOptionDefault (mkBefore cfg.streamConfig));
}; };
}; };
in {config, gensokyo-zone, lib, ...}: let in
{
config,
gensokyo-zone,
lib,
...
}: let
inherit (gensokyo-zone.lib) mkAlmostOptionDefault; inherit (gensokyo-zone.lib) mkAlmostOptionDefault;
inherit (lib.options) mkOption mkEnableOption; inherit (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkDefault mkOptionDefault; inherit (lib.modules) mkIf mkDefault mkOptionDefault;

View file

@ -18,7 +18,14 @@ let
${xvars.init "forwarded_server" "$http_x_forwarded_server"} ${xvars.init "forwarded_server" "$http_x_forwarded_server"}
} }
''; '';
locationModule = { config, virtualHost, xvars, gensokyo-zone, lib, ... }: let locationModule = {
config,
virtualHost,
xvars,
gensokyo-zone,
lib,
...
}: let
inherit (gensokyo-zone.lib) mkJustBefore mkAlmostOptionDefault; inherit (gensokyo-zone.lib) mkJustBefore mkAlmostOptionDefault;
inherit (lib.options) mkOption; inherit (lib.options) mkOption;
inherit (lib.modules) mkIf mkMerge mkOptionDefault; inherit (lib.modules) mkIf mkMerge mkOptionDefault;
@ -65,7 +72,14 @@ let
]; ];
}; };
}; };
hostModule = { config, nixosConfig, xvars, gensokyo-zone, lib, ... }: let hostModule = {
config,
nixosConfig,
xvars,
gensokyo-zone,
lib,
...
}: let
inherit (gensokyo-zone.lib) mkAlmostOptionDefault orderJustBefore unmerged; inherit (gensokyo-zone.lib) mkAlmostOptionDefault orderJustBefore unmerged;
inherit (lib.options) mkOption; inherit (lib.options) mkOption;
inherit (lib.modules) mkIf mkOrder mkDefault; inherit (lib.modules) mkIf mkOrder mkDefault;
@ -105,11 +119,20 @@ let
proxied = { proxied = {
cloudflared = let cloudflared = let
listen = config.listen'.proxied; listen = config.listen'.proxied;
scheme = if listen.ssl then "https" else "http"; scheme =
in mkIf (cfg.enable == "cloudflared") { if listen.ssl
then "https"
else "http";
in
mkIf (cfg.enable == "cloudflared") {
ingressSettings.${config.serverName} = { ingressSettings.${config.serverName} = {
service = "${scheme}://localhost:${toString listen.port}"; service = "${scheme}://localhost:${toString listen.port}";
originRequest.${if scheme == "https" then "noTLSVerify" else null} = true; originRequest.${
if scheme == "https"
then "noTLSVerify"
else null
} =
true;
}; };
getIngress = {}: unmerged.mergeAttrs cfg.cloudflared.ingressSettings; getIngress = {}: unmerged.mergeAttrs cfg.cloudflared.ingressSettings;
}; };
@ -127,7 +150,8 @@ let
); );
}; };
}; };
in { in
{
config, config,
system, system,
gensokyo-zone, gensokyo-zone,

View file

@ -1,5 +1,12 @@
let let
proxyModule = {config, name, options, gensokyo-zone, lib, ...}: let proxyModule = {
config,
name,
options,
gensokyo-zone,
lib,
...
}: let
inherit (lib.options) mkOption mkEnableOption; inherit (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkMerge mkAfter mkOptionDefault; inherit (lib.modules) mkIf mkMerge mkAfter mkOptionDefault;
inherit (lib.strings) optionalString; inherit (lib.strings) optionalString;
@ -32,7 +39,14 @@ let
]); ]);
}; };
}; };
serverModule = {config, name, options, gensokyo-zone, lib, ...}: let serverModule = {
config,
name,
options,
gensokyo-zone,
lib,
...
}: let
inherit (lib.modules) mkIf mkAfter; inherit (lib.modules) mkIf mkAfter;
cfg = config.proxy; cfg = config.proxy;
in { in {
@ -41,12 +55,22 @@ let
config = let config = let
warnProxy = lib.warnIf (!cfg.enable && options.proxy.url.isDefined) "nginx.stream.servers.${name}.proxy.url set without proxy.enable"; warnProxy = lib.warnIf (!cfg.enable && options.proxy.url.isDefined) "nginx.stream.servers.${name}.proxy.url set without proxy.enable";
in { in {
streamConfig = warnProxy (mkIf cfg.enable (mkAfter streamConfig = warnProxy (mkIf cfg.enable (
mkAfter
"proxy_pass ${cfg.url};" "proxy_pass ${cfg.url};"
)); ));
}; };
}; };
locationModule = { config, nixosConfig, name, virtualHost, xvars, gensokyo-zone, lib, ... }: let locationModule = {
config,
nixosConfig,
name,
virtualHost,
xvars,
gensokyo-zone,
lib,
...
}: let
inherit (gensokyo-zone.lib) mkJustBefore mkJustAfter mkAlmostOptionDefault mapOptionDefaults coalesce parseUrl; inherit (gensokyo-zone.lib) mkJustBefore mkJustAfter mkAlmostOptionDefault mapOptionDefaults coalesce parseUrl;
inherit (lib.options) mkOption mkEnableOption; inherit (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkMerge mkBefore mkOptionDefault; inherit (lib.modules) mkIf mkMerge mkBefore mkOptionDefault;
@ -75,7 +99,9 @@ let
host = mkOption { host = mkOption {
type = nullOr str; type = nullOr str;
}; };
websocket.enable = mkEnableOption "websocket proxy" // { websocket.enable =
mkEnableOption "websocket proxy"
// {
default = cfg.inheritServerDefaults && virtualHost.proxy.websocket.enable; default = cfg.inheritServerDefaults && virtualHost.proxy.websocket.enable;
}; };
parsed = { parsed = {
@ -129,7 +155,10 @@ let
hasUpstream = cfg.upstream != null && !dynamicUpstream; hasUpstream = cfg.upstream != null && !dynamicUpstream;
hasUpstreamServer = upstream.defaultServerName != null; hasUpstreamServer = upstream.defaultServerName != null;
recommendedHeaders = { recommendedHeaders = {
Host = if cfg.host == null then xvars.get.proxy_hostport else cfg.host; Host =
if cfg.host == null
then xvars.get.proxy_hostport
else cfg.host;
Referer = xvars.get.referer; Referer = xvars.get.referer;
X-Real-IP = xvars.get.remote_addr; X-Real-IP = xvars.get.remote_addr;
X-Forwarded-For = xvars.get.forwarded_for; X-Forwarded-For = xvars.get.forwarded_for;
@ -137,10 +166,13 @@ let
X-Forwarded-Host = xvars.get.host; X-Forwarded-Host = xvars.get.host;
X-Forwarded-Server = xvars.get.forwarded_server; X-Forwarded-Server = xvars.get.forwarded_server;
}; };
schemePort = { schemePort =
{
http = 80; http = 80;
https = 443; https = 443;
}.${cfg.parsed.scheme} or (throw "unsupported proxy_scheme ${toString cfg.parsed.scheme}"); }
.${cfg.parsed.scheme}
or (throw "unsupported proxy_scheme ${toString cfg.parsed.scheme}");
upstreamHost = coalesce ([upstream.host] ++ optional hasUpstreamServer upstreamServer.addr); upstreamHost = coalesce ([upstream.host] ++ optional hasUpstreamServer upstreamServer.addr);
port = coalesce [cfg.parsed.port schemePort]; port = coalesce [cfg.parsed.port schemePort];
hostport = cfg.parsed.host + optionalString (port != schemePort) ":${toString port}"; hostport = cfg.parsed.host + optionalString (port != schemePort) ":${toString port}";
@ -174,8 +206,12 @@ let
${xvars.init "proxy_hostport" xvars.get.proxy_host} ${xvars.init "proxy_hostport" xvars.get.proxy_host}
} }
''; '';
init = if cfg.upstream != null then initUpstream else initDynamic; init =
in init; if cfg.upstream != null
then initUpstream
else initDynamic;
in
init;
hostHeader = coalesce [ hostHeader = coalesce [
cfg.headers.set.Host or null cfg.headers.set.Host or null
cfg.host cfg.host
@ -192,7 +228,8 @@ let
setHeaders' = filterAttrs (_: header: header != null) cfg.headers.set; setHeaders' = filterAttrs (_: header: header != null) cfg.headers.set;
setHeaders = concatStringsSep "\n" (mapAttrsToList ( setHeaders = concatStringsSep "\n" (mapAttrsToList (
name: value: "proxy_set_header ${name} ${xvars.escapeString value};" name: value: "proxy_set_header ${name} ${xvars.escapeString value};"
) setHeaders'); )
setHeaders');
hideHeaders = mapAttrsToList (header: hide: mkIf hide "proxy_hide_header ${xvars.escapeString header};") cfg.headers.hide; hideHeaders = mapAttrsToList (header: hide: mkIf hide "proxy_hide_header ${xvars.escapeString header};") cfg.headers.hide;
in { in {
xvars = { xvars = {
@ -210,9 +247,13 @@ let
url = mkIf (cfg.inheritServerDefaults && virtualHost.proxy.url != null) (mkOptionDefault virtualHost.proxy.url); url = mkIf (cfg.inheritServerDefaults && virtualHost.proxy.url != null) (mkOptionDefault virtualHost.proxy.url);
headers = { headers = {
enableRecommended = mkOptionDefault ( enableRecommended = mkOptionDefault (
if cfg.enable && (!cfg.inheritServerDefaults || virtualHost.proxy.headers.enableRecommended != false) then true if cfg.enable && (!cfg.inheritServerDefaults || virtualHost.proxy.headers.enableRecommended != false)
else if cfg.inheritServerDefaults then virtualHost.proxy.headers.enableRecommended then true
else if nginx.recommendedProxySettings then "nixpkgs" else false else if cfg.inheritServerDefaults
then virtualHost.proxy.headers.enableRecommended
else if nginx.recommendedProxySettings
then "nixpkgs"
else false
); );
set = mkMerge [ set = mkMerge [
(mkOptionDefault {}) (mkOptionDefault {})
@ -230,8 +271,10 @@ let
]; ];
}; };
host = mkOptionDefault ( host = mkOptionDefault (
if cfg.inheritServerDefaults && virtualHost.proxy.host != null then virtualHost.proxy.host if cfg.inheritServerDefaults && virtualHost.proxy.host != null
else if cfg.headers.enableRecommended == false then null then virtualHost.proxy.host
else if cfg.headers.enableRecommended == false
then null
else xvars.get.host else xvars.get.host
); );
parsed = { parsed = {
@ -242,11 +285,13 @@ let
mapNullable (_: url.path) config.proxyPass mapNullable (_: url.path) config.proxyPass
); );
host = mkOptionDefault ( host = mkOptionDefault (
if hasUpstream then assert url.host == upstream.name; upstreamHost if hasUpstream
then assert url.host == upstream.name; upstreamHost
else mapNullable (_: url.host) config.proxyPass else mapNullable (_: url.host) config.proxyPass
); );
port = mkOptionDefault ( port = mkOptionDefault (
if hasUpstream && hasUpstreamServer && url.port == null then assert url.host == upstream.name; upstreamServer.port if hasUpstream && hasUpstreamServer && url.port == null
then assert url.host == upstream.name; upstreamServer.port
else mapNullable (_: url.port) config.proxyPass else mapNullable (_: url.port) config.proxyPass
); );
}; };
@ -257,12 +302,19 @@ let
(mkIf virtualHost.xvars.enable (mkJustBefore initProxyVars)) (mkIf virtualHost.xvars.enable (mkJustBefore initProxyVars))
(mkIf (cfg.headers.rewriteReferer.enable) (mkJustBefore rewriteReferer)) (mkIf (cfg.headers.rewriteReferer.enable) (mkJustBefore rewriteReferer))
(mkIf (cfg.redirect.enable) (mkBefore redirect)) (mkIf (cfg.redirect.enable) (mkBefore redirect))
(mkIf (emitHeaders) (mkJustAfter setHeaders)) (mkIf emitHeaders (mkJustAfter setHeaders))
(mkIf cfg.websocket.enable "proxy_cache_bypass $http_upgrade;") (mkIf cfg.websocket.enable "proxy_cache_bypass $http_upgrade;")
] ++ hideHeaders)); ]
++ hideHeaders));
}; };
}; };
hostModule = { config, nixosConfig, gensokyo-zone, lib, ... }: let hostModule = {
config,
nixosConfig,
gensokyo-zone,
lib,
...
}: let
inherit (gensokyo-zone.lib) mapOptionDefaults mapAlmostOptionDefaults; inherit (gensokyo-zone.lib) mapOptionDefaults mapAlmostOptionDefaults;
inherit (lib.options) mkOption mkEnableOption; inherit (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkOptionDefault; inherit (lib.modules) mkIf mkOptionDefault;
@ -289,7 +341,10 @@ let
websocket.enable = mkEnableOption "websocket proxy"; websocket.enable = mkEnableOption "websocket proxy";
headers.enableRecommended = mkOption { headers.enableRecommended = mkOption {
type = enum [true false "nixpkgs"]; type = enum [true false "nixpkgs"];
default = if nginx.recommendedProxySettings then "nixpkgs" else false; default =
if nginx.recommendedProxySettings
then "nixpkgs"
else false;
}; };
}; };
locations = mkOption { locations = mkOption {
@ -303,9 +358,11 @@ let
needsReferer = loc: loc.proxy.enabled && loc.proxy.headers.rewriteReferer.enable; needsReferer = loc: loc.proxy.enabled && loc.proxy.headers.rewriteReferer.enable;
confCopy = let confCopy = let
proxyHost = nginx.virtualHosts.${cfg.copyFromVhost}; proxyHost = nginx.virtualHosts.${cfg.copyFromVhost};
in mapAlmostOptionDefaults { in
mapAlmostOptionDefaults {
inherit (proxyHost.proxy) host url upstream; inherit (proxyHost.proxy) host url upstream;
} // { }
// {
websocket = mapAlmostOptionDefaults { websocket = mapAlmostOptionDefaults {
inherit (proxyHost.proxy.websocket) enable; inherit (proxyHost.proxy.websocket) enable;
}; };
@ -326,10 +383,8 @@ let
proxy = mkIf (cfg.copyFromVhost != null) confCopy; proxy = mkIf (cfg.copyFromVhost != null) confCopy;
}; };
}; };
in { in
lib, {lib, ...}: let
...
}: let
inherit (lib.options) mkOption; inherit (lib.options) mkOption;
in { in {
options.services.nginx = with lib.types; { options.services.nginx = with lib.types; {

View file

@ -1,5 +1,11 @@
let let
sslModule = { config, nixosConfig, gensokyo-zone, lib, ... }: let sslModule = {
config,
nixosConfig,
gensokyo-zone,
lib,
...
}: let
inherit (lib.options) mkOption; inherit (lib.options) mkOption;
inherit (lib.modules) mkIf mkMerge mkDefault mkOptionDefault; inherit (lib.modules) mkIf mkMerge mkDefault mkOptionDefault;
inherit (nixosConfig.services) nginx; inherit (nixosConfig.services) nginx;
@ -60,14 +66,19 @@ let
}; };
copyCertVhost = mkCopyCert nginx.virtualHosts.${cfg.cert.copyFromVhost}.ssl.cert; copyCertVhost = mkCopyCert nginx.virtualHosts.${cfg.cert.copyFromVhost}.ssl.cert;
copyCertStreamServer = mkCopyCert nginx.stream.servers.${cfg.cert.copyFromStreamServer}.ssl.cert; copyCertStreamServer = mkCopyCert nginx.stream.servers.${cfg.cert.copyFromStreamServer}.ssl.cert;
in mkMerge [ in
mkMerge [
(mkIf (cfg.cert.copyFromStreamServer != null) copyCertStreamServer) (mkIf (cfg.cert.copyFromStreamServer != null) copyCertStreamServer)
(mkIf (cfg.cert.copyFromVhost != null) copyCertVhost) (mkIf (cfg.cert.copyFromVhost != null) copyCertVhost)
]; ];
}; };
}; };
}; };
sslProxyModule = { config, lib, ... }: let sslProxyModule = {
config,
lib,
...
}: let
inherit (lib.options) mkOption mkEnableOption; inherit (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkMerge mkAfter; inherit (lib.modules) mkIf mkMerge mkAfter;
inherit (config) proxy; inherit (config) proxy;
@ -78,7 +89,9 @@ let
type = bool; type = bool;
}; };
verify = mkEnableOption "proxy_ssl_verify"; verify = mkEnableOption "proxy_ssl_verify";
sni = mkEnableOption "proxy_ssl_server_name" // { sni =
mkEnableOption "proxy_ssl_server_name"
// {
default = cfg.host != null; default = cfg.host != null;
}; };
host = mkOption { host = mkOption {
@ -97,7 +110,13 @@ let
]); ]);
}; };
}; };
streamServerModule = { config, nixosConfig, gensokyo-zone, lib, ... }: let streamServerModule = {
config,
nixosConfig,
gensokyo-zone,
lib,
...
}: let
inherit (gensokyo-zone.lib) mkAlmostDefault; inherit (gensokyo-zone.lib) mkAlmostDefault;
inherit (lib.options) mkEnableOption; inherit (lib.options) mkEnableOption;
inherit (lib.modules) mkIf mkMerge mkOptionDefault; inherit (lib.modules) mkIf mkMerge mkOptionDefault;
@ -106,7 +125,9 @@ let
imports = [sslModule sslProxyModule]; imports = [sslModule sslProxyModule];
options = with lib.types; { options = with lib.types; {
ssl = { ssl = {
kTLS = mkEnableOption "kTLS support" // { kTLS =
mkEnableOption "kTLS support"
// {
default = true; default = true;
}; };
}; };
@ -126,13 +147,15 @@ let
(mkIf cfg.kTLS "ssl_conf_command Options KTLS;") (mkIf cfg.kTLS "ssl_conf_command Options KTLS;")
]; ];
confProxy.extraConfig = mkIf proxy.ssl.enable "proxy_ssl on;"; confProxy.extraConfig = mkIf proxy.ssl.enable "proxy_ssl on;";
in mkMerge [ in
mkMerge [
conf conf
(mkIf cfg.enable confSsl) (mkIf cfg.enable confSsl)
(mkIf proxy.enable confProxy) (mkIf proxy.enable confProxy)
]; ];
}; };
in { in
{
config, config,
gensokyo-zone, gensokyo-zone,
lib, lib,
@ -145,12 +168,20 @@ in {
inherit (lib.trivial) warnIf; inherit (lib.trivial) warnIf;
inherit (lib.strings) hasPrefix; inherit (lib.strings) hasPrefix;
inherit (config.services) nginx; inherit (config.services) nginx;
forceRedirectConfig = { virtualHost, xvars }: '' forceRedirectConfig = {
virtualHost,
xvars,
}: ''
if (${xvars.get.scheme} = http) { if (${xvars.get.scheme} = http) {
return ${toString virtualHost.redirectCode} https://${xvars.get.host}$request_uri; return ${toString virtualHost.redirectCode} https://${xvars.get.host}$request_uri;
} }
''; '';
locationModule = { config, virtualHost, xvars, ... }: let locationModule = {
config,
virtualHost,
xvars,
...
}: let
cfg = config.ssl; cfg = config.ssl;
emitForce = cfg.force && !virtualHost.ssl.forced; emitForce = cfg.force && !virtualHost.ssl.forced;
in { in {
@ -164,7 +195,11 @@ in {
extraConfig = mkIf emitForce (forceRedirectConfig {inherit xvars virtualHost;}); extraConfig = mkIf emitForce (forceRedirectConfig {inherit xvars virtualHost;});
}; };
}; };
hostModule = { config, xvars, ... }: let hostModule = {
config,
xvars,
...
}: let
cfg = config.ssl; cfg = config.ssl;
emitForce = cfg.forced && config.proxied.enabled; emitForce = cfg.forced && config.proxied.enabled;
in { in {
@ -188,7 +223,8 @@ in {
certConfig.name = mkIf cfg.cert.enable (warnIf (config.name.shortServer == null) "ssl.cert.enable set but name.shortServer is null" ( certConfig.name = mkIf cfg.cert.enable (warnIf (config.name.shortServer == null) "ssl.cert.enable set but name.shortServer is null" (
mkAlmostOptionDefault config.name.shortServer mkAlmostOptionDefault config.name.shortServer
)); ));
in certConfig; in
certConfig;
}; };
addSSL = mkIf (cfg.enable && (cfg.force == false || emitForce)) (mkDefault true); addSSL = mkIf (cfg.enable && (cfg.force == false || emitForce)) (mkDefault true);
forceSSL = mkIf (cfg.enable && cfg.force == true && !emitForce) (mkDefault true); forceSSL = mkIf (cfg.enable && cfg.force == true && !emitForce) (mkDefault true);
@ -200,7 +236,10 @@ in {
kTLS = mkAlmostOptionDefault true; kTLS = mkAlmostOptionDefault true;
xvars.enable = mkIf emitForce true; xvars.enable = mkIf emitForce true;
extraConfig = mkIf emitForce (forceRedirectConfig { virtualHost = config; inherit xvars; }); extraConfig = mkIf emitForce (forceRedirectConfig {
virtualHost = config;
inherit xvars;
});
}; };
}; };
in { in {
@ -219,11 +258,13 @@ in {
}; };
}; };
config.systemd.services.nginx = let config.systemd.services.nginx = let
mapStreamServer = server: mkIf (server.enable && server.ssl.enable && server.ssl.cert.name != null) { mapStreamServer = server:
mkIf (server.enable && server.ssl.enable && server.ssl.cert.name != null) {
wants = ["acme-finished-${server.ssl.cert.name}.target"]; wants = ["acme-finished-${server.ssl.cert.name}.target"];
after = ["acme-selfsigned-${server.ssl.cert.name}.service"]; after = ["acme-selfsigned-${server.ssl.cert.name}.service"];
before = ["acme-${server.ssl.cert.name}.service"]; before = ["acme-${server.ssl.cert.name}.service"];
}; };
streamServerCerts = mapAttrsToList (_: mapStreamServer) nginx.stream.servers; streamServerCerts = mapAttrsToList (_: mapStreamServer) nginx.stream.servers;
in mkIf nginx.enable (mkMerge streamServerCerts); in
mkIf nginx.enable (mkMerge streamServerCerts);
} }

View file

@ -10,7 +10,9 @@
cfg = config.services.nginx.stream; cfg = config.services.nginx.stream;
serverModule = {config, ...}: { serverModule = {config, ...}: {
options = with lib.types; { options = with lib.types; {
enable = mkEnableOption "stream server block" // { enable =
mkEnableOption "stream server block"
// {
default = true; default = true;
}; };
extraConfig = mkOption { extraConfig = mkOption {

View file

@ -1,5 +1,13 @@
let let
upstreamServerAccessModule = {config, nixosConfig, name, gensokyo-zone, lib, upstreamKind, ...}: let upstreamServerAccessModule = {
config,
nixosConfig,
name,
gensokyo-zone,
lib,
upstreamKind,
...
}: let
inherit (lib.options) mkOption; inherit (lib.options) mkOption;
inherit (lib.modules) mkIf mkMerge mkOptionDefault; inherit (lib.modules) mkIf mkMerge mkOptionDefault;
inherit (gensokyo-zone.lib) mkAlmostOptionDefault; inherit (gensokyo-zone.lib) mkAlmostOptionDefault;
@ -57,12 +65,20 @@ let
port = mkOptionDefault port.port; port = mkOptionDefault port.port;
ssl.enable = mkIf port.ssl (mkAlmostOptionDefault true); ssl.enable = mkIf port.ssl (mkAlmostOptionDefault true);
}; };
in mkMerge [ in
mkMerge [
confAccess confAccess
(mkIf cfg.enable conf) (mkIf cfg.enable conf)
]; ];
}; };
upstreamServerModule = {config, name, gensokyo-zone, lib, upstreamKind, ...}: let upstreamServerModule = {
config,
name,
gensokyo-zone,
lib,
upstreamKind,
...
}: let
inherit (gensokyo-zone.lib) mkAddress6; inherit (gensokyo-zone.lib) mkAddress6;
inherit (lib.options) mkOption mkEnableOption; inherit (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkMerge mkBefore mkOptionDefault; inherit (lib.modules) mkIf mkMerge mkBefore mkOptionDefault;
@ -72,7 +88,9 @@ let
inherit (lib.trivial) isBool; inherit (lib.trivial) isBool;
in { in {
options = with lib.types; { options = with lib.types; {
enable = mkEnableOption "upstream server" // { enable =
mkEnableOption "upstream server"
// {
default = true; default = true;
}; };
addr = mkOption { addr = mkOption {
@ -108,7 +126,8 @@ let
}; };
config = let config = let
mapSetting = key: value: mapSetting = key: value:
if isBool value then mkIf value key if isBool value
then mkIf value key
else "${key}=${toString value}"; else "${key}=${toString value}";
settings = mapAttrsToList mapSetting config.settings; settings = mapAttrsToList mapSetting config.settings;
port = optionalString (config.port != null) ":${toString config.port}"; port = optionalString (config.port != null) ":${toString config.port}";
@ -122,7 +141,15 @@ let
serverDirective = mkOptionDefault "server ${config.serverConfig};"; serverDirective = mkOptionDefault "server ${config.serverConfig};";
}; };
}; };
upstreamModule = {config, name, nixosConfig, gensokyo-zone, lib, upstreamKind, ...}: let upstreamModule = {
config,
name,
nixosConfig,
gensokyo-zone,
lib,
upstreamKind,
...
}: let
inherit (gensokyo-zone.lib) mkAlmostOptionDefault unmerged; inherit (gensokyo-zone.lib) mkAlmostOptionDefault unmerged;
inherit (lib.options) mkOption mkEnableOption; inherit (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkMerge mkOptionDefault; inherit (lib.modules) mkIf mkMerge mkOptionDefault;
@ -139,7 +166,9 @@ let
}; };
}; };
in { in {
enable = mkEnableOption "upstream block" // { enable =
mkEnableOption "upstream block"
// {
default = true; default = true;
}; };
name = mkOption { name = mkOption {
@ -199,16 +228,28 @@ let
upstreamSettings = assertServers (mkOptionDefault { upstreamSettings = assertServers (mkOptionDefault {
#extraConfig = config.upstreamConfig; #extraConfig = config.upstreamConfig;
extraConfig = config.extraConfig; extraConfig = config.extraConfig;
servers = mapAttrs' (name: server: nameValuePair (if server.enable then server.server else "disabled_${name}") (mkIf server.enable (mkMerge [ servers = mapAttrs' (name: server:
nameValuePair (
if server.enable
then server.server
else "disabled_${name}"
) (mkIf server.enable (mkMerge [
server.settings server.settings
(mkIf (server.extraConfig != "") { (mkIf (server.extraConfig != "") {
${config.extraConfig} = true; ${config.extraConfig} = true;
}) })
]))) config.servers; ])))
config.servers;
}); });
}; };
}; };
serverModule = {config, nixosConfig, gensokyo-zone, lib, ...}: let serverModule = {
config,
nixosConfig,
gensokyo-zone,
lib,
...
}: let
inherit (gensokyo-zone.lib) mkAlmostOptionDefault; inherit (gensokyo-zone.lib) mkAlmostOptionDefault;
inherit (lib.options) mkOption; inherit (lib.options) mkOption;
inherit (lib.modules) mkIf; inherit (lib.modules) mkIf;
@ -229,7 +270,8 @@ let
dynamicUpstream = hasPrefix "$" config.proxy.upstream; dynamicUpstream = hasPrefix "$" config.proxy.upstream;
hasUpstream = config.proxy.upstream != null && !dynamicUpstream; hasUpstream = config.proxy.upstream != null && !dynamicUpstream;
proxyPass = proxyPass =
if dynamicUpstream then config.proxy.upstream if dynamicUpstream
then config.proxy.upstream
else assert proxyUpstream.enable; proxyUpstream.name; else assert proxyUpstream.enable; proxyUpstream.name;
in { in {
proxy = { proxy = {
@ -242,7 +284,12 @@ let
}; };
}; };
}; };
proxyUpstreamModule = {config, nixosConfig, lib, ...}: let proxyUpstreamModule = {
config,
nixosConfig,
lib,
...
}: let
inherit (lib.options) mkOption; inherit (lib.options) mkOption;
in { in {
options = with lib.types; { options = with lib.types; {
@ -253,7 +300,14 @@ let
}; };
}; };
}; };
locationModule = {config, nixosConfig, virtualHost, gensokyo-zone, lib, ...}: let locationModule = {
config,
nixosConfig,
virtualHost,
gensokyo-zone,
lib,
...
}: let
inherit (gensokyo-zone.lib) mkAlmostOptionDefault; inherit (gensokyo-zone.lib) mkAlmostOptionDefault;
inherit (lib.modules) mkIf mkOptionDefault; inherit (lib.modules) mkIf mkOptionDefault;
inherit (lib.strings) hasPrefix; inherit (lib.strings) hasPrefix;
@ -263,28 +317,42 @@ let
config = let config = let
proxyUpstream = nginx.upstreams'.${config.proxy.upstream}; proxyUpstream = nginx.upstreams'.${config.proxy.upstream};
proxyScheme = if config.proxy.ssl.enable then "https" else "http"; proxyScheme =
if config.proxy.ssl.enable
then "https"
else "http";
dynamicUpstream = hasPrefix "$" config.proxy.upstream; dynamicUpstream = hasPrefix "$" config.proxy.upstream;
hasUpstream = config.proxy.upstream != null && !dynamicUpstream; hasUpstream = config.proxy.upstream != null && !dynamicUpstream;
proxyHost = proxyHost =
if dynamicUpstream then config.proxy.upstream if dynamicUpstream
then config.proxy.upstream
else assert proxyUpstream.enable; proxyUpstream.name; else assert proxyUpstream.enable; proxyUpstream.name;
in { in {
proxy = { proxy = {
upstream = mkOptionDefault virtualHost.proxy.upstream; upstream = mkOptionDefault virtualHost.proxy.upstream;
enable = mkIf (config.proxy.upstream != null && virtualHost.proxy.upstream == null) true; enable = mkIf (config.proxy.upstream != null && virtualHost.proxy.upstream == null) true;
url = mkIf (config.proxy.upstream != null) (mkAlmostOptionDefault url = mkIf (config.proxy.upstream != null) (
mkAlmostOptionDefault
"${proxyScheme}://${proxyHost}" "${proxyScheme}://${proxyHost}"
); );
ssl = { ssl = {
enable = mkAlmostOptionDefault (if hasUpstream then proxyUpstream.ssl.enable else false); enable = mkAlmostOptionDefault (
if hasUpstream
then proxyUpstream.ssl.enable
else false
);
host = mkIf hasUpstream (mkAlmostOptionDefault proxyUpstream.ssl.host); host = mkIf hasUpstream (mkAlmostOptionDefault proxyUpstream.ssl.host);
}; };
host = mkIf (hasUpstream && proxyUpstream.host != null) (mkAlmostOptionDefault proxyUpstream.host); host = mkIf (hasUpstream && proxyUpstream.host != null) (mkAlmostOptionDefault proxyUpstream.host);
}; };
}; };
}; };
hostModule = {config, nixosConfig, lib, ...}: let hostModule = {
config,
nixosConfig,
lib,
...
}: let
inherit (lib.options) mkOption; inherit (lib.options) mkOption;
inherit (lib.modules) mkOptionDefault; inherit (lib.modules) mkOptionDefault;
in { in {
@ -302,7 +370,8 @@ let
}; };
}; };
}; };
in { in
{
config, config,
lib, lib,
gensokyo-zone, gensokyo-zone,
@ -356,14 +425,21 @@ in {
mapAttrsToList (_: upstream: mkIf upstream.enable upstream.upstreamBlock) cfg.stream.upstreams mapAttrsToList (_: upstream: mkIf upstream.enable upstream.upstreamBlock) cfg.stream.upstreams
); );
useUpstreams = true; useUpstreams = true;
confUpstreams.upstreams = mkMerge (mapAttrsToList (_: upstream: mkIf upstream.enable { confUpstreams.upstreams = mkMerge (mapAttrsToList (_: upstream:
mkIf upstream.enable {
${upstream.name} = unmerged.mergeAttrs upstream.upstreamSettings; ${upstream.name} = unmerged.mergeAttrs upstream.upstreamSettings;
}) cfg.upstreams'); })
cfg.upstreams');
confBlock.commonHttpConfig = mkMerge ( confBlock.commonHttpConfig = mkMerge (
mapAttrsToList (_: upstream: mkIf upstream.enable upstream.upstreamBlock) cfg.upstreams' mapAttrsToList (_: upstream: mkIf upstream.enable upstream.upstreamBlock) cfg.upstreams'
); );
in mkMerge [ in
mkMerge [
confStream confStream
(if useUpstreams then confUpstreams else confBlock) (
if useUpstreams
then confUpstreams
else confBlock
)
]; ];
} }

View file

@ -13,7 +13,12 @@
inherit (config) networking; inherit (config) networking;
inherit (config.services) vouch-proxy nginx tailscale; inherit (config.services) vouch-proxy nginx tailscale;
inherit (nginx) vouch; inherit (nginx) vouch;
locationModule = {config, virtualHost, xvars, ...}: { locationModule = {
config,
virtualHost,
xvars,
...
}: {
options.vouch = with lib.types; { options.vouch = with lib.types; {
requireAuth = mkEnableOption "require auth to access this location"; requireAuth = mkEnableOption "require auth to access this location";
setProxyHeader = mkOption { setProxyHeader = mkOption {
@ -26,7 +31,8 @@
enableVouchLocal = virtualHost.vouch.localSso.enable; enableVouchLocal = virtualHost.vouch.localSso.enable;
enableVouchTail = enableVouchLocal && tailscale.enable && false; enableVouchTail = enableVouchLocal && tailscale.enable && false;
allowOrigin = url: "add_header Access-Control-Allow-Origin ${url};"; allowOrigin = url: "add_header Access-Control-Allow-Origin ${url};";
in mkIf config.vouch.requireAuth { in
mkIf config.vouch.requireAuth {
lua = mkIf virtualHost.vouch.auth.lua.enable { lua = mkIf virtualHost.vouch.auth.lua.enable {
access.block = mkMerge [ access.block = mkMerge [
(mkBefore virtualHost.vouch.auth.lua.accessRequest) (mkBefore virtualHost.vouch.auth.lua.accessRequest)
@ -36,7 +42,8 @@
}; };
xvars.enable = mkIf (enableVouchTail || virtualHost.vouch.auth.lua.enable) true; xvars.enable = mkIf (enableVouchTail || virtualHost.vouch.auth.lua.enable) true;
proxy.headers.set.X-Vouch-User = mkOptionDefault "$auth_resp_x_vouch_user"; proxy.headers.set.X-Vouch-User = mkOptionDefault "$auth_resp_x_vouch_user";
extraConfig = assert virtualHost.vouch.enable; mkMerge [ extraConfig = assert virtualHost.vouch.enable;
mkMerge [
(mkIf (!virtualHost.vouch.requireAuth) virtualHost.vouch.auth.requestDirective) (mkIf (!virtualHost.vouch.requireAuth) virtualHost.vouch.auth.requestDirective)
(allowOrigin vouch.url) (allowOrigin vouch.url)
(allowOrigin vouch.authUrl) (allowOrigin vouch.authUrl)
@ -46,7 +53,11 @@
]; ];
}; };
}; };
hostModule = {config, xvars, ...}: let hostModule = {
config,
xvars,
...
}: let
cfg = config.vouch; cfg = config.vouch;
mkHeaderVar = header: toLower (replaceStrings ["-"] ["_"] header); mkHeaderVar = header: toLower (replaceStrings ["-"] ["_"] header);
mkUpstreamVar = header: "\$upstream_http_${mkHeaderVar header}"; mkUpstreamVar = header: "\$upstream_http_${mkHeaderVar header}";
@ -57,10 +68,14 @@
}; };
vouch = { vouch = {
enable = mkEnableOption "vouch auth proxy"; enable = mkEnableOption "vouch auth proxy";
localSso.enable = mkEnableOption "lan-local vouch" // { localSso.enable =
mkEnableOption "lan-local vouch"
// {
default = vouch.localSso.enable && config.local.enable; default = vouch.localSso.enable && config.local.enable;
}; };
requireAuth = mkEnableOption "require auth to access this host" // { requireAuth =
mkEnableOption "require auth to access this host"
// {
default = true; default = true;
}; };
auth = { auth = {
@ -129,9 +144,12 @@
return ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) return ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
end end
''); '');
accessVariables = mkMerge (mapAttrsToList (authVar: header: mkOptionDefault accessVariables = mkMerge (mapAttrsToList (
authVar: header:
mkOptionDefault
''ngx.var["${authVar}"] = ngx.ctx.auth_res.header["${header}"] or ""'' ''ngx.var["${authVar}"] = ngx.ctx.auth_res.header["${header}"] or ""''
) cfg.auth.variables); )
cfg.auth.variables);
}; };
errorLocation = mkIf cfg.auth.lua.enable (mkAlmostOptionDefault null); errorLocation = mkIf cfg.auth.lua.enable (mkAlmostOptionDefault null);
requestDirective = mkIf cfg.auth.lua.enable (mkAlmostOptionDefault ""); requestDirective = mkIf cfg.auth.lua.enable (mkAlmostOptionDefault "");
@ -161,14 +179,18 @@
(mkIf cfg.localSso.enable localVouchUrl) (mkIf cfg.localSso.enable localVouchUrl)
(mkIf (cfg.localSso.enable && tailscale.enable) tailVouchUrl) (mkIf (cfg.localSso.enable && tailscale.enable) tailVouchUrl)
]; ];
in mkIf cfg.enable (mkMerge ( in
mkIf cfg.enable (mkMerge (
[ [
(mkIf (cfg.requireAuth) (mkBefore cfg.auth.requestDirective)) (mkIf (cfg.requireAuth) (mkBefore cfg.auth.requestDirective))
(mkIf (cfg.auth.errorLocation != null) "error_page 401 = ${cfg.auth.errorLocation};") (mkIf (cfg.auth.errorLocation != null) "error_page 401 = ${cfg.auth.errorLocation};")
] ++ setVouchUrl ]
++ mapAttrsToList (authVar: header: mkIf (!cfg.auth.lua.enable) ( ++ setVouchUrl
++ mapAttrsToList (authVar: header:
mkIf (!cfg.auth.lua.enable) (
mkBefore "auth_request_set \$${authVar} ${mkUpstreamVar header};" mkBefore "auth_request_set \$${authVar} ${mkUpstreamVar header};"
)) cfg.auth.variables ))
cfg.auth.variables
)); ));
xvars.enable = mkIf cfg.enable true; xvars.enable = mkIf cfg.enable true;
locations = mkIf cfg.enable { locations = mkIf cfg.enable {
@ -181,18 +203,30 @@
return 302 $vouch_url/login?url=${xvars.get.scheme}://${xvars.get.host}$request_uri&X-Vouch-Token=$auth_resp_jwt&error=$auth_resp_err; return 302 $vouch_url/login?url=${xvars.get.scheme}://${xvars.get.host}$request_uri&X-Vouch-Token=$auth_resp_jwt&error=$auth_resp_err;
''; '';
}; };
${cfg.auth.requestLocation} = { config, xvars, ... }: { ${cfg.auth.requestLocation} = {
config,
xvars,
...
}: {
proxy = { proxy = {
enable = true; enable = true;
inheritServerDefaults = false; inheritServerDefaults = false;
upstream = mkDefault ( upstream = mkDefault (
if vouch.doubleProxy.enable then "vouch'proxy" if vouch.doubleProxy.enable
else if cfg.localSso.enable then "vouch'auth'local" then "vouch'proxy"
else if cfg.localSso.enable
then "vouch'auth'local"
else "vouch'auth" else "vouch'auth"
); );
# nginx-proxied vouch must use X-Forwarded-Host, but vanilla vouch requires Host # nginx-proxied vouch must use X-Forwarded-Host, but vanilla vouch requires Host
host = if config.proxy.upstream == "vouch'proxy" host =
then (if cfg.localSso.enable then vouch.doubleProxy.localServerName else vouch.doubleProxy.serverName) if config.proxy.upstream == "vouch'proxy"
then
(
if cfg.localSso.enable
then vouch.doubleProxy.localServerName
else vouch.doubleProxy.serverName
)
else xvars.get.host; else xvars.get.host;
headers = { headers = {
set.Content-Length = ""; set.Content-Length = "";
@ -212,7 +246,9 @@ in {
vouch = { vouch = {
enable = mkEnableOption "vouch auth proxy"; enable = mkEnableOption "vouch auth proxy";
localSso = { localSso = {
enable = mkEnableOption "lan-local auth" // { enable =
mkEnableOption "lan-local auth"
// {
default = true; default = true;
}; };
}; };
@ -283,7 +319,9 @@ in {
vouch'auth'local = { vouch'auth'local = {
enable = vouch.enable && vouch.localSso.enable; enable = vouch.enable && vouch.localSso.enable;
servers = { servers = {
local = localVouch // { local =
localVouch
// {
enable = mkAlmostOptionDefault false; enable = mkAlmostOptionDefault false;
}; };
service = {upstream, ...}: { service = {upstream, ...}: {

View file

@ -1,5 +1,10 @@
let let
locationModule = { config, virtualHost, lib, ... }: let locationModule = {
config,
virtualHost,
lib,
...
}: let
inherit (lib.options) mkEnableOption mkOption; inherit (lib.options) mkEnableOption mkOption;
inherit (lib.attrsets) mapAttrs; inherit (lib.attrsets) mapAttrs;
cfg = config.xvars; cfg = config.xvars;
@ -18,15 +23,28 @@ let
xvars = { xvars = {
lib = let lib = let
xvars = virtualHost.xvars.lib; xvars = virtualHost.xvars.lib;
get = mapAttrs (name: default: if virtualHost.xvars.enable then "$x_${name}" else assert default != null; default) cfg.defaults; get = mapAttrs (name: default:
in xvars // { if virtualHost.xvars.enable
then "$x_${name}"
else assert default != null; default)
cfg.defaults;
in
xvars
// {
get = xvars.get // get; get = xvars.get // get;
}; };
}; };
_module.args.xvars = config.xvars.lib; _module.args.xvars = config.xvars.lib;
}; };
}; };
hostModule = { config, nixosConfig, gensokyo-zone, xvars, lib, ... }: let hostModule = {
config,
nixosConfig,
gensokyo-zone,
xvars,
lib,
...
}: let
inherit (gensokyo-zone.lib) mkJustBefore; inherit (gensokyo-zone.lib) mkJustBefore;
inherit (lib.options) mkOption mkEnableOption; inherit (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkMerge mkOptionDefault; inherit (lib.modules) mkIf mkMerge mkOptionDefault;
@ -36,11 +54,16 @@ let
inherit (lib.trivial) isInt; inherit (lib.trivial) isInt;
cfg = config.xvars; cfg = config.xvars;
escapeString = value: escapeString = value:
if value == "" then ''""'' if value == ""
else if isInt value then toString value then ''""''
else if hasPrefix ''"'' value || hasPrefix "'" value then value # already escaped, may include trailing arguments else if isInt value
else if hasInfix ''"'' value then "'${value}'" then toString value
else if hasInfix " " value || hasInfix ";" value || hasInfix "'" value then ''"${value}"'' else if hasPrefix ''"'' value || hasPrefix "'" value
then value # already escaped, may include trailing arguments
else if hasInfix ''"'' value
then "'${value}'"
else if hasInfix " " value || hasInfix ";" value || hasInfix "'" value
then ''"${value}"''
else value; else value;
anyLocations = f: any (loc: loc.enable && f loc) (attrValues config.locations); anyLocations = f: any (loc: loc.enable && f loc) (attrValues config.locations);
in { in {
@ -99,7 +122,11 @@ let
referer_path = null; referer_path = null;
}); });
lib = { lib = {
get = mapAttrs (name: default: if cfg.enable then "$x_${name}" else assert default != null; default) cfg.defaults; get = mapAttrs (name: default:
if cfg.enable
then "$x_${name}"
else assert default != null; default)
cfg.defaults;
init = name: value: assert cfg.enable && cfg.defaults ? ${name}; "set $x_${name} ${escapeString value};"; init = name: value: assert cfg.enable && cfg.defaults ? ${name}; "set $x_${name} ${escapeString value};";
inherit escapeString; inherit escapeString;
}; };
@ -111,7 +138,8 @@ let
_module.args.xvars = config.xvars.lib; _module.args.xvars = config.xvars.lib;
}; };
}; };
in { in
{
config, config,
lib, lib,
gensokyo-zone, gensokyo-zone,

View file

@ -40,7 +40,9 @@
allow = mkEnableOption "tailscale TCP connections"; allow = mkEnableOption "tailscale TCP connections";
}; };
int = { int = {
allow = mkEnableOption "internal TCP connections" // { allow =
mkEnableOption "internal TCP connections"
// {
default = config.authentication.local.allow; default = config.authentication.local.allow;
}; };
}; };

View file

@ -55,7 +55,9 @@ in {
ldap = { ldap = {
enable = mkEnableOption "LDAP"; enable = mkEnableOption "LDAP";
passdb = { passdb = {
enable = mkEnableOption "LDAP authentication" // { enable =
mkEnableOption "LDAP authentication"
// {
default = true; default = true;
}; };
backend = mkOption { backend = mkOption {
@ -64,7 +66,9 @@ in {
}; };
}; };
idmap = { idmap = {
enable = mkEnableOption "LDAP users" // { enable =
mkEnableOption "LDAP users"
// {
default = true; default = true;
}; };
domain = mkOption { domain = mkOption {
@ -98,10 +102,14 @@ in {
}; };
}; };
tls = { tls = {
enable = mkEnableOption "tls" // { enable =
mkEnableOption "tls"
// {
default = cfg.tls.certPath != null; default = cfg.tls.certPath != null;
}; };
peer.enable = mkEnableOption "peer verification" // { peer.enable =
mkEnableOption "peer verification"
// {
default = cfg.tls.caPath != null; default = cfg.tls.caPath != null;
}; };
useACMECert = mkOption { useACMECert = mkOption {
@ -212,19 +220,30 @@ in {
config = { config = {
services.samba = { services.samba = {
package = mkIf cfg.ldap.enable (mkAlmostOptionDefault ( package = mkIf cfg.ldap.enable (mkAlmostOptionDefault (
if cfg.ldap.passdb.enable && cfg.ldap.passdb.backend == "ipasam" then pkgs.samba-ipa else pkgs.samba-ldap if cfg.ldap.passdb.enable && cfg.ldap.passdb.backend == "ipasam"
then pkgs.samba-ipa
else pkgs.samba-ldap
)); ));
domain = { domain = {
isWorkgroup = mkOptionDefault (cfg.securityType != "domain" && cfg.securityType != "ads"); isWorkgroup = mkOptionDefault (cfg.securityType != "domain" && cfg.securityType != "ads");
netbiosName' = let netbiosName' = let
name = if cfg.domain.netbiosName != null then cfg.domain.netbiosName else config.networking.hostName; name =
in mkOptionDefault (if cfg.domain.isWorkgroup then toUpper name else name); if cfg.domain.netbiosName != null
then cfg.domain.netbiosName
else config.networking.hostName;
in
mkOptionDefault (
if cfg.domain.isWorkgroup
then toUpper name
else name
);
netbiosHostAddresses = mkIf (cfg.domain.netbiosName != null) { netbiosHostAddresses = mkIf (cfg.domain.netbiosName != null) {
${cfg.domain.netbiosName'} = ["127.0.0.1" "::1"]; ${cfg.domain.netbiosName'} = ["127.0.0.1" "::1"];
}; };
lmhosts = let lmhosts = let
addrs = mapAttrsToList (name: map (flip nameValuePair name)) cfg.domain.netbiosHostAddresses; addrs = mapAttrsToList (name: map (flip nameValuePair name)) cfg.domain.netbiosHostAddresses;
in listToAttrs (concatLists addrs); in
listToAttrs (concatLists addrs);
}; };
ldap = { ldap = {
adminPasswordPath = mkIf (cfg.ldap.adminDn != null && hasPrefix "name=anonymous," cfg.ldap.adminDn) (mkAlmostOptionDefault ( adminPasswordPath = mkIf (cfg.ldap.adminDn != null && hasPrefix "name=anonymous," cfg.ldap.adminDn) (mkAlmostOptionDefault (
@ -269,10 +288,12 @@ in {
(mkIf cfg.kerberos.enable { (mkIf cfg.kerberos.enable {
"realm" = mkOptionDefault cfg.kerberos.realm; "realm" = mkOptionDefault cfg.kerberos.realm;
"kerberos method" = mkOptionDefault ( "kerberos method" = mkOptionDefault (
if cfg.kerberos.keytabPath != null then "dedicated keytab" if cfg.kerberos.keytabPath != null
then "dedicated keytab"
else "system keytab" else "system keytab"
); );
"dedicated keytab file" = mkIf (cfg.kerberos.keytabPath != null) (mkOptionDefault "dedicated keytab file" = mkIf (cfg.kerberos.keytabPath != null) (
mkOptionDefault
"FILE:${cfg.kerberos.keytabPath}" "FILE:${cfg.kerberos.keytabPath}"
); );
"kerberos encryption types" = mkOptionDefault "strong"; "kerberos encryption types" = mkOptionDefault "strong";
@ -302,7 +323,8 @@ in {
"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 ( extraConfig = mkMerge (
mapAttrsToList (key: value: ''${key} = ${settingValue value}'') cfg.settings mapAttrsToList (key: value: ''${key} = ${settingValue value}'') cfg.settings
++ [ ++ [

View file

@ -1,11 +1,20 @@
{ config, lib, utils, ... }: let {
config,
lib,
utils,
...
}: let
inherit (lib.options) mkOption; inherit (lib.options) mkOption;
inherit (lib.modules) mkIf mkMerge mkOptionDefault; inherit (lib.modules) mkIf mkMerge mkOptionDefault;
inherit (lib.attrsets) mapAttrsToList; inherit (lib.attrsets) mapAttrsToList;
inherit (lib.lists) head; inherit (lib.lists) head;
inherit (lib.strings) splitString; inherit (lib.strings) splitString;
inherit (utils) escapeSystemdPath; inherit (utils) escapeSystemdPath;
mountModule = { config, name, ... }: { mountModule = {
config,
name,
...
}: {
options = with lib.types; { options = with lib.types; {
source = mkOption { source = mkOption {
type = path; type = path;
@ -32,23 +41,38 @@
}; };
}; };
}; };
mkMountType' = { rootDir, specialArgs, modules ? [ ] }: let mkMountType' = {
rootDir,
specialArgs,
modules ? [],
}: let
rootDirModule = {...}: { rootDirModule = {...}: {
config.rootDir = mkOptionDefault rootDir; config.rootDir = mkOptionDefault rootDir;
}; };
in lib.types.submoduleWith { in
lib.types.submoduleWith {
modules = [mountModule rootDirModule] ++ modules; modules = [mountModule rootDirModule] ++ modules;
inherit specialArgs; inherit specialArgs;
}; };
mkMountType = args: with lib.types; coercedTo path (path: {path = mkOptionDefault path;}) (mkMountType' args); mkMountType = args: with lib.types; coercedTo path (path: {path = mkOptionDefault path;}) (mkMountType' args);
serviceModule = { config, nixosConfig, ... }: let serviceModule = {
config,
nixosConfig,
...
}: let
cfg = config.gensokyo-zone; cfg = config.gensokyo-zone;
mapSharedMounts = f: mapAttrsToList (_: target: mapSharedMounts = f:
mapAttrsToList (
_: target:
f target f target
) cfg.sharedMounts; )
mapCacheMounts = f: mapAttrsToList (_: target: cfg.sharedMounts;
mapCacheMounts = f:
mapAttrsToList (
_: target:
f target f target
) cfg.cacheMounts; )
cfg.cacheMounts;
mkRequire = mount: mount.mountUnit; mkRequire = mount: mount.mountUnit;
mkBindPath = mount: "${mount.source}:${mount.path}"; mkBindPath = mount: "${mount.source}:${mount.path}";
specialArgs = { specialArgs = {
@ -62,11 +86,17 @@
in { in {
options.gensokyo-zone = with lib.types; { options.gensokyo-zone = with lib.types; {
sharedMounts = mkOption { sharedMounts = mkOption {
type = attrsOf (mkMountType { rootDir = "/mnt/shared"; inherit specialArgs; }); type = attrsOf (mkMountType {
rootDir = "/mnt/shared";
inherit specialArgs;
});
default = {}; default = {};
}; };
cacheMounts = mkOption { cacheMounts = mkOption {
type = attrsOf (mkMountType { rootDir = "/mnt/caches"; inherit specialArgs; }); type = attrsOf (mkMountType {
rootDir = "/mnt/caches";
inherit specialArgs;
});
default = {}; default = {};
}; };
}; };

View file

@ -1,4 +1,10 @@
{ gensokyo-zone, pkgs, config, lib, ... }: let {
gensokyo-zone,
pkgs,
config,
lib,
...
}: let
inherit (gensokyo-zone.lib) mkAlmostOptionDefault mapOptionDefaults mapAlmostOptionDefaults mapDefaults; inherit (gensokyo-zone.lib) mkAlmostOptionDefault mapOptionDefaults mapAlmostOptionDefaults mapDefaults;
inherit (lib.options) mkOption mkEnableOption; inherit (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkMerge mkAfter mkDefault mkOptionDefault; inherit (lib.modules) mkIf mkMerge mkAfter mkDefault mkOptionDefault;
@ -39,21 +45,26 @@
}; };
}; };
}; };
mkServerType = { modules }: lib.types.submoduleWith { mkServerType = {modules}:
lib.types.submoduleWith {
modules = [serverModule] ++ modules; modules = [serverModule] ++ modules;
specialArgs = { specialArgs = {
inherit gensokyo-zone pkgs; inherit gensokyo-zone pkgs;
nixosConfig = config; nixosConfig = config;
}; };
}; };
mkServerOption = { name, kind ? "server" }: let mkServerOption = {
name,
kind ? "server",
}: let
serverInfoModule = {...}: { serverInfoModule = {...}: {
config = { config = {
serverName = mkOptionDefault name; serverName = mkOptionDefault name;
serverKind = mkAlmostOptionDefault kind; serverKind = mkAlmostOptionDefault kind;
}; };
}; };
in mkOption { in
mkOption {
type = mkServerType { type = mkServerType {
modules = [serverInfoModule]; modules = [serverInfoModule];
}; };
@ -61,7 +72,9 @@
}; };
in { in {
options.services.sssd.gensokyo-zone = with lib.types; { options.services.sssd.gensokyo-zone = with lib.types; {
enable = mkEnableOption "realm" // { enable =
mkEnableOption "realm"
// {
default = genso.enable; default = genso.enable;
}; };
ldap = { ldap = {
@ -71,13 +84,18 @@ in {
default = null; default = null;
}; };
}; };
uris = mkServerOption { name = "ldap"; kind = "uri"; }; uris = mkServerOption {
name = "ldap";
kind = "uri";
};
}; };
krb5 = { krb5 = {
servers = mkServerOption {name = "krb5";}; servers = mkServerOption {name = "krb5";};
}; };
ipa = { ipa = {
servers = mkServerOption { name = "ipa"; } // { servers =
mkServerOption {name = "ipa";}
// {
default = { default = {
inherit (cfg.krb5.servers) servers backups; inherit (cfg.krb5.servers) servers backups;
}; };
@ -97,12 +115,14 @@ in {
# or "ipaNTSecurityIdentifier" which isn't set for most groups, maybe check netgroups..? # or "ipaNTSecurityIdentifier" which isn't set for most groups, maybe check netgroups..?
objectsid = "sambaSID"; objectsid = "sambaSID";
backendDomainSettings = { backendDomainSettings = {
ldap = mapDefaults { ldap =
mapDefaults {
id_provider = "ldap"; id_provider = "ldap";
auth_provider = "krb5"; auth_provider = "krb5";
access_provider = "ldap"; access_provider = "ldap";
ldap_tls_cacert = "/etc/ssl/certs/ca-bundle.crt"; ldap_tls_cacert = "/etc/ssl/certs/ca-bundle.crt";
} // mapOptionDefaults { }
// mapOptionDefaults {
ldap_access_order = ["host"]; ldap_access_order = ["host"];
ldap_schema = "IPA"; ldap_schema = "IPA";
ldap_default_bind_dn = genso.ldap.bind.dn; ldap_default_bind_dn = genso.ldap.bind.dn;
@ -124,9 +144,11 @@ in {
dyndns_iface = ipa.dyndns.interface; dyndns_iface = ipa.dyndns.interface;
}; };
}; };
domainSettings = mapAlmostOptionDefaults { domainSettings =
mapAlmostOptionDefaults {
ipa_hostname = cfg.ipa.hostName; ipa_hostname = cfg.ipa.hostName;
} // mapOptionDefaults { }
// mapOptionDefaults {
enumerate = true; enumerate = true;
ipa_domain = genso.domain; ipa_domain = genso.domain;
krb5_realm = genso.realm; krb5_realm = genso.realm;
@ -191,4 +213,3 @@ in {
}; };
}; };
} }

View file

@ -15,13 +15,16 @@
inherit (lib) generators; inherit (lib) generators;
cfg = config.services.sssd; cfg = config.services.sssd;
mkValuePrimitive = value: mkValuePrimitive = value:
if value == true then "True" if value == true
else if value == false then "False" then "True"
else if value == false
then "False"
else toString value; else toString value;
toINI = generators.toINI { toINI = generators.toINI {
mkKeyValue = generators.mkKeyValueDefault { mkKeyValue = generators.mkKeyValueDefault {
mkValueString = value: mkValueString = value:
if isList value then concatMapStringsSep ", " mkValuePrimitive value if isList value
then concatMapStringsSep ", " mkValuePrimitive value
else mkValuePrimitive value; else mkValuePrimitive value;
} " = "; } " = ";
}; };
@ -51,7 +54,9 @@
}; };
domainModule = {name, ...}: { domainModule = {name, ...}: {
options = with lib.types; { options = with lib.types; {
enable = mkEnableOption "domain" // { enable =
mkEnableOption "domain"
// {
default = true; default = true;
}; };
domain = mkOption { domain = mkOption {
@ -95,14 +100,16 @@
authtokConfig = mkIf (cfg.authtok.password != null || cfg.authtok.passwordFile != null) { authtokConfig = mkIf (cfg.authtok.password != null || cfg.authtok.passwordFile != null) {
ldap_default_authtok_type = mkOptionDefault cfg.authtok.type; ldap_default_authtok_type = mkOptionDefault cfg.authtok.type;
ldap_default_authtok = mkOptionDefault ( ldap_default_authtok = mkOptionDefault (
if cfg.authtok.passwordFile != null then "\$${cfg.authtok.passwordVar}" if cfg.authtok.passwordFile != null
then "\$${cfg.authtok.passwordVar}"
else cfg.authtok.password else cfg.authtok.password
); );
}; };
extraAttrsConfig = mkIf (cfg.extraAttrs.user != {}) { extraAttrsConfig = mkIf (cfg.extraAttrs.user != {}) {
ldap_user_extra_attrs = let ldap_user_extra_attrs = let
mkAttr = name: attr: "${name}:${attr}"; mkAttr = name: attr: "${name}:${attr}";
in mapAttrsToList mkAttr cfg.extraAttrs.user; in
mapAttrsToList mkAttr cfg.extraAttrs.user;
}; };
in { in {
settings = mkMerge [ settings = mkMerge [
@ -135,7 +142,8 @@ in {
}; };
}; };
services = let services = let
mkServiceOption = name: { modules ? [ ] }: mkOption { mkServiceOption = name: {modules ? []}:
mkOption {
type = submoduleWith { type = submoduleWith {
modules = [serviceModule] ++ modules; modules = [serviceModule] ++ modules;
specialArgs = { specialArgs = {
@ -153,7 +161,8 @@ in {
ssh = {}; ssh = {};
pac = {}; pac = {};
}; };
in mapAttrs mkServiceOption services; in
mapAttrs mkServiceOption services;
settings = mkOption { settings = mkOption {
type = attrsOf settingsType; type = attrsOf settingsType;
}; };
@ -175,11 +184,14 @@ in {
domains = map (domain: domain.domain) enabledDomains; domains = map (domain: domain.domain) enabledDomains;
}; };
}; };
domainSettings = map (domain: { domainSettings =
map (domain: {
"domain/${domain.domain}" = mapAttrs (_: mkOptionDefault) domain.settings; "domain/${domain.domain}" = mapAttrs (_: mkOptionDefault) domain.settings;
}) enabledDomains; })
enabledDomains;
settings = [defaultSettings serviceSettings] ++ domainSettings; settings = [defaultSettings serviceSettings] ++ domainSettings;
in mkMerge settings; in
mkMerge settings;
services = { services = {
nss.enable = mkAlmostOptionDefault true; nss.enable = mkAlmostOptionDefault true;
pam.enable = mkAlmostOptionDefault true; pam.enable = mkAlmostOptionDefault true;
@ -201,8 +213,14 @@ in {
}; };
config.system.nssDatabases = let config.system.nssDatabases = let
inherit (cfg.services) nss; inherit (cfg.services) nss;
in mkIf cfg.enable { in
${if options ? system.nssDatabases.netgroup then "netgroup" else null} = mkIf (nss.enable && nss.netgroup.enable) [ "sss" ]; mkIf cfg.enable {
${
if options ? system.nssDatabases.netgroup
then "netgroup"
else null
} =
mkIf (nss.enable && nss.netgroup.enable) ["sss"];
shadow = mkIf (!nss.enable || !nss.shadow.enable) ( shadow = mkIf (!nss.enable || !nss.shadow.enable) (
mkForce ["files"] mkForce ["files"]
); );

View file

@ -12,7 +12,11 @@
inherit (lib.lists) singleton; inherit (lib.lists) singleton;
inherit (lib.strings) removePrefix; inherit (lib.strings) removePrefix;
cfg = config.services.steam.accountSwitch; cfg = config.services.steam.accountSwitch;
machineModule = { config, name, ... }: { machineModule = {
config,
name,
...
}: {
options = with lib.types; { options = with lib.types; {
name = mkOption { name = mkOption {
type = str; type = str;
@ -93,7 +97,8 @@ in {
inherit owner; inherit owner;
inherit (shared) group mode; inherit (shared) group mode;
}; };
setupFiles = singleton { setupFiles =
singleton {
${cfg.rootDir} = toplevel; ${cfg.rootDir} = toplevel;
${cfg.binDir} = toplevel; ${cfg.binDir} = toplevel;
${cfg.binDir + "/users"} = shared; ${cfg.binDir + "/users"} = shared;
@ -101,15 +106,19 @@ in {
${cfg.sharedDataDir} = shared; ${cfg.sharedDataDir} = shared;
${cfg.workingDir} = toplevel; ${cfg.workingDir} = toplevel;
${cfg.sharedWorkingDir} = shared; ${cfg.sharedWorkingDir} = shared;
} ++ map (owner: { }
++ map (owner: {
${cfg.dataDir + "/${owner}"} = personal owner; ${cfg.dataDir + "/${owner}"} = personal owner;
${cfg.workingDir + "/${owner}"} = personal owner; ${cfg.workingDir + "/${owner}"} = personal owner;
}) cfg.users })
cfg.users
++ mapAttrsToList (_: machine: { ++ mapAttrsToList (_: machine: {
${cfg.dataDir + "/${machine.name}"} = personal machine.owner; ${cfg.dataDir + "/${machine.name}"} = personal machine.owner;
${cfg.workingDir + "/${machine.name}"} = personal machine.owner; ${cfg.workingDir + "/${machine.name}"} = personal machine.owner;
}) cfg.machines; })
userBinFiles = listToAttrs (map (user: nameValuePair "${cfg.binDir}/users/${user}.bat" { cfg.machines;
userBinFiles = listToAttrs (map (user:
nameValuePair "${cfg.binDir}/users/${user}.bat" {
inherit (toplevel) owner group; inherit (toplevel) owner group;
mode = "0755"; mode = "0755";
type = "copy"; type = "copy";
@ -120,7 +129,8 @@ in {
setx GENSO_STEAM_USER ${user} setx GENSO_STEAM_USER ${user}
''; '';
}; };
}) cfg.users); })
cfg.users);
in { in {
enable = mkIf (cfg.enable || cfg.setup) true; enable = mkIf (cfg.enable || cfg.setup) true;
files = mkMerge [ files = mkMerge [
@ -132,12 +142,14 @@ in {
mkSharePathWith = { mkSharePathWith = {
path, path,
winRoot ? "%GENSO_SMB_SHARED_MOUNT%", winRoot ? "%GENSO_SMB_SHARED_MOUNT%",
}: mkWinPath ( }:
mkWinPath (
winRoot winRoot
+ "/${cfg.sharePath}" + "/${cfg.sharePath}"
+ "/${removePrefix (cfg.rootDir + "/") path}" + "/${removePrefix (cfg.rootDir + "/") path}"
); );
mkSharePath = path: config.lib.steam.mkSharePathWith { mkSharePath = path:
config.lib.steam.mkSharePathWith {
inherit path; inherit path;
}; };
}; };

View file

@ -17,8 +17,15 @@
sortedVersions = sort (a: b: versionOlder a.version b.version) (attrValues cfg.versions); sortedVersions = sort (a: b: versionOlder a.version b.version) (attrValues cfg.versions);
prevVersionFor = version: let prevVersionFor = version: let
olderVersions = filter (v: versionOlder v.version version) sortedVersions; olderVersions = filter (v: versionOlder v.version version) sortedVersions;
in if olderVersions != [] then last olderVersions else null; in
versionModule = { config, name, ... }: { if olderVersions != []
then last olderVersions
else null;
versionModule = {
config,
name,
...
}: {
options = with lib.types; { options = with lib.types; {
version = mkOption { version = mkOption {
type = str; type = str;
@ -40,7 +47,11 @@
); );
}; };
}; };
fileModule = { config, name, ... }: { fileModule = {
config,
name,
...
}: {
options = with lib.types; { options = with lib.types; {
relativePath = mkOption { relativePath = mkOption {
type = str; type = str;
@ -61,7 +72,10 @@
mode = { mode = {
file = mkOption { file = mkOption {
type = str; type = str;
default = if hasSuffix ".exe" config.relativePath || hasSuffix ".dll" config.relativePath then "775" else "664"; default =
if hasSuffix ".exe" config.relativePath || hasSuffix ".dll" config.relativePath
then "775"
else "664";
}; };
dir = mkOption { dir = mkOption {
type = str; type = str;
@ -106,32 +120,56 @@
versionPathFor = version: optionalString config.versioned "/${version}"; versionPathFor = version: optionalString config.versioned "/${version}";
in { in {
init = mkOptionDefault ( init = mkOptionDefault (
if config.target == "game" then null if config.target == "game"
else if config.type == "directory" then "${emptyDir}" then null
else if hasSuffix ".json" config.relativePath then "${emptyJson}" else if config.type == "directory"
else if hasSuffix ".dll" config.relativePath || hasSuffix ".exe" config.relativePath then "${emptyExecutable}" then "${emptyDir}"
else if hasSuffix ".json" config.relativePath
then "${emptyJson}"
else if hasSuffix ".dll" config.relativePath || hasSuffix ".exe" config.relativePath
then "${emptyExecutable}"
else "${emptyFile}" else "${emptyFile}"
); );
initFor = mkOptionDefault ( initFor = mkOptionDefault (
{ user, version }: config.init {
user,
version,
}:
config.init
); );
ownerFor = mkOptionDefault (user: ownerFor = mkOptionDefault (
if config.target == "user" then user else "admin" user:
if config.target == "user"
then user
else "admin"
); );
srcPathFor = mkOptionDefault ({ user, version }: srcPathFor = mkOptionDefault (
{
user,
version,
}:
{ {
shared = cfg.sharedDataDir + versionPathFor version; shared = cfg.sharedDataDir + versionPathFor version;
user = cfg.dataDirFor user + versionPathFor version; user = cfg.dataDirFor user + versionPathFor version;
game = cfg.gameDirFor version; game = cfg.gameDirFor version;
}.${config.target} or (throw "unsupported target") }
.${config.target}
or (throw "unsupported target")
+ "/${config.relativePath}" + "/${config.relativePath}"
); );
workingPathFor = mkOptionDefault ({ user, version }: workingPathFor = mkOptionDefault (
{
user,
version,
}:
cfg.workingDirFor {inherit user version;} cfg.workingDirFor {inherit user version;}
+ "/${config.relativePath}" + "/${config.relativePath}"
); );
# TODO: setup.shared and do inits seperately! # TODO: setup.shared and do inits seperately!
setup.script = { user, version }@args: let setup.script = {
user,
version,
} @ args: let
owner = config.ownerFor user; owner = config.ownerFor user;
srcPath = config.srcPathFor args; srcPath = config.srcPathFor args;
workingPath = config.workingPathFor args; workingPath = config.workingPathFor args;
@ -148,13 +186,30 @@
fi fi
chown ${owner}:${cfg.group} ${escapeShellArg dest} chown ${owner}:${cfg.group} ${escapeShellArg dest}
''; '';
mkStyle = { style, src }: if style != "none" && src == { mkStyle = {
style,
src,
}:
if
style
!= "none"
&& src
== {
file = "${emptyFile}"; file = "${emptyFile}";
directory = "${emptyDir}"; directory = "${emptyDir}";
}.${config.type} then "empty" else style; }
doInit = { style, src, dest }: { .${config.type}
then "empty"
else style;
doInit = {
style,
src,
dest,
}:
{
none = "true"; none = "true";
copy = { copy =
{
file = '' file = ''
if [[ -L ${escapeShellArg dest} ]]; then if [[ -L ${escapeShellArg dest} ]]; then
rm -f ${escapeShellArg dest} rm -f ${escapeShellArg dest}
@ -172,8 +227,10 @@
chown -R ${owner}:${cfg.group} ${escapeShellArg dest} chown -R ${owner}:${cfg.group} ${escapeShellArg dest}
find ${escapeShellArg dest} -type f -exec chmod -m${config.mode.file} "{}" \; find ${escapeShellArg dest} -type f -exec chmod -m${config.mode.file} "{}" \;
''; '';
}.${config.type}; }
empty = { .${config.type};
empty =
{
directory = '' directory = ''
${mkdir dest} ${mkdir dest}
''; '';
@ -182,7 +239,8 @@
chmod ${config.mode.file} ${escapeShellArg dest} chmod ${config.mode.file} ${escapeShellArg dest}
chown ${owner}:${cfg.group} ${escapeShellArg dest} chown ${owner}:${cfg.group} ${escapeShellArg dest}
''; '';
}.${config.type}; }
.${config.type};
symlink = '' symlink = ''
if [[ -e ${escapeShellArg dest} && ! -L ${escapeShellArg dest} ]]; then if [[ -e ${escapeShellArg dest} && ! -L ${escapeShellArg dest} ]]; then
echo ERR: something is in the way of linking ${escapeShellArg dest} >&2 echo ERR: something is in the way of linking ${escapeShellArg dest} >&2
@ -190,16 +248,25 @@
fi fi
ln -sfT ${escapeShellArg src} ${escapeShellArg dest} ln -sfT ${escapeShellArg src} ${escapeShellArg dest}
''; '';
symlink-shallow = { symlink-shallow =
{
directory = '' directory = ''
${mkdir dest} ${mkdir dest}
ln -sf ${escapeShellArg src}/* ${escapeShellArg dest}/ ln -sf ${escapeShellArg src}/* ${escapeShellArg dest}/
''; '';
}.${config.type}; }
}.${mkStyle { inherit style src; }}; .${config.type};
doSetup = { style, src, dest }: rec { }
.${mkStyle {inherit style src;}};
doSetup = {
style,
src,
dest,
}:
rec {
none = "true"; none = "true";
copy = { copy =
{
file = '' file = ''
${empty} ${empty}
''; '';
@ -209,8 +276,10 @@
chmod -m${config.mode.file} ${escapeShellArg dest}/* chmod -m${config.mode.file} ${escapeShellArg dest}/*
fi fi
''; '';
}.${config.type}; }
empty = { .${config.type};
empty =
{
directory = '' directory = ''
chmod ${config.mode.dir} ${escapeShellArg dest} chmod ${config.mode.dir} ${escapeShellArg dest}
chown ${owner}:${cfg.group} ${escapeShellArg dest} chown ${owner}:${cfg.group} ${escapeShellArg dest}
@ -219,14 +288,18 @@
chmod ${config.mode.file} ${escapeShellArg dest} chmod ${config.mode.file} ${escapeShellArg dest}
chown ${owner}:${cfg.group} ${escapeShellArg dest} chown ${owner}:${cfg.group} ${escapeShellArg dest}
''; '';
}.${config.type}; }
.${config.type};
symlink = "true"; symlink = "true";
symlink-shallow = { symlink-shallow =
{
directory = '' directory = ''
${mkdir.directory} ${mkdir.directory}
''; '';
}.${config.type}; }
}.${mkStyle { inherit style src; }}; .${config.type};
}
.${mkStyle {inherit style src;}};
init = doInit { init = doInit {
style = config.initStyle; style = config.initStyle;
src = initPath; src = initPath;
@ -242,32 +315,41 @@
src = srcPath; src = srcPath;
dest = workingPath; dest = workingPath;
}; };
checkFlag = { checkFlag =
file = { {
file =
{
none = "e"; none = "e";
copy = "f"; copy = "f";
symlink = "L"; symlink = "L";
}.${config.initStyle}; }
directory = { .${config.initStyle};
directory =
{
none = "e"; none = "e";
copy = "d"; copy = "d";
symlink-shallow = "d"; symlink-shallow = "d";
symlink = "L"; symlink = "L";
}.${config.initStyle}; }
}.${config.type}; .${config.initStyle};
}
.${config.type};
checkParent = '' checkParent = ''
if [[ ! -d ${escapeShellArg parentWorkingPath} ]]; then if [[ ! -d ${escapeShellArg parentWorkingPath} ]]; then
echo ERR: parent of ${escapeShellArg workingPath} does not exist >&2 echo ERR: parent of ${escapeShellArg workingPath} does not exist >&2
exit 1 exit 1
fi fi
''; '';
check = if initPath != null then '' check =
if initPath != null
then ''
if [[ ! -${checkFlag} ${escapeShellArg srcPath} ]]; then if [[ ! -${checkFlag} ${escapeShellArg srcPath} ]]; then
${init} ${init}
else else
${setup} ${setup}
fi fi
'' else '' ''
else ''
if [[ ! -${checkFlag} ${escapeShellArg srcPath} ]]; then if [[ ! -${checkFlag} ${escapeShellArg srcPath} ]]; then
echo ERR: src ${escapeShellArg srcPath} for ${escapeShellArg workingPath} does not exist >&2 echo ERR: src ${escapeShellArg srcPath} for ${escapeShellArg workingPath} does not exist >&2
exit 1 exit 1
@ -280,7 +362,11 @@
''; '';
}; };
}; };
userModule = { config, name, ... }: { userModule = {
config,
name,
...
}: {
options = with lib.types; { options = with lib.types; {
name = mkOption { name = mkOption {
type = str; type = str;
@ -347,9 +433,11 @@
rmdir "%STEAM_BS_LIBRARY%" rmdir "%STEAM_BS_LIBRARY%"
mklink /D "%STEAM_BS_LIBRARY%" "%STEAM_BS_LAUNCH%" mklink /D "%STEAM_BS_LIBRARY%" "%STEAM_BS_LAUNCH%"
''; '';
launch = '' launch =
''
cd /d "%STEAM_BS_LIBRARY%" cd /d "%STEAM_BS_LIBRARY%"
'' + ''"%STEAM_BS_LIBRARY%\Beat Saber.exe"''; ''
+ ''"%STEAM_BS_LIBRARY%\Beat Saber.exe"'';
setup = '' setup = ''
rmdir "%STEAM_BS_APPDATA%" rmdir "%STEAM_BS_APPDATA%"
rmdir "%STEAM_BS_LIBRARY%" rmdir "%STEAM_BS_LIBRARY%"
@ -404,7 +492,10 @@
${launch} ${launch}
${eof} ${eof}
''; '';
beatsaber-user = { user, version }: '' beatsaber-user = {
user,
version,
}: ''
set GENSO_STEAM_USER=${user} set GENSO_STEAM_USER=${user}
set GENSO_STEAM_BS_VERSION=${version} set GENSO_STEAM_BS_VERSION=${version}
${vars} ${vars}
@ -416,9 +507,13 @@
setx GENSO_STEAM_BS_VERSION Vanilla setx GENSO_STEAM_BS_VERSION Vanilla
''; '';
mksetupbeatsaber = { user, version }: let mksetupbeatsaber = {
user,
version,
}: let
setupFiles = mapAttrsToList (_: file: file.setup.script {inherit user version;}) cfg.files; setupFiles = mapAttrsToList (_: file: file.setup.script {inherit user version;}) cfg.files;
in pkgs.writeShellScript "setupbeatsaber-${user}-${version}" '' in
pkgs.writeShellScript "setupbeatsaber-${user}-${version}" ''
set -eu set -eu
export PATH="$PATH:${makeBinPath [pkgs.coreutils]}" export PATH="$PATH:${makeBinPath [pkgs.coreutils]}"
${concatStringsSep "\n" setupFiles} ${concatStringsSep "\n" setupFiles}
@ -426,7 +521,9 @@
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 =
mkEnableOption "beatsaber data"
// {
default = accountSwitch.setup; default = accountSwitch.setup;
}; };
group = mkOption { group = mkOption {
@ -489,7 +586,11 @@ in {
}; };
workingDirFor = mkOption { workingDirFor = mkOption {
type = functionTo path; type = functionTo path;
default = { user, version }: cfg.userWorkingDirFor user + "/${version}"; default = {
user,
version,
}:
cfg.userWorkingDirFor user + "/${version}";
}; };
}; };
@ -658,17 +759,23 @@ in {
"UserData/JDFixer.json".versioned = true; "UserData/JDFixer.json".versioned = true;
}; };
userDataFiles = [ userDataFiles = [
"modprefs.ini" "Disabled Mods.json" "modprefs.ini"
"Disabled Mods.json"
"AutoPauseStealth.json" "AutoPauseStealth.json"
"BeatSaberMarkupLanguage.json" "BeatSaberMarkupLanguage.json"
"BeatSaviorData.ini" "BeatSaviorData.ini"
"BetterSongList.json" "BetterSongList.json"
"BetterSongSearch.json" "BetterSongSearch.json"
"bookmarkedSongs.json" "votedSongs.json" "bookmarkedSongs.json"
"votedSongs.json"
"Chroma.json" "Chroma.json"
"Cinema.json" "Cinema.json"
"CountersPlus.json" "CountersPlus.json"
"CustomAvatars.CalibrationData.dat" "CustomAvatars.json" "CustomNotes.json" "Custom Platforms.json" "CustomWalls.json" "CustomAvatars.CalibrationData.dat"
"CustomAvatars.json"
"CustomNotes.json"
"Custom Platforms.json"
"CustomWalls.json"
"DrinkWater.json" "DrinkWater.json"
"EasyOffset.json" "EasyOffset.json"
"Enhancements.json" "Enhancements.json"
@ -702,13 +809,18 @@ in {
"Tweaks55.json" "Tweaks55.json"
"UITweaks.json" "UITweaks.json"
]; ];
mapSharedFile = file: file // { mapSharedFile = file:
file
// {
target = "shared"; target = "shared";
}; };
mapGameFile = file: file // { mapGameFile = file:
file
// {
target = "game"; target = "game";
}; };
mapUserDataFile = file: nameValuePair "UserData/${file}" { mapUserDataFile = file:
nameValuePair "UserData/${file}" {
target = "user"; target = "user";
}; };
in { in {
@ -736,11 +848,16 @@ in {
serviceConfig = { serviceConfig = {
Type = mkOptionDefault "oneshot"; Type = mkOptionDefault "oneshot";
RemainAfterExit = mkOptionDefault true; RemainAfterExit = mkOptionDefault true;
ExecStart = mkMerge (mapAttrsToList (_: user: ExecStart = mkMerge (mapAttrsToList (
(mapAttrsToList (_: version: _: user: (mapAttrsToList (
"${mksetupbeatsaber { user = user.name; inherit (version) version; }}" _: version: "${mksetupbeatsaber {
) cfg.versions) user = user.name;
) cfg.users); inherit (version) version;
}}"
)
cfg.versions)
)
cfg.users);
}; };
}; };
services.tmpfiles = let services.tmpfiles = let
@ -774,31 +891,49 @@ in {
"AppData" "AppData"
"UserData" "UserData"
]; ];
setupFiles = [ setupFiles =
[
{ {
${cfg.sharedDataDir} = toplevel; ${cfg.sharedDataDir} = toplevel;
${cfg.binDir} = shared; ${cfg.binDir} = shared;
} }
(listToAttrs ( (listToAttrs (
map (folder: map (
folder:
nameValuePair "${cfg.sharedDataDir}/${folder}" shared nameValuePair "${cfg.sharedDataDir}/${folder}" shared
) sharedFolders )
sharedFolders
)) ))
] ++ concatLists (mapAttrsToList (_: user: ]
++ concatLists (mapAttrsToList (
_: user:
singleton { singleton {
${cfg.dataDirFor user.name} = personal user.name; ${cfg.dataDirFor user.name} = personal user.name;
"${cfg.dataDirFor user.name}/AppData" = personal user.name; "${cfg.dataDirFor user.name}/AppData" = personal user.name;
"${cfg.dataDirFor user.name}/UserData" = personal user.name; "${cfg.dataDirFor user.name}/UserData" = personal user.name;
} ++ mapAttrsToList (_: version: { }
++ mapAttrsToList (_: version: {
"${cfg.dataDirFor user.name}/${version.version}" = personal user.name; "${cfg.dataDirFor user.name}/${version.version}" = personal user.name;
${cfg.userWorkingDirFor user.name} = personal user.name; ${cfg.userWorkingDirFor user.name} = personal user.name;
${cfg.workingDirFor { user = user.name; inherit (version) version; }} = personal user.name; ${
}) cfg.versions cfg.workingDirFor {
) cfg.users) user = user.name;
inherit (version) version;
}
} =
personal user.name;
})
cfg.versions
)
cfg.users)
++ mapAttrsToList (_: version: { ++ mapAttrsToList (_: version: {
"${cfg.sharedDataDir}/${version.version}" = shared; "${cfg.sharedDataDir}/${version.version}" = shared;
}) cfg.versions; })
versionBinFiles = mapAttrs' (_: version: nameValuePair cfg.versions;
versionBinFiles =
mapAttrs' (
_: version:
nameValuePair
"${cfg.binDir}/${replaceStrings ["."] ["_"] version.version}.bat" "${cfg.binDir}/${replaceStrings ["."] ["_"] version.version}.bat"
{ {
inherit (bin) owner group mode type; inherit (bin) owner group mode type;
@ -810,8 +945,12 @@ in {
''; '';
}; };
} }
) cfg.versions; )
userBinFiles = mapAttrs' (_: user: nameValuePair cfg.versions;
userBinFiles =
mapAttrs' (
_: user:
nameValuePair
"${cfg.binDir}/${user.name}.bat" "${cfg.binDir}/${user.name}.bat"
{ {
inherit (bin) owner group mode type; inherit (bin) owner group mode type;
@ -824,8 +963,10 @@ in {
}; };
}; };
} }
) cfg.users; )
binFiles = { cfg.users;
binFiles =
{
"${cfg.binDir}/mount.bat" = { "${cfg.binDir}/mount.bat" = {
inherit (bin) owner group mode type; inherit (bin) owner group mode type;
src = pkgs.writeTextFile { src = pkgs.writeTextFile {
@ -898,7 +1039,8 @@ in {
executable = true; executable = true;
}; };
}; };
} // versionBinFiles }
// versionBinFiles
// userBinFiles; // userBinFiles;
in { in {
enable = mkIf cfg.setup true; enable = mkIf cfg.setup true;

View file

@ -24,7 +24,10 @@
... ...
}: let }: let
cfg = config.networking.access; cfg = config.networking.access;
addressForAttr = if config.networking.enableIPv6 then "address6ForNetwork" else "address4ForNetwork"; addressForAttr =
if config.networking.enableIPv6
then "address6ForNetwork"
else "address4ForNetwork";
has'Int = system.network.networks.int.enable or false; has'Int = system.network.networks.int.enable or false;
has'Local = system.network.networks.local.enable or false; has'Local = system.network.networks.local.enable or false;
has'Tail' = system.network.networks.tail.enable or false; has'Tail' = system.network.networks.tail.enable or false;
@ -48,26 +51,53 @@
forSystem = access.systemFor hostName; forSystem = access.systemFor hostName;
forSystemHas = network: forSystem.access ? ${addressForAttr}.${network} || forSystem.access ? address4ForNetwork.${network}; forSystemHas = network: forSystem.access ? ${addressForAttr}.${network} || forSystem.access ? address4ForNetwork.${network};
err = throw "no interface found between ${config.networking.hostName} -> ${hostName}@${network}"; err = throw "no interface found between ${config.networking.hostName} -> ${hostName}@${network}";
fallback = if nameAllowed fallback =
if nameAllowed
then lib.warn "getAddressFor hostname fallback for ${config.networking.hostName} -> ${hostName}@${network}" (access.getHostnameFor hostName network) then lib.warn "getAddressFor hostname fallback for ${config.networking.hostName} -> ${hostName}@${network}" (access.getHostnameFor hostName network)
else err; else err;
local = forSystem.access.${addressForAttr}.local or forSystem.access.address4ForNetwork.local or fallback; local = forSystem.access.${addressForAttr}.local or forSystem.access.address4ForNetwork.local or fallback;
int = forSystem.access.${addressForAttr}.int or forSystem.access.address4ForNetwork.int or fallback; int = forSystem.access.${addressForAttr}.int or forSystem.access.address4ForNetwork.int or fallback;
tail = forSystem.access.${addressForAttr}.tail or fallback; tail = forSystem.access.${addressForAttr}.tail or fallback;
in { in
{
lan = lan =
if hostName == system.name then forSystem.access.${addressForAttr}.localhost if hostName == system.name
else if has'Int && forSystemHas "int" then int then forSystem.access.${addressForAttr}.localhost
else if has'Local && forSystemHas "local" then local else if has'Int && forSystemHas "int"
then int
else if has'Local && forSystemHas "local"
then local
else fallback; else fallback;
${if has'Local then "local" else null} = local; ${
${if has'Int then "int" else null} = int; if has'Local
${if has'Tail then "tail" else null} = tail; then "local"
}.${network} or fallback; else null
} =
local;
${
if has'Int
then "int"
else null
} =
int;
${
if has'Tail
then "tail"
else null
} =
tail;
}
.${network}
or fallback;
in { in {
inherit (systemAccess) inherit
hostnameForNetwork address4ForNetwork address6ForNetwork (systemAccess)
systemForService systemForServiceId; hostnameForNetwork
address4ForNetwork
address6ForNetwork
systemForService
systemForServiceId
;
addressForNetwork = systemAccess.${addressForAttr}; addressForNetwork = systemAccess.${addressForAttr};
systemFor = hostName: systemFor = hostName:
if hostName == config.networking.hostName if hostName == config.networking.hostName
@ -91,34 +121,63 @@
getHostnameFor = hostName: network: let getHostnameFor = hostName: network: let
forSystem = access.systemFor hostName; forSystem = access.systemFor hostName;
err = throw "no hostname found between ${config.networking.hostName} and ${hostName}@${network}"; err = throw "no hostname found between ${config.networking.hostName} and ${hostName}@${network}";
in { in
{
lan = lan =
if hostName == system.name then forSystem.access.hostnameForNetwork.localhost if hostName == system.name
else if has'Int && forSystem.access.hostnameForNetwork ? int then forSystem.access.hostnameForNetwork.int then forSystem.access.hostnameForNetwork.localhost
else if has'Local && forSystem.access.hostnameForNetwork ? local then forSystem.access.hostnameForNetwork.local else if has'Int && forSystem.access.hostnameForNetwork ? int
then forSystem.access.hostnameForNetwork.int
else if has'Local && forSystem.access.hostnameForNetwork ? local
then forSystem.access.hostnameForNetwork.local
else err; else err;
${if has'Local then "local" else null} = forSystem.access.hostnameForNetwork.local or err; ${
${if has'Int then "int" else null} = forSystem.access.hostnameForNetwork.int or err; if has'Local
${if has'Tail then "tail" else null} = forSystem.access.hostnameForNetwork.tail or err; then "local"
}.${network} or err; else null
} =
forSystem.access.hostnameForNetwork.local or err;
${
if has'Int
then "int"
else null
} =
forSystem.access.hostnameForNetwork.int or err;
${
if has'Tail
then "tail"
else null
} =
forSystem.access.hostnameForNetwork.tail or err;
}
.${network}
or err;
proxyUrlFor = { proxyUrlFor = {
system ? if serviceId != null then access.systemForServiceId serviceId else access.systemForService serviceName, system ?
if serviceId != null
then access.systemForServiceId serviceId
else access.systemForService serviceName,
serviceName ? mapNullable (serviceId: (findSingle (s: s.id == serviceId) null null (attrValues system.exports.services)).name) serviceId, serviceName ? mapNullable (serviceId: (findSingle (s: s.id == serviceId) null null (attrValues system.exports.services)).name) serviceId,
serviceId ? null, serviceId ? null,
service ? system.exports.services.${serviceName}, service ? system.exports.services.${serviceName},
portName ? "default", portName ? "default",
network ? "lan", network ? "lan",
scheme ? null, scheme ? null,
getAddressFor ? "getAddressFor" getAddressFor ? "getAddressFor",
}: let }: let
port = service.ports.${portName}; port = service.ports.${portName};
scheme' = if scheme == null then port.protocol else scheme; scheme' =
port' = if !port.enable if scheme == null
then port.protocol
else scheme;
port' =
if !port.enable
then throw "${system.name}.exports.services.${service.name}.ports.${portName} isn't enabled" then throw "${system.name}.exports.services.${service.name}.ports.${portName} isn't enabled"
else ":${toString port.port}"; else ":${toString port.port}";
host = access.${getAddressFor} system.name network; host = access.${getAddressFor} system.name network;
url = "${scheme'}://${mkAddress6 host}${port'}"; url = "${scheme'}://${mkAddress6 host}${port'}";
in assert service.enable; url; in
assert service.enable; url;
}; };
}; };
networking.tempAddresses = mkIf cfg.global.enable ( networking.tempAddresses = mkIf cfg.global.enable (
@ -142,7 +201,9 @@ in {
default = domain; default = domain;
}; };
global.enable = mkEnableOption "globally routeable"; global.enable = mkEnableOption "globally routeable";
online.enable = mkEnableOption "a deployed machine" // { online.enable =
mkEnableOption "a deployed machine"
// {
default = true; default = true;
}; };
hostnameForNetwork = mkOption { hostnameForNetwork = mkOption {
@ -164,7 +225,12 @@ in {
]; ];
access = let access = let
noNetwork = { enable = false; address4 = null; address6 = null; fqdn = null; }; noNetwork = {
enable = false;
address4 = null;
address6 = null;
fqdn = null;
};
local = config.network.networks.local or noNetwork; local = config.network.networks.local or noNetwork;
int = config.network.networks.int or noNetwork; int = config.network.networks.int or noNetwork;
mapNetwork' = mkDefault: attr: network: mkIf (network.enable && network.${attr} != null) (mkDefault network.${attr}); mapNetwork' = mkDefault: attr: network: mkIf (network.enable && network.${attr} != null) (mkDefault network.${attr});
@ -216,12 +282,14 @@ in {
hasService = system: system.config.exports.services.${service}.enable; hasService = system: system.config.exports.services.${service}.enable;
notFound = throw "no system found serving ${service}"; notFound = throw "no system found serving ${service}";
multiple = throw "multiple systems found serving ${service}"; multiple = throw "multiple systems found serving ${service}";
in (findSingle hasService notFound multiple (attrValues systems)).config; in
(findSingle hasService notFound multiple (attrValues systems)).config;
systemForServiceId = serviceId: let systemForServiceId = serviceId: let
hasService = system: findSingle (service: service.id == serviceId && service.enable) null multiple (attrValues system.config.exports.services) != null; hasService = system: findSingle (service: service.id == serviceId && service.enable) null multiple (attrValues system.config.exports.services) != null;
notFound = throw "no system found serving ${serviceId}"; notFound = throw "no system found serving ${serviceId}";
multiple = throw "multiple systems found serving ${serviceId}"; multiple = throw "multiple systems found serving ${serviceId}";
in (findSingle hasService notFound multiple (attrValues systems)).config; in
(findSingle hasService notFound multiple (attrValues systems)).config;
}; };
}; };
} }

View file

@ -10,7 +10,9 @@
inherit (lib.modules) mkIf mkOptionDefault; inherit (lib.modules) mkIf mkOptionDefault;
in { in {
options.ci = with lib.types; { options.ci = with lib.types; {
enable = mkEnableOption "build via CI" // { enable =
mkEnableOption "build via CI"
// {
default = config.type == "NixOS"; default = config.type == "NixOS";
}; };
allowFailure = mkOption { allowFailure = mkOption {

View file

@ -1,4 +1,8 @@
{lib, gensokyo-zone, ...}: let {
lib,
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault; inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (lib.attrsets) mapAttrs; inherit (lib.attrsets) mapAttrs;
in { in {

View file

@ -1,4 +1,8 @@
{lib, gensokyo-zone, ...}: let {
lib,
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault; inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (lib.attrsets) mapAttrs; inherit (lib.attrsets) mapAttrs;
in { in {

View file

@ -24,7 +24,12 @@
}; };
id = mkOption { id = mkOption {
type = str; type = str;
default = cfg.services.${config.serviceName}.id/* or config.name*/; default =
cfg.services.${config.serviceName}.id
/*
or config.name
*/
;
}; };
}; };
}; };

View file

@ -1,4 +1,8 @@
{lib, gensokyo-zone, ...}: let {
lib,
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault; inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (lib.attrsets) mapAttrs; inherit (lib.attrsets) mapAttrs;
in { in {

View file

@ -1,4 +1,8 @@
{lib, gensokyo-zone, ...}: let {
lib,
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault; inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (lib.attrsets) mapAttrs; inherit (lib.attrsets) mapAttrs;
in { in {

View file

@ -1,4 +1,8 @@
{lib, gensokyo-zone, ...}: let {
lib,
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault; inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (lib.modules) mkIf; inherit (lib.modules) mkIf;
inherit (lib.attrsets) mapAttrs; inherit (lib.attrsets) mapAttrs;
@ -8,7 +12,8 @@ in {
config.exports.services.home-assistant = {config, ...}: let config.exports.services.home-assistant = {config, ...}: let
mkAssertion = f: nixosConfig: let mkAssertion = f: nixosConfig: let
cfg = nixosConfig.services.home-assistant; cfg = nixosConfig.services.home-assistant;
in f nixosConfig cfg; in
f nixosConfig cfg;
assertPort = nixosConfig: cfg: { assertPort = nixosConfig: cfg: {
assertion = config.ports.default.port == cfg.config.http.server_port; assertion = config.ports.default.port == cfg.config.http.server_port;
message = "port mismatch"; message = "port mismatch";
@ -16,7 +21,8 @@ in {
assertHomekitPort = let assertHomekitPort = let
portName = i: "homekit${toString i}"; portName = i: "homekit${toString i}";
mkAssertPort = i: homekit: config.ports.${portName i}.port or null == homekit.port; mkAssertPort = i: homekit: config.ports.${portName i}.port or null == homekit.port;
in nixosConfig: cfg: { in
nixosConfig: cfg: {
assertion = all id (imap0 mkAssertPort cfg.config.homekit); assertion = all id (imap0 mkAssertPort cfg.config.homekit);
message = "homekit port mismatch"; message = "homekit port mismatch";
}; };

View file

@ -1,4 +1,8 @@
{lib, gensokyo-zone, ...}: let {
lib,
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault; inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (lib.modules) mkIf; inherit (lib.modules) mkIf;
in { in {

View file

@ -1,4 +1,8 @@
{lib, gensokyo-zone, ...}: let {
lib,
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults; inherit (gensokyo-zone.lib) mapAlmostOptionDefaults;
inherit (lib.attrsets) mapAttrs; inherit (lib.attrsets) mapAttrs;
in { in {

View file

@ -1,4 +1,8 @@
{lib, gensokyo-zone, ...}: let {
lib,
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault; inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (lib.modules) mkIf; inherit (lib.modules) mkIf;
inherit (lib.attrsets) mapAttrs; inherit (lib.attrsets) mapAttrs;
@ -10,8 +14,10 @@ in {
assertions = let assertions = let
mkAssertion = f: nixosConfig: let mkAssertion = f: nixosConfig: let
cfg = nixosConfig.services.keycloak; cfg = nixosConfig.services.keycloak;
in f nixosConfig cfg; in
in mkIf config.enable [ f nixosConfig cfg;
in
mkIf config.enable [
(mkAssertion (nixosConfig: cfg: { (mkAssertion (nixosConfig: cfg: {
assertion = config.ports.${cfg.protocol}.port == cfg.port; assertion = config.ports.${cfg.protocol}.port == cfg.port;
message = "port mismatch"; message = "port mismatch";

View file

@ -1,4 +1,8 @@
{lib, gensokyo-zone, ...}: let {
lib,
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault; inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (lib.attrsets) mapAttrs; inherit (lib.attrsets) mapAttrs;
in { in {

View file

@ -1,4 +1,8 @@
{lib, gensokyo-zone, ...}: let {
lib,
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault; inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (lib.modules) mkIf; inherit (lib.modules) mkIf;
inherit (lib.attrsets) mapAttrs; inherit (lib.attrsets) mapAttrs;
@ -6,7 +10,8 @@ in {
config.exports.services.minecraft-bedrock-server = {config, ...}: let config.exports.services.minecraft-bedrock-server = {config, ...}: let
mkAssertion = f: nixosConfig: let mkAssertion = f: nixosConfig: let
cfg = nixosConfig.services.minecraft-bedrock-server; cfg = nixosConfig.services.minecraft-bedrock-server;
in f nixosConfig cfg; in
f nixosConfig cfg;
in { in {
nixos = { nixos = {
serviceAttr = "minecraft-bedrock-server"; serviceAttr = "minecraft-bedrock-server";

View file

@ -1,4 +1,8 @@
{lib, gensokyo-zone, ...}: let {
lib,
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault; inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (lib.modules) mkIf; inherit (lib.modules) mkIf;
inherit (lib.attrsets) mapAttrs; inherit (lib.attrsets) mapAttrs;
@ -13,7 +17,8 @@ in {
(nixosConfig: let (nixosConfig: let
cfg = nixosConfig.services.mosquitto; cfg = nixosConfig.services.mosquitto;
portName = i: portName = i:
if i == 0 then "default" if i == 0
then "default"
else "listener${toString i}"; else "listener${toString i}";
mkAssertPort = i: listener: config.ports.${portName i}.port or null == listener.port; mkAssertPort = i: listener: config.ports.${portName i}.port or null == listener.port;
in { in {

View file

@ -1,4 +1,8 @@
{lib, gensokyo-zone, ...}: let {
lib,
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault; inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (lib.attrsets) mapAttrs; inherit (lib.attrsets) mapAttrs;
in { in {

View file

@ -1,4 +1,8 @@
{lib, gensokyo-zone, ...}: let {
lib,
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault; inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (lib.modules) mkIf; inherit (lib.modules) mkIf;
inherit (lib.attrsets) mapAttrs; inherit (lib.attrsets) mapAttrs;
@ -6,16 +10,22 @@ in {
config.exports.services.nfs = {config, ...}: let config.exports.services.nfs = {config, ...}: let
mkAssertion = f: nixosConfig: let mkAssertion = f: nixosConfig: let
cfg = nixosConfig.services.nfs; cfg = nixosConfig.services.nfs;
in f nixosConfig cfg; in
mkAssertionPort = portName: mkAssertion (nixosConfig: cfg: let f nixosConfig cfg;
mkAssertionPort = portName:
mkAssertion (nixosConfig: cfg: let
portAttr = "${portName}Port"; portAttr = "${portName}Port";
in { in {
assertion = mkAssertPort config.ports.${portName} cfg.server.${portAttr}; assertion = mkAssertPort config.ports.${portName} cfg.server.${portAttr};
message = "${portAttr} mismatch"; message = "${portAttr} mismatch";
}); });
mkAssertPort = port: cfgPort: let mkAssertPort = port: cfgPort: let
cmpPort = if port.enable then port.port else null; cmpPort =
in cfgPort == cmpPort; if port.enable
then port.port
else null;
in
cfgPort == cmpPort;
in { in {
nixos = { nixos = {
serviceAttrPath = ["services" "nfs" "server"]; serviceAttrPath = ["services" "nfs" "server"];

View file

@ -1,4 +1,8 @@
{lib, gensokyo-zone, ...}: let {
lib,
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault; inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (lib.modules) mkIf; inherit (lib.modules) mkIf;
inherit (lib.attrsets) mapAttrs; inherit (lib.attrsets) mapAttrs;
@ -6,7 +10,8 @@ in {
config.exports.services.nginx = {config, ...}: let config.exports.services.nginx = {config, ...}: let
mkAssertion = f: nixosConfig: let mkAssertion = f: nixosConfig: let
cfg = nixosConfig.services.nginx; cfg = nixosConfig.services.nginx;
in f nixosConfig cfg; in
f nixosConfig cfg;
assertPorts = nixosConfig: cfg: { assertPorts = nixosConfig: cfg: {
assertion = config.ports.http.port == cfg.defaultHTTPListenPort && config.ports.https.port == cfg.defaultSSLListenPort; assertion = config.ports.http.port == cfg.defaultHTTPListenPort && config.ports.https.port == cfg.defaultSSLListenPort;
message = "ports mismatch"; message = "ports mismatch";

View file

@ -1,4 +1,8 @@
{lib, gensokyo-zone, ...}: let {
lib,
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault; inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (lib.modules) mkIf; inherit (lib.modules) mkIf;
inherit (lib.attrsets) mapAttrs; inherit (lib.attrsets) mapAttrs;
@ -10,8 +14,10 @@ in {
assertions = let assertions = let
mkAssertion = f: nixosConfig: let mkAssertion = f: nixosConfig: let
cfg = nixosConfig.services.openwebrx; cfg = nixosConfig.services.openwebrx;
in f nixosConfig cfg; in
in mkIf config.enable [ f nixosConfig cfg;
in
mkIf config.enable [
(mkAssertion (nixosConfig: cfg: { (mkAssertion (nixosConfig: cfg: {
assertion = config.ports.default.port == cfg.port; assertion = config.ports.default.port == cfg.port;
message = "port mismatch"; message = "port mismatch";

View file

@ -1,4 +1,8 @@
{lib, gensokyo-zone, ...}: let {
lib,
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault; inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (lib.attrsets) mapAttrs; inherit (lib.attrsets) mapAttrs;
in { in {

View file

@ -1,11 +1,16 @@
{lib, gensokyo-zone, ...}: let {
lib,
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults; inherit (gensokyo-zone.lib) mapAlmostOptionDefaults;
inherit (lib.modules) mkIf; inherit (lib.modules) mkIf;
in { in {
config.exports.services.postgresql = {config, ...}: let config.exports.services.postgresql = {config, ...}: let
mkAssertion = f: nixosConfig: let mkAssertion = f: nixosConfig: let
cfg = nixosConfig.services.postgresql; cfg = nixosConfig.services.postgresql;
in f nixosConfig cfg; in
f nixosConfig cfg;
in { in {
nixos = { nixos = {
serviceAttr = "postgresql"; serviceAttr = "postgresql";

View file

@ -1,4 +1,8 @@
{lib, gensokyo-zone, ...}: let {
lib,
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault; inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
in { in {
config.exports.services.proxmox = {config, ...}: { config.exports.services.proxmox = {config, ...}: {

View file

@ -1,4 +1,8 @@
{lib, gensokyo-zone, ...}: let {
lib,
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault; inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (lib.attrsets) mapAttrs; inherit (lib.attrsets) mapAttrs;
in { in {

View file

@ -12,7 +12,11 @@
inherit (lib.trivial) mapNullable; inherit (lib.trivial) mapNullable;
inherit (lib.strings) concatStringsSep; inherit (lib.strings) concatStringsSep;
systemConfig = config; systemConfig = config;
portModule = {config, service, ...}: { portModule = {
config,
service,
...
}: {
options = with lib.types; { options = with lib.types; {
enable = enable =
mkEnableOption "port" mkEnableOption "port"
@ -107,7 +111,8 @@
serviceConfig = getAttrFromPath config.nixos.serviceAttrPath; serviceConfig = getAttrFromPath config.nixos.serviceAttrPath;
mkAssertion = f: nixosConfig: let mkAssertion = f: nixosConfig: let
cfg = serviceConfig nixosConfig; cfg = serviceConfig nixosConfig;
in f nixosConfig cfg; in
f nixosConfig cfg;
enableAssertion = nixosConfig: cfg: { enableAssertion = nixosConfig: cfg: {
assertion = (! cfg ? enable) || (config.enable == cfg.enable); assertion = (! cfg ? enable) || (config.enable == cfg.enable);
message = "enable == nixosConfig.${concatStringsSep "." config.nixos.serviceAttrPath}.enable"; message = "enable == nixosConfig.${concatStringsSep "." config.nixos.serviceAttrPath}.enable";
@ -120,10 +125,16 @@
}; };
}; };
}; };
nixosModule = {config, system, ...}: let nixosModule = {
config,
system,
...
}: let
mapAssertion = service: a: let mapAssertion = service: a: let
res = a config; res = a config;
in res // { in
res
// {
message = "system.exports.${service.name}: " + res.message or "assertion failed"; message = "system.exports.${service.name}: " + res.message or "assertion failed";
}; };
assertions = mapAttrsToList (_: service: map (mapAssertion service) service.nixos.assertions) system.exports.services; assertions = mapAttrsToList (_: service: map (mapAssertion service) service.nixos.assertions) system.exports.services;

View file

@ -1,4 +1,8 @@
{lib, gensokyo-zone, ...}: let {
lib,
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault; inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (lib.modules) mkIf; inherit (lib.modules) mkIf;
inherit (lib.attrsets) mapAttrs filterAttrs mapAttrsToList; inherit (lib.attrsets) mapAttrs filterAttrs mapAttrsToList;
@ -7,7 +11,8 @@ in {
config.exports.services.sshd = {config, ...}: let config.exports.services.sshd = {config, ...}: let
mkAssertion = f: nixosConfig: let mkAssertion = f: nixosConfig: let
cfg = nixosConfig.services.openssh; cfg = nixosConfig.services.openssh;
in f nixosConfig cfg; in
f nixosConfig cfg;
sorted = sort (a: b: a > b); sorted = sort (a: b: a > b);
assertPorts = nixosConfig: cfg: let assertPorts = nixosConfig: cfg: let
nixosPorts = cfg.ports; nixosPorts = cfg.ports;

View file

@ -1,4 +1,8 @@
{lib, gensokyo-zone, ...}: let {
lib,
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault; inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (lib.attrsets) mapAttrs; inherit (lib.attrsets) mapAttrs;
in { in {

View file

@ -1,4 +1,8 @@
{lib, gensokyo-zone, ...}: let {
lib,
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault; inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (lib.modules) mkIf; inherit (lib.modules) mkIf;
in { in {

View file

@ -1,4 +1,8 @@
{lib, gensokyo-zone, ...}: let {
lib,
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault; inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (lib.modules) mkIf; inherit (lib.modules) mkIf;
in { in {

View file

@ -1,11 +1,19 @@
let let
fileModule = {config, name, gensokyo-zone, lib, ...}: let fileModule = {
config,
name,
gensokyo-zone,
lib,
...
}: let
inherit (lib.options) mkOption mkEnableOption; inherit (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkOptionDefault; inherit (lib.modules) mkOptionDefault;
inherit (lib.strings) hasPrefix removePrefix; inherit (lib.strings) hasPrefix removePrefix;
in { in {
options = with lib.types; { options = with lib.types; {
enable = mkEnableOption "external file" // { enable =
mkEnableOption "external file"
// {
default = true; default = true;
}; };
path = mkOption { path = mkOption {
@ -35,13 +43,21 @@ let
relativeSource = let relativeSource = let
flakeRoot = toString gensokyo-zone.self + "/"; flakeRoot = toString gensokyo-zone.self + "/";
sourcePath = toString config.source; sourcePath = toString config.source;
in mkOptionDefault ( in
if hasPrefix flakeRoot sourcePath then removePrefix flakeRoot sourcePath mkOptionDefault (
if hasPrefix flakeRoot sourcePath
then removePrefix flakeRoot sourcePath
else null else null
); );
}; };
}; };
in {config, gensokyo-zone, lib, ...}: let in
{
config,
gensokyo-zone,
lib,
...
}: let
inherit (lib.options) mkOption; inherit (lib.options) mkOption;
in { in {
options.extern = with lib.types; { options.extern = with lib.types; {

View file

@ -101,10 +101,13 @@ in {
darwin = inputs.darwin.lib.darwinSystem; darwin = inputs.darwin.lib.darwinSystem;
macos = inputs.darwin.lib.darwinSystem; macos = inputs.darwin.lib.darwinSystem;
} }
.${string.toLower config.type} or null; .${string.toLower config.type}
built = mkOptionDefault (mapNullable (builder: builder { or null;
built = mkOptionDefault (mapNullable (builder:
builder {
inherit (config) system modules specialArgs; inherit (config) system modules specialArgs;
}) config.builder); })
config.builder);
specialArgs = { specialArgs = {
inherit name inputs std Std meta; inherit name inputs std Std meta;
inherit (inputs.self.lib) gensokyo-zone; inherit (inputs.self.lib) gensokyo-zone;

View file

@ -1,9 +1,19 @@
{config, lib, inputs, ...}: let {
config,
lib,
inputs,
...
}: let
inherit (inputs.self.lib.lib) eui64; inherit (inputs.self.lib.lib) eui64;
inherit (lib.options) mkOption mkEnableOption; inherit (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkOptionDefault; inherit (lib.modules) mkIf mkOptionDefault;
inherit (lib.trivial) mapNullable; inherit (lib.trivial) mapNullable;
networkModule = { config, name, system, ... }: let networkModule = {
config,
name,
system,
...
}: let
knownNetworks = { knownNetworks = {
local.slaac = { local.slaac = {
enable = true; enable = true;
@ -13,7 +23,9 @@
}; };
in { in {
options = with lib.types; { options = with lib.types; {
enable = mkEnableOption "network" // { enable =
mkEnableOption "network"
// {
default = true; default = true;
}; };
slaac = { slaac = {

View file

@ -1,4 +1,8 @@
{config, lib, ...}: let {
config,
lib,
...
}: let
inherit (lib.options) mkOption mkEnableOption; inherit (lib.options) mkOption mkEnableOption;
cfg = config.proxmox.container; cfg = config.proxmox.container;
in { in {

View file

@ -1,4 +1,10 @@
{config, gensokyo-zone, lib, Std, ...}: let {
config,
gensokyo-zone,
lib,
Std,
...
}: let
inherit (Std) UInt; inherit (Std) UInt;
inherit (gensokyo-zone.lib) unmerged eui64 mkAlmostOptionDefault mapAlmostOptionDefaults; inherit (gensokyo-zone.lib) unmerged eui64 mkAlmostOptionDefault mapAlmostOptionDefaults;
inherit (lib.options) mkOption mkEnableOption; inherit (lib.options) mkOption mkEnableOption;
@ -9,9 +15,16 @@
inherit (lib.trivial) mapNullable; inherit (lib.trivial) mapNullable;
cfg = config.proxmox.network; cfg = config.proxmox.network;
internalOffset = 32; internalOffset = 32;
networkInterfaceModule = { config, name, system, ... }: { networkInterfaceModule = {
config,
name,
system,
...
}: {
options = with lib.types; { options = with lib.types; {
enable = mkEnableOption "network interface" // { enable =
mkEnableOption "network interface"
// {
default = true; default = true;
}; };
bridge = mkOption { bridge = mkOption {
@ -51,7 +64,9 @@
default = "virtio"; default = "virtio";
}; };
mdns = { mdns = {
enable = mkEnableOption "mDNS" // { enable =
mkEnableOption "mDNS"
// {
default = config.local.enable && config.id == "net0"; default = config.local.enable && config.id == "net0";
}; };
}; };
@ -76,7 +91,9 @@
}; };
}; };
networkd = { networkd = {
enable = mkEnableOption "systemd.network" // { enable =
mkEnableOption "systemd.network"
// {
default = true; default = true;
}; };
name = mkOption { name = mkOption {
@ -94,10 +111,16 @@
hasAddr6 = ! elem config.address6 [null "dhcp" "auto"]; hasAddr6 = ! elem config.address6 [null "dhcp" "auto"];
conf = { conf = {
local = mkIf config.local.enable { local = mkIf config.local.enable {
address4 = mkOptionDefault (if hasAddr4 then config.address4 else null); address4 = mkOptionDefault (
if hasAddr4
then config.address4
else null
);
address6 = mkOptionDefault ( address6 = mkOptionDefault (
if config.address6 == "auto" && config.slaac.postfix != null then "fd0a::${config.slaac.postfix}" if config.address6 == "auto" && config.slaac.postfix != null
else if hasAddr6 then config.address6 then "fd0a::${config.slaac.postfix}"
else if hasAddr6
then config.address6
else null else null
); );
}; };
@ -142,9 +165,12 @@
(mkIf (config.gateway6 != null) [config.gateway6]) (mkIf (config.gateway6 != null) [config.gateway6])
]; ];
DHCP = mkAlmostOptionDefault ( DHCP = mkAlmostOptionDefault (
if config.address4 == "dhcp" && config.address6 == "dhcp" then "yes" if config.address4 == "dhcp" && config.address6 == "dhcp"
else if config.address6 == "dhcp" then "ipv6" then "yes"
else if config.address4 == "dhcp" then "ipv4" else if config.address6 == "dhcp"
then "ipv6"
else if config.address4 == "dhcp"
then "ipv4"
else "no" else "no"
); );
}; };
@ -172,7 +198,8 @@
}; };
}; };
}; };
in mkMerge [ in
mkMerge [
conf conf
(mkIf config.internal.enable confInternal) (mkIf config.internal.enable confInternal)
]; ];

View file

@ -1,4 +1,9 @@
{config, lib, gensokyo-zone, ...}: let {
config,
lib,
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mkAlmostOptionDefault; inherit (gensokyo-zone.lib) mkAlmostOptionDefault;
inherit (lib.options) mkOption mkEnableOption; inherit (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf; inherit (lib.modules) mkIf;

View file

@ -1,4 +1,8 @@
{config, lib, ...}: let {
config,
lib,
...
}: let
inherit (lib.options) mkOption mkEnableOption; inherit (lib.options) mkOption mkEnableOption;
cfg = config.proxmox; cfg = config.proxmox;
in { in {

View file

@ -25,7 +25,8 @@ in {
requireAuth = false; requireAuth = false;
}; };
proxy = { proxy = {
upstream = mkIf barcodebuddy.enable (mkDefault upstream = mkIf barcodebuddy.enable (
mkDefault
"nginx'proxied" "nginx'proxied"
); );
host = mkDefault serverName; host = mkDefault serverName;

View file

@ -5,8 +5,7 @@
gensokyo-zone, gensokyo-zone,
lib, lib,
... ...
}: }: let
let
inherit (gensokyo-zone.lib) mapOptionDefaults; inherit (gensokyo-zone.lib) mapOptionDefaults;
inherit (lib.options) mkOption mkEnableOption; inherit (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkMerge mkDefault mkOptionDefault; inherit (lib.modules) mkIf mkMerge mkDefault mkOptionDefault;
@ -19,7 +18,11 @@ let
ssl_verify_client optional_no_ca; ssl_verify_client optional_no_ca;
''; '';
locations = { locations = {
"/" = { config, xvars, ... }: { "/" = {
config,
xvars,
...
}: {
proxy = { proxy = {
enable = true; enable = true;
upstream = "freeipa"; upstream = "freeipa";
@ -67,7 +70,9 @@ in {
}; };
}; };
kerberos = { kerberos = {
enable = mkEnableOption "proxy kerberos" // { enable =
mkEnableOption "proxy kerberos"
// {
default = true; default = true;
}; };
ports = { ports = {
@ -208,7 +213,8 @@ in {
ssl.cert.copyFromVhost = mkDefault "freeipa"; ssl.cert.copyFromVhost = mkDefault "freeipa";
}; };
}; };
in mkMerge [ in
mkMerge [
conf conf
(mkIf nginx.ssl.preread.enable prereadConf) (mkIf nginx.ssl.preread.enable prereadConf)
(mkIf cfg.kerberos.enable kerberosConf) (mkIf cfg.kerberos.enable kerberosConf)
@ -233,7 +239,11 @@ in {
name.shortServer = mkDefault "idp-ca"; name.shortServer = mkDefault "idp-ca";
locations."/" = mkMerge [ locations."/" = mkMerge [
locations."/" locations."/"
({config, virtualHost, ...}: { ({
config,
virtualHost,
...
}: {
proxy.ssl.host = virtualHost.serverName; proxy.ssl.host = virtualHost.serverName;
proxy.host = config.proxy.ssl.host; proxy.host = config.proxy.ssl.host;
}) })
@ -295,14 +305,16 @@ in {
inherit (nginx.stream.servers) krb5 kadmin kpasswd kticket4; inherit (nginx.stream.servers) krb5 kadmin kpasswd kticket4;
in { in {
allowedTCPPorts = mkMerge [ allowedTCPPorts = mkMerge [
(mkIf cfg.kerberos.enable (map (server: (mkIf cfg.kerberos.enable (map (
server:
mkIf (server.enable && server.listen.tcp.enable) server.listen.tcp.port mkIf (server.enable && server.listen.tcp.enable) server.listen.tcp.port
) [krb5 kticket4 kpasswd kadmin])) ) [krb5 kticket4 kpasswd kadmin]))
(mkIf nginx.ssl.preread.enable [ (mkIf nginx.ssl.preread.enable [
ldapsPort ldapsPort
]) ])
]; ];
allowedUDPPorts = mkIf cfg.kerberos.enable (map (server: allowedUDPPorts = mkIf cfg.kerberos.enable (map (
server:
mkIf (server.enable && server.listen.udp.enable) server.listen.udp.port mkIf (server.enable && server.listen.udp.enable) server.listen.udp.port
) [krb5 kticket4 kpasswd]); ) [krb5 kticket4 kpasswd]);
}; };

View file

@ -13,8 +13,15 @@ in {
config.services.nginx = { config.services.nginx = {
virtualHosts = let virtualHosts = let
proxyScheme = "https"; proxyScheme = "https";
url = access.proxyUrlFor { serviceName = "freepbx"; portName = proxyScheme; }; url = access.proxyUrlFor {
ucpUrl = access.proxyUrlFor { serviceName = "freepbx"; portName = "ucp-ssl"; getAddressFor = "getAddress4For"; }; serviceName = "freepbx";
portName = proxyScheme;
};
ucpUrl = access.proxyUrlFor {
serviceName = "freepbx";
portName = "ucp-ssl";
getAddressFor = "getAddress4For";
};
ucpPath = "/socket.io"; ucpPath = "/socket.io";
# TODO: ports.asterisk/asterisk-ssl? # TODO: ports.asterisk/asterisk-ssl?
extraConfig = '' extraConfig = ''
@ -33,7 +40,11 @@ in {
}; };
}; };
}; };
${ucpPath} = { xvars, virtualHost, ... }: { ${ucpPath} = {
xvars,
virtualHost,
...
}: {
proxy = { proxy = {
enable = true; enable = true;
websocket.enable = true; websocket.enable = true;
@ -103,9 +114,11 @@ in {
}; };
}; };
config.networking.firewall = let config.networking.firewall = let
websocketPorts = virtualHost: [ websocketPorts = virtualHost:
[
virtualHost.listen'.ucp.port virtualHost.listen'.ucp.port
] ++ optional virtualHost.listen'.ucpSsl.enable virtualHost.listen'.ucpSsl.port; ]
++ optional virtualHost.listen'.ucpSsl.enable virtualHost.listen'.ucpSsl.port;
in { in {
interfaces.local.allowedTCPPorts = websocketPorts nginx.virtualHosts.freepbx'local; interfaces.local.allowedTCPPorts = websocketPorts nginx.virtualHosts.freepbx'local;
allowedTCPPorts = mkIf (!nginx.virtualHosts.freepbx'ucp.local.denyGlobal) (websocketPorts nginx.virtualHosts.freepbx'ucp); allowedTCPPorts = mkIf (!nginx.virtualHosts.freepbx'ucp.local.denyGlobal) (websocketPorts nginx.virtualHosts.freepbx'ucp);

View file

@ -20,7 +20,11 @@
headers.set.X-Grocy-User = mkOptionDefault "$grocy_user"; headers.set.X-Grocy-User = mkOptionDefault "$grocy_user";
}; };
}; };
luaAuthHost = { config, xvars, ... }: { luaAuthHost = {
config,
xvars,
...
}: {
vouch.auth.lua = { vouch.auth.lua = {
enable = true; enable = true;
accessRequest = '' accessRequest = ''
@ -56,16 +60,20 @@ in {
proxied.enable = true; proxied.enable = true;
local.denyGlobal = true; local.denyGlobal = true;
}; };
grocy = mkMerge [ luaAuthHost { grocy = mkMerge [
luaAuthHost
{
inherit name extraConfig locations; inherit name extraConfig locations;
vouch.enable = true; vouch.enable = true;
proxy = { proxy = {
upstream = mkIf grocy.enable (mkDefault upstream = mkIf grocy.enable (
mkDefault
"nginx'proxied" "nginx'proxied"
); );
host = mkDefault serverName; host = mkDefault serverName;
}; };
} ]; }
];
grocy'local = { grocy'local = {
inherit name; inherit name;
local.enable = mkDefault true; local.enable = mkDefault true;
@ -78,7 +86,9 @@ in {
proxy.enable = true; proxy.enable = true;
}; };
}; };
grocy'local'int = mkMerge [ luaAuthHost { grocy'local'int = mkMerge [
luaAuthHost
{
# internal proxy workaround for http2 lua compat issues # internal proxy workaround for http2 lua compat issues
serverName = serverName'local; serverName = serverName'local;
inherit name extraConfig locations; inherit name extraConfig locations;
@ -91,7 +101,8 @@ in {
enable = true; enable = true;
localSso.enable = true; localSso.enable = true;
}; };
} ]; }
];
}; };
}; };
} }

View file

@ -63,7 +63,8 @@ in {
}; };
config.networking.firewall.allowedTCPPorts = let config.networking.firewall.allowedTCPPorts = let
inherit (nginx.virtualHosts.home-assistant'local) listen'; inherit (nginx.virtualHosts.home-assistant'local) listen';
in mkIf nginx.virtualHosts.home-assistant'local.enable [ in
mkIf nginx.virtualHosts.home-assistant'local.enable [
(mkIf listen'.hass.enable listen'.hass.port) (mkIf listen'.hass.enable listen'.hass.port)
]; ];
} }

View file

@ -61,7 +61,11 @@ in {
upstream = "nginx'proxied"; upstream = "nginx'proxied";
host = mkDefault nginx.virtualHosts.invidious'int.serverName; host = mkDefault nginx.virtualHosts.invidious'int.serverName;
}; };
locations."/" = { xvars, virtualHost, ... }: { locations."/" = {
xvars,
virtualHost,
...
}: {
proxy.enable = true; proxy.enable = true;
extraConfig = '' extraConfig = ''
proxy_http_version 1.1; proxy_http_version 1.1;
@ -72,7 +76,11 @@ in {
''; '';
}; };
}; };
invidious'int = { config, xvars, ... }: { invidious'int = {
config,
xvars,
...
}: {
serverName = "@invidious_internal"; serverName = "@invidious_internal";
proxied.enable = true; proxied.enable = true;
local.denyGlobal = true; local.denyGlobal = true;

View file

@ -12,8 +12,15 @@
in { in {
config.services.nginx = { config.services.nginx = {
virtualHosts = let virtualHosts = let
url = access.proxyUrlFor { inherit system; service = motion; }; url = access.proxyUrlFor {
streamUrl = access.proxyUrlFor { inherit system; service = motion; portName = "stream"; }; inherit system;
service = motion;
};
streamUrl = access.proxyUrlFor {
inherit system;
service = motion;
portName = "stream";
};
extraConfig = '' extraConfig = ''
proxy_redirect off; proxy_redirect off;
proxy_buffering off; proxy_buffering off;
@ -49,9 +56,12 @@ in {
inherit name listen'; inherit name listen';
ssl.cert.copyFromVhost = "kitchencam"; ssl.cert.copyFromVhost = "kitchencam";
local.enable = true; local.enable = true;
locations = mapAttrs (name: location: location // { locations = mapAttrs (name: location:
location
// {
proxyPass = mkDefault nginx.virtualHosts.kitchencam.locations.${name}.proxyPass; proxyPass = mkDefault nginx.virtualHosts.kitchencam.locations.${name}.proxyPass;
}) locations; })
locations;
}; };
}; };
}; };

View file

@ -4,8 +4,7 @@
gensokyo-zone, gensokyo-zone,
access, access,
... ...
}: }: let
let
inherit (gensokyo-zone.lib) mkAlmostOptionDefault; inherit (gensokyo-zone.lib) mkAlmostOptionDefault;
inherit (lib.options) mkOption; inherit (lib.options) mkOption;
inherit (lib.modules) mkIf mkOptionDefault; inherit (lib.modules) mkIf mkOptionDefault;

View file

@ -4,8 +4,7 @@
access, access,
gensokyo-zone, gensokyo-zone,
... ...
}: }: let
let
inherit (gensokyo-zone.lib) mkAlmostOptionDefault; inherit (gensokyo-zone.lib) mkAlmostOptionDefault;
inherit (lib.modules) mkIf mkOptionDefault; inherit (lib.modules) mkIf mkOptionDefault;
inherit (config.services) nginx; inherit (config.services) nginx;
@ -42,7 +41,9 @@ in {
}; };
}; };
proxy.upstream = mkAlmostOptionDefault ( proxy.upstream = mkAlmostOptionDefault (
if nginx.stream.upstreams.mqtts.enable then "mqtts" else "mqtt" if nginx.stream.upstreams.mqtts.enable
then "mqtts"
else "mqtt"
); );
}; };
}; };

View file

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

View file

@ -88,7 +88,8 @@ in {
}; };
config.networking.firewall.allowedTCPPorts = let config.networking.firewall.allowedTCPPorts = let
inherit (nginx.virtualHosts.plex) listen'; inherit (nginx.virtualHosts.plex) listen';
in mkIf listen'.external.enable [ in
mkIf listen'.external.enable [
listen'.external.port listen'.external.port
]; ];
} }

View file

@ -28,7 +28,11 @@ in {
proxy_redirect default; proxy_redirect default;
''; '';
}; };
"/validate" = {config, virtualHost, ...}: { "/validate" = {
config,
virtualHost,
...
}: {
proxied.enable = true; proxied.enable = true;
proxy.enable = true; proxy.enable = true;
local.denyGlobal = true; local.denyGlobal = true;

View file

@ -1,4 +1,9 @@
{config, access, lib, ...}: let {
config,
access,
lib,
...
}: let
inherit (lib.modules) mkIf mkDefault; inherit (lib.modules) mkIf mkDefault;
inherit (config.services) nginx; inherit (config.services) nginx;
cfg = config.services.barcodebuddy; cfg = config.services.barcodebuddy;
@ -28,7 +33,8 @@ in {
}; };
config.systemd.services = let config.systemd.services = let
gensokyo-zone.sharedMounts.barcodebuddy.path = mkDefault cfg.dataDir; gensokyo-zone.sharedMounts.barcodebuddy.path = mkDefault cfg.dataDir;
in mkIf cfg.enable { in
mkIf cfg.enable {
phpfpm-barcodebuddy = { phpfpm-barcodebuddy = {
inherit gensokyo-zone; inherit gensokyo-zone;
}; };

View file

@ -1,7 +1,4 @@
{ {pkgs, ...}: {
pkgs,
...
}: {
fonts.packages = [ fonts.packages = [
pkgs.tamzen pkgs.tamzen
]; ];

View file

@ -14,8 +14,14 @@ in {
hostName = mkOverride 25 name; hostName = mkOverride 25 name;
nameservers' = [ nameservers' = [
#{ address = "8.8.8.8"; host = "dns.google"; } #{ address = "8.8.8.8"; host = "dns.google"; }
{ address = "1.1.1.1"; host = "cloudflare-dns.com"; } {
{ address = "1.0.0.1"; host = "cloudflare-dns.com"; } address = "1.1.1.1";
host = "cloudflare-dns.com";
}
{
address = "1.0.0.1";
host = "cloudflare-dns.com";
}
]; ];
}; };

View file

@ -23,10 +23,12 @@ in {
lock = importJSON ../../flake.lock; lock = importJSON ../../flake.lock;
mapFlake = name: let mapFlake = name: let
node = lock.nodes.${name}; node = lock.nodes.${name};
in { in
{
inherit (node.original) type; inherit (node.original) type;
inherit (node.locked) lastModified rev narHash; inherit (node.locked) lastModified rev narHash;
} // optionalAttrs (node.original.type == "github") { }
// optionalAttrs (node.original.type == "github") {
inherit (node.original) repo owner; inherit (node.original) repo owner;
}; };
in { in {

View file

@ -1,11 +1,18 @@
{ pkgs, config, lib, ... }: let {
pkgs,
config,
lib,
...
}: let
inherit (lib.options) mkEnableOption mkPackageOption; inherit (lib.options) mkEnableOption mkPackageOption;
inherit (lib.modules) mkIf; inherit (lib.modules) mkIf;
cfg = config.boot.binfmt.cross.aarch64; cfg = config.boot.binfmt.cross.aarch64;
in { in {
options = { options = {
boot.binfmt.cross.aarch64 = { boot.binfmt.cross.aarch64 = {
enable = mkEnableOption "qemu-aarch64" // { enable =
mkEnableOption "qemu-aarch64"
// {
default = true; default = true;
}; };
package = mkPackageOption pkgs "qemu" {}; package = mkPackageOption pkgs "qemu" {};

View file

@ -13,9 +13,12 @@
inherit (lib.trivial) mapNullable flip; inherit (lib.trivial) mapNullable flip;
cfg = config.services.dnsmasq; cfg = config.services.dnsmasq;
inherit (gensokyo-zone) systems; inherit (gensokyo-zone) systems;
localSystems = filterAttrs (_: system: localSystems =
filterAttrs (
_: system:
system.config.access.online.enable && system.config.network.networks.local.enable or false system.config.access.online.enable && system.config.network.networks.local.enable or false
) systems; )
systems;
mkHostRecordPairs = _: system: [ mkHostRecordPairs = _: system: [
(mkHostRecordPair "int" system) (mkHostRecordPair "int" system)
(mkHostRecordPair "local" system) (mkHostRecordPair "local" system)
@ -26,9 +29,12 @@
mkDynamicHostRecord = _: system: let mkDynamicHostRecord = _: system: let
address4 = system.config.network.networks.local.address4 or null; address4 = system.config.network.networks.local.address4 or null;
address6 = system.config.network.networks.local.address6 or null; address6 = system.config.network.networks.local.address6 or null;
in concatStringsSep "," ([ in
concatStringsSep "," (
[
system.config.access.fqdn system.config.access.fqdn
] ++ optional (address4 != null) ]
++ optional (address4 != null)
(toString (mapNullable mapDynamic4 address4)) (toString (mapNullable mapDynamic4 address4))
++ optional (address6 != null) ++ optional (address6 != null)
(toString (mapNullable mapDynamic6 address6)) (toString (mapNullable mapDynamic6 address6))
@ -39,8 +45,13 @@
address4 = system.config.network.networks.${network}.address4 or null; address4 = system.config.network.networks.${network}.address4 or null;
address6 = system.config.network.networks.${network}.address6 or null; address6 = system.config.network.networks.${network}.address6 or null;
fqdn = system.config.network.networks.${network}.fqdn or null; fqdn = system.config.network.networks.${network}.fqdn or null;
in nameValuePair in
(if fqdn != null then fqdn else "${network}.${system.config.access.fqdn}") nameValuePair
(
if fqdn != null
then fqdn
else "${network}.${system.config.access.fqdn}"
)
(concatStringsSep "," ( (concatStringsSep "," (
optional (address4 != null) optional (address4 != null)
(toString address4) (toString address4)
@ -93,15 +104,16 @@ in {
"mco.cubecraft.net" "mco.cubecraft.net"
]; ];
bedrockRecords = map (flip mkHostRecord bedrockRecord) bedrockRecordNames; bedrockRecords = map (flip mkHostRecord bedrockRecord) bedrockRecordNames;
in mkMerge [ in
mkMerge [
(mapAttrsToList mkHostRecord systemHosts) (mapAttrsToList mkHostRecord systemHosts)
(mkIf (cfg.bedrockConnect.address != null || cfg.bedrockConnect.address6 != null) bedrockRecords) (mkIf (cfg.bedrockConnect.address != null || cfg.bedrockConnect.address6 != null) bedrockRecords)
]; ];
dynamic-host = mapAttrsToList mkDynamicHostRecord localSystems; dynamic-host = mapAttrsToList mkDynamicHostRecord localSystems;
server = server =
if config.networking.nameservers' != [ ] then map (ns: ns.address) (filter filterns' config.networking.nameservers') if config.networking.nameservers' != []
else filter filterns config.networking.nameservers then map (ns: ns.address) (filter filterns' config.networking.nameservers')
; else filter filterns config.networking.nameservers;
max-cache-ttl = 60; max-cache-ttl = 60;
}; };
bedrockConnect = let bedrockConnect = let

View file

@ -1,4 +1,8 @@
{config, lib, ...}: let {
config,
lib,
...
}: let
inherit (lib.modules) mkIf mkMerge mkBefore mkDefault; inherit (lib.modules) mkIf mkMerge mkBefore mkDefault;
cfg = config.services.grocy; cfg = config.services.grocy;
in { in {
@ -72,7 +76,8 @@ in {
}; };
systemd.services = let systemd.services = let
gensokyo-zone.sharedMounts.grocy.path = mkDefault cfg.dataDir; gensokyo-zone.sharedMounts.grocy.path = mkDefault cfg.dataDir;
in mkIf cfg.enable { in
mkIf cfg.enable {
grocy-setup = { grocy-setup = {
inherit gensokyo-zone; inherit gensokyo-zone;
}; };

View file

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

View file

@ -1,4 +1,8 @@
{ config, lib, ... }: let {
config,
lib,
...
}: let
inherit (lib.modules) mkDefault; inherit (lib.modules) mkDefault;
in { in {
# NOTE: requires manual post-install setup... # NOTE: requires manual post-install setup...

View file

@ -1,4 +1,11 @@
{inputs, system, access, config, lib, ...}: let {
inputs,
system,
access,
config,
lib,
...
}: let
inherit (lib.modules) mkIf mkForce mkDefault; inherit (lib.modules) mkIf mkForce mkDefault;
inherit (lib.lists) optional; inherit (lib.lists) optional;
cfg = config.services.keycloak; cfg = config.services.keycloak;
@ -20,7 +27,8 @@ in {
sopsFile = ./secrets/keycloak.yaml; sopsFile = ./secrets/keycloak.yaml;
owner = "keycloak"; owner = "keycloak";
}; };
in mkIf cfg.enable { in
mkIf cfg.enable {
keycloak_db_password = commonSecret; keycloak_db_password = commonSecret;
}; };
users = mkIf cfg.enable { users = mkIf cfg.enable {
@ -54,8 +62,16 @@ in {
}; };
settings = { settings = {
hostname = mkDefault (if hostname-strict then hostname else null); hostname = mkDefault (
proxy = mkDefault (if cfg.protocol == "https" then "reencrypt" else "edge"); if hostname-strict
then hostname
else null
);
proxy = mkDefault (
if cfg.protocol == "https"
then "reencrypt"
else "edge"
);
hostname-strict = mkDefault hostname-strict; hostname-strict = mkDefault hostname-strict;
hostname-strict-https = mkDefault hostname-strict; hostname-strict-https = mkDefault hostname-strict;
proxy-headers = mkDefault "xforwarded"; proxy-headers = mkDefault "xforwarded";

View file

@ -1,4 +1,11 @@
{ inputs, pkgs, config, access, lib, ... }: let {
inputs,
pkgs,
config,
access,
lib,
...
}: let
inherit (inputs.self.lib.lib) mkAlmostOptionDefault mapAlmostOptionDefaults; inherit (inputs.self.lib.lib) mkAlmostOptionDefault mapAlmostOptionDefaults;
inherit (lib.modules) mkIf mkMerge mkBefore mkDefault mkOptionDefault; inherit (lib.modules) mkIf mkMerge mkBefore mkDefault mkOptionDefault;
inherit (lib.strings) replaceStrings; inherit (lib.strings) replaceStrings;
@ -68,7 +75,8 @@ in {
kinit -k host/${config.networking.fqdn} kinit -k host/${config.networking.fqdn}
''; '';
in mkIf enabled { in
mkIf enabled {
path = [config.security.krb5.package]; path = [config.security.krb5.package];
serviceConfig = { serviceConfig = {
Type = mkOptionDefault "oneshot"; Type = mkOptionDefault "oneshot";
@ -78,7 +86,8 @@ in {
sops.secrets = let sops.secrets = let
sopsFile = mkDefault ./secrets/krb5.yaml; sopsFile = mkDefault ./secrets/krb5.yaml;
in mkIf enabled { in
mkIf enabled {
krb5-keytab = { krb5-keytab = {
mode = "0400"; mode = "0400";
path = "/etc/krb5.keytab"; path = "/etc/krb5.keytab";

View file

@ -47,7 +47,8 @@ in {
"nfs-mountd.service" "nfs-mountd.service"
]; ];
before = wantedBy; before = wantedBy;
in mkIf config.services.nfs.server.enable [ in
mkIf config.services.nfs.server.enable [
{ {
inherit type options wantedBy before; inherit type options wantedBy before;
what = kyuuto.mountDir; what = kyuuto.mountDir;

Some files were not shown because too many files have changed in this diff Show more