System: Rename system/modules to system/systemmodules
This commit is contained in:
14
system/systemmodules/0_template/default.nix
Normal file
14
system/systemmodules/0_template/default.nix
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
mylib,
|
||||
...
|
||||
}: let
|
||||
inherit (config.modules) TEMPLATE;
|
||||
in {
|
||||
options.modules.TEMPLATE = import ./options.nix {inherit lib mylib;};
|
||||
|
||||
config =
|
||||
lib.mkIf TEMPLATE.enable {
|
||||
};
|
||||
}
|
||||
7
system/systemmodules/0_template/options.nix
Normal file
7
system/systemmodules/0_template/options.nix
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
lib,
|
||||
mylib,
|
||||
...
|
||||
}: {
|
||||
enable = lib.mkEnableOption "TEMPLATE";
|
||||
}
|
||||
52
system/systemmodules/1_deprecated/agenix/default.nix
Normal file
52
system/systemmodules/1_deprecated/agenix/default.nix
Normal file
@ -0,0 +1,52 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
mylib,
|
||||
pkgs,
|
||||
username,
|
||||
publicKeys,
|
||||
...
|
||||
}: let
|
||||
inherit (config.modules) agenix;
|
||||
in {
|
||||
options.modules.agenix = import ./options.nix {inherit lib mylib;};
|
||||
|
||||
config = {
|
||||
# NOTE: Add below snippet to home/christoph/default.nix to generate the secrets.nix file
|
||||
|
||||
# The user will be able to decrypt .age files using agenix.
|
||||
# On each user/machine, this should generate a corresponding secrets.nix
|
||||
# "${config.paths.nixflake}/system/modules/agenix/secrets.nix".text = let
|
||||
# mkSecret = key: name: "\"${name}.age\".publicKeys = [\"${key}\"];";
|
||||
# in ''
|
||||
# # This file will contain keys depending on the host/by which user it was built on.
|
||||
# {
|
||||
# ${lib.optionalString
|
||||
# # If this user defined any secrets...
|
||||
# (builtins.hasAttr "${username}" nixosConfig.modules.agenix.secrets)
|
||||
# # ...we will add them to the current secrets.nix,
|
||||
# # s.t. agenix can be used to encrypt/access them.
|
||||
# (builtins.concatStringsSep "\n"
|
||||
# (builtins.map
|
||||
# (mkSecret publicKeys.${username}.ssh)
|
||||
# nixosConfig.modules.agenix.secrets.${username}))}
|
||||
# }
|
||||
# '';
|
||||
|
||||
# Register generated secrets to the age system module
|
||||
age.secrets = let
|
||||
mkSecretIfExists = name:
|
||||
# If this user has already encrypted the secret...
|
||||
if builtins.pathExists ./${name}.age
|
||||
# ...we will register it with age...
|
||||
then {${name}.file = ./${name}.age;}
|
||||
# ...otherwise we link to a bogus file.
|
||||
else {${name}.file = ./void.age;};
|
||||
in
|
||||
lib.mkIf
|
||||
# If this user defined any secrets...
|
||||
(builtins.hasAttr "${username}" agenix.secrets)
|
||||
# ...we will register all secrets files that have already been generated.
|
||||
(lib.mkMerge (builtins.map mkSecretIfExists agenix.secrets.${username}));
|
||||
};
|
||||
}
|
||||
22
system/systemmodules/1_deprecated/agenix/options.nix
Normal file
22
system/systemmodules/1_deprecated/agenix/options.nix
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
lib,
|
||||
mylib,
|
||||
...
|
||||
}: {
|
||||
secrets = lib.mkOption {
|
||||
type = lib.types.attrs;
|
||||
description = "The secret files managed by agenix (encrypted by SSH key)";
|
||||
example = ''
|
||||
{
|
||||
christoph = [
|
||||
"heidi-discord-token"
|
||||
"kopia-password"
|
||||
"kopia-server-username"
|
||||
"kopia-server-password"
|
||||
];
|
||||
}
|
||||
'';
|
||||
|
||||
default = {};
|
||||
};
|
||||
}
|
||||
1
system/systemmodules/1_deprecated/agenix/void.age
Normal file
1
system/systemmodules/1_deprecated/agenix/void.age
Normal file
@ -0,0 +1 @@
|
||||
This secret has not been generated.
|
||||
76
system/systemmodules/1_deprecated/containers/default.nix
Normal file
76
system/systemmodules/1_deprecated/containers/default.nix
Normal file
@ -0,0 +1,76 @@
|
||||
# TODO: Generate file with names for rofi
|
||||
{
|
||||
config,
|
||||
nixosConfig,
|
||||
lib,
|
||||
mylib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
with lib;
|
||||
with mylib.virtualisation;
|
||||
with mylib.modules; let
|
||||
cfg = config.modules.containers;
|
||||
in {
|
||||
options.modules.containers = import ./options.nix {inherit lib mylib;};
|
||||
|
||||
# TODO: These need config options exposed through the module,
|
||||
# e.g. to set paths/volumes/binds differently per system...
|
||||
|
||||
config = mkIf cfg.enable rec {
|
||||
virtualisation.oci-containers.containers = {
|
||||
# Examples how to use the mkOciContainer function:
|
||||
|
||||
# stablediffusion = mkIf cfg.stablediffusion.enable (mkOciContainer {
|
||||
# image = "rocm/pytorch:rocm5.5_ubuntu20.04_py3.8_pytorch_1.13.1";
|
||||
# vols = [
|
||||
# "/home/christoph/NoSync/StableDiffusionWebUI:/webui-data"
|
||||
# ];
|
||||
# opts = [
|
||||
# "--network=host"
|
||||
# "--device=/dev/kfd"
|
||||
# "--device=/dev/dri"
|
||||
# "--group-add=video"
|
||||
# "--ipc=host"
|
||||
# "--cap-add=SYS_PTRACE"
|
||||
# "--security-opt=seccomp=unconfined"
|
||||
# ];
|
||||
# extraConfig = {
|
||||
# entrypoint = "/webui-data/launch.sh";
|
||||
# };
|
||||
# });
|
||||
|
||||
# sonarr = mkIf cfg.sonarr.enable (mkOciContainer {
|
||||
# image = "linuxserver/sonarr:3.0.10";
|
||||
# id-ports = [8989];
|
||||
# vols = [
|
||||
# "sonarr-config:/config:Z"
|
||||
# "/media/Shows:/media/Shows"
|
||||
# "/media/Usenet:/media/Usenet"
|
||||
# ];
|
||||
# netns = "wg0-de-115";
|
||||
# netdns = "10.2.0.1";
|
||||
# });
|
||||
};
|
||||
|
||||
# Allow start/stop containers without root password
|
||||
modules.polkit.allowedSystemServices = let
|
||||
container-services =
|
||||
virtualisation.oci-containers.containers
|
||||
|> builtins.attrNames
|
||||
|> builtins.filter (c: cfg.${c}.enable)
|
||||
|> builtins.map (c: "podman-${c}.service");
|
||||
in
|
||||
container-services;
|
||||
|
||||
# Generate list of containers for rofi menu
|
||||
environment.etc."rofi-containers".text = let
|
||||
containers =
|
||||
virtualisation.oci-containers.containers
|
||||
|> builtins.attrNames
|
||||
|> builtins.filter (c: cfg.${c}.enable)
|
||||
|> builtins.concatStringsSep "\n";
|
||||
in
|
||||
containers;
|
||||
};
|
||||
}
|
||||
50
system/systemmodules/1_deprecated/containers/options.nix
Normal file
50
system/systemmodules/1_deprecated/containers/options.nix
Normal file
@ -0,0 +1,50 @@
|
||||
# TODO: Rofi Integration
|
||||
# - Hotkey through hyprland module
|
||||
# - Menu through rofi module
|
||||
# - Permissions through polkit module
|
||||
{
|
||||
lib,
|
||||
mylib,
|
||||
...
|
||||
}:
|
||||
with lib;
|
||||
with mylib.modules; {
|
||||
enable = mkEnableOption "Enable OCI Containers";
|
||||
|
||||
homeassistant = {
|
||||
enable = mkEnableOption "Enable HomeAssistant Container";
|
||||
};
|
||||
stablediffusion = {
|
||||
enable = mkEnableOption "Enable StableDiffusion Container with Automatic1111 WebUI";
|
||||
};
|
||||
jellyfin = {
|
||||
enable = mkEnableOption "Enable Jellyfin Container";
|
||||
};
|
||||
fileflows = {
|
||||
enable = mkEnableOption "Enable FileFlows Container";
|
||||
};
|
||||
sonarr = {
|
||||
enable = mkEnableOption "Enable Sonarr Container";
|
||||
};
|
||||
radarr = {
|
||||
enable = mkEnableOption "Enable Radarr Container";
|
||||
};
|
||||
hydra = {
|
||||
enable = mkEnableOption "Enable Hydra Container";
|
||||
};
|
||||
sabnzbd = {
|
||||
enable = mkEnableOption "Enable SabNzbd Container";
|
||||
};
|
||||
|
||||
rofiIntegration = {
|
||||
enable = mkEnableOption "Enable Rofi Menu for Container Servicing";
|
||||
hotkey = mkOption {
|
||||
type = types.str;
|
||||
example = ''
|
||||
"$mainMod, D"
|
||||
'';
|
||||
default = "$mainMod, D";
|
||||
description = "What Key should trigger the Menu";
|
||||
};
|
||||
};
|
||||
}
|
||||
51
system/systemmodules/bootloader/default.nix
Normal file
51
system/systemmodules/bootloader/default.nix
Normal file
@ -0,0 +1,51 @@
|
||||
{
|
||||
pkgs,
|
||||
config,
|
||||
lib,
|
||||
mylib,
|
||||
...
|
||||
}: let
|
||||
inherit (config.modules) bootloader;
|
||||
in {
|
||||
options.modules.bootloader = import ./options.nix {inherit lib mylib;};
|
||||
|
||||
config = lib.mkIf bootloader.enable (lib.mkMerge [
|
||||
{
|
||||
boot.loader = {
|
||||
timeout = 10;
|
||||
efi.canTouchEfiVariables = true;
|
||||
efi.efiSysMountPoint = bootloader.systemd-boot.bootDevice;
|
||||
};
|
||||
}
|
||||
(lib.mkIf (bootloader.loader == "systemd-boot") {
|
||||
boot.loader.systemd-boot = {
|
||||
enable = true;
|
||||
configurationLimit = 5;
|
||||
editor = false;
|
||||
consoleMode = "max";
|
||||
};
|
||||
})
|
||||
(lib.mkIf (bootloader.loader == "grub") {
|
||||
boot.loader.grub = {
|
||||
enable = true;
|
||||
useOSProber = true;
|
||||
device = bootloader.grub.bootDevice;
|
||||
};
|
||||
})
|
||||
(lib.mkIf (bootloader.loader == "lanzaboote") {
|
||||
environment.systemPackages = with pkgs; [
|
||||
sbctl
|
||||
];
|
||||
|
||||
# Lanzaboote replaces systemd-boot
|
||||
boot.loader.systemd-boot.enable = lib.mkForce false;
|
||||
|
||||
boot.lanzaboote = {
|
||||
enable = true;
|
||||
|
||||
# WARN: Make sure to persist this if using impermanence!
|
||||
pkiBundle = "/var/lib/sbctl";
|
||||
};
|
||||
})
|
||||
]);
|
||||
}
|
||||
32
system/systemmodules/bootloader/options.nix
Normal file
32
system/systemmodules/bootloader/options.nix
Normal file
@ -0,0 +1,32 @@
|
||||
{
|
||||
lib,
|
||||
mylib,
|
||||
...
|
||||
}: {
|
||||
enable = lib.mkEnableOption "Enable boot loader configuration";
|
||||
|
||||
loader = lib.mkOption {
|
||||
type = lib.types.enum [
|
||||
"grub"
|
||||
"systemd-boot"
|
||||
"lanzaboote"
|
||||
];
|
||||
description = "What boot loader to use";
|
||||
example = "systemd-boot";
|
||||
default = "systemd-boot";
|
||||
};
|
||||
|
||||
systemd-boot.bootDevice = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "The path to the boot partition";
|
||||
example = "/boot/efi";
|
||||
default = "/boot/efi";
|
||||
};
|
||||
|
||||
grub.bootDevice = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "The path to the boot partition";
|
||||
example = "/dev/sda";
|
||||
default = "/dev/sda";
|
||||
};
|
||||
}
|
||||
13
system/systemmodules/default.nix
Normal file
13
system/systemmodules/default.nix
Normal file
@ -0,0 +1,13 @@
|
||||
{...}: {
|
||||
imports = [
|
||||
./bootloader
|
||||
./desktopportal
|
||||
./docker
|
||||
./fonts
|
||||
./impermanence
|
||||
./mime
|
||||
./network
|
||||
./polkit
|
||||
./sops-nix
|
||||
];
|
||||
}
|
||||
66
system/systemmodules/desktopportal/default.nix
Normal file
66
system/systemmodules/desktopportal/default.nix
Normal file
@ -0,0 +1,66 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
mylib,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
inherit (config.modules) desktopportal;
|
||||
in {
|
||||
options.modules.desktopportal = import ./options.nix {inherit lib mylib;};
|
||||
|
||||
config = lib.mkIf desktopportal.enable {
|
||||
xdg = {
|
||||
portal = {
|
||||
enable = true;
|
||||
xdgOpenUsePortal = true;
|
||||
wlr.enable = true;
|
||||
|
||||
# TODO: Replace lib.optional(s) throughout the config with mkMerge
|
||||
config = lib.mkMerge [
|
||||
{
|
||||
# https://discourse.nixos.org/t/clicked-links-in-desktop-apps-not-opening-browers/29114/26
|
||||
common.default = ["*"];
|
||||
}
|
||||
|
||||
(lib.mkIf desktopportal.termfilechooser.enable {
|
||||
common."org.freedesktop.impl.portal.FileChooser" = ["termfilechooser"];
|
||||
})
|
||||
|
||||
(lib.mkIf desktopportal.hyprland.enable {
|
||||
hyprland.default = ["hyprland"];
|
||||
})
|
||||
|
||||
(lib.mkIf
|
||||
(desktopportal.hyprland.enable && desktopportal.termfilechooser.enable) {
|
||||
hyprland."org.freedesktop.impl.portal.FileChooser" = ["termfilechooser"];
|
||||
})
|
||||
|
||||
(lib.mkIf desktopportal.niri.enable {
|
||||
niri.default = ["gtk" "gnome"];
|
||||
})
|
||||
|
||||
(lib.mkIf (desktopportal.niri.enable && desktopportal.termfilechooser.enable) {
|
||||
niri."org.freedesktop.impl.portal.FileChooser" = ["termfilechooser"];
|
||||
})
|
||||
];
|
||||
|
||||
extraPortals = with pkgs;
|
||||
lib.mkMerge [
|
||||
[
|
||||
xdg-desktop-portal-gtk # Fallback
|
||||
]
|
||||
|
||||
# We don't need to install that explicitly
|
||||
# (lib.mkIf desktopportal.hyprland.enable [
|
||||
# xdg-desktop-portal-hyprland
|
||||
# ])
|
||||
|
||||
(lib.mkIf desktopportal.termfilechooser.enable [
|
||||
xdg-desktop-portal-termfilechooser # Filechooser using yazi
|
||||
])
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
10
system/systemmodules/desktopportal/options.nix
Normal file
10
system/systemmodules/desktopportal/options.nix
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
lib,
|
||||
mylib,
|
||||
...
|
||||
}: {
|
||||
enable = lib.mkEnableOption "Enable XDG desktop portals";
|
||||
termfilechooser.enable = lib.mkEnableOption "Enable xdg-desktop-portal-termfilechooser";
|
||||
hyprland.enable = lib.mkEnableOption "Configure portals for Hyprland";
|
||||
niri.enable = lib.mkEnableOption "Configure portals for Niri";
|
||||
}
|
||||
146
system/systemmodules/docker/default.nix
Normal file
146
system/systemmodules/docker/default.nix
Normal file
@ -0,0 +1,146 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
mylib,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
inherit (config.modules) docker;
|
||||
in {
|
||||
options.modules.docker = import ./options.nix {inherit lib mylib;};
|
||||
|
||||
config = lib.mkIf docker.enable {
|
||||
environment.variables = lib.mkMerge [
|
||||
(lib.mkIf ((!docker.podman) && docker.docker.buildkit) {
|
||||
DOCKER_BUILDKIT = 1;
|
||||
})
|
||||
];
|
||||
|
||||
networking.firewall.trustedInterfaces = ["docker0" "podman0"];
|
||||
|
||||
# Needed for default bridge network to automatically work
|
||||
# boot.kernel.sysctl."net.ipv4.ip_forward" = 1;
|
||||
# boot.kernel.sysctl."net.ipv6.ip_forward" = 1;
|
||||
|
||||
virtualisation = {
|
||||
docker = {
|
||||
enable = !docker.podman;
|
||||
autoPrune.enable = true;
|
||||
|
||||
extraPackages = with pkgs; [docker-compose];
|
||||
|
||||
# TODO: Rootless docker has no internet?
|
||||
rootless = {
|
||||
enable = docker.docker.rootless;
|
||||
setSocketVariable = true;
|
||||
};
|
||||
|
||||
daemon.settings = {
|
||||
# ipv6 = true;
|
||||
# fixed-cidr-v6 = "2001::/80";
|
||||
|
||||
dns = [
|
||||
"8.8.8.8"
|
||||
# "2001:4860:4860::8888"
|
||||
|
||||
# "127.0.0.1"
|
||||
# "192.168.86.25"
|
||||
];
|
||||
|
||||
hosts = [
|
||||
# Allow access to docker socket
|
||||
"tcp://0.0.0.0:2375"
|
||||
"unix:///var/run/docker.sock"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
podman = {
|
||||
enable = docker.podman;
|
||||
autoPrune.enable = true;
|
||||
dockerCompat = true;
|
||||
dockerSocket.enable = true;
|
||||
defaultNetwork.settings.dns_enabled = true;
|
||||
|
||||
extraPackages = with pkgs; [podman-compose];
|
||||
};
|
||||
|
||||
oci-containers.backend =
|
||||
if docker.podman
|
||||
then "podman"
|
||||
else "docker"; # "docker" or "podman"
|
||||
libvirtd.enable = true;
|
||||
};
|
||||
|
||||
systemd.services = let
|
||||
cli =
|
||||
if docker.podman
|
||||
then "${config.virtualisation.podman.package}/bin/podman"
|
||||
else "${config.virtualisation.docker.package}/bin/docker";
|
||||
|
||||
mkDockerNetwork = options:
|
||||
builtins.concatStringsSep "\n" [
|
||||
# Make sure to return true on fail to not crash
|
||||
''
|
||||
check=$(${cli} network inspect ${options.name} || true)
|
||||
if [ -z "$check" ]; then
|
||||
''
|
||||
|
||||
(builtins.concatStringsSep " " [
|
||||
"${cli} network create"
|
||||
|
||||
# Disable masquerading
|
||||
(lib.optionalString
|
||||
options.disable_masquerade
|
||||
''-o "com.docker.network.bridge.enable_ip_masquerade"="false"'')
|
||||
|
||||
# Enable ipv6
|
||||
(lib.optionalString
|
||||
options.ipv6.enable
|
||||
"--ipv6")
|
||||
(lib.optionalString
|
||||
(!(builtins.isNull options.ipv6.gateway))
|
||||
''--gateway="${options.ipv6.gateway}"'')
|
||||
(lib.optionalString
|
||||
(!(builtins.isNull options.ipv6.subnet))
|
||||
''--subnet="${options.ipv6.subnet}"'')
|
||||
|
||||
"${options.name}"
|
||||
])
|
||||
|
||||
''
|
||||
else
|
||||
echo "Network ${options.name} already exists!"
|
||||
fi
|
||||
''
|
||||
];
|
||||
|
||||
mkPodmanNetwork = options:
|
||||
builtins.concatStringsSep "\n" [
|
||||
''
|
||||
echo "Can't create Podman networks (yet)!"
|
||||
''
|
||||
];
|
||||
|
||||
mkSystemdNetworkService = options: let
|
||||
toolName =
|
||||
if docker.podman
|
||||
then "podman"
|
||||
else "docker";
|
||||
in {
|
||||
"${toolName}-create-${options.name}-network" = {
|
||||
description = "Creates the ${toolName} network \"${options.name}\"";
|
||||
after = ["network.target"];
|
||||
wantedBy = ["multi-user.target"];
|
||||
|
||||
serviceConfig.Type = "oneshot";
|
||||
script =
|
||||
if docker.podman
|
||||
then (mkPodmanNetwork options)
|
||||
else (mkDockerNetwork options);
|
||||
};
|
||||
};
|
||||
in
|
||||
lib.mkMerge (builtins.map mkSystemdNetworkService docker.networks);
|
||||
};
|
||||
}
|
||||
61
system/systemmodules/docker/options.nix
Normal file
61
system/systemmodules/docker/options.nix
Normal file
@ -0,0 +1,61 @@
|
||||
{
|
||||
lib,
|
||||
mylib,
|
||||
...
|
||||
}: {
|
||||
enable = lib.mkEnableOption "Enable light virtualization using containers";
|
||||
|
||||
podman = lib.mkEnableOption "Use podman instead of docker";
|
||||
docker.rootless = lib.mkEnableOption "Use rootless docker (no effect if podman is used)";
|
||||
docker.buildkit = lib.mkEnableOption "Use Docker BuildKit (no effect if podman is used)";
|
||||
|
||||
networks = lib.mkOption {
|
||||
type = lib.types.listOf (lib.types.submodule ({
|
||||
lib,
|
||||
mylib,
|
||||
...
|
||||
}: {
|
||||
options = {
|
||||
name = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "The name of the docker/podman network";
|
||||
example = "behind-nginx";
|
||||
};
|
||||
|
||||
disable_masquerade = lib.mkEnableOption "Disable IP masquerading for this network";
|
||||
|
||||
ipv6 = {
|
||||
enable = lib.mkEnableOption "Enable IPv6 for this network";
|
||||
|
||||
gateway = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
description = "The IPv6 gateway for this network";
|
||||
example = "2000::1";
|
||||
default = null;
|
||||
};
|
||||
|
||||
subnet = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
description = "The IVv6 subnet mask for this network";
|
||||
example = "2000::/80";
|
||||
default = null;
|
||||
};
|
||||
};
|
||||
};
|
||||
}));
|
||||
description = "Docker/Podman networks to create";
|
||||
example = ''
|
||||
{
|
||||
behind-nginx = {
|
||||
disable_masquerade = false;
|
||||
ipv6 = {
|
||||
enable = true;
|
||||
gateway = "2000::1";
|
||||
subnet = "2000::/80";
|
||||
};
|
||||
}
|
||||
}
|
||||
'';
|
||||
default = [];
|
||||
};
|
||||
}
|
||||
55
system/systemmodules/fonts/default.nix
Normal file
55
system/systemmodules/fonts/default.nix
Normal file
@ -0,0 +1,55 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
mylib,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
inherit (config.modules) fonts;
|
||||
in {
|
||||
options.modules.fonts = import ./options.nix {inherit lib mylib;};
|
||||
|
||||
config = lib.mkIf fonts.enable {
|
||||
fonts = {
|
||||
# Some default fonts for unicode coverage
|
||||
enableDefaultPackages = true;
|
||||
|
||||
# Puts fonts to /run/current-system/sw/share/X11/fonts
|
||||
# https://wiki.nixos.org/wiki/Fonts#Flatpak_applications_can.27t_find_system_fonts
|
||||
fontDir.enable = true;
|
||||
|
||||
# Font packages go here.
|
||||
# They are installed system-wide so they land in fontdir,
|
||||
# this is required for flatpak to find them.
|
||||
packages = with pkgs; [
|
||||
# Monospace fonts
|
||||
nerd-fonts.jetbrains-mono
|
||||
nerd-fonts.victor-mono
|
||||
monolisa
|
||||
|
||||
# Sans/Serif fonts
|
||||
noto-fonts
|
||||
noto-fonts-color-emoji
|
||||
noto-fonts-cjk-sans
|
||||
lxgw-wenkai
|
||||
];
|
||||
|
||||
fontconfig = {
|
||||
enable = true;
|
||||
antialias = true;
|
||||
hinting.enable = true;
|
||||
hinting.autohint = true;
|
||||
cache32Bit = true;
|
||||
|
||||
# https://wiki.nixos.org/wiki/Fonts#Noto_Color_Emoji_doesn.27t_render_on_Firefox
|
||||
useEmbeddedBitmaps = true;
|
||||
|
||||
defaultFonts = {
|
||||
serif = [fonts.defaultSerifFont] ++ fonts.fallbackSerifFonts;
|
||||
sansSerif = [fonts.defaultSansSerifFont] ++ fonts.fallbackSansSerifFonts;
|
||||
monospace = [fonts.defaultMonoFont] ++ fonts.fallbackMonoFonts;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
69
system/systemmodules/fonts/options.nix
Normal file
69
system/systemmodules/fonts/options.nix
Normal file
@ -0,0 +1,69 @@
|
||||
{
|
||||
lib,
|
||||
mylib,
|
||||
...
|
||||
}: {
|
||||
enable = lib.mkEnableOption "Enable fonts configuration";
|
||||
|
||||
defaultSerifFont = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "Select default serif font";
|
||||
example = ''
|
||||
"Noto Serif CJK SC"
|
||||
'';
|
||||
default = "Noto Serif CJK SC";
|
||||
};
|
||||
|
||||
defaultSansSerifFont = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "Select default sans-serif font";
|
||||
example = ''
|
||||
"Noto Sans CJK SC"
|
||||
'';
|
||||
default = "Noto Sans CJK SC";
|
||||
};
|
||||
|
||||
defaultMonoFont = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "Select default monospace font";
|
||||
example = ''
|
||||
"MonoLisa Alt Script"
|
||||
'';
|
||||
default = "MonoLisa Alt Script";
|
||||
};
|
||||
|
||||
fallbackSerifFonts = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
description = "Select fallback serif fonts";
|
||||
example = ''
|
||||
[
|
||||
"Noto Serif CJK SC"
|
||||
]
|
||||
'';
|
||||
default = [];
|
||||
};
|
||||
|
||||
fallbackSansSerifFonts = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
description = "Select fallback sans-serif fonts";
|
||||
example = ''
|
||||
[
|
||||
"Noto Sans CJK SC"
|
||||
]
|
||||
'';
|
||||
default = [];
|
||||
};
|
||||
|
||||
fallbackMonoFonts = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
description = "Select fallback monospace fonts";
|
||||
example = ''
|
||||
[
|
||||
"JetBrainsMono Nerd Font Mono"
|
||||
]
|
||||
'';
|
||||
default = [
|
||||
"JetBrainsMono Nerd Font Mono"
|
||||
];
|
||||
};
|
||||
}
|
||||
384
system/systemmodules/impermanence/default.nix
Normal file
384
system/systemmodules/impermanence/default.nix
Normal file
@ -0,0 +1,384 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
mylib,
|
||||
username,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
inherit (config.modules) impermanence;
|
||||
in {
|
||||
options.modules.impermanence = import ./options.nix {inherit lib mylib;};
|
||||
|
||||
config = let
|
||||
# NOTE: Setting user/group/mode only has an effect if the
|
||||
# directory is created by impermanence!
|
||||
m777 = "u=rwx,g=rwx,o=rwx";
|
||||
m755 = "u=rwx,g=rx,o=rx";
|
||||
m711 = "u=rwx,g=x,o=x";
|
||||
m700 = "u=rwx,g=,o=";
|
||||
m644 = "u=rw,g=r,o=r";
|
||||
m600 = "u=rw,g=,o=";
|
||||
m444 = "u=r,g=r,o=r";
|
||||
|
||||
mkDir = user: directory: mode: {
|
||||
inherit directory mode;
|
||||
user = config.users.users.${user}.name;
|
||||
group = config.users.users.${user}.group;
|
||||
};
|
||||
|
||||
mkFile = user: file: mode: {
|
||||
inherit file;
|
||||
|
||||
# This doesn't make much sense to set generally, e.g. when
|
||||
# linking multiple files to ~/.config (they all have the same parent directory)
|
||||
# parentDirectory = {
|
||||
# inherit mode;
|
||||
# user = config.users.users.${user}.name;
|
||||
# group = config.users.users.${user}.group;
|
||||
# };
|
||||
};
|
||||
|
||||
mkRDir = mkDir "root";
|
||||
mkRFile = mkFile "root";
|
||||
mkUDir = mkDir "${username}";
|
||||
mkUFile = mkFile "${username}";
|
||||
# TODO: sth. like this, make options for configdirs/sharedirs/statedirs/homedirs
|
||||
# populate options from respective modules, not here...
|
||||
# mkConfigDirs = dirs:
|
||||
# dirs
|
||||
# |> builtins.map (dir: ".config/${dir}")
|
||||
# |> builtins.map mkUDir # NOTE: mkUDir has wrong arg order
|
||||
in
|
||||
lib.mkIf impermanence.enable {
|
||||
# TODO: Create options to allow host-specific impermanence setup
|
||||
# inside the respective modules
|
||||
environment.persistence."/persist" = {
|
||||
hideMounts = false; # Sets x-gvfs-hide option
|
||||
|
||||
files = [
|
||||
(mkRFile "/etc/adjtime" m644)
|
||||
(mkRFile "/etc/machine-id" m444)
|
||||
];
|
||||
|
||||
directories = [
|
||||
(mkRDir "/etc/NetworkManager" m755)
|
||||
(mkRDir "/etc/secureboot" m755)
|
||||
(mkRDir "/etc/ssh" m755)
|
||||
|
||||
# https://github.com/nix-community/impermanence/issues/253
|
||||
(mkRDir "/usr/systemd-placeholder" m755)
|
||||
|
||||
(mkRDir "/var/cache/restic-backups-synology" m755)
|
||||
|
||||
(mkRDir "/var/db/sudo" m711)
|
||||
|
||||
(mkRDir "/var/lib/bluetooth" m755) # m700
|
||||
(mkRDir "/var/lib/btrfs" m755)
|
||||
(mkRDir "/var/lib/containers" m755)
|
||||
(mkRDir "/var/lib/flatpak" m755)
|
||||
(mkRDir "/var/lib/libvirt" m755)
|
||||
(mkRDir "/var/lib/NetworkManager" m755)
|
||||
(mkRDir "/var/lib/nixos" m755)
|
||||
(mkRDir "/var/lib/sbctl" m755)
|
||||
(mkRDir "/var/lib/systemd" m755)
|
||||
|
||||
(mkRDir "/var/tmp" m777)
|
||||
];
|
||||
|
||||
users.${username} = {
|
||||
files = [
|
||||
# NOTE: Don't put files generated/linked by HM here (they're already managed)
|
||||
|
||||
# TODO: Specifying files here (e.g. .config/QtProject.conf) doesn't seem to work
|
||||
# They won't get mounted, also they can't be unmounted (because they're not mounted),
|
||||
# which leads to /home not being unmounted correctly during shutdown...
|
||||
];
|
||||
|
||||
directories = [
|
||||
# Home directory
|
||||
(mkUDir "Downloads" m755)
|
||||
(mkUDir "Documents" m755)
|
||||
(mkUDir "GitRepos" m755)
|
||||
(mkUDir "NixFlake" m755)
|
||||
(mkUDir "Notes" m755)
|
||||
(mkUDir "Pictures" m755)
|
||||
(mkUDir "Projects" m755)
|
||||
(mkUDir "Public" m755)
|
||||
# (mkUDir "Unity" m755)
|
||||
(mkUDir "Videos" m755)
|
||||
|
||||
# Secrets
|
||||
(mkUDir ".gnupg" m755) # m600
|
||||
(mkUDir ".secrets" m755) # m644
|
||||
(mkUDir ".ssh" m755) # m644
|
||||
|
||||
# The shit some applications add to ~/ without asking
|
||||
# (mkUDir ".android" m755) # Unity
|
||||
# (mkUDir ".gradle" m755) # Unity
|
||||
# (mkUDir ".java" m755) # Unity/Rider
|
||||
(mkUDir ".MakeMKV" m755)
|
||||
(mkUDir ".mozilla/firefox" m755) # TODO: Remove this someday
|
||||
(mkUDir ".mozilla/native-messaging-hosts" m755)
|
||||
(mkUDir ".nix-package-search" m755)
|
||||
# (mkUDir ".nv" m755) # Unity
|
||||
(mkUDir ".ollama" m755)
|
||||
# (mkUDir ".plastic4" m755) # Unity
|
||||
(mkUDir ".var/app" m755)
|
||||
(mkUDir ".vim/undo" m755)
|
||||
(mkUDir ".zotero" m755)
|
||||
|
||||
# Cache that's actually useful
|
||||
(mkUDir ".cache/fish/generated_completions" m755)
|
||||
(mkUDir ".cache/nix-index" m755)
|
||||
(mkUDir ".cache/nix-search-tv" m755)
|
||||
(mkUDir ".cache/nvim" m755)
|
||||
|
||||
# Config
|
||||
# (mkUDir ".config/.android" m755) # Unity
|
||||
(mkUDir ".config/beets" m755)
|
||||
(mkUDir ".config/blender" m755)
|
||||
(mkUDir ".config/chromium" m755) # TODO: Remove this someday
|
||||
(mkUDir ".config/Ferdium" m755)
|
||||
(mkUDir ".config/fish/completions" m755)
|
||||
(mkUDir ".config/impermanence" m755)
|
||||
(mkUDir ".config/jellyfin-mpv-shim" m755)
|
||||
(mkUDir ".config/JetBrains" m755)
|
||||
(mkUDir ".config/kdeconnect" m755)
|
||||
(mkUDir ".config/keepassxc" m755)
|
||||
(mkUDir ".config/Msty" m755)
|
||||
(mkUDir ".config/Nextcloud" m755)
|
||||
(mkUDir ".config/niri/dms" m755)
|
||||
(mkUDir ".config/obsidian" m755)
|
||||
(mkUDir ".config/obs-studio" m755)
|
||||
(mkUDir ".config/Signal" m755)
|
||||
# (mkUDir ".config/singularitygroup-hotreload" m755) # Unity
|
||||
(mkUDir ".config/TeamSpeak" m755)
|
||||
(mkUDir ".config/tidal-hifi" m755)
|
||||
(mkUDir ".config/tidal_dl_ng" m755)
|
||||
# (mkUDir ".config/unity3d" m755) # Unity
|
||||
# (mkUDir ".config/unityhub" m755) # Unity
|
||||
(mkUDir ".config/vlc" m755)
|
||||
(mkUDir ".config/Zeal" m755)
|
||||
|
||||
# Share
|
||||
# (mkUDir ".local/share/containers" m755) # Rootless docker
|
||||
(mkUDir ".local/share/direnv" m755)
|
||||
(mkUDir ".local/share/docker" m755)
|
||||
(mkUDir ".local/share/fish" m755)
|
||||
(mkUDir ".local/share/flatpak" m755)
|
||||
(mkUDir ".local/share/JetBrains" m755) # Unity
|
||||
(mkUDir ".local/share/hyprland" m755)
|
||||
(mkUDir ".local/share/keyrings" m755) # m700
|
||||
(mkUDir ".local/share/LRCGET" m755)
|
||||
(mkUDir ".local/share/mime" m755)
|
||||
(mkUDir ".local/share/net.lrclib.lrcget" m755)
|
||||
(mkUDir ".local/share/nix" m755)
|
||||
(mkUDir ".local/share/nvim" m755)
|
||||
(mkUDir ".local/share/qutebrowser" m755)
|
||||
(mkUDir ".local/share/systemd" m755)
|
||||
# (mkUDir ".local/share/unity3d" m755) # Unity
|
||||
(mkUDir ".local/share/zoxide" m755)
|
||||
|
||||
# State
|
||||
(mkUDir ".local/state/astal/notifd" m755)
|
||||
(mkUDir ".local/state/home-manager/gc-roots" m755) # nix-flatpak stores its state there
|
||||
(mkUDir ".local/state/lazygit" m755)
|
||||
(mkUDir ".local/state/nix" m755)
|
||||
(mkUDir ".local/state/nvim" m755)
|
||||
(mkUDir ".local/state/wireplumber" m755)
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
# Add some helper scripts to identify files that might need persisting
|
||||
environment.systemPackages = let
|
||||
base = {
|
||||
"root" = "/";
|
||||
"home" = "/home/${username}";
|
||||
};
|
||||
ignore = {
|
||||
"root" = "/home/${username}/.config/impermanence/fdignore-root";
|
||||
"home" = "/home/${username}/.config/impermanence/fdignore-home";
|
||||
};
|
||||
move = {
|
||||
"root" = "/persist/$(dirname {})";
|
||||
"home" = "/persist/home/${username}/$(dirname {})";
|
||||
};
|
||||
|
||||
mkHeader = "Press CTRL-R to reload, CTRL-M to move, CTRL-I to ignore file";
|
||||
mkPreview = mode: "bat --color=always --theme=ansi --style=numbers --line-range=:100 ${base.${mode}}/{}";
|
||||
mkReload = mode: "sudo fd --one-file-system --type f --hidden --base-directory ${base.${mode}} --ignore-file ${ignore.${mode}}";
|
||||
mkIgnore = mode: "echo '{}' >> ${ignore.${mode}}";
|
||||
mkMove = mode: "sudo mkdir -p ${move.${mode}} && sudo mv {} ${move.${mode}}";
|
||||
|
||||
mkScript = mode: ''
|
||||
sudo ${mkReload mode} | \
|
||||
sudo fzf \
|
||||
--header "${mkHeader}" \
|
||||
--preview "${mkPreview mode}" \
|
||||
--bind "ctrl-r:reload:(${mkReload mode})" \
|
||||
--bind "ctrl-i:execute:(${mkIgnore mode})" \
|
||||
--bind "ctrl-m:execute:(${mkMove mode})"
|
||||
'';
|
||||
|
||||
newroot = pkgs.writeShellScriptBin "newroot" (mkScript "root");
|
||||
newhome = pkgs.writeShellScriptBin "newhome" (mkScript "home");
|
||||
in [
|
||||
newroot
|
||||
newhome
|
||||
];
|
||||
|
||||
# NOTE: This is REQUIRED for HM activation!
|
||||
# Otherwise the home directory won't be writable!
|
||||
systemd.services."impermanence-fix-home-ownership" = let
|
||||
homeDir = "/home/${username}";
|
||||
homeUser =
|
||||
builtins.toString
|
||||
config.users.users.${username}.uid;
|
||||
homeGroup =
|
||||
builtins.toString
|
||||
config.users.groups.${config.users.users.${username}.group}.gid;
|
||||
in {
|
||||
description = "Fix impermanent home ownership";
|
||||
wantedBy = ["home-manager-${username}.service"];
|
||||
before = ["home-manager-${username}.service"];
|
||||
after = ["home.mount"];
|
||||
partOf = ["home.mount"];
|
||||
serviceConfig.Type = "oneshot";
|
||||
|
||||
script = ''
|
||||
# Don't chown if NFS shares are already mounted.
|
||||
# This can happen outside of regular booting (e.g. nixos-rebuild switch),
|
||||
# so we don't return an error.
|
||||
# NOTE: Use || true as NixOS sets the damn -e, otherwise this unit fails on boot!
|
||||
nfs_mounts=$(grep ' nfs4 ' /proc/mounts || true)
|
||||
if [[ -n "$nfs_mounts" ]]; then
|
||||
echo "NFS shares are mounted into the home directory, aborting:"
|
||||
echo "$nfs_mounts"
|
||||
exit 0
|
||||
else
|
||||
echo "No NFS shares are mounted into the home directory, continuing..."
|
||||
fi
|
||||
|
||||
if [[ -d ${homeDir} ]]; then
|
||||
chown -R ${homeUser}:${homeGroup} ${homeDir}
|
||||
echo "Set ownership for ${homeDir} to ${homeUser}:${homeGroup}"
|
||||
else
|
||||
echo "ERROR: Home ${homeDir} does not exist!"
|
||||
exit 1
|
||||
fi
|
||||
'';
|
||||
};
|
||||
|
||||
# Because we have a LUKS encrypted drive
|
||||
# we use a systemd service to cleanup the volumes
|
||||
boot.initrd.systemd = {
|
||||
enable = true;
|
||||
|
||||
services.impermanence-btrfs-cleanup = let
|
||||
backupDuration = "7"; # Days
|
||||
mountDir = "/btrfs_tmp";
|
||||
persistDir = "${mountDir}/persist";
|
||||
in {
|
||||
description = "Clean impermanent btrfs subvolumes";
|
||||
wantedBy = ["initrd.target"];
|
||||
after = ["systemd-cryptsetup@crypted.service"];
|
||||
before = ["sysroot.mount"];
|
||||
unitConfig.DefaultDependencies = "no";
|
||||
serviceConfig.Type = "oneshot";
|
||||
|
||||
# NOTE: If any single line of this script fails
|
||||
# the entire system might be bricked.
|
||||
# NixOS automatically sets "-e", so if unlucky,
|
||||
# the subvolumes won'e exist for mounting...
|
||||
script = let
|
||||
mvSubvolToPersist = subvol: ''
|
||||
if [[ -e ${mountDir}/${subvol} ]]; then
|
||||
mkdir -p ${persistDir}/old_${subvol}s
|
||||
timestamp=$(date --date="@$(stat -c %Y ${mountDir}/${subvol})" "+%Y-%m-%-d_%H:%M:%S")
|
||||
mv ${mountDir}/${subvol} "${persistDir}/old_${subvol}s/$timestamp"
|
||||
|
||||
# Make the backup mutable (in case it is not, e.g. /var/empty)
|
||||
# chattr -R -i -f "${persistDir}/old_${subvol}s/$timestamp"
|
||||
|
||||
echo "Backed up previous ${subvol} subvolume to ${persistDir}/old_${subvol}s/$timestamp"
|
||||
fi
|
||||
'';
|
||||
|
||||
mkNewSubvol = subvol: ''
|
||||
if [[ ! -e ${mountDir}/${subvol} ]]; then
|
||||
btrfs subvolume create ${mountDir}/${subvol}
|
||||
echo "Created new subvolume ${mountDir}/${subvol}"
|
||||
else
|
||||
echo "Failed to move ${mountDir}/${subvol} (${mountDir}/${subvol} still exists), not creating new subvolume..."
|
||||
fi
|
||||
'';
|
||||
|
||||
# TODO: This fails and bricks the system
|
||||
deleteOldBackups = subvol: ''
|
||||
for old_${subvol} in $(find ${persistDir}/old_${subvol}s/ -maxdepth 1 -mtime +${backupDuration}); do
|
||||
delete_subvolume_recursively "$old_${subvol}"
|
||||
done
|
||||
'';
|
||||
in ''
|
||||
# This dir will be created in the initrd ramdisk
|
||||
mkdir -p ${mountDir}
|
||||
|
||||
# We mount the root subvolume. Because we're using a flat btrfs layout,
|
||||
# "/" contains the subfolders (-volumes) home, log, nix, persist, root, swap, ...
|
||||
mount -o subvol=/ /dev/mapper/crypted ${mountDir}
|
||||
|
||||
# Check if the persist dir exists so we can move stuff to it
|
||||
if [[ ! -e ${persistDir} ]]; then
|
||||
echo "${persistDir} doesn't exist, aborting..."
|
||||
umount ${mountDir}
|
||||
rmdir ${mountDir}
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Move root subvolume to backup location
|
||||
${mvSubvolToPersist "root"}
|
||||
|
||||
# Move home subvolume to backup location
|
||||
${mvSubvolToPersist "home"}
|
||||
|
||||
# Create new root subvolume
|
||||
${mkNewSubvol "root"}
|
||||
|
||||
# Create new home subvolume
|
||||
${mkNewSubvol "home"}
|
||||
|
||||
# TODO: Did this removal of old backups always brick the system?
|
||||
# Delete a backed up subvolume
|
||||
# delete_subvolume_recursively() {
|
||||
# IFS=$'\n'
|
||||
|
||||
# # https://github.com/nix-community/impermanence/issues/258#issuecomment-2733383737
|
||||
# # If we accidentally end up with a file or directory under old_roots,
|
||||
# # the code will enumerate all subvolumes under the main volume.
|
||||
# # We don't want to remove everything under true main volume. Only
|
||||
# # proceed if this path is a btrfs subvolume (inode=256).
|
||||
# if [ $(stat -c %i "$1") -ne 256 ]; then return; fi
|
||||
|
||||
# for subvol in $(btrfs subvolume list -o "$1" | cut -f 9- -d ' '); do
|
||||
# delete_subvolume_recursively "${persistDir}/$subvol"
|
||||
# done
|
||||
|
||||
# btrfs subvolume delete "$1"
|
||||
# echo "Deleted old subvolume $1"
|
||||
# }
|
||||
|
||||
# Delete old root backups
|
||||
# $ {deleteOldBackups "root"}
|
||||
|
||||
# Delete old home backups
|
||||
# $ {deleteOldBackups "home"}
|
||||
|
||||
umount ${mountDir}
|
||||
rmdir ${mountDir}
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
9
system/systemmodules/impermanence/options.nix
Normal file
9
system/systemmodules/impermanence/options.nix
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
lib,
|
||||
mylib,
|
||||
...
|
||||
}: {
|
||||
enable = lib.mkEnableOption "Enable opt-in state using impermanence.";
|
||||
|
||||
# TODO: Options for host-specific config
|
||||
}
|
||||
94
system/systemmodules/mime/default.nix
Normal file
94
system/systemmodules/mime/default.nix
Normal file
@ -0,0 +1,94 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
mylib,
|
||||
...
|
||||
}: let
|
||||
inherit (config.modules) mime;
|
||||
in {
|
||||
options.modules.mime = import ./options.nix {inherit lib mylib;};
|
||||
|
||||
config = lib.mkIf mime.enable {
|
||||
xdg = {
|
||||
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types
|
||||
# Find .desktop files: fd ".*\.desktop" / | grep --color=auto -E neovide
|
||||
mime = rec {
|
||||
enable = true;
|
||||
|
||||
defaultApplications = let
|
||||
associations =
|
||||
{
|
||||
${mime.defaultTextEditor} = mime.textTypes;
|
||||
${mime.defaultFileBrowser} = ["inode/directory"];
|
||||
${mime.defaultWebBrowser} = mime.webTypes;
|
||||
${mime.defaultPdfViewer} = ["application/pdf"];
|
||||
${mime.defaultImageViewer} = mime.imageTypes;
|
||||
|
||||
# If audio and video player are equal, we assign all types to the audio player,
|
||||
# as multiple identical keys cannot exist in attrsets.
|
||||
${mime.defaultAudioPlayer} =
|
||||
mime.audioTypes
|
||||
++ (lib.optionals
|
||||
(mime.defaultAudioPlayer == mime.defaultVideoPlayer)
|
||||
mime.videoTypes);
|
||||
}
|
||||
# If audio and video player are not equal, we associate the video types with
|
||||
# the chosen video player. Otherwise video types will be included with audio.
|
||||
// (lib.optionalAttrs (mime.defaultAudioPlayer != mime.defaultVideoPlayer) {
|
||||
${mime.defaultVideoPlayer} = mime.videoTypes;
|
||||
});
|
||||
|
||||
# Applied to a single app and a single type
|
||||
# Result: { "image/jpg" = ["imv.desktop"]; }
|
||||
mkAssociation = app: type: {${type} = [app];};
|
||||
|
||||
# Applied to a single app and a list of types
|
||||
# Result: { "image/jpg" = ["imv.desktop"]; "image/png" = ["imv.desktop"]; ... }
|
||||
mkAssociations = app: types:
|
||||
lib.mergeAttrsList
|
||||
(builtins.map (mkAssociation app) types);
|
||||
in
|
||||
# Apply to a list of apps each with a list of types
|
||||
lib.mergeAttrsList (lib.mapAttrsToList mkAssociations associations);
|
||||
|
||||
addedAssociations = defaultApplications;
|
||||
|
||||
removedAssociations = let
|
||||
# Applied to a list of apps and a single type
|
||||
removeAssociation = apps: type: {${type} = apps;};
|
||||
|
||||
# Applied to a list of apps and a list of types:
|
||||
# For each type the list of apps should be removed
|
||||
removeAssociations = apps: types:
|
||||
lib.mergeAttrsList
|
||||
(builtins.map (removeAssociation apps) types);
|
||||
|
||||
# Only create if more than 0 apps are specified: (len from...Types) > 0
|
||||
mkIfExists = apps: types:
|
||||
lib.optionalAttrs
|
||||
(builtins.lessThan 0 (builtins.length apps))
|
||||
(removeAssociations apps types);
|
||||
in
|
||||
lib.mergeAttrsList [
|
||||
{
|
||||
"application/pdf" = [
|
||||
"chromium-browser.desktop"
|
||||
"com.google.Chrome.desktop"
|
||||
"firefox.desktop"
|
||||
];
|
||||
"text/plain" = [
|
||||
"firefox.desktop"
|
||||
"code.desktop"
|
||||
];
|
||||
}
|
||||
|
||||
(mkIfExists mime.removedTextTypes mime.textTypes)
|
||||
(mkIfExists mime.removedImageTypes mime.imageTypes)
|
||||
(mkIfExists mime.removedAudioTypes mime.audioTypes)
|
||||
(mkIfExists mime.removedVideoTypes mime.videoTypes)
|
||||
(mkIfExists mime.removedWebTypes mime.webTypes)
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
327
system/systemmodules/mime/options.nix
Normal file
327
system/systemmodules/mime/options.nix
Normal file
@ -0,0 +1,327 @@
|
||||
{
|
||||
lib,
|
||||
mylib,
|
||||
...
|
||||
}: {
|
||||
enable = lib.mkEnableOption "TEMPLATE";
|
||||
|
||||
defaultTextEditor = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "Default application to open text files";
|
||||
example = ''
|
||||
"neovide.desktop"
|
||||
'';
|
||||
default = "neovide.desktop";
|
||||
};
|
||||
|
||||
defaultFileBrowser = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "Default application for file browsing";
|
||||
example = ''
|
||||
"yazi.desktop"
|
||||
'';
|
||||
default = "yazi.desktop";
|
||||
};
|
||||
|
||||
defaultWebBrowser = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "Default web browser";
|
||||
example = ''
|
||||
"firefox.desktop"
|
||||
'';
|
||||
default = "firefox.desktop";
|
||||
};
|
||||
|
||||
defaultPdfViewer = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "Default application to open PDF files";
|
||||
example = ''
|
||||
"org.pwmt.zathura.desktop"
|
||||
'';
|
||||
default = "org.pwmt.zathura.desktop";
|
||||
};
|
||||
|
||||
defaultImageViewer = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "Default application to open image files";
|
||||
example = ''
|
||||
"imv-dir.desktop"
|
||||
'';
|
||||
default = "imv-dir.desktop";
|
||||
};
|
||||
|
||||
defaultAudioPlayer = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "Default application to play audio files";
|
||||
example = ''
|
||||
"vlc.desktop"
|
||||
'';
|
||||
default = "vlc.desktop";
|
||||
};
|
||||
|
||||
defaultVideoPlayer = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "Default application to play video files";
|
||||
example = ''
|
||||
"vlc.desktop"
|
||||
'';
|
||||
default = "vlc.desktop";
|
||||
};
|
||||
|
||||
textTypes = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
description = "Mime types that should be associated with a text editor";
|
||||
example = ''
|
||||
[
|
||||
"text/css"
|
||||
"text/csv"
|
||||
"text/javascript"
|
||||
"text/plain"
|
||||
"text/xml"
|
||||
"application/json"
|
||||
"application/ld+json"
|
||||
"application/x-sh"
|
||||
"application/xml"
|
||||
]
|
||||
'';
|
||||
default = [
|
||||
"text/css"
|
||||
"text/csv"
|
||||
"text/javascript"
|
||||
"text/plain"
|
||||
"text/xml"
|
||||
"application/json"
|
||||
"application/ld+json"
|
||||
"application/x-sh"
|
||||
"application/xml"
|
||||
];
|
||||
};
|
||||
|
||||
imageTypes = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
description = "Mime types that should be associated with an image viewer";
|
||||
example = ''
|
||||
[
|
||||
"image/apng"
|
||||
"image/avif"
|
||||
"image/bmp"
|
||||
"image/gif"
|
||||
"image/jpeg"
|
||||
"image/png"
|
||||
"image/svg+xml"
|
||||
"image/tiff"
|
||||
"image/webp"
|
||||
]
|
||||
'';
|
||||
default = [
|
||||
"image/apng"
|
||||
"image/avif"
|
||||
"image/bmp"
|
||||
"image/gif"
|
||||
"image/jpeg"
|
||||
"image/png"
|
||||
"image/svg+xml"
|
||||
"image/tiff"
|
||||
"image/webp"
|
||||
];
|
||||
};
|
||||
|
||||
audioTypes = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
description = "Mime types that should be associated with an audio player";
|
||||
example = ''
|
||||
[
|
||||
"audio/aac"
|
||||
"audio/flac"
|
||||
"audio/mp4"
|
||||
"audio/mpeg"
|
||||
"audio/ogg"
|
||||
"audio/opus"
|
||||
"audio/wav"
|
||||
"audio/webm"
|
||||
"audio/3gpp"
|
||||
"audio/3gpp2"
|
||||
]
|
||||
'';
|
||||
default = [
|
||||
"audio/aac"
|
||||
"audio/flac"
|
||||
"audio/mp4"
|
||||
"audio/mpeg"
|
||||
"audio/ogg"
|
||||
"audio/opus"
|
||||
"audio/wav"
|
||||
"audio/webm"
|
||||
"audio/3gpp"
|
||||
"audio/3gpp2"
|
||||
];
|
||||
};
|
||||
|
||||
videoTypes = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
description = "Mime types that should be associated with a video player";
|
||||
example = ''
|
||||
[
|
||||
"video/x-msvideo"
|
||||
"video/mp4"
|
||||
"video/mpeg"
|
||||
"video/ogg"
|
||||
"video/mp2t"
|
||||
"video/webm"
|
||||
"video/3gpp"
|
||||
"video/3gpp2"
|
||||
]
|
||||
'';
|
||||
default = [
|
||||
"video/x-msvideo"
|
||||
"video/mp4"
|
||||
"video/mpeg"
|
||||
"video/ogg"
|
||||
"video/mp2t"
|
||||
"video/webm"
|
||||
"video/3gpp"
|
||||
"video/3gpp2"
|
||||
];
|
||||
};
|
||||
|
||||
webTypes = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
description = "Mime types that should be associated with a web browser";
|
||||
example = ''
|
||||
[
|
||||
"text/uri-list"
|
||||
"text/x-uri"
|
||||
"text/html"
|
||||
"application/xhtml+xml"
|
||||
"x-scheme-handler/https"
|
||||
]
|
||||
'';
|
||||
default = [
|
||||
"text/uri-list"
|
||||
"text/x-uri"
|
||||
"text/html"
|
||||
"application/xhtml+xml"
|
||||
"x-scheme-handler/https"
|
||||
];
|
||||
};
|
||||
|
||||
removedTextTypes = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
description = "Applications that shouldn't be used to open text files";
|
||||
example = ''
|
||||
[
|
||||
"nvim.desktop"
|
||||
]
|
||||
'';
|
||||
default = [
|
||||
"nvim.desktop"
|
||||
];
|
||||
};
|
||||
|
||||
removedImageTypes = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
description = "Applications that shouldn't be used to view image files";
|
||||
example = ''
|
||||
[
|
||||
"imv.desktop"
|
||||
"org.inkscape.Inkscape.desktop"
|
||||
"chromium-browser.desktop"
|
||||
"org.kde.krita.desktop"
|
||||
"krita.desktop"
|
||||
"krita_svg.desktop"
|
||||
"krita_raw.desktop"
|
||||
"krita_heif.desktop"
|
||||
"krita_webp.desktop"
|
||||
"krita_gif.desktop"
|
||||
"krita_brush.desktop"
|
||||
"krita_xcf.desktop"
|
||||
"krita_jpeg.desktop"
|
||||
"krita_spriter.desktop"
|
||||
"krita_jxl.desktop"
|
||||
"krita_ora.desktop"
|
||||
"krita_csv.desktop"
|
||||
"krita_tga.desktop"
|
||||
"krita_psd.desktop"
|
||||
"krita_png.desktop"
|
||||
"krita_tiff.desktop"
|
||||
"krita_exr.desktop"
|
||||
"krita_qimageio.desktop"
|
||||
"krita_pdf.desktop"
|
||||
"krita_jp2.desktop"
|
||||
"krita_heightmap.desktop"
|
||||
"krita_kra.desktop"
|
||||
"krita_krz.desktop"
|
||||
]
|
||||
'';
|
||||
default = [
|
||||
"imv.desktop"
|
||||
"chromium-browser.desktop"
|
||||
"org.kde.krita.desktop"
|
||||
"krita.desktop"
|
||||
"krita_svg.desktop"
|
||||
"krita_raw.desktop"
|
||||
"krita_heif.desktop"
|
||||
"krita_webp.desktop"
|
||||
"krita_gif.desktop"
|
||||
"krita_brush.desktop"
|
||||
"krita_xcf.desktop"
|
||||
"krita_jpeg.desktop"
|
||||
"krita_spriter.desktop"
|
||||
"krita_jxl.desktop"
|
||||
"krita_ora.desktop"
|
||||
"krita_csv.desktop"
|
||||
"krita_tga.desktop"
|
||||
"krita_psd.desktop"
|
||||
"krita_png.desktop"
|
||||
"krita_tiff.desktop"
|
||||
"krita_exr.desktop"
|
||||
"krita_qimageio.desktop"
|
||||
"krita_pdf.desktop"
|
||||
"krita_jp2.desktop"
|
||||
"krita_heightmap.desktop"
|
||||
"krita_kra.desktop"
|
||||
"krita_krz.desktop"
|
||||
];
|
||||
};
|
||||
|
||||
removedAudioTypes = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
description = "Applications that shouldn't be used to play audio files";
|
||||
example = ''
|
||||
[
|
||||
"mpv.desktop"
|
||||
]
|
||||
'';
|
||||
default = [
|
||||
"mpv.desktop"
|
||||
];
|
||||
};
|
||||
|
||||
removedVideoTypes = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
description = "Applications that shouldn't be used to play video files";
|
||||
example = ''
|
||||
[
|
||||
"mpv.desktop"
|
||||
]
|
||||
'';
|
||||
default = [
|
||||
"mpv.desktop"
|
||||
];
|
||||
};
|
||||
|
||||
removedWebTypes = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
description = "Web browsers that shouldn't be used for web types";
|
||||
example = ''
|
||||
[
|
||||
"chromium-browser.desktop"
|
||||
"com.google.Chrome.desktop"
|
||||
]
|
||||
'';
|
||||
default = [
|
||||
"chromium-browser.desktop"
|
||||
"com.google.Chrome.desktop"
|
||||
];
|
||||
};
|
||||
}
|
||||
120
system/systemmodules/network/default.nix
Normal file
120
system/systemmodules/network/default.nix
Normal file
@ -0,0 +1,120 @@
|
||||
# TODO: Setup Wireless (IWD/Networkd?)
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
mylib,
|
||||
...
|
||||
}:
|
||||
with lib;
|
||||
with mylib.networking;
|
||||
with mylib.modules; let
|
||||
cfg = config.modules.network;
|
||||
in {
|
||||
options.modules.network = import ./options.nix {inherit lib mylib;};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
services.resolved = {
|
||||
enable = true;
|
||||
|
||||
# llmnr = "false";
|
||||
# extraConfig = ''
|
||||
# DNSStubListener=no
|
||||
# '';
|
||||
|
||||
settings.Resolve = {
|
||||
DNS = config.networking.nameservers;
|
||||
DNSOverTLS = false;
|
||||
DNSSEC = false;
|
||||
Domains = config.networking.search;
|
||||
LLMNR = false;
|
||||
DNSStubListener = false;
|
||||
};
|
||||
};
|
||||
|
||||
# Use the programs.nm-applet instead
|
||||
# environment.systemPackages = with pkgs;
|
||||
# builtins.concatLists [
|
||||
# []
|
||||
# (lib.optionals cfg.useNetworkManager [networkmanagerapplet]) # This is started by hyprland if enabled
|
||||
# ];
|
||||
|
||||
programs.nm-applet.enable = cfg.useNetworkManager;
|
||||
|
||||
# Main Networks
|
||||
systemd.network = {
|
||||
enable = !cfg.useNetworkManager;
|
||||
wait-online.timeout = 10;
|
||||
|
||||
# Don't wait for all networks to be configured, as e.g. wg0 will only be upon manual activation
|
||||
wait-online.anyInterface = true;
|
||||
|
||||
# TODO: Apparently anyInterface doesn't work?
|
||||
# wait-online.ignoredInterfaces = [
|
||||
# "wg0"
|
||||
# "wlp7s0"
|
||||
# "enp5s0"
|
||||
# ];
|
||||
|
||||
# networks = cfg.networks;
|
||||
inherit (cfg) networks;
|
||||
};
|
||||
|
||||
modules.polkit.allowedActions = mkIf cfg.useNetworkManager [
|
||||
# List NM permissions by running "nmcli general permissions"
|
||||
"org.freedesktop.NetworkManager.settings.modify.system"
|
||||
];
|
||||
|
||||
# General Networking Settings
|
||||
networking = {
|
||||
# Gets inherited from flake in nixos mylib and passed through the module option
|
||||
hostName = cfg.hostname; # Define your hostname.
|
||||
enableIPv6 = false;
|
||||
|
||||
# Disable a lot of stuff not needed for systemd-networkd
|
||||
networkmanager = {
|
||||
enable = cfg.useNetworkManager;
|
||||
ensureProfiles.profiles = cfg.profiles;
|
||||
|
||||
insertNameservers = [
|
||||
"192.168.86.26"
|
||||
"8.8.8.8"
|
||||
];
|
||||
|
||||
wifi = {
|
||||
backend = "iwd";
|
||||
};
|
||||
};
|
||||
|
||||
useDHCP = false; # Default: true, don't use with networkd
|
||||
dhcpcd.enable = false; # Don't use with networkd
|
||||
useNetworkd = false; # Only use this if the configuration can't be written in systemd.network completely. It translates some of the networking... options to systemd
|
||||
# resolvconf.enable = true;
|
||||
|
||||
wireless = {
|
||||
enable = false; # Enables wireless support via wpa_supplicant.
|
||||
iwd.enable = true; # Use iwd instead of wpa_supplicant
|
||||
};
|
||||
|
||||
# Open Ports
|
||||
nftables.enable = true;
|
||||
firewall = {
|
||||
enable = true;
|
||||
# networking.firewall.checkReversePath = "loose";
|
||||
|
||||
trustedInterfaces = [
|
||||
"podman0"
|
||||
"docker0"
|
||||
];
|
||||
|
||||
# allowedTCPPorts = cfg.allowedTCPPorts;
|
||||
# allowedTCPPortRanges = [];
|
||||
# allowedUDPPorts = cfg.allowedUDPPorts;
|
||||
# allowedUDPPortRanges = [];
|
||||
inherit (cfg) allowedTCPPorts allowedUDPPorts;
|
||||
};
|
||||
};
|
||||
|
||||
# We need this (sadly), otherwise the nfs mounts don't work
|
||||
systemd.services.NetworkManager-wait-online.enable = true;
|
||||
};
|
||||
}
|
||||
61
system/systemmodules/network/options.nix
Normal file
61
system/systemmodules/network/options.nix
Normal file
@ -0,0 +1,61 @@
|
||||
{
|
||||
lib,
|
||||
mylib,
|
||||
...
|
||||
}:
|
||||
with lib;
|
||||
with mylib.modules; {
|
||||
enable = mkEnableOption "Systemd Network Configuration";
|
||||
|
||||
useNetworkManager = mkEnableOption "Use NetworkManager instead of systemd-networkd";
|
||||
|
||||
hostname = mkOption {
|
||||
type = types.str;
|
||||
description = "The System's Hostname";
|
||||
example = ''
|
||||
"Nixinator"
|
||||
'';
|
||||
};
|
||||
|
||||
networks = mkOption {
|
||||
type = types.attrs;
|
||||
default = {};
|
||||
description = "Systemd-Networkd Networks";
|
||||
example = ''
|
||||
{
|
||||
"50-ether" = {
|
||||
[...]
|
||||
};
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
profiles = mkOption {
|
||||
type = types.attrs;
|
||||
default = {};
|
||||
description = "NetworkManager Profiles";
|
||||
example = ''
|
||||
"50-ether" = {
|
||||
[...]
|
||||
};
|
||||
'';
|
||||
};
|
||||
|
||||
allowedTCPPorts = mkOption {
|
||||
type = types.listOf types.int;
|
||||
default = [];
|
||||
description = "Open TCP Ports in the Firewall";
|
||||
example = ''
|
||||
[22 80 443]
|
||||
'';
|
||||
};
|
||||
|
||||
allowedUDPPorts = mkOption {
|
||||
type = types.listOf types.int;
|
||||
default = [];
|
||||
description = "Open UDP Ports in the Firewall";
|
||||
example = ''
|
||||
[22 80 443]
|
||||
'';
|
||||
};
|
||||
}
|
||||
79
system/systemmodules/polkit/default.nix
Normal file
79
system/systemmodules/polkit/default.nix
Normal file
@ -0,0 +1,79 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
mylib,
|
||||
username,
|
||||
...
|
||||
}:
|
||||
with lib;
|
||||
with mylib.modules; let
|
||||
cfg = config.modules.polkit;
|
||||
in {
|
||||
options.modules.polkit = import ./options.nix {inherit lib mylib;};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
security.polkit.enable = true;
|
||||
|
||||
# NOTE: Polkit stuff:
|
||||
# - subject.active: The subject is part of the currently active session
|
||||
# - subject.local: The subject is spawned from a local seat/session
|
||||
# - subject.user == ${username}: Only unlock stuff for the user defined by this config
|
||||
security.polkit.extraConfig = let
|
||||
# Services that should always get a rule
|
||||
always-services = [];
|
||||
|
||||
mkServicePredicate = service: "action.lookup(\"unit\") == \"${service}\"";
|
||||
servicePredicates =
|
||||
(cfg.allowedSystemServices ++ always-services)
|
||||
|> builtins.map mkServicePredicate
|
||||
|> builtins.concatStringsSep " ||\n";
|
||||
|
||||
# Actions that should always be allowed
|
||||
always-actions = [];
|
||||
|
||||
mkActionPredicate = action: "action.id == \"${action}\"";
|
||||
actionPredicates =
|
||||
(cfg.allowedActions ++ always-actions)
|
||||
|> builtins.map mkActionPredicate
|
||||
|> builtins.concatStringsSep " ||\n";
|
||||
in
|
||||
lib.concatStrings [
|
||||
''
|
||||
// NixOS PolKit Rules Start
|
||||
''
|
||||
|
||||
# Only add this ruleset if (len servicePredicates) > 0
|
||||
(lib.optionalString (builtins.lessThan 0 (builtins.length cfg.allowedSystemServices)) ''
|
||||
polkit.addRule(function(action, subject) {
|
||||
if (
|
||||
action.id == "org.freedesktop.systemd1.manage-units" &&
|
||||
subject.user == "${username}" &&
|
||||
subject.local &&
|
||||
subject.active &&
|
||||
(${servicePredicates})
|
||||
) {
|
||||
return polkit.Result.YES;
|
||||
}
|
||||
});
|
||||
'')
|
||||
|
||||
# Only add this ruleset if (len actionPredicates) > 0
|
||||
(lib.optionalString (builtins.lessThan 0 (builtins.length cfg.allowedActions)) ''
|
||||
polkit.addRule(function(action, subject) {
|
||||
if (
|
||||
subject.user == "${username}" &&
|
||||
subject.local &&
|
||||
subject.active &&
|
||||
(${actionPredicates})
|
||||
) {
|
||||
return polkit.Result.YES;
|
||||
}
|
||||
});
|
||||
'')
|
||||
|
||||
''
|
||||
// NixOS PolKit Rules End
|
||||
''
|
||||
];
|
||||
};
|
||||
}
|
||||
32
system/systemmodules/polkit/options.nix
Normal file
32
system/systemmodules/polkit/options.nix
Normal file
@ -0,0 +1,32 @@
|
||||
{
|
||||
lib,
|
||||
mylib,
|
||||
...
|
||||
}:
|
||||
with lib;
|
||||
with mylib.modules; {
|
||||
enable = mkEnableOption "Polkit";
|
||||
|
||||
allowedActions = mkOption {
|
||||
type = types.listOf types.str;
|
||||
description = "Actions that should be manageable by a User without Root Password";
|
||||
example = ''
|
||||
[
|
||||
"org.freedesktop.NetworkManager.settings.modify.system"
|
||||
]
|
||||
'';
|
||||
default = [];
|
||||
};
|
||||
|
||||
allowedSystemServices = mkOption {
|
||||
type = types.listOf types.str;
|
||||
description = "System Services that should be manageable by a User without Root Password";
|
||||
example = ''
|
||||
[
|
||||
"jellyfin"
|
||||
"stablediffusion"
|
||||
]
|
||||
'';
|
||||
default = [];
|
||||
};
|
||||
}
|
||||
64
system/systemmodules/sops-nix/default.nix
Normal file
64
system/systemmodules/sops-nix/default.nix
Normal file
@ -0,0 +1,64 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
mylib,
|
||||
pkgs,
|
||||
username,
|
||||
...
|
||||
}: let
|
||||
inherit (config.modules) sops-nix;
|
||||
in {
|
||||
options.modules.sops-nix = import ./options.nix {inherit lib mylib;};
|
||||
|
||||
config = {
|
||||
environment.systemPackages = with pkgs; [
|
||||
sops
|
||||
age
|
||||
# ssh-to-age
|
||||
];
|
||||
|
||||
environment.variables = {
|
||||
# Set this environment variable to make "sops edit secrets.yaml" work
|
||||
SOPS_AGE_KEY_FILE = config.sops.age.keyFile;
|
||||
};
|
||||
|
||||
sops = {
|
||||
defaultSopsFile = ./secrets.yaml;
|
||||
|
||||
age = {
|
||||
keyFile = lib.mkDefault "/home/${username}/.secrets/age/age.key";
|
||||
generateKey = false;
|
||||
sshKeyPaths = [];
|
||||
};
|
||||
|
||||
secrets = let
|
||||
mkSecret = name: {
|
||||
${name} = {
|
||||
owner = config.users.users.${username}.name;
|
||||
group = config.users.users.${username}.group;
|
||||
};
|
||||
};
|
||||
|
||||
mkBootSecret = name: {
|
||||
${name} = {
|
||||
# Make these secrets available before creating users.
|
||||
# This means we can't set the owner or group.
|
||||
neededForUsers = true;
|
||||
};
|
||||
};
|
||||
in
|
||||
lib.mkMerge [
|
||||
(
|
||||
if (builtins.hasAttr "${username}" sops-nix.secrets)
|
||||
then lib.mergeAttrsList (builtins.map mkSecret sops-nix.secrets.${username})
|
||||
else {}
|
||||
)
|
||||
(
|
||||
if (builtins.hasAttr "${username}" sops-nix.bootSecrets)
|
||||
then lib.mergeAttrsList (builtins.map mkBootSecret sops-nix.bootSecrets.${username})
|
||||
else {}
|
||||
)
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
27
system/systemmodules/sops-nix/options.nix
Normal file
27
system/systemmodules/sops-nix/options.nix
Normal file
@ -0,0 +1,27 @@
|
||||
{
|
||||
lib,
|
||||
mylib,
|
||||
...
|
||||
}: {
|
||||
secrets = lib.mkOption {
|
||||
type = lib.types.attrsOf (lib.types.listOf lib.types.str);
|
||||
description = "The secrets to expose on this host";
|
||||
example = ''
|
||||
christoph = [
|
||||
"docker-password"
|
||||
];
|
||||
'';
|
||||
default = [];
|
||||
};
|
||||
|
||||
bootSecrets = lib.mkOption {
|
||||
type = lib.types.attrsOf (lib.types.listOf lib.types.str);
|
||||
description = "The secrets to expose on this host earlier in the boot process";
|
||||
example = ''
|
||||
christoph = [
|
||||
"user-password"
|
||||
];
|
||||
'';
|
||||
default = [];
|
||||
};
|
||||
}
|
||||
39
system/systemmodules/sops-nix/secrets.yaml
Normal file
39
system/systemmodules/sops-nix/secrets.yaml
Normal file
@ -0,0 +1,39 @@
|
||||
#
|
||||
#ENC[AES256_GCM,data:mZKPbrWtgyRvOg==,iv:vLyN3JkWWrWS+0pndTuom8cNVfpb8SUC4dA6m7utXoE=,tag:YAy2gPot6KFS9/VLVAoSxw==,type:comment]
|
||||
#
|
||||
user-password: ENC[AES256_GCM,data:okgvaTTesCDwriI8PxhNdHZF8XgzB4yxapuFl2/CK8x4WNYxGFjuZqGKcu7pqfnBofNcF2ByuM+HLH9FKxpK0dMCoHD/laR1IA==,iv:ltExELuM7g7ydSAMj8ioF9Nb7N4xe5enhDQrVJ+k2jQ=,tag:AV165m5yKnX+uJnMyC3mxA==,type:str]
|
||||
ssh-private-key: ENC[AES256_GCM,data:JrRarfeS3y6b9gxg4Za5GIc5Ci3aGR+OyZxQybj4dcv2mzxXmT/bm7KOwM1zkz1PFl1xW5X82T5jte+XQOKx0+6m4ovjUgUmQUMP4E/yosp8XSdi0+YlUKBEHEJx6HqCZy+v6qx5kfp9JC6fZqCbL1J6FIqWqAoKTFXoiou1YnhmBa2fM17Q++i6TflDWiVrUS7X9xjuZFq1hz1aQXS303uvJEUOEpXdqPyJvUKJWzVsFrAwpa9FG+reO70SSc+1hBbqdw1QjrzNWh3eNnztwZURauJtVFBYUZ5ozHmWBr4aVFjYvqz+t6G1SAunmBRbVqbH4bjBv9jXXjHAB4U0wanvkJN2C+EY1zxwjyx2fWckMdhoLr9gtC1FJKMbV49UFHJ3iXWNczKj1t7LrctehEKXJa0Eb3UogYuaRxbVYbC++kD8LvL4AY8ertgc9/pxQQZmogdINJmIxKN4HTlGbX8kSDLbohZLheOfzZ5ycTlrbOjfJ1EBMLo+mJcMUW0qhFySl1aamPqTeII7lvgTOE3xV/d/9VAQTFKsftWPNkfhAJIym51bYrrMPV8AVeFQnLhSid3d3zK4w20zIQKSYnq9A8zcNhM0keddiv4XC+M=,iv:7HP7VCFpMRZXRD6GD/zFzDSBO02V/DyxKLmuDCLXTLU=,tag:Ugx81JwCP8HmhtflYoevLg==,type:str]
|
||||
nix-github-token: ENC[AES256_GCM,data:AXV0ODLhfa4M6+7clulfIKm0qCOeo3lQ+66iYgoDeR12RxZOV19UtA==,iv:1XECVKyzH3NumKwRSPKNlUwJMLFwptcG8DQ09U4LrGk=,tag:QdtvJNV8BttWjhH4v0RtRQ==,type:str]
|
||||
docker-password: ENC[AES256_GCM,data:mK5YWEQPKWBtVCgRBZvwWTdVAi8MEGbLnLeP7hfDkcc=,iv:Az8+eAK6R6xssmmbhuEsDbLU+ks8lS+qzc4L33WfefA=,tag:NSXvRhbIuRZZqRR28Tu0PQ==,type:str]
|
||||
#
|
||||
#ENC[AES256_GCM,data:y5dlZFhK38dR+Q==,iv:1JYizUeyWeMR4KUblkj7kVSHPCL5l8mFpaQdo774BcM=,tag:kUTnBZb46KYQyi8bgIYSOQ==,type:comment]
|
||||
#
|
||||
makemkv-app-key: ENC[AES256_GCM,data:/pTxr4q4ucJLx5VI8ySzOgd4g1s+6lcZNe4crxRmidTYrhJ0I6V3CIhm4wLC105W+Xka6HIZTqPn8SbqcMC4Dt3wSus=,iv:aYsGobD+Vl/VUNAHcAxQb7HEmLT8aXyKNOELgzvKDH4=,tag:xhnVb/ns6VZEnTuoUv9w5A==,type:str]
|
||||
restic-repo-key: ENC[AES256_GCM,data:lSFuhjbhdQq4cabAVFGQ4kuaJxb7EhXgBDlgoEQWJhs=,iv:7IhGDBYEwY1TwLvc/4DOkUBQ3eqSszZcKwnT7Lllfps=,tag:yJVlMi9X0W+Kh3zMkb0QuA==,type:str]
|
||||
#
|
||||
#ENC[AES256_GCM,data:Raagjz1qPvXC,iv:OSWTKaIlmo1paU2ZZn20XMeZ2gdM52pHmVZ3m2ngCdI=,tag:bPCdvjOFjpxxkrwA7Mhl5Q==,type:comment]
|
||||
#
|
||||
heidi-discord-token: ENC[AES256_GCM,data:FYvfUn8tG7glqIomSDj9rGyNQjnHSCsD/C3Kk/JR1vm/xkrxzXwP3rpyxAzqRQ7vd+zFBf2BJfV/zMk=,iv:b+aKcu98rxslEGSYf6t/jGwPfS256WQ3B/iuQ4Qeykk=,tag:e48Q0BraIvItyD2WBfbYEA==,type:str]
|
||||
kopia-server-username: ENC[AES256_GCM,data:4onewFkWpi9g,iv:aA4WSS8T6KUcGbAIHDd8BjE0sRK/Qz0j4QvEnKdlt2U=,tag:FQlB0Wx2u8wT3TKIhMAyLg==,type:str]
|
||||
kopia-server-password: ENC[AES256_GCM,data:6nMnhRA=,iv:Qz9qP+m0obzL+eHFmW1qVmc/0TR4Iw4X1GL4zACOSMk=,tag:v3v+33+g4y6se5q+b4e8mA==,type:str]
|
||||
kopia-user-password: ENC[AES256_GCM,data:jPWeru4e2w9qzA==,iv:WpZS3Qmx8v12v3q1Lq1YrPnWw7BY0FhxurXYuaOdfwA=,tag:+8bQAnHRh55rUMdyoK6N8w==,type:str]
|
||||
paperless-nextcloud-sync-password: ENC[AES256_GCM,data:pfLg3OVBqLsM4R7mSgLQEachj9gMkexPjBMSyzU=,iv:XBe1cdwlTjPfQW70NIEjD8CikK58iGErI9ZTlLWtCA4=,tag:qO35GdjljgS3/z5/1fCOFg==,type:str]
|
||||
#
|
||||
#ENC[AES256_GCM,data:Gdh/hjCaOuAE,iv:XjPXn3SskpUPUkDIEDl5701/g9QhuS83fACMaoPMiIM=,tag:Q7s8xZG/GsOtQrasekBnkQ==,type:comment]
|
||||
#
|
||||
wireguard-vps-private-key: ENC[AES256_GCM,data:B6IWYuzKV9YZ+G9GIjOsXVEVugwMY14PrwmYyHsFAJEb1OJRXMg8+zeFnqs=,iv:2QroGA10UVSmNIBHFSTeCgMBD3VjtiUnng3pkR/mPVQ=,tag:FGlCrmdccgsObyut6E5ggA==,type:str]
|
||||
sops:
|
||||
age:
|
||||
- recipient: age14ph8vrj657e7s35d60xehzuq46t9zd6pzcm6pw4jragzrvf6xs9s77usnm
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBWSVRhVDREMXduZElrRklE
|
||||
R2s3Y081TGVTOCtKWVVWN0RLb0ZIT3lmMTNZCjFaNmRqb2hRVXFDSU12dFhDNmJo
|
||||
UHUyTUlOWWpMaVZ6Tlg3ZkRhOHJDUUEKLS0tIHduRXdxQ1VCR1ZuV3hjVjM1REtY
|
||||
SURMTmh1TGIrRmtENzc0Sk4rNFJNUE0KOpjN6jkEHO+lvdWdp4P++r9SNSPWaT0h
|
||||
FAbbvZZ/EdIk/njLEcayFN7B4ftTcD/f4XJZiyosilZnIkk76bMOHA==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2025-07-19T01:29:00Z"
|
||||
mac: ENC[AES256_GCM,data:IzLYRuOlkUpry37sw7OB5MglntVflMjCcNiWpi7rvT2suOivLX9IT36qZFfYIbVIFXDmfsi1hsTvsPyekD7vVWQ1vkajAlGQYYTVpnO2cFrK3+TfWCyYjiD01rQBiRikybrR11zWRq6atieurDIxMUMEI7ypiqFOwpYaqSePAFc=,iv:9bc6rc4gjuiJWNjg1g0KfySqxnPjpzmlzDi/R+Iv2g4=,tag:tEwthVZAmdXbwRtoNykGrQ==,type:str]
|
||||
unencrypted_suffix: _unencrypted
|
||||
version: 3.10.2
|
||||
Reference in New Issue
Block a user