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,23 +73,30 @@ 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 (
optional (network == null && sshd.ports.global.enable or false) sshd.ports.global.port optional (network == null && sshd.ports.global.enable or false) sshd.ports.global.port
++ optional (sshd.ports.public.enable or false) sshd.ports.public.port ++ optional (sshd.ports.public.enable or false) sshd.ports.public.port
++ [ 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;
}; };
}; };
}; };
@ -124,7 +139,7 @@ let
}; };
hosts = mkOption { hosts = mkOption {
type = attrsOf (submoduleWith { type = attrsOf (submoduleWith {
modules = [ sshHostModule ]; modules = [sshHostModule];
specialArgs = { specialArgs = {
inherit gensokyo-zone osConfig homeConfig pkgs; inherit gensokyo-zone osConfig homeConfig pkgs;
}; };
@ -132,7 +147,7 @@ let
}; };
networks = mkOption { networks = mkOption {
type = listOf (nullOr str); type = listOf (nullOr str);
default = [ null ]; default = [null];
}; };
proxyJump = mkOption { proxyJump = mkOption {
type = str; type = str;
@ -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,31 +175,35 @@ 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,
gensokyo-zone, gensokyo-zone,
pkgs, pkgs,
... ...
}: let }: let
inherit (lib.options) mkOption; inherit (lib.options) mkOption;
inherit (lib.modules) mkIf; inherit (lib.modules) mkIf;
inherit (gensokyo-zone.lib) unmerged; inherit (gensokyo-zone.lib) unmerged;
cfg = config.gensokyo-zone.ssh; cfg = config.gensokyo-zone.ssh;
in { in {
options.gensokyo-zone.ssh = mkOption { options.gensokyo-zone.ssh = mkOption {
type = lib.types.submoduleWith { type = lib.types.submoduleWith {
modules = [sshModule]; modules = [sshModule];
@ -193,7 +213,7 @@ in {
homeConfig = config; homeConfig = config;
}; };
}; };
default = { }; default = {};
}; };
config = { config = {
@ -206,4 +226,4 @@ in {
inherit cfg sshModule sshHostModule; inherit cfg sshModule sshHostModule;
}; };
}; };
} }

View file

@ -1,4 +1,4 @@
{ ... }: { {...}: {
imports = [ imports = [
../../nixos/ipa.nix ../../nixos/ipa.nix
]; ];

View file

@ -1,4 +1,4 @@
{ ... }: { {...}: {
imports = [ imports = [
../../nixos/network/netgroups.nix ../../nixos/network/netgroups.nix
]; ];

View file

@ -1,4 +1,4 @@
{ ... }: { {...}: {
imports = [ imports = [
../../nixos/sssd/sssd.nix ../../nixos/sssd/sssd.nix
../../nixos/sssd/pam.nix ../../nixos/sssd/pam.nix

View file

@ -35,7 +35,7 @@ in {
nixosConfig = config; nixosConfig = config;
}; };
}; };
default = { }; default = {};
}; };
config = { config = {

View file

@ -42,7 +42,7 @@
type = listOf str; type = listOf str;
}; };
fallback = mkOption { fallback = mkOption {
type = nullOr (enum [ "cloudflare" "google" ]); type = nullOr (enum ["cloudflare" "google"]);
default = "cloudflare"; default = "cloudflare";
}; };
fallbackNameservers = mkOption { fallbackNameservers = mkOption {
@ -67,8 +67,9 @@
]; ];
nameservers = let nameservers = let
inherit (gensokyo-zone.systems) utsuho hakurei; inherit (gensokyo-zone.systems) utsuho hakurei;
in mkMerge [ in
(mkOptionDefault [ ]) mkMerge [
(mkOptionDefault [])
(mkIf access.local.enable [ (mkIf access.local.enable [
(mkIf enableIPv6 utsuho.config.access.address6ForNetwork.local) (mkIf enableIPv6 utsuho.config.access.address6ForNetwork.local)
utsuho.config.access.address4ForNetwork.local utsuho.config.access.address4ForNetwork.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 [
@ -123,11 +129,11 @@ in {
nixosConfig = config; nixosConfig = config;
}; };
}; };
default = { }; default = {};
}; };
config = { config = {
networking.nameservers = mkIf (cfg.enable && cfg.nameservers != [ ]) (mkMerge [ networking.nameservers = mkIf (cfg.enable && cfg.nameservers != []) (mkMerge [
(mkBefore cfg.nameservers) (mkBefore cfg.nameservers)
cfg.fallbackNameservers cfg.fallbackNameservers
]); ]);

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 {
@ -59,7 +61,7 @@
}; };
urls = mkOption { urls = mkOption {
type = listOf str; type = listOf str;
default = [ "ldaps://${config.ldap.host}" ]; default = ["ldaps://${config.ldap.host}"];
}; };
baseDn = mkOption { baseDn = mkOption {
type = str; type = str;
@ -75,21 +77,21 @@
}; };
passwordFileKrb5 = mkOption { passwordFileKrb5 = mkOption {
type = path; type = path;
example = lib.literalExpression "\${pkgs.writeText "ldap.kdb5" '' example = lib.literalExpression "\${pkgs.writeText " ldap.kdb5 " ''
${config.bind.dn}#{HEX}616e6f6e796d6f7573 ${config.bind.dn}#{HEX}616e6f6e796d6f7573
''}"; ''}";
}; };
passwordFileSssdEnv = mkOption { passwordFileSssdEnv = mkOption {
type = path; type = path;
example = lib.literalExpression "\${pkgs.writeText "ldap.kdb5" '' example = lib.literalExpression "\${pkgs.writeText " ldap.kdb5 " ''
${"SSSD_AUTHTOK_" + replaceStrings [ "." ] [ "_" ] (toUpper config.domain)}=verysecretpassword ${"SSSD_AUTHTOK_" + replaceStrings ["."] ["_"] (toUpper config.domain)}=verysecretpassword
''}"; ''}";
}; };
}; };
}; };
db = { db = {
backend = mkOption { backend = mkOption {
type = enum [ "kldap" "ipa" ]; type = enum ["kldap" "ipa"];
default = "kldap"; default = "kldap";
}; };
}; };
@ -99,7 +101,7 @@
}; };
authToLocalNames = mkOption { authToLocalNames = mkOption {
type = attrsOf str; type = attrsOf str;
default = { }; default = {};
example = { example = {
"arc@${config.realm}" = "arc"; "arc@${config.realm}" = "arc";
}; };
@ -108,26 +110,30 @@
enable = mkEnableOption "sssd"; enable = mkEnableOption "sssd";
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 {
type = listOf str; type = listOf str;
example = [ config.ipa.host ]; example = [config.ipa.host];
default = [ "2.fedora.pool.ntp.org" ]; default = ["2.fedora.pool.ntp.org"];
}; };
}; };
nfs = { nfs = {
enable = mkEnableOption "nfs"; enable = mkEnableOption "nfs";
package = mkPackageOption pkgs "nfs-utils" { }; package = mkPackageOption pkgs "nfs-utils" {};
idmapd = { idmapd = {
localDomain = mkOption { localDomain = mkOption {
type = bool; type = bool;
@ -135,11 +141,11 @@
}; };
localRealms = mkOption { localRealms = mkOption {
type = listOf str; type = listOf str;
default = [ config.realm ]; default = [config.realm];
}; };
methods = mkOption { methods = mkOption {
type = listOf str; type = listOf str;
default = [ "nsswitch" ]; default = ["nsswitch"];
}; };
authToLocalNames = mkOption { authToLocalNames = mkOption {
type = attrsOf str; type = attrsOf str;
@ -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;
@ -211,11 +219,11 @@
package = mkIf (elem "umich_ldap" config.nfs.idmapd.methods) (mkAlmostOptionDefault pkgs.nfs-utils-ldap); package = mkIf (elem "umich_ldap" config.nfs.idmapd.methods) (mkAlmostOptionDefault pkgs.nfs-utils-ldap);
idmapd = { idmapd = {
methods = mkMerge [ methods = mkMerge [
(mkIf (config.nfs.idmapd.authToLocalNames != { }) ( (mkIf (config.nfs.idmapd.authToLocalNames != {}) (
mkOptionDefault (mkBefore [ "static" ]) mkOptionDefault (mkBefore ["static"])
)) ))
(mkIf (!enabled.sssd) ( (mkIf (!enabled.sssd) (
mkOptionDefault [ "umich_ldap" ] mkOptionDefault ["umich_ldap"]
)) ))
]; ];
}; };
@ -243,22 +251,24 @@
}; };
}; };
sssdSettings = let sssdSettings = let
servers = optional access.local.enable "idp.local.${config.domain}" servers =
++ [ "_srv" ]; optional access.local.enable "idp.local.${config.domain}"
++ ["_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;
krb5.servers = { krb5.servers = {
servers = servers ++ [ config.host ]; servers = servers ++ [config.host];
inherit backups; inherit backups;
}; };
ipa.servers = { ipa.servers = {
servers = servers ++ [ config.ipa.host ]; servers = servers ++ [config.ipa.host];
inherit backups; inherit backups;
}; };
ldap = { ldap = {
@ -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
@ -344,10 +364,10 @@
Domain = mkForce config.domain; Domain = mkForce config.domain;
Local-Realms = concatStringsSep "," config.nfs.idmapd.localRealms; Local-Realms = concatStringsSep "," config.nfs.idmapd.localRealms;
}; };
Translation.Method = mkIf (config.nfs.idmapd.methods != [ "nsswitch" ]) (mkForce ( Translation.Method = mkIf (config.nfs.idmapd.methods != ["nsswitch"]) (mkForce (
concatStringsSep "," config.nfs.idmapd.methods concatStringsSep "," config.nfs.idmapd.methods
)); ));
Static = mkIf (config.nfs.idmapd.authToLocalNames != { }) config.nfs.idmapd.authToLocalNames; Static = mkIf (config.nfs.idmapd.authToLocalNames != {}) config.nfs.idmapd.authToLocalNames;
UMICH_SCHEMA = mkIf (elem "umich_ldap" config.nfs.idmapd.methods) (mapOptionDefaults { UMICH_SCHEMA = mkIf (elem "umich_ldap" config.nfs.idmapd.methods) (mapOptionDefaults {
LDAP_server = config.ldap.host; LDAP_server = config.ldap.host;
LDAP_use_ssl = true; LDAP_use_ssl = true;
@ -389,7 +409,7 @@ in {
nixosOptions = options; nixosOptions = options;
}; };
}; };
default = { }; default = {};
}; };
config = { config = {
@ -413,9 +433,10 @@ 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
${freeipa.config.access.address6ForNetwork.local} = mkIf config.networking.enableIPv6 (mkBefore [ cfg.host ]); mkIf (cfg.enable && !config.gensokyo-zone.dns.enable or false && config.gensokyo-zone.access.local.enable) {
${freeipa.config.access.address4ForNetwork.local} = mkBefore [ cfg.host ]; ${freeipa.config.access.address6ForNetwork.local} = mkIf config.networking.enableIPv6 (mkBefore [cfg.host]);
${freeipa.config.access.address4ForNetwork.local} = mkBefore [cfg.host];
}; };
}; };
environment.etc = { environment.etc = {
@ -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")
]) ])
]); ]);
@ -204,7 +218,7 @@ in {
nixosConfig = config; nixosConfig = config;
}; };
}; };
default = { }; default = {};
}; };
config = { config = {

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 {
@ -105,8 +107,8 @@
]; ];
builder = { builder = {
systems = mkMerge [ systems = mkMerge [
(mkIf config.builder.cross.aarch64 (mkOptionDefault [ "aarch64-linux" ])) (mkIf config.builder.cross.aarch64 (mkOptionDefault ["aarch64-linux"]))
(mkIf config.builder.cross.armv7l (mkOptionDefault [ "armv7l-linux" ])) (mkIf config.builder.cross.armv7l (mkOptionDefault ["armv7l-linux"]))
]; ];
domain = mkMerge [ domain = mkMerge [
(mkIf access.tail.enabled (mkAlmostOptionDefault "nixbld.tail.${domain}")) (mkIf access.tail.enabled (mkAlmostOptionDefault "nixbld.tail.${domain}"))
@ -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 = {
@ -145,7 +149,7 @@ in {
nixosOptions = options; nixosOptions = options;
}; };
}; };
default = { }; default = {};
}; };
config = { config = {
@ -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

@ -162,7 +162,7 @@
modules = [userModule]; modules = [userModule];
inherit specialArgs; inherit specialArgs;
}); });
default = { }; default = {};
}; };
excludeUsers = mkOption { excludeUsers = mkOption {
type = listOf str; type = listOf str;
@ -172,7 +172,7 @@
modules = [groupModule]; modules = [groupModule];
inherit specialArgs; inherit specialArgs;
}); });
default = { }; default = {};
}; };
excludeGroups = mkOption { excludeGroups = mkOption {
type = listOf str; type = listOf str;

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

@ -55,7 +55,7 @@ in {
nftables.ruleset = mkIf cfg.enable (mkBefore cfg.nftablesInclude); nftables.ruleset = mkIf cfg.enable (mkBefore cfg.nftablesInclude);
firewall = { firewall = {
interfaces.local = { interfaces.local = {
nftables.conditions = mkIf (cfg.enable && networking.enableIPv6) [ "ip6 saddr $localrange6" ]; nftables.conditions = mkIf (cfg.enable && networking.enableIPv6) ["ip6 saddr $localrange6"];
}; };
}; };
}; };

View file

@ -15,33 +15,42 @@
hasSops = options ? sops.secrets; hasSops = options ? sops.secrets;
in { in {
options.networking.access.peeps = with lib.types; { options.networking.access.peeps = with lib.types; {
enable = mkEnableOption "peeps" // { default = hasSops; }; enable = mkEnableOption "peeps" // {default = hasSops;};
ranges = mkOption { ranges = mkOption {
type = attrsOf str; type = attrsOf str;
default = { }; default = {};
}; };
stateDir = mkOption { stateDir = mkOption {
type = path; type = path;
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 (
nftRanges nftRanges
++ [ (mkBefore ''include "${cfg.stateDir}/*.nft"'') ] ++ [(mkBefore ''include "${cfg.stateDir}/*.nft"'')]
)); ));
firewall.interfaces.peeps = { firewall.interfaces.peeps = {
nftables.enable = cfg.enable; nftables.enable = cfg.enable;

View file

@ -1,4 +1,4 @@
{ gensokyo-zone, ... }: { {gensokyo-zone, ...}: {
config.lib = { config.lib = {
inherit gensokyo-zone; inherit gensokyo-zone;
}; };

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,17 +14,20 @@
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}"'';
in { in {
options.services.barcodebuddy = with lib.types; { options.services.barcodebuddy = with lib.types; {
enable = mkEnableOption "Barcode Buddy"; enable = mkEnableOption "Barcode Buddy";
package = mkPackageOption pkgs "barcodebuddy" { }; package = mkPackageOption pkgs "barcodebuddy" {};
phpPackageUnwrapped = mkPackageOption pkgs "php83" { }; phpPackageUnwrapped = mkPackageOption pkgs "php83" {};
hostName = mkOption { hostName = mkOption {
type = str; type = str;
}; };
@ -38,7 +47,7 @@ in {
enable = mkEnableOption "reverse proxy"; enable = mkEnableOption "reverse proxy";
trustedAddresses = mkOption { trustedAddresses = mkOption {
type = listOf str; type = listOf str;
default = [ "127.0.0.1" "::1" ]; default = ["127.0.0.1" "::1"];
}; };
}; };
screen = { screen = {
@ -65,13 +74,15 @@ 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)]);
description = "https://github.com/Forceu/barcodebuddy/blob/master/config-dist.php"; description = "https://github.com/Forceu/barcodebuddy/blob/master/config-dist.php";
}; };
nginxConfig = mkOption { nginxConfig = mkOption {
@ -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
@ -190,7 +220,7 @@ in {
}; };
}; };
conf.systemd.services.bbuddy-websocket = mkIf cfg.screen.enable { conf.systemd.services.bbuddy-websocket = mkIf cfg.screen.enable {
wantedBy = [ "multi-user.target" ]; wantedBy = ["multi-user.target"];
environment = mapAttrs' toEnvPair cfg.settings; environment = mapAttrs' toEnvPair cfg.settings;
unitConfig = { unitConfig = {
Description = "Run websocket server for barcodebuddy screen feature"; Description = "Run websocket server for barcodebuddy screen feature";
@ -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

@ -82,7 +82,7 @@ in {
interfaces.local = { interfaces.local = {
allowedTCPPorts = mkMerge [ allowedTCPPorts = mkMerge [
(mkIf (!cfg.homekit.openFirewall) homekitTcp) (mkIf (!cfg.homekit.openFirewall) homekitTcp)
(mkIf (!cfg.openFirewall) [ cfg.config.http.server_port ]) (mkIf (!cfg.openFirewall) [cfg.config.http.server_port])
]; ];
allowedUDPPortRanges = mkIf (!cfg.cast.openFirewall) castUdpRanges; allowedUDPPortRanges = mkIf (!cfg.cast.openFirewall) castUdpRanges;
}; };

View file

@ -14,7 +14,7 @@
cfg = config.security.ipa; cfg = config.security.ipa;
in { in {
options.security.ipa = with lib.types; { options.security.ipa = with lib.types; {
package = mkPackageOption pkgs "freeipa" { }; package = mkPackageOption pkgs "freeipa" {};
overrideConfigs = { overrideConfigs = {
krb5 = mkOption { krb5 = mkOption {
type = bool; type = bool;
@ -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,14 +48,15 @@ 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";
chpass_provider = "ipa"; chpass_provider = "ipa";
ipa_domain = cfg.domain; ipa_domain = cfg.domain;
ipa_server = [ "_srv_" cfg.server ]; ipa_server = ["_srv_" cfg.server];
ipa_hostname = "${config.networking.hostName}.${cfg.domain}"; ipa_hostname = "${config.networking.hostName}.${cfg.domain}";
@ -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);
}; };
}; };
@ -136,8 +139,9 @@ 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,11 +1,15 @@
{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;
in { in {
options.services.keycloak = with lib.types; { options.services.keycloak = with lib.types; {
protocol = mkOption { protocol = mkOption {
type = enum [ "http" "https" ]; type = enum ["http" "https"];
readOnly = true; readOnly = true;
}; };
port = mkOption { port = mkOption {
@ -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;
@ -50,12 +56,12 @@ in {
}; };
}; };
db.backend = mkOption { db.backend = mkOption {
type = enum [ "kldap" "ipa" ]; type = enum ["kldap" "ipa"];
default = "kldap"; default = "kldap";
}; };
authToLocalNames = mkOption { authToLocalNames = mkOption {
type = attrsOf str; type = attrsOf str;
default = { }; default = {};
}; };
}; };
config = { config = {
@ -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,23 +79,26 @@ 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 {
db_library = "${ipa.package}/lib/krb5/plugins/kdb/ipadb.so"; db_library = "${ipa.package}/lib/krb5/plugins/kdb/ipadb.so";
}); });
${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));
}; };
domain_realm = mapOptionDefaults { domain_realm = mapOptionDefaults {
${cfg.domain} = cfg.realm; ${cfg.domain} = cfg.realm;
@ -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}"
@ -120,16 +131,18 @@ in {
]; ];
}; };
}; };
networking.timeServers = mkIf (cfg.enable && enabled) [ "2.fedora.pool.ntp.org" ]; networking.timeServers = mkIf (cfg.enable && enabled) ["2.fedora.pool.ntp.org"];
security.ipa = mkIf cfg.enable { security.ipa = mkIf cfg.enable {
certificate = mkDefault cfg.ca.cert; certificate = mkDefault cfg.ca.cert;
basedn = mkDefault cfg.ldap.baseDn; basedn = mkDefault cfg.ldap.baseDn;
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;
@ -11,10 +17,10 @@ let
default = name; default = name;
}; };
xuid = mkOption { xuid = mkOption {
type = oneOf [ int str ]; type = oneOf [int str];
}; };
permission = mkOption { permission = mkOption {
type = enum [ "visitor" "member" "operator" ]; type = enum ["visitor" "member" "operator"];
default = "member"; default = "member";
}; };
settings = mkOption { settings = mkOption {
@ -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 {
@ -59,41 +73,55 @@ let
type = str; type = str;
}; };
packType = mkOption { packType = mkOption {
type = enum [ "resource_packs" "behavior_packs" ]; type = enum ["resource_packs" "behavior_packs"];
}; };
packId = mkOption { packId = mkOption {
type = str; type = str;
}; };
version = mkOption { version = mkOption {
type = oneOf [ str (listOf str) ]; type = oneOf [str (listOf str)];
}; };
settings = mkOption { settings = mkOption {
type = attrsOf (oneOf [ str (listOf str) ]); type = attrsOf (oneOf [str (listOf str)]);
}; };
}; };
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,13 +134,18 @@ 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
in { (n: v: "${n}=${cfgToString v}")
cfg.serverProperties));
in {
options.services.minecraft-bedrock-server = with lib.types; { options.services.minecraft-bedrock-server = with lib.types; {
enable = mkOption { enable = mkOption {
type = bool; type = bool;
@ -133,7 +166,7 @@ in {
}; };
serverProperties = mkOption { serverProperties = mkOption {
type = attrsOf (oneOf [ bool int str float ]); type = attrsOf (oneOf [bool int str float]);
example = literalExample '' example = literalExample ''
{ {
server-name = "Dedicated Server"; server-name = "Dedicated Server";
@ -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.";
}; };
@ -187,7 +222,7 @@ in {
allowPlayers = mkOption { allowPlayers = mkOption {
type = nullOr (attrsOf (submoduleWith { type = nullOr (attrsOf (submoduleWith {
modules = [ allowListModule ]; modules = [allowListModule];
specialArgs = { specialArgs = {
inherit gensokyo-zone; inherit gensokyo-zone;
nixosConfig = config; nixosConfig = config;
@ -206,13 +241,13 @@ in {
packs = mkOption { packs = mkOption {
type = attrsOf (submoduleWith { type = attrsOf (submoduleWith {
modules = [ packModule ]; modules = [packModule];
specialArgs = { specialArgs = {
inherit gensokyo-zone; inherit gensokyo-zone;
nixosConfig = config; nixosConfig = config;
}; };
}); });
default = { }; default = {};
}; };
}; };
@ -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
); );
}; };
@ -274,8 +313,8 @@ in {
conf.systemd.services.minecraft-bedrock-server = { conf.systemd.services.minecraft-bedrock-server = {
description = "Minecraft Bedrock Server Service"; description = "Minecraft Bedrock Server Service";
wantedBy = [ "multi-user.target" ]; wantedBy = ["multi-user.target"];
after = [ "network.target" ]; after = ["network.target"];
serviceConfig = { serviceConfig = {
BindReadOnlyPaths = let BindReadOnlyPaths = let
@ -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,17 +347,19 @@ 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"])
(mkIf (cfg.packs != { }) packsPaths) (mkIf (cfg.packs != {}) packsPaths)
]; ];
ExecStart = [ ExecStart = [
"${getExe cfg.package}" "${getExe cfg.package}"
@ -339,12 +382,14 @@ 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,14 +9,18 @@
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;
default = name; default = name;
}; };
user = mkOption { user = mkOption {
type = either (enum [ null "-" ]) str; type = either (enum [null "-"]) str;
default = "-"; default = "-";
}; };
domain = mkOption { domain = mkOption {
@ -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;
@ -40,14 +48,14 @@
}; };
members = mkOption { members = mkOption {
type = attrsOf (submodule netgroupMemberModule); type = attrsOf (submodule netgroupMemberModule);
default = { }; default = {};
}; };
fileLine = mkOption { fileLine = mkOption {
type = str; type = str;
}; };
}; };
config = { config = {
fileLine = mkOptionDefault (concatStringsSep " " ([ config.name ] ++ mapAttrsToList (_: member: member.triple) config.members)); fileLine = mkOptionDefault (concatStringsSep " " ([config.name] ++ mapAttrsToList (_: member: member.triple) config.members));
}; };
}; };
in { in {
@ -60,7 +68,7 @@ in {
networking = { networking = {
netgroups = mkOption { netgroups = mkOption {
type = attrsOf (submodule netgroupModule); type = attrsOf (submodule netgroupModule);
default = { }; default = {};
}; };
extraNetgroups = mkOption { extraNetgroups = mkOption {
type = lines; type = lines;
@ -71,17 +79,17 @@ in {
config = { config = {
system.nssDatabases = { system.nssDatabases = {
netgroup = mkMerge [ netgroup = mkMerge [
(mkBefore [ "files" ]) (mkBefore ["files"])
(mkAfter [ "nis" ]) (mkAfter ["nis"])
]; ];
}; };
environment.etc."nsswitch.conf".text = mkIf (nssDatabases.netgroup != [ ]) (mkAfter '' environment.etc."nsswitch.conf".text = mkIf (nssDatabases.netgroup != []) (mkAfter ''
netgroup: ${concatStringsSep " " nssDatabases.netgroup} netgroup: ${concatStringsSep " " nssDatabases.netgroup}
''); '');
environment.etc."netgroup" = mkIf (networking.netgroups != { } || networking.extraNetgroups != "") { environment.etc."netgroup" = mkIf (networking.netgroups != {} || networking.extraNetgroups != "") {
text = mkMerge ( text = mkMerge (
mapAttrsToList (_: ng: ng.fileLine) networking.netgroups mapAttrsToList (_: ng: ng.fileLine) networking.netgroups
++ [ networking.extraNetgroups ] ++ [networking.extraNetgroups]
); );
}; };
}; };

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,19 +11,30 @@
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
[ addr ] then "[${address}]"
else address;
in
concatStrings (
[addr]
++ optional (port != dnsPort) ":${toString port}" ++ optional (port != dnsPort) ":${toString port}"
++ optional (interface != null) "%${interface}" ++ optional (interface != null) "%${interface}"
++ optional (host != null) "#${host}" ++ optional (host != null) "#${host}"
); );
in { in {
options = with lib.types; { options = with lib.types; {
enable = mkEnableOption "nameserver" // { enable =
mkEnableOption "nameserver"
// {
default = true; default = true;
}; };
address = mkOption { address = mkOption {
@ -59,12 +74,16 @@ in {
options.networking = with lib.types; { options.networking = with lib.types; {
nameservers' = mkOption { nameservers' = mkOption {
type = listOf (submodule nameserverModule); type = listOf (submodule nameserverModule);
default = { }; default = {};
}; };
}; };
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,16 +21,20 @@
(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)];
default = name; default = name;
example = "*"; example = "*";
}; };
flags = mkOption { flags = mkOption {
type = listOf str; type = listOf str;
default = [ ]; default = [];
}; };
entry = mkOption { entry = mkOption {
type = str; type = str;
@ -38,12 +42,17 @@
}; };
config = { config = {
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;
@ -60,12 +69,14 @@
}; };
}; };
config = { config = {
flags = mkOptionDefault (cfg.export.flagSets.common or [ ]); flags = mkOptionDefault (cfg.export.flagSets.common or []);
fileLine = let fileLine = let
parts = [ config.path ] parts =
++ optional (config.flags != [ ]) "-${concatFlags config.flags}" [config.path]
++ 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 {
@ -74,15 +85,15 @@ in {
flagSets = mkOption { flagSets = mkOption {
type = lazyAttrsOf (listOf str); type = lazyAttrsOf (listOf str);
default = { default = {
common = [ "no_subtree_check" ]; common = ["no_subtree_check"];
}; };
}; };
root = mkOption { root = mkOption {
type = nullOr (submodule [ type = nullOr (submodule [
exportModule exportModule
({ ... }: { ({...}: {
flags = mkMerge [ flags = mkMerge [
(cfg.export.flagSets.common or [ ]) (cfg.export.flagSets.common or [])
]; ];
}) })
]); ]);
@ -90,7 +101,7 @@ in {
}; };
paths = mkOption { paths = mkOption {
type = attrsOf (submodule exportModule); type = attrsOf (submodule exportModule);
default = { }; default = {};
}; };
}; };
}; };

View file

@ -111,7 +111,7 @@
}; };
conditions = mkOption { conditions = mkOption {
type = types.listOf types.str; type = types.listOf types.str;
default = [ "iifname ${name}" ]; default = ["iifname ${name}"];
}; };
}; };
}; };

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;
}; };
}; };
@ -15,14 +18,16 @@
extraConfig = mkExtraForce "deny all;"; extraConfig = mkExtraForce "deny all;";
}; };
}; };
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 {
type = attrsOf (submoduleWith { type = attrsOf (submoduleWith {
modules = [ locationModule ]; modules = [locationModule];
shorthandOnlyDefinesConfig = true; shorthandOnlyDefinesConfig = true;
}); });
}; };
@ -39,7 +44,7 @@ in {
options = with lib.types; { options = with lib.types; {
services.nginx.virtualHosts = mkOption { services.nginx.virtualHosts = mkOption {
type = attrsOf (submoduleWith { type = attrsOf (submoduleWith {
modules = [ hostModule ]; modules = [hostModule];
shorthandOnlyDefinesConfig = true; shorthandOnlyDefinesConfig = true;
}); });
}; };

View file

@ -30,7 +30,7 @@ let
}; };
passHeaders = mkOption { passHeaders = mkOption {
type = attrsOf bool; type = attrsOf bool;
default = { }; default = {};
description = "fastcgi_pass_header"; description = "fastcgi_pass_header";
}; };
socket = mkOption { socket = mkOption {
@ -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,15 +87,13 @@ 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; {
services.nginx.virtualHosts = mkOption { services.nginx.virtualHosts = mkOption {
type = attrsOf (submodule [hostModule]); type = attrsOf (submodule [hostModule]);
}; };
}; };
} }

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;
@ -13,25 +20,32 @@ let
default = true; default = true;
}; };
set = mkOption { set = mkOption {
type = attrsOf (nullOr (oneOf [ str (listOf str) ])); type = attrsOf (nullOr (oneOf [str (listOf str)]));
}; };
}; };
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 {
headers = { headers = {
set = mkMerge [ set = mkMerge [
(mkOptionDefault { }) (mkOptionDefault {})
(mkIf cfg.inheritServerDefaults (mapOptionDefaults virtualHost.headers.set)) (mkIf cfg.inheritServerDefaults (mapOptionDefaults virtualHost.headers.set))
]; ];
}; };
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;
@ -39,12 +53,12 @@ let
options = with lib.types; { options = with lib.types; {
headers = { headers = {
set = mkOption { set = mkOption {
type = attrsOf (nullOr (oneOf [ str (listOf str) ])); type = attrsOf (nullOr (oneOf [str (listOf str)]));
}; };
}; };
locations = mkOption { locations = mkOption {
type = attrsOf (submoduleWith { type = attrsOf (submoduleWith {
modules = [ locationModule ]; modules = [locationModule];
shorthandOnlyDefinesConfig = true; shorthandOnlyDefinesConfig = true;
}); });
}; };
@ -55,16 +69,14 @@ 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; {
headers = { headers = {
set = mkOption { set = mkOption {
type = attrsOf (nullOr (oneOf [ str (listOf str) ])); type = attrsOf (nullOr (oneOf [str (listOf str)]));
default = { default = {
}; };
}; };
@ -73,4 +85,4 @@ in {
type = attrsOf (submodule [hostModule]); type = attrsOf (submodule [hostModule]);
}; };
}; };
} }

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 {
@ -34,7 +41,7 @@
}; };
extraParameters = mkOption { extraParameters = mkOption {
type = listOf str; type = listOf str;
default = [ ]; default = [];
}; };
proxyProtocol = mkOption { proxyProtocol = mkOption {
type = bool; type = bool;
@ -59,11 +66,13 @@
(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')
(mkIf (config.addr != null) (mkAlmostOptionDefault [ config.addr ])) (mkIf (config.addr != null) (mkAlmostOptionDefault [config.addr]))
]; ];
listenParameters = mkOptionDefault ( listenParameters = mkOptionDefault (
optional config.ssl "ssl" optional config.ssl "ssl"
@ -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;
[ (mkBefore host) ] inherit (config) port;
};
in
mkMerge (
[(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; {
@ -113,7 +141,7 @@
listenKind = "virtualHost"; listenKind = "virtualHost";
}; };
}); });
default = { }; default = {};
}; };
listenAddresses' = mkOption { listenAddresses' = mkOption {
type = listOf str; type = listOf str;
@ -122,16 +150,22 @@
}; };
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; {
@ -144,7 +178,7 @@
listenKind = "streamServer"; listenKind = "streamServer";
}; };
}); });
default = { }; default = {};
}; };
listenAddresses = mkOption { listenAddresses = mkOption {
type = nullOr (listOf str); type = nullOr (listOf str);
@ -163,11 +197,13 @@
}; };
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
)); ));
}; };
@ -176,13 +212,13 @@ in {
options.services.nginx = with lib.types; { options.services.nginx = with lib.types; {
virtualHosts = mkOption { virtualHosts = mkOption {
type = attrsOf (submoduleWith { type = attrsOf (submoduleWith {
modules = [ hostModule ]; modules = [hostModule];
shorthandOnlyDefinesConfig = true; shorthandOnlyDefinesConfig = true;
}); });
}; };
stream.servers = mkOption { stream.servers = mkOption {
type = attrsOf (submoduleWith { type = attrsOf (submoduleWith {
modules = [ streamServerModule ]; modules = [streamServerModule];
shorthandOnlyDefinesConfig = false; shorthandOnlyDefinesConfig = false;
}); });
}; };

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}
@ -25,12 +31,12 @@
}; };
files = mkOption { files = mkOption {
type = listOf path; type = listOf path;
default = [ ]; default = [];
}; };
}; };
set = mkOption { set = mkOption {
type = attrsOf (either path lines); type = attrsOf (either path lines);
default = { }; default = {};
}; };
}; };
config = { config = {
@ -40,25 +46,27 @@
${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
))) )))
]; ];
}; };
}; };
locationModule = {config, ...}: { locationModule = {config, ...}: {
imports = [ luaModule ]; imports = [luaModule];
}; };
hostModule = {config, ...}: { hostModule = {config, ...}: {
imports = [ luaModule ]; imports = [luaModule];
options = with lib.types; { options = with lib.types; {
locations = mkOption { locations = mkOption {
type = attrsOf (submoduleWith { type = attrsOf (submoduleWith {
modules = [ locationModule ]; modules = [locationModule];
shorthandOnlyDefinesConfig = true; shorthandOnlyDefinesConfig = true;
}); });
}; };
@ -84,7 +92,7 @@ in {
}; };
virtualHosts = mkOption { virtualHosts = mkOption {
type = attrsOf (submoduleWith { type = attrsOf (submoduleWith {
modules = [ hostModule ]; modules = [hostModule];
shorthandOnlyDefinesConfig = true; shorthandOnlyDefinesConfig = true;
}); });
}; };
@ -92,18 +100,20 @@ 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 ";")]
); );
}; };
additionalModules = mkMerge [ additionalModules = mkMerge [
(mkIf cfg.ndk.enable [ pkgs.nginxModules.develkit ]) (mkIf cfg.ndk.enable [pkgs.nginxModules.develkit])
(mkIf cfg.http.enable [ pkgs.nginxModules.lua ]) (mkIf cfg.http.enable [pkgs.nginxModules.lua])
(mkIf cfg.upstream.enable [ pkgs.nginxModules.lua-upstream ]) (mkIf cfg.upstream.enable [pkgs.nginxModules.lua-upstream])
]; ];
}; };
systemd.services.nginx = mkIf config.services.nginx.enable { systemd.services.nginx = mkIf config.services.nginx.enable {

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
); );
}; };
@ -71,7 +74,7 @@
(mkIf (cfg.tailscaleName != null) cfg.tailscaleName) (mkIf (cfg.tailscaleName != null) cfg.tailscaleName)
]); ]);
allServerNames = mkOptionDefault (filter (name: ! hasPrefix "@" name) ( allServerNames = mkOptionDefault (filter (name: ! hasPrefix "@" name) (
[ config.serverName ] ++ config.serverAliases [config.serverName] ++ config.serverAliases
)); ));
otherServerNames = mkOptionDefault (filter (name: ! hasPrefix "@" name) ( otherServerNames = mkOptionDefault (filter (name: ! hasPrefix "@" name) (
config.serverAliases config.serverAliases

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;
@ -13,7 +20,7 @@ let
enable = mkEnableOption "ngx_stream_ssl_preread_module"; enable = mkEnableOption "ngx_stream_ssl_preread_module";
upstream = mkOption { upstream = mkOption {
type = str; type = str;
default = "$preread_" + replaceStrings [ "'" ] [ "_" ] name; default = "$preread_" + replaceStrings ["'"] ["_"] name;
}; };
upstreams = mkOption { upstreams = mkOption {
type = nullOr (attrsOf str); type = nullOr (attrsOf str);
@ -25,8 +32,9 @@ let
config = let config = 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,12 +54,18 @@ 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;
cfg = config.services.nginx.ssl.preread; cfg = config.services.nginx.ssl.preread;
in { in {
options.services.nginx = with lib.types; { options.services.nginx = with lib.types; {
ssl.preread = { ssl.preread = {
enable = mkEnableOption "ssl preread"; enable = mkEnableOption "ssl preread";
@ -101,4 +115,4 @@ in {
}; };
}; };
}; };
} }

View file

@ -1,5 +1,5 @@
let let
xHeadersProxied = { xvars }: '' xHeadersProxied = {xvars}: ''
${xvars.init "forwarded_for" "$proxy_add_x_forwarded_for"} ${xvars.init "forwarded_for" "$proxy_add_x_forwarded_for"}
if ($http_x_forwarded_proto) { if ($http_x_forwarded_proto) {
${xvars.init "scheme" "$http_x_forwarded_proto"} ${xvars.init "scheme" "$http_x_forwarded_proto"}
@ -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;
@ -27,7 +34,7 @@ let
options = with lib.types; { options = with lib.types; {
proxied = { proxied = {
enable = mkOption { enable = mkOption {
type = enum [ false true "cloudflared" ]; type = enum [false true "cloudflared"];
default = false; default = false;
}; };
enabled = mkOption { enabled = mkOption {
@ -60,12 +67,19 @@ let
xvars.enable = mkIf cfg.enabled true; xvars.enable = mkIf cfg.enabled true;
extraConfig = mkMerge [ extraConfig = mkMerge [
(mkIf emitVars ( (mkIf emitVars (
mkJustBefore (xHeadersProxied { inherit xvars; }) mkJustBefore (xHeadersProxied {inherit xvars;})
)) ))
]; ];
}; };
}; };
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;
@ -75,7 +89,7 @@ let
options = with lib.types; { options = with lib.types; {
proxied = { proxied = {
enable = mkOption { enable = mkOption {
type = enum [ false true "cloudflared" ]; type = enum [false true "cloudflared"];
default = false; default = false;
}; };
enabled = mkOption { enabled = mkOption {
@ -93,7 +107,7 @@ let
}; };
locations = mkOption { locations = mkOption {
type = attrsOf (submoduleWith { type = attrsOf (submoduleWith {
modules = [ locationModule ]; modules = [locationModule];
shorthandOnlyDefinesConfig = true; shorthandOnlyDefinesConfig = true;
}); });
}; };
@ -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;
}; };
@ -123,17 +146,18 @@ let
}; };
}; };
extraConfig = mkIf (cfg.enabled && config.xvars.enable) ( extraConfig = mkIf (cfg.enabled && config.xvars.enable) (
mkOrder (orderJustBefore + 25) (xHeadersProxied { inherit xvars; }) mkOrder (orderJustBefore + 25) (xHeadersProxied {inherit xvars;})
); );
}; };
}; };
in { in
{
config, config,
system, system,
gensokyo-zone, gensokyo-zone,
lib, lib,
... ...
}: let }: 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 mkOptionDefault; inherit (lib.modules) mkIf mkOptionDefault;
@ -141,7 +165,7 @@ in {
inherit (lib.lists) any; inherit (lib.lists) any;
inherit (config.services) nginx; inherit (config.services) nginx;
cfg = nginx.proxied; cfg = nginx.proxied;
in { in {
options.services.nginx = with lib.types; { options.services.nginx = with lib.types; {
proxied = { proxied = {
enable = mkEnableOption "proxy"; enable = mkEnableOption "proxy";
@ -190,7 +214,7 @@ in {
}; };
}; };
networking.firewall.interfaces.lan = mkIf nginx.enable { networking.firewall.interfaces.lan = mkIf nginx.enable {
allowedTCPPorts = mkIf cfg.enable [ cfg.listenPort ]; allowedTCPPorts = mkIf cfg.enable [cfg.listenPort];
}; };
}; };
} }

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,21 +39,38 @@ 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 {
imports = [ proxyModule ]; imports = [proxyModule];
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;
@ -57,7 +81,7 @@ let
inherit (nixosConfig.services) nginx; inherit (nixosConfig.services) nginx;
cfg = config.proxy; cfg = config.proxy;
in { in {
imports = [ proxyModule ]; imports = [proxyModule];
options = with lib.types; { options = with lib.types; {
proxy = { proxy = {
@ -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 = {
@ -94,7 +120,7 @@ let
}; };
headers = { headers = {
enableRecommended = mkOption { enableRecommended = mkOption {
type = enum [ true false "nixpkgs" ]; type = enum [true false "nixpkgs"];
}; };
rewriteReferer.enable = mkEnableOption "rewrite referer host"; rewriteReferer.enable = mkEnableOption "rewrite referer host";
set = mkOption { set = mkOption {
@ -102,7 +128,7 @@ let
}; };
hide = mkOption { hide = mkOption {
type = attrsOf bool; type = attrsOf bool;
default = { }; default = {};
}; };
}; };
redirect = { redirect = {
@ -121,7 +147,7 @@ let
}; };
}; };
config = let config = let
emitHeaders = setHeaders' != { }; emitHeaders = setHeaders' != {};
url = parseUrl config.proxyPass; url = parseUrl config.proxyPass;
upstream = nginx.upstreams'.${cfg.upstream}; upstream = nginx.upstreams'.${cfg.upstream};
upstreamServer = upstream.servers.${upstream.defaultServerName}; upstreamServer = upstream.servers.${upstream.defaultServerName};
@ -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,12 +166,15 @@ 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}"); }
upstreamHost = coalesce ([ upstream.host ] ++ optional hasUpstreamServer upstreamServer.addr); .${cfg.parsed.scheme}
port = coalesce [ cfg.parsed.port schemePort ]; or (throw "unsupported proxy_scheme ${toString cfg.parsed.scheme}");
upstreamHost = coalesce ([upstream.host] ++ optional hasUpstreamServer upstreamServer.addr);
port = coalesce [cfg.parsed.port schemePort];
hostport = cfg.parsed.host + optionalString (port != schemePort) ":${toString port}"; hostport = cfg.parsed.host + optionalString (port != schemePort) ":${toString port}";
initProxyVars = let initProxyVars = let
initScheme = xvars.init "proxy_scheme" config.xvars.defaults.proxy_scheme; initScheme = xvars.init "proxy_scheme" config.xvars.defaults.proxy_scheme;
@ -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,12 +247,16 @@ 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 {})
(mkIf (cfg.headers.enableRecommended == true) (mapOptionDefaults recommendedHeaders)) (mkIf (cfg.headers.enableRecommended == true) (mapOptionDefaults recommendedHeaders))
(mkIf (cfg.host != null) { (mkIf (cfg.host != null) {
Host = mkIf (cfg.headers.enableRecommended != "nixpkgs") (mkAlmostOptionDefault cfg.host); Host = mkIf (cfg.headers.enableRecommended != "nixpkgs") (mkAlmostOptionDefault cfg.host);
@ -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;
@ -288,13 +340,16 @@ 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 {
type = attrsOf (submoduleWith { type = attrsOf (submoduleWith {
modules = [ locationModule ]; modules = [locationModule];
shorthandOnlyDefinesConfig = true; shorthandOnlyDefinesConfig = true;
}); });
}; };
@ -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,12 +383,10 @@ 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; {
virtualHosts = mkOption { virtualHosts = mkOption {
type = attrsOf (submodule [hostModule]); type = attrsOf (submodule [hostModule]);
@ -343,4 +398,4 @@ in {
}); });
}; };
}; };
} }

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;
@ -12,7 +18,7 @@ let
}; };
force = mkOption { force = mkOption {
# TODO: "force-nonlocal"? exceptions for tailscale? # TODO: "force-nonlocal"? exceptions for tailscale?
type = enum [ false true "only" "reject" ]; type = enum [false true "only" "reject"];
default = false; default = false;
}; };
forced = mkOption { forced = mkOption {
@ -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,16 +110,24 @@ 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;
cfg = config.ssl; cfg = config.ssl;
in { in {
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,18 +147,20 @@ 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,
... ...
}: let }: 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 mkMerge mkDefault mkOptionDefault; inherit (lib.modules) mkIf mkMerge mkDefault mkOptionDefault;
@ -145,30 +168,42 @@ 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 {
imports = [ sslProxyModule ]; imports = [sslProxyModule];
options.ssl = { options.ssl = {
force = mkEnableOption "redirect to SSL"; force = mkEnableOption "redirect to SSL";
}; };
config = { config = {
proxy.ssl.enable = mkOptionDefault (hasPrefix "https://" config.proxyPass); proxy.ssl.enable = mkOptionDefault (hasPrefix "https://" config.proxyPass);
xvars.enable = mkIf emitForce true; xvars.enable = mkIf emitForce true;
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 {
imports = [ sslModule ]; imports = [sslModule];
options = with lib.types; { options = with lib.types; {
ssl = { ssl = {
cert = { cert = {
@ -177,7 +212,7 @@ in {
}; };
locations = mkOption { locations = mkOption {
type = attrsOf (submoduleWith { type = attrsOf (submoduleWith {
modules = [ locationModule ]; modules = [locationModule];
shorthandOnlyDefinesConfig = true; shorthandOnlyDefinesConfig = true;
}); });
}; };
@ -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,30 +236,35 @@ 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 {
options.services.nginx = with lib.types; { options.services.nginx = with lib.types; {
virtualHosts = mkOption { virtualHosts = mkOption {
type = attrsOf (submoduleWith { type = attrsOf (submoduleWith {
modules = [ hostModule ]; modules = [hostModule];
shorthandOnlyDefinesConfig = true; shorthandOnlyDefinesConfig = true;
}); });
}; };
stream.servers = mkOption { stream.servers = mkOption {
type = attrsOf (submoduleWith { type = attrsOf (submoduleWith {
modules = [ streamServerModule ]; modules = [streamServerModule];
shorthandOnlyDefinesConfig = false; shorthandOnlyDefinesConfig = false;
}); });
}; };
}; };
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:
wants = [ "acme-finished-${server.ssl.cert.name}.target" ]; mkIf (server.enable && server.ssl.enable && server.ssl.cert.name != null) {
after = [ "acme-selfsigned-${server.ssl.cert.name}.service" ]; wants = ["acme-finished-${server.ssl.cert.name}.target"];
before = [ "acme-${server.ssl.cert.name}.service" ]; after = ["acme-selfsigned-${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 {
@ -49,7 +51,7 @@ in {
nixosConfig = config; nixosConfig = config;
}; };
}); });
default = { }; default = {};
}; };
}; };
config.services.nginx = { config.services.nginx = {

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 {
@ -90,8 +108,8 @@ let
example = "unix:/tmp/backend3"; example = "unix:/tmp/backend3";
}; };
settings = mkOption { settings = mkOption {
type = attrsOf (oneOf [ int str bool ]); type = attrsOf (oneOf [int str bool]);
default = { }; default = {};
}; };
extraConfig = mkOption { extraConfig = mkOption {
type = str; type = str;
@ -108,21 +126,30 @@ 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}";
in { in {
server = mkOptionDefault "${mkAddress6 config.addr}${port}"; server = mkOptionDefault "${mkAddress6 config.addr}${port}";
serverConfig = mkMerge ( serverConfig = mkMerge (
[ (mkBefore config.server) ] [(mkBefore config.server)]
++ settings ++ settings
++ optional (config.extraConfig != "") config.extraConfig ++ optional (config.extraConfig != "") config.extraConfig
); );
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;
@ -132,19 +159,21 @@ let
in { in {
options = with lib.types; let options = with lib.types; let
upstreamServer = submoduleWith { upstreamServer = submoduleWith {
modules = [ upstreamServerModule upstreamServerAccessModule ]; modules = [upstreamServerModule upstreamServerAccessModule];
specialArgs = { specialArgs = {
inherit nixosConfig gensokyo-zone upstreamKind; inherit nixosConfig gensokyo-zone upstreamKind;
upstream = config; upstream = config;
}; };
}; };
in { in {
enable = mkEnableOption "upstream block" // { enable =
mkEnableOption "upstream block"
// {
default = true; default = true;
}; };
name = mkOption { name = mkOption {
type = str; type = str;
default = replaceStrings [ "'" ] [ "_" ] name; default = replaceStrings ["'"] ["_"] name;
}; };
servers = mkOption { servers = mkOption {
type = attrsOf upstreamServer; type = attrsOf upstreamServer;
@ -183,13 +212,13 @@ let
config = let config = let
enabledServers = filterAttrs (_: server: server.enable) config.servers; enabledServers = filterAttrs (_: server: server.enable) config.servers;
assertServers = v: assert enabledServers != { }; v; assertServers = v: assert enabledServers != {}; v;
in { in {
ssl.enable = mkIf (any (server: server.ssl.enable) (attrValues enabledServers)) (mkAlmostOptionDefault true); ssl.enable = mkIf (any (server: server.ssl.enable) (attrValues enabledServers)) (mkAlmostOptionDefault true);
defaultServerName = findSingle (_: true) null null (attrNames enabledServers); defaultServerName = findSingle (_: true) null null (attrNames enabledServers);
upstreamConfig = mkMerge ( upstreamConfig = mkMerge (
mapAttrsToList (_: server: mkIf server.enable server.serverDirective) config.servers mapAttrsToList (_: server: mkIf server.enable server.serverDirective) config.servers
++ [ config.extraConfig ] ++ [config.extraConfig]
); );
upstreamBlock = mkOptionDefault '' upstreamBlock = mkOptionDefault ''
upstream ${config.name} { upstream ${config.name} {
@ -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,42 +300,63 @@ 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;
inherit (nixosConfig.services) nginx; inherit (nixosConfig.services) nginx;
in { in {
imports = [ proxyUpstreamModule ]; imports = [proxyUpstreamModule];
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 {
imports = [ proxyUpstreamModule ]; imports = [proxyUpstreamModule];
options = with lib.types; { options = with lib.types; {
locations = mkOption { locations = mkOption {
@ -302,18 +370,19 @@ let
}; };
}; };
}; };
in { in
{
config, config,
lib, lib,
gensokyo-zone, gensokyo-zone,
... ...
}: let }: let
inherit (gensokyo-zone.lib) unmerged; inherit (gensokyo-zone.lib) unmerged;
inherit (lib.options) mkOption; inherit (lib.options) mkOption;
inherit (lib.modules) mkIf mkMerge; inherit (lib.modules) mkIf mkMerge;
inherit (lib.attrsets) mapAttrsToList; inherit (lib.attrsets) mapAttrsToList;
cfg = config.services.nginx; cfg = config.services.nginx;
in { in {
options.services.nginx = with lib.types; { options.services.nginx = with lib.types; {
upstreams' = mkOption { upstreams' = mkOption {
type = attrsOf (submoduleWith { type = attrsOf (submoduleWith {
@ -325,7 +394,7 @@ in {
upstreamKind = "virtualHost"; upstreamKind = "virtualHost";
}; };
}); });
default = { }; default = {};
}; };
virtualHosts = mkOption { virtualHosts = mkOption {
type = attrsOf (submodule hostModule); type = attrsOf (submodule hostModule);
@ -341,7 +410,7 @@ in {
upstreamKind = "stream"; upstreamKind = "stream";
}; };
}); });
default = { }; default = {};
}; };
servers = mkOption { servers = mkOption {
type = attrsOf (submoduleWith { type = attrsOf (submoduleWith {
@ -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,9 +53,13 @@
]; ];
}; };
}; };
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}";
in { in {
options = with lib.types; { options = with lib.types; {
@ -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;
}; };
}; };
@ -271,7 +307,7 @@ in {
enable = vouch.enable; enable = vouch.enable;
servers = { servers = {
local = localVouch; local = localVouch;
service = { upstream, ... }: { service = {upstream, ...}: {
enable = mkIf upstream.servers.local.enable false; enable = mkIf upstream.servers.local.enable false;
accessService = { accessService = {
name = "vouch-proxy"; name = "vouch-proxy";
@ -283,10 +319,12 @@ 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, ...}: {
enable = mkIf upstream.servers.local.enable false; enable = mkIf upstream.servers.local.enable false;
accessService = { accessService = {
name = "vouch-proxy"; name = "vouch-proxy";
@ -299,18 +337,18 @@ in {
enable = vouch.enable && vouch.doubleProxy.enable; enable = vouch.enable && vouch.doubleProxy.enable;
# TODO: need exported hosts options for this to detect the correct host/port/etc # TODO: need exported hosts options for this to detect the correct host/port/etc
servers = { servers = {
lan = { upstream, ... }: { lan = {upstream, ...}: {
enable = mkAlmostOptionDefault (!upstream.servers.int.enable); enable = mkAlmostOptionDefault (!upstream.servers.int.enable);
addr = mkAlmostOptionDefault "login.local.${networking.domain}"; addr = mkAlmostOptionDefault "login.local.${networking.domain}";
port = mkOptionDefault 9080; port = mkOptionDefault 9080;
ssl.enable = mkAlmostOptionDefault true; ssl.enable = mkAlmostOptionDefault true;
}; };
int = { upstream, ... }: { int = {upstream, ...}: {
enable = mkAlmostOptionDefault system.network.networks.int.enable or false; enable = mkAlmostOptionDefault system.network.networks.int.enable or false;
addr = mkAlmostOptionDefault "login.int.${networking.domain}"; addr = mkAlmostOptionDefault "login.int.${networking.domain}";
port = mkOptionDefault 9080; port = mkOptionDefault 9080;
}; };
tail = { upstream, ... }: { tail = {upstream, ...}: {
enable = mkAlmostOptionDefault (tailscale.enable && !upstream.servers.lan.enable && !upstream.servers.int.enable); enable = mkAlmostOptionDefault (tailscale.enable && !upstream.servers.lan.enable && !upstream.servers.int.enable);
addr = mkAlmostOptionDefault "login.tail.${networking.domain}"; addr = mkAlmostOptionDefault "login.tail.${networking.domain}";
port = mkOptionDefault 9080; port = mkOptionDefault 9080;

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;
@ -8,7 +13,7 @@ let
enable = mkEnableOption "$x_variables"; enable = mkEnableOption "$x_variables";
defaults = mkOption { defaults = mkOption {
type = attrsOf (nullOr str); type = attrsOf (nullOr str);
default = { }; default = {};
}; };
lib = mkOption { lib = mkOption {
type = attrs; type = attrs;
@ -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 {
@ -66,7 +89,7 @@ let
}; };
locations = mkOption { locations = mkOption {
type = attrsOf (submoduleWith { type = attrsOf (submoduleWith {
modules = [ locationModule ]; modules = [locationModule];
shorthandOnlyDefinesConfig = true; shorthandOnlyDefinesConfig = true;
specialArgs = { specialArgs = {
inherit nixosConfig gensokyo-zone; inherit nixosConfig gensokyo-zone;
@ -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,18 +138,19 @@ let
_module.args.xvars = config.xvars.lib; _module.args.xvars = config.xvars.lib;
}; };
}; };
in { in
{
config, config,
lib, lib,
gensokyo-zone, gensokyo-zone,
... ...
}: let }: let
inherit (lib.options) mkOption; inherit (lib.options) mkOption;
in { in {
options = with lib.types; { options = with lib.types; {
services.nginx.virtualHosts = mkOption { services.nginx.virtualHosts = mkOption {
type = attrsOf (submoduleWith { type = attrsOf (submoduleWith {
modules = [ hostModule ]; modules = [hostModule];
shorthandOnlyDefinesConfig = true; shorthandOnlyDefinesConfig = true;
specialArgs = { specialArgs = {
inherit gensokyo-zone; inherit gensokyo-zone;
@ -131,4 +159,4 @@ in {
}); });
}; };
}; };
} }

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

@ -45,26 +45,30 @@ in {
}; };
netbiosHostAddresses = mkOption { netbiosHostAddresses = mkOption {
type = attrsOf (listOf str); type = attrsOf (listOf str);
default = { }; default = {};
}; };
lmhosts = mkOption { lmhosts = mkOption {
type = attrsOf str; type = attrsOf str;
default = { }; default = {};
}; };
}; };
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 {
type = enum [ "ldapsam" "ipasam" ]; type = enum ["ldapsam" "ipasam"];
default = "ldapsam"; default = "ldapsam";
}; };
}; };
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 (
@ -254,7 +273,7 @@ in {
{ {
"use sendfile" = mkOptionDefault true; "use sendfile" = mkOptionDefault true;
"mdns name" = mkOptionDefault "mdns"; "mdns name" = mkOptionDefault "mdns";
"name resolve order" = mkOptionDefault [ "lmhosts" "host" "bcast" ]; "name resolve order" = mkOptionDefault ["lmhosts" "host" "bcast"];
workgroup = mkIf (cfg.domain.name != null) (mkOptionDefault cfg.domain.name); workgroup = mkIf (cfg.domain.name != null) (mkOptionDefault cfg.domain.name);
"netbios name" = mkIf (cfg.domain.netbiosName != null) (mkOptionDefault cfg.domain.netbiosName); "netbios name" = mkIf (cfg.domain.netbiosName != null) (mkOptionDefault cfg.domain.netbiosName);
} }
@ -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";
@ -296,13 +317,14 @@ in {
"usershare owner only" = mkOptionDefault true; "usershare owner only" = mkOptionDefault true;
"usershare template share" = mkOptionDefault cfg.usershare.templateShare; "usershare template share" = mkOptionDefault cfg.usershare.templateShare;
"usershare path" = mkOptionDefault cfg.usershare.path; "usershare path" = mkOptionDefault cfg.usershare.path;
"usershare prefix allow list" = mkOptionDefault [ cfg.usershare.path ]; "usershare prefix allow list" = mkOptionDefault [cfg.usershare.path];
}) })
(mkIf cfg.guest.enable { (mkIf cfg.guest.enable {
"map to guest" = mkOptionDefault "Bad User"; "map to guest" = mkOptionDefault "Bad User";
"guest account" = mkOptionDefault cfg.guest.user; "guest account" = mkOptionDefault cfg.guest.user;
}) })
] ++ mapAttrsToList (_: idmap: mapAttrs' (key: value: nameValuePair "idmap config ${idmap.domain} : ${key}" (mkOptionDefault value)) idmap.settings) cfg.idmap.domains); ]
++ mapAttrsToList (_: idmap: mapAttrs' (key: value: nameValuePair "idmap config ${idmap.domain} : ${key}" (mkOptionDefault value)) idmap.settings) cfg.idmap.domains);
extraConfig = mkMerge ( extraConfig = mkMerge (
mapAttrsToList (key: value: ''${key} = ${settingValue value}'') cfg.settings mapAttrsToList (key: value: ''${key} = ${settingValue value}'') cfg.settings
++ [ ++ [
@ -340,11 +362,11 @@ in {
]; ];
networking.hosts = mkIf (cfg.enable && cfg.domain.netbiosName != null) { networking.hosts = mkIf (cfg.enable && cfg.domain.netbiosName != null) {
"::1" = mkAfter [ cfg.domain.netbiosName' ]; "::1" = mkAfter [cfg.domain.netbiosName'];
# not a typo... # not a typo...
"127.0.0.2" = mkAfter [ cfg.domain.netbiosName' ]; "127.0.0.2" = mkAfter [cfg.domain.netbiosName'];
}; };
environment.etc."samba/lmhosts" = mkIf (cfg.enable && cfg.domain.lmhosts != { }) { environment.etc."samba/lmhosts" = mkIf (cfg.enable && cfg.domain.lmhosts != {}) {
text = mkMerge ( text = mkMerge (
mapAttrsToList (address: name: "${address} ${name}") cfg.domain.lmhosts mapAttrsToList (address: name: "${address} ${name}") cfg.domain.lmhosts
); );

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' = {
rootDirModule = { ... }: { rootDir,
specialArgs,
modules ? [],
}: let
rootDirModule = {...}: {
config.rootDir = mkOptionDefault rootDir; config.rootDir = mkOptionDefault rootDir;
}; };
in lib.types.submoduleWith { in
modules = [ mountModule rootDirModule ] ++ modules; lib.types.submoduleWith {
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 = {
@ -56,28 +80,34 @@
inherit nixosConfig; inherit nixosConfig;
}; };
mountUnits = mkMerge [ mountUnits = mkMerge [
(mkIf (cfg.sharedMounts != { }) (mapSharedMounts mkRequire)) (mkIf (cfg.sharedMounts != {}) (mapSharedMounts mkRequire))
(mkIf (cfg.cacheMounts != { }) (mapCacheMounts mkRequire)) (mkIf (cfg.cacheMounts != {}) (mapCacheMounts mkRequire))
]; ];
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 {
default = { }; rootDir = "/mnt/shared";
inherit specialArgs;
});
default = {};
}; };
cacheMounts = mkOption { cacheMounts = mkOption {
type = attrsOf (mkMountType { rootDir = "/mnt/caches"; inherit specialArgs; }); type = attrsOf (mkMountType {
default = { }; rootDir = "/mnt/caches";
inherit specialArgs;
});
default = {};
}; };
}; };
config = { config = {
requires = mountUnits; requires = mountUnits;
after = mountUnits; after = mountUnits;
serviceConfig = mkMerge [ serviceConfig = mkMerge [
(mkIf (cfg.sharedMounts != { }) { (mkIf (cfg.sharedMounts != {}) {
BindPaths = mapSharedMounts mkBindPath; BindPaths = mapSharedMounts mkBindPath;
}) })
(mkIf (cfg.cacheMounts != { }) { (mkIf (cfg.cacheMounts != {}) {
BindPaths = mapCacheMounts mkBindPath; BindPaths = mapCacheMounts mkBindPath;
}) })
]; ];
@ -87,7 +117,7 @@ in {
options = with lib.types; { options = with lib.types; {
systemd.services = mkOption { systemd.services = mkOption {
type = attrsOf (submoduleWith { type = attrsOf (submoduleWith {
modules = [ serviceModule ]; modules = [serviceModule];
shorthandOnlyDefinesConfig = true; shorthandOnlyDefinesConfig = true;
specialArgs = { specialArgs = {
nixosConfig = config; nixosConfig = config;

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;
@ -6,7 +12,7 @@
inherit (config.services) sssd; inherit (config.services) sssd;
genso = krb5.gensokyo-zone; genso = krb5.gensokyo-zone;
cfg = sssd.gensokyo-zone; cfg = sssd.gensokyo-zone;
serverModule = { config, ... }: { serverModule = {config, ...}: {
options = with lib.types; { options = with lib.types; {
servers = mkOption { servers = mkOption {
type = nullOr (listOf str); type = nullOr (listOf str);
@ -14,14 +20,14 @@
}; };
backups = mkOption { backups = mkOption {
type = listOf str; type = listOf str;
default = [ ]; default = [];
}; };
serverName = mkOption { serverName = mkOption {
type = str; type = str;
internal = true; internal = true;
}; };
serverKind = mkOption { serverKind = mkOption {
type = enum [ "server" "uri" ]; type = enum ["server" "uri"];
default = "server"; default = "server";
internal = true; internal = true;
}; };
@ -35,33 +41,40 @@
in { in {
settings = { settings = {
${key} = mkIf (config.servers != null) (mkOptionDefault config.servers); ${key} = mkIf (config.servers != null) (mkOptionDefault config.servers);
${keyBackups} = mkIf (config.backups != [ ]) (mkOptionDefault config.backups); ${keyBackups} = mkIf (config.backups != []) (mkOptionDefault config.backups);
}; };
}; };
}; };
mkServerType = { modules }: lib.types.submoduleWith { mkServerType = {modules}:
modules = [ serverModule ] ++ modules; lib.types.submoduleWith {
modules = [serverModule] ++ modules;
specialArgs = { specialArgs = {
inherit gensokyo-zone pkgs; inherit gensokyo-zone pkgs;
nixosConfig = config; nixosConfig = config;
}; };
}; };
mkServerOption = { name, kind ? "server" }: let mkServerOption = {
serverInfoModule = { ... }: { name,
kind ? "server",
}: let
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];
}; };
default = { }; default = {};
}; };
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;
}; };
@ -88,7 +106,7 @@ in {
}; };
}; };
backend = mkOption { backend = mkOption {
type = enum [ "ldap" "ipa" ]; type = enum ["ldap" "ipa"];
default = "ipa"; default = "ipa";
}; };
}; };
@ -97,13 +115,15 @@ 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 { }
ldap_access_order = [ "host" ]; // mapOptionDefaults {
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;
ldap_search_base = genso.ldap.baseDn; ldap_search_base = genso.ldap.baseDn;
@ -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;
@ -138,12 +160,12 @@ in {
in { in {
gensokyo-zone = { gensokyo-zone = {
krb5.servers.servers = mkMerge [ krb5.servers.servers = mkMerge [
[ genso.host ] [genso.host]
(mkAfter [ "_srv" genso.canonHost ]) (mkAfter ["_srv" genso.canonHost])
]; ];
ldap.uris = { ldap.uris = {
servers = mkMerge [ servers = mkMerge [
(mkAfter [ "_srv" ]) (mkAfter ["_srv"])
genso.ldap.urls genso.ldap.urls
]; ];
}; };
@ -191,4 +213,3 @@ in {
}; };
}; };
} }

View file

@ -9,8 +9,8 @@
inherit (lib.modules) mkIf; inherit (lib.modules) mkIf;
inherit (lib.attrsets) genAttrs; inherit (lib.attrsets) genAttrs;
cfg = config.services.sssd; cfg = config.services.sssd;
pamRulesModule = { ... }: let pamRulesModule = {...}: let
rules = [ "account" "auth" "password" "session" ]; rules = ["account" "auth" "password" "session"];
mkRuleConfig = ruleName: { mkRuleConfig = ruleName: {
sss = mkIf cfg.enable { sss = mkIf cfg.enable {
enable = mkIf (!cfg.services.pam.enable) (mkAlmostForce false); enable = mkIf (!cfg.services.pam.enable) (mkAlmostForce false);
@ -19,7 +19,7 @@
in { in {
config = genAttrs rules mkRuleConfig; config = genAttrs rules mkRuleConfig;
}; };
pamServiceModule = { ... }: { pamServiceModule = {...}: {
options = with lib.types; { options = with lib.types; {
rules = mkOption { rules = mkOption {
type = submodule pamRulesModule; type = submodule pamRulesModule;

View file

@ -15,20 +15,23 @@
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;
} " = "; } " = ";
}; };
primitiveType = with lib.types; oneOf [ str int bool ]; primitiveType = with lib.types; oneOf [str int bool];
valueType = with lib.types; oneOf [ primitiveType (listOf primitiveType) ]; valueType = with lib.types; oneOf [primitiveType (listOf primitiveType)];
settingsType = lib.types.attrsOf valueType; settingsType = lib.types.attrsOf valueType;
serviceModule = { name, ... }: { serviceModule = {name, ...}: {
options = with lib.types; { options = with lib.types; {
enable = mkEnableOption "${name} service"; enable = mkEnableOption "${name} service";
name = mkOption { name = mkOption {
@ -38,20 +41,22 @@
}; };
settings = mkOption { settings = mkOption {
type = settingsType; type = settingsType;
default = { }; default = {};
}; };
}; };
}; };
nssModule = { nixosConfig, ... }: { nssModule = {nixosConfig, ...}: {
options = { options = {
# TODO: passwd.enable = mkEnableOption "passwd" // { default = true; }; # TODO: passwd.enable = mkEnableOption "passwd" // { default = true; };
shadow.enable = mkEnableOption "shadow" // { default = nixosConfig.services.sssd.services.pam.enable; }; shadow.enable = mkEnableOption "shadow" // {default = nixosConfig.services.sssd.services.pam.enable;};
netgroup.enable = mkEnableOption "netgroup" // { default = true; }; netgroup.enable = mkEnableOption "netgroup" // {default = true;};
}; };
}; };
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 {
@ -63,17 +68,17 @@
}; };
}; };
}; };
domainLdapModule = { config, ... }: let domainLdapModule = {config, ...}: let
cfg = config.ldap; cfg = config.ldap;
in { in {
options.ldap = with lib.types; { options.ldap = with lib.types; {
extraAttrs.user = mkOption { extraAttrs.user = mkOption {
type = attrsOf str; type = attrsOf str;
default = { }; default = {};
}; };
authtok = { authtok = {
type = mkOption { type = mkOption {
type = enum [ "password" "obfuscated_password" ]; type = enum ["password" "obfuscated_password"];
default = "password"; default = "password";
}; };
password = mkOption { password = mkOption {
@ -87,7 +92,7 @@
passwordVar = mkOption { passwordVar = mkOption {
type = str; type = str;
internal = true; internal = true;
default = "SSSD_AUTHTOK_" + replaceStrings [ "-" "." ] [ "_" "_" ] (toUpper config.domain); default = "SSSD_AUTHTOK_" + replaceStrings ["-" "."] ["_" "_"] (toUpper config.domain);
}; };
}; };
}; };
@ -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 [
@ -119,7 +126,7 @@ in {
}; };
domains = mkOption { domains = mkOption {
type = attrsOf (submoduleWith { type = attrsOf (submoduleWith {
modules = [ domainModule domainLdapModule ]; modules = [domainModule domainLdapModule];
specialArgs = { specialArgs = {
nixosConfig = config; nixosConfig = config;
}; };
@ -135,9 +142,10 @@ 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 = {
inherit name; inherit name;
nixosConfig = config; nixosConfig = config;
@ -145,15 +153,16 @@ in {
}; };
}; };
services = { services = {
nss = { modules = [ nssModule ]; }; nss = {modules = [nssModule];};
pam = { }; pam = {};
ifp = { }; ifp = {};
sudo = { }; sudo = {};
autofs = { }; autofs = {};
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; })
settings = [ defaultSettings serviceSettings ] ++ domainSettings; enabledDomains;
in mkMerge settings; settings = [defaultSettings serviceSettings] ++ domainSettings;
in
mkMerge settings;
services = { services = {
nss.enable = mkAlmostOptionDefault true; nss.enable = mkAlmostOptionDefault true;
pam.enable = mkAlmostOptionDefault true; pam.enable = mkAlmostOptionDefault true;
@ -187,24 +199,30 @@ in {
extraUserAttrs = listToAttrs (concatMap (domain: map (flip nameValuePair {}) (attrNames domain.ldap.extraAttrs.user)) enabledDomains); extraUserAttrs = listToAttrs (concatMap (domain: map (flip nameValuePair {}) (attrNames domain.ldap.extraAttrs.user)) enabledDomains);
mkExtraAttr = name: _: "+${name}"; mkExtraAttr = name: _: "+${name}";
in { in {
user_attributes = mkIf (extraUserAttrs != { }) (mkOptionDefault ( user_attributes = mkIf (extraUserAttrs != {}) (mkOptionDefault (
mapAttrsToList mkExtraAttr extraUserAttrs mapAttrsToList mkExtraAttr extraUserAttrs
)); ));
}; };
sudo = { }; sudo = {};
autofs = { }; autofs = {};
ssh = { }; ssh = {};
pac = { }; pac = {};
}; };
configText = mkOptionDefault (toINI cfg.settings); configText = mkOptionDefault (toINI cfg.settings);
config = mkIf (cfg.configText != null) (mkAlmostOptionDefault cfg.configText); config = mkIf (cfg.configText != null) (mkAlmostOptionDefault cfg.configText);
}; };
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;
@ -67,7 +71,7 @@ in {
}; };
machines = mkOption { machines = mkOption {
type = attrsOf (submodule machineModule); type = attrsOf (submodule machineModule);
default = { }; default = {};
}; };
}; };
@ -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,14 +47,18 @@
); );
}; };
}; };
fileModule = { config, name, ... }: { fileModule = {
config,
name,
...
}: {
options = with lib.types; { options = with lib.types; {
relativePath = mkOption { relativePath = mkOption {
type = str; type = str;
default = name; default = name;
}; };
type = mkOption { type = mkOption {
type = enum [ "file" "directory" ]; type = enum ["file" "directory"];
default = "file"; default = "file";
}; };
versioned = mkOption { versioned = mkOption {
@ -55,13 +66,16 @@
default = false; default = false;
}; };
target = mkOption { target = mkOption {
type = enum [ "user" "shared" "game" ]; type = enum ["user" "shared" "game"];
default = "user"; default = "user";
}; };
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;
@ -75,7 +89,7 @@
type = functionTo path; type = functionTo path;
}; };
srcStyle = mkOption { srcStyle = mkOption {
type = enum [ "empty" "copy" "symlink" "symlink-shallow" ]; type = enum ["empty" "copy" "symlink" "symlink-shallow"];
default = "symlink"; default = "symlink";
}; };
workingPathFor = mkOption { workingPathFor = mkOption {
@ -88,7 +102,7 @@
type = functionTo (nullOr path); type = functionTo (nullOr path);
}; };
initStyle = mkOption { initStyle = mkOption {
type = enum [ "none" "copy" "symlink" "symlink-shallow" ]; type = enum ["none" "copy" "symlink" "symlink-shallow"];
default = "copy"; default = "copy";
}; };
setup = { setup = {
@ -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 (
cfg.workingDirFor { inherit user version; } {
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;
@ -294,7 +380,7 @@
}; };
emptyFile = pkgs.writeText "empty.txt" ""; emptyFile = pkgs.writeText "empty.txt" "";
emptyJson = pkgs.writeText "empty.json" "{}"; emptyJson = pkgs.writeText "empty.json" "{}";
emptyDir = pkgs.runCommand "empty" { } '' emptyDir = pkgs.runCommand "empty" {} ''
mkdir $out mkdir $out
''; '';
emptyExecutable = pkgs.writeTextFile { emptyExecutable = pkgs.writeTextFile {
@ -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,17 +507,23 @@
setx GENSO_STEAM_BS_VERSION Vanilla setx GENSO_STEAM_BS_VERSION Vanilla
''; '';
mksetupbeatsaber = { user, version }: let mksetupbeatsaber = {
setupFiles = mapAttrsToList (_: file: file.setup.script { inherit user version; }) cfg.files; user,
in pkgs.writeShellScript "setupbeatsaber-${user}-${version}" '' version,
}: let
setupFiles = mapAttrsToList (_: file: file.setup.script {inherit user version;}) cfg.files;
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}
''; '';
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 {
@ -438,7 +535,7 @@ in {
}; };
versions = mkOption { versions = mkOption {
type = attrsOf (submodule versionModule); type = attrsOf (submodule versionModule);
default = { }; default = {};
}; };
setupServiceNames = mkOption { setupServiceNames = mkOption {
type = listOf str; type = listOf str;
@ -446,7 +543,7 @@ in {
}; };
files = mkOption { files = mkOption {
type = attrsOf (submodule fileModule); type = attrsOf (submodule fileModule);
default = { }; default = {};
}; };
users = mkOption { users = mkOption {
type = attrsOf (submodule userModule); type = attrsOf (submodule userModule);
@ -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}";
}; };
}; };
@ -498,9 +599,9 @@ in {
bsUsers = filterAttrs (_: userIs cfg.group) config.users.users; bsUsers = filterAttrs (_: userIs cfg.group) config.users.users;
allVersions = mapAttrsToList (_: version: version.version) cfg.versions; allVersions = mapAttrsToList (_: version: version.version) cfg.versions;
gameFiles = { gameFiles = {
"Beat Saber.exe" = { }; "Beat Saber.exe" = {};
"UnityCrashHandler64.exe" = { }; "UnityCrashHandler64.exe" = {};
"UnityPlayer.dll" = { }; "UnityPlayer.dll" = {};
"MonoBleedingEdge".type = "directory"; "MonoBleedingEdge".type = "directory";
}; };
sharedFiles = { sharedFiles = {
@ -526,7 +627,7 @@ in {
}; };
"BeatSaberVersion.txt" = { "BeatSaberVersion.txt" = {
versioned = true; versioned = true;
initFor = { version, ... }: pkgs.writeText "BeatSaberVersion-${version}.txt" version; initFor = {version, ...}: pkgs.writeText "BeatSaberVersion-${version}.txt" version;
}; };
"IPA.exe".versioned = true; "IPA.exe".versioned = true;
"IPA.exe.config".versioned = true; "IPA.exe.config".versioned = true;
@ -538,19 +639,19 @@ in {
#initStyle = "symlink-shallow"; #initStyle = "symlink-shallow";
#initFor = { version, ... }: cfg.gameDirFor version + "/${bsdata}"; #initFor = { version, ... }: cfg.gameDirFor version + "/${bsdata}";
initStyle = "none"; initStyle = "none";
srcPathFor = { version, ... }: cfg.gameDirFor version + "/${bsdata}"; srcPathFor = {version, ...}: cfg.gameDirFor version + "/${bsdata}";
srcStyle = "symlink-shallow"; srcStyle = "symlink-shallow";
}; };
"${bsdata}/Managed" = { "${bsdata}/Managed" = {
type = "directory"; type = "directory";
versioned = true; versioned = true;
initFor = { version, ... }: cfg.gameDirFor version + "/${bsdata}/Managed"; initFor = {version, ...}: cfg.gameDirFor version + "/${bsdata}/Managed";
}; };
# TODO: remove this to use multiple folders # TODO: remove this to use multiple folders
"${bsdata}/CustomLevels" = { "${bsdata}/CustomLevels" = {
type = "directory"; type = "directory";
initStyle = "none"; initStyle = "none";
srcPathFor = { ... }: cfg.sharedDataDir + "/CustomLevels"; srcPathFor = {...}: cfg.sharedDataDir + "/CustomLevels";
}; };
CustomAvatars = { CustomAvatars = {
type = "directory"; type = "directory";
@ -579,7 +680,7 @@ in {
"UserData/ScoreSaber/Replays" = { "UserData/ScoreSaber/Replays" = {
type = "directory"; type = "directory";
initStyle = "none"; initStyle = "none";
srcPathFor = { ... }: cfg.sharedDataDir + "/Replays"; srcPathFor = {...}: cfg.sharedDataDir + "/Replays";
}; };
"UserData/Beat Saber IPA.json".versioned = true; "UserData/Beat Saber IPA.json".versioned = true;
"UserData/SongCore/" = { "UserData/SongCore/" = {
@ -619,8 +720,8 @@ in {
}; };
"UserData/Saber Factory/Cache".type = "directory"; "UserData/Saber Factory/Cache".type = "directory";
"UserData/Saber Factory/Textures".type = "directory"; "UserData/Saber Factory/Textures".type = "directory";
"UserData/BeatSaverDownloader.ini" = { }; "UserData/BeatSaverDownloader.ini" = {};
"UserData/BeatSaverUpdater.json" = { }; "UserData/BeatSaverUpdater.json" = {};
"UserData/SongDetailsCache.proto".versioned = true; "UserData/SongDetailsCache.proto".versioned = true;
"UserData/SongDetailsCache.proto.Direct.etag".versioned = true; "UserData/SongDetailsCache.proto.Direct.etag".versioned = true;
}; };
@ -636,7 +737,7 @@ in {
srcStyle = "empty"; srcStyle = "empty";
}; };
"UserData/Saber Factory/Presets".type = "directory"; "UserData/Saber Factory/Presets".type = "directory";
"UserData/Saber Factory/TrailConfig.json" = { }; "UserData/Saber Factory/TrailConfig.json" = {};
"UserData/SongCore" = { "UserData/SongCore" = {
type = "directory"; type = "directory";
versioned = true; versioned = true;
@ -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,20 +809,25 @@ 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 {
defaultVersion = mkIf (allVersions != [ ]) (mkOptionDefault ( defaultVersion = mkIf (allVersions != []) (mkOptionDefault (
head allVersions head allVersions
)); ));
users = mapAttrs (_: user: { name = mkDefault user.name; }) bsUsers; users = mapAttrs (_: user: {name = mkDefault user.name;}) bsUsers;
setupServiceNames = mkOptionDefault ( setupServiceNames = mkOptionDefault (
mapAttrsToList (_: user: "steam-setup-beatsaber-${user.name}.service") cfg.users mapAttrsToList (_: user: "steam-setup-beatsaber-${user.name}.service") cfg.users
); );
@ -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,32 +891,50 @@ 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;
"${cfg.binDir}/${replaceStrings [ "." ] [ "_" ] version.version}.bat" versionBinFiles =
mapAttrs' (
_: version:
nameValuePair
"${cfg.binDir}/${replaceStrings ["."] ["_"] version.version}.bat"
{ {
inherit (bin) owner group mode type; inherit (bin) owner group mode type;
src = pkgs.writeTextFile { src = pkgs.writeTextFile {
@ -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,8 +1,12 @@
{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 {
config.exports.services.dnsmasq = { config, ... }: { config.exports.services.dnsmasq = {config, ...}: {
id = mkAlmostOptionDefault "dns"; id = mkAlmostOptionDefault "dns";
nixos = { nixos = {
serviceAttr = "dnsmasq"; serviceAttr = "dnsmasq";

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,14 +1,19 @@
{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;
inherit (lib.lists) all imap0; inherit (lib.lists) all imap0;
inherit (lib.trivial) id; inherit (lib.trivial) id;
in { 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,8 +1,12 @@
{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 {
config.exports.services.invidious = { config, ... }: { config.exports.services.invidious = {config, ...}: {
id = mkAlmostOptionDefault "yt"; id = mkAlmostOptionDefault "yt";
nixos = { nixos = {
serviceAttr = "invidious"; serviceAttr = "invidious";

View file

@ -1,8 +1,12 @@
{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 {
config.exports.services.kerberos = { config, ... }: { config.exports.services.kerberos = {config, ...}: {
id = "krb5"; id = "krb5";
ports = mapAttrs (_: mapAlmostOptionDefaults) { ports = mapAttrs (_: mapAlmostOptionDefaults) {
default = { default = {

View file

@ -1,17 +1,23 @@
{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;
in { in {
config.exports.services.keycloak = { config, ... }: { config.exports.services.keycloak = {config, ...}: {
id = mkAlmostOptionDefault "sso"; id = mkAlmostOptionDefault "sso";
nixos = { nixos = {
serviceAttr = "keycloak"; serviceAttr = "keycloak";
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,8 +1,12 @@
{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 {
config.exports.services.ldap = { config, ... }: { config.exports.services.ldap = {config, ...}: {
defaults.port.listen = mkAlmostOptionDefault "lan"; defaults.port.listen = mkAlmostOptionDefault "lan";
ports = mapAttrs (_: mapAlmostOptionDefaults) { ports = mapAttrs (_: mapAlmostOptionDefaults) {
default = { default = {

View file

@ -1,12 +1,17 @@
{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;
in { 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,11 +1,15 @@
{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;
inherit (lib.lists) all imap0; inherit (lib.lists) all imap0;
inherit (lib.trivial) id; inherit (lib.trivial) id;
in { in {
config.exports.services.mosquitto = { config, ... }: { config.exports.services.mosquitto = {config, ...}: {
id = mkAlmostOptionDefault "mqtt"; id = mkAlmostOptionDefault "mqtt";
nixos = { nixos = {
serviceAttr = "mosquitto"; serviceAttr = "mosquitto";
@ -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,8 +1,12 @@
{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 {
config.exports.services.motion = { config, ... }: { config.exports.services.motion = {config, ...}: {
defaults.port.listen = mkAlmostOptionDefault "lan"; defaults.port.listen = mkAlmostOptionDefault "lan";
ports = mapAttrs (_: mapAlmostOptionDefaults) { ports = mapAttrs (_: mapAlmostOptionDefaults) {
default = { default = {

View file

@ -1,24 +1,34 @@
{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;
in { 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"];
assertions = mkIf config.enable [ assertions = mkIf config.enable [
(mkAssertionPort "statd") (mkAssertionPort "statd")
(mkAssertionPort "lockd") (mkAssertionPort "lockd")

View file

@ -1,12 +1,17 @@
{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;
in { 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,17 +1,23 @@
{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;
in { in {
config.exports.services.openwebrx = { config, ... }: { config.exports.services.openwebrx = {config, ...}: {
id = mkAlmostOptionDefault "webrx"; id = mkAlmostOptionDefault "webrx";
nixos = { nixos = {
serviceAttr = "openwebrx"; serviceAttr = "openwebrx";
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,7 +1,11 @@
{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, ...}: {
id = mkAlmostOptionDefault "prox"; id = mkAlmostOptionDefault "prox";
defaults.port.listen = mkAlmostOptionDefault "lan"; defaults.port.listen = mkAlmostOptionDefault "lan";
ports.default = mapAlmostOptionDefaults { ports.default = mapAlmostOptionDefaults {

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"
@ -86,7 +90,7 @@
}; };
assertions = mkOption { assertions = mkOption {
type = listOf (functionTo attrs); type = listOf (functionTo attrs);
default = [ ]; default = [];
}; };
}; };
defaults = { defaults = {
@ -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,13 +1,18 @@
{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;
inherit (lib.lists) sort; inherit (lib.lists) sort;
in { 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,8 +1,12 @@
{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 {
config.exports.services.unifi = { config, ... }: { config.exports.services.unifi = {config, ...}: {
nixos.serviceAttr = "unifi"; nixos.serviceAttr = "unifi";
defaults.port.listen = mkAlmostOptionDefault "lan"; defaults.port.listen = mkAlmostOptionDefault "lan";
ports = mapAttrs (_: mapAlmostOptionDefaults) { ports = mapAttrs (_: mapAlmostOptionDefaults) {

View file

@ -1,8 +1,12 @@
{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 {
config.exports.services.vouch-proxy = { config, ... }: { config.exports.services.vouch-proxy = {config, ...}: {
id = mkAlmostOptionDefault "login"; id = mkAlmostOptionDefault "login";
defaults.port.listen = mkAlmostOptionDefault "localhost"; defaults.port.listen = mkAlmostOptionDefault "localhost";
nixos = { nixos = {

View file

@ -1,8 +1,12 @@
{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 {
config.exports.services.zigbee2mqtt = { config, ... }: { config.exports.services.zigbee2mqtt = {config, ...}: {
id = mkAlmostOptionDefault "z2m"; id = mkAlmostOptionDefault "z2m";
nixos = { nixos = {
serviceAttr = "zigbee2mqtt"; serviceAttr = "zigbee2mqtt";

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,25 +43,33 @@ 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; {
files = mkOption { files = mkOption {
type = attrsOf (submoduleWith { type = attrsOf (submoduleWith {
modules = [ fileModule ]; modules = [fileModule];
specialArgs = { specialArgs = {
inherit gensokyo-zone; inherit gensokyo-zone;
system = config; system = config;
}; };
}); });
default = { }; default = {};
}; };
}; };
} }

View file

@ -41,7 +41,7 @@ in {
}; };
modules = mkOption { modules = mkOption {
type = listOf unspecified; type = listOf unspecified;
default = [ ]; default = [];
}; };
specialArgs = mkOption { specialArgs = mkOption {
type = attrs; type = attrs;
@ -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 = {
@ -65,12 +77,12 @@ in {
options.network = with lib.types; { options.network = with lib.types; {
networks = mkOption { networks = mkOption {
type = attrsOf (submoduleWith { type = attrsOf (submoduleWith {
modules = [ networkModule ]; modules = [networkModule];
specialArgs = { specialArgs = {
system = config; system = config;
}; };
}); });
default = { }; default = {};
}; };
}; };
} }

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 {
@ -30,7 +43,7 @@
default = null; default = null;
}; };
address4 = mkOption { address4 = mkOption {
type = nullOr (either (enum [ "dhcp" ]) str); type = nullOr (either (enum ["dhcp"]) str);
default = null; default = null;
}; };
gateway4 = mkOption { gateway4 = mkOption {
@ -38,7 +51,7 @@
default = null; default = null;
}; };
address6 = mkOption { address6 = mkOption {
type = nullOr (either (enum [ "auto" "dhcp" ]) str); type = nullOr (either (enum ["auto" "dhcp"]) str);
default = null; default = null;
}; };
gateway6 = mkOption { gateway6 = mkOption {
@ -47,11 +60,13 @@
}; };
firewall.enable = mkEnableOption "firewall"; firewall.enable = mkEnableOption "firewall";
vm.model = mkOption { vm.model = mkOption {
type = enum [ "virtio" "e1000" "rtl8139" "vmxnet3" ]; type = enum ["virtio" "e1000" "rtl8139" "vmxnet3"];
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 {
@ -90,14 +107,20 @@
}; };
}; };
config = let config = let
hasAddr4 = ! elem config.address4 [ null "dhcp" ]; hasAddr4 = ! elem config.address4 [null "dhcp"];
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
); );
}; };
@ -123,7 +146,7 @@
Type = mkOptionDefault "ether"; Type = mkOptionDefault "ether";
}; };
linkConfig = mkMerge [ linkConfig = mkMerge [
(mkIf config.mdns.enable { Multicast = mkOptionDefault true; }) (mkIf config.mdns.enable {Multicast = mkOptionDefault true;})
]; ];
networkConfig = mkMerge [ networkConfig = mkMerge [
(mkIf (config.address6 == "auto") { (mkIf (config.address6 == "auto") {
@ -134,17 +157,20 @@
}) })
]; ];
address = mkMerge [ address = mkMerge [
(mkIf (! elem config.address4 [ null "dhcp" ]) [ config.address4 ]) (mkIf (! elem config.address4 [null "dhcp"]) [config.address4])
(mkIf (! elem config.address6 [ null "auto" "dhcp" ]) [ config.address6 ]) (mkIf (! elem config.address6 [null "auto" "dhcp"]) [config.address6])
]; ];
gateway = mkMerge [ gateway = mkMerge [
(mkIf (config.gateway4 != null) [ config.gateway4 ]) (mkIf (config.gateway4 != null) [config.gateway4])
(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"
); );
}; };
@ -157,11 +183,11 @@
address4 = mkAlmostOptionDefault "10.9.1.${toString index}/24"; address4 = mkAlmostOptionDefault "10.9.1.${toString index}/24";
address6 = mkAlmostOptionDefault "fd0c::${UInt.toHexLower index}/64"; address6 = mkAlmostOptionDefault "fd0c::${UInt.toHexLower index}/64";
macAddress = mkIf (system.proxmox.network.interfaces.net0.macAddress or null != null && hasPrefix "BC:24:11:" system.proxmox.network.interfaces.net0.macAddress) (mkAlmostOptionDefault ( macAddress = mkIf (system.proxmox.network.interfaces.net0.macAddress or null != null && hasPrefix "BC:24:11:" system.proxmox.network.interfaces.net0.macAddress) (mkAlmostOptionDefault (
replaceStrings [ "BC:24:11:" ] [ "BC:24:19:" ] system.proxmox.network.interfaces.net0.macAddress replaceStrings ["BC:24:11:"] ["BC:24:19:"] system.proxmox.network.interfaces.net0.macAddress
)); ));
networkd.name = mkDefault "_00-int"; networkd.name = mkDefault "_00-int";
networkd.networkSettings = { networkd.networkSettings = {
domains = mkDefault [ ]; # int.${domain}? domains = mkDefault []; # int.${domain}?
linkConfig.RequiredForOnline = false; linkConfig.RequiredForOnline = false;
ipv6AcceptRAConfig = { ipv6AcceptRAConfig = {
Token = mkOptionDefault "static:::${UInt.toHexLower index}"; Token = mkOptionDefault "static:::${UInt.toHexLower index}";
@ -172,7 +198,8 @@
}; };
}; };
}; };
in mkMerge [ in
mkMerge [
conf conf
(mkIf config.internal.enable confInternal) (mkIf config.internal.enable confInternal)
]; ];
@ -181,12 +208,12 @@ in {
options.proxmox.network = with lib.types; { options.proxmox.network = with lib.types; {
interfaces = mkOption { interfaces = mkOption {
type = attrsOf (submoduleWith { type = attrsOf (submoduleWith {
modules = [ networkInterfaceModule ]; modules = [networkInterfaceModule];
specialArgs = { specialArgs = {
system = config; system = config;
}; };
}); });
default = { }; default = {};
}; };
internal = { internal = {
interface = mkOption { interface = mkOption {

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;
@ -48,7 +49,7 @@ in {
upstream = mkDefault nginx.virtualHosts.barcodebuddy.proxy.upstream; upstream = mkDefault nginx.virtualHosts.barcodebuddy.proxy.upstream;
host = mkDefault nginx.virtualHosts.barcodebuddy.proxy.host; host = mkDefault nginx.virtualHosts.barcodebuddy.proxy.host;
}; };
locations."/" = { config, ... }: { locations."/" = {config, ...}: {
proxy = { proxy = {
headers.enableRecommended = true; headers.enableRecommended = true;
redirect = { redirect = {

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 = {
@ -177,7 +182,7 @@ in {
kticket4 = mkKrb5Upstream "ticket4"; kticket4 = mkKrb5Upstream "ticket4";
}; };
servers = let servers = let
mkKrb5Server = tcpPort: udpPort: { name, ... }: { mkKrb5Server = tcpPort: udpPort: {name, ...}: {
enable = mkDefault nginx.stream.upstreams.${name}.enable; enable = mkDefault nginx.stream.upstreams.${name}.enable;
listen = { listen = {
tcp = mkIf (tcpPort != null) { tcp = mkIf (tcpPort != null) {
@ -187,7 +192,7 @@ in {
udp = mkIf (udpPort != null) { udp = mkIf (udpPort != null) {
enable = mkDefault kerberos.ports.${udpPort}.enable; enable = mkDefault kerberos.ports.${udpPort}.enable;
port = mkOptionDefault kerberos.ports.${udpPort}.port; port = mkOptionDefault kerberos.ports.${udpPort}.port;
extraParameters = [ "udp" ]; extraParameters = ["udp"];
}; };
}; };
proxy.upstream = name; proxy.upstream = name;
@ -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;
}) })
@ -276,7 +286,7 @@ in {
}; };
freeipa'ldap'local = { freeipa'ldap'local = {
serverName = mkDefault ldap.localDomain; serverName = mkDefault ldap.localDomain;
serverAliases = [ ldap.intDomain ]; serverAliases = [ldap.intDomain];
ssl.cert.copyFromVhost = "freeipa'ldap"; ssl.cert.copyFromVhost = "freeipa'ldap";
globalRedirect = virtualHosts.freeipa'web'local.serverName; globalRedirect = virtualHosts.freeipa'web'local.serverName;
local.enable = true; local.enable = true;
@ -295,16 +305,18 @@ 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 = ''
@ -23,7 +30,7 @@ in {
proxy_busy_buffers_size 256k; proxy_busy_buffers_size 256k;
''; '';
locations = { locations = {
"/" = { xvars, ... }: { "/" = {xvars, ...}: {
xvars.enable = true; xvars.enable = true;
proxy = { proxy = {
enable = true; enable = true;
@ -33,7 +40,11 @@ in {
}; };
}; };
}; };
${ucpPath} = { xvars, virtualHost, ... }: { ${ucpPath} = {
xvars,
virtualHost,
...
}: {
proxy = { proxy = {
enable = true; enable = true;
websocket.enable = true; websocket.enable = true;
@ -63,12 +74,12 @@ in {
listen' = { listen' = {
ucp = { ucp = {
port = mkDefault freepbx.ports.ucp.port; port = mkDefault freepbx.ports.ucp.port;
extraParameters = [ "default_server" ]; extraParameters = ["default_server"];
}; };
ucpSsl = { ucpSsl = {
port = mkDefault freepbx.ports.ucp-ssl.port; port = mkDefault freepbx.ports.ucp-ssl.port;
ssl = true; ssl = true;
extraParameters = [ "default_server" ]; extraParameters = ["default_server"];
}; };
}; };
proxy = { proxy = {
@ -84,7 +95,7 @@ in {
}; };
freepbx'local = { freepbx'local = {
listen' = { listen' = {
http = { }; http = {};
https.ssl = true; https.ssl = true;
ucp = { ucp = {
port = mkDefault nginx.virtualHosts.freepbx'ucp.listen'.ucp.port; port = mkDefault nginx.virtualHosts.freepbx'ucp.listen'.ucp.port;
@ -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

@ -7,12 +7,12 @@
inherit (config.services) nginx home-assistant; inherit (config.services) nginx home-assistant;
name.shortServer = mkDefault "home"; name.shortServer = mkDefault "home";
listen' = { listen' = {
http = { }; http = {};
https.ssl = true; https.ssl = true;
hass = { hass = {
enable = !home-assistant.enable; enable = !home-assistant.enable;
port = mkDefault home-assistant.config.http.server_port; port = mkDefault home-assistant.config.http.server_port;
extraParameters = [ "default_server" ]; extraParameters = ["default_server"];
}; };
}; };
upstreamName = "home-assistant'access"; upstreamName = "home-assistant'access";
@ -24,7 +24,7 @@ in {
addr = mkDefault "localhost"; addr = mkDefault "localhost";
port = mkIf home-assistant.enable (mkDefault home-assistant.config.http.server_port); port = mkIf home-assistant.enable (mkDefault home-assistant.config.http.server_port);
}; };
service = { upstream, ... }: { service = {upstream, ...}: {
enable = mkIf upstream.servers.local.enable (mkDefault false); enable = mkIf upstream.servers.local.enable (mkDefault false);
accessService = { accessService = {
name = "home-assistant"; name = "home-assistant";
@ -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

@ -19,7 +19,7 @@ in {
addr = mkDefault "localhost"; addr = mkDefault "localhost";
port = mkIf cfg.enable (mkDefault cfg.port); port = mkIf cfg.enable (mkDefault cfg.port);
}; };
service = { upstream, ... }: { service = {upstream, ...}: {
enable = mkIf upstream.servers.local.enable (mkDefault false); enable = mkIf upstream.servers.local.enable (mkDefault false);
accessService = { accessService = {
name = "invidious"; name = "invidious";
@ -40,7 +40,7 @@ in {
proxy_redirect off; proxy_redirect off;
proxy_buffering off; proxy_buffering off;
''; '';
location = { xvars, ... }: { location = {xvars, ...}: {
proxy = { proxy = {
enable = true; enable = true;
websocket.enable = true; websocket.enable = true;
@ -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;
@ -115,7 +123,7 @@ in {
}; };
inherit extraConfig; inherit extraConfig;
}; };
invidious'local = { xvars, ... }: { invidious'local = {xvars, ...}: {
local.enable = true; local.enable = true;
ssl.cert.copyFromVhost = "invidious"; ssl.cert.copyFromVhost = "invidious";
proxy = { proxy = {

View file

@ -18,7 +18,7 @@ in {
port = mkDefault cfg.port; port = mkDefault cfg.port;
ssl.enable = mkIf (cfg.protocol == "https") true; ssl.enable = mkIf (cfg.protocol == "https") true;
}; };
access = { upstream, ... }: { access = {upstream, ...}: {
enable = mkDefault (!upstream.servers.local.enable or false); enable = mkDefault (!upstream.servers.local.enable or false);
accessService = { accessService = {
name = "keycloak"; name = "keycloak";

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;
@ -32,7 +39,7 @@ in {
}; };
}; };
listen' = { listen' = {
http = { }; http = {};
https.ssl = true; https.ssl = true;
stream = { stream = {
enable = mkDefault motion.ports.stream.enable; enable = mkDefault motion.ports.stream.enable;
@ -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;
@ -42,7 +41,7 @@ in {
inherit (nginx.stream.upstreams.ldaps.servers.access.accessService) system name id port; inherit (nginx.stream.upstreams.ldaps.servers.access.accessService) system name id port;
}; };
}; };
ldap = { upstream, ... }: { ldap = {upstream, ...}: {
enable = mkIf upstream.servers.ldaps.enable false; enable = mkIf upstream.servers.ldaps.enable false;
accessService = { accessService = {
inherit (nginx.stream.upstreams.ldap.servers.access.accessService) system name id port; inherit (nginx.stream.upstreams.ldap.servers.access.accessService) system name id port;
@ -54,7 +53,7 @@ in {
name = "ldap"; name = "ldap";
}; };
}; };
ldaps = { config, ... }: { ldaps = {config, ...}: {
enable = mkAlmostOptionDefault config.servers.access.enable; enable = mkAlmostOptionDefault config.servers.access.enable;
servers.access = { servers.access = {
accessService = { accessService = {

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

@ -15,7 +15,7 @@ in {
addr = mkDefault "localhost"; addr = mkDefault "localhost";
port = mkIf openwebrx.enable (mkDefault openwebrx.port); port = mkIf openwebrx.enable (mkDefault openwebrx.port);
}; };
service = { upstream, ... }: { service = {upstream, ...}: {
enable = mkIf upstream.servers.local.enable (mkDefault false); enable = mkIf upstream.servers.local.enable (mkDefault false);
accessService = { accessService = {
name = "openwebrx"; name = "openwebrx";

View file

@ -16,7 +16,7 @@ in {
addr = mkDefault "localhost"; addr = mkDefault "localhost";
port = mkDefault cfg.port; port = mkDefault cfg.port;
}; };
access = { upstream, ... }: { access = {upstream, ...}: {
enable = mkDefault (!upstream.servers.local.enable); enable = mkDefault (!upstream.servers.local.enable);
accessService.name = "plex"; accessService.name = "plex";
}; };
@ -65,12 +65,12 @@ in {
inherit name locations extraConfig; inherit name locations extraConfig;
proxy.upstream = mkDefault upstreamName; proxy.upstream = mkDefault upstreamName;
listen' = { listen' = {
http = { }; http = {};
https.ssl = true; https.ssl = true;
external = { external = {
enable = mkDefault false; enable = mkDefault false;
port = mkDefault 32400; port = mkDefault 32400;
extraParameters = [ "default_server" ]; extraParameters = ["default_server"];
}; };
}; };
}; };
@ -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

@ -7,7 +7,7 @@
inherit (lib.modules) mkDefault; inherit (lib.modules) mkDefault;
inherit (lib.strings) escapeRegex; inherit (lib.strings) escapeRegex;
inherit (config.services) nginx tailscale; inherit (config.services) nginx tailscale;
proxyPass = access.proxyUrlFor { serviceName = "proxmox"; } + "/"; proxyPass = access.proxyUrlFor {serviceName = "proxmox";} + "/";
in { in {
config.services.nginx.virtualHosts = let config.services.nginx.virtualHosts = let
locations."/" = { locations."/" = {

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