mirror of
https://github.com/gensokyo-zone/infrastructure.git
synced 2026-02-09 12:29:19 -08:00
chore: nf-fmt-nix
This commit is contained in:
parent
7486517713
commit
9903866044
160 changed files with 4570 additions and 3019 deletions
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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"];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
inherit sopsFile;
|
||||
path = mkDefault "${cfg.stateDir}/${name}.nft";
|
||||
}) cfg.ranges;
|
||||
in mkIf cfg.enable sopsSecrets;
|
||||
sopsSecrets = mapAttrs' (name: _:
|
||||
nameValuePair (mkSopsName name) {
|
||||
inherit sopsFile;
|
||||
path = mkDefault "${cfg.stateDir}/${name}.nft";
|
||||
})
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
{ gensokyo-zone, ... }: {
|
||||
{gensokyo-zone, ...}: {
|
||||
config.lib = {
|
||||
inherit gensokyo-zone;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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,13 +147,18 @@ in {
|
|||
};
|
||||
redis = let
|
||||
redis = config.services.redis.servers.${cfg.redis.server};
|
||||
in mkIf (cfg.redis.server != null) {
|
||||
enable = mkAlmostOptionDefault redis.enable;
|
||||
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;
|
||||
};
|
||||
in
|
||||
mkIf (cfg.redis.server != null) {
|
||||
enable = mkAlmostOptionDefault redis.enable;
|
||||
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;
|
||||
};
|
||||
};
|
||||
conf.users.users.barcodebuddy = {
|
||||
isSystemUser = true;
|
||||
|
|
@ -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)];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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,67 +36,70 @@ in {
|
|||
config.services.sssd = let
|
||||
inherit (config.services) sssd;
|
||||
ipaDebugLevel = 65510;
|
||||
in mkIf cfg.enable {
|
||||
debugLevel = mkAlmostOptionDefault ipaDebugLevel;
|
||||
domains = {
|
||||
${cfg.domain} = {
|
||||
ldap.extraAttrs.user = {
|
||||
mail = "mail";
|
||||
sn = "sn";
|
||||
givenname = "givenname";
|
||||
telephoneNumber = "telephoneNumber";
|
||||
lock = "nsaccountlock";
|
||||
};
|
||||
settings = mapOptionDefaults {
|
||||
id_provider = "ipa";
|
||||
auth_provider = "ipa";
|
||||
access_provider = "ipa";
|
||||
chpass_provider = "ipa";
|
||||
ipa_domain = cfg.domain;
|
||||
in
|
||||
mkIf cfg.enable {
|
||||
debugLevel = mkAlmostOptionDefault ipaDebugLevel;
|
||||
domains = {
|
||||
${cfg.domain} = {
|
||||
ldap.extraAttrs.user = {
|
||||
mail = "mail";
|
||||
sn = "sn";
|
||||
givenname = "givenname";
|
||||
telephoneNumber = "telephoneNumber";
|
||||
lock = "nsaccountlock";
|
||||
};
|
||||
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}";
|
||||
ipa_hostname = "${config.networking.hostName}.${cfg.domain}";
|
||||
|
||||
cache_credentials = cfg.cacheCredentials;
|
||||
cache_credentials = cfg.cacheCredentials;
|
||||
|
||||
krb5_store_password_if_offline = cfg.offlinePasswords;
|
||||
krb5_store_password_if_offline = cfg.offlinePasswords;
|
||||
|
||||
dyndns_update = cfg.dyndns.enable;
|
||||
dyndns_update = cfg.dyndns.enable;
|
||||
|
||||
dyndns_iface = cfg.dyndns.interface;
|
||||
dyndns_iface = cfg.dyndns.interface;
|
||||
|
||||
ldap_tls_cacert = "/etc/ipa/ca.crt";
|
||||
} // {
|
||||
krb5_realm = mkIf (toLower cfg.domain != toLower cfg.realm) (mkOptionDefault cfg.realm);
|
||||
ldap_tls_cacert = "/etc/ipa/ca.crt";
|
||||
}
|
||||
// {
|
||||
krb5_realm = mkIf (toLower cfg.domain != toLower cfg.realm) (mkOptionDefault cfg.realm);
|
||||
};
|
||||
};
|
||||
};
|
||||
services = {
|
||||
nss.settings = mapOptionDefaults {
|
||||
homedir_substring = "/home";
|
||||
};
|
||||
pam.settings = mapOptionDefaults {
|
||||
pam_pwd_expiration_warning = 3;
|
||||
pam_verbosity = 3;
|
||||
};
|
||||
sudo = {
|
||||
enable = mkAlmostOptionDefault true;
|
||||
settings = mapOptionDefaults {
|
||||
debug_level = ipaDebugLevel;
|
||||
};
|
||||
};
|
||||
ssh.enable = mkAlmostOptionDefault true;
|
||||
ifp = {
|
||||
enable = mkAlmostOptionDefault true;
|
||||
settings = mapOptionDefaults {
|
||||
allowed_uids = cfg.ifpAllowedUids;
|
||||
};
|
||||
};
|
||||
};
|
||||
configText = mkIf (cfg.overrideConfigs.sssd) (mkAlmostOptionDefault null);
|
||||
config = mkIf (sssd.configText != null) (mkAlmostForce sssd.configText);
|
||||
};
|
||||
services = {
|
||||
nss.settings = mapOptionDefaults {
|
||||
homedir_substring = "/home";
|
||||
};
|
||||
pam.settings = mapOptionDefaults {
|
||||
pam_pwd_expiration_warning = 3;
|
||||
pam_verbosity = 3;
|
||||
};
|
||||
sudo = {
|
||||
enable = mkAlmostOptionDefault true;
|
||||
settings = mapOptionDefaults {
|
||||
debug_level = ipaDebugLevel;
|
||||
};
|
||||
};
|
||||
ssh.enable = mkAlmostOptionDefault true;
|
||||
ifp = {
|
||||
enable = mkAlmostOptionDefault true;
|
||||
settings = mapOptionDefaults {
|
||||
allowed_uids = cfg.ifpAllowedUids;
|
||||
};
|
||||
};
|
||||
};
|
||||
configText = mkIf (cfg.overrideConfigs.sssd) (mkAlmostOptionDefault null);
|
||||
config = mkIf (sssd.configText != null) (mkAlmostForce sssd.configText);
|
||||
};
|
||||
config.security.krb5 = mkIf cfg.enable {
|
||||
enable = mkAlmostForce false;
|
||||
package = mkAlmostOptionDefault pkgs.krb5Full;
|
||||
|
|
@ -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) {
|
||||
text = mkForce (format.generate "krb5.conf" krb5.settings).text;
|
||||
};
|
||||
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;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,32 +70,36 @@ 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 {
|
||||
db_library = "kldap";
|
||||
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);
|
||||
});
|
||||
db_library = "kldap";
|
||||
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 { });
|
||||
};
|
||||
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}" ];
|
||||
} // {
|
||||
database_module = mkOptionDefault "genso-${cfg.db.backend}";
|
||||
auth_to_local_names = mkIf (cfg.authToLocalNames != { }) (mkDefault (subsection cfg.authToLocalNames));
|
||||
${cfg.realm} = mkIf ipa.enable (mkForce {});
|
||||
};
|
||||
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}"];
|
||||
}
|
||||
// {
|
||||
database_module = mkOptionDefault "genso-${cfg.db.backend}";
|
||||
auth_to_local_names = mkIf (cfg.authToLocalNames != {}) (mkDefault (subsection cfg.authToLocalNames));
|
||||
};
|
||||
domain_realm = mapOptionDefaults {
|
||||
${cfg.domain} = cfg.realm;
|
||||
".${cfg.domain}" = cfg.realm;
|
||||
|
|
@ -112,7 +122,8 @@ in {
|
|||
url = "https://ipa.${cfg.domain}/ipa/config/ca.crt";
|
||||
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 = [
|
||||
"root"
|
||||
] ++ config.users.groups.wheel.members;
|
||||
ifpAllowedUids =
|
||||
[
|
||||
"root"
|
||||
]
|
||||
++ config.users.groups.wheel.members;
|
||||
dyndns.enable = mkDefault false;
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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 = {
|
||||
string = toString (UInt.FromHex config.xuid);
|
||||
int = toString config.xuid;
|
||||
}.${typeOf config.xuid};
|
||||
xuid =
|
||||
{
|
||||
string = toString (UInt.FromHex config.xuid);
|
||||
int = toString config.xuid;
|
||||
}
|
||||
.${typeOf config.xuid};
|
||||
in {
|
||||
settings = {
|
||||
name = mkOptionDefault config.name;
|
||||
|
|
@ -41,16 +49,22 @@ 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" // {
|
||||
default = true;
|
||||
};
|
||||
enable =
|
||||
mkEnableOption "pack"
|
||||
// {
|
||||
default = true;
|
||||
};
|
||||
package = mkOption {
|
||||
type = nullOr package;
|
||||
default = null;
|
||||
|
|
@ -59,90 +73,194 @@ 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 {
|
||||
string = splitString "." config.version;
|
||||
list = config.version;
|
||||
}.${typeOf config.version};
|
||||
version =
|
||||
mkOptionDefault
|
||||
{
|
||||
string = splitString "." config.version;
|
||||
list = config.version;
|
||||
}
|
||||
.${typeOf config.version};
|
||||
};
|
||||
};
|
||||
};
|
||||
in { config, gensokyo-zone, lib, pkgs, ... }: let
|
||||
# see https://gist.github.com/datakurre/cfdf627fb23ed8ff62bb7b3520b92674
|
||||
inherit (gensokyo-zone.lib) mapOptionDefaults;
|
||||
inherit (lib.options) mkOption mkPackageOption;
|
||||
inherit (lib.modules) mkIf mkMerge mkOptionDefault;
|
||||
inherit (lib.attrsets) filterAttrs mapAttrsToList;
|
||||
inherit (lib.lists) optional;
|
||||
inherit (lib.strings) concatStringsSep;
|
||||
inherit (lib.trivial) boolToString;
|
||||
inherit (lib.meta) getExe;
|
||||
inherit (builtins) toJSON;
|
||||
cfg = config.services.minecraft-bedrock-server;
|
||||
in
|
||||
{
|
||||
config,
|
||||
gensokyo-zone,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
# see https://gist.github.com/datakurre/cfdf627fb23ed8ff62bb7b3520b92674
|
||||
inherit (gensokyo-zone.lib) mapOptionDefaults;
|
||||
inherit (lib.options) mkOption mkPackageOption;
|
||||
inherit (lib.modules) mkIf mkMerge mkOptionDefault;
|
||||
inherit (lib.attrsets) filterAttrs mapAttrsToList;
|
||||
inherit (lib.lists) optional;
|
||||
inherit (lib.strings) concatStringsSep;
|
||||
inherit (lib.trivial) boolToString;
|
||||
inherit (lib.meta) getExe;
|
||||
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 {
|
||||
options.services.minecraft-bedrock-server = with lib.types; {
|
||||
enable = mkOption {
|
||||
type = bool;
|
||||
default = false;
|
||||
description = ''
|
||||
If enabled, start a Minecraft Bedrock Server. The server
|
||||
data will be loaded from and saved to
|
||||
<option>services.minecraft-bedrock-server.dataDir</option>.
|
||||
'';
|
||||
serverPropertiesFile = pkgs.writeText "server.properties" (''
|
||||
# server.properties managed by NixOS configuration
|
||||
''
|
||||
+ concatStringsSep "\n" (mapAttrsToList
|
||||
(n: v: "${n}=${cfgToString v}")
|
||||
cfg.serverProperties));
|
||||
in {
|
||||
options.services.minecraft-bedrock-server = with lib.types; {
|
||||
enable = mkOption {
|
||||
type = bool;
|
||||
default = false;
|
||||
description = ''
|
||||
If enabled, start a Minecraft Bedrock Server. The server
|
||||
data will be loaded from and saved to
|
||||
<option>services.minecraft-bedrock-server.dataDir</option>.
|
||||
'';
|
||||
};
|
||||
|
||||
dataDir = mkOption {
|
||||
type = path;
|
||||
default = "/var/lib/minecraft-bedrock";
|
||||
description = ''
|
||||
Directory to store Minecraft Bedrock database and other state/data files.
|
||||
'';
|
||||
};
|
||||
|
||||
serverProperties = mkOption {
|
||||
type = attrsOf (oneOf [bool int str float]);
|
||||
example = literalExample ''
|
||||
{
|
||||
server-name = "Dedicated Server";
|
||||
gamemode = "survival";
|
||||
difficulty = "easy";
|
||||
allow-cheats = false;
|
||||
max-players = 10;
|
||||
online-mode = false;
|
||||
white-list = false;
|
||||
server-port = 19132;
|
||||
server-portv6 = 19133;
|
||||
view-distance = 32;
|
||||
tick-distance = 4;
|
||||
player-idle-timeout = 30;
|
||||
max-threads = 8;
|
||||
level-name = "Bedrock level";
|
||||
level-seed = "";
|
||||
default-player-permission-level = "member";
|
||||
texturepack-required = false;
|
||||
content-log-file-enabled = false;
|
||||
compression-threshold = 1;
|
||||
server-authoritative-movement = "server-auth";
|
||||
player-movement-score-threshold = 20;
|
||||
player-movement-distance-threshold = 0.3;
|
||||
player-movement-duration-threshold-in-ms = 500;
|
||||
correct-player-movement = false;
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
Minecraft Bedrock server properties for the server.properties file.
|
||||
'';
|
||||
};
|
||||
|
||||
package =
|
||||
mkPackageOption pkgs "minecraft-bedrock-server" {}
|
||||
// {
|
||||
description = "Version of minecraft-bedrock-server to run.";
|
||||
};
|
||||
|
||||
openFirewall = mkOption {
|
||||
type = bool;
|
||||
default = false;
|
||||
};
|
||||
|
||||
user = mkOption {
|
||||
type = str;
|
||||
default = "minecraft-bedrock";
|
||||
};
|
||||
group = mkOption {
|
||||
type = str;
|
||||
default = cfg.user;
|
||||
};
|
||||
|
||||
allowPlayers = mkOption {
|
||||
type = nullOr (attrsOf (submoduleWith {
|
||||
modules = [allowListModule];
|
||||
specialArgs = {
|
||||
inherit gensokyo-zone;
|
||||
nixosConfig = config;
|
||||
};
|
||||
}));
|
||||
default = null;
|
||||
};
|
||||
|
||||
allowList = mkOption {
|
||||
type = nullOr path;
|
||||
};
|
||||
|
||||
permissions = mkOption {
|
||||
type = nullOr path;
|
||||
};
|
||||
|
||||
packs = mkOption {
|
||||
type = attrsOf (submoduleWith {
|
||||
modules = [packModule];
|
||||
specialArgs = {
|
||||
inherit gensokyo-zone;
|
||||
nixosConfig = config;
|
||||
};
|
||||
});
|
||||
default = {};
|
||||
};
|
||||
};
|
||||
|
||||
dataDir = mkOption {
|
||||
type = path;
|
||||
default = "/var/lib/minecraft-bedrock";
|
||||
description = ''
|
||||
Directory to store Minecraft Bedrock database and other state/data files.
|
||||
'';
|
||||
};
|
||||
|
||||
serverProperties = mkOption {
|
||||
type = attrsOf (oneOf [ bool int str float ]);
|
||||
example = literalExample ''
|
||||
{
|
||||
config = let
|
||||
confService.services.minecraft-bedrock-server = {
|
||||
serverProperties = mapOptionDefaults {
|
||||
server-name = "Dedicated Server";
|
||||
gamemode = "survival";
|
||||
difficulty = "easy";
|
||||
allow-cheats = false;
|
||||
max-players = 10;
|
||||
online-mode = false;
|
||||
white-list = false;
|
||||
allow-list = cfg.allowList != null;
|
||||
server-port = 19132;
|
||||
server-portv6 = 19133;
|
||||
view-distance = 32;
|
||||
|
|
@ -160,191 +278,118 @@ in {
|
|||
player-movement-distance-threshold = 0.3;
|
||||
player-movement-duration-threshold-in-ms = 500;
|
||||
correct-player-movement = false;
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
Minecraft Bedrock server properties for the server.properties file.
|
||||
'';
|
||||
};
|
||||
|
||||
package = mkPackageOption pkgs "minecraft-bedrock-server" { }// {
|
||||
description = "Version of minecraft-bedrock-server to run.";
|
||||
};
|
||||
|
||||
openFirewall = mkOption {
|
||||
type = bool;
|
||||
default = false;
|
||||
};
|
||||
|
||||
user = mkOption {
|
||||
type = str;
|
||||
default = "minecraft-bedrock";
|
||||
};
|
||||
group = mkOption {
|
||||
type = str;
|
||||
default = cfg.user;
|
||||
};
|
||||
|
||||
allowPlayers = mkOption {
|
||||
type = nullOr (attrsOf (submoduleWith {
|
||||
modules = [ allowListModule ];
|
||||
specialArgs = {
|
||||
inherit gensokyo-zone;
|
||||
nixosConfig = config;
|
||||
};
|
||||
}));
|
||||
default = null;
|
||||
};
|
||||
|
||||
allowList = mkOption {
|
||||
type = nullOr path;
|
||||
};
|
||||
|
||||
permissions = mkOption {
|
||||
type = nullOr path;
|
||||
};
|
||||
|
||||
packs = mkOption {
|
||||
type = attrsOf (submoduleWith {
|
||||
modules = [ packModule ];
|
||||
specialArgs = {
|
||||
inherit gensokyo-zone;
|
||||
nixosConfig = config;
|
||||
};
|
||||
});
|
||||
default = { };
|
||||
};
|
||||
};
|
||||
|
||||
config = let
|
||||
confService.services.minecraft-bedrock-server = {
|
||||
serverProperties = mapOptionDefaults {
|
||||
server-name = "Dedicated Server";
|
||||
gamemode = "survival";
|
||||
difficulty = "easy";
|
||||
allow-cheats = false;
|
||||
max-players = 10;
|
||||
online-mode = false;
|
||||
allow-list = cfg.allowList != null;
|
||||
server-port = 19132;
|
||||
server-portv6 = 19133;
|
||||
view-distance = 32;
|
||||
tick-distance = 4;
|
||||
player-idle-timeout = 30;
|
||||
max-threads = 8;
|
||||
level-name = "Bedrock level";
|
||||
level-seed = "";
|
||||
default-player-permission-level = "member";
|
||||
texturepack-required = false;
|
||||
content-log-file-enabled = false;
|
||||
compression-threshold = 1;
|
||||
server-authoritative-movement = "server-auth";
|
||||
player-movement-score-threshold = 20;
|
||||
player-movement-distance-threshold = 0.3;
|
||||
player-movement-duration-threshold-in-ms = 500;
|
||||
correct-player-movement = false;
|
||||
allowList = let
|
||||
allowPlayers = mapAttrsToList (_: allow: allow.settings) cfg.allowPlayers;
|
||||
allowListJson = pkgs.writeText "minecraft-bedrock-server-allowlist.json" (
|
||||
toJSON allowPlayers
|
||||
);
|
||||
in
|
||||
mkOptionDefault (
|
||||
if cfg.allowPlayers != null
|
||||
then allowListJson
|
||||
else null
|
||||
);
|
||||
permissions = let
|
||||
permissions = mapAttrsToList (_: allow: allow.permissionSettings) cfg.allowPlayers;
|
||||
permissionsJson = pkgs.writeText "minecraft-bedrock-server-permissions.json" (
|
||||
toJSON permissions
|
||||
);
|
||||
in
|
||||
mkOptionDefault (
|
||||
if cfg.allowPlayers != null
|
||||
then permissionsJson
|
||||
else null
|
||||
);
|
||||
};
|
||||
allowList = let
|
||||
allowPlayers = mapAttrsToList (_: allow: allow.settings) cfg.allowPlayers;
|
||||
allowListJson = pkgs.writeText "minecraft-bedrock-server-allowlist.json" (
|
||||
toJSON allowPlayers
|
||||
);
|
||||
in mkOptionDefault (
|
||||
if cfg.allowPlayers != null then allowListJson
|
||||
else null
|
||||
);
|
||||
permissions = let
|
||||
permissions = mapAttrsToList (_: allow: allow.permissionSettings) cfg.allowPlayers;
|
||||
permissionsJson = pkgs.writeText "minecraft-bedrock-server-permissions.json" (
|
||||
toJSON permissions
|
||||
);
|
||||
in mkOptionDefault (
|
||||
if cfg.allowPlayers != null then permissionsJson
|
||||
else null
|
||||
);
|
||||
};
|
||||
conf.users.users.${cfg.user} = {
|
||||
inherit (cfg) group;
|
||||
description = "Minecraft server service user";
|
||||
home = cfg.dataDir;
|
||||
createHome = true;
|
||||
isSystemUser = true;
|
||||
};
|
||||
conf.users.groups.${cfg.group} = {};
|
||||
conf.users.users.${cfg.user} = {
|
||||
inherit (cfg) group;
|
||||
description = "Minecraft server service user";
|
||||
home = cfg.dataDir;
|
||||
createHome = true;
|
||||
isSystemUser = true;
|
||||
};
|
||||
conf.users.groups.${cfg.group} = {};
|
||||
|
||||
conf.systemd.services.minecraft-bedrock-server = {
|
||||
description = "Minecraft Bedrock Server Service";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "network.target" ];
|
||||
conf.systemd.services.minecraft-bedrock-server = {
|
||||
description = "Minecraft Bedrock Server Service";
|
||||
wantedBy = ["multi-user.target"];
|
||||
after = ["network.target"];
|
||||
|
||||
serviceConfig = {
|
||||
BindReadOnlyPaths = let
|
||||
packageResources = map (subpath: "${cfg.package}/var/lib/minecraft-bedrock/${subpath}:${cfg.dataDir}/${subpath}") ([
|
||||
"definitions/attachables"
|
||||
"definitions/biomes"
|
||||
"definitions/feature_rules"
|
||||
"definitions/features"
|
||||
"definitions/persona"
|
||||
"definitions/sdl_layouts"
|
||||
"definitions/spawn_groups"
|
||||
"resource_packs/vanilla"
|
||||
"resource_packs/chemistry"
|
||||
"config/default"
|
||||
"bedrock_server_symbols.debug"
|
||||
"env-vars"
|
||||
] ++ 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 != { }) [
|
||||
"${packsJsonPath}:${cfg.dataDir}/worlds/${cfg.serverProperties.level-name}/${jsonName}"
|
||||
serviceConfig = {
|
||||
BindReadOnlyPaths = let
|
||||
packageResources = map (subpath: "${cfg.package}/var/lib/minecraft-bedrock/${subpath}:${cfg.dataDir}/${subpath}") ([
|
||||
"definitions/attachables"
|
||||
"definitions/biomes"
|
||||
"definitions/feature_rules"
|
||||
"definitions/features"
|
||||
"definitions/persona"
|
||||
"definitions/sdl_layouts"
|
||||
"definitions/spawn_groups"
|
||||
"resource_packs/vanilla"
|
||||
"resource_packs/chemistry"
|
||||
"config/default"
|
||||
"bedrock_server_symbols.debug"
|
||||
"env-vars"
|
||||
]
|
||||
++ 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 != {}) [
|
||||
"${packsJsonPath}:${cfg.dataDir}/worlds/${cfg.serverProperties.level-name}/${jsonName}"
|
||||
];
|
||||
mapWorldPacks = packs: let
|
||||
enabledPacks = filterAttrs (_: pack: pack.enable && pack.package != null) packs;
|
||||
mapPackPath = _: pack: let
|
||||
subDir = "${pack.packType}/${pack.packDir}";
|
||||
in "${pack.package}/${cfg.package.dataDir}/${subDir}:${cfg.dataDir}/${subDir}";
|
||||
in
|
||||
mapAttrsToList mapPackPath enabledPacks;
|
||||
packsPaths = mkMerge [
|
||||
(mkWorldPacks "behavior")
|
||||
(mkWorldPacks "resource")
|
||||
(mapWorldPacks cfg.packs)
|
||||
];
|
||||
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)
|
||||
];
|
||||
ExecStart = [
|
||||
"${getExe cfg.package}"
|
||||
];
|
||||
mapWorldPacks = packs: let
|
||||
enabledPacks = filterAttrs (_: pack: pack.enable && pack.package != null) packs;
|
||||
mapPackPath = _: pack: let
|
||||
subDir = "${pack.packType}/${pack.packDir}";
|
||||
in "${pack.package}/${cfg.package.dataDir}/${subDir}:${cfg.dataDir}/${subDir}";
|
||||
in mapAttrsToList mapPackPath enabledPacks;
|
||||
packsPaths = mkMerge [
|
||||
(mkWorldPacks "behavior")
|
||||
(mkWorldPacks "resource")
|
||||
(mapWorldPacks cfg.packs)
|
||||
Restart = "always";
|
||||
User = cfg.user;
|
||||
WorkingDirectory = cfg.dataDir;
|
||||
LogFilterPatterns = [
|
||||
"~.*minecraft:trial_chambers/chamber/end"
|
||||
"~Running AutoCompaction"
|
||||
];
|
||||
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)
|
||||
];
|
||||
ExecStart = [
|
||||
"${getExe cfg.package}"
|
||||
];
|
||||
Restart = "always";
|
||||
User = cfg.user;
|
||||
WorkingDirectory = cfg.dataDir;
|
||||
LogFilterPatterns = [
|
||||
"~.*minecraft:trial_chambers/chamber/end"
|
||||
"~Running AutoCompaction"
|
||||
];
|
||||
};
|
||||
|
||||
preStart = ''
|
||||
mkdir -p behavior_packs
|
||||
ln -sf ${cfg.package}/var/lib/minecraft-bedrock/behavior_packs/* behavior_packs/
|
||||
cp -f ${serverPropertiesFile} server.properties
|
||||
chmod +w server.properties
|
||||
'';
|
||||
};
|
||||
|
||||
preStart = ''
|
||||
mkdir -p behavior_packs
|
||||
ln -sf ${cfg.package}/var/lib/minecraft-bedrock/behavior_packs/* behavior_packs/
|
||||
cp -f ${serverPropertiesFile} server.properties
|
||||
chmod +w server.properties
|
||||
'';
|
||||
};
|
||||
|
||||
conf.networking.firewall = let
|
||||
ports = [ cfg.serverProperties.server-port cfg.serverProperties.server-portv6 ];
|
||||
in mkIf cfg.openFirewall {
|
||||
allowedUDPPorts = ports;
|
||||
};
|
||||
in mkMerge [
|
||||
confService
|
||||
(mkIf cfg.enable conf)
|
||||
];
|
||||
}
|
||||
conf.networking.firewall = let
|
||||
ports = [cfg.serverProperties.server-port cfg.serverProperties.server-portv6];
|
||||
in
|
||||
mkIf cfg.openFirewall {
|
||||
allowedUDPPorts = ports;
|
||||
};
|
||||
in
|
||||
mkMerge [
|
||||
confService
|
||||
(mkIf cfg.enable conf)
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
);
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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,21 +11,32 @@
|
|||
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 ]
|
||||
++ optional (port != dnsPort) ":${toString port}"
|
||||
++ optional (interface != null) "%${interface}"
|
||||
++ optional (host != null) "#${host}"
|
||||
);
|
||||
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" // {
|
||||
default = true;
|
||||
};
|
||||
enable =
|
||||
mkEnableOption "nameserver"
|
||||
// {
|
||||
default = true;
|
||||
};
|
||||
address = mkOption {
|
||||
type = str;
|
||||
};
|
||||
|
|
@ -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
|
||||
);
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 = {};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@
|
|||
};
|
||||
conditions = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [ "iifname ${name}" ];
|
||||
default = ["iifname ${name}"];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,28 +1,33 @@
|
|||
{
|
||||
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" // {
|
||||
default = true;
|
||||
};
|
||||
enable =
|
||||
mkEnableOption "enable location"
|
||||
// {
|
||||
default = true;
|
||||
};
|
||||
};
|
||||
config = mkIf (!virtualHost.enable || !config.enable) {
|
||||
extraConfig = mkExtraForce "deny all;";
|
||||
};
|
||||
};
|
||||
hostModule = { config, ... }: {
|
||||
hostModule = {config, ...}: {
|
||||
options = with lib.types; {
|
||||
enable = mkEnableOption "enable server" // {
|
||||
default = true;
|
||||
};
|
||||
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;
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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 ([
|
||||
(mkIf cfg.includeDefaults (mkAlmostBefore ''
|
||||
include ${nginx.package}/conf/fastcgi.conf;
|
||||
''))
|
||||
(mkIf (cfg.socket != null) (mkJustAfter ''
|
||||
fastcgi_pass unix:${cfg.socket};
|
||||
''))
|
||||
] ++ passHeadersConfig
|
||||
++ paramsConfig));
|
||||
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
|
||||
++ 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
|
||||
inherit (lib.options) mkOption;
|
||||
in {
|
||||
options = with lib.types; {
|
||||
services.nginx.virtualHosts = mkOption {
|
||||
type = attrsOf (submodule [hostModule]);
|
||||
in
|
||||
{lib, ...}: let
|
||||
inherit (lib.options) mkOption;
|
||||
in {
|
||||
options = with lib.types; {
|
||||
services.nginx.virtualHosts = mkOption {
|
||||
type = attrsOf (submodule [hostModule]);
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,22 +69,20 @@ let
|
|||
};
|
||||
};
|
||||
};
|
||||
in {
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (lib.options) mkOption;
|
||||
in {
|
||||
options.services.nginx = with lib.types; {
|
||||
headers = {
|
||||
set = mkOption {
|
||||
type = attrsOf (nullOr (oneOf [ str (listOf str) ]));
|
||||
default = {
|
||||
in
|
||||
{lib, ...}: let
|
||||
inherit (lib.options) mkOption;
|
||||
in {
|
||||
options.services.nginx = with lib.types; {
|
||||
headers = {
|
||||
set = mkOption {
|
||||
type = attrsOf (nullOr (oneOf [str (listOf str)]));
|
||||
default = {
|
||||
};
|
||||
};
|
||||
};
|
||||
virtualHosts = mkOption {
|
||||
type = attrsOf (submodule [hostModule]);
|
||||
};
|
||||
};
|
||||
virtualHosts = mkOption {
|
||||
type = attrsOf (submodule [hostModule]);
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,11 +10,18 @@
|
|||
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" // {
|
||||
default = true;
|
||||
};
|
||||
enable =
|
||||
mkEnableOption "this port"
|
||||
// {
|
||||
default = true;
|
||||
};
|
||||
addr = mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
|
|
@ -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) ]
|
||||
++ config.listenParameters
|
||||
);
|
||||
in mkOptionDefault (map (mkDirective) config.addresses);
|
||||
host = mkListenHost {
|
||||
inherit addr;
|
||||
inherit (config) port;
|
||||
};
|
||||
in
|
||||
mkMerge (
|
||||
[(mkBefore host)]
|
||||
++ config.listenParameters
|
||||
);
|
||||
in
|
||||
mkOptionDefault (map mkDirective config.addresses);
|
||||
listenDirectives = mkMerge (map (conf: mkOptionDefault "listen ${conf};") config.listenConfigs);
|
||||
};
|
||||
};
|
||||
listenType = { specialArgs, modules ? [ ] }: lib.types.submoduleWith {
|
||||
inherit specialArgs;
|
||||
modules = [ listenModule ] ++ modules;
|
||||
};
|
||||
hostModule = { nixosConfig, config, ... }: let
|
||||
listenType = {
|
||||
specialArgs,
|
||||
modules ? [],
|
||||
}:
|
||||
lib.types.submoduleWith {
|
||||
inherit specialArgs;
|
||||
modules = [listenModule] ++ modules;
|
||||
};
|
||||
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;
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -8,55 +8,62 @@
|
|||
inherit (lib.strings) concatMapStringsSep optionalString;
|
||||
inherit (config.services) tailscale;
|
||||
inherit (config.networking.access) cidrForNetwork localaddrs;
|
||||
mkAddrVar = remoteAddr: varPrefix: ''
|
||||
set ${varPrefix}tailscale 0;
|
||||
'' + 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;
|
||||
}
|
||||
if (${remoteAddr} ~ "^fd0a::") {
|
||||
set ${varPrefix}lan 1;
|
||||
}
|
||||
if (${remoteAddr} ~ "^fe80::") {
|
||||
set ${varPrefix}lan 1;
|
||||
}
|
||||
set ${varPrefix}int 0;
|
||||
if (${remoteAddr} ~ "^10\.9\.1\.[0-9]+") {
|
||||
set ${varPrefix}lan 1;
|
||||
}
|
||||
if (${remoteAddr} ~ "^fd0c::") {
|
||||
set ${varPrefix}int 1;
|
||||
}
|
||||
set ${varPrefix}localhost 0;
|
||||
if (${remoteAddr} = "::1") {
|
||||
set ${varPrefix}localhost 1;
|
||||
}
|
||||
if (${remoteAddr} ~ "127\.0\.0\.[0-9]+") {
|
||||
set ${varPrefix}localhost 1;
|
||||
}
|
||||
set ${varPrefix}client 0;
|
||||
if (${varPrefix}tailscale) {
|
||||
set ${varPrefix}client 1;
|
||||
}
|
||||
if (${varPrefix}lan) {
|
||||
set ${varPrefix}client 1;
|
||||
}
|
||||
if (${varPrefix}int) {
|
||||
set ${varPrefix}client 1;
|
||||
}
|
||||
if (${varPrefix}localhost) {
|
||||
set ${varPrefix}client 1;
|
||||
}
|
||||
'';
|
||||
localModule = {config, xvars, ...}: let
|
||||
mkAddrVar = remoteAddr: varPrefix:
|
||||
''
|
||||
set ${varPrefix}tailscale 0;
|
||||
''
|
||||
+ 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;
|
||||
}
|
||||
if (${remoteAddr} ~ "^fd0a::") {
|
||||
set ${varPrefix}lan 1;
|
||||
}
|
||||
if (${remoteAddr} ~ "^fe80::") {
|
||||
set ${varPrefix}lan 1;
|
||||
}
|
||||
set ${varPrefix}int 0;
|
||||
if (${remoteAddr} ~ "^10\.9\.1\.[0-9]+") {
|
||||
set ${varPrefix}lan 1;
|
||||
}
|
||||
if (${remoteAddr} ~ "^fd0c::") {
|
||||
set ${varPrefix}int 1;
|
||||
}
|
||||
set ${varPrefix}localhost 0;
|
||||
if (${remoteAddr} = "::1") {
|
||||
set ${varPrefix}localhost 1;
|
||||
}
|
||||
if (${remoteAddr} ~ "127\.0\.0\.[0-9]+") {
|
||||
set ${varPrefix}localhost 1;
|
||||
}
|
||||
set ${varPrefix}client 0;
|
||||
if (${varPrefix}tailscale) {
|
||||
set ${varPrefix}client 1;
|
||||
}
|
||||
if (${varPrefix}lan) {
|
||||
set ${varPrefix}client 1;
|
||||
}
|
||||
if (${varPrefix}int) {
|
||||
set ${varPrefix}client 1;
|
||||
}
|
||||
if (${varPrefix}localhost) {
|
||||
set ${varPrefix}client 1;
|
||||
}
|
||||
'';
|
||||
localModule = {
|
||||
config,
|
||||
xvars,
|
||||
...
|
||||
}: let
|
||||
cfg = config.local;
|
||||
in {
|
||||
options.local = with lib.types; {
|
||||
|
|
@ -97,11 +104,12 @@
|
|||
${allows}
|
||||
deny all;
|
||||
'';
|
||||
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_")))
|
||||
];
|
||||
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_")))
|
||||
];
|
||||
};
|
||||
};
|
||||
locationModule = {
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
map (file: "access_by_lua_file ${file};") cfg.access.files
|
||||
)))
|
||||
(mkIf (cfg.set != { }) (assert lua.http.enable && lua.ndk.enable; mkMerge (
|
||||
mapAttrsToList mkSetBy cfg.set
|
||||
)))
|
||||
(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 (
|
||||
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 = [
|
||||
cfg.luaPackage.pkgs.lua-resty-core
|
||||
] ++ cfg.luaPackage.pkgs.lua-resty-core.propagatedBuildInputs;
|
||||
modules =
|
||||
[
|
||||
cfg.luaPackage.pkgs.lua-resty-core
|
||||
]
|
||||
++ 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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,9 +32,10 @@ let
|
|||
config = let
|
||||
inherit (nginx.stream) upstreams;
|
||||
mkUpstream = host: upstream: "${host} ${upstreams.${upstream}.name};";
|
||||
upstreams' = removeAttrs cfg.upstreams [ "default" ];
|
||||
upstreamLines = mapAttrsToList mkUpstream upstreams'
|
||||
++ optional (cfg.upstreams ? default) (mkUpstream "default" cfg.upstreams.default);
|
||||
upstreams' = removeAttrs cfg.upstreams ["default"];
|
||||
upstreamLines =
|
||||
mapAttrsToList mkUpstream upstreams'
|
||||
++ optional (cfg.upstreams ? default) (mkUpstream "default" cfg.upstreams.default);
|
||||
in {
|
||||
ssl.preread = {
|
||||
streamConfig = mkIf (cfg.upstreams != null) ''
|
||||
|
|
@ -46,59 +54,65 @@ let
|
|||
serverBlock = mkIf cfg.enable (mkOptionDefault (mkBefore cfg.streamConfig));
|
||||
};
|
||||
};
|
||||
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 {
|
||||
options.services.nginx = with lib.types; {
|
||||
ssl.preread = {
|
||||
enable = mkEnableOption "ssl preread";
|
||||
listenPort = mkOption {
|
||||
type = port;
|
||||
default = 444;
|
||||
};
|
||||
serverPort = mkOption {
|
||||
type = port;
|
||||
default = 443;
|
||||
};
|
||||
serverName = mkOption {
|
||||
type = str;
|
||||
default = "preread'https";
|
||||
};
|
||||
upstreamName = mkOption {
|
||||
type = str;
|
||||
default = "preread'nginx";
|
||||
};
|
||||
};
|
||||
stream.servers = mkOption {
|
||||
type = attrsOf (submoduleWith {
|
||||
modules = [serverModule];
|
||||
shorthandOnlyDefinesConfig = false;
|
||||
});
|
||||
};
|
||||
};
|
||||
config = {
|
||||
services.nginx = {
|
||||
defaultSSLListenPort = mkIf cfg.enable cfg.listenPort;
|
||||
stream = {
|
||||
upstreams.${cfg.upstreamName} = mkIf cfg.enable {
|
||||
ssl.enable = true;
|
||||
servers.access = {
|
||||
addr = mkDefault "localhost";
|
||||
port = mkOptionDefault cfg.listenPort;
|
||||
};
|
||||
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 {
|
||||
options.services.nginx = with lib.types; {
|
||||
ssl.preread = {
|
||||
enable = mkEnableOption "ssl preread";
|
||||
listenPort = mkOption {
|
||||
type = port;
|
||||
default = 444;
|
||||
};
|
||||
servers.${cfg.serverName} = {
|
||||
enable = mkIf (!cfg.enable) (mkAlmostOptionDefault false);
|
||||
listen.https.port = cfg.serverPort;
|
||||
ssl.preread = {
|
||||
enable = true;
|
||||
upstreams.default = mkOptionDefault cfg.upstreamName;
|
||||
serverPort = mkOption {
|
||||
type = port;
|
||||
default = 443;
|
||||
};
|
||||
serverName = mkOption {
|
||||
type = str;
|
||||
default = "preread'https";
|
||||
};
|
||||
upstreamName = mkOption {
|
||||
type = str;
|
||||
default = "preread'nginx";
|
||||
};
|
||||
};
|
||||
stream.servers = mkOption {
|
||||
type = attrsOf (submoduleWith {
|
||||
modules = [serverModule];
|
||||
shorthandOnlyDefinesConfig = false;
|
||||
});
|
||||
};
|
||||
};
|
||||
config = {
|
||||
services.nginx = {
|
||||
defaultSSLListenPort = mkIf cfg.enable cfg.listenPort;
|
||||
stream = {
|
||||
upstreams.${cfg.upstreamName} = mkIf cfg.enable {
|
||||
ssl.enable = true;
|
||||
servers.access = {
|
||||
addr = mkDefault "localhost";
|
||||
port = mkOptionDefault cfg.listenPort;
|
||||
};
|
||||
};
|
||||
servers.${cfg.serverName} = {
|
||||
enable = mkIf (!cfg.enable) (mkAlmostOptionDefault false);
|
||||
listen.https.port = cfg.serverPort;
|
||||
ssl.preread = {
|
||||
enable = true;
|
||||
upstreams.default = mkOptionDefault cfg.upstreamName;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,14 +119,23 @@ let
|
|||
proxied = {
|
||||
cloudflared = let
|
||||
listen = config.listen'.proxied;
|
||||
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;
|
||||
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;
|
||||
};
|
||||
getIngress = {}: unmerged.mergeAttrs cfg.cloudflared.ingressSettings;
|
||||
};
|
||||
getIngress = {}: unmerged.mergeAttrs cfg.cloudflared.ingressSettings;
|
||||
};
|
||||
};
|
||||
xvars.enable = mkIf cfg.enabled true;
|
||||
local.denyGlobal = mkIf listenProxied (mkDefault true);
|
||||
|
|
@ -123,74 +146,75 @@ let
|
|||
};
|
||||
};
|
||||
extraConfig = mkIf (cfg.enabled && config.xvars.enable) (
|
||||
mkOrder (orderJustBefore + 25) (xHeadersProxied { inherit xvars; })
|
||||
mkOrder (orderJustBefore + 25) (xHeadersProxied {inherit xvars;})
|
||||
);
|
||||
};
|
||||
};
|
||||
in {
|
||||
config,
|
||||
system,
|
||||
gensokyo-zone,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (gensokyo-zone.lib) mkAlmostOptionDefault;
|
||||
inherit (lib.options) mkOption mkEnableOption;
|
||||
inherit (lib.modules) mkIf mkOptionDefault;
|
||||
inherit (lib.attrsets) attrValues;
|
||||
inherit (lib.lists) any;
|
||||
inherit (config.services) nginx;
|
||||
cfg = nginx.proxied;
|
||||
in {
|
||||
options.services.nginx = with lib.types; {
|
||||
proxied = {
|
||||
enable = mkEnableOption "proxy";
|
||||
listenAddr = mkOption {
|
||||
type = str;
|
||||
default = "[::]";
|
||||
in
|
||||
{
|
||||
config,
|
||||
system,
|
||||
gensokyo-zone,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (gensokyo-zone.lib) mkAlmostOptionDefault;
|
||||
inherit (lib.options) mkOption mkEnableOption;
|
||||
inherit (lib.modules) mkIf mkOptionDefault;
|
||||
inherit (lib.attrsets) attrValues;
|
||||
inherit (lib.lists) any;
|
||||
inherit (config.services) nginx;
|
||||
cfg = nginx.proxied;
|
||||
in {
|
||||
options.services.nginx = with lib.types; {
|
||||
proxied = {
|
||||
enable = mkEnableOption "proxy";
|
||||
listenAddr = mkOption {
|
||||
type = str;
|
||||
default = "[::]";
|
||||
};
|
||||
listenPort = mkOption {
|
||||
type = port;
|
||||
default = 9080;
|
||||
};
|
||||
};
|
||||
listenPort = mkOption {
|
||||
type = port;
|
||||
default = 9080;
|
||||
virtualHosts = mkOption {
|
||||
type = attrsOf (submodule [hostModule]);
|
||||
};
|
||||
};
|
||||
virtualHosts = mkOption {
|
||||
type = attrsOf (submodule [hostModule]);
|
||||
};
|
||||
};
|
||||
config = {
|
||||
services.nginx = let
|
||||
warnEnable = lib.warnIf (cfg.enable != hasProxiedHosts) "services.nginx.proxied.enable expected to be set";
|
||||
hasProxiedHosts = any (virtualHost: virtualHost.enable && virtualHost.proxied.enabled) (attrValues nginx.virtualHosts);
|
||||
in {
|
||||
upstreams' = {
|
||||
nginx'proxied = mkIf (warnEnable cfg.enable) {
|
||||
servers.local = {
|
||||
accessService = {
|
||||
system = system.name;
|
||||
name = "nginx";
|
||||
port = "proxied";
|
||||
config = {
|
||||
services.nginx = let
|
||||
warnEnable = lib.warnIf (cfg.enable != hasProxiedHosts) "services.nginx.proxied.enable expected to be set";
|
||||
hasProxiedHosts = any (virtualHost: virtualHost.enable && virtualHost.proxied.enabled) (attrValues nginx.virtualHosts);
|
||||
in {
|
||||
upstreams' = {
|
||||
nginx'proxied = mkIf (warnEnable cfg.enable) {
|
||||
servers.local = {
|
||||
accessService = {
|
||||
system = system.name;
|
||||
name = "nginx";
|
||||
port = "proxied";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
virtualHosts = {
|
||||
fallback'proxied = mkIf cfg.enable {
|
||||
serverName = null;
|
||||
reuseport = mkAlmostOptionDefault true;
|
||||
default = mkAlmostOptionDefault true;
|
||||
listen'.proxied = {
|
||||
addr = mkAlmostOptionDefault cfg.listenAddr;
|
||||
port = mkAlmostOptionDefault cfg.listenPort;
|
||||
virtualHosts = {
|
||||
fallback'proxied = mkIf cfg.enable {
|
||||
serverName = null;
|
||||
reuseport = mkAlmostOptionDefault true;
|
||||
default = mkAlmostOptionDefault true;
|
||||
listen'.proxied = {
|
||||
addr = mkAlmostOptionDefault cfg.listenAddr;
|
||||
port = mkAlmostOptionDefault cfg.listenPort;
|
||||
};
|
||||
locations."/".extraConfig = mkAlmostOptionDefault ''
|
||||
return 502;
|
||||
'';
|
||||
};
|
||||
locations."/".extraConfig = mkAlmostOptionDefault ''
|
||||
return 502;
|
||||
'';
|
||||
};
|
||||
};
|
||||
networking.firewall.interfaces.lan = mkIf nginx.enable {
|
||||
allowedTCPPorts = mkIf cfg.enable [cfg.listenPort];
|
||||
};
|
||||
};
|
||||
networking.firewall.interfaces.lan = mkIf nginx.enable {
|
||||
allowedTCPPorts = mkIf cfg.enable [ cfg.listenPort ];
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,9 +99,11 @@ let
|
|||
host = mkOption {
|
||||
type = nullOr str;
|
||||
};
|
||||
websocket.enable = mkEnableOption "websocket proxy" // {
|
||||
default = cfg.inheritServerDefaults && virtualHost.proxy.websocket.enable;
|
||||
};
|
||||
websocket.enable =
|
||||
mkEnableOption "websocket proxy"
|
||||
// {
|
||||
default = cfg.inheritServerDefaults && virtualHost.proxy.websocket.enable;
|
||||
};
|
||||
parsed = {
|
||||
scheme = mkOption {
|
||||
type = nullOr str;
|
||||
|
|
@ -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 = {
|
||||
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 ];
|
||||
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];
|
||||
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
|
||||
|
|
@ -191,8 +227,9 @@ let
|
|||
'';
|
||||
setHeaders' = filterAttrs (_: header: header != null) cfg.headers.set;
|
||||
setHeaders = concatStringsSep "\n" (mapAttrsToList (
|
||||
name: value: "proxy_set_header ${name} ${xvars.escapeString value};"
|
||||
) setHeaders');
|
||||
name: value: "proxy_set_header ${name} ${xvars.escapeString value};"
|
||||
)
|
||||
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
|
||||
);
|
||||
};
|
||||
|
|
@ -254,15 +299,22 @@ let
|
|||
proxyPass = mkIf cfg.enable (mkAlmostOptionDefault (removeSuffix "/" cfg.url + cfg.path));
|
||||
recommendedProxySettings = mkAlmostOptionDefault (cfg.headers.enableRecommended == "nixpkgs");
|
||||
extraConfig = mkIf cfg.enabled (mkMerge ([
|
||||
(mkIf virtualHost.xvars.enable (mkJustBefore initProxyVars))
|
||||
(mkIf (cfg.headers.rewriteReferer.enable) (mkJustBefore rewriteReferer))
|
||||
(mkIf (cfg.redirect.enable) (mkBefore redirect))
|
||||
(mkIf (emitHeaders) (mkJustAfter setHeaders))
|
||||
(mkIf cfg.websocket.enable "proxy_cache_bypass $http_upgrade;")
|
||||
] ++ hideHeaders));
|
||||
(mkIf virtualHost.xvars.enable (mkJustBefore initProxyVars))
|
||||
(mkIf (cfg.headers.rewriteReferer.enable) (mkJustBefore rewriteReferer))
|
||||
(mkIf (cfg.redirect.enable) (mkBefore redirect))
|
||||
(mkIf emitHeaders (mkJustAfter setHeaders))
|
||||
(mkIf cfg.websocket.enable "proxy_cache_bypass $http_upgrade;")
|
||||
]
|
||||
++ 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,16 +358,18 @@ let
|
|||
needsReferer = loc: loc.proxy.enabled && loc.proxy.headers.rewriteReferer.enable;
|
||||
confCopy = let
|
||||
proxyHost = nginx.virtualHosts.${cfg.copyFromVhost};
|
||||
in mapAlmostOptionDefaults {
|
||||
inherit (proxyHost.proxy) host url upstream;
|
||||
} // {
|
||||
websocket = mapAlmostOptionDefaults {
|
||||
inherit (proxyHost.proxy.websocket) enable;
|
||||
in
|
||||
mapAlmostOptionDefaults {
|
||||
inherit (proxyHost.proxy) host url upstream;
|
||||
}
|
||||
// {
|
||||
websocket = mapAlmostOptionDefaults {
|
||||
inherit (proxyHost.proxy.websocket) enable;
|
||||
};
|
||||
headers = mapAlmostOptionDefaults {
|
||||
inherit (proxyHost.proxy.headers) enableRecommended;
|
||||
};
|
||||
};
|
||||
headers = mapAlmostOptionDefaults {
|
||||
inherit (proxyHost.proxy.headers) enableRecommended;
|
||||
};
|
||||
};
|
||||
in {
|
||||
xvars = {
|
||||
parseReferer = mkIf (anyLocations needsReferer) true;
|
||||
|
|
@ -326,21 +383,19 @@ let
|
|||
proxy = mkIf (cfg.copyFromVhost != null) confCopy;
|
||||
};
|
||||
};
|
||||
in {
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (lib.options) mkOption;
|
||||
in {
|
||||
options.services.nginx = with lib.types; {
|
||||
virtualHosts = mkOption {
|
||||
type = attrsOf (submodule [hostModule]);
|
||||
in
|
||||
{lib, ...}: let
|
||||
inherit (lib.options) mkOption;
|
||||
in {
|
||||
options.services.nginx = with lib.types; {
|
||||
virtualHosts = mkOption {
|
||||
type = attrsOf (submodule [hostModule]);
|
||||
};
|
||||
stream.servers = mkOption {
|
||||
type = attrsOf (submoduleWith {
|
||||
modules = [serverModule];
|
||||
shorthandOnlyDefinesConfig = false;
|
||||
});
|
||||
};
|
||||
};
|
||||
stream.servers = mkOption {
|
||||
type = attrsOf (submoduleWith {
|
||||
modules = [serverModule];
|
||||
shorthandOnlyDefinesConfig = false;
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 [
|
||||
(mkIf (cfg.cert.copyFromStreamServer != null) copyCertStreamServer)
|
||||
(mkIf (cfg.cert.copyFromVhost != null) copyCertVhost)
|
||||
];
|
||||
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,9 +89,11 @@ let
|
|||
type = bool;
|
||||
};
|
||||
verify = mkEnableOption "proxy_ssl_verify";
|
||||
sni = mkEnableOption "proxy_ssl_server_name" // {
|
||||
default = cfg.host != null;
|
||||
};
|
||||
sni =
|
||||
mkEnableOption "proxy_ssl_server_name"
|
||||
// {
|
||||
default = cfg.host != null;
|
||||
};
|
||||
host = mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
|
|
@ -97,18 +110,26 @@ 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" // {
|
||||
default = true;
|
||||
};
|
||||
kTLS =
|
||||
mkEnableOption "kTLS support"
|
||||
// {
|
||||
default = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
config = let
|
||||
|
|
@ -126,104 +147,124 @@ let
|
|||
(mkIf cfg.kTLS "ssl_conf_command Options KTLS;")
|
||||
];
|
||||
confProxy.extraConfig = mkIf proxy.ssl.enable "proxy_ssl on;";
|
||||
in mkMerge [
|
||||
conf
|
||||
(mkIf cfg.enable confSsl)
|
||||
(mkIf proxy.enable confProxy)
|
||||
];
|
||||
in
|
||||
mkMerge [
|
||||
conf
|
||||
(mkIf cfg.enable confSsl)
|
||||
(mkIf proxy.enable confProxy)
|
||||
];
|
||||
};
|
||||
in {
|
||||
config,
|
||||
gensokyo-zone,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (gensokyo-zone.lib) mkAlmostOptionDefault;
|
||||
inherit (lib.options) mkOption mkEnableOption;
|
||||
inherit (lib.modules) mkIf mkMerge mkDefault mkOptionDefault;
|
||||
inherit (lib.attrsets) mapAttrsToList;
|
||||
inherit (lib.trivial) warnIf;
|
||||
inherit (lib.strings) hasPrefix;
|
||||
inherit (config.services) nginx;
|
||||
forceRedirectConfig = { virtualHost, xvars }: ''
|
||||
if (${xvars.get.scheme} = http) {
|
||||
return ${toString virtualHost.redirectCode} https://${xvars.get.host}$request_uri;
|
||||
}
|
||||
'';
|
||||
locationModule = { config, virtualHost, xvars, ... }: let
|
||||
cfg = config.ssl;
|
||||
emitForce = cfg.force && !virtualHost.ssl.forced;
|
||||
in {
|
||||
imports = [ sslProxyModule ];
|
||||
options.ssl = {
|
||||
force = mkEnableOption "redirect to SSL";
|
||||
in
|
||||
{
|
||||
config,
|
||||
gensokyo-zone,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (gensokyo-zone.lib) mkAlmostOptionDefault;
|
||||
inherit (lib.options) mkOption mkEnableOption;
|
||||
inherit (lib.modules) mkIf mkMerge mkDefault mkOptionDefault;
|
||||
inherit (lib.attrsets) mapAttrsToList;
|
||||
inherit (lib.trivial) warnIf;
|
||||
inherit (lib.strings) hasPrefix;
|
||||
inherit (config.services) nginx;
|
||||
forceRedirectConfig = {
|
||||
virtualHost,
|
||||
xvars,
|
||||
}: ''
|
||||
if (${xvars.get.scheme} = http) {
|
||||
return ${toString virtualHost.redirectCode} https://${xvars.get.host}$request_uri;
|
||||
}
|
||||
'';
|
||||
locationModule = {
|
||||
config,
|
||||
virtualHost,
|
||||
xvars,
|
||||
...
|
||||
}: let
|
||||
cfg = config.ssl;
|
||||
emitForce = cfg.force && !virtualHost.ssl.forced;
|
||||
in {
|
||||
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;});
|
||||
};
|
||||
};
|
||||
config = {
|
||||
proxy.ssl.enable = mkOptionDefault (hasPrefix "https://" config.proxyPass);
|
||||
xvars.enable = mkIf emitForce true;
|
||||
extraConfig = mkIf emitForce (forceRedirectConfig { inherit xvars virtualHost; });
|
||||
};
|
||||
};
|
||||
hostModule = { config, xvars, ... }: let
|
||||
cfg = config.ssl;
|
||||
emitForce = cfg.forced && config.proxied.enabled;
|
||||
in {
|
||||
imports = [ sslModule ];
|
||||
options = with lib.types; {
|
||||
ssl = {
|
||||
cert = {
|
||||
enable = mkEnableOption "ssl cert via name.shortServer";
|
||||
hostModule = {
|
||||
config,
|
||||
xvars,
|
||||
...
|
||||
}: let
|
||||
cfg = config.ssl;
|
||||
emitForce = cfg.forced && config.proxied.enabled;
|
||||
in {
|
||||
imports = [sslModule];
|
||||
options = with lib.types; {
|
||||
ssl = {
|
||||
cert = {
|
||||
enable = mkEnableOption "ssl cert via name.shortServer";
|
||||
};
|
||||
};
|
||||
locations = mkOption {
|
||||
type = attrsOf (submoduleWith {
|
||||
modules = [locationModule];
|
||||
shorthandOnlyDefinesConfig = true;
|
||||
});
|
||||
};
|
||||
};
|
||||
locations = mkOption {
|
||||
type = attrsOf (submoduleWith {
|
||||
modules = [ locationModule ];
|
||||
shorthandOnlyDefinesConfig = true;
|
||||
config = {
|
||||
ssl = {
|
||||
cert = let
|
||||
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;
|
||||
};
|
||||
addSSL = mkIf (cfg.enable && (cfg.force == false || emitForce)) (mkDefault true);
|
||||
forceSSL = mkIf (cfg.enable && cfg.force == true && !emitForce) (mkDefault true);
|
||||
onlySSL = mkIf (cfg.enable && cfg.force == "only" && !emitForce) (mkDefault true);
|
||||
rejectSSL = mkIf (cfg.force == "reject") (mkDefault true);
|
||||
useACMEHost = mkAlmostOptionDefault cfg.cert.name;
|
||||
sslCertificate = mkIf (cfg.cert.path != null) (mkAlmostOptionDefault cfg.cert.path);
|
||||
sslCertificateKey = mkIf (cfg.cert.keyPath != null) (mkAlmostOptionDefault cfg.cert.keyPath);
|
||||
kTLS = mkAlmostOptionDefault true;
|
||||
|
||||
xvars.enable = mkIf emitForce true;
|
||||
extraConfig = mkIf emitForce (forceRedirectConfig {
|
||||
virtualHost = config;
|
||||
inherit xvars;
|
||||
});
|
||||
};
|
||||
};
|
||||
config = {
|
||||
ssl = {
|
||||
cert = let
|
||||
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 {
|
||||
options.services.nginx = with lib.types; {
|
||||
virtualHosts = mkOption {
|
||||
type = attrsOf (submoduleWith {
|
||||
modules = [hostModule];
|
||||
shorthandOnlyDefinesConfig = true;
|
||||
});
|
||||
};
|
||||
stream.servers = mkOption {
|
||||
type = attrsOf (submoduleWith {
|
||||
modules = [streamServerModule];
|
||||
shorthandOnlyDefinesConfig = false;
|
||||
});
|
||||
};
|
||||
addSSL = mkIf (cfg.enable && (cfg.force == false || emitForce)) (mkDefault true);
|
||||
forceSSL = mkIf (cfg.enable && cfg.force == true && !emitForce) (mkDefault true);
|
||||
onlySSL = mkIf (cfg.enable && cfg.force == "only" && !emitForce) (mkDefault true);
|
||||
rejectSSL = mkIf (cfg.force == "reject") (mkDefault true);
|
||||
useACMEHost = mkAlmostOptionDefault cfg.cert.name;
|
||||
sslCertificate = mkIf (cfg.cert.path != null) (mkAlmostOptionDefault cfg.cert.path);
|
||||
sslCertificateKey = mkIf (cfg.cert.keyPath != null) (mkAlmostOptionDefault cfg.cert.keyPath);
|
||||
kTLS = mkAlmostOptionDefault true;
|
||||
|
||||
xvars.enable = mkIf emitForce true;
|
||||
extraConfig = mkIf emitForce (forceRedirectConfig { virtualHost = config; inherit xvars; });
|
||||
};
|
||||
};
|
||||
in {
|
||||
options.services.nginx = with lib.types; {
|
||||
virtualHosts = mkOption {
|
||||
type = attrsOf (submoduleWith {
|
||||
modules = [ hostModule ];
|
||||
shorthandOnlyDefinesConfig = true;
|
||||
});
|
||||
};
|
||||
stream.servers = mkOption {
|
||||
type = attrsOf (submoduleWith {
|
||||
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" ];
|
||||
};
|
||||
streamServerCerts = mapAttrsToList (_: mapStreamServer) nginx.stream.servers;
|
||||
in mkIf nginx.enable (mkMerge streamServerCerts);
|
||||
}
|
||||
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"];
|
||||
};
|
||||
streamServerCerts = mapAttrsToList (_: mapStreamServer) nginx.stream.servers;
|
||||
in
|
||||
mkIf nginx.enable (mkMerge streamServerCerts);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,9 +10,11 @@
|
|||
cfg = config.services.nginx.stream;
|
||||
serverModule = {config, ...}: {
|
||||
options = with lib.types; {
|
||||
enable = mkEnableOption "stream server block" // {
|
||||
default = true;
|
||||
};
|
||||
enable =
|
||||
mkEnableOption "stream server block"
|
||||
// {
|
||||
default = true;
|
||||
};
|
||||
extraConfig = mkOption {
|
||||
type = lines;
|
||||
default = "";
|
||||
|
|
@ -49,7 +51,7 @@ in {
|
|||
nixosConfig = config;
|
||||
};
|
||||
});
|
||||
default = { };
|
||||
default = {};
|
||||
};
|
||||
};
|
||||
config.services.nginx = {
|
||||
|
|
|
|||
|
|
@ -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 [
|
||||
confAccess
|
||||
(mkIf cfg.enable conf)
|
||||
];
|
||||
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,9 +88,11 @@ let
|
|||
inherit (lib.trivial) isBool;
|
||||
in {
|
||||
options = with lib.types; {
|
||||
enable = mkEnableOption "upstream server" // {
|
||||
default = true;
|
||||
};
|
||||
enable =
|
||||
mkEnableOption "upstream server"
|
||||
// {
|
||||
default = true;
|
||||
};
|
||||
addr = mkOption {
|
||||
type = str;
|
||||
default = name;
|
||||
|
|
@ -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" // {
|
||||
default = true;
|
||||
};
|
||||
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 [
|
||||
server.settings
|
||||
(mkIf (server.extraConfig != "") {
|
||||
${config.extraConfig} = true;
|
||||
})
|
||||
]))) config.servers;
|
||||
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;
|
||||
});
|
||||
};
|
||||
};
|
||||
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,68 +370,76 @@ let
|
|||
};
|
||||
};
|
||||
};
|
||||
in {
|
||||
config,
|
||||
lib,
|
||||
gensokyo-zone,
|
||||
...
|
||||
}: let
|
||||
inherit (gensokyo-zone.lib) unmerged;
|
||||
inherit (lib.options) mkOption;
|
||||
inherit (lib.modules) mkIf mkMerge;
|
||||
inherit (lib.attrsets) mapAttrsToList;
|
||||
cfg = config.services.nginx;
|
||||
in {
|
||||
options.services.nginx = with lib.types; {
|
||||
upstreams' = mkOption {
|
||||
type = attrsOf (submoduleWith {
|
||||
modules = [upstreamModule];
|
||||
shorthandOnlyDefinesConfig = false;
|
||||
specialArgs = {
|
||||
inherit gensokyo-zone;
|
||||
nixosConfig = config;
|
||||
upstreamKind = "virtualHost";
|
||||
};
|
||||
});
|
||||
default = { };
|
||||
};
|
||||
virtualHosts = mkOption {
|
||||
type = attrsOf (submodule hostModule);
|
||||
};
|
||||
stream = {
|
||||
upstreams = mkOption {
|
||||
in
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
gensokyo-zone,
|
||||
...
|
||||
}: let
|
||||
inherit (gensokyo-zone.lib) unmerged;
|
||||
inherit (lib.options) mkOption;
|
||||
inherit (lib.modules) mkIf mkMerge;
|
||||
inherit (lib.attrsets) mapAttrsToList;
|
||||
cfg = config.services.nginx;
|
||||
in {
|
||||
options.services.nginx = with lib.types; {
|
||||
upstreams' = mkOption {
|
||||
type = attrsOf (submoduleWith {
|
||||
modules = [upstreamModule];
|
||||
shorthandOnlyDefinesConfig = false;
|
||||
specialArgs = {
|
||||
inherit gensokyo-zone;
|
||||
nixosConfig = config;
|
||||
upstreamKind = "stream";
|
||||
upstreamKind = "virtualHost";
|
||||
};
|
||||
});
|
||||
default = { };
|
||||
default = {};
|
||||
};
|
||||
servers = mkOption {
|
||||
type = attrsOf (submoduleWith {
|
||||
modules = [serverModule];
|
||||
shorthandOnlyDefinesConfig = false;
|
||||
});
|
||||
virtualHosts = mkOption {
|
||||
type = attrsOf (submodule hostModule);
|
||||
};
|
||||
stream = {
|
||||
upstreams = mkOption {
|
||||
type = attrsOf (submoduleWith {
|
||||
modules = [upstreamModule];
|
||||
shorthandOnlyDefinesConfig = false;
|
||||
specialArgs = {
|
||||
inherit gensokyo-zone;
|
||||
nixosConfig = config;
|
||||
upstreamKind = "stream";
|
||||
};
|
||||
});
|
||||
default = {};
|
||||
};
|
||||
servers = mkOption {
|
||||
type = attrsOf (submoduleWith {
|
||||
modules = [serverModule];
|
||||
shorthandOnlyDefinesConfig = false;
|
||||
});
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
config.services.nginx = let
|
||||
confStream.streamConfig = mkMerge (
|
||||
mapAttrsToList (_: upstream: mkIf upstream.enable upstream.upstreamBlock) cfg.stream.upstreams
|
||||
);
|
||||
useUpstreams = true;
|
||||
confUpstreams.upstreams = mkMerge (mapAttrsToList (_: upstream: mkIf upstream.enable {
|
||||
${upstream.name} = unmerged.mergeAttrs upstream.upstreamSettings;
|
||||
}) cfg.upstreams');
|
||||
confBlock.commonHttpConfig = mkMerge (
|
||||
mapAttrsToList (_: upstream: mkIf upstream.enable upstream.upstreamBlock) cfg.upstreams'
|
||||
);
|
||||
in mkMerge [
|
||||
confStream
|
||||
(if useUpstreams then confUpstreams else confBlock)
|
||||
];
|
||||
}
|
||||
config.services.nginx = let
|
||||
confStream.streamConfig = mkMerge (
|
||||
mapAttrsToList (_: upstream: mkIf upstream.enable upstream.upstreamBlock) cfg.stream.upstreams
|
||||
);
|
||||
useUpstreams = true;
|
||||
confUpstreams.upstreams = mkMerge (mapAttrsToList (_: upstream:
|
||||
mkIf upstream.enable {
|
||||
${upstream.name} = unmerged.mergeAttrs upstream.upstreamSettings;
|
||||
})
|
||||
cfg.upstreams');
|
||||
confBlock.commonHttpConfig = mkMerge (
|
||||
mapAttrsToList (_: upstream: mkIf upstream.enable upstream.upstreamBlock) cfg.upstreams'
|
||||
);
|
||||
in
|
||||
mkMerge [
|
||||
confStream
|
||||
(
|
||||
if useUpstreams
|
||||
then confUpstreams
|
||||
else confBlock
|
||||
)
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,29 +31,35 @@
|
|||
enableVouchLocal = virtualHost.vouch.localSso.enable;
|
||||
enableVouchTail = enableVouchLocal && tailscale.enable && false;
|
||||
allowOrigin = url: "add_header Access-Control-Allow-Origin ${url};";
|
||||
in mkIf config.vouch.requireAuth {
|
||||
lua = mkIf virtualHost.vouch.auth.lua.enable {
|
||||
access.block = mkMerge [
|
||||
(mkBefore virtualHost.vouch.auth.lua.accessRequest)
|
||||
(mkBefore virtualHost.vouch.auth.lua.accessVariables)
|
||||
(mkBefore virtualHost.vouch.auth.lua.accessLogic)
|
||||
];
|
||||
in
|
||||
mkIf config.vouch.requireAuth {
|
||||
lua = mkIf virtualHost.vouch.auth.lua.enable {
|
||||
access.block = mkMerge [
|
||||
(mkBefore virtualHost.vouch.auth.lua.accessRequest)
|
||||
(mkBefore virtualHost.vouch.auth.lua.accessVariables)
|
||||
(mkBefore virtualHost.vouch.auth.lua.accessLogic)
|
||||
];
|
||||
};
|
||||
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 [
|
||||
(mkIf (!virtualHost.vouch.requireAuth) virtualHost.vouch.auth.requestDirective)
|
||||
(allowOrigin vouch.url)
|
||||
(allowOrigin vouch.authUrl)
|
||||
(mkIf enableVouchLocal (allowOrigin vouch.localUrl))
|
||||
(mkIf enableVouchLocal (allowOrigin "sso.local.${networking.domain}"))
|
||||
(mkIf enableVouchTail (allowOrigin "${xvars.get.scheme}://${vouch.tailDomain}"))
|
||||
];
|
||||
};
|
||||
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 [
|
||||
(mkIf (!virtualHost.vouch.requireAuth) virtualHost.vouch.auth.requestDirective)
|
||||
(allowOrigin vouch.url)
|
||||
(allowOrigin vouch.authUrl)
|
||||
(mkIf enableVouchLocal (allowOrigin vouch.localUrl))
|
||||
(mkIf enableVouchLocal (allowOrigin "sso.local.${networking.domain}"))
|
||||
(mkIf enableVouchTail (allowOrigin "${xvars.get.scheme}://${vouch.tailDomain}"))
|
||||
];
|
||||
};
|
||||
};
|
||||
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,12 +68,16 @@
|
|||
};
|
||||
vouch = {
|
||||
enable = mkEnableOption "vouch auth proxy";
|
||||
localSso.enable = mkEnableOption "lan-local vouch" // {
|
||||
default = vouch.localSso.enable && config.local.enable;
|
||||
};
|
||||
requireAuth = mkEnableOption "require auth to access this host" // {
|
||||
default = true;
|
||||
};
|
||||
localSso.enable =
|
||||
mkEnableOption "lan-local vouch"
|
||||
// {
|
||||
default = vouch.localSso.enable && config.local.enable;
|
||||
};
|
||||
requireAuth =
|
||||
mkEnableOption "require auth to access this host"
|
||||
// {
|
||||
default = true;
|
||||
};
|
||||
auth = {
|
||||
lua = {
|
||||
enable = mkEnableOption "lua";
|
||||
|
|
@ -129,9 +144,12 @@
|
|||
return ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
|
||||
end
|
||||
'');
|
||||
accessVariables = mkMerge (mapAttrsToList (authVar: header: mkOptionDefault
|
||||
''ngx.var["${authVar}"] = ngx.ctx.auth_res.header["${header}"] or ""''
|
||||
) cfg.auth.variables);
|
||||
accessVariables = mkMerge (mapAttrsToList (
|
||||
authVar: header:
|
||||
mkOptionDefault
|
||||
''ngx.var["${authVar}"] = ngx.ctx.auth_res.header["${header}"] or ""''
|
||||
)
|
||||
cfg.auth.variables);
|
||||
};
|
||||
errorLocation = mkIf cfg.auth.lua.enable (mkAlmostOptionDefault null);
|
||||
requestDirective = mkIf cfg.auth.lua.enable (mkAlmostOptionDefault "");
|
||||
|
|
@ -161,15 +179,19 @@
|
|||
(mkIf cfg.localSso.enable localVouchUrl)
|
||||
(mkIf (cfg.localSso.enable && tailscale.enable) tailVouchUrl)
|
||||
];
|
||||
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) (
|
||||
mkBefore "auth_request_set \$${authVar} ${mkUpstreamVar header};"
|
||||
)) cfg.auth.variables
|
||||
));
|
||||
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) (
|
||||
mkBefore "auth_request_set \$${authVar} ${mkUpstreamVar header};"
|
||||
))
|
||||
cfg.auth.variables
|
||||
));
|
||||
xvars.enable = mkIf cfg.enable true;
|
||||
locations = mkIf cfg.enable {
|
||||
"/" = mkIf cfg.requireAuth {
|
||||
|
|
@ -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,9 +246,11 @@ in {
|
|||
vouch = {
|
||||
enable = mkEnableOption "vouch auth proxy";
|
||||
localSso = {
|
||||
enable = mkEnableOption "lan-local auth" // {
|
||||
default = true;
|
||||
};
|
||||
enable =
|
||||
mkEnableOption "lan-local auth"
|
||||
// {
|
||||
default = true;
|
||||
};
|
||||
};
|
||||
doubleProxy = {
|
||||
enable = mkOption {
|
||||
|
|
@ -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 // {
|
||||
enable = mkAlmostOptionDefault false;
|
||||
};
|
||||
service = { upstream, ... }: {
|
||||
local =
|
||||
localVouch
|
||||
// {
|
||||
enable = mkAlmostOptionDefault false;
|
||||
};
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -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 = xvars.get // get;
|
||||
};
|
||||
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,24 +138,25 @@ let
|
|||
_module.args.xvars = config.xvars.lib;
|
||||
};
|
||||
};
|
||||
in {
|
||||
config,
|
||||
lib,
|
||||
gensokyo-zone,
|
||||
...
|
||||
}: let
|
||||
inherit (lib.options) mkOption;
|
||||
in {
|
||||
options = with lib.types; {
|
||||
services.nginx.virtualHosts = mkOption {
|
||||
type = attrsOf (submoduleWith {
|
||||
modules = [ hostModule ];
|
||||
shorthandOnlyDefinesConfig = true;
|
||||
specialArgs = {
|
||||
inherit gensokyo-zone;
|
||||
nixosConfig = config;
|
||||
};
|
||||
});
|
||||
in
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
gensokyo-zone,
|
||||
...
|
||||
}: let
|
||||
inherit (lib.options) mkOption;
|
||||
in {
|
||||
options = with lib.types; {
|
||||
services.nginx.virtualHosts = mkOption {
|
||||
type = attrsOf (submoduleWith {
|
||||
modules = [hostModule];
|
||||
shorthandOnlyDefinesConfig = true;
|
||||
specialArgs = {
|
||||
inherit gensokyo-zone;
|
||||
nixosConfig = config;
|
||||
};
|
||||
});
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,9 +40,11 @@
|
|||
allow = mkEnableOption "tailscale TCP connections";
|
||||
};
|
||||
int = {
|
||||
allow = mkEnableOption "internal TCP connections" // {
|
||||
default = config.authentication.local.allow;
|
||||
};
|
||||
allow =
|
||||
mkEnableOption "internal TCP connections"
|
||||
// {
|
||||
default = config.authentication.local.allow;
|
||||
};
|
||||
};
|
||||
local = {
|
||||
allow = mkEnableOption "local TCP connections";
|
||||
|
|
|
|||
|
|
@ -45,28 +45,32 @@ 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" // {
|
||||
default = true;
|
||||
};
|
||||
enable =
|
||||
mkEnableOption "LDAP authentication"
|
||||
// {
|
||||
default = true;
|
||||
};
|
||||
backend = mkOption {
|
||||
type = enum [ "ldapsam" "ipasam" ];
|
||||
type = enum ["ldapsam" "ipasam"];
|
||||
default = "ldapsam";
|
||||
};
|
||||
};
|
||||
idmap = {
|
||||
enable = mkEnableOption "LDAP users" // {
|
||||
default = true;
|
||||
};
|
||||
enable =
|
||||
mkEnableOption "LDAP users"
|
||||
// {
|
||||
default = true;
|
||||
};
|
||||
domain = mkOption {
|
||||
type = str;
|
||||
default = "*";
|
||||
|
|
@ -98,12 +102,16 @@ in {
|
|||
};
|
||||
};
|
||||
tls = {
|
||||
enable = mkEnableOption "tls" // {
|
||||
default = cfg.tls.certPath != null;
|
||||
};
|
||||
peer.enable = mkEnableOption "peer verification" // {
|
||||
default = cfg.tls.caPath != null;
|
||||
};
|
||||
enable =
|
||||
mkEnableOption "tls"
|
||||
// {
|
||||
default = cfg.tls.certPath != null;
|
||||
};
|
||||
peer.enable =
|
||||
mkEnableOption "peer verification"
|
||||
// {
|
||||
default = cfg.tls.caPath != null;
|
||||
};
|
||||
useACMECert = mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
|
|
@ -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 (
|
||||
|
|
@ -251,58 +270,61 @@ in {
|
|||
})
|
||||
];
|
||||
settings = mkMerge ([
|
||||
{
|
||||
"use sendfile" = mkOptionDefault true;
|
||||
"mdns name" = mkOptionDefault "mdns";
|
||||
"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);
|
||||
}
|
||||
(mkIf (cfg.passdb.smbpasswd.path != null) {
|
||||
"passdb backend" = mkOptionDefault "smbpasswd:${cfg.passdb.smbpasswd.path}";
|
||||
})
|
||||
(mkIf cfg.ldap.enable {
|
||||
"ldap ssl" = mkIf (hasPrefix "ldaps://" cfg.ldap.url) (mkOptionDefault "off");
|
||||
"ldap admin dn" = mkIf (cfg.ldap.adminDn != null) (mkOptionDefault cfg.ldap.adminDn);
|
||||
"ldap suffix" = mkOptionDefault cfg.ldap.baseDn;
|
||||
})
|
||||
(mkIf cfg.kerberos.enable {
|
||||
"realm" = mkOptionDefault cfg.kerberos.realm;
|
||||
"kerberos method" = mkOptionDefault (
|
||||
if cfg.kerberos.keytabPath != null then "dedicated keytab"
|
||||
else "system keytab"
|
||||
);
|
||||
"dedicated keytab file" = mkIf (cfg.kerberos.keytabPath != null) (mkOptionDefault
|
||||
"FILE:${cfg.kerberos.keytabPath}"
|
||||
);
|
||||
"kerberos encryption types" = mkOptionDefault "strong";
|
||||
"create krb5 conf" = mkOptionDefault false;
|
||||
})
|
||||
(mkIf cfg.enableWinbindd {
|
||||
"winbind nss info" = mkOptionDefault "rfc2307";
|
||||
"winbind use default domain" = mkOptionDefault true;
|
||||
})
|
||||
(mkIf cfg.tls.enable {
|
||||
"tls enabled" = mkOptionDefault true;
|
||||
"tls verify peer" = mkIf cfg.tls.peer.enable (mkOptionDefault "ca_and_name_if_available");
|
||||
"tls certfile" = mkIf (cfg.tls.certPath != null) (mkOptionDefault cfg.tls.certPath);
|
||||
"tls keyfile" = mkIf (cfg.tls.keyPath != null) (mkOptionDefault cfg.tls.keyPath);
|
||||
"tls cafile" = mkIf (cfg.tls.caPath != null) (mkOptionDefault cfg.tls.caPath);
|
||||
"tls crlfile" = mkIf (cfg.tls.crlPath != null) (mkOptionDefault cfg.tls.crlPath);
|
||||
})
|
||||
(mkIf cfg.usershare.enable {
|
||||
"usershare allow guests" = mkOptionDefault true;
|
||||
"usershare max shares" = mkOptionDefault 16;
|
||||
"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 ];
|
||||
})
|
||||
(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);
|
||||
{
|
||||
"use sendfile" = mkOptionDefault true;
|
||||
"mdns name" = mkOptionDefault "mdns";
|
||||
"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);
|
||||
}
|
||||
(mkIf (cfg.passdb.smbpasswd.path != null) {
|
||||
"passdb backend" = mkOptionDefault "smbpasswd:${cfg.passdb.smbpasswd.path}";
|
||||
})
|
||||
(mkIf cfg.ldap.enable {
|
||||
"ldap ssl" = mkIf (hasPrefix "ldaps://" cfg.ldap.url) (mkOptionDefault "off");
|
||||
"ldap admin dn" = mkIf (cfg.ldap.adminDn != null) (mkOptionDefault cfg.ldap.adminDn);
|
||||
"ldap suffix" = mkOptionDefault cfg.ldap.baseDn;
|
||||
})
|
||||
(mkIf cfg.kerberos.enable {
|
||||
"realm" = mkOptionDefault cfg.kerberos.realm;
|
||||
"kerberos method" = mkOptionDefault (
|
||||
if cfg.kerberos.keytabPath != null
|
||||
then "dedicated keytab"
|
||||
else "system keytab"
|
||||
);
|
||||
"dedicated keytab file" = mkIf (cfg.kerberos.keytabPath != null) (
|
||||
mkOptionDefault
|
||||
"FILE:${cfg.kerberos.keytabPath}"
|
||||
);
|
||||
"kerberos encryption types" = mkOptionDefault "strong";
|
||||
"create krb5 conf" = mkOptionDefault false;
|
||||
})
|
||||
(mkIf cfg.enableWinbindd {
|
||||
"winbind nss info" = mkOptionDefault "rfc2307";
|
||||
"winbind use default domain" = mkOptionDefault true;
|
||||
})
|
||||
(mkIf cfg.tls.enable {
|
||||
"tls enabled" = mkOptionDefault true;
|
||||
"tls verify peer" = mkIf cfg.tls.peer.enable (mkOptionDefault "ca_and_name_if_available");
|
||||
"tls certfile" = mkIf (cfg.tls.certPath != null) (mkOptionDefault cfg.tls.certPath);
|
||||
"tls keyfile" = mkIf (cfg.tls.keyPath != null) (mkOptionDefault cfg.tls.keyPath);
|
||||
"tls cafile" = mkIf (cfg.tls.caPath != null) (mkOptionDefault cfg.tls.caPath);
|
||||
"tls crlfile" = mkIf (cfg.tls.crlPath != null) (mkOptionDefault cfg.tls.crlPath);
|
||||
})
|
||||
(mkIf cfg.usershare.enable {
|
||||
"usershare allow guests" = mkOptionDefault true;
|
||||
"usershare max shares" = mkOptionDefault 16;
|
||||
"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];
|
||||
})
|
||||
(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);
|
||||
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
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
inherit specialArgs;
|
||||
};
|
||||
mkMountType = args: with lib.types; coercedTo path (path: { path = mkOptionDefault path; }) (mkMountType' args);
|
||||
serviceModule = { config, nixosConfig, ... }: let
|
||||
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
|
||||
cfg = config.gensokyo-zone;
|
||||
mapSharedMounts = f: mapAttrsToList (_: target:
|
||||
f target
|
||||
) cfg.sharedMounts;
|
||||
mapCacheMounts = f: mapAttrsToList (_: target:
|
||||
f target
|
||||
) cfg.cacheMounts;
|
||||
mapSharedMounts = f:
|
||||
mapAttrsToList (
|
||||
_: target:
|
||||
f target
|
||||
)
|
||||
cfg.sharedMounts;
|
||||
mapCacheMounts = f:
|
||||
mapAttrsToList (
|
||||
_: target:
|
||||
f target
|
||||
)
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -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,35 +41,42 @@
|
|||
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;
|
||||
specialArgs = {
|
||||
inherit gensokyo-zone pkgs;
|
||||
nixosConfig = config;
|
||||
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 {
|
||||
type = mkServerType {
|
||||
modules = [ serverInfoModule ];
|
||||
in
|
||||
mkOption {
|
||||
type = mkServerType {
|
||||
modules = [serverInfoModule];
|
||||
};
|
||||
default = {};
|
||||
};
|
||||
default = { };
|
||||
};
|
||||
in {
|
||||
options.services.sssd.gensokyo-zone = with lib.types; {
|
||||
enable = mkEnableOption "realm" // {
|
||||
default = genso.enable;
|
||||
};
|
||||
enable =
|
||||
mkEnableOption "realm"
|
||||
// {
|
||||
default = genso.enable;
|
||||
};
|
||||
ldap = {
|
||||
bind = {
|
||||
passwordFile = mkOption {
|
||||
|
|
@ -71,24 +84,29 @@ 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"; } // {
|
||||
default = {
|
||||
inherit (cfg.krb5.servers) servers backups;
|
||||
servers =
|
||||
mkServerOption {name = "ipa";}
|
||||
// {
|
||||
default = {
|
||||
inherit (cfg.krb5.servers) servers backups;
|
||||
};
|
||||
};
|
||||
};
|
||||
hostName = mkOption {
|
||||
type = str;
|
||||
default = config.networking.fqdn;
|
||||
};
|
||||
};
|
||||
backend = mkOption {
|
||||
type = enum [ "ldap" "ipa" ];
|
||||
type = enum ["ldap" "ipa"];
|
||||
default = "ipa";
|
||||
};
|
||||
};
|
||||
|
|
@ -97,24 +115,26 @@ in {
|
|||
# or "ipaNTSecurityIdentifier" which isn't set for most groups, maybe check netgroups..?
|
||||
objectsid = "sambaSID";
|
||||
backendDomainSettings = {
|
||||
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" ];
|
||||
ldap_schema = "IPA";
|
||||
ldap_default_bind_dn = genso.ldap.bind.dn;
|
||||
ldap_search_base = genso.ldap.baseDn;
|
||||
ldap_user_search_base = "cn=users,cn=accounts,${genso.ldap.baseDn}";
|
||||
ldap_group_search_base = "cn=groups,cn=accounts,${genso.ldap.baseDn}";
|
||||
ldap_user_uuid = "ipaUniqueID";
|
||||
ldap_user_ssh_public_key = "ipaSshPubKey";
|
||||
ldap_user_objectsid = objectsid;
|
||||
ldap_group_uuid = "ipaUniqueID";
|
||||
ldap_group_objectsid = objectsid;
|
||||
};
|
||||
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"];
|
||||
ldap_schema = "IPA";
|
||||
ldap_default_bind_dn = genso.ldap.bind.dn;
|
||||
ldap_search_base = genso.ldap.baseDn;
|
||||
ldap_user_search_base = "cn=users,cn=accounts,${genso.ldap.baseDn}";
|
||||
ldap_group_search_base = "cn=groups,cn=accounts,${genso.ldap.baseDn}";
|
||||
ldap_user_uuid = "ipaUniqueID";
|
||||
ldap_user_ssh_public_key = "ipaSshPubKey";
|
||||
ldap_user_objectsid = objectsid;
|
||||
ldap_group_uuid = "ipaUniqueID";
|
||||
ldap_group_objectsid = objectsid;
|
||||
};
|
||||
ipa = mapOptionDefaults {
|
||||
id_provider = "ipa";
|
||||
auth_provider = "ipa";
|
||||
|
|
@ -124,26 +144,28 @@ in {
|
|||
dyndns_iface = ipa.dyndns.interface;
|
||||
};
|
||||
};
|
||||
domainSettings = mapAlmostOptionDefaults {
|
||||
ipa_hostname = cfg.ipa.hostName;
|
||||
} // mapOptionDefaults {
|
||||
enumerate = true;
|
||||
ipa_domain = genso.domain;
|
||||
krb5_realm = genso.realm;
|
||||
cache_credentials = ipa.cacheCredentials;
|
||||
krb5_store_password_if_offline = ipa.offlinePasswords;
|
||||
#min_id = 8000;
|
||||
#max_id = 8999;
|
||||
};
|
||||
domainSettings =
|
||||
mapAlmostOptionDefaults {
|
||||
ipa_hostname = cfg.ipa.hostName;
|
||||
}
|
||||
// mapOptionDefaults {
|
||||
enumerate = true;
|
||||
ipa_domain = genso.domain;
|
||||
krb5_realm = genso.realm;
|
||||
cache_credentials = ipa.cacheCredentials;
|
||||
krb5_store_password_if_offline = ipa.offlinePasswords;
|
||||
#min_id = 8000;
|
||||
#max_id = 8999;
|
||||
};
|
||||
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 {
|
|||
};
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,22 +41,24 @@
|
|||
};
|
||||
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" // {
|
||||
default = true;
|
||||
};
|
||||
enable =
|
||||
mkEnableOption "domain"
|
||||
// {
|
||||
default = true;
|
||||
};
|
||||
domain = mkOption {
|
||||
type = str;
|
||||
default = name;
|
||||
|
|
@ -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,25 +142,27 @@ in {
|
|||
};
|
||||
};
|
||||
services = let
|
||||
mkServiceOption = name: { modules ? [ ] }: mkOption {
|
||||
type = submoduleWith {
|
||||
modules = [ serviceModule ] ++ modules;
|
||||
specialArgs = {
|
||||
inherit name;
|
||||
nixosConfig = config;
|
||||
mkServiceOption = name: {modules ? []}:
|
||||
mkOption {
|
||||
type = submoduleWith {
|
||||
modules = [serviceModule] ++ modules;
|
||||
specialArgs = {
|
||||
inherit name;
|
||||
nixosConfig = config;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
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: {
|
||||
"domain/${domain.domain}" = mapAttrs (_: mkOptionDefault) domain.settings;
|
||||
}) enabledDomains;
|
||||
settings = [ defaultSettings serviceSettings ] ++ domainSettings;
|
||||
in mkMerge settings;
|
||||
domainSettings =
|
||||
map (domain: {
|
||||
"domain/${domain.domain}" = mapAttrs (_: mkOptionDefault) domain.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" ];
|
||||
shadow = mkIf (!nss.enable || !nss.shadow.enable) (
|
||||
mkForce [ "files" ]
|
||||
);
|
||||
};
|
||||
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"]
|
||||
);
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,34 +97,40 @@ in {
|
|||
inherit owner;
|
||||
inherit (shared) group mode;
|
||||
};
|
||||
setupFiles = singleton {
|
||||
${cfg.rootDir} = toplevel;
|
||||
${cfg.binDir} = toplevel;
|
||||
${cfg.binDir + "/users"} = shared;
|
||||
${cfg.dataDir} = toplevel;
|
||||
${cfg.sharedDataDir} = shared;
|
||||
${cfg.workingDir} = toplevel;
|
||||
${cfg.sharedWorkingDir} = shared;
|
||||
} ++ map (owner: {
|
||||
${cfg.dataDir + "/${owner}"} = personal owner;
|
||||
${cfg.workingDir + "/${owner}"} = personal owner;
|
||||
}) 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" {
|
||||
inherit (toplevel) owner group;
|
||||
mode = "0755";
|
||||
type = "copy";
|
||||
src = pkgs.writeTextFile {
|
||||
name = "steam-${user}.bat";
|
||||
executable = true;
|
||||
text = ''
|
||||
setx GENSO_STEAM_USER ${user}
|
||||
'';
|
||||
};
|
||||
}) cfg.users);
|
||||
setupFiles =
|
||||
singleton {
|
||||
${cfg.rootDir} = toplevel;
|
||||
${cfg.binDir} = toplevel;
|
||||
${cfg.binDir + "/users"} = shared;
|
||||
${cfg.dataDir} = toplevel;
|
||||
${cfg.sharedDataDir} = shared;
|
||||
${cfg.workingDir} = toplevel;
|
||||
${cfg.sharedWorkingDir} = shared;
|
||||
}
|
||||
++ map (owner: {
|
||||
${cfg.dataDir + "/${owner}"} = personal owner;
|
||||
${cfg.workingDir + "/${owner}"} = personal owner;
|
||||
})
|
||||
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" {
|
||||
inherit (toplevel) owner group;
|
||||
mode = "0755";
|
||||
type = "copy";
|
||||
src = pkgs.writeTextFile {
|
||||
name = "steam-${user}.bat";
|
||||
executable = true;
|
||||
text = ''
|
||||
setx GENSO_STEAM_USER ${user}
|
||||
'';
|
||||
};
|
||||
})
|
||||
cfg.users);
|
||||
in {
|
||||
enable = mkIf (cfg.enable || cfg.setup) true;
|
||||
files = mkMerge [
|
||||
|
|
@ -132,14 +142,16 @@ in {
|
|||
mkSharePathWith = {
|
||||
path,
|
||||
winRoot ? "%GENSO_SMB_SHARED_MOUNT%",
|
||||
}: mkWinPath (
|
||||
winRoot
|
||||
+ "/${cfg.sharePath}"
|
||||
+ "/${removePrefix (cfg.rootDir + "/") path}"
|
||||
);
|
||||
mkSharePath = path: config.lib.steam.mkSharePathWith {
|
||||
inherit path;
|
||||
};
|
||||
}:
|
||||
mkWinPath (
|
||||
winRoot
|
||||
+ "/${cfg.sharePath}"
|
||||
+ "/${removePrefix (cfg.rootDir + "/") path}"
|
||||
);
|
||||
mkSharePath = path:
|
||||
config.lib.steam.mkSharePathWith {
|
||||
inherit path;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
);
|
||||
ownerFor = mkOptionDefault (user:
|
||||
if config.target == "user" then user else "admin"
|
||||
);
|
||||
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.relativePath}"
|
||||
user,
|
||||
version,
|
||||
}:
|
||||
config.init
|
||||
);
|
||||
workingPathFor = mkOptionDefault ({ user, version }:
|
||||
cfg.workingDirFor { inherit user version; }
|
||||
+ "/${config.relativePath}"
|
||||
ownerFor = mkOptionDefault (
|
||||
user:
|
||||
if config.target == "user"
|
||||
then user
|
||||
else "admin"
|
||||
);
|
||||
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.relativePath}"
|
||||
);
|
||||
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,85 +186,120 @@
|
|||
fi
|
||||
chown ${owner}:${cfg.group} ${escapeShellArg dest}
|
||||
'';
|
||||
mkStyle = { style, src }: if style != "none" && src == {
|
||||
file = "${emptyFile}";
|
||||
directory = "${emptyDir}";
|
||||
}.${config.type} then "empty" else style;
|
||||
doInit = { style, src, dest }: {
|
||||
none = "true";
|
||||
copy = {
|
||||
file = ''
|
||||
if [[ -L ${escapeShellArg dest} ]]; then
|
||||
rm -f ${escapeShellArg dest}
|
||||
elif [[ -e ${escapeShellArg dest} ]]; then
|
||||
echo ERR: something is in the way of copying ${escapeShellArg dest} >&2
|
||||
mkStyle = {
|
||||
style,
|
||||
src,
|
||||
}:
|
||||
if
|
||||
style
|
||||
!= "none"
|
||||
&& src
|
||||
== {
|
||||
file = "${emptyFile}";
|
||||
directory = "${emptyDir}";
|
||||
}
|
||||
.${config.type}
|
||||
then "empty"
|
||||
else style;
|
||||
doInit = {
|
||||
style,
|
||||
src,
|
||||
dest,
|
||||
}:
|
||||
{
|
||||
none = "true";
|
||||
copy =
|
||||
{
|
||||
file = ''
|
||||
if [[ -L ${escapeShellArg dest} ]]; then
|
||||
rm -f ${escapeShellArg dest}
|
||||
elif [[ -e ${escapeShellArg dest} ]]; then
|
||||
echo ERR: something is in the way of copying ${escapeShellArg dest} >&2
|
||||
exit 1
|
||||
fi
|
||||
cp -TP --no-preserve=all ${escapeShellArg src} ${escapeShellArg dest}
|
||||
chmod ${config.mode.file} ${escapeShellArg dest}
|
||||
chown ${owner}:${cfg.group} ${escapeShellArg dest}
|
||||
'';
|
||||
directory = ''
|
||||
${mkdir dest}
|
||||
cp -rTP --no-preserve=all ${escapeShellArg src} ${escapeShellArg dest}
|
||||
chown -R ${owner}:${cfg.group} ${escapeShellArg dest}
|
||||
find ${escapeShellArg dest} -type f -exec chmod -m${config.mode.file} "{}" \;
|
||||
'';
|
||||
}
|
||||
.${config.type};
|
||||
empty =
|
||||
{
|
||||
directory = ''
|
||||
${mkdir dest}
|
||||
'';
|
||||
file = ''
|
||||
touch ${escapeShellArg dest}
|
||||
chmod ${config.mode.file} ${escapeShellArg dest}
|
||||
chown ${owner}:${cfg.group} ${escapeShellArg dest}
|
||||
'';
|
||||
}
|
||||
.${config.type};
|
||||
symlink = ''
|
||||
if [[ -e ${escapeShellArg dest} && ! -L ${escapeShellArg dest} ]]; then
|
||||
echo ERR: something is in the way of linking ${escapeShellArg dest} >&2
|
||||
exit 1
|
||||
fi
|
||||
cp -TP --no-preserve=all ${escapeShellArg src} ${escapeShellArg dest}
|
||||
chmod ${config.mode.file} ${escapeShellArg dest}
|
||||
chown ${owner}:${cfg.group} ${escapeShellArg dest}
|
||||
ln -sfT ${escapeShellArg src} ${escapeShellArg dest}
|
||||
'';
|
||||
directory = ''
|
||||
${mkdir dest}
|
||||
cp -rTP --no-preserve=all ${escapeShellArg src} ${escapeShellArg dest}
|
||||
chown -R ${owner}:${cfg.group} ${escapeShellArg dest}
|
||||
find ${escapeShellArg dest} -type f -exec chmod -m${config.mode.file} "{}" \;
|
||||
'';
|
||||
}.${config.type};
|
||||
empty = {
|
||||
directory = ''
|
||||
${mkdir dest}
|
||||
'';
|
||||
file = ''
|
||||
touch ${escapeShellArg dest}
|
||||
chmod ${config.mode.file} ${escapeShellArg dest}
|
||||
chown ${owner}:${cfg.group} ${escapeShellArg dest}
|
||||
'';
|
||||
}.${config.type};
|
||||
symlink = ''
|
||||
if [[ -e ${escapeShellArg dest} && ! -L ${escapeShellArg dest} ]]; then
|
||||
echo ERR: something is in the way of linking ${escapeShellArg dest} >&2
|
||||
exit 1
|
||||
fi
|
||||
ln -sfT ${escapeShellArg src} ${escapeShellArg dest}
|
||||
'';
|
||||
symlink-shallow = {
|
||||
directory = ''
|
||||
${mkdir dest}
|
||||
ln -sf ${escapeShellArg src}/* ${escapeShellArg dest}/
|
||||
'';
|
||||
}.${config.type};
|
||||
}.${mkStyle { inherit style src; }};
|
||||
doSetup = { style, src, dest }: rec {
|
||||
none = "true";
|
||||
copy = {
|
||||
file = ''
|
||||
${empty}
|
||||
'';
|
||||
directory = ''
|
||||
${empty}
|
||||
if [[ ${escapeShellArg dest}/* != ${escapeShellArg dest}/\* ]]; then
|
||||
chmod -m${config.mode.file} ${escapeShellArg dest}/*
|
||||
fi
|
||||
'';
|
||||
}.${config.type};
|
||||
empty = {
|
||||
directory = ''
|
||||
chmod ${config.mode.dir} ${escapeShellArg dest}
|
||||
chown ${owner}:${cfg.group} ${escapeShellArg dest}
|
||||
'';
|
||||
file = ''
|
||||
chmod ${config.mode.file} ${escapeShellArg dest}
|
||||
chown ${owner}:${cfg.group} ${escapeShellArg dest}
|
||||
'';
|
||||
}.${config.type};
|
||||
symlink = "true";
|
||||
symlink-shallow = {
|
||||
directory = ''
|
||||
${mkdir.directory}
|
||||
'';
|
||||
}.${config.type};
|
||||
}.${mkStyle { inherit style src; }};
|
||||
symlink-shallow =
|
||||
{
|
||||
directory = ''
|
||||
${mkdir dest}
|
||||
ln -sf ${escapeShellArg src}/* ${escapeShellArg dest}/
|
||||
'';
|
||||
}
|
||||
.${config.type};
|
||||
}
|
||||
.${mkStyle {inherit style src;}};
|
||||
doSetup = {
|
||||
style,
|
||||
src,
|
||||
dest,
|
||||
}:
|
||||
rec {
|
||||
none = "true";
|
||||
copy =
|
||||
{
|
||||
file = ''
|
||||
${empty}
|
||||
'';
|
||||
directory = ''
|
||||
${empty}
|
||||
if [[ ${escapeShellArg dest}/* != ${escapeShellArg dest}/\* ]]; then
|
||||
chmod -m${config.mode.file} ${escapeShellArg dest}/*
|
||||
fi
|
||||
'';
|
||||
}
|
||||
.${config.type};
|
||||
empty =
|
||||
{
|
||||
directory = ''
|
||||
chmod ${config.mode.dir} ${escapeShellArg dest}
|
||||
chown ${owner}:${cfg.group} ${escapeShellArg dest}
|
||||
'';
|
||||
file = ''
|
||||
chmod ${config.mode.file} ${escapeShellArg dest}
|
||||
chown ${owner}:${cfg.group} ${escapeShellArg dest}
|
||||
'';
|
||||
}
|
||||
.${config.type};
|
||||
symlink = "true";
|
||||
symlink-shallow =
|
||||
{
|
||||
directory = ''
|
||||
${mkdir.directory}
|
||||
'';
|
||||
}
|
||||
.${config.type};
|
||||
}
|
||||
.${mkStyle {inherit style src;}};
|
||||
init = doInit {
|
||||
style = config.initStyle;
|
||||
src = initPath;
|
||||
|
|
@ -242,37 +315,46 @@
|
|||
src = srcPath;
|
||||
dest = workingPath;
|
||||
};
|
||||
checkFlag = {
|
||||
file = {
|
||||
none = "e";
|
||||
copy = "f";
|
||||
symlink = "L";
|
||||
}.${config.initStyle};
|
||||
directory = {
|
||||
none = "e";
|
||||
copy = "d";
|
||||
symlink-shallow = "d";
|
||||
symlink = "L";
|
||||
}.${config.initStyle};
|
||||
}.${config.type};
|
||||
checkFlag =
|
||||
{
|
||||
file =
|
||||
{
|
||||
none = "e";
|
||||
copy = "f";
|
||||
symlink = "L";
|
||||
}
|
||||
.${config.initStyle};
|
||||
directory =
|
||||
{
|
||||
none = "e";
|
||||
copy = "d";
|
||||
symlink-shallow = "d";
|
||||
symlink = "L";
|
||||
}
|
||||
.${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 ''
|
||||
if [[ ! -${checkFlag} ${escapeShellArg srcPath} ]]; then
|
||||
${init}
|
||||
else
|
||||
${setup}
|
||||
fi
|
||||
'' else ''
|
||||
if [[ ! -${checkFlag} ${escapeShellArg srcPath} ]]; then
|
||||
echo ERR: src ${escapeShellArg srcPath} for ${escapeShellArg workingPath} does not exist >&2
|
||||
exit 1
|
||||
fi
|
||||
'';
|
||||
check =
|
||||
if initPath != null
|
||||
then ''
|
||||
if [[ ! -${checkFlag} ${escapeShellArg srcPath} ]]; then
|
||||
${init}
|
||||
else
|
||||
${setup}
|
||||
fi
|
||||
''
|
||||
else ''
|
||||
if [[ ! -${checkFlag} ${escapeShellArg srcPath} ]]; then
|
||||
echo ERR: src ${escapeShellArg srcPath} for ${escapeShellArg workingPath} does not exist >&2
|
||||
exit 1
|
||||
fi
|
||||
'';
|
||||
in ''
|
||||
${checkParent}
|
||||
${check}
|
||||
|
|
@ -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 = ''
|
||||
cd /d "%STEAM_BS_LIBRARY%"
|
||||
'' + ''"%STEAM_BS_LIBRARY%\Beat Saber.exe"'';
|
||||
launch =
|
||||
''
|
||||
cd /d "%STEAM_BS_LIBRARY%"
|
||||
''
|
||||
+ ''"%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,19 +507,25 @@
|
|||
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}" ''
|
||||
set -eu
|
||||
export PATH="$PATH:${makeBinPath [ pkgs.coreutils ]}"
|
||||
${concatStringsSep "\n" setupFiles}
|
||||
'';
|
||||
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]}"
|
||||
${concatStringsSep "\n" setupFiles}
|
||||
'';
|
||||
in {
|
||||
options.services.steam.beatsaber = with lib.types; {
|
||||
enable = mkEnableOption "beatsaber scripts";
|
||||
setup = mkEnableOption "beatsaber data" // {
|
||||
default = accountSwitch.setup;
|
||||
};
|
||||
setup =
|
||||
mkEnableOption "beatsaber data"
|
||||
// {
|
||||
default = accountSwitch.setup;
|
||||
};
|
||||
group = mkOption {
|
||||
type = str;
|
||||
default = "beatsaber";
|
||||
|
|
@ -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 // {
|
||||
target = "shared";
|
||||
};
|
||||
mapGameFile = file: file // {
|
||||
target = "game";
|
||||
};
|
||||
mapUserDataFile = file: nameValuePair "UserData/${file}" {
|
||||
target = "user";
|
||||
};
|
||||
mapSharedFile = file:
|
||||
file
|
||||
// {
|
||||
target = "shared";
|
||||
};
|
||||
mapGameFile = file:
|
||||
file
|
||||
// {
|
||||
target = "game";
|
||||
};
|
||||
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,132 +891,157 @@ in {
|
|||
"AppData"
|
||||
"UserData"
|
||||
];
|
||||
setupFiles = [
|
||||
setupFiles =
|
||||
[
|
||||
{
|
||||
${cfg.sharedDataDir} = toplevel;
|
||||
${cfg.binDir} = shared;
|
||||
}
|
||||
(listToAttrs (
|
||||
map (
|
||||
folder:
|
||||
nameValuePair "${cfg.sharedDataDir}/${folder}" shared
|
||||
)
|
||||
sharedFolders
|
||||
))
|
||||
]
|
||||
++ 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: {
|
||||
"${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)
|
||||
++ mapAttrsToList (_: version: {
|
||||
"${cfg.sharedDataDir}/${version.version}" = shared;
|
||||
})
|
||||
cfg.versions;
|
||||
versionBinFiles =
|
||||
mapAttrs' (
|
||||
_: version:
|
||||
nameValuePair
|
||||
"${cfg.binDir}/${replaceStrings ["."] ["_"] version.version}.bat"
|
||||
{
|
||||
inherit (bin) owner group mode type;
|
||||
src = pkgs.writeTextFile {
|
||||
name = "beatsaber-${version.version}.bat";
|
||||
executable = true;
|
||||
text = ''
|
||||
setx GENSO_STEAM_BS_VERSION ${version.version}
|
||||
'';
|
||||
};
|
||||
}
|
||||
)
|
||||
cfg.versions;
|
||||
userBinFiles =
|
||||
mapAttrs' (
|
||||
_: user:
|
||||
nameValuePair
|
||||
"${cfg.binDir}/${user.name}.bat"
|
||||
{
|
||||
inherit (bin) owner group mode type;
|
||||
src = pkgs.writeTextFile {
|
||||
name = "beatsaber-${user.name}.bat";
|
||||
executable = true;
|
||||
text = beatsaber-user {
|
||||
user = user.name;
|
||||
version = user.preferredVersion;
|
||||
};
|
||||
};
|
||||
}
|
||||
)
|
||||
cfg.users;
|
||||
binFiles =
|
||||
{
|
||||
${cfg.sharedDataDir} = toplevel;
|
||||
${cfg.binDir} = shared;
|
||||
}
|
||||
(listToAttrs (
|
||||
map (folder:
|
||||
nameValuePair "${cfg.sharedDataDir}/${folder}" shared
|
||||
) sharedFolders
|
||||
))
|
||||
] ++ 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: {
|
||||
"${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)
|
||||
++ mapAttrsToList (_: version: {
|
||||
"${cfg.sharedDataDir}/${version.version}" = shared;
|
||||
}) cfg.versions;
|
||||
versionBinFiles = mapAttrs' (_: version: nameValuePair
|
||||
"${cfg.binDir}/${replaceStrings [ "." ] [ "_" ] version.version}.bat"
|
||||
{
|
||||
inherit (bin) owner group mode type;
|
||||
src = pkgs.writeTextFile {
|
||||
name = "beatsaber-${version.version}.bat";
|
||||
executable = true;
|
||||
text = ''
|
||||
setx GENSO_STEAM_BS_VERSION ${version.version}
|
||||
'';
|
||||
"${cfg.binDir}/mount.bat" = {
|
||||
inherit (bin) owner group mode type;
|
||||
src = pkgs.writeTextFile {
|
||||
name = "beatsaber-mount.bat";
|
||||
executable = true;
|
||||
text = mountbeatsaber;
|
||||
};
|
||||
};
|
||||
}
|
||||
) cfg.versions;
|
||||
userBinFiles = mapAttrs' (_: user: nameValuePair
|
||||
"${cfg.binDir}/${user.name}.bat"
|
||||
{
|
||||
inherit (bin) owner group mode type;
|
||||
src = pkgs.writeTextFile {
|
||||
name = "beatsaber-${user.name}.bat";
|
||||
executable = true;
|
||||
text = beatsaber-user {
|
||||
user = user.name;
|
||||
version = user.preferredVersion;
|
||||
"${cfg.binDir}/launch.bat" = {
|
||||
inherit (bin) owner group mode type;
|
||||
src = pkgs.writeTextFile {
|
||||
name = "beatsaber-launch.bat";
|
||||
executable = true;
|
||||
text = launchbeatsaber;
|
||||
};
|
||||
};
|
||||
"${cfg.binDir}/fpfc.bat" = {
|
||||
inherit (bin) owner group mode type;
|
||||
src = pkgs.writeTextFile {
|
||||
name = "beatsaber-fpfc.bat";
|
||||
executable = true;
|
||||
text = fpfcbeatsaber;
|
||||
};
|
||||
};
|
||||
"${cfg.binDir}/setup.bat" = {
|
||||
inherit (bin) owner group mode type;
|
||||
src = pkgs.writeTextFile {
|
||||
name = "beatsaber-setup.bat";
|
||||
executable = true;
|
||||
text = setupbeatsaber;
|
||||
};
|
||||
};
|
||||
"${cfg.binDir}/local-launch.bat" = {
|
||||
inherit (bin) owner group mode type;
|
||||
src = pkgs.writeTextFile {
|
||||
name = "beatsaber-local-launch.bat";
|
||||
executable = true;
|
||||
text = localbeatsaber-launch;
|
||||
};
|
||||
};
|
||||
"${cfg.binDir}/local-mount.bat" = {
|
||||
inherit (bin) owner group mode type;
|
||||
src = pkgs.writeTextFile {
|
||||
name = "beatsaber-local-mount.bat";
|
||||
executable = true;
|
||||
text = localbeatsaber-mount;
|
||||
};
|
||||
};
|
||||
"${cfg.binDir}/local-vanilla.bat" = {
|
||||
inherit (bin) owner group mode type;
|
||||
src = pkgs.writeTextFile {
|
||||
name = "beatsaber-local-vanilla.bat";
|
||||
executable = true;
|
||||
text = localbeatsaber-vanilla;
|
||||
};
|
||||
};
|
||||
"${cfg.binDir}/vanilla.bat" = {
|
||||
inherit (bin) owner group mode type;
|
||||
src = pkgs.writeTextFile {
|
||||
name = "beatsaber-version-vanilla.bat";
|
||||
executable = true;
|
||||
text = vanilla;
|
||||
};
|
||||
};
|
||||
"${cfg.binDir}/ModAssistant.exe" = {
|
||||
inherit (bin) owner group mode type;
|
||||
src = pkgs.fetchurl {
|
||||
url = "https://github.com/Assistant/ModAssistant/releases/download/v1.1.32/ModAssistant.exe";
|
||||
hash = "sha256-ozu2gYFiz+2BjptqL80DmUopbahbyGKFO1IPd7BhVPM=";
|
||||
executable = true;
|
||||
};
|
||||
};
|
||||
}
|
||||
) cfg.users;
|
||||
binFiles = {
|
||||
"${cfg.binDir}/mount.bat" = {
|
||||
inherit (bin) owner group mode type;
|
||||
src = pkgs.writeTextFile {
|
||||
name = "beatsaber-mount.bat";
|
||||
executable = true;
|
||||
text = mountbeatsaber;
|
||||
};
|
||||
};
|
||||
"${cfg.binDir}/launch.bat" = {
|
||||
inherit (bin) owner group mode type;
|
||||
src = pkgs.writeTextFile {
|
||||
name = "beatsaber-launch.bat";
|
||||
executable = true;
|
||||
text = launchbeatsaber;
|
||||
};
|
||||
};
|
||||
"${cfg.binDir}/fpfc.bat" = {
|
||||
inherit (bin) owner group mode type;
|
||||
src = pkgs.writeTextFile {
|
||||
name = "beatsaber-fpfc.bat";
|
||||
executable = true;
|
||||
text = fpfcbeatsaber;
|
||||
};
|
||||
};
|
||||
"${cfg.binDir}/setup.bat" = {
|
||||
inherit (bin) owner group mode type;
|
||||
src = pkgs.writeTextFile {
|
||||
name = "beatsaber-setup.bat";
|
||||
executable = true;
|
||||
text = setupbeatsaber;
|
||||
};
|
||||
};
|
||||
"${cfg.binDir}/local-launch.bat" = {
|
||||
inherit (bin) owner group mode type;
|
||||
src = pkgs.writeTextFile {
|
||||
name = "beatsaber-local-launch.bat";
|
||||
executable = true;
|
||||
text = localbeatsaber-launch;
|
||||
};
|
||||
};
|
||||
"${cfg.binDir}/local-mount.bat" = {
|
||||
inherit (bin) owner group mode type;
|
||||
src = pkgs.writeTextFile {
|
||||
name = "beatsaber-local-mount.bat";
|
||||
executable = true;
|
||||
text = localbeatsaber-mount;
|
||||
};
|
||||
};
|
||||
"${cfg.binDir}/local-vanilla.bat" = {
|
||||
inherit (bin) owner group mode type;
|
||||
src = pkgs.writeTextFile {
|
||||
name = "beatsaber-local-vanilla.bat";
|
||||
executable = true;
|
||||
text = localbeatsaber-vanilla;
|
||||
};
|
||||
};
|
||||
"${cfg.binDir}/vanilla.bat" = {
|
||||
inherit (bin) owner group mode type;
|
||||
src = pkgs.writeTextFile {
|
||||
name = "beatsaber-version-vanilla.bat";
|
||||
executable = true;
|
||||
text = vanilla;
|
||||
};
|
||||
};
|
||||
"${cfg.binDir}/ModAssistant.exe" = {
|
||||
inherit (bin) owner group mode type;
|
||||
src = pkgs.fetchurl {
|
||||
url = "https://github.com/Assistant/ModAssistant/releases/download/v1.1.32/ModAssistant.exe";
|
||||
hash = "sha256-ozu2gYFiz+2BjptqL80DmUopbahbyGKFO1IPd7BhVPM=";
|
||||
executable = true;
|
||||
};
|
||||
};
|
||||
} // versionBinFiles
|
||||
// userBinFiles;
|
||||
// versionBinFiles
|
||||
// userBinFiles;
|
||||
in {
|
||||
enable = mkIf cfg.setup true;
|
||||
files = mkIf cfg.setup (mkMerge (
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue