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 = [
"overlays/default.nix"
"ci/fmt.nix"
"docs/derivation.nix"
"devShells.nix"
"shell.nix"
"generate.nix"
"lib.nix"
"outputs.nix"
"tree.nix"
];
whitelistDirs = [
"modules/extern"
"modules/nixos"
"modules/system"
"nixos"
"overlays"
"packages"
"systems"
];
blacklistDirs = [
"overlays"
"modules/nixos/ldap"
"ci"
];
};

View file

@ -151,11 +151,15 @@
LDAPSASL_NOCANON = "on";
};
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) "$@"
'';
in default.overrideAttrs (default: {
nativeBuildInputs = default.nativeBuildInputs ++ [
in
default.overrideAttrs (default: {
nativeBuildInputs =
default.nativeBuildInputs
++ [
(ldapdm "ldapwhoami")
(ldapdm "ldappasswd")
(ldapdm "ldapsearch")

View file

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

57
lib.nix
View file

@ -23,11 +23,15 @@
parts' = Regex.match ''^([^:]+)://(\[[0-9a-fA-F:]+]|[^/:\[]+)(|:[0-9]+)(|/.*)$'' url;
parts = parts'.value;
port' = List.index parts 2;
in assert Opt.isJust parts'; rec {
in
assert Opt.isJust parts'; rec {
inherit url parts;
scheme = List.index parts 0;
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';
path = List.index parts 3;
};
@ -36,7 +40,10 @@
mkWinPath = Str.replace ["/"] ["\\"];
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);
mapListToAttrs = f: l: listToAttrs (map f l);
@ -85,13 +92,43 @@ in {
Std = inputs.std-fl.lib;
lib = {
domain = "gensokyo.zone";
inherit treeToModulesOutput userIs
eui64 parseUrl mkWinPath 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
treeToModulesOutput
userIs
eui64
parseUrl
mkWinPath
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;
};
gensokyo-zone = {

View file

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

View file

@ -19,16 +19,23 @@ let
system = gensokyo-zone.systems.${config.systemName}.config;
networks = let
fallbackNetwork =
if system.network.networks.local.enable or false && access.local.enable then "local"
else if system.access.global.enable then null
else if system.network.networks.int.enable or false then "int"
else if system.network.networks.local.enable or false then "local"
if system.network.networks.local.enable or false && access.local.enable
then "local"
else if system.access.global.enable
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;
networks = map (name: coalesce [ name fallbackNetwork ]) config.networks;
in unique networks;
networks = map (name: coalesce [name fallbackNetwork]) config.networks;
in
unique networks;
in {
options = with lib.types; {
enable = mkEnableOption "ssh client configuration" // {
enable =
mkEnableOption "ssh client configuration"
// {
default = true;
};
name = mkOption {
@ -66,23 +73,30 @@ let
enabledNetworks = filterAttrs (_: net: net.enable) system.network.networks;
networkNames = mapAttrsToList (_: net: net.name) enabledNetworks;
networks = filter (name: name == null || elem name networkNames) cfg.networks;
in mkOptionDefault networks;
in
mkOptionDefault networks;
set = {
matchBlocksSettings = let
canonNetworkName' = intersectLists networks [ null "int" "local" ];
canonNetworkName = if canonNetworkName' != [ ] then head canonNetworkName' else null;
in mapListToAttrs (network: let
canonNetworkName' = intersectLists networks [null "int" "local"];
canonNetworkName =
if canonNetworkName' != []
then head canonNetworkName'
else null;
in
mapListToAttrs (network: let
name = config.name + optionalString (network != canonNetworkName) "-${network}";
inherit (system.exports.services) sshd;
port = head (
optional (network == null && sshd.ports.global.enable or false) sshd.ports.global.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);
in nameValuePair name {
in
nameValuePair name {
hostname = mkDefault (
if network == null then system.access.fqdn
if network == null
then system.access.fqdn
else system.network.networks.${network}.fqdn
);
user = mkIf (config.user != null) (mkDefault config.user);
@ -97,7 +111,8 @@ let
HostKeyAlias = mkIf (config.hostName != null && network != null) (mkOptionDefault system.access.fqdn);
}
];
}) networks;
})
networks;
};
};
};
@ -124,7 +139,7 @@ let
};
hosts = mkOption {
type = attrsOf (submoduleWith {
modules = [ sshHostModule ];
modules = [sshHostModule];
specialArgs = {
inherit gensokyo-zone osConfig homeConfig pkgs;
};
@ -132,7 +147,7 @@ let
};
networks = mkOption {
type = listOf (nullOr str);
default = [ null ];
default = [null];
};
proxyJump = mkOption {
type = str;
@ -150,7 +165,8 @@ let
};
config = {
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
);
networks = mkOptionDefault [
@ -159,31 +175,35 @@ let
];
hosts = mapAttrs (name: system: let
enabled = system.config.access.online.enable && system.config.exports.services.sshd.enable;
in mkIf enabled {
in
mkIf enabled {
systemName = mkOptionDefault name;
}) gensokyo-zone.systems;
})
gensokyo-zone.systems;
set = {
matchBlocksSettings = let
mkMatchBlocksHost = host: mkIf host.enable (unmerged.mergeAttrs host.set.matchBlocksSettings);
in mkMerge (
in
mkMerge (
mapAttrsToList (_: mkMatchBlocksHost) config.hosts
);
};
};
};
in {
in
{
config,
osConfig,
lib,
gensokyo-zone,
pkgs,
...
}: let
}: let
inherit (lib.options) mkOption;
inherit (lib.modules) mkIf;
inherit (gensokyo-zone.lib) unmerged;
cfg = config.gensokyo-zone.ssh;
in {
in {
options.gensokyo-zone.ssh = mkOption {
type = lib.types.submoduleWith {
modules = [sshModule];
@ -193,7 +213,7 @@ in {
homeConfig = config;
};
};
default = { };
default = {};
};
config = {
@ -206,4 +226,4 @@ in {
inherit cfg sshModule sshHostModule;
};
};
}
}

View file

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

View file

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

View file

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

View file

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

View file

@ -42,7 +42,7 @@
type = listOf str;
};
fallback = mkOption {
type = nullOr (enum [ "cloudflare" "google" ]);
type = nullOr (enum ["cloudflare" "google"]);
default = "cloudflare";
};
fallbackNameservers = mkOption {
@ -67,8 +67,9 @@
];
nameservers = let
inherit (gensokyo-zone.systems) utsuho hakurei;
in mkMerge [
(mkOptionDefault [ ])
in
mkMerge [
(mkOptionDefault [])
(mkIf access.local.enable [
(mkIf enableIPv6 utsuho.config.access.address6ForNetwork.local)
utsuho.config.access.address4ForNetwork.local
@ -79,20 +80,25 @@
hakurei.config.access.address4ForNetwork.tail
])
];
fallbackNameservers = mkOptionDefault {
fallbackNameservers =
mkOptionDefault
{
cloudflare = [
"1.1.1.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::8844]#dns.google"
] ++ [
]
++ [
"8.8.8.8#dns.google"
"8.8.4.4#dns.google"
];
${toString null} = [ ];
}.${toString config.fallback};
${toString null} = [];
}
.${toString config.fallback};
set = {
nssSettings = {
hosts = mkMerge [
@ -123,11 +129,11 @@ in {
nixosConfig = config;
};
};
default = { };
default = {};
};
config = {
networking.nameservers = mkIf (cfg.enable && cfg.nameservers != [ ]) (mkMerge [
networking.nameservers = mkIf (cfg.enable && cfg.nameservers != []) (mkMerge [
(mkBefore cfg.nameservers)
cfg.fallbackNameservers
]);

View file

@ -40,7 +40,9 @@
default = toUpper config.domain;
};
ca = {
trust = mkEnableOption "trust CA" // {
trust =
mkEnableOption "trust CA"
// {
default = true;
};
pem = mkOption {
@ -59,7 +61,7 @@
};
urls = mkOption {
type = listOf str;
default = [ "ldaps://${config.ldap.host}" ];
default = ["ldaps://${config.ldap.host}"];
};
baseDn = mkOption {
type = str;
@ -75,21 +77,21 @@
};
passwordFileKrb5 = mkOption {
type = path;
example = lib.literalExpression "\${pkgs.writeText "ldap.kdb5" ''
example = lib.literalExpression "\${pkgs.writeText " ldap.kdb5 " ''
${config.bind.dn}#{HEX}616e6f6e796d6f7573
''}";
};
passwordFileSssdEnv = mkOption {
type = path;
example = lib.literalExpression "\${pkgs.writeText "ldap.kdb5" ''
${"SSSD_AUTHTOK_" + replaceStrings [ "." ] [ "_" ] (toUpper config.domain)}=verysecretpassword
example = lib.literalExpression "\${pkgs.writeText " ldap.kdb5 " ''
${"SSSD_AUTHTOK_" + replaceStrings ["."] ["_"] (toUpper config.domain)}=verysecretpassword
''}";
};
};
};
db = {
backend = mkOption {
type = enum [ "kldap" "ipa" ];
type = enum ["kldap" "ipa"];
default = "kldap";
};
};
@ -99,7 +101,7 @@
};
authToLocalNames = mkOption {
type = attrsOf str;
default = { };
default = {};
example = {
"arc@${config.realm}" = "arc";
};
@ -108,26 +110,30 @@
enable = mkEnableOption "sssd";
pam.enable = mkEnableOption "PAM";
backend = mkOption {
type = enum [ "ipa" "ldap" ];
default = {
type = enum ["ipa" "ldap"];
default =
{
ipa = "ipa";
kldap = "ldap";
}.${config.db.backend};
}
.${config.db.backend};
};
};
ntp = {
enable = mkEnableOption "ntp" // {
enable =
mkEnableOption "ntp"
// {
default = true;
};
servers = mkOption {
type = listOf str;
example = [ config.ipa.host ];
default = [ "2.fedora.pool.ntp.org" ];
example = [config.ipa.host];
default = ["2.fedora.pool.ntp.org"];
};
};
nfs = {
enable = mkEnableOption "nfs";
package = mkPackageOption pkgs "nfs-utils" { };
package = mkPackageOption pkgs "nfs-utils" {};
idmapd = {
localDomain = mkOption {
type = bool;
@ -135,11 +141,11 @@
};
localRealms = mkOption {
type = listOf str;
default = [ config.realm ];
default = [config.realm];
};
methods = mkOption {
type = listOf str;
default = [ "nsswitch" ];
default = ["nsswitch"];
};
authToLocalNames = mkOption {
type = attrsOf str;
@ -185,7 +191,8 @@
url = "https://${config.ipa.httpHost}/ipa/config/ca.crt";
sha256 = "sha256-PKjnjn1jIq9x4BX8+WGkZfj4HQtmnHqmFSALqggo91o=";
};
in mkOptionDefault caPem;
in
mkOptionDefault caPem;
ldap = {
urls = mkMerge [
(mkIf access.local.enable (mkOptionDefault (mkBefore [
@ -200,7 +207,8 @@
];
bind = let
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;
passwordFile = mkOptionDefault nixosConfig.sops.secrets.gensokyo-zone-krb5-peep-password.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);
idmapd = {
methods = mkMerge [
(mkIf (config.nfs.idmapd.authToLocalNames != { }) (
mkOptionDefault (mkBefore [ "static" ])
(mkIf (config.nfs.idmapd.authToLocalNames != {}) (
mkOptionDefault (mkBefore ["static"])
))
(mkIf (!enabled.sssd) (
mkOptionDefault [ "umich_ldap" ]
mkOptionDefault ["umich_ldap"]
))
];
};
@ -243,22 +251,24 @@
};
};
sssdSettings = let
servers = optional access.local.enable "idp.local.${config.domain}"
++ [ "_srv" ];
servers =
optional access.local.enable "idp.local.${config.domain}"
++ ["_srv"];
backups = mkMerge [
(mkIf access.tail.enabled (mkAlmostOptionDefault [ "ipa.tail.${config.domain}" ]))
(mkIf access.local.enable (mkAlmostOptionDefault [ "ipa.local.${config.domain}" ]))
(mkIf access.tail.enabled (mkAlmostOptionDefault ["ipa.tail.${config.domain}"]))
(mkIf access.local.enable (mkAlmostOptionDefault ["ipa.local.${config.domain}"]))
];
in mkIf config.sssd.enable {
in
mkIf config.sssd.enable {
enable = mkAlmostOptionDefault true;
gensokyo-zone = {
backend = mkAlmostOptionDefault config.sssd.backend;
krb5.servers = {
servers = servers ++ [ config.host ];
servers = servers ++ [config.host];
inherit backups;
};
ipa.servers = {
servers = servers ++ [ config.ipa.host ];
servers = servers ++ [config.ipa.host];
inherit backups;
};
ldap = {
@ -268,7 +278,8 @@
]));
};
};
environmentFile = mkIf (config.sssd.backend == "ldap") (mkAlmostOptionDefault
environmentFile = mkIf (config.sssd.backend == "ldap") (
mkAlmostOptionDefault
config.ldap.bind.passwordFileSssdEnv
);
services = {
@ -284,14 +295,19 @@
realm = config.realm;
server = config.ipa.server;
# TODO: dyndns?
} // {
}
// {
overrideConfigs = mapAlmostOptionDefaults {
sssd = false;
krb5 = false;
};
});
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 {
#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]
#use-machine-creds = false
@ -344,10 +364,10 @@
Domain = mkForce config.domain;
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
));
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 {
LDAP_server = config.ldap.host;
LDAP_use_ssl = true;
@ -389,7 +409,7 @@ in {
nixosOptions = options;
};
};
default = { };
default = {};
};
config = {
@ -413,9 +433,10 @@ in {
hosts = let
inherit (gensokyo-zone.systems) freeipa;
# TODO: consider hakurei instead...
in mkIf (cfg.enable && !config.gensokyo-zone.dns.enable or false && config.gensokyo-zone.access.local.enable) {
${freeipa.config.access.address6ForNetwork.local} = mkIf config.networking.enableIPv6 (mkBefore [ cfg.host ]);
${freeipa.config.access.address4ForNetwork.local} = mkBefore [ cfg.host ];
in
mkIf (cfg.enable && !config.gensokyo-zone.dns.enable or false && config.gensokyo-zone.access.local.enable) {
${freeipa.config.access.address6ForNetwork.local} = mkIf config.networking.enableIPv6 (mkBefore [cfg.host]);
${freeipa.config.access.address4ForNetwork.local} = mkBefore [cfg.host];
};
};
environment.etc = {
@ -425,14 +446,20 @@ in {
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${config.system.nssModules.path}"
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
'');
};
};
${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;
in mkIf cfg.enable {
in
mkIf cfg.enable {
gensokyo-zone-krb5-passwords = mkIf (cfg.db.backend == "kldap") {
inherit sopsFile;
};

View file

@ -33,18 +33,26 @@
options = with lib.types; {
enable = mkEnableOption "kyuuto";
media = {
enable = mkEnableOption "/mnt/kyuuto-media" // {
enable =
mkEnableOption "/mnt/kyuuto-media"
// {
default = true;
};
krb5.enable = mkEnableOption "krb5" // {
krb5.enable =
mkEnableOption "krb5"
// {
default = enabled.krb5;
};
};
transfer = {
enable = mkEnableOption "/mnt/kyuuto-transfer" // {
enable =
mkEnableOption "/mnt/kyuuto-transfer"
// {
default = true;
};
krb5.enable = mkEnableOption "krb5" // {
krb5.enable =
mkEnableOption "krb5"
// {
default = enabled.krb5;
};
};
@ -135,7 +143,8 @@
(mkIf config.nfs.enable "nfs4")
(mkIf config.smb.enable "smb3")
];
options = mkMerge (setFilesystemOptions ++ [
options = mkMerge (setFilesystemOptions
++ [
(mkIf config.media.krb5.enable [
"sec=krb5"
(mkIf config.nfs.enable "nfsvers=4")
@ -151,9 +160,14 @@
(mkIf config.nfs.enable "nfs4")
(mkIf config.smb.enable "smb3")
];
options = mkMerge (setFilesystemOptions ++ [
options = mkMerge (setFilesystemOptions
++ [
(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")
])
]);
@ -204,7 +218,7 @@ in {
nixosConfig = config;
};
};
default = { };
default = {};
};
config = {

View file

@ -46,7 +46,9 @@
default = "ssh";
};
ssh = {
commonKey = mkEnableOption "shared secret nixbld key" // {
commonKey =
mkEnableOption "shared secret nixbld key"
// {
default = true;
};
user = mkOption {
@ -105,8 +107,8 @@
];
builder = {
systems = mkMerge [
(mkIf config.builder.cross.aarch64 (mkOptionDefault [ "aarch64-linux" ]))
(mkIf config.builder.cross.armv7l (mkOptionDefault [ "armv7l-linux" ]))
(mkIf config.builder.cross.aarch64 (mkOptionDefault ["aarch64-linux"]))
(mkIf config.builder.cross.armv7l (mkOptionDefault ["armv7l-linux"]))
];
domain = mkMerge [
(mkIf access.tail.enabled (mkAlmostOptionDefault "nixbld.tail.${domain}"))
@ -114,7 +116,9 @@
];
ssh.key = let
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
);
setBuildMachine = {
@ -145,7 +149,7 @@ in {
nixosOptions = options;
};
};
default = { };
default = {};
};
config = {
@ -153,9 +157,14 @@ in {
settings = unmerged.merge cfg.setNixSettings;
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;
in mkIf cfg.enable {
in
mkIf cfg.enable {
gensokyo-zone-nix-bld-key = mkIf cfg.builder.ssh.commonKey {
inherit sopsFile;
};

View file

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

View file

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

View file

@ -55,7 +55,7 @@ in {
nftables.ruleset = mkIf cfg.enable (mkBefore cfg.nftablesInclude);
firewall = {
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;
in {
options.networking.access.peeps = with lib.types; {
enable = mkEnableOption "peeps" // { default = hasSops; };
enable = mkEnableOption "peeps" // {default = hasSops;};
ranges = mkOption {
type = attrsOf str;
default = { };
default = {};
};
stateDir = mkOption {
type = path;
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;
sopsSecrets = mapAttrs' (name: _: nameValuePair (mkSopsName name) {
sopsSecrets = mapAttrs' (name: _:
nameValuePair (mkSopsName name) {
inherit sopsFile;
path = mkDefault "${cfg.stateDir}/${name}.nft";
}) cfg.ranges;
in mkIf cfg.enable sopsSecrets;
})
cfg.ranges;
in
mkIf cfg.enable sopsSecrets;
config.networking = let
nftRanges = mapAttrsToList (name: range: let
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)} }";
in {
nftables.ruleset = mkIf cfg.enable (mkMerge (
nftRanges
++ [ (mkBefore ''include "${cfg.stateDir}/*.nft"'') ]
++ [(mkBefore ''include "${cfg.stateDir}/*.nft"'')]
));
firewall.interfaces.peeps = {
nftables.enable = cfg.enable;

View file

@ -1,4 +1,4 @@
{ gensokyo-zone, ... }: {
{gensokyo-zone, ...}: {
config.lib = {
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 (lib.options) mkOption mkEnableOption mkPackageOption;
inherit (lib.modules) mkIf mkMerge mkDefault mkOptionDefault;
@ -8,17 +14,20 @@
cfg = config.services.barcodebuddy;
toEnvName = key: "BBUDDY_" + key;
toEnvValue = value:
if value == true then "true"
else if value == false then "false"
else if isList value then concatStringsSep ";" (imap0 (i: v: "${toString i}=${toEnvValue v}") value)
if value == true
then "true"
else if value == false
then "false"
else if isList value
then concatStringsSep ";" (imap0 (i: v: "${toString i}=${toEnvValue v}") value)
else toString value;
toEnvPair = key: value: nameValuePair (toEnvName key) (toEnvValue value);
toPhpEnvPair = key: value: nameValuePair (toEnvName key) ''"${toEnvValue value}"'';
in {
options.services.barcodebuddy = with lib.types; {
enable = mkEnableOption "Barcode Buddy";
package = mkPackageOption pkgs "barcodebuddy" { };
phpPackageUnwrapped = mkPackageOption pkgs "php83" { };
package = mkPackageOption pkgs "barcodebuddy" {};
phpPackageUnwrapped = mkPackageOption pkgs "php83" {};
hostName = mkOption {
type = str;
};
@ -38,7 +47,7 @@ in {
enable = mkEnableOption "reverse proxy";
trustedAddresses = mkOption {
type = listOf str;
default = [ "127.0.0.1" "::1" ];
default = ["127.0.0.1" "::1"];
};
};
screen = {
@ -65,13 +74,15 @@ in {
type = nullOr str;
default = null;
};
/* TODO: passwordFile = mkOption {
/*
TODO: passwordFile = mkOption {
type = nullOr path;
default = null;
};*/
};
*/
};
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";
};
nginxConfig = mkOption {
@ -95,9 +106,19 @@ in {
bbuddyConfig.services.barcodebuddy = {
settings = let
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=";
${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;
DATABASE_PATH = cfg.databasePath;
AUTHDB_PATH = cfg.authDatabasePath;
@ -109,7 +130,8 @@ in {
REDIS_PORT = cfg.redis.port;
REDIS_PW = toString cfg.redis.password;
};
in mkMerge [ defaults (mkIf cfg.redis.enable redis) ];
in
mkMerge [defaults (mkIf cfg.redis.enable redis)];
nginxConfig = ''
index index.php index.html index.htm;
'';
@ -125,9 +147,14 @@ in {
};
redis = let
redis = config.services.redis.servers.${cfg.redis.server};
in mkIf (cfg.redis.server != null) {
in
mkIf (cfg.redis.server != null) {
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);
password = mkAlmostOptionDefault redis.requirePass;
# TODO: passwordFile = mkAlmostOptionDefault redis.requirePassFile;
@ -146,7 +173,10 @@ in {
user = "barcodebuddy";
inherit (config.services.nginx) group;
phpPackage = cfg.phpPackageUnwrapped.withExtensions ({ enabled, all }: [
phpPackage = cfg.phpPackageUnwrapped.withExtensions ({
enabled,
all,
}: [
all.curl
all.mbstring
all.sqlite3
@ -190,7 +220,7 @@ in {
};
};
conf.systemd.services.bbuddy-websocket = mkIf cfg.screen.enable {
wantedBy = [ "multi-user.target" ];
wantedBy = ["multi-user.target"];
environment = mapAttrs' toEnvPair cfg.settings;
unitConfig = {
Description = "Run websocket server for barcodebuddy screen feature";
@ -202,5 +232,6 @@ in {
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 = {
allowedTCPPorts = mkMerge [
(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;
};

View file

@ -14,7 +14,7 @@
cfg = config.security.ipa;
in {
options.security.ipa = with lib.types; {
package = mkPackageOption pkgs "freeipa" { };
package = mkPackageOption pkgs "freeipa" {};
overrideConfigs = {
krb5 = mkOption {
type = bool;
@ -36,7 +36,8 @@ in {
config.services.sssd = let
inherit (config.services) sssd;
ipaDebugLevel = 65510;
in mkIf cfg.enable {
in
mkIf cfg.enable {
debugLevel = mkAlmostOptionDefault ipaDebugLevel;
domains = {
${cfg.domain} = {
@ -47,14 +48,15 @@ in {
telephoneNumber = "telephoneNumber";
lock = "nsaccountlock";
};
settings = mapOptionDefaults {
settings =
mapOptionDefaults {
id_provider = "ipa";
auth_provider = "ipa";
access_provider = "ipa";
chpass_provider = "ipa";
ipa_domain = cfg.domain;
ipa_server = [ "_srv_" cfg.server ];
ipa_server = ["_srv_" cfg.server];
ipa_hostname = "${config.networking.hostName}.${cfg.domain}";
@ -67,7 +69,8 @@ in {
dyndns_iface = cfg.dyndns.interface;
ldap_tls_cacert = "/etc/ipa/ca.crt";
} // {
}
// {
krb5_realm = mkIf (toLower cfg.domain != toLower cfg.realm) (mkOptionDefault cfg.realm);
};
};
@ -136,8 +139,9 @@ in {
};
config.environment.etc."krb5.conf" = let
inherit (config.security) krb5;
format = import (modulesPath + "/security/krb5/krb5-conf-format.nix") { inherit pkgs lib; } { };
in mkIf (cfg.enable && !cfg.overrideConfigs.krb5) {
format = import (modulesPath + "/security/krb5/krb5-conf-format.nix") {inherit pkgs lib;} {};
in
mkIf (cfg.enable && !cfg.overrideConfigs.krb5) {
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.modules) mkOptionDefault;
cfg = config.services.keycloak;
in {
options.services.keycloak = with lib.types; {
protocol = mkOption {
type = enum [ "http" "https" ];
type = enum ["http" "https"];
readOnly = true;
};
port = mkOption {
@ -14,7 +18,11 @@ in {
};
};
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";
};
}

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 (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkDefault mkOptionDefault mkForce;
@ -50,12 +56,12 @@ in {
};
};
db.backend = mkOption {
type = enum [ "kldap" "ipa" ];
type = enum ["kldap" "ipa"];
default = "kldap";
};
authToLocalNames = mkOption {
type = attrsOf str;
default = { };
default = {};
};
};
config = {
@ -64,7 +70,8 @@ in {
krb5-ldap = pkgs.krb5.override {
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 {
dbmodules = {
genso-kldap = mkIf (cfg.db.backend == "kldap") (mapDefaults {
@ -72,23 +79,26 @@ in {
ldap_servers = concatStringsSep " " cfg.ldap.urls;
ldap_kdc_dn = cfg.ldap.bind.dn;
ldap_kerberos_container_dn = cfg.ldap.baseDn;
} // {
}
// {
ldap_service_password_file = mkIf (cfg.ldap.bind.passwordFile != null) (mkDefault cfg.ldap.bind.passwordFile);
});
genso-ipa = mkIf (cfg.db.backend == "ipa") (mapDefaults {
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";
master_kdc = "${cfg.host}:88";
admin_server = "${cfg.host}:749";
default_domain = cfg.domain;
pkinit_anchors = [ "FILE:${cfg.ca.cert}" ];
} // {
pkinit_anchors = ["FILE:${cfg.ca.cert}"];
}
// {
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 {
${cfg.domain} = cfg.realm;
@ -112,7 +122,8 @@ in {
url = "https://ipa.${cfg.domain}/ipa/config/ca.crt";
sha256 = "sha256-PKjnjn1jIq9x4BX8+WGkZfj4HQtmnHqmFSALqggo91o=";
};
in mkOptionDefault caPem;
in
mkOptionDefault caPem;
db.backend = mkIf ipa.enable (mkAlmostOptionDefault "ipa");
ldap.urls = mkOptionDefault [
"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 {
certificate = mkDefault cfg.ca.cert;
basedn = mkDefault cfg.ldap.baseDn;
domain = mkDefault cfg.domain;
realm = mkDefault cfg.realm;
server = mkDefault cfg.canonHost;
ifpAllowedUids = [
ifpAllowedUids =
[
"root"
] ++ config.users.groups.wheel.members;
]
++ config.users.groups.wheel.members;
dyndns.enable = mkDefault false;
};
};

View file

@ -1,5 +1,11 @@
let
allowListModule = {config, name, gensokyo-zone, lib, ...}: let
allowListModule = {
config,
name,
gensokyo-zone,
lib,
...
}: let
inherit (gensokyo-zone.Std) UInt;
inherit (lib.options) mkOption;
inherit (lib.modules) mkOptionDefault;
@ -11,10 +17,10 @@ let
default = name;
};
xuid = mkOption {
type = oneOf [ int str ];
type = oneOf [int str];
};
permission = mkOption {
type = enum [ "visitor" "member" "operator" ];
type = enum ["visitor" "member" "operator"];
default = "member";
};
settings = mkOption {
@ -25,10 +31,12 @@ let
};
};
config = let
xuid = {
xuid =
{
string = toString (UInt.FromHex config.xuid);
int = toString config.xuid;
}.${typeOf config.xuid};
}
.${typeOf config.xuid};
in {
settings = {
name = mkOptionDefault config.name;
@ -41,14 +49,20 @@ let
};
};
};
packModule = {config, lib, ...}: let
packModule = {
config,
lib,
...
}: let
inherit (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkOptionDefault;
inherit (lib.strings) splitString;
inherit (builtins) typeOf;
in {
options = with lib.types; {
enable = mkEnableOption "pack" // {
enable =
mkEnableOption "pack"
// {
default = true;
};
package = mkOption {
@ -59,41 +73,55 @@ let
type = str;
};
packType = mkOption {
type = enum [ "resource_packs" "behavior_packs" ];
type = enum ["resource_packs" "behavior_packs"];
};
packId = mkOption {
type = str;
};
version = mkOption {
type = oneOf [ str (listOf str) ];
type = oneOf [str (listOf str)];
};
settings = mkOption {
type = attrsOf (oneOf [ str (listOf str) ]);
type = attrsOf (oneOf [str (listOf str)]);
};
};
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
);
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
);
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
);
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
);
settings = {
pack_id = mkOptionDefault config.packId;
version = mkOptionDefault {
version =
mkOptionDefault
{
string = splitString "." 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
inherit (gensokyo-zone.lib) mapOptionDefaults;
inherit (lib.options) mkOption mkPackageOption;
@ -106,13 +134,18 @@ in { config, gensokyo-zone, lib, pkgs, ... }: let
inherit (builtins) toJSON;
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" (''
# server.properties managed by NixOS configuration
'' + concatStringsSep "\n" (mapAttrsToList
(n: v: "${n}=${cfgToString v}") cfg.serverProperties));
in {
''
+ concatStringsSep "\n" (mapAttrsToList
(n: v: "${n}=${cfgToString v}")
cfg.serverProperties));
in {
options.services.minecraft-bedrock-server = with lib.types; {
enable = mkOption {
type = bool;
@ -133,7 +166,7 @@ in {
};
serverProperties = mkOption {
type = attrsOf (oneOf [ bool int str float ]);
type = attrsOf (oneOf [bool int str float]);
example = literalExample ''
{
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.";
};
@ -187,7 +222,7 @@ in {
allowPlayers = mkOption {
type = nullOr (attrsOf (submoduleWith {
modules = [ allowListModule ];
modules = [allowListModule];
specialArgs = {
inherit gensokyo-zone;
nixosConfig = config;
@ -206,13 +241,13 @@ in {
packs = mkOption {
type = attrsOf (submoduleWith {
modules = [ packModule ];
modules = [packModule];
specialArgs = {
inherit gensokyo-zone;
nixosConfig = config;
};
});
default = { };
default = {};
};
};
@ -249,8 +284,10 @@ in {
allowListJson = pkgs.writeText "minecraft-bedrock-server-allowlist.json" (
toJSON allowPlayers
);
in mkOptionDefault (
if cfg.allowPlayers != null then allowListJson
in
mkOptionDefault (
if cfg.allowPlayers != null
then allowListJson
else null
);
permissions = let
@ -258,8 +295,10 @@ in {
permissionsJson = pkgs.writeText "minecraft-bedrock-server-permissions.json" (
toJSON permissions
);
in mkOptionDefault (
if cfg.allowPlayers != null then permissionsJson
in
mkOptionDefault (
if cfg.allowPlayers != null
then permissionsJson
else null
);
};
@ -274,8 +313,8 @@ in {
conf.systemd.services.minecraft-bedrock-server = {
description = "Minecraft Bedrock Server Service";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
wantedBy = ["multi-user.target"];
after = ["network.target"];
serviceConfig = {
BindReadOnlyPaths = let
@ -292,13 +331,15 @@ in {
"config/default"
"bedrock_server_symbols.debug"
"env-vars"
] ++ optional (cfg.permissions == null) "permissions.json");
]
++ optional (cfg.permissions == null) "permissions.json");
mkWorldPacks = type: let
enabledPacks = filterAttrs (_: pack: pack.enable && pack.packType == "${type}_packs") cfg.packs;
jsonName = "world_${type}_packs.json";
packsJson = mapAttrsToList (_: pack: pack.settings) enabledPacks;
packsJsonPath = pkgs.writeText jsonName (toJSON packsJson);
in mkIf (enabledPacks != { }) [
in
mkIf (enabledPacks != {}) [
"${packsJsonPath}:${cfg.dataDir}/worlds/${cfg.serverProperties.level-name}/${jsonName}"
];
mapWorldPacks = packs: let
@ -306,17 +347,19 @@ in {
mapPackPath = _: pack: let
subDir = "${pack.packType}/${pack.packDir}";
in "${pack.package}/${cfg.package.dataDir}/${subDir}:${cfg.dataDir}/${subDir}";
in mapAttrsToList mapPackPath enabledPacks;
in
mapAttrsToList mapPackPath enabledPacks;
packsPaths = mkMerge [
(mkWorldPacks "behavior")
(mkWorldPacks "resource")
(mapWorldPacks cfg.packs)
];
in mkMerge [
in
mkMerge [
packageResources
(mkIf (cfg.allowList != null) [ "${cfg.allowList}:${cfg.dataDir}/allowlist.json" ])
(mkIf (cfg.permissions != null) [ "${cfg.permissions}:${cfg.dataDir}/permissions.json" ])
(mkIf (cfg.packs != { }) packsPaths)
(mkIf (cfg.allowList != null) ["${cfg.allowList}:${cfg.dataDir}/allowlist.json"])
(mkIf (cfg.permissions != null) ["${cfg.permissions}:${cfg.dataDir}/permissions.json"])
(mkIf (cfg.packs != {}) packsPaths)
];
ExecStart = [
"${getExe cfg.package}"
@ -339,12 +382,14 @@ in {
};
conf.networking.firewall = let
ports = [ cfg.serverProperties.server-port cfg.serverProperties.server-portv6 ];
in mkIf cfg.openFirewall {
ports = [cfg.serverProperties.server-port cfg.serverProperties.server-portv6];
in
mkIf cfg.openFirewall {
allowedUDPPorts = ports;
};
in mkMerge [
in
mkMerge [
confService
(mkIf cfg.enable conf)
];
}
}

View file

@ -9,14 +9,18 @@
inherit (lib.strings) concatStringsSep;
inherit (config.system) nssDatabases;
inherit (config) networking;
netgroupMemberModule = { config, name, ... }: {
netgroupMemberModule = {
config,
name,
...
}: {
options = with lib.types; {
hostname = mkOption {
type = str;
default = name;
};
user = mkOption {
type = either (enum [ null "-" ]) str;
type = either (enum [null "-"]) str;
default = "-";
};
domain = mkOption {
@ -32,7 +36,11 @@
triple = mkOptionDefault "(${config.hostname},${toString config.user},${config.domain})";
};
};
netgroupModule = { config, name, ... }: {
netgroupModule = {
config,
name,
...
}: {
options = with lib.types; {
name = mkOption {
type = str;
@ -40,14 +48,14 @@
};
members = mkOption {
type = attrsOf (submodule netgroupMemberModule);
default = { };
default = {};
};
fileLine = mkOption {
type = str;
};
};
config = {
fileLine = mkOptionDefault (concatStringsSep " " ([ config.name ] ++ mapAttrsToList (_: member: member.triple) config.members));
fileLine = mkOptionDefault (concatStringsSep " " ([config.name] ++ mapAttrsToList (_: member: member.triple) config.members));
};
};
in {
@ -60,7 +68,7 @@ in {
networking = {
netgroups = mkOption {
type = attrsOf (submodule netgroupModule);
default = { };
default = {};
};
extraNetgroups = mkOption {
type = lines;
@ -71,17 +79,17 @@ in {
config = {
system.nssDatabases = {
netgroup = mkMerge [
(mkBefore [ "files" ])
(mkAfter [ "nis" ])
(mkBefore ["files"])
(mkAfter ["nis"])
];
};
environment.etc."nsswitch.conf".text = mkIf (nssDatabases.netgroup != [ ]) (mkAfter ''
environment.etc."nsswitch.conf".text = mkIf (nssDatabases.netgroup != []) (mkAfter ''
netgroup: ${concatStringsSep " " nssDatabases.netgroup}
'');
environment.etc."netgroup" = mkIf (networking.netgroups != { } || networking.extraNetgroups != "") {
environment.etc."netgroup" = mkIf (networking.netgroups != {} || networking.extraNetgroups != "") {
text = mkMerge (
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.modules) mkIf mkOptionDefault;
inherit (lib.lists) filter optional;
@ -7,19 +11,30 @@
enabledNameservers = filter (ns: ns.enable) (config.networking.nameservers');
nameserverModule = {config, ...}: let
dnsPort = 53;
mkResolvedValue = { address, port, interface ? null, host ? null }: let
mkResolvedValue = {
address,
port,
interface ? null,
host ? null,
}: let
isIpv6 = hasInfix ":" address;
isPlain = port == dnsPort && interface == null && host == null;
addr = if isIpv6 && !isPlain then "[${address}]" else address;
in concatStrings (
[ addr ]
addr =
if isIpv6 && !isPlain
then "[${address}]"
else address;
in
concatStrings (
[addr]
++ optional (port != dnsPort) ":${toString port}"
++ optional (interface != null) "%${interface}"
++ optional (host != null) "#${host}"
);
in {
options = with lib.types; {
enable = mkEnableOption "nameserver" // {
enable =
mkEnableOption "nameserver"
// {
default = true;
};
address = mkOption {
@ -59,12 +74,16 @@ in {
options.networking = with lib.types; {
nameservers' = mkOption {
type = listOf (submodule nameserverModule);
default = { };
default = {};
};
};
config = {
networking.nameservers = mkIf (config.networking.nameservers' != [ ]) (
map (ns: if resolved.enable then ns.resolvedValue else ns.value) enabledNameservers
networking.nameservers = mkIf (config.networking.nameservers' != []) (
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)
];
concatFlags = concatStringsSep ",";
clientModule = { config, name, ... }: {
clientModule = {
config,
name,
...
}: {
options = with lib.types; {
machine = mkOption {
type = oneOf [ str (listOf str) ];
type = oneOf [str (listOf str)];
default = name;
example = "*";
};
flags = mkOption {
type = listOf str;
default = [ ];
default = [];
};
entry = mkOption {
type = str;
@ -38,12 +42,17 @@
};
config = {
entry = let
flags = optionalString (config.flags != [ ]) "(${concatFlags config.flags})";
flags = optionalString (config.flags != []) "(${concatFlags config.flags})";
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; {
path = mkOption {
type = path;
@ -60,12 +69,14 @@
};
};
config = {
flags = mkOptionDefault (cfg.export.flagSets.common or [ ]);
flags = mkOptionDefault (cfg.export.flagSets.common or []);
fileLine = let
parts = [ config.path ]
++ optional (config.flags != [ ]) "-${concatFlags config.flags}"
parts =
[config.path]
++ optional (config.flags != []) "-${concatFlags config.flags}"
++ mapAttrsToList (_: client: client.entry) config.clients;
in mkOptionDefault (concatStringsSep " " parts);
in
mkOptionDefault (concatStringsSep " " parts);
};
};
in {
@ -74,15 +85,15 @@ in {
flagSets = mkOption {
type = lazyAttrsOf (listOf str);
default = {
common = [ "no_subtree_check" ];
common = ["no_subtree_check"];
};
};
root = mkOption {
type = nullOr (submodule [
exportModule
({ ... }: {
({...}: {
flags = mkMerge [
(cfg.export.flagSets.common or [ ])
(cfg.export.flagSets.common or [])
];
})
]);
@ -90,7 +101,7 @@ in {
};
paths = mkOption {
type = attrsOf (submodule exportModule);
default = { };
default = {};
};
};
};

View file

@ -111,7 +111,7 @@
};
conditions = mkOption {
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.modules) mkIf mkOverride;
mkExtraForce = mkOverride 25;
locationModule = { config, virtualHost, ... }: {
locationModule = {
config,
virtualHost,
...
}: {
options = with lib.types; {
enable = mkEnableOption "enable location" // {
enable =
mkEnableOption "enable location"
// {
default = true;
};
};
@ -15,14 +18,16 @@
extraConfig = mkExtraForce "deny all;";
};
};
hostModule = { config, ... }: {
hostModule = {config, ...}: {
options = with lib.types; {
enable = mkEnableOption "enable server" // {
enable =
mkEnableOption "enable server"
// {
default = true;
};
locations = mkOption {
type = attrsOf (submoduleWith {
modules = [ locationModule ];
modules = [locationModule];
shorthandOnlyDefinesConfig = true;
});
};
@ -39,7 +44,7 @@ in {
options = with lib.types; {
services.nginx.virtualHosts = mkOption {
type = attrsOf (submoduleWith {
modules = [ hostModule ];
modules = [hostModule];
shorthandOnlyDefinesConfig = true;
});
};

View file

@ -30,7 +30,7 @@ let
};
passHeaders = mkOption {
type = attrsOf bool;
default = { };
default = {};
description = "fastcgi_pass_header";
};
socket = mkOption {
@ -43,7 +43,8 @@ let
config = {
fastcgi = {
socket = mkIf (cfg.phpfpmPool != null) (mkAlmostOptionDefault
socket = mkIf (cfg.phpfpmPool != null) (
mkAlmostOptionDefault
nixosConfig.services.phpfpm.pools.${cfg.phpfpmPool}.socket
);
params = mapOptionDefaults {
@ -60,18 +61,24 @@ let
extraConfig = let
passHeadersConfig = map (header: "fastcgi_pass_header ${xvars.escapeString header};") passHeaders;
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 ''
include ${nginx.package}/conf/fastcgi.conf;
''))
(mkIf (cfg.socket != null) (mkJustAfter ''
fastcgi_pass unix:${cfg.socket};
''))
] ++ passHeadersConfig
]
++ passHeadersConfig
++ paramsConfig));
};
};
hostModule = {config, lib, ...}: let
hostModule = {
config,
lib,
...
}: let
inherit (lib.options) mkOption;
in {
options = with lib.types; {
@ -80,15 +87,13 @@ let
};
};
};
in {
lib,
...
}: let
in
{lib, ...}: let
inherit (lib.options) mkOption;
in {
in {
options = with lib.types; {
services.nginx.virtualHosts = mkOption {
type = attrsOf (submodule [hostModule]);
};
};
}
}

View file

@ -1,5 +1,12 @@
let
locationModule = { config, virtualHost, xvars, gensokyo-zone, lib, ... }: let
locationModule = {
config,
virtualHost,
xvars,
gensokyo-zone,
lib,
...
}: let
inherit (gensokyo-zone.lib) mapOptionDefaults;
inherit (lib.options) mkOption;
inherit (lib.modules) mkIf mkMerge mkAfter mkOptionDefault;
@ -13,25 +20,32 @@ let
default = true;
};
set = mkOption {
type = attrsOf (nullOr (oneOf [ str (listOf str) ]));
type = attrsOf (nullOr (oneOf [str (listOf str)]));
};
};
config = let
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};";
setHeaders = mapAttrsToList (name: value: mkIf (value != null) (mkHeader name value)) cfg.set;
in {
headers = {
set = mkMerge [
(mkOptionDefault { })
(mkOptionDefault {})
(mkIf cfg.inheritServerDefaults (mapOptionDefaults virtualHost.headers.set))
];
};
extraConfig = mkMerge setHeaders;
};
};
hostModule = { config, nixosConfig, gensokyo-zone, lib, ... }: let
hostModule = {
config,
nixosConfig,
gensokyo-zone,
lib,
...
}: let
inherit (gensokyo-zone.lib) mapOptionDefaults;
inherit (lib.options) mkOption;
inherit (nixosConfig.services) nginx;
@ -39,12 +53,12 @@ let
options = with lib.types; {
headers = {
set = mkOption {
type = attrsOf (nullOr (oneOf [ str (listOf str) ]));
type = attrsOf (nullOr (oneOf [str (listOf str)]));
};
};
locations = mkOption {
type = attrsOf (submoduleWith {
modules = [ locationModule ];
modules = [locationModule];
shorthandOnlyDefinesConfig = true;
});
};
@ -55,16 +69,14 @@ let
};
};
};
in {
lib,
...
}: let
in
{lib, ...}: let
inherit (lib.options) mkOption;
in {
in {
options.services.nginx = with lib.types; {
headers = {
set = mkOption {
type = attrsOf (nullOr (oneOf [ str (listOf str) ]));
type = attrsOf (nullOr (oneOf [str (listOf str)]));
default = {
};
};
@ -73,4 +85,4 @@ in {
type = attrsOf (submodule [hostModule]);
};
};
}
}

View file

@ -10,9 +10,16 @@
inherit (lib.attrsets) attrValues mapAttrs;
inherit (lib.lists) optional filter concatMap;
inherit (config.services) nginx;
listenModule = { config, virtualHost, listenKind, ... }: {
listenModule = {
config,
virtualHost,
listenKind,
...
}: {
options = with lib.types; {
enable = mkEnableOption "this port" // {
enable =
mkEnableOption "this port"
// {
default = true;
};
addr = mkOption {
@ -34,7 +41,7 @@
};
extraParameters = mkOption {
type = listOf str;
default = [ ];
default = [];
};
proxyProtocol = mkOption {
type = bool;
@ -59,11 +66,13 @@
(mkIf (listenKind == "streamServer" && !config.ssl && virtualHost.ssl.enable && virtualHost.ssl.force != false) (mkForce false))
];
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 [
(mkOptionDefault virtualHost.listenAddresses')
(mkIf (config.addr != null) (mkAlmostOptionDefault [ config.addr ]))
(mkIf (config.addr != null) (mkAlmostOptionDefault [config.addr]))
];
listenParameters = mkOptionDefault (
optional config.ssl "ssl"
@ -74,26 +83,44 @@
);
listenConfigs = let
# TODO: handle quic listener..?
mkListenHost = { addr, port }: let
mkListenHost = {
addr,
port,
}: let
host =
if addr != null then "${mkAddress6 addr}:${toString port}"
if addr != null
then "${mkAddress6 addr}:${toString port}"
else toString port;
in assert port != null; host;
in
assert port != null; host;
mkDirective = addr: let
host = mkListenHost { inherit addr; inherit (config) port; };
in mkMerge (
[ (mkBefore host) ]
host = mkListenHost {
inherit addr;
inherit (config) port;
};
in
mkMerge (
[(mkBefore host)]
++ config.listenParameters
);
in mkOptionDefault (map (mkDirective) config.addresses);
in
mkOptionDefault (map mkDirective config.addresses);
listenDirectives = mkMerge (map (conf: mkOptionDefault "listen ${conf};") config.listenConfigs);
};
};
listenType = { specialArgs, modules ? [ ] }: lib.types.submoduleWith {
listenType = {
specialArgs,
modules ? [],
}:
lib.types.submoduleWith {
inherit specialArgs;
modules = [ listenModule ] ++ modules;
modules = [listenModule] ++ modules;
};
hostModule = { nixosConfig, config, ... }: let
hostModule = {
nixosConfig,
config,
...
}: let
cfg = attrValues config.listen';
enabledCfg = filter (port: port.enable) cfg;
mkListen = listen: addr: let
@ -101,7 +128,8 @@
inherit addr;
inherit (listen) port ssl extraParameters proxyProtocol;
};
in mapAttrs (_: mkAlmostOptionDefault) listenAttrs;
in
mapAttrs (_: mkAlmostOptionDefault) listenAttrs;
mkListens = listen: map (mkListen listen) listen.addresses;
in {
options = with lib.types; {
@ -113,7 +141,7 @@
listenKind = "virtualHost";
};
});
default = { };
default = {};
};
listenAddresses' = mkOption {
type = listOf str;
@ -122,16 +150,22 @@
};
config = {
enable = mkIf (cfg != [ ] && enabledCfg == [ ]) (mkForce false);
enable = mkIf (cfg != [] && enabledCfg == []) (mkForce false);
listenAddresses' = mkOptionDefault (
if config.listenAddresses != [ ] then config.listenAddresses else nginx.defaultListenAddresses
if config.listenAddresses != []
then config.listenAddresses
else nginx.defaultListenAddresses
);
listen = mkIf (cfg != { }) (mkAlmostOptionDefault (
concatMap (mkListens) enabledCfg
listen = mkIf (cfg != {}) (mkAlmostOptionDefault (
concatMap mkListens enabledCfg
));
};
};
streamServerModule = { nixosConfig, config, ... }: let
streamServerModule = {
nixosConfig,
config,
...
}: let
enabledListen = filter (port: port.enable) (attrValues config.listen);
in {
options = with lib.types; {
@ -144,7 +178,7 @@
listenKind = "streamServer";
};
});
default = { };
default = {};
};
listenAddresses = mkOption {
type = nullOr (listOf str);
@ -163,11 +197,13 @@
};
config = {
enable = mkIf (config.listen != { } && enabledListen == [ ]) (mkForce false);
enable = mkIf (config.listen != {} && enabledListen == []) (mkForce false);
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
));
};
@ -176,13 +212,13 @@ in {
options.services.nginx = with lib.types; {
virtualHosts = mkOption {
type = attrsOf (submoduleWith {
modules = [ hostModule ];
modules = [hostModule];
shorthandOnlyDefinesConfig = true;
});
};
stream.servers = mkOption {
type = attrsOf (submoduleWith {
modules = [ streamServerModule ];
modules = [streamServerModule];
shorthandOnlyDefinesConfig = false;
});
};

View file

@ -8,16 +8,19 @@
inherit (lib.strings) concatMapStringsSep optionalString;
inherit (config.services) tailscale;
inherit (config.networking.access) cidrForNetwork localaddrs;
mkAddrVar = remoteAddr: varPrefix: ''
mkAddrVar = remoteAddr: varPrefix:
''
set ${varPrefix}tailscale 0;
'' + optionalString tailscale.enable ''
''
+ optionalString tailscale.enable ''
if (${remoteAddr} ~ "^fd7a:115c:a1e0:(:|ab12:)") {
set ${varPrefix}tailscale 1;
}
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}lan 0;
if (${remoteAddr} ~ "^10\.1\.1\.[0-9]+") {
set ${varPrefix}lan 1;
@ -56,7 +59,11 @@
set ${varPrefix}client 1;
}
'';
localModule = {config, xvars, ...}: let
localModule = {
config,
xvars,
...
}: let
cfg = config.local;
in {
options.local = with lib.types; {
@ -97,7 +104,8 @@
${allows}
deny all;
'';
in mkMerge [
in
mkMerge [
(mkIf cfg.emitDenyGlobal (mkBefore allowDirectives))
(mkIf cfg.emitVars (mkBefore (mkAddrVar "$remote_addr" "$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.modules) mkIf mkMerge mkAfter mkOptionDefault;
inherit (lib.strings) hasPrefix;
@ -10,7 +15,8 @@
luaModule = {config, ...}: let
cfg = config.lua;
mkSetBy = var: value:
if hasPrefix "/" "${value}" then "set_by_lua_file \$${var} ${value};"
if hasPrefix "/" "${value}"
then "set_by_lua_file \$${var} ${value};"
else ''
set_by_lua_block ''$${var} {
${value}
@ -25,12 +31,12 @@
};
files = mkOption {
type = listOf path;
default = [ ];
default = [];
};
};
set = mkOption {
type = attrsOf (either path lines);
default = { };
default = {};
};
};
config = {
@ -40,25 +46,27 @@
${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
)))
(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
)))
];
};
};
locationModule = {config, ...}: {
imports = [ luaModule ];
imports = [luaModule];
};
hostModule = {config, ...}: {
imports = [ luaModule ];
imports = [luaModule];
options = with lib.types; {
locations = mkOption {
type = attrsOf (submoduleWith {
modules = [ locationModule ];
modules = [locationModule];
shorthandOnlyDefinesConfig = true;
});
};
@ -84,7 +92,7 @@ in {
};
virtualHosts = mkOption {
type = attrsOf (submoduleWith {
modules = [ hostModule ];
modules = [hostModule];
shorthandOnlyDefinesConfig = true;
});
};
@ -92,18 +100,20 @@ in {
config = {
services.nginx = {
lua = {
modules = [
modules =
[
cfg.luaPackage.pkgs.lua-resty-core
] ++ cfg.luaPackage.pkgs.lua-resty-core.propagatedBuildInputs;
]
++ cfg.luaPackage.pkgs.lua-resty-core.propagatedBuildInputs;
luaPath = mkMerge (
map luaPkgPath cfg.modules
++ [ (mkAfter ";") ]
++ [(mkAfter ";")]
);
};
additionalModules = mkMerge [
(mkIf cfg.ndk.enable [ pkgs.nginxModules.develkit ])
(mkIf cfg.http.enable [ pkgs.nginxModules.lua ])
(mkIf cfg.upstream.enable [ pkgs.nginxModules.lua-upstream ])
(mkIf cfg.ndk.enable [pkgs.nginxModules.develkit])
(mkIf cfg.http.enable [pkgs.nginxModules.lua])
(mkIf cfg.upstream.enable [pkgs.nginxModules.lua-upstream])
];
};
systemd.services.nginx = mkIf config.services.nginx.enable {

View file

@ -46,18 +46,21 @@
config = {
name = {
qualifier = mkOptionDefault (
if config.local.enable then "local"
if config.local.enable
then "local"
else null
);
includeTailscale = mkOptionDefault (
config.local.enable && tailscale.enable && cfg.qualifier != "tail"
);
localName = mkOptionDefault (
if cfg.includeLocal then "${cfg.shortServer}.local.${networking.domain}"
if cfg.includeLocal
then "${cfg.shortServer}.local.${networking.domain}"
else null
);
tailscaleName = mkOptionDefault (
if cfg.includeTailscale then "${cfg.shortServer}.tail.${networking.domain}"
if cfg.includeTailscale
then "${cfg.shortServer}.tail.${networking.domain}"
else null
);
};
@ -71,7 +74,7 @@
(mkIf (cfg.tailscaleName != null) cfg.tailscaleName)
]);
allServerNames = mkOptionDefault (filter (name: ! hasPrefix "@" name) (
[ config.serverName ] ++ config.serverAliases
[config.serverName] ++ config.serverAliases
));
otherServerNames = mkOptionDefault (filter (name: ! hasPrefix "@" name) (
config.serverAliases

View file

@ -1,5 +1,12 @@
let
serverModule = {config, nixosConfig, name, gensokyo-zone, lib, ...}: let
serverModule = {
config,
nixosConfig,
name,
gensokyo-zone,
lib,
...
}: let
inherit (gensokyo-zone.lib) mkAlmostOptionDefault;
inherit (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkBefore mkOptionDefault;
@ -13,7 +20,7 @@ let
enable = mkEnableOption "ngx_stream_ssl_preread_module";
upstream = mkOption {
type = str;
default = "$preread_" + replaceStrings [ "'" ] [ "_" ] name;
default = "$preread_" + replaceStrings ["'"] ["_"] name;
};
upstreams = mkOption {
type = nullOr (attrsOf str);
@ -25,8 +32,9 @@ let
config = let
inherit (nginx.stream) upstreams;
mkUpstream = host: upstream: "${host} ${upstreams.${upstream}.name};";
upstreams' = removeAttrs cfg.upstreams [ "default" ];
upstreamLines = mapAttrsToList mkUpstream upstreams'
upstreams' = removeAttrs cfg.upstreams ["default"];
upstreamLines =
mapAttrsToList mkUpstream upstreams'
++ optional (cfg.upstreams ? default) (mkUpstream "default" cfg.upstreams.default);
in {
ssl.preread = {
@ -46,12 +54,18 @@ let
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 (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkDefault mkOptionDefault;
cfg = config.services.nginx.ssl.preread;
in {
in {
options.services.nginx = with lib.types; {
ssl.preread = {
enable = mkEnableOption "ssl preread";
@ -101,4 +115,4 @@ in {
};
};
};
}
}

View file

@ -1,5 +1,5 @@
let
xHeadersProxied = { xvars }: ''
xHeadersProxied = {xvars}: ''
${xvars.init "forwarded_for" "$proxy_add_x_forwarded_for"}
if ($http_x_forwarded_proto) {
${xvars.init "scheme" "$http_x_forwarded_proto"}
@ -18,7 +18,14 @@ let
${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 (lib.options) mkOption;
inherit (lib.modules) mkIf mkMerge mkOptionDefault;
@ -27,7 +34,7 @@ let
options = with lib.types; {
proxied = {
enable = mkOption {
type = enum [ false true "cloudflared" ];
type = enum [false true "cloudflared"];
default = false;
};
enabled = mkOption {
@ -60,12 +67,19 @@ let
xvars.enable = mkIf cfg.enabled true;
extraConfig = mkMerge [
(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 (lib.options) mkOption;
inherit (lib.modules) mkIf mkOrder mkDefault;
@ -75,7 +89,7 @@ let
options = with lib.types; {
proxied = {
enable = mkOption {
type = enum [ false true "cloudflared" ];
type = enum [false true "cloudflared"];
default = false;
};
enabled = mkOption {
@ -93,7 +107,7 @@ let
};
locations = mkOption {
type = attrsOf (submoduleWith {
modules = [ locationModule ];
modules = [locationModule];
shorthandOnlyDefinesConfig = true;
});
};
@ -105,11 +119,20 @@ let
proxied = {
cloudflared = let
listen = config.listen'.proxied;
scheme = if listen.ssl then "https" else "http";
in mkIf (cfg.enable == "cloudflared") {
scheme =
if listen.ssl
then "https"
else "http";
in
mkIf (cfg.enable == "cloudflared") {
ingressSettings.${config.serverName} = {
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;
};
@ -123,17 +146,18 @@ let
};
};
extraConfig = mkIf (cfg.enabled && config.xvars.enable) (
mkOrder (orderJustBefore + 25) (xHeadersProxied { inherit xvars; })
mkOrder (orderJustBefore + 25) (xHeadersProxied {inherit xvars;})
);
};
};
in {
in
{
config,
system,
gensokyo-zone,
lib,
...
}: let
}: let
inherit (gensokyo-zone.lib) mkAlmostOptionDefault;
inherit (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkOptionDefault;
@ -141,7 +165,7 @@ in {
inherit (lib.lists) any;
inherit (config.services) nginx;
cfg = nginx.proxied;
in {
in {
options.services.nginx = with lib.types; {
proxied = {
enable = mkEnableOption "proxy";
@ -190,7 +214,7 @@ in {
};
};
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
proxyModule = {config, name, options, gensokyo-zone, lib, ...}: let
proxyModule = {
config,
name,
options,
gensokyo-zone,
lib,
...
}: let
inherit (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkMerge mkAfter mkOptionDefault;
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;
cfg = config.proxy;
in {
imports = [ proxyModule ];
imports = [proxyModule];
config = let
warnProxy = lib.warnIf (!cfg.enable && options.proxy.url.isDefined) "nginx.stream.servers.${name}.proxy.url set without proxy.enable";
in {
streamConfig = warnProxy (mkIf cfg.enable (mkAfter
streamConfig = warnProxy (mkIf cfg.enable (
mkAfter
"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 (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkMerge mkBefore mkOptionDefault;
@ -57,7 +81,7 @@ let
inherit (nixosConfig.services) nginx;
cfg = config.proxy;
in {
imports = [ proxyModule ];
imports = [proxyModule];
options = with lib.types; {
proxy = {
@ -75,7 +99,9 @@ let
host = mkOption {
type = nullOr str;
};
websocket.enable = mkEnableOption "websocket proxy" // {
websocket.enable =
mkEnableOption "websocket proxy"
// {
default = cfg.inheritServerDefaults && virtualHost.proxy.websocket.enable;
};
parsed = {
@ -94,7 +120,7 @@ let
};
headers = {
enableRecommended = mkOption {
type = enum [ true false "nixpkgs" ];
type = enum [true false "nixpkgs"];
};
rewriteReferer.enable = mkEnableOption "rewrite referer host";
set = mkOption {
@ -102,7 +128,7 @@ let
};
hide = mkOption {
type = attrsOf bool;
default = { };
default = {};
};
};
redirect = {
@ -121,7 +147,7 @@ let
};
};
config = let
emitHeaders = setHeaders' != { };
emitHeaders = setHeaders' != {};
url = parseUrl config.proxyPass;
upstream = nginx.upstreams'.${cfg.upstream};
upstreamServer = upstream.servers.${upstream.defaultServerName};
@ -129,7 +155,10 @@ let
hasUpstream = cfg.upstream != null && !dynamicUpstream;
hasUpstreamServer = upstream.defaultServerName != null;
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;
X-Real-IP = xvars.get.remote_addr;
X-Forwarded-For = xvars.get.forwarded_for;
@ -137,12 +166,15 @@ let
X-Forwarded-Host = xvars.get.host;
X-Forwarded-Server = xvars.get.forwarded_server;
};
schemePort = {
schemePort =
{
http = 80;
https = 443;
}.${cfg.parsed.scheme} or (throw "unsupported proxy_scheme ${toString cfg.parsed.scheme}");
upstreamHost = coalesce ([ upstream.host ] ++ optional hasUpstreamServer upstreamServer.addr);
port = coalesce [ cfg.parsed.port schemePort ];
}
.${cfg.parsed.scheme}
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}";
initProxyVars = let
initScheme = xvars.init "proxy_scheme" config.xvars.defaults.proxy_scheme;
@ -174,8 +206,12 @@ let
${xvars.init "proxy_hostport" xvars.get.proxy_host}
}
'';
init = if cfg.upstream != null then initUpstream else initDynamic;
in init;
init =
if cfg.upstream != null
then initUpstream
else initDynamic;
in
init;
hostHeader = coalesce [
cfg.headers.set.Host or null
cfg.host
@ -192,7 +228,8 @@ let
setHeaders' = filterAttrs (_: header: header != null) cfg.headers.set;
setHeaders = concatStringsSep "\n" (mapAttrsToList (
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;
in {
xvars = {
@ -210,12 +247,16 @@ let
url = mkIf (cfg.inheritServerDefaults && virtualHost.proxy.url != null) (mkOptionDefault virtualHost.proxy.url);
headers = {
enableRecommended = mkOptionDefault (
if cfg.enable && (!cfg.inheritServerDefaults || virtualHost.proxy.headers.enableRecommended != false) then true
else if cfg.inheritServerDefaults then virtualHost.proxy.headers.enableRecommended
else if nginx.recommendedProxySettings then "nixpkgs" else false
if cfg.enable && (!cfg.inheritServerDefaults || virtualHost.proxy.headers.enableRecommended != false)
then true
else if cfg.inheritServerDefaults
then virtualHost.proxy.headers.enableRecommended
else if nginx.recommendedProxySettings
then "nixpkgs"
else false
);
set = mkMerge [
(mkOptionDefault { })
(mkOptionDefault {})
(mkIf (cfg.headers.enableRecommended == true) (mapOptionDefaults recommendedHeaders))
(mkIf (cfg.host != null) {
Host = mkIf (cfg.headers.enableRecommended != "nixpkgs") (mkAlmostOptionDefault cfg.host);
@ -230,8 +271,10 @@ let
];
};
host = mkOptionDefault (
if cfg.inheritServerDefaults && virtualHost.proxy.host != null then virtualHost.proxy.host
else if cfg.headers.enableRecommended == false then null
if cfg.inheritServerDefaults && virtualHost.proxy.host != null
then virtualHost.proxy.host
else if cfg.headers.enableRecommended == false
then null
else xvars.get.host
);
parsed = {
@ -242,11 +285,13 @@ let
mapNullable (_: url.path) config.proxyPass
);
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
);
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
);
};
@ -257,12 +302,19 @@ let
(mkIf virtualHost.xvars.enable (mkJustBefore initProxyVars))
(mkIf (cfg.headers.rewriteReferer.enable) (mkJustBefore rewriteReferer))
(mkIf (cfg.redirect.enable) (mkBefore redirect))
(mkIf (emitHeaders) (mkJustAfter setHeaders))
(mkIf emitHeaders (mkJustAfter setHeaders))
(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 (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkOptionDefault;
@ -288,13 +340,16 @@ let
};
websocket.enable = mkEnableOption "websocket proxy";
headers.enableRecommended = mkOption {
type = enum [ true false "nixpkgs" ];
default = if nginx.recommendedProxySettings then "nixpkgs" else false;
type = enum [true false "nixpkgs"];
default =
if nginx.recommendedProxySettings
then "nixpkgs"
else false;
};
};
locations = mkOption {
type = attrsOf (submoduleWith {
modules = [ locationModule ];
modules = [locationModule];
shorthandOnlyDefinesConfig = true;
});
};
@ -303,9 +358,11 @@ let
needsReferer = loc: loc.proxy.enabled && loc.proxy.headers.rewriteReferer.enable;
confCopy = let
proxyHost = nginx.virtualHosts.${cfg.copyFromVhost};
in mapAlmostOptionDefaults {
in
mapAlmostOptionDefaults {
inherit (proxyHost.proxy) host url upstream;
} // {
}
// {
websocket = mapAlmostOptionDefaults {
inherit (proxyHost.proxy.websocket) enable;
};
@ -326,12 +383,10 @@ let
proxy = mkIf (cfg.copyFromVhost != null) confCopy;
};
};
in {
lib,
...
}: let
in
{lib, ...}: let
inherit (lib.options) mkOption;
in {
in {
options.services.nginx = with lib.types; {
virtualHosts = mkOption {
type = attrsOf (submodule [hostModule]);
@ -343,4 +398,4 @@ in {
});
};
};
}
}

View file

@ -1,5 +1,11 @@
let
sslModule = { config, nixosConfig, gensokyo-zone, lib, ... }: let
sslModule = {
config,
nixosConfig,
gensokyo-zone,
lib,
...
}: let
inherit (lib.options) mkOption;
inherit (lib.modules) mkIf mkMerge mkDefault mkOptionDefault;
inherit (nixosConfig.services) nginx;
@ -12,7 +18,7 @@ let
};
force = mkOption {
# TODO: "force-nonlocal"? exceptions for tailscale?
type = enum [ false true "only" "reject" ];
type = enum [false true "only" "reject"];
default = false;
};
forced = mkOption {
@ -60,14 +66,19 @@ let
};
copyCertVhost = mkCopyCert nginx.virtualHosts.${cfg.cert.copyFromVhost}.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.copyFromVhost != null) copyCertVhost)
];
};
};
};
sslProxyModule = { config, lib, ... }: let
sslProxyModule = {
config,
lib,
...
}: let
inherit (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkMerge mkAfter;
inherit (config) proxy;
@ -78,7 +89,9 @@ let
type = bool;
};
verify = mkEnableOption "proxy_ssl_verify";
sni = mkEnableOption "proxy_ssl_server_name" // {
sni =
mkEnableOption "proxy_ssl_server_name"
// {
default = cfg.host != null;
};
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 (lib.options) mkEnableOption;
inherit (lib.modules) mkIf mkMerge mkOptionDefault;
cfg = config.ssl;
in {
imports = [ sslModule sslProxyModule ];
imports = [sslModule sslProxyModule];
options = with lib.types; {
ssl = {
kTLS = mkEnableOption "kTLS support" // {
kTLS =
mkEnableOption "kTLS support"
// {
default = true;
};
};
@ -126,18 +147,20 @@ let
(mkIf cfg.kTLS "ssl_conf_command Options KTLS;")
];
confProxy.extraConfig = mkIf proxy.ssl.enable "proxy_ssl on;";
in mkMerge [
in
mkMerge [
conf
(mkIf cfg.enable confSsl)
(mkIf proxy.enable confProxy)
];
};
in {
in
{
config,
gensokyo-zone,
lib,
...
}: let
}: let
inherit (gensokyo-zone.lib) mkAlmostOptionDefault;
inherit (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkMerge mkDefault mkOptionDefault;
@ -145,30 +168,42 @@ in {
inherit (lib.trivial) warnIf;
inherit (lib.strings) hasPrefix;
inherit (config.services) nginx;
forceRedirectConfig = { virtualHost, xvars }: ''
forceRedirectConfig = {
virtualHost,
xvars,
}: ''
if (${xvars.get.scheme} = http) {
return ${toString virtualHost.redirectCode} https://${xvars.get.host}$request_uri;
}
'';
locationModule = { config, virtualHost, xvars, ... }: let
locationModule = {
config,
virtualHost,
xvars,
...
}: let
cfg = config.ssl;
emitForce = cfg.force && !virtualHost.ssl.forced;
in {
imports = [ sslProxyModule ];
imports = [sslProxyModule];
options.ssl = {
force = mkEnableOption "redirect to SSL";
};
config = {
proxy.ssl.enable = mkOptionDefault (hasPrefix "https://" config.proxyPass);
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;
emitForce = cfg.forced && config.proxied.enabled;
in {
imports = [ sslModule ];
imports = [sslModule];
options = with lib.types; {
ssl = {
cert = {
@ -177,7 +212,7 @@ in {
};
locations = mkOption {
type = attrsOf (submoduleWith {
modules = [ locationModule ];
modules = [locationModule];
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" (
mkAlmostOptionDefault config.name.shortServer
));
in certConfig;
in
certConfig;
};
addSSL = mkIf (cfg.enable && (cfg.force == false || emitForce)) (mkDefault true);
forceSSL = mkIf (cfg.enable && cfg.force == true && !emitForce) (mkDefault true);
@ -200,30 +236,35 @@ in {
kTLS = mkAlmostOptionDefault 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; {
virtualHosts = mkOption {
type = attrsOf (submoduleWith {
modules = [ hostModule ];
modules = [hostModule];
shorthandOnlyDefinesConfig = true;
});
};
stream.servers = mkOption {
type = attrsOf (submoduleWith {
modules = [ streamServerModule ];
modules = [streamServerModule];
shorthandOnlyDefinesConfig = false;
});
};
};
config.systemd.services.nginx = let
mapStreamServer = server: mkIf (server.enable && server.ssl.enable && server.ssl.cert.name != null) {
wants = [ "acme-finished-${server.ssl.cert.name}.target" ];
after = [ "acme-selfsigned-${server.ssl.cert.name}.service" ];
before = [ "acme-${server.ssl.cert.name}.service" ];
mapStreamServer = server:
mkIf (server.enable && server.ssl.enable && server.ssl.cert.name != null) {
wants = ["acme-finished-${server.ssl.cert.name}.target"];
after = ["acme-selfsigned-${server.ssl.cert.name}.service"];
before = ["acme-${server.ssl.cert.name}.service"];
};
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;
serverModule = {config, ...}: {
options = with lib.types; {
enable = mkEnableOption "stream server block" // {
enable =
mkEnableOption "stream server block"
// {
default = true;
};
extraConfig = mkOption {
@ -49,7 +51,7 @@ in {
nixosConfig = config;
};
});
default = { };
default = {};
};
};
config.services.nginx = {

View file

@ -1,5 +1,13 @@
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.modules) mkIf mkMerge mkOptionDefault;
inherit (gensokyo-zone.lib) mkAlmostOptionDefault;
@ -57,12 +65,20 @@ let
port = mkOptionDefault port.port;
ssl.enable = mkIf port.ssl (mkAlmostOptionDefault true);
};
in mkMerge [
in
mkMerge [
confAccess
(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 (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkMerge mkBefore mkOptionDefault;
@ -72,7 +88,9 @@ let
inherit (lib.trivial) isBool;
in {
options = with lib.types; {
enable = mkEnableOption "upstream server" // {
enable =
mkEnableOption "upstream server"
// {
default = true;
};
addr = mkOption {
@ -90,8 +108,8 @@ let
example = "unix:/tmp/backend3";
};
settings = mkOption {
type = attrsOf (oneOf [ int str bool ]);
default = { };
type = attrsOf (oneOf [int str bool]);
default = {};
};
extraConfig = mkOption {
type = str;
@ -108,21 +126,30 @@ let
};
config = let
mapSetting = key: value:
if isBool value then mkIf value key
if isBool value
then mkIf value key
else "${key}=${toString value}";
settings = mapAttrsToList mapSetting config.settings;
port = optionalString (config.port != null) ":${toString config.port}";
in {
server = mkOptionDefault "${mkAddress6 config.addr}${port}";
serverConfig = mkMerge (
[ (mkBefore config.server) ]
[(mkBefore config.server)]
++ settings
++ optional (config.extraConfig != "") config.extraConfig
);
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 (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkMerge mkOptionDefault;
@ -132,19 +159,21 @@ let
in {
options = with lib.types; let
upstreamServer = submoduleWith {
modules = [ upstreamServerModule upstreamServerAccessModule ];
modules = [upstreamServerModule upstreamServerAccessModule];
specialArgs = {
inherit nixosConfig gensokyo-zone upstreamKind;
upstream = config;
};
};
in {
enable = mkEnableOption "upstream block" // {
enable =
mkEnableOption "upstream block"
// {
default = true;
};
name = mkOption {
type = str;
default = replaceStrings [ "'" ] [ "_" ] name;
default = replaceStrings ["'"] ["_"] name;
};
servers = mkOption {
type = attrsOf upstreamServer;
@ -183,13 +212,13 @@ let
config = let
enabledServers = filterAttrs (_: server: server.enable) config.servers;
assertServers = v: assert enabledServers != { }; v;
assertServers = v: assert enabledServers != {}; v;
in {
ssl.enable = mkIf (any (server: server.ssl.enable) (attrValues enabledServers)) (mkAlmostOptionDefault true);
defaultServerName = findSingle (_: true) null null (attrNames enabledServers);
upstreamConfig = mkMerge (
mapAttrsToList (_: server: mkIf server.enable server.serverDirective) config.servers
++ [ config.extraConfig ]
++ [config.extraConfig]
);
upstreamBlock = mkOptionDefault ''
upstream ${config.name} {
@ -199,16 +228,28 @@ let
upstreamSettings = assertServers (mkOptionDefault {
#extraConfig = config.upstreamConfig;
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
(mkIf (server.extraConfig != "") {
${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 (lib.options) mkOption;
inherit (lib.modules) mkIf;
@ -229,7 +270,8 @@ let
dynamicUpstream = hasPrefix "$" config.proxy.upstream;
hasUpstream = config.proxy.upstream != null && !dynamicUpstream;
proxyPass =
if dynamicUpstream then config.proxy.upstream
if dynamicUpstream
then config.proxy.upstream
else assert proxyUpstream.enable; proxyUpstream.name;
in {
proxy = {
@ -242,7 +284,12 @@ let
};
};
};
proxyUpstreamModule = {config, nixosConfig, lib, ...}: let
proxyUpstreamModule = {
config,
nixosConfig,
lib,
...
}: let
inherit (lib.options) mkOption;
in {
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 (lib.modules) mkIf mkOptionDefault;
inherit (lib.strings) hasPrefix;
inherit (nixosConfig.services) nginx;
in {
imports = [ proxyUpstreamModule ];
imports = [proxyUpstreamModule];
config = let
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;
hasUpstream = config.proxy.upstream != null && !dynamicUpstream;
proxyHost =
if dynamicUpstream then config.proxy.upstream
if dynamicUpstream
then config.proxy.upstream
else assert proxyUpstream.enable; proxyUpstream.name;
in {
proxy = {
upstream = mkOptionDefault virtualHost.proxy.upstream;
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}"
);
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 && proxyUpstream.host != null) (mkAlmostOptionDefault proxyUpstream.host);
};
};
};
hostModule = {config, nixosConfig, lib, ...}: let
hostModule = {
config,
nixosConfig,
lib,
...
}: let
inherit (lib.options) mkOption;
inherit (lib.modules) mkOptionDefault;
in {
imports = [ proxyUpstreamModule ];
imports = [proxyUpstreamModule];
options = with lib.types; {
locations = mkOption {
@ -302,18 +370,19 @@ let
};
};
};
in {
in
{
config,
lib,
gensokyo-zone,
...
}: let
}: let
inherit (gensokyo-zone.lib) unmerged;
inherit (lib.options) mkOption;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.attrsets) mapAttrsToList;
cfg = config.services.nginx;
in {
in {
options.services.nginx = with lib.types; {
upstreams' = mkOption {
type = attrsOf (submoduleWith {
@ -325,7 +394,7 @@ in {
upstreamKind = "virtualHost";
};
});
default = { };
default = {};
};
virtualHosts = mkOption {
type = attrsOf (submodule hostModule);
@ -341,7 +410,7 @@ in {
upstreamKind = "stream";
};
});
default = { };
default = {};
};
servers = mkOption {
type = attrsOf (submoduleWith {
@ -356,14 +425,21 @@ in {
mapAttrsToList (_: upstream: mkIf upstream.enable upstream.upstreamBlock) cfg.stream.upstreams
);
useUpstreams = true;
confUpstreams.upstreams = mkMerge (mapAttrsToList (_: upstream: mkIf upstream.enable {
confUpstreams.upstreams = mkMerge (mapAttrsToList (_: upstream:
mkIf upstream.enable {
${upstream.name} = unmerged.mergeAttrs upstream.upstreamSettings;
}) cfg.upstreams');
})
cfg.upstreams');
confBlock.commonHttpConfig = mkMerge (
mapAttrsToList (_: upstream: mkIf upstream.enable upstream.upstreamBlock) cfg.upstreams'
);
in mkMerge [
in
mkMerge [
confStream
(if useUpstreams then confUpstreams else confBlock)
(
if useUpstreams
then confUpstreams
else confBlock
)
];
}
}

View file

@ -13,7 +13,12 @@
inherit (config) networking;
inherit (config.services) vouch-proxy nginx tailscale;
inherit (nginx) vouch;
locationModule = {config, virtualHost, xvars, ...}: {
locationModule = {
config,
virtualHost,
xvars,
...
}: {
options.vouch = with lib.types; {
requireAuth = mkEnableOption "require auth to access this location";
setProxyHeader = mkOption {
@ -26,7 +31,8 @@
enableVouchLocal = virtualHost.vouch.localSso.enable;
enableVouchTail = enableVouchLocal && tailscale.enable && false;
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 {
access.block = mkMerge [
(mkBefore virtualHost.vouch.auth.lua.accessRequest)
@ -36,7 +42,8 @@
};
xvars.enable = mkIf (enableVouchTail || virtualHost.vouch.auth.lua.enable) true;
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)
(allowOrigin vouch.url)
(allowOrigin vouch.authUrl)
@ -46,9 +53,13 @@
];
};
};
hostModule = {config, xvars, ...}: let
hostModule = {
config,
xvars,
...
}: let
cfg = config.vouch;
mkHeaderVar = header: toLower (replaceStrings [ "-" ] [ "_" ] header);
mkHeaderVar = header: toLower (replaceStrings ["-"] ["_"] header);
mkUpstreamVar = header: "\$upstream_http_${mkHeaderVar header}";
in {
options = with lib.types; {
@ -57,10 +68,14 @@
};
vouch = {
enable = mkEnableOption "vouch auth proxy";
localSso.enable = mkEnableOption "lan-local vouch" // {
localSso.enable =
mkEnableOption "lan-local vouch"
// {
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;
};
auth = {
@ -129,9 +144,12 @@
return ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
end
'');
accessVariables = mkMerge (mapAttrsToList (authVar: header: mkOptionDefault
accessVariables = mkMerge (mapAttrsToList (
authVar: header:
mkOptionDefault
''ngx.var["${authVar}"] = ngx.ctx.auth_res.header["${header}"] or ""''
) cfg.auth.variables);
)
cfg.auth.variables);
};
errorLocation = mkIf cfg.auth.lua.enable (mkAlmostOptionDefault null);
requestDirective = mkIf cfg.auth.lua.enable (mkAlmostOptionDefault "");
@ -161,14 +179,18 @@
(mkIf cfg.localSso.enable localVouchUrl)
(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.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};"
)) cfg.auth.variables
))
cfg.auth.variables
));
xvars.enable = mkIf cfg.enable true;
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;
'';
};
${cfg.auth.requestLocation} = { config, xvars, ... }: {
${cfg.auth.requestLocation} = {
config,
xvars,
...
}: {
proxy = {
enable = true;
inheritServerDefaults = false;
upstream = mkDefault (
if vouch.doubleProxy.enable then "vouch'proxy"
else if cfg.localSso.enable then "vouch'auth'local"
if vouch.doubleProxy.enable
then "vouch'proxy"
else if cfg.localSso.enable
then "vouch'auth'local"
else "vouch'auth"
);
# nginx-proxied vouch must use X-Forwarded-Host, but vanilla vouch requires Host
host = if config.proxy.upstream == "vouch'proxy"
then (if cfg.localSso.enable then vouch.doubleProxy.localServerName else vouch.doubleProxy.serverName)
host =
if config.proxy.upstream == "vouch'proxy"
then
(
if cfg.localSso.enable
then vouch.doubleProxy.localServerName
else vouch.doubleProxy.serverName
)
else xvars.get.host;
headers = {
set.Content-Length = "";
@ -212,7 +246,9 @@ in {
vouch = {
enable = mkEnableOption "vouch auth proxy";
localSso = {
enable = mkEnableOption "lan-local auth" // {
enable =
mkEnableOption "lan-local auth"
// {
default = true;
};
};
@ -271,7 +307,7 @@ in {
enable = vouch.enable;
servers = {
local = localVouch;
service = { upstream, ... }: {
service = {upstream, ...}: {
enable = mkIf upstream.servers.local.enable false;
accessService = {
name = "vouch-proxy";
@ -283,10 +319,12 @@ in {
vouch'auth'local = {
enable = vouch.enable && vouch.localSso.enable;
servers = {
local = localVouch // {
local =
localVouch
// {
enable = mkAlmostOptionDefault false;
};
service = { upstream, ... }: {
service = {upstream, ...}: {
enable = mkIf upstream.servers.local.enable false;
accessService = {
name = "vouch-proxy";
@ -299,18 +337,18 @@ in {
enable = vouch.enable && vouch.doubleProxy.enable;
# TODO: need exported hosts options for this to detect the correct host/port/etc
servers = {
lan = { upstream, ... }: {
lan = {upstream, ...}: {
enable = mkAlmostOptionDefault (!upstream.servers.int.enable);
addr = mkAlmostOptionDefault "login.local.${networking.domain}";
port = mkOptionDefault 9080;
ssl.enable = mkAlmostOptionDefault true;
};
int = { upstream, ... }: {
int = {upstream, ...}: {
enable = mkAlmostOptionDefault system.network.networks.int.enable or false;
addr = mkAlmostOptionDefault "login.int.${networking.domain}";
port = mkOptionDefault 9080;
};
tail = { upstream, ... }: {
tail = {upstream, ...}: {
enable = mkAlmostOptionDefault (tailscale.enable && !upstream.servers.lan.enable && !upstream.servers.int.enable);
addr = mkAlmostOptionDefault "login.tail.${networking.domain}";
port = mkOptionDefault 9080;

View file

@ -1,5 +1,10 @@
let
locationModule = { config, virtualHost, lib, ... }: let
locationModule = {
config,
virtualHost,
lib,
...
}: let
inherit (lib.options) mkEnableOption mkOption;
inherit (lib.attrsets) mapAttrs;
cfg = config.xvars;
@ -8,7 +13,7 @@ let
enable = mkEnableOption "$x_variables";
defaults = mkOption {
type = attrsOf (nullOr str);
default = { };
default = {};
};
lib = mkOption {
type = attrs;
@ -18,15 +23,28 @@ let
xvars = {
lib = let
xvars = virtualHost.xvars.lib;
get = mapAttrs (name: default: if virtualHost.xvars.enable then "$x_${name}" else assert default != null; default) cfg.defaults;
in xvars // {
get = mapAttrs (name: default:
if virtualHost.xvars.enable
then "$x_${name}"
else assert default != null; default)
cfg.defaults;
in
xvars
// {
get = xvars.get // get;
};
};
_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 (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkMerge mkOptionDefault;
@ -36,11 +54,16 @@ let
inherit (lib.trivial) isInt;
cfg = config.xvars;
escapeString = value:
if value == "" then ''""''
else if isInt value then toString 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}"''
if value == ""
then ''""''
else if isInt value
then toString 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;
anyLocations = f: any (loc: loc.enable && f loc) (attrValues config.locations);
in {
@ -66,7 +89,7 @@ let
};
locations = mkOption {
type = attrsOf (submoduleWith {
modules = [ locationModule ];
modules = [locationModule];
shorthandOnlyDefinesConfig = true;
specialArgs = {
inherit nixosConfig gensokyo-zone;
@ -99,7 +122,11 @@ let
referer_path = null;
});
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};";
inherit escapeString;
};
@ -111,18 +138,19 @@ let
_module.args.xvars = config.xvars.lib;
};
};
in {
in
{
config,
lib,
gensokyo-zone,
...
}: let
}: let
inherit (lib.options) mkOption;
in {
in {
options = with lib.types; {
services.nginx.virtualHosts = mkOption {
type = attrsOf (submoduleWith {
modules = [ hostModule ];
modules = [hostModule];
shorthandOnlyDefinesConfig = true;
specialArgs = {
inherit gensokyo-zone;
@ -131,4 +159,4 @@ in {
});
};
};
}
}

View file

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

View file

@ -45,26 +45,30 @@ in {
};
netbiosHostAddresses = mkOption {
type = attrsOf (listOf str);
default = { };
default = {};
};
lmhosts = mkOption {
type = attrsOf str;
default = { };
default = {};
};
};
ldap = {
enable = mkEnableOption "LDAP";
passdb = {
enable = mkEnableOption "LDAP authentication" // {
enable =
mkEnableOption "LDAP authentication"
// {
default = true;
};
backend = mkOption {
type = enum [ "ldapsam" "ipasam" ];
type = enum ["ldapsam" "ipasam"];
default = "ldapsam";
};
};
idmap = {
enable = mkEnableOption "LDAP users" // {
enable =
mkEnableOption "LDAP users"
// {
default = true;
};
domain = mkOption {
@ -98,10 +102,14 @@ in {
};
};
tls = {
enable = mkEnableOption "tls" // {
enable =
mkEnableOption "tls"
// {
default = cfg.tls.certPath != null;
};
peer.enable = mkEnableOption "peer verification" // {
peer.enable =
mkEnableOption "peer verification"
// {
default = cfg.tls.caPath != null;
};
useACMECert = mkOption {
@ -212,19 +220,30 @@ in {
config = {
services.samba = {
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 = {
isWorkgroup = mkOptionDefault (cfg.securityType != "domain" && cfg.securityType != "ads");
netbiosName' = let
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);
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) {
${cfg.domain.netbiosName'} = [ "127.0.0.1" "::1" ];
${cfg.domain.netbiosName'} = ["127.0.0.1" "::1"];
};
lmhosts = let
addrs = mapAttrsToList (name: map (flip nameValuePair name)) cfg.domain.netbiosHostAddresses;
in listToAttrs (concatLists addrs);
in
listToAttrs (concatLists addrs);
};
ldap = {
adminPasswordPath = mkIf (cfg.ldap.adminDn != null && hasPrefix "name=anonymous," cfg.ldap.adminDn) (mkAlmostOptionDefault (
@ -254,7 +273,7 @@ in {
{
"use sendfile" = mkOptionDefault true;
"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);
"netbios name" = mkIf (cfg.domain.netbiosName != null) (mkOptionDefault cfg.domain.netbiosName);
}
@ -269,10 +288,12 @@ in {
(mkIf cfg.kerberos.enable {
"realm" = mkOptionDefault cfg.kerberos.realm;
"kerberos method" = mkOptionDefault (
if cfg.kerberos.keytabPath != null then "dedicated keytab"
if cfg.kerberos.keytabPath != null
then "dedicated 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}"
);
"kerberos encryption types" = mkOptionDefault "strong";
@ -296,13 +317,14 @@ in {
"usershare owner only" = mkOptionDefault true;
"usershare template share" = mkOptionDefault cfg.usershare.templateShare;
"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 {
"map to guest" = mkOptionDefault "Bad User";
"guest account" = mkOptionDefault cfg.guest.user;
})
] ++ mapAttrsToList (_: idmap: mapAttrs' (key: value: nameValuePair "idmap config ${idmap.domain} : ${key}" (mkOptionDefault value)) idmap.settings) cfg.idmap.domains);
]
++ mapAttrsToList (_: idmap: mapAttrs' (key: value: nameValuePair "idmap config ${idmap.domain} : ${key}" (mkOptionDefault value)) idmap.settings) cfg.idmap.domains);
extraConfig = mkMerge (
mapAttrsToList (key: value: ''${key} = ${settingValue value}'') cfg.settings
++ [
@ -340,11 +362,11 @@ in {
];
networking.hosts = mkIf (cfg.enable && cfg.domain.netbiosName != null) {
"::1" = mkAfter [ cfg.domain.netbiosName' ];
"::1" = mkAfter [cfg.domain.netbiosName'];
# 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 (
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.modules) mkIf mkMerge mkOptionDefault;
inherit (lib.attrsets) mapAttrsToList;
inherit (lib.lists) head;
inherit (lib.strings) splitString;
inherit (utils) escapeSystemdPath;
mountModule = { config, name, ... }: {
mountModule = {
config,
name,
...
}: {
options = with lib.types; {
source = mkOption {
type = path;
@ -32,23 +41,38 @@
};
};
};
mkMountType' = { rootDir, specialArgs, modules ? [ ] }: let
rootDirModule = { ... }: {
mkMountType' = {
rootDir,
specialArgs,
modules ? [],
}: let
rootDirModule = {...}: {
config.rootDir = mkOptionDefault rootDir;
};
in lib.types.submoduleWith {
modules = [ mountModule rootDirModule ] ++ modules;
in
lib.types.submoduleWith {
modules = [mountModule rootDirModule] ++ modules;
inherit specialArgs;
};
mkMountType = args: with lib.types; coercedTo path (path: { path = mkOptionDefault path; }) (mkMountType' args);
serviceModule = { config, nixosConfig, ... }: let
mkMountType = args: with lib.types; coercedTo path (path: {path = mkOptionDefault path;}) (mkMountType' args);
serviceModule = {
config,
nixosConfig,
...
}: let
cfg = config.gensokyo-zone;
mapSharedMounts = f: mapAttrsToList (_: target:
mapSharedMounts = f:
mapAttrsToList (
_: target:
f target
) cfg.sharedMounts;
mapCacheMounts = f: mapAttrsToList (_: target:
)
cfg.sharedMounts;
mapCacheMounts = f:
mapAttrsToList (
_: target:
f target
) cfg.cacheMounts;
)
cfg.cacheMounts;
mkRequire = mount: mount.mountUnit;
mkBindPath = mount: "${mount.source}:${mount.path}";
specialArgs = {
@ -56,28 +80,34 @@
inherit nixosConfig;
};
mountUnits = mkMerge [
(mkIf (cfg.sharedMounts != { }) (mapSharedMounts mkRequire))
(mkIf (cfg.cacheMounts != { }) (mapCacheMounts mkRequire))
(mkIf (cfg.sharedMounts != {}) (mapSharedMounts mkRequire))
(mkIf (cfg.cacheMounts != {}) (mapCacheMounts mkRequire))
];
in {
options.gensokyo-zone = with lib.types; {
sharedMounts = mkOption {
type = attrsOf (mkMountType { rootDir = "/mnt/shared"; inherit specialArgs; });
default = { };
type = attrsOf (mkMountType {
rootDir = "/mnt/shared";
inherit specialArgs;
});
default = {};
};
cacheMounts = mkOption {
type = attrsOf (mkMountType { rootDir = "/mnt/caches"; inherit specialArgs; });
default = { };
type = attrsOf (mkMountType {
rootDir = "/mnt/caches";
inherit specialArgs;
});
default = {};
};
};
config = {
requires = mountUnits;
after = mountUnits;
serviceConfig = mkMerge [
(mkIf (cfg.sharedMounts != { }) {
(mkIf (cfg.sharedMounts != {}) {
BindPaths = mapSharedMounts mkBindPath;
})
(mkIf (cfg.cacheMounts != { }) {
(mkIf (cfg.cacheMounts != {}) {
BindPaths = mapCacheMounts mkBindPath;
})
];
@ -87,7 +117,7 @@ in {
options = with lib.types; {
systemd.services = mkOption {
type = attrsOf (submoduleWith {
modules = [ serviceModule ];
modules = [serviceModule];
shorthandOnlyDefinesConfig = true;
specialArgs = {
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 (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkMerge mkAfter mkDefault mkOptionDefault;
@ -6,7 +12,7 @@
inherit (config.services) sssd;
genso = krb5.gensokyo-zone;
cfg = sssd.gensokyo-zone;
serverModule = { config, ... }: {
serverModule = {config, ...}: {
options = with lib.types; {
servers = mkOption {
type = nullOr (listOf str);
@ -14,14 +20,14 @@
};
backups = mkOption {
type = listOf str;
default = [ ];
default = [];
};
serverName = mkOption {
type = str;
internal = true;
};
serverKind = mkOption {
type = enum [ "server" "uri" ];
type = enum ["server" "uri"];
default = "server";
internal = true;
};
@ -35,33 +41,40 @@
in {
settings = {
${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 {
modules = [ serverModule ] ++ modules;
mkServerType = {modules}:
lib.types.submoduleWith {
modules = [serverModule] ++ modules;
specialArgs = {
inherit gensokyo-zone pkgs;
nixosConfig = config;
};
};
mkServerOption = { name, kind ? "server" }: let
serverInfoModule = { ... }: {
mkServerOption = {
name,
kind ? "server",
}: let
serverInfoModule = {...}: {
config = {
serverName = mkOptionDefault name;
serverKind = mkAlmostOptionDefault kind;
};
};
in mkOption {
in
mkOption {
type = mkServerType {
modules = [ serverInfoModule ];
modules = [serverInfoModule];
};
default = { };
default = {};
};
in {
options.services.sssd.gensokyo-zone = with lib.types; {
enable = mkEnableOption "realm" // {
enable =
mkEnableOption "realm"
// {
default = genso.enable;
};
ldap = {
@ -71,13 +84,18 @@ in {
default = null;
};
};
uris = mkServerOption { name = "ldap"; kind = "uri"; };
uris = mkServerOption {
name = "ldap";
kind = "uri";
};
};
krb5 = {
servers = mkServerOption { name = "krb5"; };
servers = mkServerOption {name = "krb5";};
};
ipa = {
servers = mkServerOption { name = "ipa"; } // {
servers =
mkServerOption {name = "ipa";}
// {
default = {
inherit (cfg.krb5.servers) servers backups;
};
@ -88,7 +106,7 @@ in {
};
};
backend = mkOption {
type = enum [ "ldap" "ipa" ];
type = enum ["ldap" "ipa"];
default = "ipa";
};
};
@ -97,13 +115,15 @@ in {
# or "ipaNTSecurityIdentifier" which isn't set for most groups, maybe check netgroups..?
objectsid = "sambaSID";
backendDomainSettings = {
ldap = mapDefaults {
ldap =
mapDefaults {
id_provider = "ldap";
auth_provider = "krb5";
access_provider = "ldap";
ldap_tls_cacert = "/etc/ssl/certs/ca-bundle.crt";
} // mapOptionDefaults {
ldap_access_order = [ "host" ];
}
// mapOptionDefaults {
ldap_access_order = ["host"];
ldap_schema = "IPA";
ldap_default_bind_dn = genso.ldap.bind.dn;
ldap_search_base = genso.ldap.baseDn;
@ -124,9 +144,11 @@ in {
dyndns_iface = ipa.dyndns.interface;
};
};
domainSettings = mapAlmostOptionDefaults {
domainSettings =
mapAlmostOptionDefaults {
ipa_hostname = cfg.ipa.hostName;
} // mapOptionDefaults {
}
// mapOptionDefaults {
enumerate = true;
ipa_domain = genso.domain;
krb5_realm = genso.realm;
@ -138,12 +160,12 @@ in {
in {
gensokyo-zone = {
krb5.servers.servers = mkMerge [
[ genso.host ]
(mkAfter [ "_srv" genso.canonHost ])
[genso.host]
(mkAfter ["_srv" genso.canonHost])
];
ldap.uris = {
servers = mkMerge [
(mkAfter [ "_srv" ])
(mkAfter ["_srv"])
genso.ldap.urls
];
};
@ -191,4 +213,3 @@ in {
};
};
}

View file

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

View file

@ -15,20 +15,23 @@
inherit (lib) generators;
cfg = config.services.sssd;
mkValuePrimitive = value:
if value == true then "True"
else if value == false then "False"
if value == true
then "True"
else if value == false
then "False"
else toString value;
toINI = generators.toINI {
mkKeyValue = generators.mkKeyValueDefault {
mkValueString = value:
if isList value then concatMapStringsSep ", " mkValuePrimitive value
if isList value
then concatMapStringsSep ", " mkValuePrimitive value
else mkValuePrimitive value;
} " = ";
};
primitiveType = with lib.types; oneOf [ str int bool ];
valueType = with lib.types; oneOf [ primitiveType (listOf primitiveType) ];
primitiveType = with lib.types; oneOf [str int bool];
valueType = with lib.types; oneOf [primitiveType (listOf primitiveType)];
settingsType = lib.types.attrsOf valueType;
serviceModule = { name, ... }: {
serviceModule = {name, ...}: {
options = with lib.types; {
enable = mkEnableOption "${name} service";
name = mkOption {
@ -38,20 +41,22 @@
};
settings = mkOption {
type = settingsType;
default = { };
default = {};
};
};
};
nssModule = { nixosConfig, ... }: {
nssModule = {nixosConfig, ...}: {
options = {
# TODO: passwd.enable = mkEnableOption "passwd" // { default = true; };
shadow.enable = mkEnableOption "shadow" // { default = nixosConfig.services.sssd.services.pam.enable; };
netgroup.enable = mkEnableOption "netgroup" // { default = true; };
shadow.enable = mkEnableOption "shadow" // {default = nixosConfig.services.sssd.services.pam.enable;};
netgroup.enable = mkEnableOption "netgroup" // {default = true;};
};
};
domainModule = { name, ... }: {
domainModule = {name, ...}: {
options = with lib.types; {
enable = mkEnableOption "domain" // {
enable =
mkEnableOption "domain"
// {
default = true;
};
domain = mkOption {
@ -63,17 +68,17 @@
};
};
};
domainLdapModule = { config, ... }: let
domainLdapModule = {config, ...}: let
cfg = config.ldap;
in {
options.ldap = with lib.types; {
extraAttrs.user = mkOption {
type = attrsOf str;
default = { };
default = {};
};
authtok = {
type = mkOption {
type = enum [ "password" "obfuscated_password" ];
type = enum ["password" "obfuscated_password"];
default = "password";
};
password = mkOption {
@ -87,7 +92,7 @@
passwordVar = mkOption {
type = str;
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) {
ldap_default_authtok_type = mkOptionDefault cfg.authtok.type;
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
);
};
extraAttrsConfig = mkIf (cfg.extraAttrs.user != { }) {
extraAttrsConfig = mkIf (cfg.extraAttrs.user != {}) {
ldap_user_extra_attrs = let
mkAttr = name: attr: "${name}:${attr}";
in mapAttrsToList mkAttr cfg.extraAttrs.user;
in
mapAttrsToList mkAttr cfg.extraAttrs.user;
};
in {
settings = mkMerge [
@ -119,7 +126,7 @@ in {
};
domains = mkOption {
type = attrsOf (submoduleWith {
modules = [ domainModule domainLdapModule ];
modules = [domainModule domainLdapModule];
specialArgs = {
nixosConfig = config;
};
@ -135,9 +142,10 @@ in {
};
};
services = let
mkServiceOption = name: { modules ? [ ] }: mkOption {
mkServiceOption = name: {modules ? []}:
mkOption {
type = submoduleWith {
modules = [ serviceModule ] ++ modules;
modules = [serviceModule] ++ modules;
specialArgs = {
inherit name;
nixosConfig = config;
@ -145,15 +153,16 @@ in {
};
};
services = {
nss = { modules = [ nssModule ]; };
pam = { };
ifp = { };
sudo = { };
autofs = { };
ssh = { };
pac = { };
nss = {modules = [nssModule];};
pam = {};
ifp = {};
sudo = {};
autofs = {};
ssh = {};
pac = {};
};
in mapAttrs mkServiceOption services;
in
mapAttrs mkServiceOption services;
settings = mkOption {
type = attrsOf settingsType;
};
@ -175,11 +184,14 @@ in {
domains = map (domain: domain.domain) enabledDomains;
};
};
domainSettings = map (domain: {
domainSettings =
map (domain: {
"domain/${domain.domain}" = mapAttrs (_: mkOptionDefault) domain.settings;
}) enabledDomains;
settings = [ defaultSettings serviceSettings ] ++ domainSettings;
in mkMerge settings;
})
enabledDomains;
settings = [defaultSettings serviceSettings] ++ domainSettings;
in
mkMerge settings;
services = {
nss.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);
mkExtraAttr = name: _: "+${name}";
in {
user_attributes = mkIf (extraUserAttrs != { }) (mkOptionDefault (
user_attributes = mkIf (extraUserAttrs != {}) (mkOptionDefault (
mapAttrsToList mkExtraAttr extraUserAttrs
));
};
sudo = { };
autofs = { };
ssh = { };
pac = { };
sudo = {};
autofs = {};
ssh = {};
pac = {};
};
configText = mkOptionDefault (toINI cfg.settings);
config = mkIf (cfg.configText != null) (mkAlmostOptionDefault cfg.configText);
};
config.system.nssDatabases = let
inherit (cfg.services) nss;
in mkIf cfg.enable {
${if options ? system.nssDatabases.netgroup then "netgroup" else null} = mkIf (nss.enable && nss.netgroup.enable) [ "sss" ];
in
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) (
mkForce [ "files" ]
mkForce ["files"]
);
};
}

View file

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

View file

@ -17,8 +17,15 @@
sortedVersions = sort (a: b: versionOlder a.version b.version) (attrValues cfg.versions);
prevVersionFor = version: let
olderVersions = filter (v: versionOlder v.version version) sortedVersions;
in if olderVersions != [] then last olderVersions else null;
versionModule = { config, name, ... }: {
in
if olderVersions != []
then last olderVersions
else null;
versionModule = {
config,
name,
...
}: {
options = with lib.types; {
version = mkOption {
type = str;
@ -40,14 +47,18 @@
);
};
};
fileModule = { config, name, ... }: {
fileModule = {
config,
name,
...
}: {
options = with lib.types; {
relativePath = mkOption {
type = str;
default = name;
};
type = mkOption {
type = enum [ "file" "directory" ];
type = enum ["file" "directory"];
default = "file";
};
versioned = mkOption {
@ -55,13 +66,16 @@
default = false;
};
target = mkOption {
type = enum [ "user" "shared" "game" ];
type = enum ["user" "shared" "game"];
default = "user";
};
mode = {
file = mkOption {
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 {
type = str;
@ -75,7 +89,7 @@
type = functionTo path;
};
srcStyle = mkOption {
type = enum [ "empty" "copy" "symlink" "symlink-shallow" ];
type = enum ["empty" "copy" "symlink" "symlink-shallow"];
default = "symlink";
};
workingPathFor = mkOption {
@ -88,7 +102,7 @@
type = functionTo (nullOr path);
};
initStyle = mkOption {
type = enum [ "none" "copy" "symlink" "symlink-shallow" ];
type = enum ["none" "copy" "symlink" "symlink-shallow"];
default = "copy";
};
setup = {
@ -106,32 +120,56 @@
versionPathFor = version: optionalString config.versioned "/${version}";
in {
init = mkOptionDefault (
if config.target == "game" then null
else if config.type == "directory" then "${emptyDir}"
else if hasSuffix ".json" config.relativePath then "${emptyJson}"
else if hasSuffix ".dll" config.relativePath || hasSuffix ".exe" config.relativePath then "${emptyExecutable}"
if config.target == "game"
then null
else if config.type == "directory"
then "${emptyDir}"
else if hasSuffix ".json" config.relativePath
then "${emptyJson}"
else if hasSuffix ".dll" config.relativePath || hasSuffix ".exe" config.relativePath
then "${emptyExecutable}"
else "${emptyFile}"
);
initFor = mkOptionDefault (
{ user, version }: config.init
{
user,
version,
}:
config.init
);
ownerFor = mkOptionDefault (user:
if config.target == "user" then user else "admin"
ownerFor = mkOptionDefault (
user:
if config.target == "user"
then user
else "admin"
);
srcPathFor = mkOptionDefault ({ user, version }:
srcPathFor = mkOptionDefault (
{
user,
version,
}:
{
shared = cfg.sharedDataDir + versionPathFor version;
user = cfg.dataDirFor user + versionPathFor version;
game = cfg.gameDirFor version;
}.${config.target} or (throw "unsupported target")
}
.${config.target}
or (throw "unsupported target")
+ "/${config.relativePath}"
);
workingPathFor = mkOptionDefault ({ user, version }:
cfg.workingDirFor { inherit user version; }
workingPathFor = mkOptionDefault (
{
user,
version,
}:
cfg.workingDirFor {inherit user version;}
+ "/${config.relativePath}"
);
# TODO: setup.shared and do inits seperately!
setup.script = { user, version }@args: let
setup.script = {
user,
version,
} @ args: let
owner = config.ownerFor user;
srcPath = config.srcPathFor args;
workingPath = config.workingPathFor args;
@ -148,13 +186,30 @@
fi
chown ${owner}:${cfg.group} ${escapeShellArg dest}
'';
mkStyle = { style, src }: if style != "none" && src == {
mkStyle = {
style,
src,
}:
if
style
!= "none"
&& src
== {
file = "${emptyFile}";
directory = "${emptyDir}";
}.${config.type} then "empty" else style;
doInit = { style, src, dest }: {
}
.${config.type}
then "empty"
else style;
doInit = {
style,
src,
dest,
}:
{
none = "true";
copy = {
copy =
{
file = ''
if [[ -L ${escapeShellArg dest} ]]; then
rm -f ${escapeShellArg dest}
@ -172,8 +227,10 @@
chown -R ${owner}:${cfg.group} ${escapeShellArg dest}
find ${escapeShellArg dest} -type f -exec chmod -m${config.mode.file} "{}" \;
'';
}.${config.type};
empty = {
}
.${config.type};
empty =
{
directory = ''
${mkdir dest}
'';
@ -182,7 +239,8 @@
chmod ${config.mode.file} ${escapeShellArg dest}
chown ${owner}:${cfg.group} ${escapeShellArg dest}
'';
}.${config.type};
}
.${config.type};
symlink = ''
if [[ -e ${escapeShellArg dest} && ! -L ${escapeShellArg dest} ]]; then
echo ERR: something is in the way of linking ${escapeShellArg dest} >&2
@ -190,16 +248,25 @@
fi
ln -sfT ${escapeShellArg src} ${escapeShellArg dest}
'';
symlink-shallow = {
symlink-shallow =
{
directory = ''
${mkdir dest}
ln -sf ${escapeShellArg src}/* ${escapeShellArg dest}/
'';
}.${config.type};
}.${mkStyle { inherit style src; }};
doSetup = { style, src, dest }: rec {
}
.${config.type};
}
.${mkStyle {inherit style src;}};
doSetup = {
style,
src,
dest,
}:
rec {
none = "true";
copy = {
copy =
{
file = ''
${empty}
'';
@ -209,8 +276,10 @@
chmod -m${config.mode.file} ${escapeShellArg dest}/*
fi
'';
}.${config.type};
empty = {
}
.${config.type};
empty =
{
directory = ''
chmod ${config.mode.dir} ${escapeShellArg dest}
chown ${owner}:${cfg.group} ${escapeShellArg dest}
@ -219,14 +288,18 @@
chmod ${config.mode.file} ${escapeShellArg dest}
chown ${owner}:${cfg.group} ${escapeShellArg dest}
'';
}.${config.type};
}
.${config.type};
symlink = "true";
symlink-shallow = {
symlink-shallow =
{
directory = ''
${mkdir.directory}
'';
}.${config.type};
}.${mkStyle { inherit style src; }};
}
.${config.type};
}
.${mkStyle {inherit style src;}};
init = doInit {
style = config.initStyle;
src = initPath;
@ -242,32 +315,41 @@
src = srcPath;
dest = workingPath;
};
checkFlag = {
file = {
checkFlag =
{
file =
{
none = "e";
copy = "f";
symlink = "L";
}.${config.initStyle};
directory = {
}
.${config.initStyle};
directory =
{
none = "e";
copy = "d";
symlink-shallow = "d";
symlink = "L";
}.${config.initStyle};
}.${config.type};
}
.${config.initStyle};
}
.${config.type};
checkParent = ''
if [[ ! -d ${escapeShellArg parentWorkingPath} ]]; then
echo ERR: parent of ${escapeShellArg workingPath} does not exist >&2
exit 1
fi
'';
check = if initPath != null then ''
check =
if initPath != null
then ''
if [[ ! -${checkFlag} ${escapeShellArg srcPath} ]]; then
${init}
else
${setup}
fi
'' else ''
''
else ''
if [[ ! -${checkFlag} ${escapeShellArg srcPath} ]]; then
echo ERR: src ${escapeShellArg srcPath} for ${escapeShellArg workingPath} does not exist >&2
exit 1
@ -280,7 +362,11 @@
'';
};
};
userModule = { config, name, ... }: {
userModule = {
config,
name,
...
}: {
options = with lib.types; {
name = mkOption {
type = str;
@ -294,7 +380,7 @@
};
emptyFile = pkgs.writeText "empty.txt" "";
emptyJson = pkgs.writeText "empty.json" "{}";
emptyDir = pkgs.runCommand "empty" { } ''
emptyDir = pkgs.runCommand "empty" {} ''
mkdir $out
'';
emptyExecutable = pkgs.writeTextFile {
@ -347,9 +433,11 @@
rmdir "%STEAM_BS_LIBRARY%"
mklink /D "%STEAM_BS_LIBRARY%" "%STEAM_BS_LAUNCH%"
'';
launch = ''
launch =
''
cd /d "%STEAM_BS_LIBRARY%"
'' + ''"%STEAM_BS_LIBRARY%\Beat Saber.exe"'';
''
+ ''"%STEAM_BS_LIBRARY%\Beat Saber.exe"'';
setup = ''
rmdir "%STEAM_BS_APPDATA%"
rmdir "%STEAM_BS_LIBRARY%"
@ -404,7 +492,10 @@
${launch}
${eof}
'';
beatsaber-user = { user, version }: ''
beatsaber-user = {
user,
version,
}: ''
set GENSO_STEAM_USER=${user}
set GENSO_STEAM_BS_VERSION=${version}
${vars}
@ -416,17 +507,23 @@
setx GENSO_STEAM_BS_VERSION Vanilla
'';
mksetupbeatsaber = { user, version }: let
setupFiles = mapAttrsToList (_: file: file.setup.script { inherit user version; }) cfg.files;
in pkgs.writeShellScript "setupbeatsaber-${user}-${version}" ''
mksetupbeatsaber = {
user,
version,
}: let
setupFiles = mapAttrsToList (_: file: file.setup.script {inherit user version;}) cfg.files;
in
pkgs.writeShellScript "setupbeatsaber-${user}-${version}" ''
set -eu
export PATH="$PATH:${makeBinPath [ pkgs.coreutils ]}"
export PATH="$PATH:${makeBinPath [pkgs.coreutils]}"
${concatStringsSep "\n" setupFiles}
'';
in {
options.services.steam.beatsaber = with lib.types; {
enable = mkEnableOption "beatsaber scripts";
setup = mkEnableOption "beatsaber data" // {
setup =
mkEnableOption "beatsaber data"
// {
default = accountSwitch.setup;
};
group = mkOption {
@ -438,7 +535,7 @@ in {
};
versions = mkOption {
type = attrsOf (submodule versionModule);
default = { };
default = {};
};
setupServiceNames = mkOption {
type = listOf str;
@ -446,7 +543,7 @@ in {
};
files = mkOption {
type = attrsOf (submodule fileModule);
default = { };
default = {};
};
users = mkOption {
type = attrsOf (submodule userModule);
@ -489,7 +586,11 @@ in {
};
workingDirFor = mkOption {
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;
allVersions = mapAttrsToList (_: version: version.version) cfg.versions;
gameFiles = {
"Beat Saber.exe" = { };
"UnityCrashHandler64.exe" = { };
"UnityPlayer.dll" = { };
"Beat Saber.exe" = {};
"UnityCrashHandler64.exe" = {};
"UnityPlayer.dll" = {};
"MonoBleedingEdge".type = "directory";
};
sharedFiles = {
@ -526,7 +627,7 @@ in {
};
"BeatSaberVersion.txt" = {
versioned = true;
initFor = { version, ... }: pkgs.writeText "BeatSaberVersion-${version}.txt" version;
initFor = {version, ...}: pkgs.writeText "BeatSaberVersion-${version}.txt" version;
};
"IPA.exe".versioned = true;
"IPA.exe.config".versioned = true;
@ -538,19 +639,19 @@ in {
#initStyle = "symlink-shallow";
#initFor = { version, ... }: cfg.gameDirFor version + "/${bsdata}";
initStyle = "none";
srcPathFor = { version, ... }: cfg.gameDirFor version + "/${bsdata}";
srcPathFor = {version, ...}: cfg.gameDirFor version + "/${bsdata}";
srcStyle = "symlink-shallow";
};
"${bsdata}/Managed" = {
type = "directory";
versioned = true;
initFor = { version, ... }: cfg.gameDirFor version + "/${bsdata}/Managed";
initFor = {version, ...}: cfg.gameDirFor version + "/${bsdata}/Managed";
};
# TODO: remove this to use multiple folders
"${bsdata}/CustomLevels" = {
type = "directory";
initStyle = "none";
srcPathFor = { ... }: cfg.sharedDataDir + "/CustomLevels";
srcPathFor = {...}: cfg.sharedDataDir + "/CustomLevels";
};
CustomAvatars = {
type = "directory";
@ -579,7 +680,7 @@ in {
"UserData/ScoreSaber/Replays" = {
type = "directory";
initStyle = "none";
srcPathFor = { ... }: cfg.sharedDataDir + "/Replays";
srcPathFor = {...}: cfg.sharedDataDir + "/Replays";
};
"UserData/Beat Saber IPA.json".versioned = true;
"UserData/SongCore/" = {
@ -619,8 +720,8 @@ in {
};
"UserData/Saber Factory/Cache".type = "directory";
"UserData/Saber Factory/Textures".type = "directory";
"UserData/BeatSaverDownloader.ini" = { };
"UserData/BeatSaverUpdater.json" = { };
"UserData/BeatSaverDownloader.ini" = {};
"UserData/BeatSaverUpdater.json" = {};
"UserData/SongDetailsCache.proto".versioned = true;
"UserData/SongDetailsCache.proto.Direct.etag".versioned = true;
};
@ -636,7 +737,7 @@ in {
srcStyle = "empty";
};
"UserData/Saber Factory/Presets".type = "directory";
"UserData/Saber Factory/TrailConfig.json" = { };
"UserData/Saber Factory/TrailConfig.json" = {};
"UserData/SongCore" = {
type = "directory";
versioned = true;
@ -658,17 +759,23 @@ in {
"UserData/JDFixer.json".versioned = true;
};
userDataFiles = [
"modprefs.ini" "Disabled Mods.json"
"modprefs.ini"
"Disabled Mods.json"
"AutoPauseStealth.json"
"BeatSaberMarkupLanguage.json"
"BeatSaviorData.ini"
"BetterSongList.json"
"BetterSongSearch.json"
"bookmarkedSongs.json" "votedSongs.json"
"bookmarkedSongs.json"
"votedSongs.json"
"Chroma.json"
"Cinema.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"
"EasyOffset.json"
"Enhancements.json"
@ -702,20 +809,25 @@ in {
"Tweaks55.json"
"UITweaks.json"
];
mapSharedFile = file: file // {
mapSharedFile = file:
file
// {
target = "shared";
};
mapGameFile = file: file // {
mapGameFile = file:
file
// {
target = "game";
};
mapUserDataFile = file: nameValuePair "UserData/${file}" {
mapUserDataFile = file:
nameValuePair "UserData/${file}" {
target = "user";
};
in {
defaultVersion = mkIf (allVersions != [ ]) (mkOptionDefault (
defaultVersion = mkIf (allVersions != []) (mkOptionDefault (
head allVersions
));
users = mapAttrs (_: user: { name = mkDefault user.name; }) bsUsers;
users = mapAttrs (_: user: {name = mkDefault user.name;}) bsUsers;
setupServiceNames = mkOptionDefault (
mapAttrsToList (_: user: "steam-setup-beatsaber-${user.name}.service") cfg.users
);
@ -736,11 +848,16 @@ in {
serviceConfig = {
Type = mkOptionDefault "oneshot";
RemainAfterExit = mkOptionDefault true;
ExecStart = mkMerge (mapAttrsToList (_: user:
(mapAttrsToList (_: version:
"${mksetupbeatsaber { user = user.name; inherit (version) version; }}"
) cfg.versions)
) cfg.users);
ExecStart = mkMerge (mapAttrsToList (
_: user: (mapAttrsToList (
_: version: "${mksetupbeatsaber {
user = user.name;
inherit (version) version;
}}"
)
cfg.versions)
)
cfg.users);
};
};
services.tmpfiles = let
@ -774,32 +891,50 @@ in {
"AppData"
"UserData"
];
setupFiles = [
setupFiles =
[
{
${cfg.sharedDataDir} = toplevel;
${cfg.binDir} = shared;
}
(listToAttrs (
map (folder:
map (
folder:
nameValuePair "${cfg.sharedDataDir}/${folder}" shared
) sharedFolders
)
sharedFolders
))
] ++ concatLists (mapAttrsToList (_: user:
]
++ concatLists (mapAttrsToList (
_: user:
singleton {
${cfg.dataDirFor user.name} = personal user.name;
"${cfg.dataDirFor user.name}/AppData" = 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.userWorkingDirFor user.name} = personal user.name;
${cfg.workingDirFor { user = user.name; inherit (version) version; }} = personal user.name;
}) cfg.versions
) cfg.users)
${
cfg.workingDirFor {
user = user.name;
inherit (version) version;
}
} =
personal user.name;
})
cfg.versions
)
cfg.users)
++ mapAttrsToList (_: version: {
"${cfg.sharedDataDir}/${version.version}" = shared;
}) cfg.versions;
versionBinFiles = mapAttrs' (_: version: nameValuePair
"${cfg.binDir}/${replaceStrings [ "." ] [ "_" ] version.version}.bat"
})
cfg.versions;
versionBinFiles =
mapAttrs' (
_: version:
nameValuePair
"${cfg.binDir}/${replaceStrings ["."] ["_"] version.version}.bat"
{
inherit (bin) owner group mode type;
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"
{
inherit (bin) owner group mode type;
@ -824,8 +963,10 @@ in {
};
};
}
) cfg.users;
binFiles = {
)
cfg.users;
binFiles =
{
"${cfg.binDir}/mount.bat" = {
inherit (bin) owner group mode type;
src = pkgs.writeTextFile {
@ -898,7 +1039,8 @@ in {
executable = true;
};
};
} // versionBinFiles
}
// versionBinFiles
// userBinFiles;
in {
enable = mkIf cfg.setup true;

View file

@ -24,7 +24,10 @@
...
}: let
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'Local = system.network.networks.local.enable or false;
has'Tail' = system.network.networks.tail.enable or false;
@ -48,26 +51,53 @@
forSystem = access.systemFor hostName;
forSystemHas = network: forSystem.access ? ${addressForAttr}.${network} || forSystem.access ? address4ForNetwork.${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)
else err;
local = forSystem.access.${addressForAttr}.local or forSystem.access.address4ForNetwork.local or fallback;
int = forSystem.access.${addressForAttr}.int or forSystem.access.address4ForNetwork.int or fallback;
tail = forSystem.access.${addressForAttr}.tail or fallback;
in {
in
{
lan =
if hostName == system.name then forSystem.access.${addressForAttr}.localhost
else if has'Int && forSystemHas "int" then int
else if has'Local && forSystemHas "local" then local
if hostName == system.name
then forSystem.access.${addressForAttr}.localhost
else if has'Int && forSystemHas "int"
then int
else if has'Local && forSystemHas "local"
then local
else fallback;
${if has'Local then "local" else null} = local;
${if has'Int then "int" else null} = int;
${if has'Tail then "tail" else null} = tail;
}.${network} or fallback;
${
if has'Local
then "local"
else null
} =
local;
${
if has'Int
then "int"
else null
} =
int;
${
if has'Tail
then "tail"
else null
} =
tail;
}
.${network}
or fallback;
in {
inherit (systemAccess)
hostnameForNetwork address4ForNetwork address6ForNetwork
systemForService systemForServiceId;
inherit
(systemAccess)
hostnameForNetwork
address4ForNetwork
address6ForNetwork
systemForService
systemForServiceId
;
addressForNetwork = systemAccess.${addressForAttr};
systemFor = hostName:
if hostName == config.networking.hostName
@ -91,34 +121,63 @@
getHostnameFor = hostName: network: let
forSystem = access.systemFor hostName;
err = throw "no hostname found between ${config.networking.hostName} and ${hostName}@${network}";
in {
in
{
lan =
if hostName == system.name then forSystem.access.hostnameForNetwork.localhost
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
if hostName == system.name
then forSystem.access.hostnameForNetwork.localhost
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;
${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'Tail then "tail" else null} = forSystem.access.hostnameForNetwork.tail or err;
}.${network} or 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'Tail
then "tail"
else null
} =
forSystem.access.hostnameForNetwork.tail or err;
}
.${network}
or err;
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,
serviceId ? null,
service ? system.exports.services.${serviceName},
portName ? "default",
network ? "lan",
scheme ? null,
getAddressFor ? "getAddressFor"
getAddressFor ? "getAddressFor",
}: let
port = service.ports.${portName};
scheme' = if scheme == null then port.protocol else scheme;
port' = if !port.enable
scheme' =
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"
else ":${toString port.port}";
host = access.${getAddressFor} system.name network;
url = "${scheme'}://${mkAddress6 host}${port'}";
in assert service.enable; url;
in
assert service.enable; url;
};
};
networking.tempAddresses = mkIf cfg.global.enable (
@ -142,7 +201,9 @@ in {
default = domain;
};
global.enable = mkEnableOption "globally routeable";
online.enable = mkEnableOption "a deployed machine" // {
online.enable =
mkEnableOption "a deployed machine"
// {
default = true;
};
hostnameForNetwork = mkOption {
@ -164,7 +225,12 @@ in {
];
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;
int = config.network.networks.int or noNetwork;
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;
notFound = throw "no system 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
hasService = system: findSingle (service: service.id == serviceId && service.enable) null multiple (attrValues system.config.exports.services) != null;
notFound = throw "no system 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;
in {
options.ci = with lib.types; {
enable = mkEnableOption "build via CI" // {
enable =
mkEnableOption "build via CI"
// {
default = config.type == "NixOS";
};
allowFailure = mkOption {

View file

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

View file

@ -1,8 +1,12 @@
{lib, gensokyo-zone, ...}: let
{
lib,
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (lib.attrsets) mapAttrs;
in {
config.exports.services.dnsmasq = { config, ... }: {
config.exports.services.dnsmasq = {config, ...}: {
id = mkAlmostOptionDefault "dns";
nixos = {
serviceAttr = "dnsmasq";

View file

@ -24,7 +24,12 @@
};
id = mkOption {
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 (lib.attrsets) mapAttrs;
in {

View file

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

View file

@ -1,14 +1,19 @@
{lib, gensokyo-zone, ...}: let
{
lib,
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (lib.modules) mkIf;
inherit (lib.attrsets) mapAttrs;
inherit (lib.lists) all imap0;
inherit (lib.trivial) id;
in {
config.exports.services.home-assistant = { config, ... }: let
config.exports.services.home-assistant = {config, ...}: let
mkAssertion = f: nixosConfig: let
cfg = nixosConfig.services.home-assistant;
in f nixosConfig cfg;
in
f nixosConfig cfg;
assertPort = nixosConfig: cfg: {
assertion = config.ports.default.port == cfg.config.http.server_port;
message = "port mismatch";
@ -16,7 +21,8 @@ in {
assertHomekitPort = let
portName = i: "homekit${toString i}";
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);
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 (lib.modules) mkIf;
in {
config.exports.services.invidious = { config, ... }: {
config.exports.services.invidious = {config, ...}: {
id = mkAlmostOptionDefault "yt";
nixos = {
serviceAttr = "invidious";

View file

@ -1,8 +1,12 @@
{lib, gensokyo-zone, ...}: let
{
lib,
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults;
inherit (lib.attrsets) mapAttrs;
in {
config.exports.services.kerberos = { config, ... }: {
config.exports.services.kerberos = {config, ...}: {
id = "krb5";
ports = mapAttrs (_: mapAlmostOptionDefaults) {
default = {

View file

@ -1,17 +1,23 @@
{lib, gensokyo-zone, ...}: let
{
lib,
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (lib.modules) mkIf;
inherit (lib.attrsets) mapAttrs;
in {
config.exports.services.keycloak = { config, ... }: {
config.exports.services.keycloak = {config, ...}: {
id = mkAlmostOptionDefault "sso";
nixos = {
serviceAttr = "keycloak";
assertions = let
mkAssertion = f: nixosConfig: let
cfg = nixosConfig.services.keycloak;
in f nixosConfig cfg;
in mkIf config.enable [
in
f nixosConfig cfg;
in
mkIf config.enable [
(mkAssertion (nixosConfig: cfg: {
assertion = config.ports.${cfg.protocol}.port == cfg.port;
message = "port mismatch";

View file

@ -1,8 +1,12 @@
{lib, gensokyo-zone, ...}: let
{
lib,
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (lib.attrsets) mapAttrs;
in {
config.exports.services.ldap = { config, ... }: {
config.exports.services.ldap = {config, ...}: {
defaults.port.listen = mkAlmostOptionDefault "lan";
ports = mapAttrs (_: mapAlmostOptionDefaults) {
default = {

View file

@ -1,12 +1,17 @@
{lib, gensokyo-zone, ...}: let
{
lib,
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (lib.modules) mkIf;
inherit (lib.attrsets) mapAttrs;
in {
config.exports.services.minecraft-bedrock-server = { config, ... }: let
config.exports.services.minecraft-bedrock-server = {config, ...}: let
mkAssertion = f: nixosConfig: let
cfg = nixosConfig.services.minecraft-bedrock-server;
in f nixosConfig cfg;
in
f nixosConfig cfg;
in {
nixos = {
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 (lib.modules) mkIf;
inherit (lib.attrsets) mapAttrs;
inherit (lib.lists) all imap0;
inherit (lib.trivial) id;
in {
config.exports.services.mosquitto = { config, ... }: {
config.exports.services.mosquitto = {config, ...}: {
id = mkAlmostOptionDefault "mqtt";
nixos = {
serviceAttr = "mosquitto";
@ -13,7 +17,8 @@ in {
(nixosConfig: let
cfg = nixosConfig.services.mosquitto;
portName = i:
if i == 0 then "default"
if i == 0
then "default"
else "listener${toString i}";
mkAssertPort = i: listener: config.ports.${portName i}.port or null == listener.port;
in {

View file

@ -1,8 +1,12 @@
{lib, gensokyo-zone, ...}: let
{
lib,
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (lib.attrsets) mapAttrs;
in {
config.exports.services.motion = { config, ... }: {
config.exports.services.motion = {config, ...}: {
defaults.port.listen = mkAlmostOptionDefault "lan";
ports = mapAttrs (_: mapAlmostOptionDefaults) {
default = {

View file

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

View file

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

View file

@ -1,17 +1,23 @@
{lib, gensokyo-zone, ...}: let
{
lib,
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (lib.modules) mkIf;
inherit (lib.attrsets) mapAttrs;
in {
config.exports.services.openwebrx = { config, ... }: {
config.exports.services.openwebrx = {config, ...}: {
id = mkAlmostOptionDefault "webrx";
nixos = {
serviceAttr = "openwebrx";
assertions = let
mkAssertion = f: nixosConfig: let
cfg = nixosConfig.services.openwebrx;
in f nixosConfig cfg;
in mkIf config.enable [
in
f nixosConfig cfg;
in
mkIf config.enable [
(mkAssertion (nixosConfig: cfg: {
assertion = config.ports.default.port == cfg.port;
message = "port mismatch";

View file

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

View file

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

View file

@ -1,7 +1,11 @@
{lib, gensokyo-zone, ...}: let
{
lib,
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
in {
config.exports.services.proxmox = { config, ... }: {
config.exports.services.proxmox = {config, ...}: {
id = mkAlmostOptionDefault "prox";
defaults.port.listen = mkAlmostOptionDefault "lan";
ports.default = mapAlmostOptionDefaults {

View file

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

View file

@ -12,7 +12,11 @@
inherit (lib.trivial) mapNullable;
inherit (lib.strings) concatStringsSep;
systemConfig = config;
portModule = {config, service, ...}: {
portModule = {
config,
service,
...
}: {
options = with lib.types; {
enable =
mkEnableOption "port"
@ -86,7 +90,7 @@
};
assertions = mkOption {
type = listOf (functionTo attrs);
default = [ ];
default = [];
};
};
defaults = {
@ -107,7 +111,8 @@
serviceConfig = getAttrFromPath config.nixos.serviceAttrPath;
mkAssertion = f: nixosConfig: let
cfg = serviceConfig nixosConfig;
in f nixosConfig cfg;
in
f nixosConfig cfg;
enableAssertion = nixosConfig: cfg: {
assertion = (! cfg ? enable) || (config.enable == cfg.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
res = a config;
in res // {
in
res
// {
message = "system.exports.${service.name}: " + res.message or "assertion failed";
};
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 (lib.modules) mkIf;
inherit (lib.attrsets) mapAttrs filterAttrs mapAttrsToList;
inherit (lib.lists) sort;
in {
config.exports.services.sshd = { config, ... }: let
config.exports.services.sshd = {config, ...}: let
mkAssertion = f: nixosConfig: let
cfg = nixosConfig.services.openssh;
in f nixosConfig cfg;
in
f nixosConfig cfg;
sorted = sort (a: b: a > b);
assertPorts = nixosConfig: cfg: let
nixosPorts = cfg.ports;

View file

@ -1,8 +1,12 @@
{lib, gensokyo-zone, ...}: let
{
lib,
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (lib.attrsets) mapAttrs;
in {
config.exports.services.unifi = { config, ... }: {
config.exports.services.unifi = {config, ...}: {
nixos.serviceAttr = "unifi";
defaults.port.listen = mkAlmostOptionDefault "lan";
ports = mapAttrs (_: mapAlmostOptionDefaults) {

View file

@ -1,8 +1,12 @@
{lib, gensokyo-zone, ...}: let
{
lib,
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (lib.modules) mkIf;
in {
config.exports.services.vouch-proxy = { config, ... }: {
config.exports.services.vouch-proxy = {config, ...}: {
id = mkAlmostOptionDefault "login";
defaults.port.listen = mkAlmostOptionDefault "localhost";
nixos = {

View file

@ -1,8 +1,12 @@
{lib, gensokyo-zone, ...}: let
{
lib,
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mapAlmostOptionDefaults mkAlmostOptionDefault;
inherit (lib.modules) mkIf;
in {
config.exports.services.zigbee2mqtt = { config, ... }: {
config.exports.services.zigbee2mqtt = {config, ...}: {
id = mkAlmostOptionDefault "z2m";
nixos = {
serviceAttr = "zigbee2mqtt";

View file

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

View file

@ -41,7 +41,7 @@ in {
};
modules = mkOption {
type = listOf unspecified;
default = [ ];
default = [];
};
specialArgs = mkOption {
type = attrs;
@ -101,10 +101,13 @@ in {
darwin = inputs.darwin.lib.darwinSystem;
macos = inputs.darwin.lib.darwinSystem;
}
.${string.toLower config.type} or null;
built = mkOptionDefault (mapNullable (builder: builder {
.${string.toLower config.type}
or null;
built = mkOptionDefault (mapNullable (builder:
builder {
inherit (config) system modules specialArgs;
}) config.builder);
})
config.builder);
specialArgs = {
inherit name inputs std Std meta;
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 (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkOptionDefault;
inherit (lib.trivial) mapNullable;
networkModule = { config, name, system, ... }: let
networkModule = {
config,
name,
system,
...
}: let
knownNetworks = {
local.slaac = {
enable = true;
@ -13,7 +23,9 @@
};
in {
options = with lib.types; {
enable = mkEnableOption "network" // {
enable =
mkEnableOption "network"
// {
default = true;
};
slaac = {
@ -65,12 +77,12 @@ in {
options.network = with lib.types; {
networks = mkOption {
type = attrsOf (submoduleWith {
modules = [ networkModule ];
modules = [networkModule];
specialArgs = {
system = config;
};
});
default = { };
default = {};
};
};
}

View file

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

View file

@ -1,4 +1,10 @@
{config, gensokyo-zone, lib, Std, ...}: let
{
config,
gensokyo-zone,
lib,
Std,
...
}: let
inherit (Std) UInt;
inherit (gensokyo-zone.lib) unmerged eui64 mkAlmostOptionDefault mapAlmostOptionDefaults;
inherit (lib.options) mkOption mkEnableOption;
@ -9,9 +15,16 @@
inherit (lib.trivial) mapNullable;
cfg = config.proxmox.network;
internalOffset = 32;
networkInterfaceModule = { config, name, system, ... }: {
networkInterfaceModule = {
config,
name,
system,
...
}: {
options = with lib.types; {
enable = mkEnableOption "network interface" // {
enable =
mkEnableOption "network interface"
// {
default = true;
};
bridge = mkOption {
@ -30,7 +43,7 @@
default = null;
};
address4 = mkOption {
type = nullOr (either (enum [ "dhcp" ]) str);
type = nullOr (either (enum ["dhcp"]) str);
default = null;
};
gateway4 = mkOption {
@ -38,7 +51,7 @@
default = null;
};
address6 = mkOption {
type = nullOr (either (enum [ "auto" "dhcp" ]) str);
type = nullOr (either (enum ["auto" "dhcp"]) str);
default = null;
};
gateway6 = mkOption {
@ -47,11 +60,13 @@
};
firewall.enable = mkEnableOption "firewall";
vm.model = mkOption {
type = enum [ "virtio" "e1000" "rtl8139" "vmxnet3" ];
type = enum ["virtio" "e1000" "rtl8139" "vmxnet3"];
default = "virtio";
};
mdns = {
enable = mkEnableOption "mDNS" // {
enable =
mkEnableOption "mDNS"
// {
default = config.local.enable && config.id == "net0";
};
};
@ -76,7 +91,9 @@
};
};
networkd = {
enable = mkEnableOption "systemd.network" // {
enable =
mkEnableOption "systemd.network"
// {
default = true;
};
name = mkOption {
@ -90,14 +107,20 @@
};
};
config = let
hasAddr4 = ! elem config.address4 [ null "dhcp" ];
hasAddr6 = ! elem config.address6 [ null "dhcp" "auto" ];
hasAddr4 = ! elem config.address4 [null "dhcp"];
hasAddr6 = ! elem config.address6 [null "dhcp" "auto"];
conf = {
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 (
if config.address6 == "auto" && config.slaac.postfix != null then "fd0a::${config.slaac.postfix}"
else if hasAddr6 then config.address6
if config.address6 == "auto" && config.slaac.postfix != null
then "fd0a::${config.slaac.postfix}"
else if hasAddr6
then config.address6
else null
);
};
@ -123,7 +146,7 @@
Type = mkOptionDefault "ether";
};
linkConfig = mkMerge [
(mkIf config.mdns.enable { Multicast = mkOptionDefault true; })
(mkIf config.mdns.enable {Multicast = mkOptionDefault true;})
];
networkConfig = mkMerge [
(mkIf (config.address6 == "auto") {
@ -134,17 +157,20 @@
})
];
address = mkMerge [
(mkIf (! elem config.address4 [ null "dhcp" ]) [ config.address4 ])
(mkIf (! elem config.address6 [ null "auto" "dhcp" ]) [ config.address6 ])
(mkIf (! elem config.address4 [null "dhcp"]) [config.address4])
(mkIf (! elem config.address6 [null "auto" "dhcp"]) [config.address6])
];
gateway = mkMerge [
(mkIf (config.gateway4 != null) [ config.gateway4 ])
(mkIf (config.gateway6 != null) [ config.gateway6 ])
(mkIf (config.gateway4 != null) [config.gateway4])
(mkIf (config.gateway6 != null) [config.gateway6])
];
DHCP = mkAlmostOptionDefault (
if config.address4 == "dhcp" && config.address6 == "dhcp" then "yes"
else if config.address6 == "dhcp" then "ipv6"
else if config.address4 == "dhcp" then "ipv4"
if config.address4 == "dhcp" && config.address6 == "dhcp"
then "yes"
else if config.address6 == "dhcp"
then "ipv6"
else if config.address4 == "dhcp"
then "ipv4"
else "no"
);
};
@ -157,11 +183,11 @@
address4 = mkAlmostOptionDefault "10.9.1.${toString index}/24";
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 (
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.networkSettings = {
domains = mkDefault [ ]; # int.${domain}?
domains = mkDefault []; # int.${domain}?
linkConfig.RequiredForOnline = false;
ipv6AcceptRAConfig = {
Token = mkOptionDefault "static:::${UInt.toHexLower index}";
@ -172,7 +198,8 @@
};
};
};
in mkMerge [
in
mkMerge [
conf
(mkIf config.internal.enable confInternal)
];
@ -181,12 +208,12 @@ in {
options.proxmox.network = with lib.types; {
interfaces = mkOption {
type = attrsOf (submoduleWith {
modules = [ networkInterfaceModule ];
modules = [networkInterfaceModule];
specialArgs = {
system = config;
};
});
default = { };
default = {};
};
internal = {
interface = mkOption {

View file

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

View file

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

View file

@ -25,7 +25,8 @@ in {
requireAuth = false;
};
proxy = {
upstream = mkIf barcodebuddy.enable (mkDefault
upstream = mkIf barcodebuddy.enable (
mkDefault
"nginx'proxied"
);
host = mkDefault serverName;
@ -48,7 +49,7 @@ in {
upstream = mkDefault nginx.virtualHosts.barcodebuddy.proxy.upstream;
host = mkDefault nginx.virtualHosts.barcodebuddy.proxy.host;
};
locations."/" = { config, ... }: {
locations."/" = {config, ...}: {
proxy = {
headers.enableRecommended = true;
redirect = {

View file

@ -5,8 +5,7 @@
gensokyo-zone,
lib,
...
}:
let
}: let
inherit (gensokyo-zone.lib) mapOptionDefaults;
inherit (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkMerge mkDefault mkOptionDefault;
@ -19,7 +18,11 @@ let
ssl_verify_client optional_no_ca;
'';
locations = {
"/" = { config, xvars, ... }: {
"/" = {
config,
xvars,
...
}: {
proxy = {
enable = true;
upstream = "freeipa";
@ -67,7 +70,9 @@ in {
};
};
kerberos = {
enable = mkEnableOption "proxy kerberos" // {
enable =
mkEnableOption "proxy kerberos"
// {
default = true;
};
ports = {
@ -177,7 +182,7 @@ in {
kticket4 = mkKrb5Upstream "ticket4";
};
servers = let
mkKrb5Server = tcpPort: udpPort: { name, ... }: {
mkKrb5Server = tcpPort: udpPort: {name, ...}: {
enable = mkDefault nginx.stream.upstreams.${name}.enable;
listen = {
tcp = mkIf (tcpPort != null) {
@ -187,7 +192,7 @@ in {
udp = mkIf (udpPort != null) {
enable = mkDefault kerberos.ports.${udpPort}.enable;
port = mkOptionDefault kerberos.ports.${udpPort}.port;
extraParameters = [ "udp" ];
extraParameters = ["udp"];
};
};
proxy.upstream = name;
@ -208,7 +213,8 @@ in {
ssl.cert.copyFromVhost = mkDefault "freeipa";
};
};
in mkMerge [
in
mkMerge [
conf
(mkIf nginx.ssl.preread.enable prereadConf)
(mkIf cfg.kerberos.enable kerberosConf)
@ -233,7 +239,11 @@ in {
name.shortServer = mkDefault "idp-ca";
locations."/" = mkMerge [
locations."/"
({config, virtualHost, ...}: {
({
config,
virtualHost,
...
}: {
proxy.ssl.host = virtualHost.serverName;
proxy.host = config.proxy.ssl.host;
})
@ -276,7 +286,7 @@ in {
};
freeipa'ldap'local = {
serverName = mkDefault ldap.localDomain;
serverAliases = [ ldap.intDomain ];
serverAliases = [ldap.intDomain];
ssl.cert.copyFromVhost = "freeipa'ldap";
globalRedirect = virtualHosts.freeipa'web'local.serverName;
local.enable = true;
@ -295,16 +305,18 @@ in {
inherit (nginx.stream.servers) krb5 kadmin kpasswd kticket4;
in {
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
) [ krb5 kticket4 kpasswd kadmin ]))
) [krb5 kticket4 kpasswd kadmin]))
(mkIf nginx.ssl.preread.enable [
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
) [ krb5 kticket4 kpasswd ]);
) [krb5 kticket4 kpasswd]);
};
};
}

View file

@ -13,8 +13,15 @@ in {
config.services.nginx = {
virtualHosts = let
proxyScheme = "https";
url = access.proxyUrlFor { serviceName = "freepbx"; portName = proxyScheme; };
ucpUrl = access.proxyUrlFor { serviceName = "freepbx"; portName = "ucp-ssl"; getAddressFor = "getAddress4For"; };
url = access.proxyUrlFor {
serviceName = "freepbx";
portName = proxyScheme;
};
ucpUrl = access.proxyUrlFor {
serviceName = "freepbx";
portName = "ucp-ssl";
getAddressFor = "getAddress4For";
};
ucpPath = "/socket.io";
# TODO: ports.asterisk/asterisk-ssl?
extraConfig = ''
@ -23,7 +30,7 @@ in {
proxy_busy_buffers_size 256k;
'';
locations = {
"/" = { xvars, ... }: {
"/" = {xvars, ...}: {
xvars.enable = true;
proxy = {
enable = true;
@ -33,7 +40,11 @@ in {
};
};
};
${ucpPath} = { xvars, virtualHost, ... }: {
${ucpPath} = {
xvars,
virtualHost,
...
}: {
proxy = {
enable = true;
websocket.enable = true;
@ -63,12 +74,12 @@ in {
listen' = {
ucp = {
port = mkDefault freepbx.ports.ucp.port;
extraParameters = [ "default_server" ];
extraParameters = ["default_server"];
};
ucpSsl = {
port = mkDefault freepbx.ports.ucp-ssl.port;
ssl = true;
extraParameters = [ "default_server" ];
extraParameters = ["default_server"];
};
};
proxy = {
@ -84,7 +95,7 @@ in {
};
freepbx'local = {
listen' = {
http = { };
http = {};
https.ssl = true;
ucp = {
port = mkDefault nginx.virtualHosts.freepbx'ucp.listen'.ucp.port;
@ -103,9 +114,11 @@ in {
};
};
config.networking.firewall = let
websocketPorts = virtualHost: [
websocketPorts = virtualHost:
[
virtualHost.listen'.ucp.port
] ++ optional virtualHost.listen'.ucpSsl.enable virtualHost.listen'.ucpSsl.port;
]
++ optional virtualHost.listen'.ucpSsl.enable virtualHost.listen'.ucpSsl.port;
in {
interfaces.local.allowedTCPPorts = websocketPorts nginx.virtualHosts.freepbx'local;
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";
};
};
luaAuthHost = { config, xvars, ... }: {
luaAuthHost = {
config,
xvars,
...
}: {
vouch.auth.lua = {
enable = true;
accessRequest = ''
@ -56,16 +60,20 @@ in {
proxied.enable = true;
local.denyGlobal = true;
};
grocy = mkMerge [ luaAuthHost {
grocy = mkMerge [
luaAuthHost
{
inherit name extraConfig locations;
vouch.enable = true;
proxy = {
upstream = mkIf grocy.enable (mkDefault
upstream = mkIf grocy.enable (
mkDefault
"nginx'proxied"
);
host = mkDefault serverName;
};
} ];
}
];
grocy'local = {
inherit name;
local.enable = mkDefault true;
@ -78,7 +86,9 @@ in {
proxy.enable = true;
};
};
grocy'local'int = mkMerge [ luaAuthHost {
grocy'local'int = mkMerge [
luaAuthHost
{
# internal proxy workaround for http2 lua compat issues
serverName = serverName'local;
inherit name extraConfig locations;
@ -91,7 +101,8 @@ in {
enable = true;
localSso.enable = true;
};
} ];
}
];
};
};
}

View file

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

View file

@ -19,7 +19,7 @@ in {
addr = mkDefault "localhost";
port = mkIf cfg.enable (mkDefault cfg.port);
};
service = { upstream, ... }: {
service = {upstream, ...}: {
enable = mkIf upstream.servers.local.enable (mkDefault false);
accessService = {
name = "invidious";
@ -40,7 +40,7 @@ in {
proxy_redirect off;
proxy_buffering off;
'';
location = { xvars, ... }: {
location = {xvars, ...}: {
proxy = {
enable = true;
websocket.enable = true;
@ -61,7 +61,11 @@ in {
upstream = "nginx'proxied";
host = mkDefault nginx.virtualHosts.invidious'int.serverName;
};
locations."/" = { xvars, virtualHost, ... }: {
locations."/" = {
xvars,
virtualHost,
...
}: {
proxy.enable = true;
extraConfig = ''
proxy_http_version 1.1;
@ -72,7 +76,11 @@ in {
'';
};
};
invidious'int = { config, xvars, ... }: {
invidious'int = {
config,
xvars,
...
}: {
serverName = "@invidious_internal";
proxied.enable = true;
local.denyGlobal = true;
@ -115,7 +123,7 @@ in {
};
inherit extraConfig;
};
invidious'local = { xvars, ... }: {
invidious'local = {xvars, ...}: {
local.enable = true;
ssl.cert.copyFromVhost = "invidious";
proxy = {

View file

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

View file

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

View file

@ -4,8 +4,7 @@
gensokyo-zone,
access,
...
}:
let
}: let
inherit (gensokyo-zone.lib) mkAlmostOptionDefault;
inherit (lib.options) mkOption;
inherit (lib.modules) mkIf mkOptionDefault;
@ -42,7 +41,7 @@ in {
inherit (nginx.stream.upstreams.ldaps.servers.access.accessService) system name id port;
};
};
ldap = { upstream, ... }: {
ldap = {upstream, ...}: {
enable = mkIf upstream.servers.ldaps.enable false;
accessService = {
inherit (nginx.stream.upstreams.ldap.servers.access.accessService) system name id port;
@ -54,7 +53,7 @@ in {
name = "ldap";
};
};
ldaps = { config, ... }: {
ldaps = {config, ...}: {
enable = mkAlmostOptionDefault config.servers.access.enable;
servers.access = {
accessService = {

View file

@ -4,8 +4,7 @@
access,
gensokyo-zone,
...
}:
let
}: let
inherit (gensokyo-zone.lib) mkAlmostOptionDefault;
inherit (lib.modules) mkIf mkOptionDefault;
inherit (config.services) nginx;
@ -42,7 +41,9 @@ in {
};
};
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;
cfg = config.services.nginx;
in {

View file

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

View file

@ -16,7 +16,7 @@ in {
addr = mkDefault "localhost";
port = mkDefault cfg.port;
};
access = { upstream, ... }: {
access = {upstream, ...}: {
enable = mkDefault (!upstream.servers.local.enable);
accessService.name = "plex";
};
@ -65,12 +65,12 @@ in {
inherit name locations extraConfig;
proxy.upstream = mkDefault upstreamName;
listen' = {
http = { };
http = {};
https.ssl = true;
external = {
enable = mkDefault false;
port = mkDefault 32400;
extraParameters = [ "default_server" ];
extraParameters = ["default_server"];
};
};
};
@ -88,7 +88,8 @@ in {
};
config.networking.firewall.allowedTCPPorts = let
inherit (nginx.virtualHosts.plex) listen';
in mkIf listen'.external.enable [
in
mkIf listen'.external.enable [
listen'.external.port
];
}

View file

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

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