diff --git a/SwarselSystems.org b/SwarselSystems.org index f51ce25..ea4c228 100644 --- a/SwarselSystems.org +++ b/SwarselSystems.org @@ -1582,7 +1582,6 @@ If we would however declare options in the same file, we would need to write: } #+end_src - * flake.nix :PROPERTIES: :CUSTOM_ID: h:c7588c0d-2528-485d-b2df-04d6336428d7 @@ -1738,7 +1737,7 @@ A short overview over each input and what it does: smallpkgs.url = "github:nixos/nixpkgs/08fcb0dcb59df0344652b38ea6326a2d8271baff?narHash=sha256-HXIQzULIG/MEUW2Q/Ss47oE3QrjxvpUX7gUl4Xp6lnc%3D&shallow=1"; nixpkgs-dev.url = "github:Swarsel/nixpkgs/main"; nixpkgs-bisect.url = "github:nixos/nixpkgs/master"; - nixpkgs-update.url = "github:r-ryantm/nixpkgs/auto-update/oauth2-proxy"; + # nixpkgs-update.url = "github:r-ryantm/nixpkgs/auto-update/oauth2-proxy"; # nixpkgs-kernel.url = "github:NixOS/nixpkgs/063f43f2dbdef86376cc29ad646c45c46e93234c?narHash=sha256-6m1Y3/4pVw1RWTsrkAK2VMYSzG4MMIj7sqUy7o8th1o%3D"; #specifically pinned for kernel version nixpkgs-kernel.url = "github:nixos/nixpkgs/dd9b079222d43e1943b6ebd802f04fd959dc8e61?narHash=sha256-I45esRSssFtJ8p/gLHUZ1OUaaTaVLluNkABkk6arQwE%3D"; #specifically pinned for kernel version nixpkgs-stable.url = "github:NixOS/nixpkgs/nixos-25.11"; @@ -2487,12 +2486,15 @@ The rest of the functions are used to build full NixOS systems as well as halfCo // config.guestConfigurations; guestResources = lib.mapAttrs - (name: _: let - f = arg: lib.foldr (base: acc: base + acc) 0 (map (node: nodes."${name}-${node}".config.microvm.${arg}) (builtins.attrNames nodes.${name}.config.guests)); - in { - mem = f "mem"; - vcpu = f "vcpu"; - }) nodes; + (name: _: + let + f = arg: lib.foldr (base: acc: base + acc) 0 (map (node: nodes."${name}-${node}".config.microvm.${arg}) (builtins.attrNames nodes.${name}.config.guests)); + in + { + mem = f "mem"; + vcpu = f "vcpu"; + }) + nodes; "@" = lib.mapAttrs (_: v: v.config.system.build.toplevel) config.nodes; }; @@ -2854,30 +2856,31 @@ Aside from the =default= devShell which is the one that should usually be called deploy = let nix-version = "2_28"; - in { - packages = [ - (builtins.trace "alarm: pinned nix_${nix-version}" pkgs.stable25_05.nixVersions."nix_${nix-version}") - pkgs.git - pkgs.just - pkgs.age - pkgs.ssh-to-age - pkgs.sops - ]; - - env = - [ - { - name = "NIX_CONFIG"; - value = '' - plugin-files = ${pkgs.stable25_05.nix-plugins.overrideAttrs (o: { - buildInputs = [pkgs.stable25_05.nixVersions."nix_${nix-version}" pkgs.stable25_05.boost]; - patches = (o.patches or []) ++ [./nix-plugins.patch]; - })}/lib/nix/plugins - extra-builtins-file = ${self + /nix/extra-builtins.nix} - ''; - } + in + { + packages = [ + (builtins.trace "alarm: pinned nix_${nix-version}" pkgs.stable25_05.nixVersions."nix_${nix-version}") + pkgs.git + pkgs.just + pkgs.age + pkgs.ssh-to-age + pkgs.sops ]; - }; + + env = + [ + { + name = "NIX_CONFIG"; + value = '' + plugin-files = ${pkgs.stable25_05.nix-plugins.overrideAttrs (o: { + buildInputs = [pkgs.stable25_05.nixVersions."nix_${nix-version}" pkgs.stable25_05.boost]; + patches = (o.patches or []) ++ [./nix-plugins.patch]; + })}/lib/nix/plugins + extra-builtins-file = ${self + /nix/extra-builtins.nix} + ''; + } + ]; + }; default = let nix-version = "2_30"; @@ -3196,166 +3199,168 @@ On the structure of overlays: as you notice, all of the attributes within overla inherit (self) outputs; inherit (outputs) lib; in - { - flake = _: + { + flake = _: { - overlays = let - nixpkgs-stable-versions = final: _: + overlays = let - nixpkgsInputs = - lib.filterAttrs - (name: _v: builtins.match "^nixpkgs-.*" name != null) - inputs; + nixpkgs-stable-versions = final: _: + let + nixpkgsInputs = + lib.filterAttrs + (name: _v: builtins.match "^nixpkgs-.*" name != null) + inputs; - rename = name: builtins.replaceStrings [ "nixpkgs-" ] [ "" ] name; + rename = name: builtins.replaceStrings [ "nixpkgs-" ] [ "" ] name; + + mkPkgs = src: + import src { + inherit (final.stdenv.hostPlatform) system; + config.allowUnfree = true; + }; + in + builtins.listToAttrs (map + (name: { + name = rename name; + value = mkPkgs nixpkgsInputs.${name}; + }) + (builtins.attrNames nixpkgsInputs)); - mkPkgs = src: - import src { - inherit (final.stdenv.hostPlatform) system; - config.allowUnfree = true; - }; in - builtins.listToAttrs (map - (name: { - name = rename name; - value = mkPkgs nixpkgsInputs.${name}; - }) - (builtins.attrNames nixpkgsInputs)); - - in rec { - default = additions; - additions = final: prev: - let - additions = final: _: import "${self}/pkgs/flake" { pkgs = final; inherit self lib; } - // { + rec { + default = additions; + additions = final: prev: + let + additions = final: _: import "${self}/pkgs/flake" { pkgs = final; inherit self lib; } + // { swarsel-nix = import inputs.swarsel-nix { pkgs = prev; }; zjstatus = inputs.zjstatus.packages.${prev.stdenv.hostPlatform.system}.default; }; - in - (additions final prev) - // (nixpkgs-stable-versions final prev) - // (inputs.niri-flake.overlays.niri final prev) - // (inputs.noctalia.overlays.default final prev) - // (inputs.vbc-nix.overlays.default final prev) - // (inputs.nur.overlays.default final prev) - // (inputs.emacs-overlay.overlay final prev) - // (inputs.nix-topology.overlays.default final prev) - // (inputs.nix-index-database.overlays.nix-index final prev) - // (inputs.nixgl.overlay final prev) - // (inputs.nix-minecraft.overlay final prev) - // (inputs.nixos-extra-modules.overlays.default final prev); + in + (additions final prev) + // (nixpkgs-stable-versions final prev) + // (inputs.niri-flake.overlays.niri final prev) + // (inputs.noctalia.overlays.default final prev) + // (inputs.vbc-nix.overlays.default final prev) + // (inputs.nur.overlays.default final prev) + // (inputs.emacs-overlay.overlay final prev) + // (inputs.nix-topology.overlays.default final prev) + // (inputs.nix-index-database.overlays.nix-index final prev) + // (inputs.nixgl.overlay final prev) + // (inputs.nix-minecraft.overlay final prev) + // (inputs.nixos-extra-modules.overlays.default final prev); - stables = final: prev: - let - mkUsePkgsFrom = pkgsFrom: names: - builtins.listToAttrs (map - (name: { - inherit name; - value = pkgsFrom.${name}; - }) - names); + stables = final: prev: + let + mkUsePkgsFrom = pkgsFrom: names: + builtins.listToAttrs (map + (name: { + inherit name; + value = pkgsFrom.${name}; + }) + names); - from = let - stablePackages = nixpkgs-stable-versions final prev; - in key: - stablePackages.${key} or (throw "Missing nixpkgs input nixpkgs-${key}"); + from = + let + stablePackages = nixpkgs-stable-versions final prev; + in + key: + stablePackages.${key} or (throw "Missing nixpkgs input nixpkgs-${key}"); - in - (mkUsePkgsFrom (from "dev") [ - # "swayosd" - "firezone-relay" - "firezone-server-web" - "firezone-server-api" - "firezone-server-domain" - ]) - // (mkUsePkgsFrom (from "stable24_05") [ - "awscli2" - ]) - // (mkUsePkgsFrom (from "stable24_11") [ - "python39" - "spotify" - "vieb" - ]) - // (mkUsePkgsFrom (from "stable25_05") [ - "steam-fhsenv-without-steam" - "transmission_3" - ]) - // (mkUsePkgsFrom (from "stable") [ - # "anki" - "azure-cli" - # "bat-extras.batgrep" - # "bluez" - "calibre" - # "chromium" - "dwarfs" - "gotenberg" - "khal" - "libreoffice" - "libreoffice-qt" - "nerd-fonts-symbols-only" - "noto-fonts" - "noto-fonts-cjk-sans" - "noto-fonts-color-emoji" - # "pipewire" - "podman" - "teams-for-linux" - # "vesktop" - "virtualbox" - ]); - - modifications = final: prev: - let - modifications = final: prev: { - # vesktop = prev.vesktop.override { - # withSystemVencord = true; - # }; - - lib = prev.lib // { - swarselsystems = self.outputs.swarselsystemsLib; - hm = self.outputs.homeLib; - }; - - firefox = prev.firefox.override { - nativeMessagingHosts = [ - prev.tridactyl-native - prev.browserpass - # prev.plasma5Packages.plasma-browser-integration - ]; - }; - - isync = prev.isync.override { - withCyrusSaslXoauth2 = true; - }; - - mgba = final.swarsel-mgba; - - noctalia-shell = prev.noctalia-shell.override { - calendarSupport = true; - }; - - retroarch = prev.retroarch.withCores (cores: with cores; [ - snes9x # snes - nestopia # nes - dosbox # dos - scummvm # scumm - vba-m # gb/a - mgba # gb/a - melonds # ds - dolphin # gc/wii + in + (mkUsePkgsFrom (from "dev") [ + # "swayosd" + "firezone-relay" + "firezone-server-web" + "firezone-server-api" + "firezone-server-domain" + ]) + // (mkUsePkgsFrom (from "stable24_05") [ + "awscli2" + ]) + // (mkUsePkgsFrom (from "stable24_11") [ + "python39" + "spotify" + "vieb" + ]) + // (mkUsePkgsFrom (from "stable25_05") [ + "steam-fhsenv-without-steam" + "transmission_3" + ]) + // (mkUsePkgsFrom (from "stable") [ + # "anki" + "azure-cli" + # "bat-extras.batgrep" + # "bluez" + "calibre" + # "chromium" + "dwarfs" + "gotenberg" + "khal" + "libreoffice" + "libreoffice-qt" + "nerd-fonts-symbols-only" + "noto-fonts-color-emoji" + # "pipewire" + "podman" + "teams-for-linux" + # "vesktop" + "virtualbox" ]); - }; - in - modifications final prev; - }; + modifications = final: prev: + let + modifications = final: prev: { + # vesktop = prev.vesktop.override { + # withSystemVencord = true; + # }; + + lib = prev.lib // { + swarselsystems = self.outputs.swarselsystemsLib; + hm = self.outputs.homeLib; + }; + + firefox = prev.firefox.override { + nativeMessagingHosts = [ + prev.tridactyl-native + prev.browserpass + # prev.plasma5Packages.plasma-browser-integration + ]; + }; + + isync = prev.isync.override { + withCyrusSaslXoauth2 = true; + }; + + mgba = final.swarsel-mgba; + + noctalia-shell = prev.noctalia-shell.override { + calendarSupport = true; + }; + + retroarch = prev.retroarch.withCores (cores: with cores; [ + snes9x # snes + nestopia # nes + dosbox # dos + scummvm # scumm + vba-m # gb/a + mgba # gb/a + melonds # ds + dolphin # gc/wii + ]); + + }; + in + modifications final prev; + }; }; - } + } #+end_src -** Installer images (iso, kexec) +** Installer images (live iso, kexec) :PROPERTIES: :CUSTOM_ID: h:1d1ccae5-62ca-4d37-a28e-c59987850ed2 :END: @@ -6143,7 +6148,6 @@ A Mac notebook that I have received from work. I use this machine for getting ac My phone. I use only a minimal config for remote debugging here. #+begin_src nix-ts :tangle hosts/android/aarch64-linux/magicant/default.nix - { pkgs, ... }: { environment = { packages = with pkgs; [ @@ -6188,8 +6192,6 @@ My phone. I use only a minimal config for remote debugging here. experimental-features = nix-command flakes ''; } - - #+end_src **** Treehouse (DGX Spark) @@ -7870,7 +7872,7 @@ This is a slim setup for developing base configuration. I do not track the hardw #+end_src -**** TODO Drugstore (ISO installer config) +**** TODO Drugstore (live ISO installer config) :PROPERTIES: :CUSTOM_ID: h:8583371d-5d47-468b-84ba-210aad7e2c90 :END: @@ -8003,7 +8005,7 @@ Steps to recover using live ISO: networking = { hostName = "drugstore"; - wireless.enable = false; + wireless.enable = lib.mkForce false; # dhcpcd.runHook = "${pkgs.utillinux}/bin/agetty --reload"; networkmanager.enable = true; usePredictableInterfaceNames = false; @@ -10736,7 +10738,7 @@ Also, since I use a GPG key in sops, it seems that scdaemon creates an instance config = lib.mkIf config.swarselmodules.yubikey { programs.ssh.startAgent = false; - services.pcscd.enable = false; + services.pcscd.enable = true; hardware.gpgSmartcards.enable = true; @@ -12012,7 +12014,7 @@ Restricts access to the system by the nix build user as per https://discourse.ni "nix-store --serve --write") exec env NIX_SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt ${config.nix.package}/bin/nix-store --serve --write ;; - ,*) + *) echo "Access only allowed for using the nix remote builder" 1>&2 exit esac @@ -12154,14 +12156,8 @@ systemd-initrd provides a lightweight SSH server in form of dropbear - in order I also take some precautions in how I get networking information during stage 1. For the most part, I just use [[#h:12370671-7892-4a74-a804-84f871acde06][systemd-networkd (server)]], however, for hosts in my local network, I take another step to define the network in the =kernelParams=, to make extra sure I can reach it. #+begin_src nix-ts :tangle modules/nixos/server/disk-encrypt.nix - { self, pkgs, lib, config, globals, minimal, ... }: + { self, pkgs, lib, config, minimal, ... }: let - localIp = globals.networks.${config.swarselsystems.server.netConfigName}.hosts.${config.node.name}.ipv4; - subnetMask = globals.networks.${config.swarselsystems.server.netConfigName}.subnetMask4; - gatewayIp = globals.hosts.${config.node.name}.defaultGateway4; - - inherit (globals.general) routerServer; - isRouter = config.node.name == routerServer; hostKeyPathBase = "/etc/secrets/initrd/ssh_host_ed25519_key"; hostKeyPath = @@ -12172,7 +12168,7 @@ I also take some precautions in how I get networking information during stage 1. # this key is only used only for ssh to stage 1 in initial provisioning (in nix store) generatedHostKey = pkgs.runCommand "initrd-hostkey" { } '' - ${pkgs.openssh}/bin/ssh-keygen -t ed25519 -N "" -f $out + ${pkgs.openssh}/bin/ssh-keygen -t ed25519 -N "" -f $out ''; in { @@ -12275,18 +12271,20 @@ By default, attic only provides a cli client to authenticate to caches. I want a config.sops.templates.attic-env.path ]; }; - script = let - attic = lib.getExe pkgs.attic-client; - in '' - set -eu - if ${attic} cache info ${config.swarselsystems.mainUser} >/dev/null 2>&1; then - echo "cache already authenticated" - exit 0 - fi - echo "cache not authenticated, attempting login..." - ${attic} login ${config.swarselsystems.mainUser} "$DOMAIN" "$TOKEN" --set-default - ${attic} use ${config.swarselsystems.mainUser} - ''; + script = + let + attic = lib.getExe pkgs.attic-client; + in + '' + set -eu + if ${attic} cache info ${config.swarselsystems.mainUser} >/dev/null 2>&1; then + echo "cache already authenticated" + exit 0 + fi + echo "cache not authenticated, attempting login..." + ${attic} login ${config.swarselsystems.mainUser} "$DOMAIN" "$TOKEN" --set-default + ${attic} use ${config.swarselsystems.mainUser} + ''; }; @@ -12331,15 +12329,17 @@ In order to define a new wireguard interface, I have to: inherit (cfg) interfaces; ifaceList = builtins.attrValues interfaces; in - { - options = { - swarselmodules.server.${serviceName} = - lib.mkEnableOption "enable ${serviceName} settings"; + { + options = { + swarselmodules.server.${serviceName} = + lib.mkEnableOption "enable ${serviceName} settings"; - swarselsystems.server.wireguard = { - interfaces = let + swarselsystems.server.wireguard = { + interfaces = + let topConfig = config; - in lib.mkOption { + in + lib.mkOption { type = lib.types.attrsOf (lib.types.submodule ({ config, name, ... }: { options = { isServer = lib.mkEnableOption "set this interface as a wireguard server"; @@ -12357,9 +12357,9 @@ In order to define a new wireguard interface, I have to: let serverCfg = nodes.${config.serverName}.config; in - if serverCfg.swarselsystems.isCloud - then serverCfg.node.name - else "home"; + if serverCfg.swarselsystems.isCloud + then serverCfg.node.name + else "home"; readOnly = true; description = "Prefix used to look up the server network in globals.networks.\"-wg\"."; }; @@ -12386,55 +12386,55 @@ In order to define a new wireguard interface, I have to: default = { }; description = "WireGuard interfaces defined on this host."; }; - }; }; + }; - config = lib.mkIf config.swarselmodules.server.${serviceName} { + config = lib.mkIf config.swarselmodules.server.${serviceName} { - assertions = lib.concatLists ( - lib.flip lib.mapAttrsToList interfaces ( - ifName: ifCfg: + assertions = lib.concatLists ( + lib.flip lib.mapAttrsToList interfaces ( + ifName: ifCfg: let assertionPrefix = "While evaluating the wireguard network ${ifName}:"; in - [ - { - assertion = ifCfg.isServer || (ifCfg.isClient && ifCfg.serverName != ""); - message = "${assertionPrefix}: This node must either be a server for the wireguard network or a client with serverName set."; - } - { - assertion = lib.stringLength ifName < 16; - message = "${assertionPrefix}: The specified linkName '${ifName}' is too long (must be max 15 characters)."; - } - ] - ) - ); - - topology.self.interfaces = lib.mapAttrs' - (wgName: _: - lib.nameValuePair "${wgName}" { - network = wgName; - } - ) - config.swarselsystems.server.wireguard.interfaces; - - environment.systemPackages = with pkgs; [ - wireguard-tools - ]; - - sops.secrets = - lib.mkMerge ( [ { - wireguard-private-key = { - inherit sopsFile; - owner = serviceUser; - group = serviceGroup; - mode = "0600"; - }; + assertion = ifCfg.isServer || (ifCfg.isClient && ifCfg.serverName != ""); + message = "${assertionPrefix}: This node must either be a server for the wireguard network or a client with serverName set."; } - ] ++ (map - (i: + { + assertion = lib.stringLength ifName < 16; + message = "${assertionPrefix}: The specified linkName '${ifName}' is too long (must be max 15 characters)."; + } + ] + ) + ); + + topology.self.interfaces = lib.mapAttrs' + (wgName: _: + lib.nameValuePair "${wgName}" { + network = wgName; + } + ) + config.swarselsystems.server.wireguard.interfaces; + + environment.systemPackages = with pkgs; [ + wireguard-tools + ]; + + sops.secrets = + lib.mkMerge ( + [ + { + wireguard-private-key = { + inherit sopsFile; + owner = serviceUser; + group = serviceGroup; + mode = "0600"; + }; + } + ] ++ (map + (i: let clientSecrets = lib.optionalAttrs i.isClient { @@ -12459,26 +12459,26 @@ In order to define a new wireguard interface, I have to: }) i.peers)); in - clientSecrets // serverSecrets - ) - ifaceList) - ); - - networking.firewall = { - checkReversePath = lib.mkIf (lib.any (i: i.isClient) ifaceList) "loose"; - allowedUDPPorts = lib.mkMerge ( - lib.flip lib.mapAttrsToList interfaces ( - _: ifCfg: - lib.optional ifCfg.isServer ifCfg.port + clientSecrets // serverSecrets ) - ); - }; + ifaceList) + ); - networking.nftables.firewall = { - zones = lib.mkMerge - ( - lib.flip lib.mapAttrsToList interfaces ( - ifName: ifCfg: + networking.firewall = { + checkReversePath = lib.mkIf (lib.any (i: i.isClient) ifaceList) "loose"; + allowedUDPPorts = lib.mkMerge ( + lib.flip lib.mapAttrsToList interfaces ( + _: ifCfg: + lib.optional ifCfg.isServer ifCfg.port + ) + ); + }; + + networking.nftables.firewall = { + zones = lib.mkMerge + ( + lib.flip lib.mapAttrsToList interfaces ( + ifName: ifCfg: { ${ifName}.interfaces = [ ifName ]; } @@ -12487,30 +12487,30 @@ In order to define a new wireguard interface, I have to: let peerNet = globals.networks."${ifCfg.serverNetConfigPrefix}-${ifName}".hosts.${peer}; in - lib.nameValuePair "${ifName}-node-${peer}" { - parent = ifName; - ipv4Addresses = lib.optional (peerNet.ipv4 != null) peerNet.ipv4; - ipv6Addresses = lib.optional (peerNet.ipv6 != null) peerNet.ipv6; - } + lib.nameValuePair "${ifName}-node-${peer}" { + parent = ifName; + ipv4Addresses = lib.optional (peerNet.ipv4 != null) peerNet.ipv4; + ipv6Addresses = lib.optional (peerNet.ipv6 != null) peerNet.ipv6; + } ) ifCfg.peers) - ) - ); - rules = lib.mkMerge ( - lib.flip lib.mapAttrsToList interfaces ( - ifName: ifCfg: + ) + ); + rules = lib.mkMerge ( + lib.flip lib.mapAttrsToList interfaces ( + ifName: ifCfg: let inherit (config.networking.nftables.firewall) localZoneName; netCfg = globals.networks."${ifCfg.serverNetConfigPrefix}-${ifName}"; in - { - "${ifName}-to-${localZoneName}" = { - inherit (netCfg.firewallRuleForAll) allowedTCPPorts allowedUDPPorts allowedTCPPortRanges allowedUDPPortRanges; - from = [ ifName ]; - to = [ localZoneName ]; - ignoreEmptyRule = true; - }; - } + { + "${ifName}-to-${localZoneName}" = { + inherit (netCfg.firewallRuleForAll) allowedTCPPorts allowedUDPPorts allowedTCPPortRanges allowedUDPPortRanges; + from = [ ifName ]; + to = [ localZoneName ]; + ignoreEmptyRule = true; + }; + } // lib.listToAttrs (map (peer: lib.nameValuePair "${ifName}-node-${peer}-to-${localZoneName}" ( @@ -12523,75 +12523,75 @@ In order to define a new wireguard interface, I have to: ) ) ifCfg.peers) - ) - ); - }; + ) + ); + }; - systemd.network = { - enable = true; + systemd.network = { + enable = true; - networks = lib.mkMerge (map - (i: + networks = lib.mkMerge (map + (i: let inherit (i) ifName; in - { - "50-${ifName}" = { - matchConfig.Name = ifName; - linkConfig = { - MTUBytes = 1408; # TODO: figure out where we lose those 12 bits (8 from pppoe maybe + ???) - }; - - address = [ - globals.networks."${i.serverNetConfigPrefix}-${ifName}".hosts.${config.node.name}.cidrv4 - globals.networks."${i.serverNetConfigPrefix}-${ifName}".hosts.${config.node.name}.cidrv6 - ]; + { + "50-${ifName}" = { + matchConfig.Name = ifName; + linkConfig = { + MTUBytes = 1408; # TODO: figure out where we lose those 12 bits (8 from pppoe maybe + ???) }; - }) - ifaceList); - netdevs = lib.mkMerge (map - (i: + address = [ + globals.networks."${i.serverNetConfigPrefix}-${ifName}".hosts.${config.node.name}.cidrv4 + globals.networks."${i.serverNetConfigPrefix}-${ifName}".hosts.${config.node.name}.cidrv6 + ]; + }; + }) + ifaceList); + + netdevs = lib.mkMerge (map + (i: let inherit (i) ifName; in - { - "50-${ifName}" = { - netdevConfig = { - Kind = "wireguard"; - Name = ifName; - }; + { + "50-${ifName}" = { + netdevConfig = { + Kind = "wireguard"; + Name = ifName; + }; - wireguardConfig = { - ListenPort = lib.mkIf i.isServer servicePort; + wireguardConfig = { + ListenPort = lib.mkIf i.isServer servicePort; - PrivateKeyFile = config.sops.secrets.wireguard-private-key.path; + PrivateKeyFile = config.sops.secrets.wireguard-private-key.path; - RouteTable = lib.mkIf i.isClient "main"; - }; + RouteTable = lib.mkIf i.isClient "main"; + }; - wireguardPeers = - lib.optionals i.isClient [ - { - PublicKey = - builtins.readFile "${self}/secrets/public/wg/${i.serverName}.pub"; + wireguardPeers = + lib.optionals i.isClient [ + { + PublicKey = + builtins.readFile "${self}/secrets/public/wg/${i.serverName}.pub"; - PresharedKeyFile = - config.sops.secrets."wireguard-${i.serverName}-${config.node.name}-${i.ifName}-presharedKey".path; + PresharedKeyFile = + config.sops.secrets."wireguard-${i.serverName}-${config.node.name}-${i.ifName}-presharedKey".path; - Endpoint = - "server.${i.serverName}.${globals.domains.main}:${toString servicePort}"; + Endpoint = + "server.${i.serverName}.${globals.domains.main}:${toString servicePort}"; - PersistentKeepalive = 25; + PersistentKeepalive = 25; - AllowedIPs = - let - wgNetwork = globals.networks."${i.serverNetConfigPrefix}-${i.ifName}"; - in - (lib.optional (wgNetwork.cidrv4 != null) wgNetwork.cidrv4) + AllowedIPs = + let + wgNetwork = globals.networks."${i.serverNetConfigPrefix}-${i.ifName}"; + in + (lib.optional (wgNetwork.cidrv4 != null) wgNetwork.cidrv4) ++ (lib.optional (wgNetwork.cidrv6 != null) wgNetwork.cidrv6); - } - ] + } + ] ++ lib.optionals i.isServer (map (clientName: { PublicKey = @@ -12605,18 +12605,18 @@ In order to define a new wireguard interface, I have to: clientInWgNetwork = globals.networks."${i.serverNetConfigPrefix}-${i.ifName}".hosts.${clientName}; in - (lib.optional (clientInWgNetwork.ipv4 != null) - (lib.net.cidr.make 32 clientInWgNetwork.ipv4)) + (lib.optional (clientInWgNetwork.ipv4 != null) + (lib.net.cidr.make 32 clientInWgNetwork.ipv4)) ++ (lib.optional (clientInWgNetwork.ipv6 != null) (lib.net.cidr.make 128 clientInWgNetwork.ipv6)); }) i.peers); - }; - }) - ifaceList); - }; + }; + }) + ifaceList); }; - } + }; + } #+end_src **** BTRFS @@ -13470,7 +13470,7 @@ Needed for audio and stuff. Many services require a databasee, and I like to go with full postgres when giving the chance. Each host will usually run its own instance instead of maintaining a centralised one. #+begin_src nix-ts :tangle modules/nixos/server/postgresql.nix - { self, config, lib, pkgs, confLib, ... }: + { config, lib, pkgs, confLib, ... }: let inherit (confLib.gen { name = "postgresql"; port = 3254; }) serviceName; postgresVersion = 14; @@ -13546,7 +13546,7 @@ Allows me to spin up containers for services that do not provide NixOS options. }; local-to-podman = { - from = [ "local" "wgProxy" "wgHome"]; + from = [ "local" "wgProxy" "wgHome" ]; to = [ "podman" ]; before = [ "drop" ]; verdict = "accept"; @@ -13992,7 +13992,7 @@ My file server. I aim to decomission this as soon as I can, however, I need a re globals.services.${serviceName} = { domain = serviceDomain; inherit proxyAddress4 proxyAddress6 isHome serviceAddress; - homeServiceAddress = lib.mkIf isHome homeServiceAddress; + homeServiceAddress = lib.mkIf isHome homeServiceAddress; }; environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { @@ -14155,140 +14155,140 @@ Also I install Tika and Gotenberg, which are needed to create PDFs out of =.eml= gotenbergPort = 3002; kanidmDomain = globals.services.kanidm.domain; in - { - options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; - config = lib.mkIf config.swarselmodules.server.${serviceName} { + { + options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselmodules.server.${serviceName} { - users = { - persistentIds = { - redis-paperless = confLib.mkIds 975; + users = { + persistentIds = { + redis-paperless = confLib.mkIds 975; + }; + users.${serviceUser} = { + extraGroups = [ "users" ]; + }; + }; + + sops.secrets = { + paperless-admin-pw = { inherit sopsFile; owner = serviceUser; }; + kanidm-paperless-client = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + }; + + # networking.firewall.allowedTCPPorts = [ servicePort ]; + + globals = { + networks = { + ${webProxyIf}.hosts = lib.mkIf isProxied { + ${config.node.name}.firewallRuleForNode.${webProxy}.allowedTCPPorts = [ servicePort ]; }; - users.${serviceUser} = { - extraGroups = [ "users" ]; + ${homeProxyIf}.hosts = lib.mkIf isHome { + ${config.node.name}.firewallRuleForNode.${homeWebProxy}.allowedTCPPorts = [ servicePort ]; }; }; - - sops.secrets = { - paperless-admin-pw = { inherit sopsFile; owner = serviceUser; }; - kanidm-paperless-client = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6 isHome serviceAddress; + homeServiceAddress = lib.mkIf isHome homeServiceAddress; }; + }; - # networking.firewall.allowedTCPPorts = [ servicePort ]; + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [ + { directory = "/var/lib/${serviceName}"; user = serviceUser; group = serviceGroup; } + { directory = "/var/lib/redis-${serviceName}"; user = "redis-${serviceUser}"; group = "redis-${serviceGroup}"; } + { directory = "/var/lib/private/tika"; } + { directory = "/var/cache/${serviceName}"; user = serviceUser; group = serviceGroup; } + { directory = "/var/cache/private/tika"; } + ]; + }; - globals = { - networks = { - ${webProxyIf}.hosts = lib.mkIf isProxied { - ${config.node.name}.firewallRuleForNode.${webProxy}.allowedTCPPorts = [ servicePort ]; + services = { + ${serviceName} = { + enable = true; + mediaDir = "/storage/Documents/${serviceName}"; + dataDir = "/var/lib/${serviceName}"; + user = serviceUser; + port = servicePort; + passwordFile = config.sops.secrets.paperless-admin-pw.path; + address = "0.0.0.0"; + settings = { + PAPERLESS_OCR_LANGUAGE = "deu+eng"; + PAPERLESS_URL = "https://${serviceDomain}"; + PAPERLESS_OCR_USER_ARGS = builtins.toJSON { + optimize = 1; + invalidate_digital_signatures = true; + pdfa_image_compression = "lossless"; }; - ${homeProxyIf}.hosts = lib.mkIf isHome { - ${config.node.name}.firewallRuleForNode.${homeWebProxy}.allowedTCPPorts = [ servicePort ]; - }; - }; - services.${serviceName} = { - domain = serviceDomain; - inherit proxyAddress4 proxyAddress6 isHome serviceAddress; - homeServiceAddress = lib.mkIf isHome homeServiceAddress; - }; - }; - - environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { - directories = [ - { directory = "/var/lib/${serviceName}"; user = serviceUser; group = serviceGroup; } - { directory = "/var/lib/redis-${serviceName}"; user = "redis-${serviceUser}"; group = "redis-${serviceGroup}"; } - { directory = "/var/lib/private/tika"; } - { directory = "/var/cache/${serviceName}"; user = serviceUser; group = serviceGroup; } - { directory = "/var/cache/private/tika"; } - ]; - }; - - services = { - ${serviceName} = { - enable = true; - mediaDir = "/storage/Documents/${serviceName}"; - dataDir = "/var/lib/${serviceName}"; - user = serviceUser; - port = servicePort; - passwordFile = config.sops.secrets.paperless-admin-pw.path; - address = "0.0.0.0"; - settings = { - PAPERLESS_OCR_LANGUAGE = "deu+eng"; - PAPERLESS_URL = "https://${serviceDomain}"; - PAPERLESS_OCR_USER_ARGS = builtins.toJSON { - optimize = 1; - invalidate_digital_signatures = true; - pdfa_image_compression = "lossless"; - }; - PAPERLESS_TIKA_ENABLED = "true"; - PAPERLESS_TIKA_ENDPOINT = "http://localhost:${builtins.toString tikaPort}"; - PAPERLESS_TIKA_GOTENBERG_ENDPOINT = "http://localhost:${builtins.toString gotenbergPort}"; - PAPERLESS_APPS = "allauth.socialaccount.providers.openid_connect"; - PAPERLESS_SOCIALACCOUNT_PROVIDERS = builtins.toJSON { - openid_connect = { - OAUTH_PKCE_ENABLED = "True"; - APPS = [ - rec { - provider_id = "kanidm"; - name = "Kanidm"; - client_id = "paperless"; - # secret will be added by paperless-web.service (see below) - #secret = ""; - settings.server_url = "https://${kanidmDomain}/oauth2/openid/${client_id}/.well-known/openid-configuration"; - } - ]; - }; + PAPERLESS_TIKA_ENABLED = "true"; + PAPERLESS_TIKA_ENDPOINT = "http://localhost:${builtins.toString tikaPort}"; + PAPERLESS_TIKA_GOTENBERG_ENDPOINT = "http://localhost:${builtins.toString gotenbergPort}"; + PAPERLESS_APPS = "allauth.socialaccount.providers.openid_connect"; + PAPERLESS_SOCIALACCOUNT_PROVIDERS = builtins.toJSON { + openid_connect = { + OAUTH_PKCE_ENABLED = "True"; + APPS = [ + rec { + provider_id = "kanidm"; + name = "Kanidm"; + client_id = "paperless"; + # secret will be added by paperless-web.service (see below) + #secret = ""; + settings.server_url = "https://${kanidmDomain}/oauth2/openid/${client_id}/.well-known/openid-configuration"; + } + ]; }; }; }; - - tika = { - enable = true; - port = tikaPort; - openFirewall = false; - listenAddress = "127.0.0.1"; - enableOcr = true; - }; - - gotenberg = { - enable = true; - package = pkgs.gotenberg; - libreoffice.package = pkgs.libreoffice; - port = gotenbergPort; - bindIP = "127.0.0.1"; - timeout = "600s"; - chromium.package = pkgs.chromium; - }; }; + tika = { + enable = true; + port = tikaPort; + openFirewall = false; + listenAddress = "127.0.0.1"; + enableOcr = true; + }; - # Add secret to PAPERLESS_SOCIALACCOUNT_PROVIDERS - systemd.services.paperless-web.script = lib.mkBefore '' + gotenberg = { + enable = true; + package = pkgs.gotenberg; + libreoffice.package = pkgs.libreoffice; + port = gotenbergPort; + bindIP = "127.0.0.1"; + timeout = "600s"; + chromium.package = pkgs.chromium; + }; + }; + + + # Add secret to PAPERLESS_SOCIALACCOUNT_PROVIDERS + systemd.services.paperless-web.script = lib.mkBefore '' oidcSecret=$(< ${config.sops.secrets.kanidm-paperless-client.path}) export PAPERLESS_SOCIALACCOUNT_PROVIDERS=$( ${pkgs.jq}/bin/jq <<< "$PAPERLESS_SOCIALACCOUNT_PROVIDERS" \ --compact-output \ --arg oidcSecret "$oidcSecret" '.openid_connect.APPS.[0].secret = $oidcSecret' ) - ''; + ''; - nodes = - let - extraConfigLoc = '' + nodes = + let + extraConfigLoc = '' proxy_connect_timeout 300; proxy_send_timeout 300; proxy_read_timeout 300; send_timeout 300; - ''; - in - { - ${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { - "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; - }; - ${webProxy}.services.nginx = confLib.genNginx { inherit serviceAddress servicePort serviceDomain serviceName extraConfigLoc; maxBody = 0; }; - ${homeWebProxy}.services.nginx = lib.mkIf isHome (confLib.genNginx { inherit servicePort serviceDomain serviceName extraConfigLoc; maxBody = 0; extraConfig = nginxAccessRules; serviceAddress = homeServiceAddress; }); - }; + ''; + in + { + ${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + ${webProxy}.services.nginx = confLib.genNginx { inherit serviceAddress servicePort serviceDomain serviceName extraConfigLoc; maxBody = 0; }; + ${homeWebProxy}.services.nginx = lib.mkIf isHome (confLib.genNginx { inherit servicePort serviceDomain serviceName extraConfigLoc; maxBody = 0; extraConfig = nginxAccessRules; serviceAddress = homeServiceAddress; }); + }; - }; - } + }; + } #+end_src **** transmission @@ -14321,233 +14321,232 @@ I use this configuration for sailing. prowlarrGroup = prowlarrUser; prowlarrPort = 9696; in - { - options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} and friends on server"; - config = lib.mkIf config.swarselmodules.server.${serviceName} { + { + options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} and friends on server"; + config = lib.mkIf config.swarselmodules.server.${serviceName} { - sops.secrets = { - pia = { inherit sopsFile; }; + sops.secrets = { + pia = { inherit sopsFile; }; + }; + + # this user/group section is probably unneeded + users = { + persistentIds = { + prowlarr = confLib.mkIds 971; + readarr = confLib.mkIds 970; + }; + groups = { + dockeruser = { + gid = 1155; + }; + "${radarrGroup}" = { }; + "${readarrGroup}" = { }; + "${sonarrGroup}" = { }; + "${lidarrGroup}" = { }; + "${prowlarrGroup}" = { }; }; - - # this user/group section is probably unneeded users = { - persistentIds = { - prowlarr = confLib.mkIds 971; - readarr = confLib.mkIds 970; + dockeruser = { + isSystemUser = true; + uid = 1155; + group = "docker"; + extraGroups = [ "users" ]; }; - groups = { - dockeruser = { - gid = 1155; - }; - "${radarrGroup}" = { }; - "${readarrGroup}" = { }; - "${sonarrGroup}" = { }; - "${lidarrGroup}" = { }; - "${prowlarrGroup}" = { }; - }; - users = { - dockeruser = { - isSystemUser = true; - uid = 1155; - group = "docker"; - extraGroups = [ "users" ]; - }; - "${radarrUser}" = { - isSystemUser = true; - group = radarrGroup; - extraGroups = [ "users" ]; - }; - "${readarrGroup}" = { - isSystemUser = true; - group = readarrGroup; - extraGroups = [ "users" ]; - }; - "${sonarrGroup}" = { - isSystemUser = true; - group = sonarrGroup; - extraGroups = [ "users" ]; - }; - "${lidarrUser}" = { - isSystemUser = true; - group = lidarrGroup; - extraGroups = [ "users" ]; - }; - "${prowlarrGroup}" = { - isSystemUser = true; - group = prowlarrGroup; - extraGroups = [ "users" ]; - }; - }; - }; - - virtualisation.docker.enable = true; - environment.systemPackages = with pkgs; [ - docker - ]; - - topology.self.services = { - radarr.info = "https://${serviceDomain}/radarr"; - readarr = { - name = "Readarr"; - info = "https://${serviceDomain}/readarr"; - icon = "${self}/files/topology-images/readarr.png"; - }; - sonarr.info = "https://${serviceDomain}/sonarr"; - lidarr.info = "https://${serviceDomain}/lidarr"; - prowlarr.info = "https://${serviceDomain}/prowlarr"; - }; - - globals.services.transmission = { - domain = serviceDomain; - inherit isHome; - }; - - environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { - directories = [ - { directory = "/var/lib/radarr"; user = radarrUser; group = radarrGroup; } - { directory = "/var/lib/readarr"; user = readarrUser; group = readarrGroup; } - { directory = "/var/lib/sonarr"; user = sonarrUser; group = sonarrGroup; } - { directory = "/var/lib/lidarr"; user = lidarrUser; group = lidarrGroup; } - { directory = "/var/lib/private/prowlarr"; user = prowlarrUser; group = prowlarrGroup; } - ]; - }; - - services = { - pia = { - enable = true; - credentials.credentialsFile = config.sops.secrets.pia.path; - protocol = "wireguard"; - autoConnect = { - enable = true; - region = "sweden"; - }; - portForwarding.enable = true; - dns.enable = true; - }; - radarr = { - enable = true; - user = radarrUser; + "${radarrUser}" = { + isSystemUser = true; group = radarrGroup; - settings.server.port = radarrPort; - openFirewall = true; - dataDir = "/var/lib/radarr"; + extraGroups = [ "users" ]; }; - readarr = { - enable = true; - user = readarrUser; + "${readarrGroup}" = { + isSystemUser = true; group = readarrGroup; - settings.server.port = readarrPort; - openFirewall = true; - dataDir = "/var/lib/readarr"; + extraGroups = [ "users" ]; }; - sonarr = { - enable = true; - user = sonarrUser; + "${sonarrGroup}" = { + isSystemUser = true; group = sonarrGroup; - settings.server.port = sonarrPort; - openFirewall = true; - dataDir = "/var/lib/sonarr"; + extraGroups = [ "users" ]; }; - lidarr = { - enable = true; - user = lidarrUser; + "${lidarrUser}" = { + isSystemUser = true; group = lidarrGroup; - settings.server.port = lidarrPort; - openFirewall = true; - dataDir = "/var/lib/lidarr"; + extraGroups = [ "users" ]; }; - prowlarr = { - enable = true; - settings.server.port = prowlarrPort; - openFirewall = true; + "${prowlarrGroup}" = { + isSystemUser = true; + group = prowlarrGroup; + extraGroups = [ "users" ]; }; }; + }; - nodes = { - ${homeWebProxy}.services.nginx = { - upstreams = { - transmission = { - servers = { - "${homeServiceAddress}:${builtins.toString servicePort}" = { }; - }; - }; - radarr = { - servers = { - "${homeServiceAddress}:${builtins.toString radarrPort}" = { }; - }; - }; - readarr = { - servers = { - "${homeServiceAddress}:${builtins.toString readarrPort}" = { }; - }; - }; - sonarr = { - servers = { - "${homeServiceAddress}:${builtins.toString sonarrPort}" = { }; - }; - }; - lidarr = { - servers = { - "${homeServiceAddress}:${builtins.toString lidarrPort}" = { }; - }; - }; - prowlarr = { - servers = { - "${homeServiceAddress}:${builtins.toString prowlarrPort}" = { }; - }; + virtualisation.docker.enable = true; + environment.systemPackages = with pkgs; [ + docker + ]; + + topology.self.services = { + radarr.info = "https://${serviceDomain}/radarr"; + readarr = { + name = "Readarr"; + info = "https://${serviceDomain}/readarr"; + icon = "${self}/files/topology-images/readarr.png"; + }; + sonarr.info = "https://${serviceDomain}/sonarr"; + lidarr.info = "https://${serviceDomain}/lidarr"; + prowlarr.info = "https://${serviceDomain}/prowlarr"; + }; + + globals.services.transmission = { + domain = serviceDomain; + inherit isHome; + }; + + environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [ + { directory = "/var/lib/radarr"; user = radarrUser; group = radarrGroup; } + { directory = "/var/lib/readarr"; user = readarrUser; group = readarrGroup; } + { directory = "/var/lib/sonarr"; user = sonarrUser; group = sonarrGroup; } + { directory = "/var/lib/lidarr"; user = lidarrUser; group = lidarrGroup; } + { directory = "/var/lib/private/prowlarr"; user = prowlarrUser; group = prowlarrGroup; } + ]; + }; + + services = { + pia = { + enable = true; + credentials.credentialsFile = config.sops.secrets.pia.path; + protocol = "wireguard"; + autoConnect = { + enable = true; + region = "sweden"; + }; + portForwarding.enable = true; + dns.enable = true; + }; + radarr = { + enable = true; + user = radarrUser; + group = radarrGroup; + settings.server.port = radarrPort; + openFirewall = true; + dataDir = "/var/lib/radarr"; + }; + readarr = { + enable = true; + user = readarrUser; + group = readarrGroup; + settings.server.port = readarrPort; + openFirewall = true; + dataDir = "/var/lib/readarr"; + }; + sonarr = { + enable = true; + user = sonarrUser; + group = sonarrGroup; + settings.server.port = sonarrPort; + openFirewall = true; + dataDir = "/var/lib/sonarr"; + }; + lidarr = { + enable = true; + user = lidarrUser; + group = lidarrGroup; + settings.server.port = lidarrPort; + openFirewall = true; + dataDir = "/var/lib/lidarr"; + }; + prowlarr = { + enable = true; + settings.server.port = prowlarrPort; + openFirewall = true; + }; + }; + + nodes = { + ${homeWebProxy}.services.nginx = { + upstreams = { + transmission = { + servers = { + "${homeServiceAddress}:${builtins.toString servicePort}" = { }; }; }; - virtualHosts = { - "${serviceDomain}" = { - enableACME = false; - forceSSL = false; - acmeRoot = null; - extraConfig = nginxAccessRules; - locations = { - "/" = { - proxyPass = "http://transmission"; - extraConfig = '' - client_max_body_size 0; - ''; - }; - "/radarr" = { - proxyPass = "http://radarr"; - extraConfig = '' - client_max_body_size 0; - ''; - }; - "/readarr" = { - proxyPass = "http://readarr"; - extraConfig = '' - client_max_body_size 0; - ''; - }; - "/sonarr" = { - proxyPass = "http://sonarr"; - extraConfig = '' - client_max_body_size 0; - ''; - }; - "/lidarr" = { - proxyPass = "http://lidarr"; - extraConfig = '' - client_max_body_size 0; - ''; - }; - "/prowlarr" = { - proxyPass = "http://prowlarr"; - extraConfig = '' - client_max_body_size 0; - ''; - }; + radarr = { + servers = { + "${homeServiceAddress}:${builtins.toString radarrPort}" = { }; + }; + }; + readarr = { + servers = { + "${homeServiceAddress}:${builtins.toString readarrPort}" = { }; + }; + }; + sonarr = { + servers = { + "${homeServiceAddress}:${builtins.toString sonarrPort}" = { }; + }; + }; + lidarr = { + servers = { + "${homeServiceAddress}:${builtins.toString lidarrPort}" = { }; + }; + }; + prowlarr = { + servers = { + "${homeServiceAddress}:${builtins.toString prowlarrPort}" = { }; + }; + }; + }; + virtualHosts = { + "${serviceDomain}" = { + enableACME = false; + forceSSL = false; + acmeRoot = null; + extraConfig = nginxAccessRules; + locations = { + "/" = { + proxyPass = "http://transmission"; + extraConfig = '' + client_max_body_size 0; + ''; + }; + "/radarr" = { + proxyPass = "http://radarr"; + extraConfig = '' + client_max_body_size 0; + ''; + }; + "/readarr" = { + proxyPass = "http://readarr"; + extraConfig = '' + client_max_body_size 0; + ''; + }; + "/sonarr" = { + proxyPass = "http://sonarr"; + extraConfig = '' + client_max_body_size 0; + ''; + }; + "/lidarr" = { + proxyPass = "http://lidarr"; + extraConfig = '' + client_max_body_size 0; + ''; + }; + "/prowlarr" = { + proxyPass = "http://prowlarr"; + extraConfig = '' + client_max_body_size 0; + ''; }; }; }; }; }; }; - } - + }; + } #+end_src **** syncthing @@ -14861,7 +14860,7 @@ This section exposes several metrics that I use to check the health of my server node-exporter = confLib.mkIds 987; grafana = confLib.mkIds 974; }; - groups.nextcloud-exporter = {}; + groups.nextcloud-exporter = { }; users = { nextcloud-exporter = { group = "nextcloud-exporter"; @@ -15269,7 +15268,7 @@ FreshRSS claims to support HTTP header auth, but at least it does not work with globals.services.${serviceName} = { domain = serviceDomain; inherit proxyAddress4 proxyAddress6 isHome serviceAddress; - homeServiceAddress = lib.mkIf isHome homeServiceAddress; + homeServiceAddress = lib.mkIf isHome homeServiceAddress; }; environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { @@ -15632,386 +15631,385 @@ kanidm person credential create-reset-token else "${keyPathBase}"; in - { - options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; - config = lib.mkIf config.swarselmodules.server.${serviceName} { + { + options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselmodules.server.${serviceName} { - users = { - persistentIds = { - kanidm = confLib.mkIds 984; - }; - users.${serviceUser} = { - group = serviceGroup; - isSystemUser = true; - }; - - groups.${serviceGroup} = { }; + users = { + persistentIds = { + kanidm = confLib.mkIds 984; + }; + users.${serviceUser} = { + group = serviceGroup; + isSystemUser = true; }; - sops = { - secrets = { - "kanidm-self-signed-crt" = { sopsFile = certsSopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; - "kanidm-self-signed-key" = { sopsFile = certsSopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; - "kanidm-admin-pw" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; - "kanidm-idm-admin-pw" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; - "kanidm-immich" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; - "kanidm-paperless" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; - "kanidm-forgejo" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; - "kanidm-grafana" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; - "kanidm-nextcloud" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; - "kanidm-freshrss" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; - "kanidm-oauth2-proxy" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + groups.${serviceGroup} = { }; + }; + + sops = { + secrets = { + "kanidm-self-signed-crt" = { sopsFile = certsSopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + "kanidm-self-signed-key" = { sopsFile = certsSopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + "kanidm-admin-pw" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + "kanidm-idm-admin-pw" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + "kanidm-immich" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + "kanidm-paperless" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + "kanidm-forgejo" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + "kanidm-grafana" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + "kanidm-nextcloud" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + "kanidm-freshrss" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + "kanidm-oauth2-proxy" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + }; + }; + + # networking.firewall.allowedTCPPorts = [ servicePort ]; + + globals = { + general.idmServer = config.node.name; + networks = { + ${webProxyIf}.hosts = lib.mkIf isProxied { + ${config.node.name}.firewallRuleForNode.${webProxy}.allowedTCPPorts = [ servicePort ]; + }; + ${homeProxyIf}.hosts = lib.mkIf isHome { + ${config.node.name}.firewallRuleForNode.${homeWebProxy}.allowedTCPPorts = [ servicePort ]; }; }; + services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6 isHome serviceAddress; + homeServiceAddress = lib.mkIf isHome homeServiceAddress; + }; + }; - # networking.firewall.allowedTCPPorts = [ servicePort ]; + environment.persistence = { + "/persist" = lib.mkIf config.swarselsystems.isImpermanence { + files = [ + certPathBase + keyPathBase + ]; + }; - globals = { - general.idmServer = config.node.name; - networks = { - ${webProxyIf}.hosts = lib.mkIf isProxied { - ${config.node.name}.firewallRuleForNode.${webProxy}.allowedTCPPorts = [ servicePort ]; + "/state" = lib.mkIf config.swarselsystems.isMicroVM { + directories = [{ directory = "/var/lib/${serviceName}"; user = serviceUser; group = serviceGroup; }]; + }; + }; + + systemd.services = { + "generateSSLCert-${serviceName}" = + let + daysValid = 3650; + renewBeforeDays = 365; + in + { + before = [ "${serviceName}.service" ]; + requiredBy = [ "${serviceName}.service" ]; + after = [ "local-fs.target" ]; + requires = [ "local-fs.target" ]; + + serviceConfig = { + Type = "oneshot"; }; - ${homeProxyIf}.hosts = lib.mkIf isHome { - ${config.node.name}.firewallRuleForNode.${homeWebProxy}.allowedTCPPorts = [ servicePort ]; - }; - }; - services.${serviceName} = { - domain = serviceDomain; - inherit proxyAddress4 proxyAddress6 isHome serviceAddress; - homeServiceAddress = lib.mkIf isHome homeServiceAddress; - }; - }; - environment.persistence = { - "/persist" = lib.mkIf config.swarselsystems.isImpermanence { - files = [ - certPathBase - keyPathBase - ]; - }; + script = '' + set -eu - "/state" = lib.mkIf config.swarselsystems.isMicroVM { - directories = [{ directory = "/var/lib/${serviceName}"; user = serviceUser; group = serviceGroup; }]; - }; - }; + ${pkgs.coreutils}/bin/install -d -m 0755 ${certsDir} + ${if config.swarselsystems.isImpermanence then "${pkgs.coreutils}/bin/install -d -m 0755 /persist${certsDir}" else ""} + ${pkgs.coreutils}/bin/install -d -m 0750 ${privateDir} + ${if config.swarselsystems.isImpermanence then "${pkgs.coreutils}/bin/install -d -m 0750 /persist${privateDir}" else ""} - systemd.services = { - "generateSSLCert-${serviceName}" = - let - daysValid = 3650; - renewBeforeDays = 365; - in - { - before = [ "${serviceName}.service" ]; - requiredBy = [ "${serviceName}.service" ]; - after = [ "local-fs.target" ]; - requires = [ "local-fs.target" ]; - - serviceConfig = { - Type = "oneshot"; - }; - - script = '' - set -eu - - ${pkgs.coreutils}/bin/install -d -m 0755 ${certsDir} - ${if config.swarselsystems.isImpermanence then "${pkgs.coreutils}/bin/install -d -m 0755 /persist${certsDir}" else ""} - ${pkgs.coreutils}/bin/install -d -m 0750 ${privateDir} - ${if config.swarselsystems.isImpermanence then "${pkgs.coreutils}/bin/install -d -m 0750 /persist${privateDir}" else ""} - - need_gen=0 - if [ ! -f "${certPath}" ] || [ ! -f "${keyPath}" ]; then - need_gen=1 - else - enddate="$(${pkgs.openssl}/bin/openssl x509 -noout -enddate -in "${certPath}" | cut -d= -f2)" - end_epoch="$(${pkgs.coreutils}/bin/date -d "$enddate" +%s)" - now_epoch="$(${pkgs.coreutils}/bin/date +%s)" - seconds_left=$(( end_epoch - now_epoch )) - days_left=$(( seconds_left / 86400 )) - if [ "$days_left" -lt ${toString renewBeforeDays} ]; then + need_gen=0 + if [ ! -f "${certPath}" ] || [ ! -f "${keyPath}" ]; then need_gen=1 else - echo 'Certificate exists and is still valid' + enddate="$(${pkgs.openssl}/bin/openssl x509 -noout -enddate -in "${certPath}" | cut -d= -f2)" + end_epoch="$(${pkgs.coreutils}/bin/date -d "$enddate" +%s)" + now_epoch="$(${pkgs.coreutils}/bin/date +%s)" + seconds_left=$(( end_epoch - now_epoch )) + days_left=$(( seconds_left / 86400 )) + if [ "$days_left" -lt ${toString renewBeforeDays} ]; then + need_gen=1 + else + echo 'Certificate exists and is still valid' + fi fi - fi - if [ "$need_gen" -eq 1 ]; then - ${pkgs.openssl}/bin/openssl req -x509 -nodes -days ${toString daysValid} -newkey rsa:4096 -sha256 \ - -keyout "${keyPath}" \ - -out "${certPath}" \ - -subj "/CN=${serviceDomain}" \ - -addext "subjectAltName=DNS:${serviceDomain}" + if [ "$need_gen" -eq 1 ]; then + ${pkgs.openssl}/bin/openssl req -x509 -nodes -days ${toString daysValid} -newkey rsa:4096 -sha256 \ + -keyout "${keyPath}" \ + -out "${certPath}" \ + -subj "/CN=${serviceDomain}" \ + -addext "subjectAltName=DNS:${serviceDomain}" - chmod 0644 "${certPath}" - chmod 0600 "${keyPath}" - chown ${serviceUser}:${serviceGroup} "${certPath}" "${keyPath}" - fi - ''; - }; - kanidm = { - environment.KANIDM_TRUST_X_FORWARD_FOR = "true"; - serviceConfig.RestartSec = "30"; + chmod 0644 "${certPath}" + chmod 0600 "${keyPath}" + chown ${serviceUser}:${serviceGroup} "${certPath}" "${keyPath}" + fi + ''; }; + kanidm = { + environment.KANIDM_TRUST_X_FORWARD_FOR = "true"; + serviceConfig.RestartSec = "30"; }; + }; - # system.activationScripts."createPersistentStorageDirs" = lib.mkIf config.swarselsystems.isImpermanence { - # deps = [ "generateSSLCert-${serviceName}" "users" "groups" ]; - # }; - # system.activationScripts."generateSSLCert-${serviceName}" = - # let - # daysValid = 3650; - # renewBeforeDays = 365; - # in - # { - # text = '' - # set -eu + # system.activationScripts."createPersistentStorageDirs" = lib.mkIf config.swarselsystems.isImpermanence { + # deps = [ "generateSSLCert-${serviceName}" "users" "groups" ]; + # }; + # system.activationScripts."generateSSLCert-${serviceName}" = + # let + # daysValid = 3650; + # renewBeforeDays = 365; + # in + # { + # text = '' + # set -eu - # ${pkgs.coreutils}/bin/install -d -m 0755 ${certsDir} - # ${if config.swarselsystems.isImpermanence then "${pkgs.coreutils}/bin/install -d -m 0755 /persist${certsDir}" else ""} - # ${pkgs.coreutils}/bin/install -d -m 0750 ${privateDir} - # ${if config.swarselsystems.isImpermanence then "${pkgs.coreutils}/bin/install -d -m 0750 /persist${privateDir}" else ""} + # ${pkgs.coreutils}/bin/install -d -m 0755 ${certsDir} + # ${if config.swarselsystems.isImpermanence then "${pkgs.coreutils}/bin/install -d -m 0755 /persist${certsDir}" else ""} + # ${pkgs.coreutils}/bin/install -d -m 0750 ${privateDir} + # ${if config.swarselsystems.isImpermanence then "${pkgs.coreutils}/bin/install -d -m 0750 /persist${privateDir}" else ""} - # need_gen=0 - # if [ ! -f "${certPathBase}" ] || [ ! -f "${keyPathBase}" ]; then - # need_gen=1 - # else - # enddate="$(${pkgs.openssl}/bin/openssl x509 -noout -enddate -in "${certPathBase}" | cut -d= -f2)" - # end_epoch="$(${pkgs.coreutils}/bin/date -d "$enddate" +%s)" - # now_epoch="$(${pkgs.coreutils}/bin/date +%s)" - # seconds_left=$(( end_epoch - now_epoch )) - # days_left=$(( seconds_left / 86400 )) - # if [ "$days_left" -lt ${toString renewBeforeDays} ]; then - # need_gen=1 - # fi - # fi + # need_gen=0 + # if [ ! -f "${certPathBase}" ] || [ ! -f "${keyPathBase}" ]; then + # need_gen=1 + # else + # enddate="$(${pkgs.openssl}/bin/openssl x509 -noout -enddate -in "${certPathBase}" | cut -d= -f2)" + # end_epoch="$(${pkgs.coreutils}/bin/date -d "$enddate" +%s)" + # now_epoch="$(${pkgs.coreutils}/bin/date +%s)" + # seconds_left=$(( end_epoch - now_epoch )) + # days_left=$(( seconds_left / 86400 )) + # if [ "$days_left" -lt ${toString renewBeforeDays} ]; then + # need_gen=1 + # fi + # fi - # if [ "$need_gen" -eq 1 ]; then - # ${pkgs.openssl}/bin/openssl req -x509 -nodes -days ${toString daysValid} -newkey rsa:4096 -sha256 \ - # -keyout "${keyPath}" \ - # -out "${certPath}" \ - # -subj "/CN=${serviceDomain}" \ - # -addext "subjectAltName=DNS:${serviceDomain}" + # if [ "$need_gen" -eq 1 ]; then + # ${pkgs.openssl}/bin/openssl req -x509 -nodes -days ${toString daysValid} -newkey rsa:4096 -sha256 \ + # -keyout "${keyPath}" \ + # -out "${certPath}" \ + # -subj "/CN=${serviceDomain}" \ + # -addext "subjectAltName=DNS:${serviceDomain}" - # chmod 0644 "${certPath}" - # chmod 0600 "${keyPath}" - # chown ${serviceUser}:${serviceGroup} "${certPath}" "${keyPath}" - # fi - # ''; - # deps = [ - # "etc" - # (lib.mkIf config.swarselsystems.isImpermanence "specialfs") - # ]; - # }; + # chmod 0644 "${certPath}" + # chmod 0600 "${keyPath}" + # chown ${serviceUser}:${serviceGroup} "${certPath}" "${keyPath}" + # fi + # ''; + # deps = [ + # "etc" + # (lib.mkIf config.swarselsystems.isImpermanence "specialfs") + # ]; + # }; - services = { - ${serviceName} = { - package = pkgs.kanidmWithSecretProvisioning_1_9; - server = { - enable = true; - settings = { - domain = serviceDomain; - origin = "https://${serviceDomain}"; - # tls_chain = config.sops.secrets.kanidm-self-signed-crt.path; - tls_chain = certPathBase; - # tls_key = config.sops.secrets.kanidm-self-signed-key.path; - tls_key = keyPathBase; - bindaddress = "0.0.0.0:${toString servicePort}"; - # trust_x_forward_for = true; - }; + services = { + ${serviceName} = { + package = pkgs.kanidmWithSecretProvisioning_1_9; + server = { + enable = true; + settings = { + domain = serviceDomain; + origin = "https://${serviceDomain}"; + # tls_chain = config.sops.secrets.kanidm-self-signed-crt.path; + tls_chain = certPathBase; + # tls_key = config.sops.secrets.kanidm-self-signed-key.path; + tls_key = keyPathBase; + bindaddress = "0.0.0.0:${toString servicePort}"; + # trust_x_forward_for = true; }; - client = { - enable = true; - settings = { - uri = config.services.kanidm.server.settings.origin; - verify_ca = true; - verify_hostnames = true; - }; + }; + client = { + enable = true; + settings = { + uri = config.services.kanidm.server.settings.origin; + verify_ca = true; + verify_hostnames = true; + }; + }; + provision = { + enable = true; + adminPasswordFile = config.sops.secrets.kanidm-admin-pw.path; + idmAdminPasswordFile = config.sops.secrets.kanidm-idm-admin-pw.path; + groups = { + "immich.access" = { }; + "paperless.access" = { }; + "forgejo.access" = { }; + "forgejo.admins" = { }; + "grafana.access" = { }; + "grafana.editors" = { }; + "grafana.admins" = { }; + "grafana.server-admins" = { }; + "nextcloud.access" = { }; + "nextcloud.admins" = { }; + "navidrome.access" = { }; + "freshrss.access" = { }; + "firefly.access" = { }; + "radicale.access" = { }; + "slink.access" = { }; + "opkssh.access" = { }; + "adguardhome.access" = { }; }; - provision = { - enable = true; - adminPasswordFile = config.sops.secrets.kanidm-admin-pw.path; - idmAdminPasswordFile = config.sops.secrets.kanidm-idm-admin-pw.path; - groups = { - "immich.access" = { }; - "paperless.access" = { }; - "forgejo.access" = { }; - "forgejo.admins" = { }; - "grafana.access" = { }; - "grafana.editors" = { }; - "grafana.admins" = { }; - "grafana.server-admins" = { }; - "nextcloud.access" = { }; - "nextcloud.admins" = { }; - "navidrome.access" = { }; - "freshrss.access" = { }; - "firefly.access" = { }; - "radicale.access" = { }; - "slink.access" = { }; - "opkssh.access" = { }; - "adguardhome.access" = { }; - }; - inherit (config.repo.secrets.local) persons; + inherit (config.repo.secrets.local) persons; - systems = { - oauth2 = { - immich = { - displayName = "Immich"; - originUrl = [ - "https://${immichDomain}/auth/login" - "https://${immichDomain}/user-settings" - "app.immich:///oauth-callback" - "https://${immichDomain}/api/oauth/mobile-redirect" - ]; - originLanding = "https://${immichDomain}/"; - basicSecretFile = config.sops.secrets.kanidm-immich.path; - preferShortUsername = true; - enableLegacyCrypto = true; # can use RS256 / HS256, not ES256 - scopeMaps."immich.access" = [ - "openid" - "email" - "profile" - ]; + systems = { + oauth2 = { + immich = { + displayName = "Immich"; + originUrl = [ + "https://${immichDomain}/auth/login" + "https://${immichDomain}/user-settings" + "app.immich:///oauth-callback" + "https://${immichDomain}/api/oauth/mobile-redirect" + ]; + originLanding = "https://${immichDomain}/"; + basicSecretFile = config.sops.secrets.kanidm-immich.path; + preferShortUsername = true; + enableLegacyCrypto = true; # can use RS256 / HS256, not ES256 + scopeMaps."immich.access" = [ + "openid" + "email" + "profile" + ]; + }; + paperless = { + displayName = "Paperless"; + originUrl = "https://${paperlessDomain}/accounts/oidc/kanidm/login/callback/"; + originLanding = "https://${paperlessDomain}/"; + basicSecretFile = config.sops.secrets.kanidm-paperless.path; + preferShortUsername = true; + scopeMaps."paperless.access" = [ + "openid" + "email" + "profile" + ]; + }; + forgejo = { + displayName = "Forgejo"; + originUrl = "https://${forgejoDomain}/user/oauth2/kanidm/callback"; + originLanding = "https://${forgejoDomain}/"; + basicSecretFile = config.sops.secrets.kanidm-forgejo.path; + scopeMaps."forgejo.access" = [ + "openid" + "email" + "profile" + ]; + # XXX: PKCE is currently not supported by gitea/forgejo, + # see https://github.com/go-gitea/gitea/issues/21376. + allowInsecureClientDisablePkce = true; + preferShortUsername = true; + claimMaps.groups = { + joinType = "array"; + valuesByGroup."forgejo.admins" = [ "admin" ]; }; - paperless = { - displayName = "Paperless"; - originUrl = "https://${paperlessDomain}/accounts/oidc/kanidm/login/callback/"; - originLanding = "https://${paperlessDomain}/"; - basicSecretFile = config.sops.secrets.kanidm-paperless.path; - preferShortUsername = true; - scopeMaps."paperless.access" = [ - "openid" - "email" - "profile" - ]; - }; - forgejo = { - displayName = "Forgejo"; - originUrl = "https://${forgejoDomain}/user/oauth2/kanidm/callback"; - originLanding = "https://${forgejoDomain}/"; - basicSecretFile = config.sops.secrets.kanidm-forgejo.path; - scopeMaps."forgejo.access" = [ - "openid" - "email" - "profile" - ]; - # XXX: PKCE is currently not supported by gitea/forgejo, - # see https://github.com/go-gitea/gitea/issues/21376. - allowInsecureClientDisablePkce = true; - preferShortUsername = true; - claimMaps.groups = { - joinType = "array"; - valuesByGroup."forgejo.admins" = [ "admin" ]; + }; + grafana = { + displayName = "Grafana"; + originUrl = "https://${grafanaDomain}/login/generic_oauth"; + originLanding = "https://${grafanaDomain}/"; + basicSecretFile = config.sops.secrets.kanidm-grafana.path; + preferShortUsername = true; + scopeMaps."grafana.access" = [ + "openid" + "email" + "profile" + ]; + claimMaps.groups = { + joinType = "array"; + valuesByGroup = { + "grafana.editors" = [ "editor" ]; + "grafana.admins" = [ "admin" ]; + "grafana.server-admins" = [ "server_admin" ]; }; }; - grafana = { - displayName = "Grafana"; - originUrl = "https://${grafanaDomain}/login/generic_oauth"; - originLanding = "https://${grafanaDomain}/"; - basicSecretFile = config.sops.secrets.kanidm-grafana.path; - preferShortUsername = true; - scopeMaps."grafana.access" = [ + }; + nextcloud = { + displayName = "Nextcloud"; + originUrl = " https://${nextcloudDomain}/apps/sociallogin/custom_oidc/kanidm"; + originLanding = "https://${nextcloudDomain}/"; + basicSecretFile = config.sops.secrets.kanidm-nextcloud.path; + allowInsecureClientDisablePkce = true; + scopeMaps."nextcloud.access" = [ + "openid" + "email" + "profile" + ]; + preferShortUsername = true; + claimMaps.groups = { + joinType = "array"; + valuesByGroup = { + "nextcloud.admins" = [ "admin" ]; + }; + }; + }; + opkssh = { + displayName = "OPKSSH"; + originUrl = [ + "http://localhost:3000" + "http://localhost:3000/login-callback" + "http://localhost:10001/login-callback" + "http://localhost:11110/login-callback" + ]; + originLanding = "http://localhost:3000"; + public = true; + enableLocalhostRedirects = true; + scopeMaps."opkssh.access" = [ + "openid" + "email" + "profile" + ]; + }; + oauth2-proxy = { + displayName = "Oauth2-Proxy"; + originUrl = "https://${oauth2ProxyDomain}/oauth2/callback"; + originLanding = "https://${oauth2ProxyDomain}/"; + basicSecretFile = config.sops.secrets.kanidm-oauth2-proxy.path; + scopeMaps = { + "freshrss.access" = [ "openid" "email" "profile" ]; - claimMaps.groups = { - joinType = "array"; - valuesByGroup = { - "grafana.editors" = [ "editor" ]; - "grafana.admins" = [ "admin" ]; - "grafana.server-admins" = [ "server_admin" ]; - }; - }; - }; - nextcloud = { - displayName = "Nextcloud"; - originUrl = " https://${nextcloudDomain}/apps/sociallogin/custom_oidc/kanidm"; - originLanding = "https://${nextcloudDomain}/"; - basicSecretFile = config.sops.secrets.kanidm-nextcloud.path; - allowInsecureClientDisablePkce = true; - scopeMaps."nextcloud.access" = [ + "navidrome.access" = [ "openid" "email" "profile" ]; - preferShortUsername = true; - claimMaps.groups = { - joinType = "array"; - valuesByGroup = { - "nextcloud.admins" = [ "admin" ]; - }; - }; - }; - opkssh = { - displayName = "OPKSSH"; - originUrl = [ - "http://localhost:3000" - "http://localhost:3000/login-callback" - "http://localhost:10001/login-callback" - "http://localhost:11110/login-callback" + "firefly.access" = [ + "openid" + "email" + "profile" ]; - originLanding = "http://localhost:3000"; - public = true; - enableLocalhostRedirects = true; - scopeMaps."opkssh.access" = [ + "radicale.access" = [ + "openid" + "email" + "profile" + ]; + "slink.access" = [ + "openid" + "email" + "profile" + ]; + "adguardhome.access" = [ "openid" "email" "profile" ]; }; - oauth2-proxy = { - displayName = "Oauth2-Proxy"; - originUrl = "https://${oauth2ProxyDomain}/oauth2/callback"; - originLanding = "https://${oauth2ProxyDomain}/"; - basicSecretFile = config.sops.secrets.kanidm-oauth2-proxy.path; - scopeMaps = { - "freshrss.access" = [ - "openid" - "email" - "profile" - ]; - "navidrome.access" = [ - "openid" - "email" - "profile" - ]; - "firefly.access" = [ - "openid" - "email" - "profile" - ]; - "radicale.access" = [ - "openid" - "email" - "profile" - ]; - "slink.access" = [ - "openid" - "email" - "profile" - ]; - "adguardhome.access" = [ - "openid" - "email" - "profile" - ]; - }; - preferShortUsername = true; - claimMaps.groups = { - joinType = "array"; - valuesByGroup = { - "freshrss.access" = [ "ttrss_access" ]; - "navidrome.access" = [ "navidrome_access" ]; - "firefly.access" = [ "firefly_access" ]; - "radicale.access" = [ "radicale_access" ]; - "slink.access" = [ "slink_access" ]; - "adguardhome.access" = [ "adguardhome_access" ]; - }; + preferShortUsername = true; + claimMaps.groups = { + joinType = "array"; + valuesByGroup = { + "freshrss.access" = [ "ttrss_access" ]; + "navidrome.access" = [ "navidrome_access" ]; + "firefly.access" = [ "firefly_access" ]; + "radicale.access" = [ "radicale_access" ]; + "slink.access" = [ "slink_access" ]; + "adguardhome.access" = [ "adguardhome_access" ]; }; }; }; @@ -16019,14 +16017,17 @@ kanidm person credential create-reset-token }; }; }; + }; - nodes = let + nodes = + let extraConfig = '' - allow ${globals.networks.home-lan.vlans.services.cidrv4}; - allow ${globals.networks.home-lan.vlans.services.cidrv6}; + allow ${globals.networks.home-lan.vlans.services.cidrv4}; + allow ${globals.networks.home-lan.vlans.services.cidrv6}; ''; - in { + in + { ${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; }; @@ -16034,8 +16035,8 @@ kanidm person credential create-reset-token ${homeWebProxy}.services.nginx = confLib.genNginx { inherit servicePort serviceDomain serviceName; protocol = "https"; noSslVerify = true; extraConfig = extraConfig + nginxAccessRules; serviceAddress = homeServiceAddress; }; }; - }; - } + }; + } #+end_src **** oauth2-proxy @@ -16214,7 +16215,7 @@ This can be used to add OIDC in a way to services that do not support it nativel services = { ${serviceName} = { enable = true; - package = pkgs.update.oauth2-proxy; + package = pkgs.oauth2-proxy; cookie = { domain = ".${mainDomain}"; secure = true; @@ -16277,7 +16278,7 @@ This can be used to add OIDC in a way to services that do not support it nativel ${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; }; - ${webProxy}.services.nginx = confLib.genNginx { inherit servicePort serviceAddress serviceDomain serviceName extraConfig; }; + ${webProxy}.services.nginx = confLib.genNginx { inherit servicePort serviceAddress serviceDomain serviceName extraConfig; }; ${homeWebProxy}.services.nginx = confLib.genNginx { inherit servicePort serviceDomain serviceName; extraConfig = extraConfig + nginxAccessRules; serviceAddress = globals.hosts.${oauthServer}.wanAddress4; }; }; }; @@ -16333,7 +16334,7 @@ My expenses tracker. globals.services.${serviceName} = { domain = serviceDomain; inherit proxyAddress4 proxyAddress6 isHome serviceAddress; - homeServiceAddress = lib.mkIf isHome homeServiceAddress; + homeServiceAddress = lib.mkIf isHome homeServiceAddress; }; environment.persistence."/state" = lib.mkIf config.swarselsystems.isMicroVM { @@ -16462,10 +16463,10 @@ My collection tracker. I am not too happy with its GUI, but the API is good, and }; topology.nodes.${topologyContainerName}.services.${serviceName} = { - name = lib.swarselsystems.toCapitalized serviceName; - info = "https://${serviceDomain}"; - icon = "${self}/files/topology-images/${serviceName}.png"; - }; + name = lib.swarselsystems.toCapitalized serviceName; + info = "https://${serviceDomain}"; + icon = "${self}/files/topology-images/${serviceName}.png"; + }; globals = { networks = { @@ -16479,7 +16480,7 @@ My collection tracker. I am not too happy with its GUI, but the API is good, and services.${serviceName} = { domain = serviceDomain; inherit proxyAddress4 proxyAddress6 isHome serviceAddress; - homeServiceAddress = lib.mkIf isHome homeServiceAddress; + homeServiceAddress = lib.mkIf isHome homeServiceAddress; }; }; @@ -16595,51 +16596,51 @@ Used to sync shell history accross machines and have it backed up somewhere. inherit (confLib.gen { name = "atuin"; port = 8888; }) servicePort serviceName serviceDomain serviceAddress proxyAddress4 proxyAddress6; inherit (confLib.static) isHome isProxied webProxy homeWebProxy dnsServer homeProxyIf webProxyIf homeServiceAddress nginxAccessRules; in - { - options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; - config = lib.mkIf config.swarselmodules.server.${serviceName} { - - swarselmodules.server = { - postgresql = true; - }; - - topology.self.services.${serviceName}.info = "https://${serviceDomain}"; - - globals = { - networks = { - ${webProxyIf}.hosts = lib.mkIf isProxied { - ${config.node.name}.firewallRuleForNode.${webProxy}.allowedTCPPorts = [ servicePort ]; - }; - ${homeProxyIf}.hosts = lib.mkIf isHome { - ${config.node.name}.firewallRuleForNode.${homeWebProxy}.allowedTCPPorts = [ servicePort ]; - }; - }; - services.${serviceName} = { - domain = serviceDomain; - inherit proxyAddress4 proxyAddress6 isHome serviceAddress; - homeServiceAddress = lib.mkIf isHome homeServiceAddress; - }; - }; - - services.${serviceName} = { - enable = true; - host = "0.0.0.0"; - port = servicePort; - # openFirewall = true; - openRegistration = false; - }; - - nodes = { - ${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { - "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; - }; - ${webProxy}.services.nginx = confLib.genNginx { inherit serviceAddress servicePort serviceDomain serviceName; maxBody = 0; }; - ${homeWebProxy}.services.nginx = lib.mkIf isHome (confLib.genNginx { inherit servicePort serviceDomain serviceName; maxBody = 0; extraConfig = nginxAccessRules; serviceAddress = homeServiceAddress; }); - }; + { + options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselmodules.server.${serviceName} { + swarselmodules.server = { + postgresql = true; }; - } + topology.self.services.${serviceName}.info = "https://${serviceDomain}"; + + globals = { + networks = { + ${webProxyIf}.hosts = lib.mkIf isProxied { + ${config.node.name}.firewallRuleForNode.${webProxy}.allowedTCPPorts = [ servicePort ]; + }; + ${homeProxyIf}.hosts = lib.mkIf isHome { + ${config.node.name}.firewallRuleForNode.${homeWebProxy}.allowedTCPPorts = [ servicePort ]; + }; + }; + services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6 isHome serviceAddress; + homeServiceAddress = lib.mkIf isHome homeServiceAddress; + }; + }; + + services.${serviceName} = { + enable = true; + host = "0.0.0.0"; + port = servicePort; + # openFirewall = true; + openRegistration = false; + }; + + nodes = { + ${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + ${webProxy}.services.nginx = confLib.genNginx { inherit serviceAddress servicePort serviceDomain serviceName; maxBody = 0; }; + ${homeWebProxy}.services.nginx = lib.mkIf isHome (confLib.genNginx { inherit servicePort serviceDomain serviceName; maxBody = 0; extraConfig = nginxAccessRules; serviceAddress = homeServiceAddress; }); + }; + + }; + + } #+end_src **** Radicale @@ -17034,10 +17035,10 @@ Self-hosted link shortener. }; topology.nodes.${topologyContainerName}.services.${serviceName} = { - name = lib.swarselsystems.toCapitalized serviceName; - info = "https://${serviceDomain}"; - icon = "${self}/files/topology-images/${serviceName}.png"; - }; + name = lib.swarselsystems.toCapitalized serviceName; + info = "https://${serviceDomain}"; + icon = "${self}/files/topology-images/${serviceName}.png"; + }; virtualisation.oci-containers.containers.${serviceName} = { image = "shlinkio/shlink@${containerRev}"; @@ -17144,10 +17145,10 @@ Deployment notes: }; topology.nodes.${topologyContainerName}.services.${serviceName} = { - name = lib.swarselsystems.toCapitalized serviceName; - info = "https://${serviceDomain}"; - icon = "services.not-available"; - }; + name = lib.swarselsystems.toCapitalized serviceName; + info = "https://${serviceDomain}"; + icon = "services.not-available"; + }; virtualisation.oci-containers.containers.${serviceName} = { image = "anirdev/slink@${containerRev}"; @@ -17200,7 +17201,7 @@ Deployment notes: services.${serviceName} = { domain = serviceDomain; inherit proxyAddress4 proxyAddress6 isHome serviceAddress; - homeServiceAddress = lib.mkIf isHome homeServiceAddress; + homeServiceAddress = lib.mkIf isHome homeServiceAddress; }; }; @@ -19408,7 +19409,7 @@ Handles my home DNS server. It also provides some nice blocklists, but the main ]; dhcp.enabled = false; }; - filtering.rewrites = (map + filtering.rewrites = (map (domain: { inherit domain; # FIXME: change to homeWebProxy once that is setup @@ -19417,12 +19418,12 @@ Handles my home DNS server. It also provides some nice blocklists, but the main enabled = true; }) homeDomains) ++ [ - { - domain = "smb.${globals.domains.main}"; - answer = globals.networks.home-lan.vlans.services.hosts.summers-storage.ipv4; - enabled = true; - } - ]; + { + domain = "smb.${globals.domains.main}"; + answer = globals.networks.home-lan.vlans.services.hosts.summers-storage.ipv4; + enabled = true; + } + ]; filters = [ { name = "AdGuard DNS filter"; @@ -19870,10 +19871,10 @@ This holds configuration that is specific to framework laptops. }; systemd.services."systemd-suspend-then-hibernate".aliases = [ "systemd-suspend.service" ]; powerManagement.enable = true; - systemd.sleep.extraConfig = '' - HibernateDelaySec=120m - SuspendState=freeze - ''; + systemd.sleep.settings.Sleep = { + HibernateDelaySec = "120m"; + SuspendState = "freeze"; + }; }; } #+end_src @@ -20268,7 +20269,7 @@ Some standard options that should be set for every microvm guest. We set the def Some standard options that should be set for every microvm guest. We set the default #+begin_src nix-ts :tangle modules/nixos/optional/microvm-guest-shares.nix - { self, lib, config, inputs, microVMParent, nodes, ... }: + { lib, config, microVMParent, nodes, ... }: { config = { microvm = { @@ -20283,7 +20284,6 @@ Some standard options that should be set for every microvm guest. We set the def }; }; } - #+end_src **** systemd-networkd (base) @@ -20590,7 +20590,7 @@ Hold standard options for nix-topology per config The general structure here is the same as in the [[#h:6da812f5-358c-49cb-aff2-0a94f20d70b3][NixOS]] section. #+begin_src nix-ts :tangle modules/home/default.nix - # @ future me: dont panic, this file is not read in by readNix + # @ future me: dont panic, this file is not read in by readNix { lib, ... }: let importNames = lib.swarselsystems.readNix "modules/home"; @@ -20598,7 +20598,6 @@ The general structure here is the same as in the [[#h:6da812f5-358c-49cb-aff2-0a { imports = lib.swarselsystems.mkImports importNames "modules/home"; } - #+end_src *** Steps to setup/upgrade home-manager only @@ -21032,13 +21031,12 @@ This holds packages that I can use as provided, or with small modifications (as }) # font stuff - nerd-fonts.fira-mono + cantarell-fonts nerd-fonts.fira-code + (iosevka-bin.override { variant = "Aile"; }) nerd-fonts.symbols-only noto-fonts-color-emoji font-awesome_5 - noto-fonts - noto-fonts-cjk-sans ]; }; } @@ -21561,32 +21559,68 @@ This section is for programs that require no further configuration. zsh Integrat nix-index provides a way to find out which packages are provided by which derivations. By default it also comes with a replacement for =command-not-found.sh=, however, the implementation is based on a channel based setup. I like consistency, so I replace the command with one that provides a flakes-based output. This also uses the =nix-index-with-full-db= from the nix-index-database input thanks to its overlay. #+begin_src nix-ts :tangle modules/home/common/nix-index.nix - { self, lib, config, pkgs, ... }: - { - options.swarselmodules.nix-index = lib.mkEnableOption "nix-index settings"; - config = lib.mkIf config.swarselmodules.nix-index { - programs.nix-index = - let - commandNotFound = pkgs.runCommandLocal "command-not-found.sh" { } '' - mkdir -p $out/etc/profile.d - substitute ${self + /files/scripts/command-not-found.sh} \ - $out/etc/profile.d/command-not-found.sh \ - --replace-fail @nix-locate@ ${pkgs.nix-index}/bin/nix-locate \ - --replace-fail @tput@ ${pkgs.ncurses}/bin/tput - ''; - in +{ lib, config, pkgs, ... }: +{ + options.swarselmodules.nix-index = lib.mkEnableOption "nix-index settings"; + config = lib.mkIf config.swarselmodules.nix-index { + programs.nix-index = + let + commandNotFound = pkgs.runCommandLocal "command-not-found.sh" { } '' + mkdir -p $out/etc/profile.d + cat > $out/etc/profile.d/command-not-found.sh <<'EOF' + # Adapted from https://github.com/bennofs/nix-index/blob/master/command-not-found.sh + command_not_found_handle() { + if [ -n "''${MC_SID-}" ] || ! [ -t 1 ]; then + >&2 echo "$1: command not found" + return 127 + fi - { + echo -n "searching nix-index..." + ATTRS=$(@nix-locate@ --minimal --no-group --type x --type s --whole-name --at-root "/bin/$1") - enable = true; - package = pkgs.symlinkJoin { - name = "nix-index"; - paths = [ commandNotFound ]; - }; + case $(echo -n "$ATTRS" | grep -c "^") in + 0) + >&2 echo -ne "$(@tput@ el1)\r" + >&2 echo "$1: command not found" + ;; + *) + >&2 echo -ne "$(@tput@ el1)\r" + >&2 echo "The program ‘$(@tput@ setaf 4)$1$(@tput@ sgr0)’ is currently not installed." + >&2 echo "It is provided by the following derivation(s):" + while read -r ATTR; do + ATTR=''${ATTR%.out} + >&2 echo " $(@tput@ setaf 12)nixpkgs#$(@tput@ setaf 4)$ATTR$(@tput@ sgr0)" + done <<< "$ATTRS" + ;; + esac + + return 127 + } + + command_not_found_handler() { + command_not_found_handle "$@" + return $? + } + EOF + + substitute $out/etc/profile.d/command-not-found.sh \ + $out/etc/profile.d/command-not-found.sh \ + --replace-fail @nix-locate@ ${pkgs.nix-index}/bin/nix-locate \ + --replace-fail @tput@ ${pkgs.ncurses}/bin/tput + ''; + in + + { + + enable = true; + package = pkgs.symlinkJoin { + name = "nix-index"; + paths = [ commandNotFound ]; }; - programs.nix-index-database.comma.enable = true; - }; - } + }; + programs.nix-index-database.comma.enable = true; + }; +} #+end_src **** nix-your-shell @@ -25503,7 +25537,7 @@ Currently, I am too lazy to explain every option here, but most of it is very se "s=AU11806002320" "v=Philips Consumer Electronics Company" ]; - exec = ["notify-send shikane \"Profile $SHIKANE_PROFILE_NAME has been applied\""]; + exec = [ "notify-send shikane \"Profile $SHIKANE_PROFILE_NAME has been applied\"" ]; in { profile = [ @@ -25586,61 +25620,64 @@ When setting up a new machine: #+end_src #+begin_src nix-ts :tangle modules/home/common/gpg-agent.nix - { self, lib, config, pkgs, ... }: - let - inherit (config.swarselsystems) mainUser homeDir; - in - { - options.swarselmodules.gpgagent = lib.mkEnableOption "gpg agent settings"; - config = lib.mkIf config.swarselmodules.gpgagent { - services.gpg-agent = { - enable = true; - verbose = true; - enableZshIntegration = true; - enableScDaemon = true; - enableSshSupport = true; - enableExtraSocket = true; - pinentry.package = pkgs.wayprompt; - pinentry.program = "pinentry-wayprompt"; - # pinentry.package = pkgs.pinentry.gtk2; - defaultCacheTtl = 600; - maxCacheTtl = 7200; - extraConfig = '' - allow-loopback-pinentry - allow-emacs-pinentry - ''; - sshKeys = [ - "4BE7925262289B476DBBC17B76FD3810215AE097" - ]; - }; + { self, lib, config, pkgs, ... }: + let + inherit (config.swarselsystems) mainUser homeDir; + in + { + options.swarselmodules.gpgagent = lib.mkEnableOption "gpg agent settings"; + config = lib.mkIf config.swarselmodules.gpgagent { + services.gpg-agent = { + enable = true; + verbose = true; + enableZshIntegration = true; + enableScDaemon = true; + enableSshSupport = true; + enableExtraSocket = true; + pinentry.package = pkgs.wayprompt; + pinentry.program = "pinentry-wayprompt"; + # pinentry.package = pkgs.pinentry.gtk2; + defaultCacheTtl = 600; + maxCacheTtl = 7200; + extraConfig = '' + allow-loopback-pinentry + allow-emacs-pinentry + ''; + sshKeys = [ + "4BE7925262289B476DBBC17B76FD3810215AE097" + ]; + }; - programs.gpg = { - enable = true; - publicKeys = [ - { - source = "${self}/secrets/public/gpg/gpg-public-key-0x76FD3810215AE097.asc"; - trust = 5; - } - ]; - }; - - systemd.user.tmpfiles.rules = [ - "d ${homeDir}/.gnupg 0700 ${mainUser} users - -" - ]; - - # assure correct permissions - # systemd.user.tmpfiles.settings."30-gpgagent".rules = { - # "${homeDir}/.gnupg" = { - # d = { - # group = "users"; - # user = mainUser; - # mode = "0700"; - # }; - # }; - # }; + programs.gpg = { + enable = true; + scdaemonSettings = { + disable-ccid = true; # prevent conflicts between pcscd and scdameon }; + publicKeys = [ + { + source = "${self}/secrets/public/gpg/gpg-public-key-0x76FD3810215AE097.asc"; + trust = 5; + } + ]; + }; - } + systemd.user.tmpfiles.rules = [ + "d ${homeDir}/.gnupg 0700 ${mainUser} users - -" + ]; + + # assure correct permissions + # systemd.user.tmpfiles.settings."30-gpgagent".rules = { + # "${homeDir}/.gnupg" = { + # d = { + # group = "users"; + # user = mainUser; + # mode = "0700"; + # }; + # }; + # }; + }; + + } #+end_src **** gammastep @@ -27360,10 +27397,10 @@ Apart from configuring Noctalia, I here also add some systemd chains to make sur }; }; } // lib.optionalAttrs (type != "nixos") { - sops.secrets = lib.mkIf (!config.swarselsystems.isPublic && !config.swarselsystems.isNixos) { - radicale-token = { path = "${xdgDir}/secrets/radicaleToken"; }; + sops.secrets = lib.mkIf (!config.swarselsystems.isPublic && !config.swarselsystems.isNixos) { + radicale-token = { path = "${xdgDir}/secrets/radicaleToken"; }; + }; }; - }; } #+end_src @@ -27755,83 +27792,83 @@ When setting up a new machine: services = { - shikane = { - settings = - let - workRight = [ - "m=HP Z32" - "s=CN41212T55" - "v=HP Inc." - ]; - workLeft = [ - "m=HP 732pk" - "s=CNC4080YL5" - "v=HP Inc." - ]; - exec = ["notify-send shikane \"Profile $SHIKANE_PROFILE_NAME has been applied\""]; - in - { - profile = [ + shikane = { + settings = + let + workRight = [ + "m=HP Z32" + "s=CN41212T55" + "v=HP Inc." + ]; + workLeft = [ + "m=HP 732pk" + "s=CNC4080YL5" + "v=HP Inc." + ]; + exec = [ "notify-send shikane \"Profile $SHIKANE_PROFILE_NAME has been applied\"" ]; + in + { + profile = [ - { - name = "work-internal-on"; - inherit exec; - output = [ - { - match = config.swarselsystems.sharescreen; - enable = true; - scale = 1.7; - position = "2560,0"; - } - { - match = workRight; - enable = true; - scale = 1.0; - mode = "3840x2160@60Hz"; - position = "-1280,0"; - } - { - match = workLeft; - enable = true; - scale = 1.0; - transform = "270"; - mode = "3840x2160@60Hz"; - position = "-3440,-1050"; - } - ]; - } - { - name = "work-internal-off"; - inherit exec; - output = [ - { - match = config.swarselsystems.sharescreen; - enable = false; - scale = 1.7; - position = "2560,0"; - } - { - match = workRight; - enable = true; - scale = 1.0; - mode = "3840x2160@60Hz"; - position = "-1280,0"; - } - { - match = workLeft; - enable = true; - scale = 1.0; - transform = "270"; - mode = "3840x2160@60Hz"; - position = "-3440,-1050"; - } - ]; - } + { + name = "work-internal-on"; + inherit exec; + output = [ + { + match = config.swarselsystems.sharescreen; + enable = true; + scale = 1.7; + position = "2560,0"; + } + { + match = workRight; + enable = true; + scale = 1.0; + mode = "3840x2160@60Hz"; + position = "-1280,0"; + } + { + match = workLeft; + enable = true; + scale = 1.0; + transform = "270"; + mode = "3840x2160@60Hz"; + position = "-3440,-1050"; + } + ]; + } + { + name = "work-internal-off"; + inherit exec; + output = [ + { + match = config.swarselsystems.sharescreen; + enable = false; + scale = 1.7; + position = "2560,0"; + } + { + match = workRight; + enable = true; + scale = 1.0; + mode = "3840x2160@60Hz"; + position = "-1280,0"; + } + { + match = workLeft; + enable = true; + scale = 1.0; + transform = "270"; + mode = "3840x2160@60Hz"; + position = "-3440,-1050"; + } + ]; + } - ]; - }; - }; + ]; + }; + }; kanshi = { settings = [ { @@ -28458,23 +28495,27 @@ In short, the options defined here are passed to the modules systems using =_mod }; serif = { # package = (pkgs.nerdfonts.override { fonts = [ "FiraMono" "FiraCode"]; }); - package = pkgs.cantarell-fonts; + # package = pkgs.cantarell-fonts; # package = pkgs.montserrat; - name = "Cantarell"; + # name = "Cantarell"; + package = pkgs.iosevka-bin.override { variant = "Aile"; }; + name = "Iosevka Aile"; # name = "FiraCode Nerd Font Propo"; # name = "Montserrat"; }; sansSerif = { # package = (pkgs.nerdfonts.override { fonts = [ "FiraMono" "FiraCode"]; }); - package = pkgs.cantarell-fonts; + # package = pkgs.cantarell-fonts; # package = pkgs.montserrat; - name = "Cantarell"; + # name = "Cantarell"; + package = pkgs.iosevka-bin.override { variant = "Aile"; }; + name = "Iosevka Aile"; # name = "FiraCode Nerd Font Propo"; # name = "Montserrat"; }; monospace = { - package = pkgs.nerd-fonts.fira-mono; # has overrides - name = "FiraCode Nerd Font Mono"; + package = pkgs.nerd-fonts.fira-code; # has overrides + name = "FiraCode Nerd Font"; }; emoji = { package = pkgs.noto-fonts-color-emoji; @@ -28824,7 +28865,8 @@ In short, the options defined here are passed to the modules systems using =_mod lib.nameValuePair "/storage/${eternorPath}" { pool = "Vault"; dataset = "Eternor/${eternorPath}"; - }) eternorPaths))); + }) + eternorPaths))); modules = [ (config.node.configDir + /guests/${guestName}/default.nix) { @@ -28935,7 +28977,7 @@ In short, the options defined here are passed to the modules systems using =_mod :CUSTOM_ID: h:64a5cc16-6b16-4802-b421-c67ccef853e1 :END: -This is the central station for self-defined packages. These are all referenced in =default.nix=. Wherever possible, I am keeping the shell version of these scripts in this file as well and then read it using =builtin.readFile= in the NixOS configurations. This lets me keep full control in this one file but also keep the separate files uncluttered. +This is the central station for self-defined packages. These are all referenced in =default.nix=. For scripts that are packaged via =writeShellApplication=, I now keep the executable body directly inside the Nix package definitions. Where a shell block still exists for readability in this document, it is no longer tangled to =files/scripts= and serves as documentation only. Note: The structure of generating the packages was changed in commit =2cf03a3 refactor: package and module generation=. That commit can be checked out in order to see a simpler version of achieving the same thing. @@ -28967,97 +29009,94 @@ Note: The structure of generating the packages was changed in commit =2cf03a3 re This app allows me, in conjunction with my Yubikey, to quickly enter passwords when the need arises. Normal and TOTP passwords are supported, and they can either be printed directly or copied to the clipboard. -#+begin_src shell :tangle files/scripts/pass-fuzzel.sh :mkdirp yes - # Adapted from https://code.kulupu.party/thesuess/home-manager/src/branch/main/modules/river.nix - shopt -s nullglob globstar - - otp=0 - typeit=0 - while :; do - case ${1:-} in - -t | --type) - typeit=1 - ;; - -o | --otp) - otp=1 - ;; - ,*) break ;; - esac - shift - done - - export PASSWORD_STORE_DIR=~/.local/share/password-store - prefix=${PASSWORD_STORE_DIR-~/.local/share/password-store} - if [[ $otp -eq 0 ]]; then - password_files=("$prefix"/**/*.gpg) - else - password_files=("$prefix"/otp/**/*.gpg) - fi - password_files=("${password_files[@]#"$prefix"/}") - password_files=("${password_files[@]%.gpg}") - - password=$(printf '%s\n' "${password_files[@]}" | fuzzel --dmenu "$@") - - [[ -n $password ]] || exit - if [[ $otp -eq 0 ]]; then - if [[ $typeit -eq 0 ]]; then - pass show -c "$password" &> /tmp/pass-fuzzel - else - pass show "$password" | { - IFS= read -r pass - printf %s "$pass" - } | wtype - - fi - else - if [[ $typeit -eq 0 ]]; then - pass otp -c "$password" &> /tmp/pass-fuzzel - else - pass otp "$password" | { - IFS= read -r pass - printf %s "$pass" - } | wtype - - fi - fi - notify-send -u critical -a pass -t 1000 "Copied/Typed Password" -#+end_src - #+begin_src nix-ts :tangle pkgs/flake/pass-fuzzel/default.nix - { self, name, writeShellApplication, libnotify, pass, fuzzel, wtype }: + { name, writeShellApplication, libnotify, pass, fuzzel, wtype, ... }: writeShellApplication { inherit name; runtimeInputs = [ libnotify (pass.withExtensions (exts: [ exts.pass-otp ])) fuzzel wtype ]; - text = builtins.readFile "${self}/files/scripts/${name}.sh"; - } + text = '' + # Adapted from https://code.kulupu.party/thesuess/home-manager/src/branch/main/modules/river.nix + shopt -s nullglob globstar + otp=0 + typeit=0 + while :; do + case ''${1:-} in + -t | --type) + typeit=1 + ;; + -o | --otp) + otp=1 + ;; + ,*) break ;; + esac + shift + done + + export PASSWORD_STORE_DIR=~/.local/share/password-store + prefix=''${PASSWORD_STORE_DIR-~/.local/share/password-store} + if [[ $otp -eq 0 ]]; then + password_files=("$prefix"/**/*.gpg) + else + password_files=("$prefix"/otp/**/*.gpg) + fi + password_files=("''${password_files[@]#"$prefix"/}") + password_files=("''${password_files[@]%.gpg}") + + password=$(printf '%s\n' "''${password_files[@]}" | fuzzel --dmenu "$@") + + [[ -n $password ]] || exit + if [[ $otp -eq 0 ]]; then + if [[ $typeit -eq 0 ]]; then + pass show -c "$password" &> /tmp/pass-fuzzel + else + pass show "$password" | { + IFS= read -r pass + printf %s "$pass" + } | wtype - + fi + else + if [[ $typeit -eq 0 ]]; then + pass otp -c "$password" &> /tmp/pass-fuzzel + else + pass otp "$password" | { + IFS= read -r pass + printf %s "$pass" + } | wtype - + fi + fi + notify-send -u critical -a pass -t 1000 "Copied/Typed Password" + ''; + } #+end_src ***** quickpass :PROPERTIES: :CUSTOM_ID: h:62b9c8cd-b585-4e93-8352-2bfa4a76aec9 :END: -#+begin_src shell :tangle files/scripts/quickpass.sh :mkdirp yes - shopt -s nullglob globstar - notify-send "$(env | grep -E 'WAYLAND|SWAY')" - - password="$1" - - pass show "$password" | { - IFS= read -r pass - printf %s "$pass" - } | wtype - - - notify-send -u critical -a pass -t 1000 "Typed Password" -#+end_src +This helper types a selected password entry directly into the active window, which is useful in places where clipboard pasting is blocked or inconvenient. #+begin_src nix-ts :tangle pkgs/flake/quickpass/default.nix - { self, name, writeShellApplication, libnotify, pass, wtype }: + { name, writeShellApplication, libnotify, pass, wtype, ... }: writeShellApplication { inherit name; runtimeInputs = [ libnotify pass wtype ]; - text = builtins.readFile "${self}/files/scripts/${name}.sh"; - } + text = '' + shopt -s nullglob globstar + notify-send "$(env | grep -E 'WAYLAND|SWAY')" + + password="$1" + + pass show "$password" | { + IFS= read -r pass + printf %s "$pass" + } | wtype - + + notify-send -u critical -a pass -t 1000 "Typed Password" + ''; + } #+end_src ***** cura5 @@ -29071,8 +29110,6 @@ The version of =cura= used to be quite outdated in nixpkgs. I am fetching a newe #+begin_src nix-ts :tangle pkgs/flake/cura5/default.nix # taken from https://github.com/NixOS/nixpkgs/issues/186570#issuecomment-1627797219 { appimageTools, fetchurl, writeScriptBin, pkgs, ... }: - - let cura5 = appimageTools.wrapType2 rec { pname = "cura5"; @@ -29111,7 +29148,6 @@ This script allows for quick git home-manager specialisation switching. #+begin_src nix-ts :tangle pkgs/flake/hm-specialisation/default.nix { name, writeShellApplication, fzf, findutils, home-manager, ... }: - writeShellApplication { inherit name; runtimeInputs = [ fzf findutils home-manager ]; @@ -29135,7 +29171,6 @@ This script allows for quick git worktree switching. #+begin_src nix-ts :tangle pkgs/flake/cdw/default.nix { name, writeShellApplication, fzf, ... }: - writeShellApplication { inherit name; runtimeInputs = [ fzf ]; @@ -29156,7 +29191,6 @@ This script allows for quick git branch switching. #+begin_src nix-ts :tangle pkgs/flake/cdb/default.nix { name, writeShellApplication, fzf, ... }: - writeShellApplication { inherit name; runtimeInputs = [ fzf ]; @@ -29176,7 +29210,6 @@ This script allows for quick checking of nixpkgs PR statuses. #+begin_src nix-ts :tangle pkgs/flake/prstatus/default.nix { name, writeShellApplication, curl, ... }: - writeShellApplication { inherit name; runtimeInputs = [ curl ]; @@ -29213,7 +29246,7 @@ This script lets me quickly backup files by appending =.bak= to the filename. :CUSTOM_ID: h:3c72d263-411c-44f0-90ff-55f14d4d9d49 :END: -This app starts a configuratble timer and uses TTS to say something once the timer runs out. +A timer that uses TTS to say something once the timer runs out. #+begin_src nix-ts :tangle pkgs/flake/timer/default.nix @@ -29236,83 +29269,36 @@ This app starts a configuratble timer and uses TTS to say something once the tim This is a shorthand for calling emacsclient mostly. Also, it hides the kittyterm scratchpad window that I sometimes use for calling a command quickly, in case it is on the screen. After emacs closes, the kittyterm window is then shown again if it was visible earlier. -#+begin_src shell :tangle files/scripts/e.sh - wait=0 - while :; do - case ${1:-} in - -w | --wait) - wait=1 - ;; - ,*) break ;; - esac - shift - done - - STR=$(swaymsg -t get_tree | jq -r 'recurse(.nodes[]) | select(.name == "__i3_scratch")' | grep kittyterm || true) - if [ "$STR" == "" ]; then - swaymsg '[title="kittyterm"]' scratchpad show - emacsclient -c -a "" "$@" - swaymsg '[title="kittyterm"]' scratchpad show - else - if [[ $wait -eq 0 ]]; then - emacsclient -n -c -a "" "$@" - else - emacsclient -c -a "" "$@" - fi - fi -#+end_src - #+begin_src nix-ts :tangle pkgs/flake/e/default.nix - { self, name, writeShellApplication, emacs30-pgtk, sway, jq }: + { name, writeShellApplication, emacs30-pgtk, sway, jq, ... }: writeShellApplication { inherit name; runtimeInputs = [ emacs30-pgtk sway jq ]; - text = builtins.readFile "${self}/files/scripts/${name}.sh"; - } + text = '' + wait=0 + while :; do + case ''${1:-} in + -w | --wait) + wait=1 + ;; + ,*) break ;; + esac + shift + done -#+end_src - -***** command-not-found -:PROPERTIES: -:CUSTOM_ID: h:10268005-a9cd-4a00-967c-cbe975c552fa -:END: - -The normal =command-not-found.sh= uses the outdated =nix-shell= commands as suggestions. This version supplies me with the more modern =nixpkgs#= version. - - -#+begin_src shell :tangle files/scripts/command-not-found.sh - # Adapted from https://github.com/bennofs/nix-index/blob/master/command-not-found.sh - command_not_found_handle() { - if [ -n "${MC_SID-}" ] || ! [ -t 1 ]; then - >&2 echo "$1: command not found" - return 127 + STR=$(swaymsg -t get_tree | jq -r 'recurse(.nodes[]) | select(.name == "__i3_scratch")' | grep kittyterm || true) + if [ "$STR" == "" ]; then + swaymsg '[title="kittyterm"]' scratchpad show + emacsclient -c -a "" "$@" + swaymsg '[title="kittyterm"]' scratchpad show + else + if [[ $wait -eq 0 ]]; then + emacsclient -n -c -a "" "$@" + else + emacsclient -c -a "" "$@" + fi fi - - echo -n "searching nix-index..." - ATTRS=$(@nix-locate@ --minimal --no-group --type x --type s --whole-name --at-root "/bin/$1") - - case $(echo -n "$ATTRS" | grep -c "^") in - 0) - >&2 echo -ne "$(@tput@ el1)\r" - >&2 echo "$1: command not found" - ;; - ,*) - >&2 echo -ne "$(@tput@ el1)\r" - >&2 echo "The program ‘$(@tput@ setaf 4)$1$(@tput@ sgr0)’ is currently not installed." - >&2 echo "It is provided by the following derivation(s):" - while read -r ATTR; do - ATTR=${ATTR%.out} - >&2 echo " $(@tput@ setaf 12)nixpkgs#$(@tput@ setaf 4)$ATTR$(@tput@ sgr0)" - done <<< "$ATTRS" - ;; - esac - - return 127 - } - - command_not_found_handler() { - command_not_found_handle "$@" - return $? + ''; } #+end_src @@ -29321,31 +29307,27 @@ The normal =command-not-found.sh= uses the outdated =nix-shell= commands as sugg :CUSTOM_ID: h:82f4f414-749b-4d5a-aaaa-6e3ec15fbc3d :END: - -#+begin_src shell :tangle files/scripts/niri-resize.sh - WORKSPACE=$(niri msg -j workspaces | jq -r '.[] | select(.is_focused == true) | .id') - - COUNT=$(niri msg -j windows | jq --argjson ws "$WORKSPACE" -r '.[] | select(.workspace_id == $ws and .is_floating == false) | .app_id' | wc -l) - - while [[ $COUNT == "0" || $COUNT == "2" ]]; do - COUNT=$(niri msg -j windows | jq --argjson ws "$WORKSPACE" -r '.[] | select(.workspace_id == $ws and .is_floating == false) | .app_id' | wc -l) - done - - if [[ $COUNT == "1" ]]; then - niri msg action maximize-column - fi -#+end_src - -#+RESULTS: +This helper adjusts focused-column behavior in Niri based on the current tiling state, so single-window layouts become easier to read without manual resizing. #+begin_src nix-ts :tangle pkgs/flake/niri-resize/default.nix - { self, name, writeShellApplication, jq }: + { name, writeShellApplication, jq, ... }: writeShellApplication { inherit name; runtimeInputs = [ jq ]; - text = builtins.readFile "${self}/files/scripts/${name}.sh"; - } + text = '' + WORKSPACE=$(niri msg -j workspaces | jq -r '.[] | select(.is_focused == true) | .id') + COUNT=$(niri msg -j windows | jq --argjson ws "$WORKSPACE" -r '.[] | select(.workspace_id == $ws and .is_floating == false) | .app_id' | wc -l) + + while [[ $COUNT == "0" || $COUNT == "2" ]]; do + COUNT=$(niri msg -j windows | jq --argjson ws "$WORKSPACE" -r '.[] | select(.workspace_id == $ws and .is_floating == false) | .app_id' | wc -l) + done + + if [[ $COUNT == "1" ]]; then + niri msg action maximize-column + fi + ''; + } #+end_src ***** swarselcheck @@ -29355,79 +29337,76 @@ The normal =command-not-found.sh= uses the outdated =nix-shell= commands as sugg This app checks for different apps that I keep around in the scratchpad for quick viewing and hiding (messengers and music players mostly) and then behaves like the kittyterm hider that I described in [[#h:1834df06-9238-4efa-9af6-851dafe66c68][e]]. -#+begin_src shell :tangle files/scripts/swarselcheck.sh - kitty=0 - element=0 - vesktop=0 - spotifyplayer=0 - while :; do - case ${1:-} in - -k | --kitty) - kitty=1 - ;; - -e | --element) - element=1 - ;; - -d | --vesktop) - vesktop=1 - ;; - -s | --spotifyplayer) - spotifyplayer=1 - ;; - ,*) break ;; - esac - shift - done - - if [[ $kitty -eq 1 ]]; then - STR=$(swaymsg -t get_tree | jq -r 'recurse(.nodes[]) | select(.name == "__i3_scratch")' | grep kittyterm || true) - CHECK=$(swaymsg -t get_tree | grep kittyterm || true) - if [ "$CHECK" == "" ]; then - exec kitty --app-id kittyterm -T kittyterm -o confirm_os_window_close=0 zellij attach --create kittyterm & - sleep 1 - fi - if [ "$STR" == "" ]; then - exec swaymsg '[title="kittyterm"]' scratchpad show - else - exec swaymsg '[title="kittyterm"]' scratchpad show - fi - elif [[ $element -eq 1 ]]; then - STR=$(swaymsg -t get_tree | grep Element || true) - if [ "$STR" == "" ]; then - exec element-desktop - else - exec swaymsg '[app_id=Element]' kill - fi - elif [[ $vesktop -eq 1 ]]; then - STR=$(swaymsg -t get_tree | grep vesktop || true) - if [ "$STR" == "" ]; then - exec vesktop - else - exec swaymsg '[app_id=vesktop]' kill - fi - elif [[ $spotifyplayer -eq 1 ]]; then - STR=$(swaymsg -t get_tree | jq -r 'recurse(.nodes[]) | select(.name == "__i3_scratch")' | grep spotifytui || true) - CHECK=$(swaymsg -t get_tree | grep spotifytui || true) - if [ "$CHECK" == "" ]; then - exec kitty --add-id spotifytui -T spotifytui -o confirm_os_window_close=0 spotify_player & - sleep 1 - fi - if [ "$STR" == "" ]; then - exec swaymsg '[title="spotifytui"]' scratchpad show - else - exec swaymsg '[title="spotifytui"]' scratchpad show - fi - fi -#+end_src - #+begin_src nix-ts :tangle pkgs/flake/swarselcheck/default.nix - { self, name, writeShellApplication, kitty, element-desktop, vesktop, spotify-player, jq }: + { name, writeShellApplication, kitty, element-desktop, vesktop, spotify-player, jq, ... }: writeShellApplication { inherit name; runtimeInputs = [ kitty element-desktop vesktop spotify-player jq ]; - text = builtins.readFile "${self}/files/scripts/${name}.sh"; - } + text = '' + kitty=0 + element=0 + vesktop=0 + spotifyplayer=0 + while :; do + case ''${1:-} in + -k | --kitty) + kitty=1 + ;; + -e | --element) + element=1 + ;; + -d | --vesktop) + vesktop=1 + ;; + -s | --spotifyplayer) + spotifyplayer=1 + ;; + ,*) break ;; + esac + shift + done + if [[ $kitty -eq 1 ]]; then + STR=$(swaymsg -t get_tree | jq -r 'recurse(.nodes[]) | select(.name == "__i3_scratch")' | grep kittyterm || true) + CHECK=$(swaymsg -t get_tree | grep kittyterm || true) + if [ "$CHECK" == "" ]; then + exec kitty --app-id kittyterm -T kittyterm -o confirm_os_window_close=0 zellij attach --create kittyterm & + sleep 1 + fi + if [ "$STR" == "" ]; then + exec swaymsg '[title="kittyterm"]' scratchpad show + else + exec swaymsg '[title="kittyterm"]' scratchpad show + fi + elif [[ $element -eq 1 ]]; then + STR=$(swaymsg -t get_tree | grep Element || true) + if [ "$STR" == "" ]; then + exec element-desktop + else + exec swaymsg '[app_id=Element]' kill + fi + elif [[ $vesktop -eq 1 ]]; then + STR=$(swaymsg -t get_tree | grep vesktop || true) + if [ "$STR" == "" ]; then + exec vesktop + else + exec swaymsg '[app_id=vesktop]' kill + fi + elif [[ $spotifyplayer -eq 1 ]]; then + STR=$(swaymsg -t get_tree | jq -r 'recurse(.nodes[]) | select(.name == "__i3_scratch")' | grep spotifytui || true) + CHECK=$(swaymsg -t get_tree | grep spotifytui || true) + if [ "$CHECK" == "" ]; then + exec kitty --add-id spotifytui -T spotifytui -o confirm_os_window_close=0 spotify_player & + sleep 1 + fi + if [ "$STR" == "" ]; then + exec swaymsg '[title="spotifytui"]' scratchpad show + else + exec swaymsg '[title="spotifytui"]' scratchpad show + fi + fi + ''; + } #+end_src ***** swarselcheck-niri @@ -29435,8 +29414,10 @@ This app checks for different apps that I keep around in the scratchpad for quic :CUSTOM_ID: h:96da8360-2d23-4e86-9602-415fbdb972af :END: +This is the Niri-native variant of my scratchpad toggler: it inspects running windows via Niri JSON state and either spawns or closes the matching helper app. + #+begin_src nix-ts :tangle pkgs/flake/swarselcheck-niri/default.nix - { self, name, writeShellApplication, kitty, element-desktop, vesktop, spotify-player, jq }: + { self, name, writeShellApplication, kitty, element-desktop, vesktop, spotify-player, jq, ... }: writeShellApplication { inherit name; runtimeInputs = [ kitty element-desktop vesktop spotify-player jq ]; @@ -29459,7 +29440,7 @@ This app checks for different apps that I keep around in the scratchpad for quic cmd=(sh -c 'kitty --add-id spotifytui -T spotifytui -o confirm_os_window_close=0 spotify_player' '&') searchapp="spotifytui" ;; - ,*) break ;; + *) break ;; esac shift done @@ -29475,7 +29456,6 @@ This app checks for different apps that I keep around in the scratchpad for quic ''; } - #+end_src ***** swarselzellij @@ -29483,25 +29463,24 @@ This app checks for different apps that I keep around in the scratchpad for quic :CUSTOM_ID: h:564c102c-e335-4f17-a613-c5a436bb4864 :END: -#+begin_src shell :tangle files/scripts/swarselzellij.sh - # KITTIES=$(($(pgrep -P 1 kitty | wc -l) - 1)) - - # if ((KITTIES < 1)); then - # exec kitty -o confirm_os_window_close=0 zellij attach --create main - # else - # exec kitty -o confirm_os_window_close=0 zellij attach --create "temp $KITTIES" - # fi - exec kitty -o confirm_os_window_close=0 zellij -#+end_src +This is a small convenience launcher that opens my preferred terminal multiplexer setup with predictable terminal flags. #+begin_src nix-ts :tangle pkgs/flake/swarselzellij/default.nix - { self, name, writeShellApplication, kitty }: + { name, writeShellApplication, kitty, ... }: writeShellApplication { inherit name; runtimeInputs = [ kitty ]; - text = builtins.readFile "${self}/files/scripts/${name}.sh"; - } + text = '' + # KITTIES=$(($(pgrep -P 1 kitty | wc -l) - 1)) + # if ((KITTIES < 1)); then + # exec kitty -o confirm_os_window_close=0 zellij attach --create main + # else + # exec kitty -o confirm_os_window_close=0 zellij attach --create "temp $KITTIES" + # fi + exec kitty -o confirm_os_window_close=0 zellij + ''; + } #+end_src ***** waybarupdate @@ -29511,41 +29490,38 @@ This app checks for different apps that I keep around in the scratchpad for quic This scripts checks if there are uncommited changes in either my dotfile repo, my university repo, or my passfile repo. In that case a warning will be shown in waybar. -#+begin_src shell :tangle files/scripts/waybarupdate.sh - CFG=$(git --git-dir="$HOME"/.dotfiles/.git --work-tree="$HOME"/.dotfiles/ status -s | wc -l) - CSE=$(git --git-dir="$DOCUMENT_DIR_PRIV"/CSE_TUWIEN/.git --work-tree="$DOCUMENT_DIR_PRIV"/CSE_TUWIEN/ status -s | wc -l) - PASS=$(($(git --git-dir="$HOME"/.local/share/password-store/.git --work-tree="$HOME"/.local/share/password-store/ status -s | wc -l) + $(git --git-dir="$HOME"/.local/share/password-store/.git --work-tree="$HOME"/.local/share/password-store/ diff origin/main..HEAD | wc -l))) - - if [[ $CFG != 0 ]]; then - CFG_STR='CONFIG' - else - CFG_STR='' - fi - - if [[ $CSE != 0 ]]; then - CSE_STR=' CSE' - else - CSE_STR='' - fi - - if [[ $PASS != 0 ]]; then - PASS_STR=' PASS' - else - PASS_STR='' - fi - - OUT="$CFG_STR""$CSE_STR""$PASS_STR" - echo "$OUT" -#+end_src - #+begin_src nix-ts :tangle pkgs/flake/waybarupdate/default.nix - { self, name, writeShellApplication, git }: + { name, writeShellApplication, git, ... }: writeShellApplication { inherit name; runtimeInputs = [ git ]; - text = builtins.readFile "${self}/files/scripts/${name}.sh"; - } + text = '' + CFG=$(git --git-dir="$HOME"/.dotfiles/.git --work-tree="$HOME"/.dotfiles/ status -s | wc -l) + CSE=$(git --git-dir="$DOCUMENT_DIR_PRIV"/CSE_TUWIEN/.git --work-tree="$DOCUMENT_DIR_PRIV"/CSE_TUWIEN/ status -s | wc -l) + PASS=$(($(git --git-dir="$HOME"/.local/share/password-store/.git --work-tree="$HOME"/.local/share/password-store/ status -s | wc -l) + $(git --git-dir="$HOME"/.local/share/password-store/.git --work-tree="$HOME"/.local/share/password-store/ diff origin/main..HEAD | wc -l))) + if [[ $CFG != 0 ]]; then + CFG_STR='CONFIG' + else + CFG_STR="" + fi + + if [[ $CSE != 0 ]]; then + CSE_STR=' CSE' + else + CSE_STR="" + fi + + if [[ $PASS != 0 ]]; then + PASS_STR=' PASS' + else + PASS_STR="" + fi + + OUT="$CFG_STR""$CSE_STR""$PASS_STR" + echo "$OUT" + ''; + } #+end_src ***** opacitytoggle @@ -29555,20 +29531,18 @@ This scripts checks if there are uncommited changes in either my dotfile repo, m This app quickly toggles between 5% and 0% transparency. -#+begin_src shell :tangle files/scripts/opacitytoggle.sh - if swaymsg opacity plus 0.01 -q; then - swaymsg opacity 1 - else - swaymsg opacity 0.95 - fi -#+end_src - #+begin_src nix-ts :tangle pkgs/flake/opacitytoggle/default.nix - { self, name, writeShellApplication, sway }: + { name, writeShellApplication, sway, ... }: writeShellApplication { inherit name; runtimeInputs = [ sway ]; - text = builtins.readFile "${self}/files/scripts/${name}.sh"; + text = '' + if swaymsg opacity plus 0.01 -q; then + swaymsg opacity 1 + else + swaymsg opacity 0.95 + fi + ''; } #+end_src @@ -29579,34 +29553,32 @@ This app quickly toggles between 5% and 0% transparency. This utility is used to compare the current state of the root directory with the blanket state that is stored in /root-blank (the snapshot that is restored on each reboot of an impermanence machine). Using this, I can find files that I will lose once I reboot - if there are important files in that list, I can then easily add them to the persist options. -#+begin_src shell :tangle files/scripts/fs-diff.sh - set -euo pipefail - - OLD_TRANSID=$(sudo btrfs subvolume find-new /mnt/root-blank 9999999) - OLD_TRANSID=${OLD_TRANSID#transid marker was } - - sudo btrfs subvolume find-new "/mnt/root" "$OLD_TRANSID" | - sed '$d' | - cut -f17- -d' ' | - sort | - uniq | - while read -r path; do - path="/$path" - if [ -L "$path" ]; then - : # The path is a symbolic link, so is probably handled by NixOS already - elif [ -d "$path" ]; then - : # The path is a directory, ignore - else - echo "$path" - fi - done -#+end_src - #+begin_src nix-ts :tangle pkgs/flake/fs-diff/default.nix - { self, name, writeShellApplication }: + { name, writeShellApplication, ... }: writeShellApplication { inherit name; - text = builtins.readFile "${self}/files/scripts/${name}.sh"; + text = '' + set -euo pipefail + + OLD_TRANSID=$(sudo btrfs subvolume find-new /mnt/root-blank 9999999) + OLD_TRANSID=''${OLD_TRANSID#transid marker was } + + sudo btrfs subvolume find-new "/mnt/root" "$OLD_TRANSID" | + sed '$d' | + cut -f17- -d' ' | + sort | + uniq | + while read -r path; do + path="/$path" + if [ -L "$path" ]; then + : # The path is a symbolic link, so is probably handled by NixOS already + elif [ -d "$path" ]; then + : # The path is a directory, ignore + else + echo "$path" + fi + done + ''; } #+end_src @@ -29663,357 +29635,362 @@ This utility checks if there are updated packages in nixpkgs-unstable. It does s This program sets up a new NixOS host remotely. It also takes care of secret management on the new host. -#+begin_src shell :tangle files/scripts/swarsel-bootstrap.sh - # highly inspired by https://github.com/EmergentMind/nix-config/blob/dev/files/scripts/bootstrap-nixos.sh - set -eo pipefail +#+begin_src nix-ts :tangle pkgs/flake/swarsel-bootstrap/default.nix + { name, writeShellApplication, openssh, ... }: + writeShellApplication { + inherit name; + runtimeInputs = [ openssh ]; + text = '' + # highly inspired by https://github.com/EmergentMind/nix-config/blob/dev/files/scripts/bootstrap-nixos.sh + set -eo pipefail - target_hostname="" - target_destination="" - target_arch="" - target_user="swarsel" - ssh_port="22" - persist_dir="" - disk_encryption=0 - disk_encryption_args="" - no_disko_deps="false" - temp=$(mktemp -d) + target_hostname="" + target_destination="" + target_arch="" + target_user="swarsel" + ssh_port="22" + persist_dir="" + disk_encryption=0 + disk_encryption_args="" + no_disko_deps="false" + temp=$(mktemp -d) - function help_and_exit() { - echo - echo "Remotely installs SwarselSystem on a target machine including secret deployment." - echo - echo "USAGE: $0 -n -d [OPTIONS]" - echo - echo "ARGS:" - echo " -n specify target_hostname of the target host to deploy the nixos config on." - echo " -d specify ip or url to the target host." - echo " -a specify the architecture of the target host." - echo " target during install process." - echo - echo "OPTIONS:" - echo " -u specify target_user with sudo access. nix-config will be cloned to their home." - echo " Default='${target_user}'." - echo " --port specify the ssh port to use for remote access. Default=${ssh_port}." - echo " --debug Enable debug mode." - echo " --no-disko-deps Upload only disk script and not dependencies (for use on low ram)." - echo " -h | --help Print this help." - exit 0 - } + function help_and_exit() { + echo + echo "Remotely installs SwarselSystem on a target machine including secret deployment." + echo + echo "USAGE: $0 -n -d [OPTIONS]" + echo + echo "ARGS:" + echo " -n specify target_hostname of the target host to deploy the nixos config on." + echo " -d specify ip or url to the target host." + echo " -a specify the architecture of the target host." + echo " target during install process." + echo + echo "OPTIONS:" + echo " -u specify target_user with sudo access. nix-config will be cloned to their home." + echo " Default=''${target_user}." + echo " --port specify the ssh port to use for remote access. Default=''${ssh_port}." + echo " --debug Enable debug mode." + echo " --no-disko-deps Upload only disk script and not dependencies (for use on low ram)." + echo " -h | --help Print this help." + exit 0 + } - function cleanup() { - rm -rf "$temp" - rm -rf /tmp/disko-password - } - trap cleanup exit + function cleanup() { + rm -rf "$temp" + rm -rf /tmp/disko-password + } + trap cleanup exit - function red() { - echo -e "\x1B[31m[!] $1 \x1B[0m" - if [ -n "${2-}" ]; then + function red() { + echo -e "\x1B[31m[!] $1 \x1B[0m" + if [ -n "''${2-}" ]; then echo -e "\x1B[31m[!] $($2) \x1B[0m" - fi - } - function green() { - echo -e "\x1B[32m[+] $1 \x1B[0m" - if [ -n "${2-}" ]; then + fi + } + function green() { + echo -e "\x1B[32m[+] $1 \x1B[0m" + if [ -n "''${2-}" ]; then echo -e "\x1B[32m[+] $($2) \x1B[0m" - fi - } - function yellow() { - echo -e "\x1B[33m[*] $1 \x1B[0m" - if [ -n "${2-}" ]; then + fi + } + function yellow() { + echo -e "\x1B[33m[*] $1 \x1B[0m" + if [ -n "''${2-}" ]; then echo -e "\x1B[33m[*] $($2) \x1B[0m" - fi - } + fi + } - function yes_or_no() { - echo -en "\x1B[32m[+] $* [y/n] (default: y): \x1B[0m" - while true; do + function yes_or_no() { + echo -en "\x1B[32m[+] $* [y/n] (default: y): \x1B[0m" + while true; do read -rp "" yn - yn=${yn:-y} + yn=''${yn:-y} case $yn in [Yy]*) return 0 ;; [Nn]*) return 1 ;; esac - done - } + done + } - function update_sops_file() { - key_name=$1 - key_type=$2 - key=$3 + function update_sops_file() { + key_name=$1 + key_type=$2 + key=$3 - if [ ! "$key_type" == "hosts" ] && [ ! "$key_type" == "users" ]; then + if [ ! "$key_type" == "hosts" ] && [ ! "$key_type" == "users" ]; then red "Invalid key type passed to update_sops_file. Must be either 'hosts' or 'users'." exit 1 - fi - cd "${git_root}" + fi + cd "''${git_root}" - SOPS_FILE=".sops.yaml" - sed -i "{ - # Remove any * and & entries for this host - /[*&]$key_name/ d; - # Inject a new age: entry - # n matches the first line following age: and p prints it, then we transform it while reusing the spacing - /age:/{n; p; s/\(.*- \*\).*/\1$key_name/}; - # Inject a new hosts or user: entry - /&$key_type/{n; p; s/\(.*- &\).*/\1$key_name $key/} - }" $SOPS_FILE - green "Updating .sops.yaml" - cd - - } + SOPS_FILE=".sops.yaml" + sed -i "{ + # Remove any * and & entries for this host + /[*&]$key_name/ d; + # Inject a new age: entry + # n matches the first line following age: and p prints it, then we transform it while reusing the spacing + /age:/{n; p; s/\(.*- \*\).*/\1$key_name/}; + # Inject a new hosts or user: entry + /&$key_type/{n; p; s/\(.*- &\).*/\1$key_name $key/} + }" $SOPS_FILE + green "Updating .sops.yaml" + cd - + } - while [[ $# -gt 0 ]]; do - case "$1" in - -n) + while [[ $# -gt 0 ]]; do + case "$1" in + -n) shift target_hostname=$1 ;; - -d) + -d) shift target_destination=$1 ;; - -a) + -a) shift target_arch=$1 ;; - -u) + -u) shift target_user=$1 ;; - --port) + --port) shift ssh_port=$1 ;; - --no-disko-deps) + --no-disko-deps) no_disko_deps="true" ;; - --debug) + --debug) set -x ;; - -h | --help) help_and_exit ;; - ,*) + -h | --help) help_and_exit ;; + ,*) echo "Invalid option detected." help_and_exit ;; - esac - shift - done + esac + shift + done - if [[ $target_arch == "" || $target_destination == "" || $target_hostname == "" ]]; then - red "error: target_arch, target_destination or target_hostname not set." - help_and_exit - fi + if [[ $target_arch == "" || $target_destination == "" || $target_hostname == "" ]]; then + red "error: target_arch, target_destination or target_hostname not set." + help_and_exit + fi - LOCKED="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.node.lockFromBootstrapping)" - if [[ $LOCKED == "true" ]]; then - red "THIS SYSTEM IS LOCKED FROM BOOTSTRAPPING - set 'node.lockFromBootstrapping = lib.mkForce false;' to proceed" - exit - fi + LOCKED="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.node.lockFromBootstrapping)" + if [[ $LOCKED == "true" ]]; then + red "THIS SYSTEM IS LOCKED FROM BOOTSTRAPPING - set 'node.lockFromBootstrapping = lib.mkForce false;' to proceed" + exit + fi - green "~SwarselSystems~ remote installer" - green "Reading system information for $target_hostname ..." + green "~SwarselSystems~ remote installer" + green "Reading system information for $target_hostname ..." - DISK="$(nix eval --raw ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.rootDisk)" - green "Root Disk: $DISK" + DISK="$(nix eval --raw ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.rootDisk)" + green "Root Disk: $DISK" - CRYPTED="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isCrypted)" - if [[ $CRYPTED == "true" ]]; then - green "Encryption: ✓" - disk_encryption=1 - disk_encryption_args=( + CRYPTED="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isCrypted)" + if [[ $CRYPTED == "true" ]]; then + green "Encryption: ✓" + disk_encryption=1 + disk_encryption_args=( --disk-encryption-keys /tmp/disko-password /tmp/disko-password - ) - else - red "Encryption: X" - disk_encryption=0 - fi + ) + else + red "Encryption: X" + disk_encryption=0 + fi - IMPERMANENCE="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isImpermanence)" - if [[ $IMPERMANENCE == "true" ]]; then - green "Impermanence: ✓" - persist_dir="/persist" - else - red "Impermanence: X" - persist_dir="" - fi + IMPERMANENCE="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isImpermanence)" + if [[ $IMPERMANENCE == "true" ]]; then + green "Impermanence: ✓" + persist_dir="/persist" + else + red "Impermanence: X" + persist_dir="" + fi - SWAP="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isSwap)" - if [[ $SWAP == "true" ]]; then - green "Swap: ✓" - else - red "Swap: X" - fi + SWAP="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isSwap)" + if [[ $SWAP == "true" ]]; then + green "Swap: ✓" + else + red "Swap: X" + fi - SECUREBOOT="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isSecureBoot)" - if [[ $SECUREBOOT == "true" ]]; then - green "Secure Boot: ✓" - else - red "Secure Boot: X" - fi + SECUREBOOT="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isSecureBoot)" + if [[ $SECUREBOOT == "true" ]]; then + green "Secure Boot: ✓" + else + red "Secure Boot: X" + fi - ssh_cmd="ssh -oport=${ssh_port} -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -t $target_user@$target_destination" - # ssh_root_cmd=$(echo "$ssh_cmd" | sed "s|${target_user}@|root@|") # uses @ in the sed switch to avoid it triggering on the $ssh_key value - ssh_root_cmd=${ssh_cmd/${target_user}@/root@} - scp_cmd="scp -oport=${ssh_port} -o StrictHostKeyChecking=no" + ssh_cmd="ssh -oport=''${ssh_port} -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -t $target_user@$target_destination" + # ssh_root_cmd=$(echo "$ssh_cmd" | sed "s|''${target_user}@|root@|") # uses @ in the sed switch to avoid it triggering on the $ssh_key value + ssh_root_cmd=''${ssh_cmd/''${target_user}@/root@} + scp_cmd="scp -oport=''${ssh_port} -o StrictHostKeyChecking=no" - if [[ -z ${FLAKE} ]]; then - FLAKE=/home/"$target_user"/.dotfiles - fi - if [ ! -d "$FLAKE" ]; then - cd /home/"$target_user" - yellow "Flake directory not found - cloning repository from GitHub" - git clone git@github.com:Swarsel/.dotfiles.git || (yellow "Could not clone repository via SSH - defaulting to HTTPS" && git clone https://github.com/Swarsel/.dotfiles.git) - FLAKE=/home/"$target_user"/.dotfiles - fi + if [[ -z ''${FLAKE} ]]; then + FLAKE=/home/"$target_user"/.dotfiles + fi + if [ ! -d "$FLAKE" ]; then + cd /home/"$target_user" + yellow "Flake directory not found - cloning repository from GitHub" + git clone git@github.com:Swarsel/.dotfiles.git || (yellow "Could not clone repository via SSH - defaulting to HTTPS" && git clone https://github.com/Swarsel/.dotfiles.git) + FLAKE=/home/"$target_user"/.dotfiles + fi - cd "$FLAKE" + cd "$FLAKE" - rm install/flake.lock || true - git_root=$(git rev-parse --show-toplevel) - # ------------------------ - green "Wiping known_hosts of $target_destination" - sed -i "/$target_hostname/d; /$target_destination/d" ~/.ssh/known_hosts - # ------------------------ - green "Preparing a new ssh_host_ed25519_key pair for $target_hostname." - # Create the directory where sshd expects to find the host keys - install -d -m755 "$temp/$persist_dir/etc/ssh" - # Generate host ssh key pair without a passphrase - ssh-keygen -t ed25519 -f "$temp/$persist_dir/etc/ssh/ssh_host_ed25519_key" -C root@"$target_hostname" -N "" - # Set the correct permissions so sshd will accept the key - chmod 600 "$temp/$persist_dir/etc/ssh/ssh_host_ed25519_key" - echo "Adding ssh host fingerprint at $target_destination to ~/.ssh/known_hosts" - # This will fail if we already know the host, but that's fine - ssh-keyscan -p "$ssh_port" "$target_destination" >> ~/.ssh/known_hosts || true - # ------------------------ - # when using luks, disko expects a passphrase on /tmp/disko-password, so we set it for now and will update the passphrase later - # via the config - if [ "$disk_encryption" -eq 1 ]; then - while true; do + rm install/flake.lock || true + git_root=$(git rev-parse --show-toplevel) + # ------------------------ + green "Wiping known_hosts of $target_destination" + sed -i "/$target_hostname/d; /$target_destination/d" ~/.ssh/known_hosts + # ------------------------ + green "Preparing a new ssh_host_ed25519_key pair for $target_hostname." + # Create the directory where sshd expects to find the host keys + install -d -m755 "$temp/$persist_dir/etc/ssh" + # Generate host ssh key pair without a passphrase + ssh-keygen -t ed25519 -f "$temp/$persist_dir/etc/ssh/ssh_host_ed25519_key" -C root@"$target_hostname" -N "" + # Set the correct permissions so sshd will accept the key + chmod 600 "$temp/$persist_dir/etc/ssh/ssh_host_ed25519_key" + echo "Adding ssh host fingerprint at $target_destination to ~/.ssh/known_hosts" + # This will fail if we already know the host, but that's fine + ssh-keyscan -p "$ssh_port" "$target_destination" >> ~/.ssh/known_hosts || true + # ------------------------ + # when using luks, disko expects a passphrase on /tmp/disko-password, so we set it for now and will update the passphrase later + # via the config + if [ "$disk_encryption" -eq 1 ]; then + while true; do green "Set disk encryption passphrase:" read -rs luks_passphrase green "Please confirm passphrase:" read -rs luks_passphrase_confirm if [[ $luks_passphrase == "$luks_passphrase_confirm" ]]; then - echo "$luks_passphrase" > /tmp/disko-password - $ssh_root_cmd "echo '$luks_passphrase' > /tmp/disko-password" - break + echo "$luks_passphrase" > /tmp/disko-password + $ssh_root_cmd "echo '$luks_passphrase' > /tmp/disko-password" + break else - red "Passwords do not match" + red "Passwords do not match" fi - done - fi - # ------------------------ - green "Generating hardware-config.nix for $target_hostname and adding it to the nix-config." - $ssh_root_cmd "nixos-generate-config --force --no-filesystems --root /mnt" + done + fi + # ------------------------ + green "Generating hardware-config.nix for $target_hostname and adding it to the nix-config." + $ssh_root_cmd "nixos-generate-config --force --no-filesystems --root /mnt" - mkdir -p "$FLAKE"/hosts/nixos/"$target_arch"/"$target_hostname" - $scp_cmd root@"$target_destination":/mnt/etc/nixos/hardware-configuration.nix "${git_root}"/hosts/nixos/"$target_arch"/"$target_hostname"/hardware-configuration.nix - # ------------------------ - green "Generating hostkey for ssh initrd" - $ssh_root_cmd "mkdir -p $temp/etc/secrets/initrd /etc/secrets/initrd" - $ssh_root_cmd "ssh-keygen -t ed25519 -N '' -f $temp/etc/secrets/initrd/ssh_host_ed25519_key" - $ssh_root_cmd "cp $temp/etc/secrets/initrd/ssh_host_ed25519_key /etc/secrets/initrd/ssh_host_ed25519_key" - # ------------------------ + mkdir -p "$FLAKE"/hosts/nixos/"$target_arch"/"$target_hostname" + $scp_cmd root@"$target_destination":/mnt/etc/nixos/hardware-configuration.nix "''${git_root}"/hosts/nixos/"$target_arch"/"$target_hostname"/hardware-configuration.nix + # ------------------------ + green "Generating hostkey for ssh initrd" + $ssh_root_cmd "mkdir -p $temp/etc/secrets/initrd /etc/secrets/initrd" + $ssh_root_cmd "ssh-keygen -t ed25519 -N '''' -f $temp/etc/secrets/initrd/ssh_host_ed25519_key" + $ssh_root_cmd "cp $temp/etc/secrets/initrd/ssh_host_ed25519_key /etc/secrets/initrd/ssh_host_ed25519_key" + # ------------------------ - green "Deploying minimal NixOS installation on $target_destination" + green "Deploying minimal NixOS installation on $target_destination" - if [[ $no_disko_deps == "true" ]]; then - green "Building without disko dependencies (using custom kexec)" - nix run github:nix-community/nixos-anywhere/1.10.0 -- "${disk_encryption_args[@]}" --no-disko-deps --ssh-port "$ssh_port" --extra-files "$temp" --flake ./install#"$target_hostname" --kexec "$(nix build --print-out-paths .#packages."$target_arch".swarsel-kexec)/swarsel-kexec-$target_arch.tar.gz" root@"$target_destination" - else - green "Building with disko dependencies (using nixos-images kexec)" - nix run github:nix-community/nixos-anywhere/1.10.0 -- "${disk_encryption_args[@]}" --ssh-port "$ssh_port" --extra-files "$temp" --flake ./install#"$target_hostname" root@"$target_destination" - fi + if [[ $no_disko_deps == "true" ]]; then + green "Building without disko dependencies (using custom kexec)" + nix run github:nix-community/nixos-anywhere/1.10.0 -- "''${disk_encryption_args[@]}" --no-disko-deps --ssh-port "$ssh_port" --extra-files "$temp" --flake ./install#"$target_hostname" --kexec "$(nix build --print-out-paths .#packages."$target_arch".swarsel-kexec)/swarsel-kexec-$target_arch.tar.gz" root@"$target_destination" + else + green "Building with disko dependencies (using nixos-images kexec)" + nix run github:nix-community/nixos-anywhere/1.10.0 -- "''${disk_encryption_args[@]}" --ssh-port "$ssh_port" --extra-files "$temp" --flake ./install#"$target_hostname" root@"$target_destination" + fi - echo "Updating ssh host fingerprint at $target_destination to ~/.ssh/known_hosts" - ssh-keyscan -p "$ssh_port" "$target_destination" >> ~/.ssh/known_hosts || true - # ------------------------ + echo "Updating ssh host fingerprint at $target_destination to ~/.ssh/known_hosts" + ssh-keyscan -p "$ssh_port" "$target_destination" >> ~/.ssh/known_hosts || true + # ------------------------ - while true; do - read -rp "Press Enter to continue once the remote host has finished booting." - if nc -z "$target_destination" "${ssh_port}" 2> /dev/null; then + while true; do + read -rp "Press Enter to continue once the remote host has finished booting." + if nc -z "$target_destination" "''${ssh_port}" 2> /dev/null; then green "$target_destination is booted. Continuing..." break - else + else yellow "$target_destination is not yet ready." + fi + done + + # ------------------------ + + if [[ $SECUREBOOT == "true" ]]; then + green "Setting up secure boot keys" + $ssh_root_cmd "mkdir -p /var/lib/sbctl" + read -ra scp_call <<< "''${scp_cmd}" + sudo "''${scp_call[@]}" -r /var/lib/sbctl root@"$target_destination":/var/lib/ + $ssh_root_cmd "sbctl enroll-keys --ignore-immutable --microsoft || true" fi - done + # ------------------------ - # ------------------------ - - if [[ $SECUREBOOT == "true" ]]; then - green "Setting up secure boot keys" - $ssh_root_cmd "mkdir -p /var/lib/sbctl" - read -ra scp_call <<< "${scp_cmd}" - sudo "${scp_call[@]}" -r /var/lib/sbctl root@"$target_destination":/var/lib/ - $ssh_root_cmd "sbctl enroll-keys --ignore-immutable --microsoft || true" - fi - # ------------------------ - - if [ -n "$persist_dir" ]; then - $ssh_root_cmd "cp /etc/machine-id $persist_dir/etc/machine-id || true" - $ssh_root_cmd "cp -R /etc/ssh/ $persist_dir/etc/ssh/ || true" - fi - # ------------------------ - green "Generating an age key based on the new ssh_host_ed25519_key." - target_key=$( - ssh-keyscan -p "$ssh_port" -t ssh-ed25519 "$target_destination" 2>&1 | + if [ -n "$persist_dir" ]; then + $ssh_root_cmd "cp /etc/machine-id $persist_dir/etc/machine-id || true" + $ssh_root_cmd "cp -R /etc/ssh/ $persist_dir/etc/ssh/ || true" + fi + # ------------------------ + green "Generating an age key based on the new ssh_host_ed25519_key." + target_key=$( + ssh-keyscan -p "$ssh_port" -t ssh-ed25519 "$target_destination" 2>&1 | grep ssh-ed25519 | cut -f2- -d" " || ( - red "Failed to get ssh key. Host down?" - exit 1 + red "Failed to get ssh key. Host down?" + exit 1 ) - ) - host_age_key=$(nix shell nixpkgs#ssh-to-age.out -c sh -c "echo $target_key | ssh-to-age") + ) + host_age_key=$(nix shell nixpkgs#ssh-to-age.out -c sh -c "echo $target_key | ssh-to-age") - if grep -qv '^age1' <<< "$host_age_key"; then - red "The result from generated age key does not match the expected format." - yellow "Result: $host_age_key" - yellow "Expected format: age1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - exit 1 - else - echo "$host_age_key" - fi - - green "Updating nix-secrets/.sops.yaml" - update_sops_file "$target_hostname" "hosts" "$host_age_key" - yellow ".sops.yaml has been updated. There may be superfluous entries, you might need to edit manually." - if yes_or_no "Do you want to manually edit .sops.yaml now?"; then - vim "${git_root}"/.sops.yaml - fi - green "Updating all secrets files to reflect updates .sops.yaml" - sops updatekeys --yes --enable-local-keyservice "${git_root}"/hosts/nixos/"$target_arch"/"$target_hostname"/secrets/* || true - # -------------------------- - green "Making ssh_host_ed25519_key available to home-manager for user $target_user" - sed -i "/$target_hostname/d; /$target_destination/d" ~/.ssh/known_hosts - $ssh_root_cmd "mkdir -p /home/$target_user/.ssh; chown -R $target_user:users /home/$target_user/.ssh/" - $scp_cmd root@"$target_destination":/etc/ssh/ssh_host_ed25519_key root@"$target_destination":/home/"$target_user"/.ssh/ssh_host_ed25519_key - $ssh_root_cmd "chown $target_user:users /home/$target_user/.ssh/ssh_host_ed25519_key" - # __________________________ - - if yes_or_no "Add ssh host fingerprints for git upstream repositories? (This is needed for building the full config)"; then - green "Adding ssh host fingerprints for git{lab,hub}" - $ssh_cmd "mkdir -p /home/$target_user/.ssh/; ssh-keyscan -t ssh-ed25519 gitlab.com github.com | tee /home/$target_user/.ssh/known_hosts" - $ssh_root_cmd "mkdir -p /root/.ssh/; ssh-keyscan -t ssh-ed25519 gitlab.com github.com | tee /root/.ssh/known_hosts" - fi - # -------------------------- - - if yes_or_no "Do you want to copy your full nix-config and nix-secrets to $target_hostname?"; then - green "Adding ssh host fingerprint at $target_destination to ~/.ssh/known_hosts" - ssh-keyscan -p "$ssh_port" "$target_destination" >> ~/.ssh/known_hosts || true - green "Copying full nix-config to $target_hostname" - cd "${git_root}" - just sync "$target_user" "$target_destination" - - if [ -n "$persist_dir" ]; then - $ssh_root_cmd "cp -r /home/$target_user/.dotfiles $persist_dir/.dotfiles || true" - $ssh_root_cmd "cp -r /home/$target_user/.ssh $persist_dir/.ssh || true" + if grep -qv '^age1' <<< "$host_age_key"; then + red "The result from generated age key does not match the expected format." + yellow "Result: $host_age_key" + yellow "Expected format: age1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + exit 1 + else + echo "$host_age_key" fi - if yes_or_no "Do you want to rebuild immediately?"; then + green "Updating nix-secrets/.sops.yaml" + update_sops_file "$target_hostname" "hosts" "$host_age_key" + yellow ".sops.yaml has been updated. There may be superfluous entries, you might need to edit manually." + if yes_or_no "Do you want to manually edit .sops.yaml now?"; then + vim "''${git_root}"/.sops.yaml + fi + green "Updating all secrets files to reflect updates .sops.yaml" + sops updatekeys --yes --enable-local-keyservice "''${git_root}"/hosts/nixos/"$target_arch"/"$target_hostname"/secrets/* || true + # -------------------------- + green "Making ssh_host_ed25519_key available to home-manager for user $target_user" + sed -i "/$target_hostname/d; /$target_destination/d" ~/.ssh/known_hosts + $ssh_root_cmd "mkdir -p /home/$target_user/.ssh; chown -R $target_user:users /home/$target_user/.ssh/" + $scp_cmd root@"$target_destination":/etc/ssh/ssh_host_ed25519_key root@"$target_destination":/home/"$target_user"/.ssh/ssh_host_ed25519_key + $ssh_root_cmd "chown $target_user:users /home/$target_user/.ssh/ssh_host_ed25519_key" + # __________________________ + + if yes_or_no "Add ssh host fingerprints for git upstream repositories? (This is needed for building the full config)"; then + green "Adding ssh host fingerprints for git{lab,hub}" + $ssh_cmd "mkdir -p /home/$target_user/.ssh/; ssh-keyscan -t ssh-ed25519 gitlab.com github.com | tee /home/$target_user/.ssh/known_hosts" + $ssh_root_cmd "mkdir -p /root/.ssh/; ssh-keyscan -t ssh-ed25519 gitlab.com github.com | tee /root/.ssh/known_hosts" + fi + # -------------------------- + + if yes_or_no "Do you want to copy your full nix-config and nix-secrets to $target_hostname?"; then + green "Adding ssh host fingerprint at $target_destination to ~/.ssh/known_hosts" + ssh-keyscan -p "$ssh_port" "$target_destination" >> ~/.ssh/known_hosts || true + green "Copying full nix-config to $target_hostname" + cd "''${git_root}" + just sync "$target_user" "$target_destination" + + if [ -n "$persist_dir" ]; then + $ssh_root_cmd "cp -r /home/$target_user/.dotfiles $persist_dir/.dotfiles || true" + $ssh_root_cmd "cp -r /home/$target_user/.ssh $persist_dir/.ssh || true" + fi + + if yes_or_no "Do you want to rebuild immediately?"; then green "Building nix-config for $target_hostname" # yellow "Reminder: The password is 'setup'" $ssh_root_cmd "mkdir -p /root/.local/share/nix/; printf '{\"extra-substituters\":{\"https://nix-community.cachix.org\":true,\"https://nix-community.cachix.org https://cache.ngi0.nixos.org/\":true},\"extra-trusted-public-keys\":{\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=\":true,\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs= cache.ngi0.nixos.org-1:KqH5CBLNSyX184S9BKZJo1LxrxJ9ltnY2uAs5c/f1MA=\":true}}' | tee /root/.local/share/nix/trusted-settings.json" @@ -30026,7 +30003,7 @@ This program sets up a new NixOS host remotely. It also takes care of secret man $ssh_root_cmd "/run/current-system/sw/bin/nix-env --profile /nix/var/nix/profiles/system --set $store_path" green "Setting generation to activate upon next boot" $ssh_root_cmd "$store_path/bin/switch-to-configuration boot" - else + else echo green "NixOS was successfully installed!" echo "Post-install config build instructions:" @@ -30038,39 +30015,27 @@ This program sets up a new NixOS host remotely. It also takes care of secret man echo "sudo nixos-rebuild .pre-commit-config.yaml show-trace --flake .#$target_hostname switch" # echo "just rebuild" echo + fi fi - fi - green "NixOS was successfully installed!" - if yes_or_no "You can now commit and push the nix-config, which includes the hardware-configuration.nix for $target_hostname?"; then - cd "${git_root}" - deadnix hosts/nixos/"$target_arch"/"$target_hostname"/hardware-configuration.nix -qe - nixpkgs--fmt hosts/nixos/"$target_arch"/"$target_hostname"/hardware-configuration.nix - (.pre-commit-config.yaml mit run --all-files 2> /dev/null || true) && + green "NixOS was successfully installed!" + if yes_or_no "You can now commit and push the nix-config, which includes the hardware-configuration.nix for $target_hostname?"; then + cd "''${git_root}" + deadnix hosts/nixos/"$target_arch"/"$target_hostname"/hardware-configuration.nix -qe + nixpkgs--fmt hosts/nixos/"$target_arch"/"$target_hostname"/hardware-configuration.nix + (.pre-commit-config.yaml mit run --all-files 2> /dev/null || true) && git add "$git_root/hosts/nixos/$target_arch/$target_hostname/hardware-configuration.nix" && git add "$git_root/.sops.yaml" && git add "$git_root/secrets" && (git commit -m "feat: deployed $target_hostname" || true) && git push - fi + fi - if yes_or_no "Reboot now?"; then - $ssh_root_cmd "reboot" - fi + if yes_or_no "Reboot now?"; then + $ssh_root_cmd "reboot" + fi - rm -rf /tmp/disko-password -#+end_src - -#+RESULTS: -| trap: | undefined | signal: | exit | | | | | -| [ | Babel | evaluation | exited | with | code | 1 | ] | - - -#+begin_src nix-ts :tangle pkgs/flake/swarsel-bootstrap/default.nix - { self, name, writeShellApplication, openssh }: - writeShellApplication { - inherit name; - runtimeInputs = [ openssh ]; - text = builtins.readFile "${self}/files/scripts/${name}.sh"; + rm -rf /tmp/disko-password + ''; } #+end_src @@ -30079,127 +30044,125 @@ This program sets up a new NixOS host remotely. It also takes care of secret man :CUSTOM_ID: h:1eabdc59-8832-44ca-a22b-11f848ab150a :END: -#+begin_src shell :tangle files/scripts/swarsel-rebuild.sh - set -eo pipefail - - target_config="hotel" - target_arch="" - target_user="swarsel" - - function help_and_exit() { - echo - echo "Builds SwarselSystem configuration." - echo - echo "USAGE: $0 [OPTIONS]" - echo - echo "ARGS:" - echo " -n specify nixos config to build." - echo " Default: hotel" - echo " -u specify user to deploy for." - echo " Default: swarsel" - echo " -a specify target architecture." - echo " -h | --help Print this help." - exit 0 - } - - function red() { - echo -e "\x1B[31m[!] $1 \x1B[0m" - if [ -n "${2-}" ]; then - echo -e "\x1B[31m[!] $($2) \x1B[0m" - fi - } - function green() { - echo -e "\x1B[32m[+] $1 \x1B[0m" - if [ -n "${2-}" ]; then - echo -e "\x1B[32m[+] $($2) \x1B[0m" - fi - } - function yellow() { - echo -e "\x1B[33m[*] $1 \x1B[0m" - if [ -n "${2-}" ]; then - echo -e "\x1B[33m[*] $($2) \x1B[0m" - fi - } - - while [[ $# -gt 0 ]]; do - case "$1" in - -n) - shift - target_config=$1 - ;; - -a) - shift - target_arch=$1 - ;; - -u) - shift - target_user=$1 - ;; - -h | --help) help_and_exit ;; - ,*) - echo "Invalid option detected." - help_and_exit - ;; - esac - shift - done - - if [[ $target_arch == "" ]]; then - red "error: target_arch not set." - help_and_exit - fi - - cd /home/"$target_user" - - if [ ! -d /home/"$target_user"/.dotfiles ]; then - green "Cloning repository from GitHub" - git clone https://github.com/Swarsel/.dotfiles.git - else - red "A .dotfiles repository is in the way. Please (re-)move the repository and try again." - exit 1 - fi - - local_keys=$(ssh-add -L || true) - pub_key=$(cat /home/"$target_user"/.dotfiles/secrets/public/ssh/yubikey.pub) - read -ra pub_arr <<< "$pub_key" - - cd .dotfiles - if [[ $local_keys != *"${pub_arr[1]}"* ]]; then - yellow "The ssh key for this configuration is not available." - green "Adjusting flake.nix so that the configuration is buildable" - sed -i '/nix-secrets = {/,/^[[:space:]]*};/d' flake.nix - sed -i '/vbc-nix = {/,/^[[:space:]]*};/d' flake.nix - sed -i '/[[:space:]]*\/\/ (inputs.vbc-nix.overlays.default final prev)/d' overlays/default.nix - rm modules/home/common/env.nix - rm modules/home/common/gammastep.nix - rm modules/home/common/git.nix - rm modules/home/common/mail.nix - rm modules/home/common/yubikey.nix - rm modules/nixos/server/restic.nix - rm hosts/nixos/aarch64-linux/milkywell/default.nix - rm -rf modules/nixos/server - rm -rf modules/home/server - nix flake update vbc-nix - git add . - else - green "Valid SSH key found! Continuing with installation" - fi - sudo nixos-generate-config --dir /home/"$target_user"/.dotfiles/hosts/nixos/"$target_arch"/"$target_config"/ - git add /home/"$target_user"/.dotfiles/hosts/nixos/"$target_arch"/"$target_config"/hardware-configuration.nix - - green "Installing flake $target_config" - sudo nixos-rebuild --show-trace --flake .#"$target_config" boot - yellow "Please keep in mind that this is only a demo of the configuration. Things might break unexpectedly." -#+end_src - - +This script is a local fallback bootstrap path: it prepares a buildable clone on a target machine and installs a selected host generation for demonstration or recovery scenarios. #+begin_src nix-ts :tangle pkgs/flake/swarsel-rebuild/default.nix - { self, name, writeShellApplication, git }: + { name, writeShellApplication, git, ... }: writeShellApplication { inherit name; runtimeInputs = [ git ]; - text = builtins.readFile "${self}/files/scripts/${name}.sh"; + text = '' + set -eo pipefail + + target_config="hotel" + target_arch="" + target_user="swarsel" + + function help_and_exit() { + echo + echo "Builds SwarselSystem configuration." + echo + echo "USAGE: $0 [OPTIONS]" + echo + echo "ARGS:" + echo " -n specify nixos config to build." + echo " Default: hotel" + echo " -u specify user to deploy for." + echo " Default: swarsel" + echo " -a specify target architecture." + echo " -h | --help Print this help." + exit 0 + } + + function red() { + echo -e "\x1B[31m[!] $1 \x1B[0m" + if [ -n "''${2-}" ]; then + echo -e "\x1B[31m[!] $($2) \x1B[0m" + fi + } + function green() { + echo -e "\x1B[32m[+] $1 \x1B[0m" + if [ -n "''${2-}" ]; then + echo -e "\x1B[32m[+] $($2) \x1B[0m" + fi + } + function yellow() { + echo -e "\x1B[33m[*] $1 \x1B[0m" + if [ -n "''${2-}" ]; then + echo -e "\x1B[33m[*] $($2) \x1B[0m" + fi + } + + while [[ $# -gt 0 ]]; do + case "$1" in + -n) + shift + target_config=$1 + ;; + -a) + shift + target_arch=$1 + ;; + -u) + shift + target_user=$1 + ;; + -h | --help) help_and_exit ;; + ,*) + echo "Invalid option detected." + help_and_exit + ;; + esac + shift + done + + if [[ $target_arch == "" ]]; then + red "error: target_arch not set." + help_and_exit + fi + + cd /home/"$target_user" + + if [ ! -d /home/"$target_user"/.dotfiles ]; then + green "Cloning repository from GitHub" + git clone https://github.com/Swarsel/.dotfiles.git + else + red "A .dotfiles repository is in the way. Please (re-)move the repository and try again." + exit 1 + fi + + local_keys=$(ssh-add -L || true) + pub_key=$(cat /home/"$target_user"/.dotfiles/secrets/public/ssh/yubikey.pub) + read -ra pub_arr <<< "$pub_key" + + cd .dotfiles + if [[ $local_keys != *"''${pub_arr[1]}"* ]]; then + yellow "The ssh key for this configuration is not available." + green "Adjusting flake.nix so that the configuration is buildable" + sed -i '/nix-secrets = {/,/^[[:space:]]*};/d' flake.nix + sed -i '/vbc-nix = {/,/^[[:space:]]*};/d' flake.nix + sed -i '/[[:space:]]*\/\/ (inputs.vbc-nix.overlays.default final prev)/d' overlays/default.nix + rm modules/home/common/env.nix + rm modules/home/common/gammastep.nix + rm modules/home/common/git.nix + rm modules/home/common/mail.nix + rm modules/home/common/yubikey.nix + rm modules/nixos/server/restic.nix + rm hosts/nixos/aarch64-linux/milkywell/default.nix + rm -rf modules/nixos/server + rm -rf modules/home/server + nix flake update vbc-nix + git add . + else + green "Valid SSH key found! Continuing with installation" + fi + sudo nixos-generate-config --dir /home/"$target_user"/.dotfiles/hosts/nixos/"$target_arch"/"$target_config"/ + git add /home/"$target_user"/.dotfiles/hosts/nixos/"$target_arch"/"$target_config"/hardware-configuration.nix + + green "Installing flake $target_config" + sudo nixos-rebuild --show-trace --flake .#"$target_config" boot + yellow "Please keep in mind that this is only a demo of the configuration. Things might break unexpectedly." + ''; } #+end_src @@ -30210,210 +30173,201 @@ This program sets up a new NixOS host remotely. It also takes care of secret man Autoformatting always puts the =EOF= with indentation, which makes shfmt check fail. When editing this block, unindent them manually. -#+begin_src shell :tangle files/scripts/swarsel-install.sh - set -eo pipefail +#+begin_src nix-ts :tangle pkgs/flake/swarsel-install/default.nix + { name, writeShellApplication, git, ... }: + writeShellApplication { + inherit name; + runtimeInputs = [ git ]; + text = '' + set -eo pipefail - target_config="hotel" - target_hostname="hotel" - target_user="swarsel" - target_arch="" - persist_dir="" - target_disk="/dev/vda" - disk_encryption=0 + target_config="hotel" + target_hostname="hotel" + target_user="swarsel" + target_arch="" + persist_dir="" + target_disk="/dev/vda" + disk_encryption=0 - function help_and_exit() { - echo - echo "Locally installs SwarselSystem on this machine." - echo - echo "USAGE: $0 -n -d [OPTIONS]" - echo - echo "ARGS:" - echo " -n specify the nixos config to deploy." - echo " Default: hotel" - echo " -d specify disk to install on." - echo " Default: /dev/vda" - echo " -u specify user to deploy for." - echo " Default: swarsel" - echo " -a specify target architecture." - echo " -h | --help Print this help." - exit 0 - } + function help_and_exit() { + echo + echo "Locally installs SwarselSystem on this machine." + echo + echo "USAGE: $0 -n -d [OPTIONS]" + echo + echo "ARGS:" + echo " -n specify the nixos config to deploy." + echo " Default: hotel" + echo " -d specify disk to install on." + echo " Default: /dev/vda" + echo " -u specify user to deploy for." + echo " Default: swarsel" + echo " -a specify target architecture." + echo " -h | --help Print this help." + exit 0 + } - function red() { - echo -e "\x1B[31m[!] $1 \x1B[0m" - if [ -n "${2-}" ]; then + function red() { + echo -e "\x1B[31m[!] $1 \x1B[0m" + if [ -n "''${2-}" ]; then echo -e "\x1B[31m[!] $($2) \x1B[0m" - fi - } - function green() { - echo -e "\x1B[32m[+] $1 \x1B[0m" - if [ -n "${2-}" ]; then + fi + } + function green() { + echo -e "\x1B[32m[+] $1 \x1B[0m" + if [ -n "''${2-}" ]; then echo -e "\x1B[32m[+] $($2) \x1B[0m" - fi - } - function yellow() { - echo -e "\x1B[33m[*] $1 \x1B[0m" - if [ -n "${2-}" ]; then + fi + } + function yellow() { + echo -e "\x1B[33m[*] $1 \x1B[0m" + if [ -n "''${2-}" ]; then echo -e "\x1B[33m[*] $($2) \x1B[0m" - fi - } + fi + } - while [[ $# -gt 0 ]]; do - case "$1" in - -n) + while [[ $# -gt 0 ]]; do + case "$1" in + -n) shift target_config=$1 target_hostname=$1 ;; - -u) + -u) shift target_user=$1 ;; - -d) + -d) shift target_disk=$1 ;; - -a) + -a) shift target_arch=$1 ;; - -h | --help) help_and_exit ;; - ,*) + -h | --help) help_and_exit ;; + ,*) echo "Invalid option detected." help_and_exit ;; - esac - shift - done + esac + shift + done + + function cleanup() { + sudo rm -rf .cache/nix + sudo rm -rf /root/.cache/nix + } + trap cleanup exit + + if [[ $target_arch == "" || $target_hostname == "" ]]; then + red "error: target_arch or target_hostname not set." + help_and_exit + fi + + green "~SwarselSystems~ local installer" + + cd /home/"$target_user" - function cleanup() { - sudo rm -rf .cache/nix sudo rm -rf /root/.cache/nix - } - trap cleanup exit + sudo rm -rf .cache/nix + sudo rm -rf .dotfiles - if [[ $target_arch == "" || $target_hostname == "" ]]; then - red "error: target_arch or target_hostname not set." - help_and_exit - fi + green "Cloning repository from GitHub" + git clone https://github.com/Swarsel/.dotfiles.git - green "~SwarselSystems~ local installer" + local_keys=$(ssh-add -L || true) + pub_key=$(cat /home/"$target_user"/.dotfiles/secrets/public/ssh/yubikey.pub) + read -ra pub_arr <<< "$pub_key" - cd /home/"$target_user" + cd .dotfiles + if [[ $local_keys != *"''${pub_arr[1]}"* ]]; then + yellow "The ssh key for this configuration is not available." + green "Adjusting flake.nix so that the configuration is buildable ..." + sed -i '/vbc-nix = {/,/^[[:space:]]*};/d' flake.nix + sed -i '/[[:space:]]*\/\/ (inputs.vbc-nix.overlays.default final prev)/d' overlays/default.nix + nix flake update vbc-nix + git add . + else + green "Valid SSH key found! Continuing with installation" + fi - sudo rm -rf /root/.cache/nix - sudo rm -rf .cache/nix - sudo rm -rf .dotfiles + green "Reading system information for $target_config ..." + DISK="$(nix eval --raw ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.rootDisk)" + green "Root Disk in config: $DISK - Root Disk passed in cli: $target_disk" - green "Cloning repository from GitHub" - git clone https://github.com/Swarsel/.dotfiles.git + CRYPTED="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isCrypted)" + if [[ $CRYPTED == "true" ]]; then + green "Encryption: ✓" + disk_encryption=1 + else + red "Encryption: X" + disk_encryption=0 + fi - local_keys=$(ssh-add -L || true) - pub_key=$(cat /home/"$target_user"/.dotfiles/secrets/public/ssh/yubikey.pub) - read -ra pub_arr <<< "$pub_key" + IMPERMANENCE="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isImpermanence)" + if [[ $IMPERMANENCE == "true" ]]; then + green "Impermanence: ✓" + persist_dir="/persist" + else + red "Impermanence: X" + persist_dir="" + fi - cd .dotfiles - if [[ $local_keys != *"${pub_arr[1]}"* ]]; then - yellow "The ssh key for this configuration is not available." - green "Adjusting flake.nix so that the configuration is buildable ..." - sed -i '/vbc-nix = {/,/^[[:space:]]*};/d' flake.nix - sed -i '/[[:space:]]*\/\/ (inputs.vbc-nix.overlays.default final prev)/d' overlays/default.nix - nix flake update vbc-nix - git add . - else - green "Valid SSH key found! Continuing with installation" - fi + SWAP="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isSwap)" + if [[ $SWAP == "true" ]]; then + green "Swap: ✓" + else + red "Swap: X" + fi - green "Reading system information for $target_config ..." - DISK="$(nix eval --raw ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.rootDisk)" - green "Root Disk in config: $DISK - Root Disk passed in cli: $target_disk" + SECUREBOOT="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isSecureBoot)" + if [[ $SECUREBOOT == "true" ]]; then + green "Secure Boot: ✓" + else + red "Secure Boot: X" + fi - CRYPTED="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isCrypted)" - if [[ $CRYPTED == "true" ]]; then - green "Encryption: ✓" - disk_encryption=1 - else - red "Encryption: X" - disk_encryption=0 - fi - - IMPERMANENCE="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isImpermanence)" - if [[ $IMPERMANENCE == "true" ]]; then - green "Impermanence: ✓" - persist_dir="/persist" - else - red "Impermanence: X" - persist_dir="" - fi - - SWAP="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isSwap)" - if [[ $SWAP == "true" ]]; then - green "Swap: ✓" - else - red "Swap: X" - fi - - SECUREBOOT="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isSecureBoot)" - if [[ $SECUREBOOT == "true" ]]; then - green "Secure Boot: ✓" - else - red "Secure Boot: X" - fi - - if [ "$disk_encryption" -eq 1 ]; then - while true; do + if [ "$disk_encryption" -eq 1 ]; then + while true; do green "Set disk encryption passphrase:" read -rs luks_passphrase green "Please confirm passphrase:" read -rs luks_passphrase_confirm if [[ $luks_passphrase == "$luks_passphrase_confirm" ]]; then - echo "$luks_passphrase" > /tmp/disko-password - break + echo "$luks_passphrase" > /tmp/disko-password + break else - red "Passwords do not match" + red "Passwords do not match" fi - done - fi + done + fi - green "Setting up disk ..." - if [[ $target_config == "hotel" ]]; then - sudo nix --experimental-features "nix-command flakes" run github:nix-community/disko/v1.10.0 -- --mode destroy,format,mount --flake .#"$target_config" --yes-wipe-all-disks --arg diskDevice "$target_disk" - else - sudo nix --experimental-features "nix-command flakes" run github:nix-community/disko/latest -- --mode destroy,format,mount --flake .#"$target_config" --yes-wipe-all-disks - fi - sudo mkdir -p /mnt/"$persist_dir"/home/"$target_user"/ - sudo cp -r /home/"$target_user"/.dotfiles /mnt/"$persist_dir"/home/"$target_user"/ - sudo chown -R 1000:100 /mnt/"$persist_dir"/home/"$target_user" + green "Setting up disk ..." + if [[ $target_config == "hotel" ]]; then + sudo nix --experimental-features "nix-command flakes" run github:nix-community/disko/v1.10.0 -- --mode destroy,format,mount --flake .#"$target_config" --yes-wipe-all-disks --arg diskDevice "$target_disk" + else + sudo nix --experimental-features "nix-command flakes" run github:nix-community/disko/latest -- --mode destroy,format,mount --flake .#"$target_config" --yes-wipe-all-disks + fi + sudo mkdir -p /mnt/"$persist_dir"/home/"$target_user"/ + sudo cp -r /home/"$target_user"/.dotfiles /mnt/"$persist_dir"/home/"$target_user"/ + sudo chown -R 1000:100 /mnt/"$persist_dir"/home/"$target_user" - green "Generating hardware configuration ..." - sudo nixos-generate-config --root /mnt --no-filesystems --dir /home/"$target_user"/.dotfiles/hosts/nixos/"$target_arch"/"$target_config"/ + green "Generating hardware configuration ..." + sudo nixos-generate-config --root /mnt --no-filesystems --dir /home/"$target_user"/.dotfiles/hosts/nixos/"$target_arch"/"$target_config"/ - git add /home/"$target_user"/.dotfiles/hosts/nixos/"$target_arch"/"$target_config"/hardware-configuration.nix - sudo mkdir -p /root/.local/share/nix/ - printf '{\"extra-substituters\":{\"https://nix-community.cachix.org\":true,\"https://nix-community.cachix.org https://cache.ngi0.nixos.org/\":true},\"extra-trusted-public-keys\":{\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=\":true,\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs= cache.ngi0.nixos.org-1:KqH5CBLNSyX184S9BKZJo1LxrxJ9ltnY2uAs5c/f1MA=\":true}}' | sudo tee /root/.local/share/nix/trusted-settings.json > /dev/null - green "Installing flake $target_config" + git add /home/"$target_user"/.dotfiles/hosts/nixos/"$target_arch"/"$target_config"/hardware-configuration.nix + sudo mkdir -p /root/.local/share/nix/ + printf '{\"extra-substituters\":{\"https://nix-community.cachix.org\":true,\"https://nix-community.cachix.org https://cache.ngi0.nixos.org/\":true},\"extra-trusted-public-keys\":{\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=\":true,\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs= cache.ngi0.nixos.org-1:KqH5CBLNSyX184S9BKZJo1LxrxJ9ltnY2uAs5c/f1MA=\":true}}' | sudo tee /root/.local/share/nix/trusted-settings.json > /dev/null + green "Installing flake $target_config" - store_path=$(nix build --no-link --print-out-paths .#nixosConfigurationsMinimal."$target_config".config.system.build.toplevel) - green "Linking generation in bootloader" - sudo "/run/current-system/sw/bin/nix-env --profile /nix/var/nix/profiles/system --set $store_path" - green "Setting generation to activate upon next boot" - sudo "$store_path/bin/switch-to-configuration boot" - green "Installation finished! Reboot to see changes" - -#+end_src - -#+RESULTS: -| trap: | undefined | signal: | exit | | | | | -| [ | Babel | evaluation | exited | with | code | 1 | ] | - - - -#+begin_src nix-ts :tangle pkgs/flake/swarsel-install/default.nix - { self, name, writeShellApplication, git }: - writeShellApplication { - inherit name; - runtimeInputs = [ git ]; - text = builtins.readFile "${self}/files/scripts/${name}.sh"; + store_path=$(nix build --no-link --print-out-paths .#nixosConfigurationsMinimal."$target_config".config.system.build.toplevel) + green "Linking generation in bootloader" + sudo "/run/current-system/sw/bin/nix-env --profile /nix/var/nix/profiles/system --set $store_path" + green "Setting generation to activate upon next boot" + sudo "$store_path/bin/switch-to-configuration boot" + green "Installation finished! Reboot to see changes" + ''; } #+end_src @@ -30422,89 +30376,87 @@ Autoformatting always puts the =EOF= with indentation, which makes shfmt check f :CUSTOM_ID: h:c98a7615-e5da-4f47-8ed1-2b2ea65519e9 :END: -#+begin_src shell :tangle files/scripts/swarsel-postinstall.sh - set -eo pipefail - - target_config="hotel" - target_user="swarsel" - - function help_and_exit() { - echo - echo "Locally installs SwarselSystem on this machine." - echo - echo "USAGE: $0 -d [OPTIONS]" - echo - echo "ARGS:" - echo " -d specify disk to install on." - echo " -n specify the nixos config to deploy." - echo " Default: hotel" - echo " Default: hotel" - echo " -u specify user to deploy for." - echo " Default: swarsel" - echo " -h | --help Print this help." - exit 0 - } - - function green() { - echo -e "\x1B[32m[+] $1 \x1B[0m" - if [ -n "${2-}" ]; then - echo -e "\x1B[32m[+] $($2) \x1B[0m" - fi - } - - while [[ $# -gt 0 ]]; do - case "$1" in - -n) - shift - target_config=$1 - ;; - -u) - shift - target_user=$1 - ;; - -h | --help) help_and_exit ;; - ,*) - echo "Invalid option detected." - help_and_exit - ;; - esac - shift - done - - function cleanup() { - sudo rm -rf .cache/nix - sudo rm -rf /root/.cache/nix - } - trap cleanup exit - - sudo rm -rf .cache/nix - sudo rm -rf /root/.cache/nix - - green "~SwarselSystems~ remote post-installer" - - cd /home/"$target_user"/.dotfiles - - SECUREBOOT="$(nix eval ~/.dotfiles#nixosConfigurations."$target_config".config.swarselsystems.isSecureBoot)" - - if [[ $SECUREBOOT == "true" ]]; then - green "Setting up secure boot keys" - sudo mkdir -p /var/lib/sbctl - sbctl create-keys || true - sbctl enroll-keys --ignore-immutable --microsoft || true - fi - - sudo nixos-rebuild --flake .#"$target_config" switch - green "Post-install finished!" -#+end_src - - +This post-install helper applies host-specific finishing steps after the initial deployment, most notably secure-boot key enrollment and a first full rebuild. #+begin_src nix-ts :tangle pkgs/flake/swarsel-postinstall/default.nix - { self, name, writeShellApplication, git }: + { name, writeShellApplication, git, ... }: writeShellApplication { inherit name; runtimeInputs = [ git ]; - text = builtins.readFile "${self}/files/scripts/${name}.sh"; + text = '' + set -eo pipefail + + target_config="hotel" + target_user="swarsel" + + function help_and_exit() { + echo + echo "Locally installs SwarselSystem on this machine." + echo + echo "USAGE: $0 -d [OPTIONS]" + echo + echo "ARGS:" + echo " -d specify disk to install on." + echo " -n specify the nixos config to deploy." + echo " Default: hotel" + echo " Default: hotel" + echo " -u specify user to deploy for." + echo " Default: swarsel" + echo " -h | --help Print this help." + exit 0 + } + + function green() { + echo -e "\x1B[32m[+] $1 \x1B[0m" + if [ -n "''${2-}" ]; then + echo -e "\x1B[32m[+] $($2) \x1B[0m" + fi + } + + while [[ $# -gt 0 ]]; do + case "$1" in + -n) + shift + target_config=$1 + ;; + -u) + shift + target_user=$1 + ;; + -h | --help) help_and_exit ;; + ,*) + echo "Invalid option detected." + help_and_exit + ;; + esac + shift + done + + function cleanup() { + sudo rm -rf .cache/nix + sudo rm -rf /root/.cache/nix + } + trap cleanup exit + + sudo rm -rf .cache/nix + sudo rm -rf /root/.cache/nix + + green "~SwarselSystems~ remote post-installer" + + cd /home/"$target_user"/.dotfiles + + SECUREBOOT="$(nix eval ~/.dotfiles#nixosConfigurations."$target_config".config.swarselsystems.isSecureBoot)" + + if [[ $SECUREBOOT == "true" ]]; then + green "Setting up secure boot keys" + sudo mkdir -p /var/lib/sbctl + sbctl create-keys || true + sbctl enroll-keys --ignore-immutable --microsoft || true + fi + + sudo nixos-rebuild --flake .#"$target_config" switch + green "Post-install finished!" + ''; } #+end_src @@ -30513,6 +30465,8 @@ Autoformatting always puts the =EOF= with indentation, which makes shfmt check f :CUSTOM_ID: h:5ad99997-e54c-4f0b-9ab7-15f76b1e16e1 :END: +Small convenience conversion from a human-readable timestamp to Unix epoch seconds. + #+begin_src nix-ts :tangle pkgs/flake/t2ts/default.nix { name, writeShellApplication, ... }: @@ -30531,6 +30485,8 @@ Autoformatting always puts the =EOF= with indentation, which makes shfmt check f :CUSTOM_ID: h:5ad99997-e54c-4f0b-9ab7-15f76b1e16e1 :END: +Inverse helper for [[#h:5ad99997-e54c-4f0b-9ab7-15f76b1e16e1][t2ts]]: converts Unix epoch values back into a readable date/time representation. + #+begin_src nix-ts :tangle pkgs/flake/ts2t/default.nix { name, writeShellApplication, ... }: @@ -30549,6 +30505,8 @@ Autoformatting always puts the =EOF= with indentation, which makes shfmt check f :CUSTOM_ID: h:7806b129-a4a5-4d10-af27-6cbeafbcb294 :END: +Quick utility to open an ephemeral shell from an explicitly selected nixpkgs revision and package. + #+begin_src nix-ts :tangle pkgs/flake/vershell/default.nix { name, writeShellApplication, ... }: @@ -30567,6 +30525,8 @@ Autoformatting always puts the =EOF= with indentation, which makes shfmt check f :CUSTOM_ID: h:9fda7829-09a4-4b8f-86f6-08b078ab2874 :END: +A derivation for eontimer :) + #+begin_src nix-ts :tangle pkgs/flake/eontimer/default.nix { lib , python3 @@ -30671,21 +30631,21 @@ Autoformatting always puts the =EOF= with indentation, which makes shfmt check f :CUSTOM_ID: h:154b6df4-dd50-4f60-9794-05a140d02994 :END: -#+begin_src shell :tangle files/scripts/project.sh - set -euo pipefail - - if [ ! -d "$(pwd)/.git" ]; then - git init - fi - nix flake init --template "$FLAKE"#"$1" - direnv allow -#+end_src +This helper bootstraps a new project directory by initializing git, applying one of my flake templates, and immediately allowing direnv. #+begin_src nix-ts :tangle pkgs/flake/project/default.nix - { self, name, writeShellApplication }: + { name, writeShellApplication, ... }: writeShellApplication { inherit name; - text = builtins.readFile "${self}/files/scripts/${name}.sh"; + text = '' + set -euo pipefail + + if [ ! -d "$(pwd)/.git" ]; then + git init + fi + nix flake init --template "$FLAKE"#"$1" + direnv allow + ''; } #+end_src @@ -30695,6 +30655,8 @@ Autoformatting always puts the =EOF= with indentation, which makes shfmt check f :END: +General-purpose FHS development shell wrapper for tools that still assume a traditional Linux filesystem layout. + #+begin_src nix-ts :tangle pkgs/flake/fhs/default.nix { name, pkgs, ... }: let @@ -30716,19 +30678,16 @@ Autoformatting always puts the =EOF= with indentation, which makes shfmt check f A crude script to power on all displays that might be attached. Needed because sometimes displays do not awake from sleep. -#+begin_src shell :tangle files/scripts/swarsel-displaypower.sh - swaymsg "output * power on" > /dev/null 2>&1 || true - swaymsg "output * dpms on" > /dev/null 2>&1 || true -#+end_src - #+begin_src nix-ts :tangle pkgs/flake/swarsel-displaypower/default.nix - { self, name, writeShellApplication, sway }: + { name, writeShellApplication, sway, ... }: writeShellApplication { inherit name; runtimeInputs = [ sway ]; - text = builtins.readFile "${self}/files/scripts/${name}.sh"; + text = '' + swaymsg "output * power on" > /dev/null 2>&1 || true + swaymsg "output * dpms on" > /dev/null 2>&1 || true + ''; } - #+end_src ***** swarsel-mgba @@ -30768,6 +30727,8 @@ AppImage version of mgba in which the lua scripting works. :CUSTOM_ID: h:c3362d4e-d3a8-43e8-9ef7-272b6de0572e :END: +Remote deployment helper that builds one or more hosts, copies closures, activates the selected action, and prints diffs for quick review. + #+begin_src nix-ts :tangle pkgs/flake/swarsel-deploy/default.nix # heavily inspired from https://github.com/oddlama/nix-config/blob/d42cbde676001a7ad8a3cace156e050933a4dcc3/pkgs/deploy.nix { name, bc, nix-output-monitor, writeShellApplication, ... }: @@ -30826,7 +30787,7 @@ AppImage version of mgba in which the lua scripting works. ;; -*) OPTIONS+=("$1") ;; - ,*) POSITIONAL_ARGS+=("$1") ;; + *) POSITIONAL_ARGS+=("$1") ;; esac shift done @@ -30892,7 +30853,6 @@ AppImage version of mgba in which the lua scripting works. done ''; } - #+end_src ***** swarsel-build @@ -30900,6 +30860,8 @@ AppImage version of mgba in which the lua scripting works. :CUSTOM_ID: h:c3362d4e-d3a8-43e8-9ef7-272b6de0572e :END: +Batch build helper for host systems that delegates output handling to =nom= for clearer progress and diagnostics. + #+begin_src nix-ts :tangle pkgs/flake/swarsel-build/default.nix { name, nix-output-monitor, writeShellApplication, ... }: writeShellApplication { @@ -30945,26 +30907,24 @@ This is a convenience function that calls =nix-instantiate= with a number of fla This programs simply runs ssh-keygen on the last host that I tried to ssh into. I need this frequently when working with cloud-init usually. -#+begin_src shell :tangle files/scripts/sshrm.sh - HISTFILE="$HOME"/.histfile - - last_ssh_cmd=$(grep -E "ssh " "$HISTFILE" | sed -E 's/^: [0-9]+:[0-9]+;//' | grep "^ssh " | tail -1) - host=$(echo "$last_ssh_cmd" | sed -E 's/.*ssh ([^@ ]+@)?([^ ]+).*/\2/') - - if [[ -n $host ]]; then - echo "Removing SSH host key for: $host" - ssh-keygen -R "$host" - else - echo "No valid SSH command found in history." - fi -#+end_src - #+begin_src nix-ts :tangle pkgs/flake/sshrm/default.nix - { self, name, writeShellApplication, openssh }: + { name, writeShellApplication, openssh, ... }: writeShellApplication { inherit name; runtimeInputs = [ openssh ]; - text = builtins.readFile "${self}/files/scripts/${name}.sh"; + text = '' + HISTFILE="$HOME"/.histfile + + last_ssh_cmd=$(grep -E "ssh " "$HISTFILE" | sed -E 's/^: [0-9]+:[0-9]+;//' | grep "^ssh " | tail -1) + host=$(echo "$last_ssh_cmd" | sed -E 's/.*ssh ([^@ ]+@)?([^ ]+).*/\2/') + + if [[ -n $host ]]; then + echo "Removing SSH host key for: $host" + ssh-keygen -R "$host" + else + echo "No valid SSH command found in history." + fi + ''; } #+end_src ***** endme @@ -31035,7 +30995,7 @@ This script allows for quick git replace of a string. target_dirs=rue ;; -h | --help) help_and_exit ;; - ,*) + *) echo "Invalid option detected." help_and_exit ;; @@ -31059,8 +31019,6 @@ This script allows for quick git replace of a string. fi ''; } - - #+end_src ***** gen-sops-guest @@ -31409,33 +31367,32 @@ Modules that need to be loaded on the NixOS level. Note that these will not be a options.swarselprofiles.server = lib.mkEnableOption "is this a server"; config = lib.mkIf config.swarselprofiles.server { swarselmodules = { + general = lib.mkDefault true; + lanzaboote = lib.mkDefault true; + pii = lib.mkDefault true; + home-manager = lib.mkDefault true; + xserver = lib.mkDefault true; + time = lib.mkDefault true; + users = lib.mkDefault true; + impermanence = lib.mkDefault true; + btrfs = lib.mkDefault true; + sops = lib.mkDefault true; + boot = lib.mkDefault true; + nftables = lib.mkDefault true; + server = { general = lib.mkDefault true; - lanzaboote = lib.mkDefault true; - pii = lib.mkDefault true; - home-manager = lib.mkDefault true; - xserver = lib.mkDefault true; - time = lib.mkDefault true; - users = lib.mkDefault true; - impermanence = lib.mkDefault true; - btrfs = lib.mkDefault true; - sops = lib.mkDefault true; - boot = lib.mkDefault true; - nftables = lib.mkDefault true; - server = { - general = lib.mkDefault true; - ids = lib.mkDefault true; - network = lib.mkDefault true; - diskEncryption = lib.mkDefault true; - packages = lib.mkDefault true; - ssh = lib.mkDefault true; - attic-setup = lib.mkDefault true; - dns-hostrecord = lib.mkDefault true; - }; + ids = lib.mkDefault true; + network = lib.mkDefault true; + diskEncryption = lib.mkDefault true; + packages = lib.mkDefault true; + ssh = lib.mkDefault true; + attic-setup = lib.mkDefault true; + dns-hostrecord = lib.mkDefault true; }; + }; }; } - #+end_src **** MicroVM :PROPERTIES: @@ -31735,22 +31692,22 @@ Also packed into the hook function is the line =(fset 'epg-wait-for-status 'igno (defvar swarsel-file-name-handler-alist file-name-handler-alist) (defvar swarsel-vc-handled-backends vc-handled-backends) + (defun swarsel/restore-startup-settings () + "Restore startup-tuned variables to their regular runtime values." + (setq gc-cons-threshold (* 32 1024 1024) + gc-cons-percentage 0.1 + jit-lock-defer-time 0.05 + read-process-output-max (* 1024 1024) + file-name-handler-alist swarsel-file-name-handler-alist + vc-handled-backends swarsel-vc-handled-backends) + (fset 'epg-wait-for-status #'ignore)) + (setq gc-cons-threshold most-positive-fixnum gc-cons-percentage 0.6 file-name-handler-alist nil vc-handled-backends nil) - (add-hook 'emacs-startup-hook - (lambda () - (progn - (setq gc-cons-threshold (* 32 1024 1024) - gc-cons-percentage 0.1 - jit-lock-defer-time 0.05 - read-process-output-max (* 1024 1024) - file-name-handler-alist swarsel-file-name-handler-alist - vc-handled-backends swarsel-vc-handled-backends) - (fset 'epg-wait-for-status 'ignore) - ))) + (add-hook 'emacs-startup-hook #'swarsel/restore-startup-settings) #+end_src *** Setup frames @@ -31792,6 +31749,7 @@ For the =default-frame-alist=, I used to also set ='(right-divider-width . 4)= a '(undecorated . t) ; no title bar, borders etc. '(background-color . "#1D252C") ; load doom-citylight colors to avoid white flash '(foreground-color . "#A0B3C5") ; load doom-citylight colors to avoid white flash + '(font . "FiraCode Nerd Font") '(vertical-scroll-bars . nil) '(horizontal-scroll-bars . nil) '(internal-border-width . 5) @@ -32229,7 +32187,27 @@ We set a hook that runs everytime we save the file. It would be a bit more effic (swarsel/run-formatting) ))) - (setq org-html-htmlize-output-type nil) + (defun swarsel/org-babel-tangle-single-block-advice (orig-fun &rest args) + "Run ORIG-FUN with redisplay and messages temporarily inhibited." + (let ((inhibit-redisplay t) + (inhibit-message t)) + (apply orig-fun args))) + + (defun swarsel/org-babel-tangle-timing-advice (orig-fun &rest args) + "Run ORIG-FUN and report elapsed tangle time." + (let ((tim (current-time))) + (prog1 (apply orig-fun args) + (message "org-tangle took %f sec" (float-time (time-subtract (current-time) tim)))))) + + (defun swarsel/markdown-mode-keys () + "Local markdown key customizations." + (local-set-key (kbd "C-c C-x C-l") #'org-latex-preview) + (local-set-key (kbd "C-c C-x C-u") #'markdown-toggle-url-hiding)) + + (defun swarsel/eglot-ensure-and-format () + "Ensure eglot is running and enable format-on-save for current buffer." + (eglot-ensure) + (add-hook 'before-save-hook #'eglot-format nil 'local)) ;; (add-hook 'org-mode-hook (lambda () (add-hook 'after-save-hook #'swarsel/org-babel-tangle-config))) @@ -32467,27 +32445,27 @@ I also define some keybinds to some combinations directly. Those are used mostly "wm" '(delete-other-windows :wk "maximize") "" 'up-list "" 'down-list - )) + ) - ;; General often used hotkeys - (general-define-key - "C-M-a" (lambda () (interactive) (org-capture nil "a")) ; make new anki card - "C-c d" 'crux-duplicate-current-line-or-region - "C-c D" 'crux-duplicate-and-comment-current-line-or-region - "" 'swarsel/last-buffer - "M-\\" 'indent-region - "M-r" 'swarsel/consult-magit-repos - "M-i" 'swarsel/org-insert-link-to-heading - "" 'yank - "" 'kill-region - "" 'kill-ring-save - "" 'evil-undo - "" 'evil-redo - "C-S-c C-S-c" 'mc/edit-lines - "C->" 'mc/mark-next-like-this - "C-<" 'mc/mark-previous-like-this - "C-c C-<" 'mc/mark-all-like-this - ) + ;; General often used hotkeys + (general-define-key + "C-M-a" (lambda () (interactive) (org-capture nil "a")) ; make new anki card + "C-c d" 'crux-duplicate-current-line-or-region + "C-c D" 'crux-duplicate-and-comment-current-line-or-region + "" 'swarsel/last-buffer + "M-\\" 'indent-region + "M-r" 'swarsel/consult-magit-repos + "M-i" 'swarsel/org-insert-link-to-heading + "" 'yank + "" 'kill-region + "" 'kill-ring-save + "" 'evil-undo + "" 'evil-redo + "C-S-c C-S-c" 'mc/edit-lines + "C->" 'mc/mark-next-like-this + "C-<" 'mc/mark-previous-like-this + "C-c C-<" 'mc/mark-all-like-this + )) #+end_src *** Directory setup / File structure @@ -32527,9 +32505,10 @@ This section also sets the emacs directory to the =~/.cache/= directory which is url-history-file (expand-file-name "url/history" user-emacs-directory)) ;; Use no-littering to automatically set common paths to the new user-emacs-directory - (use-package no-littering) - (setq custom-file (make-temp-file "emacs-custom-")) - (load custom-file t) + (use-package no-littering + :config + (setq custom-file (make-temp-file "emacs-custom-")) + (load custom-file t)) #+end_src @@ -32557,7 +32536,8 @@ Many people dislike the Emacs backup files; I do enjoy them, but have to admit t delete-old-versions t ; Clean up the backups version-control t ; Use version numbers on backups, kept-new-versions 5 ; keep some new versions - kept-old-versions 2) ; and some old ones, too + kept-old-versions 2 ; and some old ones, too + backup-by-copying-when-linked t) #+end_src ** General init.el setup + UI @@ -32585,16 +32565,13 @@ Here I set up some things that are too minor to put under other categories. (set-language-environment "UTF-8") ;; (profiler-start 'cpu) ;; set default font size - (defvar swarsel/default-font-size 130) - (setq swarsel-standard-font "FiraCode Nerd Font Mono" - swarsel-alt-font "FiraCode Nerd Font Mono") ;; (defalias 'yes-or-no-p 'y-or-n-p) ;;(setq-default show-trailing-whitespace t) (add-hook 'before-save-hook 'delete-trailing-whitespace) (global-hl-line-mode 1) ;; (setq redisplay-dont-pause t) ;; obsolete - (setq blink-cursor-mode nil) ;; blink-cursor is an unexpected source of slowdown + (blink-cursor-mode -1) ;; blink-cursor is an unexpected source of slowdown (global-subword-mode 1) ; Iterate through CamelCase words (setq blink-matching-paren nil) ;; this makes the cursor jump around annoyingly (delete-selection-mode 1) @@ -32606,7 +32583,6 @@ Here I set up some things that are too minor to put under other categories. bidi-display-reordering 'left-to-right bidi-inhibit-bpa t) (global-so-long-mode) - (setq process-adaptive-read-buffering nil) ;; not sure if this is a good idea (setq fast-but-imprecise-scrolling t redisplay-skip-fontification-on-input t inhibit-compacting-font-caches t) @@ -32614,9 +32590,7 @@ Here I set up some things that are too minor to put under other categories. which-func-update-delay 1.0) (setq undo-limit 80000000 evil-want-fine-undo t - auto-save-default t - password-cache-expiry nil - ) + auto-save-default t) (setq browse-url-browser-function 'browse-url-firefox) ;; (setenv "DISPLAY" ":0") ;; needed for firefox ;; disable a keybind that does more harm than good @@ -32707,16 +32681,18 @@ Lastly, I load the =highlight-indent-guides= package. This adds a neat visual in tab-width 2) (setq tab-always-indent 'complete) - (setq python-indent-guess-indent-offset-verbose nil) + + (use-package python + :ensure nil + :custom + (python-indent-guess-indent-offset-verbose nil)) (use-package highlight-indent-guides :hook (prog-mode . highlight-indent-guides-mode) - :init - (setq highlight-indent-guides-method 'column) - (setq highlight-indent-guides-responsive 'top) - ) - - (with-eval-after-load 'highlight-indent-guides + :custom + (highlight-indent-guides-method 'column) + (highlight-indent-guides-responsive nil) + :config (set-face-attribute 'highlight-indent-guides-even-face nil :background "gray10") (set-face-attribute 'highlight-indent-guides-odd-face nil :background "gray20") (set-face-attribute 'highlight-indent-guides-stack-even-face nil :background "gray40") @@ -32825,8 +32801,7 @@ This gives support for many different modes, and works beautifully out of the bo (use-package evil-collection :after evil :config - (evil-collection-init) - (setq forge-add-default-bindings nil)) + (evil-collection-init)) #+end_src **** evil-snipe :PROPERTIES: @@ -32885,7 +32860,7 @@ This makes it so that when setting a mark in evil mode (using =m =), it cre #+begin_src emacs-lisp (use-package evil-visual-mark-mode - :config (evil-visual-mark-mode)) + :commands evil-visual-mark-mode) #+end_src **** evil-textobj-tree-sitter @@ -32899,14 +32874,14 @@ This adds support for tree-sitter objects. This allows for the following chords: #+begin_src emacs-lisp - (use-package evil-textobj-tree-sitter) - ;; bind `function.outer`(entire function block) to `f` for use in things like `vaf`, `yaf` - (define-key evil-outer-text-objects-map "f" (evil-textobj-tree-sitter-get-textobj "function.outer")) - ;; bind `function.inner`(function block without name and args) to `f` for use in things like `vif`, `yif` - (define-key evil-inner-text-objects-map "f" (evil-textobj-tree-sitter-get-textobj "function.inner")) - - ;; You can also bind multiple items and we will match the first one we can find - (define-key evil-outer-text-objects-map "a" (evil-textobj-tree-sitter-get-textobj ("if_statement.outer" "conditional.outer" "loop.outer") '((python-mode . ((if_statement.outer) @if_statement.outer)) (python-ts-mode . ((if_statement.outer) @if_statement.outer))))) + (use-package evil-textobj-tree-sitter + :config + ;; bind `function.outer`(entire function block) to `f` for use in things like `vaf`, `yaf` + (define-key evil-outer-text-objects-map "f" (evil-textobj-tree-sitter-get-textobj "function.outer")) + ;; bind `function.inner`(function block without name and args) to `f` for use in things like `vif`, `yif` + (define-key evil-inner-text-objects-map "f" (evil-textobj-tree-sitter-get-textobj "function.inner")) + ;; You can also bind multiple items and we will match the first one we can find + (define-key evil-outer-text-objects-map "a" (evil-textobj-tree-sitter-get-textobj ("if_statement.outer" "conditional.outer" "loop.outer") '((python-mode . ((if_statement.outer) @if_statement.outer)) (python-ts-mode . ((if_statement.outer) @if_statement.outer)))))) #+end_src **** evil-numbers @@ -32944,18 +32919,12 @@ Here I define my fonts to be used. Honestly I do not understand the face-attribu #+begin_src emacs-lisp - (dolist (face '(default fixed-pitch)) - (set-face-attribute face nil - :font "FiraCode Nerd Font Mono")) - (add-to-list 'default-frame-alist '(font . "FiraCode Nerd Font Mono")) + (setq swarsel/fixed-font "FiraCode Nerd Font" + swarsel/variable-font "Iosevka Aile") - (set-face-attribute 'default nil :height 100) - (set-face-attribute 'fixed-pitch nil :height 1.0) - - (set-face-attribute 'variable-pitch nil - :family "IBM Plex Sans" - :weight 'regular - :height 1.06) + (set-face-attribute 'default nil :font swarsel/fixed-font :height 100) + (set-face-attribute 'fixed-pitch nil :font swarsel/fixed-font :height 130) + (set-face-attribute 'variable-pitch nil :font swarsel/variable-font :weight 'light :height 130) #+end_src @@ -33061,21 +33030,21 @@ This is really the perfect solution for me, but it might not be for everyone. (use-package mini-modeline :after smart-mode-line + :custom + (mini-modeline-display-gui-line nil) + (mini-modeline-enhance-visual nil) + (mini-modeline-truncate-p nil) + (mini-modeline-l-format nil) + (mini-modeline-right-padding 5) + (mini-modeline-r-format '("%e" mode-line-front-space mode-line-mule-info mode-line-client + mode-line-modified mode-line-remote mode-line-frame-identification + mode-line-buffer-identification " " mode-line-position " " mode-name evil-mode-line-tag)) :config (mini-modeline-mode t) - (setq mini-modeline-display-gui-line nil) - (setq mini-modeline-enhance-visual nil) - (setq mini-modeline-truncate-p nil) - (setq mini-modeline-l-format nil) - (setq mini-modeline-right-padding 5) - (setq window-divider-mode t) - (setq window-divider-default-places t) - (setq window-divider-default-bottom-width 1) - (setq window-divider-default-right-width 1) - (setq mini-modeline-r-format '("%e" mode-line-front-space mode-line-mule-info mode-line-client - mode-line-modified mode-line-remote mode-line-frame-identification - mode-line-buffer-identification " " mode-line-position " " mode-name evil-mode-line-tag )) - ) + (setq window-divider-default-places t + window-divider-default-bottom-width 1 + window-divider-default-right-width 1) + (window-divider-mode 1)) (use-package smart-mode-line :config @@ -33185,8 +33154,8 @@ The big winner here are the convenient keybinds being setup here for general use #+begin_src emacs-lisp (use-package consult - :config - (setq consult-fontify-max-size 1024) + :custom + (consult-fontify-max-size 1024) :bind (("C-x b" . consult-buffer) ("C-c " . consult-global-mark) @@ -33294,8 +33263,8 @@ This pair of packages provides information on keybinds in addition to function n (use-package which-key :init (which-key-mode) :diminish which-key-mode - :config - (setq which-key-idle-delay 0.3)) + :custom + (which-key-idle-delay 0.3)) (use-package helpful :bind @@ -33303,8 +33272,8 @@ This pair of packages provides information on keybinds in addition to function n ("C-h v" . helpful-variable) ("C-h k" . helpful-key) ("C-h C-." . helpful-at-point)) - :config - (setq help-window-select nil)) + :custom + (help-window-select nil)) #+end_src *** Ligatures @@ -33466,6 +33435,13 @@ This part of the configuration mostly makes some aesthetic changes, enables neat :bind (("C-" . org-fold-outer) ("C-c s" . org-store-link)) + :custom + (org-html-htmlize-output-type nil) + (org-fold-core-style 'overlays) + (org-src-preserve-indentation nil) + (org-src-fontify-natively t) + (org-export-with-broken-links 'mark) + (org-confirm-babel-evaluate nil) :config (setq org-ellipsis " ⤵" org-link-descriptive t @@ -33474,6 +33450,7 @@ This part of the configuration mostly makes some aesthetic changes, enables neat (setq org-support-shift-select t) (setq org-agenda-start-with-log-mode t) + (setq org-fontify-quote-and-verse-blocks t) (setq org-log-done 'time) (setq org-log-into-drawer t) (setq org-startup-with-inline-images t) @@ -33488,13 +33465,54 @@ This part of the configuration mostly makes some aesthetic changes, enables neat (setq org-capture-templates '(("t" "Todo" entry (file+headline "~/Org/Tasks.org" "Inbox") "* TODO %?\n %i\n %a") - ("j" "Journal" entry (file+datetree "~/Org/Journal.org") + ("j" "Journal" entry (file+olp+datetree "~/Org/Journal.org") "* %?\nEntered on %U\n %i\n %a"))) (setq org-refile-targets '((swarsel-archive-org-file :maxlevel . 1) (swarsel-tasks-org-file :maxlevel . 1))) + (org-babel-do-load-languages + 'org-babel-load-languages + '((emacs-lisp . t) + (python . t) + (js . t) + (shell . t))) + + (set-face-attribute 'org-block nil :foreground nil :inherit 'fixed-pitch) + (set-face-attribute 'org-table nil :inherit 'fixed-pitch) + (set-face-attribute 'org-formula nil :inherit 'fixed-pitch) + (set-face-attribute 'org-code nil :inherit '(shadow fixed-pitch)) + (set-face-attribute 'org-quote nil :inherit '(shadow fixed-pitch)) + (set-face-attribute 'org-verse nil :inherit '(shadow fixed-pitch)) + (set-face-attribute 'org-verbatim nil :inherit '(shadow fixed-pitch)) + (set-face-attribute 'org-special-keyword nil :inherit '(font-lock-comment-face fixed-pitch)) + (set-face-attribute 'org-meta-line nil :inherit '(font-lock-comment-face fixed-pitch)) + (set-face-attribute 'org-checkbox nil :inherit 'fixed-pitch) + + + (dolist (face '((org-level-1 . 1.2) + (org-level-2 . 1.1) + (org-level-3 . 1.0) + (org-level-4 . 1.0) + (org-level-5 . 1.0) + (org-level-6 . 1.0) + (org-level-7 . 1.0) + (org-level-8 . 1.0))) + (set-face-attribute (car face) nil :font swarsel/variable-font :weight 'medium :height (cdr face))) + + (add-to-list 'org-src-lang-modes '("conf-unix" . conf-unix)) + + (advice-add 'org-babel-tangle-single-block :around #'swarsel/org-babel-tangle-single-block-advice) + (advice-add 'org-babel-tangle :around #'swarsel/org-babel-tangle-timing-advice) + + (require 'org-tempo) + (add-to-list 'org-structure-template-alist '("sh" . "src shell")) + (add-to-list 'org-structure-template-alist '("el" . "src emacs-lisp")) + (add-to-list 'org-structure-template-alist '("py" . "src python :results output")) + (add-to-list 'org-structure-template-alist '("nix" . "src nix-ts :tangle")) + (add-to-list 'org-structure-template-alist '("ne" . "bash :exports both")) + ) #+end_src @@ -33533,87 +33551,6 @@ Function definition in: [[#h:fa710375-2efe-49b4-af6a-a875aca6e4a2][Visual-fill c #+end_src -**** Fix headings not folding sometimes -:PROPERTIES: -:CUSTOM_ID: h:c1a0adea-ca97-43d7-b5a0-b856d2ebc9a8 -:END: - -There is a weird bug in org-mode that makes it so that headings were not folding correctly sometimes. This setting seems to fix it. - -#+begin_src emacs-lisp - - (setq org-fold-core-style 'overlays) - -#+end_src - -**** Babel -:PROPERTIES: -:CUSTOM_ID: h:3e0b6da3-0497-4080-bb49-bab949c03bc4 -:END: - -org-babel allows to run blocks in other programming languages within an org-mode buffer, similar to what e.g. jupyterhub offers for python. - -It also offers a very useful utility of exporting org-mode buffers to different formats; the feature I enjoy most is what makes this file useful: the tangling functionality. - -***** Language Configuration -:PROPERTIES: -:CUSTOM_ID: h:5d5ed7be-ec5f-4e17-bbb8-820ab6a9961c -:END: - -- This configures the languages that babel recognizes. - -#+begin_src emacs-lisp - (setq org-src-preserve-indentation nil) - - (org-babel-do-load-languages - 'org-babel-load-languages - '((emacs-lisp . t) - (python . t) - (js . t) - (shell . t) - )) - - (push '("conf-unix" . conf-unix) org-src-lang-modes) - - (setq org-export-with-broken-links 'mark) - (setq org-confirm-babel-evaluate nil) - - ;; tangle is too slow, try to speed it up - (defadvice org-babel-tangle-single-block (around inhibit-redisplay activate protect compile) - "inhibit-redisplay and inhibit-message to avoid flicker." - (let ((inhibit-redisplay t) - (inhibit-message t)) - ad-do-it)) - - (defadvice org-babel-tangle (around time-it activate compile) - "Display the execution time" - (let ((tim (current-time))) - ad-do-it - (message "org-tangle took %f sec" (float-time (time-subtract (current-time) tim))))) - - -#+end_src - -***** old easy structure templates (org-tempo) -:PROPERTIES: -:CUSTOM_ID: h:d112ed66-b2dd-45cc-8d70-9cf6631f28a9 -:END: - -- org 9.2 changed the way structure templates work. This brings back the old way it worked. - - Usage: Type =<=, followed by one of the below keywords and press =TAB=. The corresponding source block should appear. - - #+begin_src emacs-lisp - - (require 'org-tempo) - (add-to-list 'org-structure-template-alist '("sh" . "src shell")) - (add-to-list 'org-structure-template-alist '("el" . "src emacs-lisp")) - (add-to-list 'org-structure-template-alist '("py" . "src python :results output")) - (add-to-list 'org-structure-template-alist '("nix" . "src nix-ts :tangle")) - (add-to-list 'org-structure-template-alist '("ne" . "bash :exports both")) - - #+end_src - **** aucTex :PROPERTIES: :CUSTOM_ID: h:4696e2fc-3296-47dc-8fc3-66912c329d4c @@ -33623,33 +33560,20 @@ This provides several utilities for LaTeX in Emacs, including many completions a #+begin_src emacs-lisp - (use-package auctex) - (setq TeX-auto-save t) - (setq TeX-save-query nil) - (setq TeX-parse-self t) - (setq-default TeX-engine 'luatex) - (setq-default TeX-master nil) - - (add-hook 'LaTeX-mode-hook 'visual-line-mode) - (add-hook 'LaTeX-mode-hook 'flyspell-mode) - (add-hook 'LaTeX-mode-hook 'LaTeX-math-mode) - (add-hook 'LaTeX-mode-hook 'reftex-mode) - (setq LaTeX-electric-left-right-brace t) - (setq font-latex-fontify-script nil) - (setq TeX-electric-sub-and-superscript t) - ;; (setq reftex-plug-into-AUCTeX t) - -#+end_src - -**** org-download -:PROPERTIES: -:CUSTOM_ID: h:406e5ecb-66f0-49bf-85ca-8b499f73ec5b -:END: - -This package allows to download and copy images into org-mode buffers. Sadly it does not work in a very stable manner - if you copy images that are also links to another page (like is often the case in a Google image search), Emacs might crash from this. - -#+begin_src emacs-lisp - + (use-package auctex + :hook ((LaTeX-mode . visual-line-mode) + (LaTeX-mode . flyspell-mode) + (LaTeX-mode . LaTeX-math-mode) + (LaTeX-mode . reftex-mode)) + :custom + (TeX-auto-save t) + (TeX-save-query nil) + (TeX-parse-self t) + (TeX-engine 'luatex) + (TeX-master nil) + (LaTeX-electric-left-right-brace t) + (font-latex-fontify-script nil) + (TeX-electric-sub-and-superscript t)) #+end_src @@ -33662,9 +33586,9 @@ This package automatically toggles LaTeX-fragments in org-files. It seems to als #+begin_src emacs-lisp - (use-package org-fragtog) - (add-hook 'org-mode-hook 'org-fragtog-mode) - (add-hook 'markdown-mode-hook 'org-fragtog-mode) + (use-package org-fragtog + :hook ((org-mode . org-fragtog-mode) + (markdown-mode . org-fragtog-mode))) #+end_src @@ -33685,7 +33609,7 @@ This just makes org-mode a little bit more beautiful, mostly by making the =begi #+end_src -**** Presentations +**** Presentations (org-present) :PROPERTIES: :CUSTOM_ID: h:4e11a845-a7bb-4eb5-b4ce-5b2f52e07425 :END: @@ -33705,6 +33629,8 @@ When holding presentations, I think it is important to not have too many distrac ("" . swarsel/org-present-next)) :hook ((org-present-mode . swarsel/org-present-start) (org-present-mode-quit . swarsel/org-present-end)) + :config + (add-hook 'org-present-after-navigate-functions #'swarsel/org-present-slide) ) @@ -33714,8 +33640,11 @@ When holding presentations, I think it is important to not have too many distrac (setq-local face-remapping-alist '((default (:height 1.5) variable-pitch) (header-line (:height 4.0) variable-pitch) (org-document-title (:height 1.75) org-document-title) - (org-code (:height 1.55) org-code) - (org-verbatim (:height 1.55) org-verbatim) + (org-code (:height 1.2) org-code) + (org-verbatim (:height 1.0) org-verbatim) + (org-quote (:height 1.0) org-quote) + (org-verse (:height 1.0) org-verse) + (org-table (:height 0.8) org-table) (org-block (:height 1.25) org-block) (org-block-begin-line (:height 0.7) org-block) )) @@ -33727,7 +33656,7 @@ When holding presentations, I think it is important to not have too many distrac (org-level-6 . 1.2) (org-level-7 . 1.2) (org-level-8 . 1.2))) - (set-face-attribute (car face) nil :font swarsel-alt-font :weight 'medium :height (cdr face))) + (set-face-attribute (car face) nil :font swarsel/variable-font :weight 'medium :height (cdr face))) (setq header-line-format " ") (setq visual-fill-column-width 90) @@ -33755,7 +33684,7 @@ When holding presentations, I think it is important to not have too many distrac (org-level-6 . 0.9) (org-level-7 . 0.9) (org-level-8 . 0.9))) - (set-face-attribute (car face) nil :font swarsel-alt-font :weight 'medium :height (cdr face))) + (set-face-attribute (car face) nil :font swarsel/variable-font :weight 'medium :height (cdr face))) (setq header-line-format nil) (setq visual-fill-column-width 150) (setq indicate-buffer-boundaries t) @@ -33790,14 +33719,6 @@ When holding presentations, I think it is important to not have too many distrac (swarsel/org-present-slide) )) - (defun clojure-leave-clojure-mode-function () - ) - - (add-hook 'buffer-list-update-hook #'clojure-leave-clojure-mode-function) - (add-hook 'org-present-mode-hook 'swarsel/org-present-start) - (add-hook 'org-present-mode-quit-hook 'swarsel/org-present-end) - (add-hook 'org-present-after-navigate-functions 'swarsel/org-present-slide) - #+end_src **** Render markdown blocks as body to expand noweb blocks @@ -33854,16 +33775,6 @@ It supports all functions that I normally need. Note that getting completions fo lsp-nix-nixd-home-manager-options-expr "(builtins.getFlake \"/home/swarsel/.dotfiles\").nixosConfigurations.pyramid.options.home-manager.users.type.getSubOptions []" )) - (add-to-list 'auto-mode-alist '("\\.nix\\.enc\\'" . nix-mode)) - (add-to-list 'auto-mode-alist '("\\.nix\\.enc\\'" . nix-ts-mode)) - - - (with-eval-after-load 'lsp-mode - (lsp-register-client - (make-lsp-client :new-connection (lsp-stdio-connection "nixd") - :major-modes '(nix-mode nix-ts-mode) - :priority 0 - :server-id 'nixd))) #+end_src *** HCL Mode :PROPERTIES: @@ -33876,8 +33787,8 @@ This adds support for Hashicorp Configuration Language. Used at work, it is most (use-package hcl-mode :mode "\\.hcl\\'" - :config - (setq hcl-indent-level 2)) + :custom + (hcl-indent-level 2)) #+end_src *** Jenkinsfile/Groovy @@ -33932,11 +33843,10 @@ This adds support for Terraform configuration files. This is basically the same (use-package terraform-mode :mode "\\.tf\\'" - :config - (setq terraform-indent-level 2) - (setq terraform-format-on-save t)) - - (add-hook 'terraform-mode-hook #'outline-minor-mode) + :hook (terraform-mode . outline-minor-mode) + :custom + (terraform-indent-level 2) + (terraform-format-on-save t)) #+end_src *** nix formatting @@ -33964,9 +33874,9 @@ Adds functions for formatting shellscripts. Similarly to [[id:460a47fd-cddc-4080 #+begin_src emacs-lisp (use-package shfmt - :config - (setq shfmt-command "shfmt") - (setq shfmt-arguments '("-i" "4" "-s" "-sr"))) + :custom + (shfmt-command "shfmt") + (shfmt-arguments '("-i" "4" "-s" "-sr"))) #+end_src @@ -33983,14 +33893,16 @@ Adds a mode for markdown, specifically MultiMarkdown, which allows me to render #+begin_src emacs-lisp - (setq markdown-command "pandoc") - (use-package markdown-mode :ensure t :mode ("README\\.md\\'" . gfm-mode) - :init (setq markdown-command "multimarkdown") + :init + (setq markdown-command "multimarkdown") + :hook (markdown-mode . swarsel/markdown-mode-keys) :bind (:map markdown-mode-map - ("C-c C-e" . markdown-do))) + ("C-c C-e" . markdown-do) + ("C-c C-x C-l" . org-latex-preview) + ("C-c C-x C-u" . markdown-toggle-url-hiding))) #+end_src @@ -34001,13 +33913,9 @@ Adds a mode for markdown, specifically MultiMarkdown, which allows me to render Allows me to render LaTeX just where I write it. I do not need this as much anymore, but during my studies this was very valuable to me. -#+begin_src emacs-lisp +#+begin_src emacs-lisp :tangle no - (add-hook 'markdown-mode-hook - (lambda () - (local-set-key (kbd "C-c C-x C-l") 'org-latex-preview) - (local-set-key (kbd "C-c C-x C-u") 'markdown-toggle-url-hiding) - )) + ;; Keybindings are configured in use-package markdown-mode above. #+end_src @@ -34020,37 +33928,37 @@ This adds elfeed, a neat RSS reader for Emacs. I use this as a client for [[#h:9 #+begin_src emacs-lisp - (use-package elfeed) - - (use-package elfeed-goodies) - (elfeed-goodies/setup) - - (setq elfeed-db-directory "~/.elfeed/db/") + (use-package elfeed + :custom + (elfeed-db-directory "~/.elfeed/db/") + (elfeed-use-curl t) + (elfeed-set-timeout 36000) + :config + (define-key elfeed-show-mode-map (kbd ";") #'visual-fill-column-mode) + (define-key elfeed-show-mode-map (kbd "j") #'elfeed-goodies/split-show-next) + (define-key elfeed-show-mode-map (kbd "k") #'elfeed-goodies/split-show-prev) + (define-key elfeed-search-mode-map (kbd "j") #'next-line) + (define-key elfeed-search-mode-map (kbd "k") #'previous-line) + (define-key elfeed-show-mode-map (kbd "S-SPC") #'scroll-down-command)) + (use-package elfeed-goodies + :after elfeed + :config + (elfeed-goodies/setup)) (use-package elfeed-protocol - :after elfeed) - - (elfeed-protocol-enable) - (setq elfeed-use-curl t) - (setq elfeed-set-timeout 36000) - (setq elfeed-protocol-enabled-protocols '(fever)) - (setq elfeed-protocol-fever-update-unread-only t) - (setq elfeed-protocol-fever-fetch-category-as-tag t) - - (let ((domain (getenv "SWARSEL_RSS_DOMAIN"))) - (setq elfeed-protocol-feeds - `((,(concat "fever+https://Swarsel@" domain) - :api-url ,(concat "https://" domain "/api/fever.php") - :password-file "~/.emacs.d/.fever")))) - - - (define-key elfeed-show-mode-map (kbd ";") 'visual-fill-column-mode) - (define-key elfeed-show-mode-map (kbd "j") 'elfeed-goodies/split-show-next) - (define-key elfeed-show-mode-map (kbd "k") 'elfeed-goodies/split-show-prev) - (define-key elfeed-search-mode-map (kbd "j") 'next-line) - (define-key elfeed-search-mode-map (kbd "k") 'previous-line) - (define-key elfeed-show-mode-map (kbd "S-SPC") 'scroll-down-command) + :after elfeed + :custom + (elfeed-protocol-enabled-protocols '(fever)) + (elfeed-protocol-fever-update-unread-only t) + (elfeed-protocol-fever-fetch-category-as-tag t) + :config + (elfeed-protocol-enable) + (let ((domain (getenv "SWARSEL_RSS_DOMAIN"))) + (setq elfeed-protocol-feeds + `((,(concat "fever+https://Swarsel@" domain) + :api-url ,(concat "https://" domain "/api/fever.php") + :password-file "~/.emacs.d/.fever"))))) #+end_src @@ -34117,7 +34025,7 @@ In order to update the language grammars, run the next command below. NOTE: sinc (use-package treesit-auto :custom - (setq treesit-auto-install t) + (treesit-auto-install t) :config (treesit-auto-add-to-auto-mode-alist 'all) (global-treesit-auto-mode)) @@ -34158,8 +34066,8 @@ In emacs, there are two packages for managing dev environments - emacs-direnv (d (use-package avy :bind (("M-o" . avy-goto-char-timer)) - :config - (setq avy-all-windows 'all-frames)) + :custom + (avy-all-windows 'all-frames)) #+end_src @@ -34174,22 +34082,14 @@ To install a documentation, use the =devdocs=install= command and select the app #+begin_src emacs-lisp - (use-package devdocs) - - (add-hook 'python-mode-hook - (lambda () (setq-local devdocs-current-docs '("python~3.12" "numpy~1.23" "matplotlib~3.7" "pandas~1")))) - (add-hook 'python-ts-mode-hook - (lambda () (setq-local devdocs-current-docs '("python~3.12" "numpy~1.23" "matplotlib~3.7" "pandas~1")))) - - (add-hook 'c-mode-hook - (lambda () (setq-local devdocs-current-docs '("c")))) - (add-hook 'c-ts-mode-hook - (lambda () (setq-local devdocs-current-docs '("c")))) - - (add-hook 'c++-mode-hook - (lambda () (setq-local devdocs-current-docs '("cpp")))) - (add-hook 'c++-ts-mode-hook - (lambda () (setq-local devdocs-current-docs '("cpp")))) + (use-package devdocs + :hook ((python-mode . (lambda () (setq-local devdocs-current-docs '("python~3.12" "numpy~1.23" "matplotlib~3.7" "pandas~1")))) + (python-ts-mode . (lambda () (setq-local devdocs-current-docs '("python~3.12" "numpy~1.23" "matplotlib~3.7" "pandas~1")))) + (c-mode . (lambda () (setq-local devdocs-current-docs '("c")))) + (c-ts-mode . (lambda () (setq-local devdocs-current-docs '("c")))) + (c++-mode . (lambda () (setq-local devdocs-current-docs '("cpp")))) + (c++-ts-mode . (lambda () (setq-local devdocs-current-docs '("cpp"))))) + ) ; (devdocs-update-all) @@ -34251,10 +34151,11 @@ The following settings are needed to make sure emacs works for magit commits and ;; yubikey support for pushing commits ;; commiting is enabled through nixos gpg-agent config - (use-package pinentry) - (pinentry-start) - (setq epg-pinentry-mode 'loopback) - (setenv "SSH_AUTH_SOCK" (string-chop-newline (shell-command-to-string "gpgconf --list-dirs agent-ssh-socket"))) + (use-package pinentry + :config + (pinentry-start) + (setq epg-pinentry-mode 'loopback) + (setenv "SSH_AUTH_SOCK" (string-chop-newline (shell-command-to-string "gpgconf --list-dirs agent-ssh-socket")))) #+end_src *** Forge @@ -34277,7 +34178,9 @@ NOTE: Make sure to configure a GitHub token before using this package! #+begin_src emacs-lisp (use-package forge - :after magit) + :after magit + :init + (setq forge-add-default-bindings nil)) #+end_src @@ -34345,7 +34248,7 @@ Complimentary to the delimiters-packages above, this package sets the background #+begin_src emacs-lisp (use-package rainbow-mode - :config (rainbow-mode)) + :hook ((css-mode css-ts-mode web-mode html-mode html-ts-mode) . rainbow-mode)) #+end_src *** Corfu @@ -34393,15 +34296,15 @@ Navigation functions defined here: [[#h:a1802f9b-bb71-4fd5-86fa-945da18e8b81][co (" " . swarsel/corfu-quit-and-down)) ) - (use-package nerd-icons-corfu) - - (add-to-list 'corfu-margin-formatters #'nerd-icons-corfu-formatter) - - (setq nerd-icons-corfu-mapping - '((array :style "cod" :icon "symbol_array" :face font-lock-type-face) - (boolean :style "cod" :icon "symbol_boolean" :face font-lock-builtin-face) - ;; ... - (t :style "cod" :icon "code" :face font-lock-warning-face))) + (use-package nerd-icons-corfu + :after corfu + :config + (add-to-list 'corfu-margin-formatters #'nerd-icons-corfu-formatter) + (setq nerd-icons-corfu-mapping + '((array :style "cod" :icon "symbol_array" :face font-lock-type-face) + (boolean :style "cod" :icon "symbol_boolean" :face font-lock-builtin-face) + ;; ... + (t :style "cod" :icon "code" :face font-lock-warning-face)))) #+end_src @@ -34497,9 +34400,6 @@ Tramp allows for SSH access of files over Emacs. I have no ideas what the option "-o ControlMaster=auto -o ControlPersist=yes")) ) - (setq vterm-tramp-shells '(("ssh" "'sh'"))) - - #+end_src @@ -34517,7 +34417,6 @@ This is a simple highlighting utility that uses the margin to visually show the ((prog-mode org-mode) . diff-hl-mode) :init - (diff-hl-flydiff-mode) (diff-hl-margin-mode) (diff-hl-show-hunk-mouse-mode)) @@ -34576,19 +34475,17 @@ A blocking issue can still occur while entering a direnv that has a longer evalu ;;rustic-mode tex-mode LaTeX-mode - ) . (lambda () (progn - (eglot-ensure) - (add-hook 'before-save-hook 'eglot-format nil 'local)))) + ) . swarsel/eglot-ensure-and-format) :custom (eldoc-echo-area-use-multiline-p nil) - (completion-category-defaults nil) - (fset #'jsonrpc--log-event #'ignore) (eglot-events-buffer-size 0) (eglot-sync-connect nil) (eglot-connect-timeout nil) (eglot-autoshutdown t) (eglot-send-changes-idle-time 3) (flymake-no-changes-timeout 5) + :config + (fset #'jsonrpc--log-event #'ignore) :bind (:map eglot-mode-map ("M-(" . flymake-goto-next-error) ("C-c ," . eglot-code-actions))) @@ -34616,7 +34513,13 @@ company is now disabled since it seems that corfu runs just fine with lsp-mode a ;; set prefix for lsp-command-keymap (few alternatives - "C-l", "C-c l") (setq lsp-keymap-prefix "C-c l") (setq lsp-auto-guess-root "t") - :commands lsp) + :commands lsp + :config + (lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection "nixd") + :major-modes '(nix-mode nix-ts-mode) + :priority 0 + :server-id 'nixd))) ;; (use-package company) @@ -34700,7 +34603,7 @@ This brings back warnings and errors on the sideline for eglot; a feature that I This setting ensures that hard links are preserved during the backup process, which is useful for maintaining the integrity of files that are linked in multiple locations. -#+begin_src emacs-lisp +#+begin_src emacs-lisp :tangle no (setq backup-by-copying-when-linked t) @@ -34843,6 +34746,8 @@ The hook functions are defined here: [[#h:34506761-06b9-43b5-a818-506d9b3faf28][ :ensure nil ;; :load-path "/usr/share/emacs/site-lisp/mu4e/" ;;:defer 20 ; Wait until 20 seconds after startup + :hook ((mu4e-compose-mode . swarsel/mu4e-send-from-correct-address) + (mu4e-compose-post . swarsel/mu4e-restore-default)) :config ;; This is set to 't' to avoid mail syncing issues when using mbsync @@ -34886,11 +34791,30 @@ The hook functions are defined here: [[#h:34506761-06b9-43b5-a818-506d9b3faf28][ ;; this does the equivalent of (setq mu4e-user-mail-address-list '(address1@about.com address2@about.com [...]))) (setq mu4e-user-mail-address-list (mapcar #'intern (split-string (or (getenv "SWARSEL_MAIL_ALL") "") "[ ,]+" t))) + + (setq mu4e--log-max-size 1000) + + (mu4e t) + + (let ((work (getenv "SWARSEL_MAIL_WORK"))) + (when (and work (not (string-empty-p work))) + (setq swarsel-smime-cert-path "~/.Certificates/$SWARSEL_MAIL_WORK.pem") + (setq swarsel-smime-cert-path (substitute-env-vars swarsel-smime-cert-path)) + (setq mml-secure-prefer-scheme 'smime) + (setq mml-secure-smime-sign-with-sender t) + (add-hook 'mu4e-compose-mode-hook + (lambda () + (when (and (boundp 'user-mail-address) + (stringp user-mail-address) + (string-equal user-mail-address (getenv "SWARSEL_MAIL_WORK"))) + (mml-secure-message-sign-smime)))) + (setq smime-keys + `((,(getenv "SWARSEL_MAIL_WORK") + ,swarsel-smime-cert-path + ("~/Certificates/harica-root.pem" + "~/Certificates/harica-intermediate.pem")))) + )) ) - - - (add-hook 'mu4e-compose-mode-hook #'swarsel/mu4e-send-from-correct-address) - (add-hook 'mu4e-compose-post-hook #'swarsel/mu4e-restore-default) #+end_src **** mu4e-alert @@ -34919,40 +34843,8 @@ This adds the simple utility of sending desktop notifications whenever a new mai (add-hook 'after-init-hook #'mu4e-alert-enable-notifications) ) - (mu4e t) #+end_src -**** Work: Signing Mails (S/MIME, smime) -:PROPERTIES: -:CUSTOM_ID: h:3584632a-9d6d-4ba6-8aa5-e1383581993c -:END: - -Used to automatically sign messages sent from my work email address using S/MIME certificate. - -#+begin_src emacs-lisp - (let ((work (getenv "SWARSEL_MAIL_WORK"))) - (when (and work (not (string-empty-p work))) - - (setq swarsel-smime-cert-path "~/.Certificates/$SWARSEL_MAIL_WORK.pem") - (setq swarsel-smime-cert-path (substitute-env-vars swarsel-smime-cert-path)) - (setq mml-secure-prefer-scheme 'smime) - (setq mml-secure-smime-sign-with-sender t) - (add-hook 'mu4e-compose-mode-hook - (lambda () - (when (and (boundp 'user-mail-address) - (stringp user-mail-address) - (string-equal user-mail-address (getenv "SWARSEL_MAIL_WORK"))) - (mml-secure-message-sign-smime)))) - - (setq smime-keys - `((,(getenv "SWARSEL_MAIL_WORK") - ,swarsel-smime-cert-path - ("~/Certificates/harica-root.pem" - "~/Certificates/harica-intermediate.pem" - )))) - )) - -#+end_src *** Calendar :PROPERTIES: @@ -35098,13 +34990,16 @@ This sets up the =dashboard=, which is really quite useless. But, it looks cool ( (,"󱄅" ,swarsel-domain - ,(concat "Browse " main-domain) + ,(concat "Browse " swarsel-domain) (lambda (&rest _) (browse-url ,(concat "https://" swarsel-domain)))) ) )))) -(add-to-list 'recentf-exclude "\\Archive\\.org\\'") -(add-to-list 'recentf-exclude "\\Tasks\\.org\\'") +(use-package recentf + :ensure nil + :config + (add-to-list 'recentf-exclude "\\Archive\\.org\\'") + (add-to-list 'recentf-exclude "\\Tasks\\.org\\'")) #+end_src @@ -35116,7 +35011,9 @@ This sets up the =dashboard=, which is really quite useless. But, it looks cool #+begin_src emacs-lisp (use-package vterm - :ensure t) + :ensure t + :custom + (vterm-tramp-shells '(("ssh" "'sh'")))) #+end_src @@ -35137,7 +35034,6 @@ This sets up the =dashboard=, which is really quite useless. But, it looks cool #+begin_src emacs-lisp - (setq mu4e--log-max-size 1000) (setq message-log-max 30) (setq comint-buffer-maximum-size 50) (add-hook 'comint-output-filter-functions 'comint-truncate-buffer) @@ -38318,125 +38214,134 @@ The double source block is intended here to circumvent a org-babel convenience w #+begin_src css :tangle files/firefox/chrome/userChrome.css :mkdirp yes /* Source file https://github.com/MrOtherGuy/firefox-csshacks/tree/master/chrome/autohide_toolbox.css made available under Mozilla Public License v. 2.0 - See the above repository for updates as well as full license text. */ + See the above repository for updates as well as full license text. */ - /* Hide the whole toolbar area unless urlbar is focused or cursor is over the toolbar - ,* Dimensions on non-Win10 OS probably needs to be adjusted. - ,*/ + /* Hide the whole toolbar area unless urlbar is focused or cursor is over the toolbar + ,* Dimensions on non-Win10 OS probably needs to be adjusted. + ,*/ - :root{ - --uc-autohide-toolbox-delay: 200ms; /* Wait 0.1s before hiding toolbars */ - --uc-toolbox-rotation: 82deg; /* This may need to be lower on mac - like 75 or so */ + :root{ + --uc-autohide-toolbox-delay: 200ms; /* Wait 0.1s before hiding toolbars */ + --uc-toolbox-rotation: 82deg; /* This may need to be lower on mac - like 75 or so */ + /* swarsel: added colorscheme */ + --base00: #1D252C; + --base01: #171D23; + --base02: #5EC4FF; + --base03: #566C7D; + --base04: #5EC4FF; + --base05: #A0B3C5; + --base06: #C06ECE; + --base07: #A0B3C5; + --base08: #D95468; + --base09: #FFA880; + --base0A: #5EC4FF; + --base0B: #8BD49C; + --base0C: #008B94; + --base0D: #5EC4FF; + --base0E: #C06ECE; + --base0F: #5EC4FF; - --base00: #1D252C; - --base01: #171D23; - --base02: #5EC4FF; - --base03: #566C7D; - --base04: #5EC4FF; - --base05: #A0B3C5; - --base06: #C06ECE; - --base07: #A0B3C5; - --base08: #D95468; - --base09: #FFA880; - --base0A: #5EC4FF; - --base0B: #8BD49C; - --base0C: #008B94; - --base0D: #5EC4FF; - --base0E: #C06ECE; - --base0F: #5EC4FF; + } - } + :root[sizemode="maximized"]{ + --uc-toolbox-rotation: 88.5deg; + } - :root[sizemode="maximized"]{ - --uc-toolbox-rotation: 88.5deg; - } + @media (-moz-platform: windows){ + :root:not([lwtheme]) #navigator-toolbox{ background-color: -moz-dialog !important; } + } - @media (-moz-platform: windows){ - :root:not([lwtheme]) #navigator-toolbox{ background-color: -moz-dialog !important; } - } + :root[sizemode="fullscreen"], + :root[sizemode="fullscreen"] #navigator-toolbox{ margin-top: 0 !important; } - :root[sizemode="fullscreen"], - :root[sizemode="fullscreen"] #navigator-toolbox{ margin-top: 0 !important; } + #navigator-toolbox{ + --browser-area-z-index-toolbox: 3; + position: fixed !important; + background-color: var(--lwt-accent-color,black) !important; + transition: transform 82ms linear, opacity 82ms linear !important; + transition-delay: var(--uc-autohide-toolbox-delay) !important; + transform-origin: top; + transform: rotateX(var(--uc-toolbox-rotation)); + opacity: 0; + line-height: 0; + z-index: 1; + pointer-events: none; + width: 100vw; + } + :root[sessionrestored] #urlbar[popover]{ + pointer-events: none; + opacity: 0; + transition: transform 82ms linear var(--uc-autohide-toolbox-delay), opacity 0ms calc(var(--uc-autohide-toolbox-delay) + 82ms); + transform-origin: 0px calc(0px - var(--tab-min-height) - var(--tab-block-margin) * 2); + transform: rotateX(89.9deg); + } - #navigator-toolbox{ - --browser-area-z-index-toolbox: 3; - position: fixed !important; - background-color: var(--lwt-accent-color,black) !important; - transition: transform 82ms linear, opacity 82ms linear !important; - transition-delay: var(--uc-autohide-toolbox-delay) !important; - transform-origin: top; - transform: rotateX(var(--uc-toolbox-rotation)); - opacity: 0; - line-height: 0; - z-index: 1; - pointer-events: none; - width: 100vw; - } - :root[sessionrestored] #urlbar[popover]{ - pointer-events: none; - opacity: 0; - transition: transform 82ms linear var(--uc-autohide-toolbox-delay), opacity 0ms calc(var(--uc-autohide-toolbox-delay) + 82ms); - transform-origin: 0px calc(0px - var(--tab-min-height) - var(--tab-block-margin) * 2); - transform: rotateX(89.9deg); - } + :root[window-modal-open] #urlbar[popover], + #mainPopupSet:has(> [panelopen]:not(#ask-chat-shortcuts,#selection-shortcut-action-panel,#chat-shortcuts-options-panel,#tab-preview-panel), > #tab-group-editor > [panelopen]) ~ toolbox #urlbar[popover], + /* swarsel: removed hover from next line */ + #navigator-toolbox:is(:focus-within,[movingtab]) #urlbar[popover], + :where(:root[sessionrestored]) #urlbar-container > #urlbar[popover]:is([focused],[open]){ + pointer-events: auto; + opacity: 1; + transition-delay: 33ms; + transform: rotateX(0deg); + } - :root[window-modal-open] #urlbar[popover], - #mainPopupSet:has(> [panelopen]:not(#ask-chat-shortcuts,#selection-shortcut-action-panel,#chat-shortcuts-options-panel,#tab-preview-panel), > #tab-group-editor > [panelopen]) ~ toolbox #urlbar[popover], - /* swarsel: removed :hover from below line */ - #navigator-toolbox:is(:focus-within,[movingtab]) #urlbar[popover], - #urlbar-container > #urlbar[popover]:is([focused],[open]){ - pointer-events: auto; - opacity: 1; - transition-delay: 33ms; - transform: rotateX(0deg); - } - - :root[window-modal-open] #navigator-toolbox, - #mainPopupSet:has(> [panelopen]:not(#ask-chat-shortcuts,#selection-shortcut-action-panel,#chat-shortcuts-options-panel,#tab-preview-panel), > #tab-group-editor > [panelopen]) ~ toolbox, - #navigator-toolbox:has(#urlbar:is([open],[focus-within])), - /* swarsel: removed :hover from below line */ - #navigator-toolbox:is(:focus-within,[movingtab]){ - transition-delay: 33ms !important; - transform: rotateX(0); - opacity: 1; - } - /* This makes things like OS menubar/taskbar show the toolbox when hovered in maximized windows. - ,* Unfortunately it also means that other OS native surfaces (such as context menu on macos) - ,* and other always-on-top applications will trigger toolbox to show up. */ - @media -moz-pref("userchrome.autohide-toolbox.unhide-by-native-ui.enabled"){ - :root[sizemode="maximized"]:not(:hover){ - #navigator-toolbox:not(:-moz-window-inactive), - #urlbar[popover]:not(:-moz-window-inactive){ - transition-delay: 33ms !important; - transform: rotateX(0); - opacity: 1; + :root[window-modal-open] #navigator-toolbox, + #mainPopupSet:has(> [panelopen]:not(#ask-chat-shortcuts,#selection-shortcut-action-panel,#chat-shortcuts-options-panel,#tab-preview-panel), > #tab-group-editor > [panelopen]) ~ toolbox, + #navigator-toolbox:has(#urlbar:is([open],[focus-within])), + /* swarsel: removed hover from next line */ + #navigator-toolbox:is(:focus-within,[movingtab]){ + transition-delay: 33ms !important; + transform: rotateX(0); + opacity: 1; + } + /* This makes things like OS menubar/taskbar show the toolbox when hovered in maximized windows. + ,* Unfortunately it also means that other OS native surfaces (such as context menu on macos) + ,* and other always-on-top applications will trigger toolbox to show up. */ + @media -moz-pref("userchrome.autohide-toolbox.unhide-by-native-ui.enabled"){ + :root[sizemode="maximized"]:not(:hover){ + #navigator-toolbox:not(:-moz-window-inactive), + #urlbar[popover]:not(:-moz-window-inactive){ + transition-delay: 33ms !important; + transform: rotateX(0); + opacity: 1; + } } } - } - #navigator-toolbox > *{ line-height: normal; pointer-events: auto } + /* swarsel: set pointer-events to none !important */ + #navigator-toolbox > *{ line-height: normal; pointer-events: none !important } - /* Don't apply transform before window has been fully created */ - :root:not([sessionrestored]) #navigator-toolbox{ transform:none !important } + /* swarsel: make toolbox clickable */ + :root[window-modal-open] #navigator-toolbox > *, + #mainPopupSet:has(> [panelopen]:not(#ask-chat-shortcuts,#selection-shortcut-action-panel,#chat-shortcuts-options-panel,#tab-preview-panel), > #tab-group-editor > [panelopen]) ~ toolbox > *, + #navigator-toolbox:has(#urlbar:is([open],[focus-within])) > *, + #navigator-toolbox:is(:focus-within,[movingtab],:hover) > * { + pointer-events: auto !important; + } - :root[customizing] #navigator-toolbox{ - position: relative !important; - transform: none !important; - opacity: 1 !important; - } + /* Don't apply transform before window has been fully created */ + :root:not([sessionrestored]) #navigator-toolbox{ transform:none !important } - #navigator-toolbox[inFullscreen] > #PersonalToolbar, - #PersonalToolbar:is([collapsed=""],[collapsed="true"]){ display: none } + :root[customizing] #navigator-toolbox{ + position: relative !important; + transform: none !important; + opacity: 1 !important; + } - /* This is a bit hacky fix for an issue that will make urlbar zero pixels tall after you enter customize mode */ - #urlbar[breakout][breakout-extend] > .urlbar-input-container{ - padding-block: calc(min(4px,(var(--urlbar-container-height) - var(--urlbar-height)) / 2) + var(--urlbar-container-padding)) !important; - } + #navigator-toolbox[inFullscreen] > #PersonalToolbar, + #PersonalToolbar:is([collapsed=""],[collapsed="true"]){ display: none } - /* Uncomment the following for compatibility with tabs_on_bottom.css - this isn't well tested though */ - /* - #navigator-toolbox{ flex-direction: column; display: flex; } - ,*/ + /* This is a bit hacky fix for an issue that will make urlbar zero pixels tall after you enter customize mode */ + #urlbar[breakout][breakout-extend] > .urlbar-input-container{ + padding-block: calc(min(4px,(var(--urlbar-container-height) - var(--urlbar-height)) / 2) + var(--urlbar-container-padding)) !important; + } + + /* Uncomment the following for compatibility with tabs_on_bottom.css - this isn't well tested though */ + /* + #navigator-toolbox{ flex-direction: column; display: flex; } + ,*/ #+end_src ** Default Flake Template diff --git a/files/emacs/early-init.el b/files/emacs/early-init.el index b86d1c1..891965d 100644 --- a/files/emacs/early-init.el +++ b/files/emacs/early-init.el @@ -2,22 +2,22 @@ (defvar swarsel-file-name-handler-alist file-name-handler-alist) (defvar swarsel-vc-handled-backends vc-handled-backends) + (defun swarsel/restore-startup-settings () + "Restore startup-tuned variables to their regular runtime values." + (setq gc-cons-threshold (* 32 1024 1024) + gc-cons-percentage 0.1 + jit-lock-defer-time 0.05 + read-process-output-max (* 1024 1024) + file-name-handler-alist swarsel-file-name-handler-alist + vc-handled-backends swarsel-vc-handled-backends) + (fset 'epg-wait-for-status #'ignore)) + (setq gc-cons-threshold most-positive-fixnum gc-cons-percentage 0.6 file-name-handler-alist nil vc-handled-backends nil) - (add-hook 'emacs-startup-hook - (lambda () - (progn - (setq gc-cons-threshold (* 32 1024 1024) - gc-cons-percentage 0.1 - jit-lock-defer-time 0.05 - read-process-output-max (* 1024 1024) - file-name-handler-alist swarsel-file-name-handler-alist - vc-handled-backends swarsel-vc-handled-backends) - (fset 'epg-wait-for-status 'ignore) - ))) + (add-hook 'emacs-startup-hook #'swarsel/restore-startup-settings) (tool-bar-mode 0) (menu-bar-mode 0) @@ -46,6 +46,7 @@ '(undecorated . t) ; no title bar, borders etc. '(background-color . "#1D252C") ; load doom-citylight colors to avoid white flash '(foreground-color . "#A0B3C5") ; load doom-citylight colors to avoid white flash + '(font . "FiraCode Nerd Font") '(vertical-scroll-bars . nil) '(horizontal-scroll-bars . nil) '(internal-border-width . 5) diff --git a/files/emacs/init.el b/files/emacs/init.el index f1adba1..b412785 100644 --- a/files/emacs/init.el +++ b/files/emacs/init.el @@ -213,7 +213,27 @@ create a new one." (swarsel/run-formatting) ))) -(setq org-html-htmlize-output-type nil) +(defun swarsel/org-babel-tangle-single-block-advice (orig-fun &rest args) + "Run ORIG-FUN with redisplay and messages temporarily inhibited." + (let ((inhibit-redisplay t) + (inhibit-message t)) + (apply orig-fun args))) + +(defun swarsel/org-babel-tangle-timing-advice (orig-fun &rest args) + "Run ORIG-FUN and report elapsed tangle time." + (let ((tim (current-time))) + (prog1 (apply orig-fun args) + (message "org-tangle took %f sec" (float-time (time-subtract (current-time) tim)))))) + +(defun swarsel/markdown-mode-keys () + "Local markdown key customizations." + (local-set-key (kbd "C-c C-x C-l") #'org-latex-preview) + (local-set-key (kbd "C-c C-x C-u") #'markdown-toggle-url-hiding)) + +(defun swarsel/eglot-ensure-and-format () + "Ensure eglot is running and enable format-on-save for current buffer." + (eglot-ensure) + (add-hook 'before-save-hook #'eglot-format nil 'local)) ;; (add-hook 'org-mode-hook (lambda () (add-hook 'after-save-hook #'swarsel/org-babel-tangle-config))) @@ -380,27 +400,27 @@ create a new one." "wm" '(delete-other-windows :wk "maximize") "" 'up-list "" 'down-list - )) + ) -;; General often used hotkeys -(general-define-key - "C-M-a" (lambda () (interactive) (org-capture nil "a")) ; make new anki card - "C-c d" 'crux-duplicate-current-line-or-region - "C-c D" 'crux-duplicate-and-comment-current-line-or-region - "" 'swarsel/last-buffer - "M-\\" 'indent-region - "M-r" 'swarsel/consult-magit-repos - "M-i" 'swarsel/org-insert-link-to-heading - "" 'yank - "" 'kill-region - "" 'kill-ring-save - "" 'evil-undo - "" 'evil-redo - "C-S-c C-S-c" 'mc/edit-lines - "C->" 'mc/mark-next-like-this - "C-<" 'mc/mark-previous-like-this - "C-c C-<" 'mc/mark-all-like-this - ) + ;; General often used hotkeys + (general-define-key + "C-M-a" (lambda () (interactive) (org-capture nil "a")) ; make new anki card + "C-c d" 'crux-duplicate-current-line-or-region + "C-c D" 'crux-duplicate-and-comment-current-line-or-region + "" 'swarsel/last-buffer + "M-\\" 'indent-region + "M-r" 'swarsel/consult-magit-repos + "M-i" 'swarsel/org-insert-link-to-heading + "" 'yank + "" 'kill-region + "" 'kill-ring-save + "" 'evil-undo + "" 'evil-redo + "C-S-c C-S-c" 'mc/edit-lines + "C->" 'mc/mark-next-like-this + "C-<" 'mc/mark-previous-like-this + "C-c C-<" 'mc/mark-all-like-this + )) ;; set Nextcloud directory for journals etc. (setq @@ -418,9 +438,10 @@ create a new one." url-history-file (expand-file-name "url/history" user-emacs-directory)) ;; Use no-littering to automatically set common paths to the new user-emacs-directory -(use-package no-littering) -(setq custom-file (make-temp-file "emacs-custom-")) -(load custom-file t) +(use-package no-littering + :config + (setq custom-file (make-temp-file "emacs-custom-")) + (load custom-file t)) (let ((backup-dir "~/tmp/emacs/backups") (auto-saves-dir "~/tmp/emacs/auto-saves/")) @@ -437,22 +458,20 @@ create a new one." delete-old-versions t ; Clean up the backups version-control t ; Use version numbers on backups, kept-new-versions 5 ; keep some new versions - kept-old-versions 2) ; and some old ones, too + kept-old-versions 2 ; and some old ones, too + backup-by-copying-when-linked t) ;; use UTF-8 everywhere (set-language-environment "UTF-8") ;; (profiler-start 'cpu) ;; set default font size -(defvar swarsel/default-font-size 130) -(setq swarsel-standard-font "FiraCode Nerd Font Mono" - swarsel-alt-font "FiraCode Nerd Font Mono") ;; (defalias 'yes-or-no-p 'y-or-n-p) ;;(setq-default show-trailing-whitespace t) (add-hook 'before-save-hook 'delete-trailing-whitespace) (global-hl-line-mode 1) ;; (setq redisplay-dont-pause t) ;; obsolete -(setq blink-cursor-mode nil) ;; blink-cursor is an unexpected source of slowdown +(blink-cursor-mode -1) ;; blink-cursor is an unexpected source of slowdown (global-subword-mode 1) ; Iterate through CamelCase words (setq blink-matching-paren nil) ;; this makes the cursor jump around annoyingly (delete-selection-mode 1) @@ -464,7 +483,6 @@ create a new one." bidi-display-reordering 'left-to-right bidi-inhibit-bpa t) (global-so-long-mode) -(setq process-adaptive-read-buffering nil) ;; not sure if this is a good idea (setq fast-but-imprecise-scrolling t redisplay-skip-fontification-on-input t inhibit-compacting-font-caches t) @@ -472,9 +490,7 @@ create a new one." which-func-update-delay 1.0) (setq undo-limit 80000000 evil-want-fine-undo t - auto-save-default t - password-cache-expiry nil - ) + auto-save-default t) (setq browse-url-browser-function 'browse-url-firefox) ;; (setenv "DISPLAY" ":0") ;; needed for firefox ;; disable a keybind that does more harm than good @@ -519,16 +535,18 @@ create a new one." tab-width 2) (setq tab-always-indent 'complete) -(setq python-indent-guess-indent-offset-verbose nil) + +(use-package python + :ensure nil + :custom + (python-indent-guess-indent-offset-verbose nil)) (use-package highlight-indent-guides :hook (prog-mode . highlight-indent-guides-mode) - :init - (setq highlight-indent-guides-method 'column) - (setq highlight-indent-guides-responsive 'top) - ) - -(with-eval-after-load 'highlight-indent-guides + :custom + (highlight-indent-guides-method 'column) + (highlight-indent-guides-responsive nil) + :config (set-face-attribute 'highlight-indent-guides-even-face nil :background "gray10") (set-face-attribute 'highlight-indent-guides-odd-face nil :background "gray20") (set-face-attribute 'highlight-indent-guides-stack-even-face nil :background "gray40") @@ -598,8 +616,7 @@ create a new one." (use-package evil-collection :after evil :config - (evil-collection-init) - (setq forge-add-default-bindings nil)) + (evil-collection-init)) ;; enables 2-char inline search (use-package evil-snipe @@ -619,34 +636,28 @@ create a new one." (global-evil-surround-mode 1)) (use-package evil-visual-mark-mode - :config (evil-visual-mark-mode)) + :commands evil-visual-mark-mode) -(use-package evil-textobj-tree-sitter) -;; bind `function.outer`(entire function block) to `f` for use in things like `vaf`, `yaf` -(define-key evil-outer-text-objects-map "f" (evil-textobj-tree-sitter-get-textobj "function.outer")) -;; bind `function.inner`(function block without name and args) to `f` for use in things like `vif`, `yif` -(define-key evil-inner-text-objects-map "f" (evil-textobj-tree-sitter-get-textobj "function.inner")) - -;; You can also bind multiple items and we will match the first one we can find -(define-key evil-outer-text-objects-map "a" (evil-textobj-tree-sitter-get-textobj ("if_statement.outer" "conditional.outer" "loop.outer") '((python-mode . ((if_statement.outer) @if_statement.outer)) (python-ts-mode . ((if_statement.outer) @if_statement.outer))))) +(use-package evil-textobj-tree-sitter + :config + ;; bind `function.outer`(entire function block) to `f` for use in things like `vaf`, `yaf` + (define-key evil-outer-text-objects-map "f" (evil-textobj-tree-sitter-get-textobj "function.outer")) + ;; bind `function.inner`(function block without name and args) to `f` for use in things like `vif`, `yif` + (define-key evil-inner-text-objects-map "f" (evil-textobj-tree-sitter-get-textobj "function.inner")) + ;; You can also bind multiple items and we will match the first one we can find + (define-key evil-outer-text-objects-map "a" (evil-textobj-tree-sitter-get-textobj ("if_statement.outer" "conditional.outer" "loop.outer") '((python-mode . ((if_statement.outer) @if_statement.outer)) (python-ts-mode . ((if_statement.outer) @if_statement.outer)))))) (use-package evil-numbers) ;; set the NixOS wordlist by hand (setq ispell-alternate-dictionary (getenv "WORDLIST")) -(dolist (face '(default fixed-pitch)) - (set-face-attribute face nil - :font "FiraCode Nerd Font Mono")) -(add-to-list 'default-frame-alist '(font . "FiraCode Nerd Font Mono")) +(setq swarsel/fixed-font "FiraCode Nerd Font" + swarsel/variable-font "Iosevka Aile") -(set-face-attribute 'default nil :height 100) -(set-face-attribute 'fixed-pitch nil :height 1.0) - -(set-face-attribute 'variable-pitch nil - :family "IBM Plex Sans" - :weight 'regular - :height 1.06) +(set-face-attribute 'default nil :font swarsel/fixed-font :height 100) +(set-face-attribute 'fixed-pitch nil :font swarsel/fixed-font :height 130) +(set-face-attribute 'variable-pitch nil :font swarsel/variable-font :weight 'light :height 130) (use-package solaire-mode :custom @@ -681,21 +692,21 @@ create a new one." (use-package mini-modeline :after smart-mode-line + :custom + (mini-modeline-display-gui-line nil) + (mini-modeline-enhance-visual nil) + (mini-modeline-truncate-p nil) + (mini-modeline-l-format nil) + (mini-modeline-right-padding 5) + (mini-modeline-r-format '("%e" mode-line-front-space mode-line-mule-info mode-line-client + mode-line-modified mode-line-remote mode-line-frame-identification + mode-line-buffer-identification " " mode-line-position " " mode-name evil-mode-line-tag)) :config (mini-modeline-mode t) - (setq mini-modeline-display-gui-line nil) - (setq mini-modeline-enhance-visual nil) - (setq mini-modeline-truncate-p nil) - (setq mini-modeline-l-format nil) - (setq mini-modeline-right-padding 5) - (setq window-divider-mode t) - (setq window-divider-default-places t) - (setq window-divider-default-bottom-width 1) - (setq window-divider-default-right-width 1) - (setq mini-modeline-r-format '("%e" mode-line-front-space mode-line-mule-info mode-line-client - mode-line-modified mode-line-remote mode-line-frame-identification - mode-line-buffer-identification " " mode-line-position " " mode-name evil-mode-line-tag )) - ) + (setq window-divider-default-places t + window-divider-default-bottom-width 1 + window-divider-default-right-width 1) + (window-divider-mode 1)) (use-package smart-mode-line :config @@ -746,8 +757,8 @@ create a new one." orderless-matching-styles '(orderless-literal orderless-regexp))) (use-package consult - :config - (setq consult-fontify-max-size 1024) + :custom + (consult-fontify-max-size 1024) :bind (("C-x b" . consult-buffer) ("C-c " . consult-global-mark) @@ -803,8 +814,8 @@ create a new one." (use-package which-key :init (which-key-mode) :diminish which-key-mode - :config - (setq which-key-idle-delay 0.3)) + :custom + (which-key-idle-delay 0.3)) (use-package helpful :bind @@ -812,8 +823,8 @@ create a new one." ("C-h v" . helpful-variable) ("C-h k" . helpful-key) ("C-h C-." . helpful-at-point)) - :config - (setq help-window-select nil)) + :custom + (help-window-select nil)) (use-package ligature :init @@ -901,6 +912,13 @@ create a new one." :bind (("C-" . org-fold-outer) ("C-c s" . org-store-link)) + :custom + (org-html-htmlize-output-type nil) + (org-fold-core-style 'overlays) + (org-src-preserve-indentation nil) + (org-src-fontify-natively t) + (org-export-with-broken-links 'mark) + (org-confirm-babel-evaluate nil) :config (setq org-ellipsis " ⤵" org-link-descriptive t @@ -909,6 +927,7 @@ create a new one." (setq org-support-shift-select t) (setq org-agenda-start-with-log-mode t) + (setq org-fontify-quote-and-verse-blocks t) (setq org-log-done 'time) (setq org-log-into-drawer t) (setq org-startup-with-inline-images t) @@ -923,13 +942,54 @@ create a new one." (setq org-capture-templates '(("t" "Todo" entry (file+headline "~/Org/Tasks.org" "Inbox") "* TODO %?\n %i\n %a") - ("j" "Journal" entry (file+datetree "~/Org/Journal.org") + ("j" "Journal" entry (file+olp+datetree "~/Org/Journal.org") "* %?\nEntered on %U\n %i\n %a"))) (setq org-refile-targets '((swarsel-archive-org-file :maxlevel . 1) (swarsel-tasks-org-file :maxlevel . 1))) + (org-babel-do-load-languages + 'org-babel-load-languages + '((emacs-lisp . t) + (python . t) + (js . t) + (shell . t))) + + (set-face-attribute 'org-block nil :foreground nil :inherit 'fixed-pitch) + (set-face-attribute 'org-table nil :inherit 'fixed-pitch) + (set-face-attribute 'org-formula nil :inherit 'fixed-pitch) + (set-face-attribute 'org-code nil :inherit '(shadow fixed-pitch)) + (set-face-attribute 'org-quote nil :inherit '(shadow fixed-pitch)) + (set-face-attribute 'org-verse nil :inherit '(shadow fixed-pitch)) + (set-face-attribute 'org-verbatim nil :inherit '(shadow fixed-pitch)) + (set-face-attribute 'org-special-keyword nil :inherit '(font-lock-comment-face fixed-pitch)) + (set-face-attribute 'org-meta-line nil :inherit '(font-lock-comment-face fixed-pitch)) + (set-face-attribute 'org-checkbox nil :inherit 'fixed-pitch) + + + (dolist (face '((org-level-1 . 1.2) + (org-level-2 . 1.1) + (org-level-3 . 1.0) + (org-level-4 . 1.0) + (org-level-5 . 1.0) + (org-level-6 . 1.0) + (org-level-7 . 1.0) + (org-level-8 . 1.0))) + (set-face-attribute (car face) nil :font swarsel/variable-font :weight 'medium :height (cdr face))) + + (add-to-list 'org-src-lang-modes '("conf-unix" . conf-unix)) + + (advice-add 'org-babel-tangle-single-block :around #'swarsel/org-babel-tangle-single-block-advice) + (advice-add 'org-babel-tangle :around #'swarsel/org-babel-tangle-timing-advice) + + (require 'org-tempo) + (add-to-list 'org-structure-template-alist '("sh" . "src shell")) + (add-to-list 'org-structure-template-alist '("el" . "src emacs-lisp")) + (add-to-list 'org-structure-template-alist '("py" . "src python :results output")) + (add-to-list 'org-structure-template-alist '("nix" . "src nix-ts :tangle")) + (add-to-list 'org-structure-template-alist '("ne" . "bash :exports both")) + ) (use-package org-appear @@ -943,64 +1003,24 @@ create a new one." (use-package visual-fill-column :hook (org-mode . swarsel/org-mode-visual-fill)) -(setq org-fold-core-style 'overlays) +(use-package auctex + :hook ((LaTeX-mode . visual-line-mode) + (LaTeX-mode . flyspell-mode) + (LaTeX-mode . LaTeX-math-mode) + (LaTeX-mode . reftex-mode)) + :custom + (TeX-auto-save t) + (TeX-save-query nil) + (TeX-parse-self t) + (TeX-engine 'luatex) + (TeX-master nil) + (LaTeX-electric-left-right-brace t) + (font-latex-fontify-script nil) + (TeX-electric-sub-and-superscript t)) -(setq org-src-preserve-indentation nil) - -(org-babel-do-load-languages - 'org-babel-load-languages - '((emacs-lisp . t) - (python . t) - (js . t) - (shell . t) - )) - -(push '("conf-unix" . conf-unix) org-src-lang-modes) - -(setq org-export-with-broken-links 'mark) -(setq org-confirm-babel-evaluate nil) - -;; tangle is too slow, try to speed it up -(defadvice org-babel-tangle-single-block (around inhibit-redisplay activate protect compile) - "inhibit-redisplay and inhibit-message to avoid flicker." - (let ((inhibit-redisplay t) - (inhibit-message t)) - ad-do-it)) - -(defadvice org-babel-tangle (around time-it activate compile) - "Display the execution time" - (let ((tim (current-time))) - ad-do-it - (message "org-tangle took %f sec" (float-time (time-subtract (current-time) tim))))) - -(require 'org-tempo) -(add-to-list 'org-structure-template-alist '("sh" . "src shell")) -(add-to-list 'org-structure-template-alist '("el" . "src emacs-lisp")) -(add-to-list 'org-structure-template-alist '("py" . "src python :results output")) -(add-to-list 'org-structure-template-alist '("nix" . "src nix-ts :tangle")) -(add-to-list 'org-structure-template-alist '("ne" . "bash :exports both")) - -(use-package auctex) -(setq TeX-auto-save t) -(setq TeX-save-query nil) -(setq TeX-parse-self t) -(setq-default TeX-engine 'luatex) -(setq-default TeX-master nil) - -(add-hook 'LaTeX-mode-hook 'visual-line-mode) -(add-hook 'LaTeX-mode-hook 'flyspell-mode) -(add-hook 'LaTeX-mode-hook 'LaTeX-math-mode) -(add-hook 'LaTeX-mode-hook 'reftex-mode) -(setq LaTeX-electric-left-right-brace t) -(setq font-latex-fontify-script nil) -(setq TeX-electric-sub-and-superscript t) -;; (setq reftex-plug-into-AUCTeX t) - - - -(use-package org-fragtog) -(add-hook 'org-mode-hook 'org-fragtog-mode) -(add-hook 'markdown-mode-hook 'org-fragtog-mode) +(use-package org-fragtog + :hook ((org-mode . org-fragtog-mode) + (markdown-mode . org-fragtog-mode))) (use-package org-modern :config (setq org-modern-block-name @@ -1017,6 +1037,8 @@ create a new one." ("" . swarsel/org-present-next)) :hook ((org-present-mode . swarsel/org-present-start) (org-present-mode-quit . swarsel/org-present-end)) + :config + (add-hook 'org-present-after-navigate-functions #'swarsel/org-present-slide) ) @@ -1026,8 +1048,11 @@ create a new one." (setq-local face-remapping-alist '((default (:height 1.5) variable-pitch) (header-line (:height 4.0) variable-pitch) (org-document-title (:height 1.75) org-document-title) - (org-code (:height 1.55) org-code) - (org-verbatim (:height 1.55) org-verbatim) + (org-code (:height 1.2) org-code) + (org-verbatim (:height 1.0) org-verbatim) + (org-quote (:height 1.0) org-quote) + (org-verse (:height 1.0) org-verse) + (org-table (:height 0.8) org-table) (org-block (:height 1.25) org-block) (org-block-begin-line (:height 0.7) org-block) )) @@ -1039,7 +1064,7 @@ create a new one." (org-level-6 . 1.2) (org-level-7 . 1.2) (org-level-8 . 1.2))) - (set-face-attribute (car face) nil :font swarsel-alt-font :weight 'medium :height (cdr face))) + (set-face-attribute (car face) nil :font swarsel/variable-font :weight 'medium :height (cdr face))) (setq header-line-format " ") (setq visual-fill-column-width 90) @@ -1067,7 +1092,7 @@ create a new one." (org-level-6 . 0.9) (org-level-7 . 0.9) (org-level-8 . 0.9))) - (set-face-attribute (car face) nil :font swarsel-alt-font :weight 'medium :height (cdr face))) + (set-face-attribute (car face) nil :font swarsel/variable-font :weight 'medium :height (cdr face))) (setq header-line-format nil) (setq visual-fill-column-width 150) (setq indicate-buffer-boundaries t) @@ -1102,14 +1127,6 @@ create a new one." (swarsel/org-present-slide) )) -(defun clojure-leave-clojure-mode-function () - ) - -(add-hook 'buffer-list-update-hook #'clojure-leave-clojure-mode-function) -(add-hook 'org-present-mode-hook 'swarsel/org-present-start) -(add-hook 'org-present-mode-quit-hook 'swarsel/org-present-end) -(add-hook 'org-present-after-navigate-functions 'swarsel/org-present-slide) - (defun org-babel-execute:markdown (body params) "Just return BODY unchanged, allowing noweb expansion." body) @@ -1145,21 +1162,10 @@ create a new one." lsp-nix-nixd-home-manager-options-expr "(builtins.getFlake \"/home/swarsel/.dotfiles\").nixosConfigurations.pyramid.options.home-manager.users.type.getSubOptions []" )) -(add-to-list 'auto-mode-alist '("\\.nix\\.enc\\'" . nix-mode)) -(add-to-list 'auto-mode-alist '("\\.nix\\.enc\\'" . nix-ts-mode)) - - -(with-eval-after-load 'lsp-mode - (lsp-register-client - (make-lsp-client :new-connection (lsp-stdio-connection "nixd") - :major-modes '(nix-mode nix-ts-mode) - :priority 0 - :server-id 'nixd))) - (use-package hcl-mode :mode "\\.hcl\\'" - :config - (setq hcl-indent-level 2)) + :custom + (hcl-indent-level 2)) (use-package groovy-mode) @@ -1173,65 +1179,60 @@ create a new one." (use-package terraform-mode :mode "\\.tf\\'" - :config - (setq terraform-indent-level 2) - (setq terraform-format-on-save t)) - -(add-hook 'terraform-mode-hook #'outline-minor-mode) + :hook (terraform-mode . outline-minor-mode) + :custom + (terraform-indent-level 2) + (terraform-format-on-save t)) (use-package nixpkgs-fmt) (use-package shfmt - :config - (setq shfmt-command "shfmt") - (setq shfmt-arguments '("-i" "4" "-s" "-sr"))) - -(setq markdown-command "pandoc") + :custom + (shfmt-command "shfmt") + (shfmt-arguments '("-i" "4" "-s" "-sr"))) (use-package markdown-mode :ensure t :mode ("README\\.md\\'" . gfm-mode) - :init (setq markdown-command "multimarkdown") + :init + (setq markdown-command "multimarkdown") + :hook (markdown-mode . swarsel/markdown-mode-keys) :bind (:map markdown-mode-map - ("C-c C-e" . markdown-do))) + ("C-c C-e" . markdown-do) + ("C-c C-x C-l" . org-latex-preview) + ("C-c C-x C-u" . markdown-toggle-url-hiding))) -(add-hook 'markdown-mode-hook - (lambda () - (local-set-key (kbd "C-c C-x C-l") 'org-latex-preview) - (local-set-key (kbd "C-c C-x C-u") 'markdown-toggle-url-hiding) - )) - -(use-package elfeed) - -(use-package elfeed-goodies) -(elfeed-goodies/setup) - -(setq elfeed-db-directory "~/.elfeed/db/") +(use-package elfeed + :custom + (elfeed-db-directory "~/.elfeed/db/") + (elfeed-use-curl t) + (elfeed-set-timeout 36000) + :config + (define-key elfeed-show-mode-map (kbd ";") #'visual-fill-column-mode) + (define-key elfeed-show-mode-map (kbd "j") #'elfeed-goodies/split-show-next) + (define-key elfeed-show-mode-map (kbd "k") #'elfeed-goodies/split-show-prev) + (define-key elfeed-search-mode-map (kbd "j") #'next-line) + (define-key elfeed-search-mode-map (kbd "k") #'previous-line) + (define-key elfeed-show-mode-map (kbd "S-SPC") #'scroll-down-command)) +(use-package elfeed-goodies + :after elfeed + :config + (elfeed-goodies/setup)) (use-package elfeed-protocol - :after elfeed) - -(elfeed-protocol-enable) -(setq elfeed-use-curl t) -(setq elfeed-set-timeout 36000) -(setq elfeed-protocol-enabled-protocols '(fever)) -(setq elfeed-protocol-fever-update-unread-only t) -(setq elfeed-protocol-fever-fetch-category-as-tag t) - -(let ((domain (getenv "SWARSEL_RSS_DOMAIN"))) - (setq elfeed-protocol-feeds - `((,(concat "fever+https://Swarsel@" domain) - :api-url ,(concat "https://" domain "/api/fever.php") - :password-file "~/.emacs.d/.fever")))) - - -(define-key elfeed-show-mode-map (kbd ";") 'visual-fill-column-mode) -(define-key elfeed-show-mode-map (kbd "j") 'elfeed-goodies/split-show-next) -(define-key elfeed-show-mode-map (kbd "k") 'elfeed-goodies/split-show-prev) -(define-key elfeed-search-mode-map (kbd "j") 'next-line) -(define-key elfeed-search-mode-map (kbd "k") 'previous-line) -(define-key elfeed-show-mode-map (kbd "S-SPC") 'scroll-down-command) + :after elfeed + :custom + (elfeed-protocol-enabled-protocols '(fever)) + (elfeed-protocol-fever-update-unread-only t) + (elfeed-protocol-fever-fetch-category-as-tag t) + :config + (elfeed-protocol-enable) + (let ((domain (getenv "SWARSEL_RSS_DOMAIN"))) + (setq elfeed-protocol-feeds + `((,(concat "fever+https://Swarsel@" domain) + :api-url ,(concat "https://" domain "/api/fever.php") + :password-file "~/.emacs.d/.fever"))))) (use-package rg) @@ -1266,7 +1267,7 @@ create a new one." (use-package treesit-auto :custom - (setq treesit-auto-install t) + (treesit-auto-install t) :config (treesit-auto-add-to-auto-mode-alist 'all) (global-treesit-auto-mode)) @@ -1281,25 +1282,17 @@ create a new one." (use-package avy :bind (("M-o" . avy-goto-char-timer)) - :config - (setq avy-all-windows 'all-frames)) + :custom + (avy-all-windows 'all-frames)) -(use-package devdocs) - -(add-hook 'python-mode-hook - (lambda () (setq-local devdocs-current-docs '("python~3.12" "numpy~1.23" "matplotlib~3.7" "pandas~1")))) -(add-hook 'python-ts-mode-hook - (lambda () (setq-local devdocs-current-docs '("python~3.12" "numpy~1.23" "matplotlib~3.7" "pandas~1")))) - -(add-hook 'c-mode-hook - (lambda () (setq-local devdocs-current-docs '("c")))) -(add-hook 'c-ts-mode-hook - (lambda () (setq-local devdocs-current-docs '("c")))) - -(add-hook 'c++-mode-hook - (lambda () (setq-local devdocs-current-docs '("cpp")))) -(add-hook 'c++-ts-mode-hook - (lambda () (setq-local devdocs-current-docs '("cpp")))) +(use-package devdocs + :hook ((python-mode . (lambda () (setq-local devdocs-current-docs '("python~3.12" "numpy~1.23" "matplotlib~3.7" "pandas~1")))) + (python-ts-mode . (lambda () (setq-local devdocs-current-docs '("python~3.12" "numpy~1.23" "matplotlib~3.7" "pandas~1")))) + (c-mode . (lambda () (setq-local devdocs-current-docs '("c")))) + (c-ts-mode . (lambda () (setq-local devdocs-current-docs '("c")))) + (c++-mode . (lambda () (setq-local devdocs-current-docs '("cpp")))) + (c++-ts-mode . (lambda () (setq-local devdocs-current-docs '("cpp"))))) + ) ; (devdocs-update-all) @@ -1326,13 +1319,16 @@ create a new one." ;; yubikey support for pushing commits ;; commiting is enabled through nixos gpg-agent config -(use-package pinentry) -(pinentry-start) -(setq epg-pinentry-mode 'loopback) -(setenv "SSH_AUTH_SOCK" (string-chop-newline (shell-command-to-string "gpgconf --list-dirs agent-ssh-socket"))) +(use-package pinentry + :config + (pinentry-start) + (setq epg-pinentry-mode 'loopback) + (setenv "SSH_AUTH_SOCK" (string-chop-newline (shell-command-to-string "gpgconf --list-dirs agent-ssh-socket")))) (use-package forge - :after magit) + :after magit + :init + (setq forge-add-default-bindings nil)) (use-package git-timemachine :hook (git-time-machine-mode . evil-normalize-keymaps) @@ -1361,7 +1357,7 @@ create a new one." ;; (if (char-equal c ?<) t (,electric-pair-inhibit-predicate c)))))) (use-package rainbow-mode - :config (rainbow-mode)) + :hook ((css-mode css-ts-mode web-mode html-mode html-ts-mode) . rainbow-mode)) (use-package corfu :init @@ -1394,15 +1390,15 @@ create a new one." (" " . swarsel/corfu-quit-and-down)) ) -(use-package nerd-icons-corfu) - -(add-to-list 'corfu-margin-formatters #'nerd-icons-corfu-formatter) - -(setq nerd-icons-corfu-mapping - '((array :style "cod" :icon "symbol_array" :face font-lock-type-face) - (boolean :style "cod" :icon "symbol_boolean" :face font-lock-builtin-face) - ;; ... - (t :style "cod" :icon "code" :face font-lock-warning-face))) +(use-package nerd-icons-corfu + :after corfu + :config + (add-to-list 'corfu-margin-formatters #'nerd-icons-corfu-formatter) + (setq nerd-icons-corfu-mapping + '((array :style "cod" :icon "symbol_array" :face font-lock-type-face) + (boolean :style "cod" :icon "symbol_boolean" :face font-lock-builtin-face) + ;; ... + (t :style "cod" :icon "code" :face font-lock-warning-face)))) (use-package cape :bind @@ -1460,14 +1456,11 @@ create a new one." "-o ControlMaster=auto -o ControlPersist=yes")) ) -(setq vterm-tramp-shells '(("ssh" "'sh'"))) - (use-package diff-hl :hook ((prog-mode org-mode) . diff-hl-mode) :init - (diff-hl-flydiff-mode) (diff-hl-margin-mode) (diff-hl-show-hunk-mouse-mode)) @@ -1488,19 +1481,17 @@ create a new one." ;;rustic-mode tex-mode LaTeX-mode - ) . (lambda () (progn - (eglot-ensure) - (add-hook 'before-save-hook 'eglot-format nil 'local)))) + ) . swarsel/eglot-ensure-and-format) :custom (eldoc-echo-area-use-multiline-p nil) - (completion-category-defaults nil) - (fset #'jsonrpc--log-event #'ignore) (eglot-events-buffer-size 0) (eglot-sync-connect nil) (eglot-connect-timeout nil) (eglot-autoshutdown t) (eglot-send-changes-idle-time 3) (flymake-no-changes-timeout 5) + :config + (fset #'jsonrpc--log-event #'ignore) :bind (:map eglot-mode-map ("M-(" . flymake-goto-next-error) ("C-c ," . eglot-code-actions))) @@ -1518,7 +1509,13 @@ create a new one." ;; set prefix for lsp-command-keymap (few alternatives - "C-l", "C-c l") (setq lsp-keymap-prefix "C-c l") (setq lsp-auto-guess-root "t") - :commands lsp) + :commands lsp + :config + (lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection "nixd") + :major-modes '(nix-mode nix-ts-mode) + :priority 0 + :server-id 'nixd))) ;; (use-package company) @@ -1562,8 +1559,6 @@ create a new one." ; 'line to show errors on the current line (setq sideline-backends-right '(sideline-flymake))) -(setq backup-by-copying-when-linked t) - (use-package dirvish :init (dirvish-override-dired-mode) @@ -1638,6 +1633,8 @@ create a new one." :ensure nil ;; :load-path "/usr/share/emacs/site-lisp/mu4e/" ;;:defer 20 ; Wait until 20 seconds after startup + :hook ((mu4e-compose-mode . swarsel/mu4e-send-from-correct-address) + (mu4e-compose-post . swarsel/mu4e-restore-default)) :config ;; This is set to 't' to avoid mail syncing issues when using mbsync @@ -1681,12 +1678,31 @@ create a new one." ;; this does the equivalent of (setq mu4e-user-mail-address-list '(address1@about.com address2@about.com [...]))) (setq mu4e-user-mail-address-list (mapcar #'intern (split-string (or (getenv "SWARSEL_MAIL_ALL") "") "[ ,]+" t))) + + (setq mu4e--log-max-size 1000) + + (mu4e t) + + (let ((work (getenv "SWARSEL_MAIL_WORK"))) + (when (and work (not (string-empty-p work))) + (setq swarsel-smime-cert-path "~/.Certificates/$SWARSEL_MAIL_WORK.pem") + (setq swarsel-smime-cert-path (substitute-env-vars swarsel-smime-cert-path)) + (setq mml-secure-prefer-scheme 'smime) + (setq mml-secure-smime-sign-with-sender t) + (add-hook 'mu4e-compose-mode-hook + (lambda () + (when (and (boundp 'user-mail-address) + (stringp user-mail-address) + (string-equal user-mail-address (getenv "SWARSEL_MAIL_WORK"))) + (mml-secure-message-sign-smime)))) + (setq smime-keys + `((,(getenv "SWARSEL_MAIL_WORK") + ,swarsel-smime-cert-path + ("~/Certificates/harica-root.pem" + "~/Certificates/harica-intermediate.pem")))) + )) ) - -(add-hook 'mu4e-compose-mode-hook #'swarsel/mu4e-send-from-correct-address) -(add-hook 'mu4e-compose-post-hook #'swarsel/mu4e-restore-default) - (use-package mu4e-alert :config (mu4e-alert-enable-notifications) @@ -1704,30 +1720,6 @@ create a new one." (add-hook 'after-init-hook #'mu4e-alert-enable-notifications) ) -(mu4e t) - -(let ((work (getenv "SWARSEL_MAIL_WORK"))) - (when (and work (not (string-empty-p work))) - - (setq swarsel-smime-cert-path "~/.Certificates/$SWARSEL_MAIL_WORK.pem") - (setq swarsel-smime-cert-path (substitute-env-vars swarsel-smime-cert-path)) - (setq mml-secure-prefer-scheme 'smime) - (setq mml-secure-smime-sign-with-sender t) - (add-hook 'mu4e-compose-mode-hook - (lambda () - (when (and (boundp 'user-mail-address) - (stringp user-mail-address) - (string-equal user-mail-address (getenv "SWARSEL_MAIL_WORK"))) - (mml-secure-message-sign-smime)))) - - (setq smime-keys - `((,(getenv "SWARSEL_MAIL_WORK") - ,swarsel-smime-cert-path - ("~/Certificates/harica-root.pem" - "~/Certificates/harica-intermediate.pem" - )))) - )) - (use-package org-caldav :init ;; set org-caldav-sync-initalization @@ -1851,20 +1843,24 @@ create a new one." ( (,"󱄅" ,swarsel-domain - ,(concat "Browse " main-domain) + ,(concat "Browse " swarsel-domain) (lambda (&rest _) (browse-url ,(concat "https://" swarsel-domain)))) ) )))) -(add-to-list 'recentf-exclude "\\Archive\\.org\\'") -(add-to-list 'recentf-exclude "\\Tasks\\.org\\'") +(use-package recentf + :ensure nil + :config + (add-to-list 'recentf-exclude "\\Archive\\.org\\'") + (add-to-list 'recentf-exclude "\\Tasks\\.org\\'")) (use-package vterm - :ensure t) + :ensure t + :custom + (vterm-tramp-shells '(("ssh" "'sh'")))) (use-package multiple-cursors) -(setq mu4e--log-max-size 1000) (setq message-log-max 30) (setq comint-buffer-maximum-size 50) (add-hook 'comint-output-filter-functions 'comint-truncate-buffer) diff --git a/files/firefox/chrome/userChrome.css b/files/firefox/chrome/userChrome.css index c616488..cbdbd98 100644 --- a/files/firefox/chrome/userChrome.css +++ b/files/firefox/chrome/userChrome.css @@ -8,7 +8,7 @@ See the above repository for updates as well as full license text. */ :root{ --uc-autohide-toolbox-delay: 200ms; /* Wait 0.1s before hiding toolbars */ --uc-toolbox-rotation: 82deg; /* This may need to be lower on mac - like 75 or so */ - + /* swarsel: added colorscheme */ --base00: #1D252C; --base01: #171D23; --base02: #5EC4FF; @@ -63,9 +63,9 @@ See the above repository for updates as well as full license text. */ :root[window-modal-open] #urlbar[popover], #mainPopupSet:has(> [panelopen]:not(#ask-chat-shortcuts,#selection-shortcut-action-panel,#chat-shortcuts-options-panel,#tab-preview-panel), > #tab-group-editor > [panelopen]) ~ toolbox #urlbar[popover], - /* swarsel: removed :hover from below line */ +/* swarsel: removed hover from next line */ #navigator-toolbox:is(:focus-within,[movingtab]) #urlbar[popover], -#urlbar-container > #urlbar[popover]:is([focused],[open]){ +:where(:root[sessionrestored]) #urlbar-container > #urlbar[popover]:is([focused],[open]){ pointer-events: auto; opacity: 1; transition-delay: 33ms; @@ -75,7 +75,7 @@ See the above repository for updates as well as full license text. */ :root[window-modal-open] #navigator-toolbox, #mainPopupSet:has(> [panelopen]:not(#ask-chat-shortcuts,#selection-shortcut-action-panel,#chat-shortcuts-options-panel,#tab-preview-panel), > #tab-group-editor > [panelopen]) ~ toolbox, #navigator-toolbox:has(#urlbar:is([open],[focus-within])), - /* swarsel: removed :hover from below line */ +/* swarsel: removed hover from next line */ #navigator-toolbox:is(:focus-within,[movingtab]){ transition-delay: 33ms !important; transform: rotateX(0); @@ -95,7 +95,16 @@ See the above repository for updates as well as full license text. */ } } -#navigator-toolbox > *{ line-height: normal; pointer-events: auto } +/* swarsel: set pointer-events to none !important */ +#navigator-toolbox > *{ line-height: normal; pointer-events: none !important } + +/* swarsel: make toolbox clickable */ +:root[window-modal-open] #navigator-toolbox > *, +#mainPopupSet:has(> [panelopen]:not(#ask-chat-shortcuts,#selection-shortcut-action-panel,#chat-shortcuts-options-panel,#tab-preview-panel), > #tab-group-editor > [panelopen]) ~ toolbox > *, +#navigator-toolbox:has(#urlbar:is([open],[focus-within])) > *, +#navigator-toolbox:is(:focus-within,[movingtab],:hover) > * { + pointer-events: auto !important; +} /* Don't apply transform before window has been fully created */ :root:not([sessionrestored]) #navigator-toolbox{ transform:none !important } diff --git a/files/scripts/command-not-found.sh b/files/scripts/command-not-found.sh deleted file mode 100644 index c81cb7a..0000000 --- a/files/scripts/command-not-found.sh +++ /dev/null @@ -1,33 +0,0 @@ -# Adapted from https://github.com/bennofs/nix-index/blob/master/command-not-found.sh -command_not_found_handle() { - if [ -n "${MC_SID-}" ] || ! [ -t 1 ]; then - >&2 echo "$1: command not found" - return 127 - fi - - echo -n "searching nix-index..." - ATTRS=$(@nix-locate@ --minimal --no-group --type x --type s --whole-name --at-root "/bin/$1") - - case $(echo -n "$ATTRS" | grep -c "^") in - 0) - >&2 echo -ne "$(@tput@ el1)\r" - >&2 echo "$1: command not found" - ;; - *) - >&2 echo -ne "$(@tput@ el1)\r" - >&2 echo "The program ‘$(@tput@ setaf 4)$1$(@tput@ sgr0)’ is currently not installed." - >&2 echo "It is provided by the following derivation(s):" - while read -r ATTR; do - ATTR=${ATTR%.out} - >&2 echo " $(@tput@ setaf 12)nixpkgs#$(@tput@ setaf 4)$ATTR$(@tput@ sgr0)" - done <<< "$ATTRS" - ;; - esac - - return 127 -} - -command_not_found_handler() { - command_not_found_handle "$@" - return $? -} diff --git a/files/scripts/e.sh b/files/scripts/e.sh deleted file mode 100644 index 7fda8f5..0000000 --- a/files/scripts/e.sh +++ /dev/null @@ -1,23 +0,0 @@ -wait=0 -while :; do - case ${1:-} in - -w | --wait) - wait=1 - ;; - *) break ;; - esac - shift -done - -STR=$(swaymsg -t get_tree | jq -r 'recurse(.nodes[]) | select(.name == "__i3_scratch")' | grep kittyterm || true) -if [ "$STR" == "" ]; then - swaymsg '[title="kittyterm"]' scratchpad show - emacsclient -c -a "" "$@" - swaymsg '[title="kittyterm"]' scratchpad show -else - if [[ $wait -eq 0 ]]; then - emacsclient -n -c -a "" "$@" - else - emacsclient -c -a "" "$@" - fi -fi diff --git a/files/scripts/fs-diff.sh b/files/scripts/fs-diff.sh deleted file mode 100644 index 1bc16af..0000000 --- a/files/scripts/fs-diff.sh +++ /dev/null @@ -1,20 +0,0 @@ -set -euo pipefail - -OLD_TRANSID=$(sudo btrfs subvolume find-new /mnt/root-blank 9999999) -OLD_TRANSID=${OLD_TRANSID#transid marker was } - -sudo btrfs subvolume find-new "/mnt/root" "$OLD_TRANSID" | - sed '$d' | - cut -f17- -d' ' | - sort | - uniq | - while read -r path; do - path="/$path" - if [ -L "$path" ]; then - : # The path is a symbolic link, so is probably handled by NixOS already - elif [ -d "$path" ]; then - : # The path is a directory, ignore - else - echo "$path" - fi - done diff --git a/files/scripts/niri-resize.sh b/files/scripts/niri-resize.sh deleted file mode 100644 index cf6fab8..0000000 --- a/files/scripts/niri-resize.sh +++ /dev/null @@ -1,11 +0,0 @@ -WORKSPACE=$(niri msg -j workspaces | jq -r '.[] | select(.is_focused == true) | .id') - -COUNT=$(niri msg -j windows | jq --argjson ws "$WORKSPACE" -r '.[] | select(.workspace_id == $ws and .is_floating == false) | .app_id' | wc -l) - -while [[ $COUNT == "0" || $COUNT == "2" ]]; do - COUNT=$(niri msg -j windows | jq --argjson ws "$WORKSPACE" -r '.[] | select(.workspace_id == $ws and .is_floating == false) | .app_id' | wc -l) -done - -if [[ $COUNT == "1" ]]; then - niri msg action maximize-column -fi diff --git a/files/scripts/opacitytoggle.sh b/files/scripts/opacitytoggle.sh deleted file mode 100644 index 4b45a2b..0000000 --- a/files/scripts/opacitytoggle.sh +++ /dev/null @@ -1,5 +0,0 @@ -if swaymsg opacity plus 0.01 -q; then - swaymsg opacity 1 -else - swaymsg opacity 0.95 -fi diff --git a/files/scripts/pass-fuzzel.sh b/files/scripts/pass-fuzzel.sh deleted file mode 100644 index cda2328..0000000 --- a/files/scripts/pass-fuzzel.sh +++ /dev/null @@ -1,51 +0,0 @@ -# Adapted from https://code.kulupu.party/thesuess/home-manager/src/branch/main/modules/river.nix -shopt -s nullglob globstar - -otp=0 -typeit=0 -while :; do - case ${1:-} in - -t | --type) - typeit=1 - ;; - -o | --otp) - otp=1 - ;; - *) break ;; - esac - shift -done - -export PASSWORD_STORE_DIR=~/.local/share/password-store -prefix=${PASSWORD_STORE_DIR-~/.local/share/password-store} -if [[ $otp -eq 0 ]]; then - password_files=("$prefix"/**/*.gpg) -else - password_files=("$prefix"/otp/**/*.gpg) -fi -password_files=("${password_files[@]#"$prefix"/}") -password_files=("${password_files[@]%.gpg}") - -password=$(printf '%s\n' "${password_files[@]}" | fuzzel --dmenu "$@") - -[[ -n $password ]] || exit -if [[ $otp -eq 0 ]]; then - if [[ $typeit -eq 0 ]]; then - pass show -c "$password" &> /tmp/pass-fuzzel - else - pass show "$password" | { - IFS= read -r pass - printf %s "$pass" - } | wtype - - fi -else - if [[ $typeit -eq 0 ]]; then - pass otp -c "$password" &> /tmp/pass-fuzzel - else - pass otp "$password" | { - IFS= read -r pass - printf %s "$pass" - } | wtype - - fi -fi -notify-send -u critical -a pass -t 1000 "Copied/Typed Password" diff --git a/files/scripts/project.sh b/files/scripts/project.sh deleted file mode 100644 index 10bff03..0000000 --- a/files/scripts/project.sh +++ /dev/null @@ -1,7 +0,0 @@ -set -euo pipefail - -if [ ! -d "$(pwd)/.git" ]; then - git init -fi -nix flake init --template "$FLAKE"#"$1" -direnv allow diff --git a/files/scripts/quickpass.sh b/files/scripts/quickpass.sh deleted file mode 100644 index 3f95abf..0000000 --- a/files/scripts/quickpass.sh +++ /dev/null @@ -1,12 +0,0 @@ -shopt -s nullglob globstar - -notify-send "$(env | grep -E 'WAYLAND|SWAY')" - -password="$1" - -pass show "$password" | { - IFS= read -r pass - printf %s "$pass" -} | wtype - - -notify-send -u critical -a pass -t 1000 "Typed Password" diff --git a/files/scripts/sshrm.sh b/files/scripts/sshrm.sh deleted file mode 100644 index 4e616c0..0000000 --- a/files/scripts/sshrm.sh +++ /dev/null @@ -1,11 +0,0 @@ -HISTFILE="$HOME"/.histfile - -last_ssh_cmd=$(grep -E "ssh " "$HISTFILE" | sed -E 's/^: [0-9]+:[0-9]+;//' | grep "^ssh " | tail -1) -host=$(echo "$last_ssh_cmd" | sed -E 's/.*ssh ([^@ ]+@)?([^ ]+).*/\2/') - -if [[ -n $host ]]; then - echo "Removing SSH host key for: $host" - ssh-keygen -R "$host" -else - echo "No valid SSH command found in history." -fi diff --git a/files/scripts/swarsel-bootstrap.sh b/files/scripts/swarsel-bootstrap.sh deleted file mode 100644 index 4030312..0000000 --- a/files/scripts/swarsel-bootstrap.sh +++ /dev/null @@ -1,394 +0,0 @@ -# highly inspired by https://github.com/EmergentMind/nix-config/blob/dev/files/scripts/bootstrap-nixos.sh -set -eo pipefail - -target_hostname="" -target_destination="" -target_arch="" -target_user="swarsel" -ssh_port="22" -persist_dir="" -disk_encryption=0 -disk_encryption_args="" -no_disko_deps="false" -temp=$(mktemp -d) - -function help_and_exit() { - echo - echo "Remotely installs SwarselSystem on a target machine including secret deployment." - echo - echo "USAGE: $0 -n -d [OPTIONS]" - echo - echo "ARGS:" - echo " -n specify target_hostname of the target host to deploy the nixos config on." - echo " -d specify ip or url to the target host." - echo " -a specify the architecture of the target host." - echo " target during install process." - echo - echo "OPTIONS:" - echo " -u specify target_user with sudo access. nix-config will be cloned to their home." - echo " Default='${target_user}'." - echo " --port specify the ssh port to use for remote access. Default=${ssh_port}." - echo " --debug Enable debug mode." - echo " --no-disko-deps Upload only disk script and not dependencies (for use on low ram)." - echo " -h | --help Print this help." - exit 0 -} - -function cleanup() { - rm -rf "$temp" - rm -rf /tmp/disko-password -} -trap cleanup exit - -function red() { - echo -e "\x1B[31m[!] $1 \x1B[0m" - if [ -n "${2-}" ]; then - echo -e "\x1B[31m[!] $($2) \x1B[0m" - fi -} -function green() { - echo -e "\x1B[32m[+] $1 \x1B[0m" - if [ -n "${2-}" ]; then - echo -e "\x1B[32m[+] $($2) \x1B[0m" - fi -} -function yellow() { - echo -e "\x1B[33m[*] $1 \x1B[0m" - if [ -n "${2-}" ]; then - echo -e "\x1B[33m[*] $($2) \x1B[0m" - fi -} - -function yes_or_no() { - echo -en "\x1B[32m[+] $* [y/n] (default: y): \x1B[0m" - while true; do - read -rp "" yn - yn=${yn:-y} - case $yn in - [Yy]*) return 0 ;; - [Nn]*) return 1 ;; - esac - done -} - -function update_sops_file() { - key_name=$1 - key_type=$2 - key=$3 - - if [ ! "$key_type" == "hosts" ] && [ ! "$key_type" == "users" ]; then - red "Invalid key type passed to update_sops_file. Must be either 'hosts' or 'users'." - exit 1 - fi - cd "${git_root}" - - SOPS_FILE=".sops.yaml" - sed -i "{ - # Remove any * and & entries for this host - /[*&]$key_name/ d; - # Inject a new age: entry - # n matches the first line following age: and p prints it, then we transform it while reusing the spacing - /age:/{n; p; s/\(.*- \*\).*/\1$key_name/}; - # Inject a new hosts or user: entry - /&$key_type/{n; p; s/\(.*- &\).*/\1$key_name $key/} - }" $SOPS_FILE - green "Updating .sops.yaml" - cd - -} - -while [[ $# -gt 0 ]]; do - case "$1" in - -n) - shift - target_hostname=$1 - ;; - -d) - shift - target_destination=$1 - ;; - -a) - shift - target_arch=$1 - ;; - -u) - shift - target_user=$1 - ;; - --port) - shift - ssh_port=$1 - ;; - --no-disko-deps) - no_disko_deps="true" - ;; - --debug) - set -x - ;; - -h | --help) help_and_exit ;; - *) - echo "Invalid option detected." - help_and_exit - ;; - esac - shift -done - -if [[ $target_arch == "" || $target_destination == "" || $target_hostname == "" ]]; then - red "error: target_arch, target_destination or target_hostname not set." - help_and_exit -fi - -LOCKED="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.node.lockFromBootstrapping)" -if [[ $LOCKED == "true" ]]; then - red "THIS SYSTEM IS LOCKED FROM BOOTSTRAPPING - set 'node.lockFromBootstrapping = lib.mkForce false;' to proceed" - exit -fi - -green "~SwarselSystems~ remote installer" -green "Reading system information for $target_hostname ..." - -DISK="$(nix eval --raw ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.rootDisk)" -green "Root Disk: $DISK" - -CRYPTED="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isCrypted)" -if [[ $CRYPTED == "true" ]]; then - green "Encryption: ✓" - disk_encryption=1 - disk_encryption_args=( - --disk-encryption-keys - /tmp/disko-password - /tmp/disko-password - ) -else - red "Encryption: X" - disk_encryption=0 -fi - -IMPERMANENCE="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isImpermanence)" -if [[ $IMPERMANENCE == "true" ]]; then - green "Impermanence: ✓" - persist_dir="/persist" -else - red "Impermanence: X" - persist_dir="" -fi - -SWAP="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isSwap)" -if [[ $SWAP == "true" ]]; then - green "Swap: ✓" -else - red "Swap: X" -fi - -SECUREBOOT="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isSecureBoot)" -if [[ $SECUREBOOT == "true" ]]; then - green "Secure Boot: ✓" -else - red "Secure Boot: X" -fi - -ssh_cmd="ssh -oport=${ssh_port} -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -t $target_user@$target_destination" -# ssh_root_cmd=$(echo "$ssh_cmd" | sed "s|${target_user}@|root@|") # uses @ in the sed switch to avoid it triggering on the $ssh_key value -ssh_root_cmd=${ssh_cmd/${target_user}@/root@} -scp_cmd="scp -oport=${ssh_port} -o StrictHostKeyChecking=no" - -if [[ -z ${FLAKE} ]]; then - FLAKE=/home/"$target_user"/.dotfiles -fi -if [ ! -d "$FLAKE" ]; then - cd /home/"$target_user" - yellow "Flake directory not found - cloning repository from GitHub" - git clone git@github.com:Swarsel/.dotfiles.git || (yellow "Could not clone repository via SSH - defaulting to HTTPS" && git clone https://github.com/Swarsel/.dotfiles.git) - FLAKE=/home/"$target_user"/.dotfiles -fi - -cd "$FLAKE" - -rm install/flake.lock || true -git_root=$(git rev-parse --show-toplevel) -# ------------------------ -green "Wiping known_hosts of $target_destination" -sed -i "/$target_hostname/d; /$target_destination/d" ~/.ssh/known_hosts -# ------------------------ -green "Preparing a new ssh_host_ed25519_key pair for $target_hostname." -# Create the directory where sshd expects to find the host keys -install -d -m755 "$temp/$persist_dir/etc/ssh" -# Generate host ssh key pair without a passphrase -ssh-keygen -t ed25519 -f "$temp/$persist_dir/etc/ssh/ssh_host_ed25519_key" -C root@"$target_hostname" -N "" -# Set the correct permissions so sshd will accept the key -chmod 600 "$temp/$persist_dir/etc/ssh/ssh_host_ed25519_key" -echo "Adding ssh host fingerprint at $target_destination to ~/.ssh/known_hosts" -# This will fail if we already know the host, but that's fine -ssh-keyscan -p "$ssh_port" "$target_destination" >> ~/.ssh/known_hosts || true -# ------------------------ -# when using luks, disko expects a passphrase on /tmp/disko-password, so we set it for now and will update the passphrase later -# via the config -if [ "$disk_encryption" -eq 1 ]; then - while true; do - green "Set disk encryption passphrase:" - read -rs luks_passphrase - green "Please confirm passphrase:" - read -rs luks_passphrase_confirm - if [[ $luks_passphrase == "$luks_passphrase_confirm" ]]; then - echo "$luks_passphrase" > /tmp/disko-password - $ssh_root_cmd "echo '$luks_passphrase' > /tmp/disko-password" - break - else - red "Passwords do not match" - fi - done -fi -# ------------------------ -green "Generating hardware-config.nix for $target_hostname and adding it to the nix-config." -$ssh_root_cmd "nixos-generate-config --force --no-filesystems --root /mnt" - -mkdir -p "$FLAKE"/hosts/nixos/"$target_arch"/"$target_hostname" -$scp_cmd root@"$target_destination":/mnt/etc/nixos/hardware-configuration.nix "${git_root}"/hosts/nixos/"$target_arch"/"$target_hostname"/hardware-configuration.nix -# ------------------------ -green "Generating hostkey for ssh initrd" -$ssh_root_cmd "mkdir -p $temp/etc/secrets/initrd /etc/secrets/initrd" -$ssh_root_cmd "ssh-keygen -t ed25519 -N '' -f $temp/etc/secrets/initrd/ssh_host_ed25519_key" -$ssh_root_cmd "cp $temp/etc/secrets/initrd/ssh_host_ed25519_key /etc/secrets/initrd/ssh_host_ed25519_key" -# ------------------------ - -green "Deploying minimal NixOS installation on $target_destination" - -if [[ $no_disko_deps == "true" ]]; then - green "Building without disko dependencies (using custom kexec)" - nix run github:nix-community/nixos-anywhere/1.10.0 -- "${disk_encryption_args[@]}" --no-disko-deps --ssh-port "$ssh_port" --extra-files "$temp" --flake ./install#"$target_hostname" --kexec "$(nix build --print-out-paths .#packages."$target_arch".swarsel-kexec)/swarsel-kexec-$target_arch.tar.gz" root@"$target_destination" -else - green "Building with disko dependencies (using nixos-images kexec)" - nix run github:nix-community/nixos-anywhere/1.10.0 -- "${disk_encryption_args[@]}" --ssh-port "$ssh_port" --extra-files "$temp" --flake ./install#"$target_hostname" root@"$target_destination" -fi - -echo "Updating ssh host fingerprint at $target_destination to ~/.ssh/known_hosts" -ssh-keyscan -p "$ssh_port" "$target_destination" >> ~/.ssh/known_hosts || true -# ------------------------ - -while true; do - read -rp "Press Enter to continue once the remote host has finished booting." - if nc -z "$target_destination" "${ssh_port}" 2> /dev/null; then - green "$target_destination is booted. Continuing..." - break - else - yellow "$target_destination is not yet ready." - fi -done - -# ------------------------ - -if [[ $SECUREBOOT == "true" ]]; then - green "Setting up secure boot keys" - $ssh_root_cmd "mkdir -p /var/lib/sbctl" - read -ra scp_call <<< "${scp_cmd}" - sudo "${scp_call[@]}" -r /var/lib/sbctl root@"$target_destination":/var/lib/ - $ssh_root_cmd "sbctl enroll-keys --ignore-immutable --microsoft || true" -fi -# ------------------------ - -if [ -n "$persist_dir" ]; then - $ssh_root_cmd "cp /etc/machine-id $persist_dir/etc/machine-id || true" - $ssh_root_cmd "cp -R /etc/ssh/ $persist_dir/etc/ssh/ || true" -fi -# ------------------------ -green "Generating an age key based on the new ssh_host_ed25519_key." -target_key=$( - ssh-keyscan -p "$ssh_port" -t ssh-ed25519 "$target_destination" 2>&1 | - grep ssh-ed25519 | - cut -f2- -d" " || - ( - red "Failed to get ssh key. Host down?" - exit 1 - ) -) -host_age_key=$(nix shell nixpkgs#ssh-to-age.out -c sh -c "echo $target_key | ssh-to-age") - -if grep -qv '^age1' <<< "$host_age_key"; then - red "The result from generated age key does not match the expected format." - yellow "Result: $host_age_key" - yellow "Expected format: age1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - exit 1 -else - echo "$host_age_key" -fi - -green "Updating nix-secrets/.sops.yaml" -update_sops_file "$target_hostname" "hosts" "$host_age_key" -yellow ".sops.yaml has been updated. There may be superfluous entries, you might need to edit manually." -if yes_or_no "Do you want to manually edit .sops.yaml now?"; then - vim "${git_root}"/.sops.yaml -fi -green "Updating all secrets files to reflect updates .sops.yaml" -sops updatekeys --yes --enable-local-keyservice "${git_root}"/hosts/nixos/"$target_arch"/"$target_hostname"/secrets/* || true -# -------------------------- -green "Making ssh_host_ed25519_key available to home-manager for user $target_user" -sed -i "/$target_hostname/d; /$target_destination/d" ~/.ssh/known_hosts -$ssh_root_cmd "mkdir -p /home/$target_user/.ssh; chown -R $target_user:users /home/$target_user/.ssh/" -$scp_cmd root@"$target_destination":/etc/ssh/ssh_host_ed25519_key root@"$target_destination":/home/"$target_user"/.ssh/ssh_host_ed25519_key -$ssh_root_cmd "chown $target_user:users /home/$target_user/.ssh/ssh_host_ed25519_key" -# __________________________ - -if yes_or_no "Add ssh host fingerprints for git upstream repositories? (This is needed for building the full config)"; then - green "Adding ssh host fingerprints for git{lab,hub}" - $ssh_cmd "mkdir -p /home/$target_user/.ssh/; ssh-keyscan -t ssh-ed25519 gitlab.com github.com | tee /home/$target_user/.ssh/known_hosts" - $ssh_root_cmd "mkdir -p /root/.ssh/; ssh-keyscan -t ssh-ed25519 gitlab.com github.com | tee /root/.ssh/known_hosts" -fi -# -------------------------- - -if yes_or_no "Do you want to copy your full nix-config and nix-secrets to $target_hostname?"; then - green "Adding ssh host fingerprint at $target_destination to ~/.ssh/known_hosts" - ssh-keyscan -p "$ssh_port" "$target_destination" >> ~/.ssh/known_hosts || true - green "Copying full nix-config to $target_hostname" - cd "${git_root}" - just sync "$target_user" "$target_destination" - - if [ -n "$persist_dir" ]; then - $ssh_root_cmd "cp -r /home/$target_user/.dotfiles $persist_dir/.dotfiles || true" - $ssh_root_cmd "cp -r /home/$target_user/.ssh $persist_dir/.ssh || true" - fi - - if yes_or_no "Do you want to rebuild immediately?"; then - green "Building nix-config for $target_hostname" - # yellow "Reminder: The password is 'setup'" - $ssh_root_cmd "mkdir -p /root/.local/share/nix/; printf '{\"extra-substituters\":{\"https://nix-community.cachix.org\":true,\"https://nix-community.cachix.org https://cache.ngi0.nixos.org/\":true},\"extra-trusted-public-keys\":{\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=\":true,\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs= cache.ngi0.nixos.org-1:KqH5CBLNSyX184S9BKZJo1LxrxJ9ltnY2uAs5c/f1MA=\":true}}' | tee /root/.local/share/nix/trusted-settings.json" - # $ssh_cmd -oForwardAgent=yes "cd .dotfiles && sudo nixos-rebuild --show-trace --flake .#$target_hostname switch" - store_path=$(nix build --no-link --print-out-paths .#nixosConfigurations."$target_hostname".config.system.build.toplevel) - green "Copying generation to $target_hostname" - nix copy --to "ssh://root@$target_destination" "$store_path" - # prev_system=$($ssh_root_cmd " readlink -e /nix/var/nix/profiles/system") - green "Linking generation in bootloader" - $ssh_root_cmd "/run/current-system/sw/bin/nix-env --profile /nix/var/nix/profiles/system --set $store_path" - green "Setting generation to activate upon next boot" - $ssh_root_cmd "$store_path/bin/switch-to-configuration boot" - else - echo - green "NixOS was successfully installed!" - echo "Post-install config build instructions:" - echo "To copy nix-config from this machine to the $target_hostname, run the following command from ~/nix-config" - echo "just sync $target_user $target_destination" - echo "To rebuild, sign into $target_hostname and run the following command from ~/nix-config" - echo "cd nix-config" - # see above FIXME:(bootstrap) - echo "sudo nixos-rebuild .pre-commit-config.yaml show-trace --flake .#$target_hostname switch" - # echo "just rebuild" - echo - fi -fi - -green "NixOS was successfully installed!" -if yes_or_no "You can now commit and push the nix-config, which includes the hardware-configuration.nix for $target_hostname?"; then - cd "${git_root}" - deadnix hosts/nixos/"$target_arch"/"$target_hostname"/hardware-configuration.nix -qe - nixpkgs--fmt hosts/nixos/"$target_arch"/"$target_hostname"/hardware-configuration.nix - (.pre-commit-config.yaml mit run --all-files 2> /dev/null || true) && - git add "$git_root/hosts/nixos/$target_arch/$target_hostname/hardware-configuration.nix" && - git add "$git_root/.sops.yaml" && - git add "$git_root/secrets" && - (git commit -m "feat: deployed $target_hostname" || true) && git push -fi - -if yes_or_no "Reboot now?"; then - $ssh_root_cmd "reboot" -fi - -rm -rf /tmp/disko-password diff --git a/files/scripts/swarsel-displaypower.sh b/files/scripts/swarsel-displaypower.sh deleted file mode 100644 index 332f784..0000000 --- a/files/scripts/swarsel-displaypower.sh +++ /dev/null @@ -1,2 +0,0 @@ -swaymsg "output * power on" > /dev/null 2>&1 || true -swaymsg "output * dpms on" > /dev/null 2>&1 || true diff --git a/files/scripts/swarsel-install.sh b/files/scripts/swarsel-install.sh deleted file mode 100644 index f62e435..0000000 --- a/files/scripts/swarsel-install.sh +++ /dev/null @@ -1,188 +0,0 @@ -set -eo pipefail - -target_config="hotel" -target_hostname="hotel" -target_user="swarsel" -target_arch="" -persist_dir="" -target_disk="/dev/vda" -disk_encryption=0 - -function help_and_exit() { - echo - echo "Locally installs SwarselSystem on this machine." - echo - echo "USAGE: $0 -n -d [OPTIONS]" - echo - echo "ARGS:" - echo " -n specify the nixos config to deploy." - echo " Default: hotel" - echo " -d specify disk to install on." - echo " Default: /dev/vda" - echo " -u specify user to deploy for." - echo " Default: swarsel" - echo " -a specify target architecture." - echo " -h | --help Print this help." - exit 0 -} - -function red() { - echo -e "\x1B[31m[!] $1 \x1B[0m" - if [ -n "${2-}" ]; then - echo -e "\x1B[31m[!] $($2) \x1B[0m" - fi -} -function green() { - echo -e "\x1B[32m[+] $1 \x1B[0m" - if [ -n "${2-}" ]; then - echo -e "\x1B[32m[+] $($2) \x1B[0m" - fi -} -function yellow() { - echo -e "\x1B[33m[*] $1 \x1B[0m" - if [ -n "${2-}" ]; then - echo -e "\x1B[33m[*] $($2) \x1B[0m" - fi -} - -while [[ $# -gt 0 ]]; do - case "$1" in - -n) - shift - target_config=$1 - target_hostname=$1 - ;; - -u) - shift - target_user=$1 - ;; - -d) - shift - target_disk=$1 - ;; - -a) - shift - target_arch=$1 - ;; - -h | --help) help_and_exit ;; - *) - echo "Invalid option detected." - help_and_exit - ;; - esac - shift -done - -function cleanup() { - sudo rm -rf .cache/nix - sudo rm -rf /root/.cache/nix -} -trap cleanup exit - -if [[ $target_arch == "" || $target_hostname == "" ]]; then - red "error: target_arch or target_hostname not set." - help_and_exit -fi - -green "~SwarselSystems~ local installer" - -cd /home/"$target_user" - -sudo rm -rf /root/.cache/nix -sudo rm -rf .cache/nix -sudo rm -rf .dotfiles - -green "Cloning repository from GitHub" -git clone https://github.com/Swarsel/.dotfiles.git - -local_keys=$(ssh-add -L || true) -pub_key=$(cat /home/"$target_user"/.dotfiles/secrets/public/ssh/yubikey.pub) -read -ra pub_arr <<< "$pub_key" - -cd .dotfiles -if [[ $local_keys != *"${pub_arr[1]}"* ]]; then - yellow "The ssh key for this configuration is not available." - green "Adjusting flake.nix so that the configuration is buildable ..." - sed -i '/vbc-nix = {/,/^[[:space:]]*};/d' flake.nix - sed -i '/[[:space:]]*\/\/ (inputs.vbc-nix.overlays.default final prev)/d' overlays/default.nix - nix flake update vbc-nix - git add . -else - green "Valid SSH key found! Continuing with installation" -fi - -green "Reading system information for $target_config ..." -DISK="$(nix eval --raw ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.rootDisk)" -green "Root Disk in config: $DISK - Root Disk passed in cli: $target_disk" - -CRYPTED="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isCrypted)" -if [[ $CRYPTED == "true" ]]; then - green "Encryption: ✓" - disk_encryption=1 -else - red "Encryption: X" - disk_encryption=0 -fi - -IMPERMANENCE="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isImpermanence)" -if [[ $IMPERMANENCE == "true" ]]; then - green "Impermanence: ✓" - persist_dir="/persist" -else - red "Impermanence: X" - persist_dir="" -fi - -SWAP="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isSwap)" -if [[ $SWAP == "true" ]]; then - green "Swap: ✓" -else - red "Swap: X" -fi - -SECUREBOOT="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isSecureBoot)" -if [[ $SECUREBOOT == "true" ]]; then - green "Secure Boot: ✓" -else - red "Secure Boot: X" -fi - -if [ "$disk_encryption" -eq 1 ]; then - while true; do - green "Set disk encryption passphrase:" - read -rs luks_passphrase - green "Please confirm passphrase:" - read -rs luks_passphrase_confirm - if [[ $luks_passphrase == "$luks_passphrase_confirm" ]]; then - echo "$luks_passphrase" > /tmp/disko-password - break - else - red "Passwords do not match" - fi - done -fi - -green "Setting up disk ..." -if [[ $target_config == "hotel" ]]; then - sudo nix --experimental-features "nix-command flakes" run github:nix-community/disko/v1.10.0 -- --mode destroy,format,mount --flake .#"$target_config" --yes-wipe-all-disks --arg diskDevice "$target_disk" -else - sudo nix --experimental-features "nix-command flakes" run github:nix-community/disko/latest -- --mode destroy,format,mount --flake .#"$target_config" --yes-wipe-all-disks -fi -sudo mkdir -p /mnt/"$persist_dir"/home/"$target_user"/ -sudo cp -r /home/"$target_user"/.dotfiles /mnt/"$persist_dir"/home/"$target_user"/ -sudo chown -R 1000:100 /mnt/"$persist_dir"/home/"$target_user" - -green "Generating hardware configuration ..." -sudo nixos-generate-config --root /mnt --no-filesystems --dir /home/"$target_user"/.dotfiles/hosts/nixos/"$target_arch"/"$target_config"/ - -git add /home/"$target_user"/.dotfiles/hosts/nixos/"$target_arch"/"$target_config"/hardware-configuration.nix -sudo mkdir -p /root/.local/share/nix/ -printf '{\"extra-substituters\":{\"https://nix-community.cachix.org\":true,\"https://nix-community.cachix.org https://cache.ngi0.nixos.org/\":true},\"extra-trusted-public-keys\":{\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=\":true,\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs= cache.ngi0.nixos.org-1:KqH5CBLNSyX184S9BKZJo1LxrxJ9ltnY2uAs5c/f1MA=\":true}}' | sudo tee /root/.local/share/nix/trusted-settings.json > /dev/null -green "Installing flake $target_config" - -store_path=$(nix build --no-link --print-out-paths .#nixosConfigurationsMinimal."$target_config".config.system.build.toplevel) -green "Linking generation in bootloader" -sudo "/run/current-system/sw/bin/nix-env --profile /nix/var/nix/profiles/system --set $store_path" -green "Setting generation to activate upon next boot" -sudo "$store_path/bin/switch-to-configuration boot" -green "Installation finished! Reboot to see changes" diff --git a/files/scripts/swarsel-postinstall.sh b/files/scripts/swarsel-postinstall.sh deleted file mode 100644 index 448d3d8..0000000 --- a/files/scripts/swarsel-postinstall.sh +++ /dev/null @@ -1,72 +0,0 @@ -set -eo pipefail - -target_config="hotel" -target_user="swarsel" - -function help_and_exit() { - echo - echo "Locally installs SwarselSystem on this machine." - echo - echo "USAGE: $0 -d [OPTIONS]" - echo - echo "ARGS:" - echo " -d specify disk to install on." - echo " -n specify the nixos config to deploy." - echo " Default: hotel" - echo " Default: hotel" - echo " -u specify user to deploy for." - echo " Default: swarsel" - echo " -h | --help Print this help." - exit 0 -} - -function green() { - echo -e "\x1B[32m[+] $1 \x1B[0m" - if [ -n "${2-}" ]; then - echo -e "\x1B[32m[+] $($2) \x1B[0m" - fi -} - -while [[ $# -gt 0 ]]; do - case "$1" in - -n) - shift - target_config=$1 - ;; - -u) - shift - target_user=$1 - ;; - -h | --help) help_and_exit ;; - *) - echo "Invalid option detected." - help_and_exit - ;; - esac - shift -done - -function cleanup() { - sudo rm -rf .cache/nix - sudo rm -rf /root/.cache/nix -} -trap cleanup exit - -sudo rm -rf .cache/nix -sudo rm -rf /root/.cache/nix - -green "~SwarselSystems~ remote post-installer" - -cd /home/"$target_user"/.dotfiles - -SECUREBOOT="$(nix eval ~/.dotfiles#nixosConfigurations."$target_config".config.swarselsystems.isSecureBoot)" - -if [[ $SECUREBOOT == "true" ]]; then - green "Setting up secure boot keys" - sudo mkdir -p /var/lib/sbctl - sbctl create-keys || true - sbctl enroll-keys --ignore-immutable --microsoft || true -fi - -sudo nixos-rebuild --flake .#"$target_config" switch -green "Post-install finished!" diff --git a/files/scripts/swarsel-rebuild.sh b/files/scripts/swarsel-rebuild.sh deleted file mode 100644 index d3b28bb..0000000 --- a/files/scripts/swarsel-rebuild.sh +++ /dev/null @@ -1,110 +0,0 @@ -set -eo pipefail - -target_config="hotel" -target_arch="" -target_user="swarsel" - -function help_and_exit() { - echo - echo "Builds SwarselSystem configuration." - echo - echo "USAGE: $0 [OPTIONS]" - echo - echo "ARGS:" - echo " -n specify nixos config to build." - echo " Default: hotel" - echo " -u specify user to deploy for." - echo " Default: swarsel" - echo " -a specify target architecture." - echo " -h | --help Print this help." - exit 0 -} - -function red() { - echo -e "\x1B[31m[!] $1 \x1B[0m" - if [ -n "${2-}" ]; then - echo -e "\x1B[31m[!] $($2) \x1B[0m" - fi -} -function green() { - echo -e "\x1B[32m[+] $1 \x1B[0m" - if [ -n "${2-}" ]; then - echo -e "\x1B[32m[+] $($2) \x1B[0m" - fi -} -function yellow() { - echo -e "\x1B[33m[*] $1 \x1B[0m" - if [ -n "${2-}" ]; then - echo -e "\x1B[33m[*] $($2) \x1B[0m" - fi -} - -while [[ $# -gt 0 ]]; do - case "$1" in - -n) - shift - target_config=$1 - ;; - -a) - shift - target_arch=$1 - ;; - -u) - shift - target_user=$1 - ;; - -h | --help) help_and_exit ;; - *) - echo "Invalid option detected." - help_and_exit - ;; - esac - shift -done - -if [[ $target_arch == "" ]]; then - red "error: target_arch not set." - help_and_exit -fi - -cd /home/"$target_user" - -if [ ! -d /home/"$target_user"/.dotfiles ]; then - green "Cloning repository from GitHub" - git clone https://github.com/Swarsel/.dotfiles.git -else - red "A .dotfiles repository is in the way. Please (re-)move the repository and try again." - exit 1 -fi - -local_keys=$(ssh-add -L || true) -pub_key=$(cat /home/"$target_user"/.dotfiles/secrets/public/ssh/yubikey.pub) -read -ra pub_arr <<< "$pub_key" - -cd .dotfiles -if [[ $local_keys != *"${pub_arr[1]}"* ]]; then - yellow "The ssh key for this configuration is not available." - green "Adjusting flake.nix so that the configuration is buildable" - sed -i '/nix-secrets = {/,/^[[:space:]]*};/d' flake.nix - sed -i '/vbc-nix = {/,/^[[:space:]]*};/d' flake.nix - sed -i '/[[:space:]]*\/\/ (inputs.vbc-nix.overlays.default final prev)/d' overlays/default.nix - rm modules/home/common/env.nix - rm modules/home/common/gammastep.nix - rm modules/home/common/git.nix - rm modules/home/common/mail.nix - rm modules/home/common/yubikey.nix - rm modules/nixos/server/restic.nix - rm hosts/nixos/aarch64-linux/milkywell/default.nix - rm -rf modules/nixos/server - rm -rf modules/home/server - nix flake update vbc-nix - git add . -else - green "Valid SSH key found! Continuing with installation" -fi -sudo nixos-generate-config --dir /home/"$target_user"/.dotfiles/hosts/nixos/"$target_arch"/"$target_config"/ -git add /home/"$target_user"/.dotfiles/hosts/nixos/"$target_arch"/"$target_config"/hardware-configuration.nix - -green "Installing flake $target_config" -sudo nixos-rebuild --show-trace --flake .#"$target_config" boot -yellow "Please keep in mind that this is only a demo of the configuration. Things might break unexpectedly." diff --git a/files/scripts/swarselcheck.sh b/files/scripts/swarselcheck.sh deleted file mode 100644 index b581068..0000000 --- a/files/scripts/swarselcheck.sh +++ /dev/null @@ -1,62 +0,0 @@ -kitty=0 -element=0 -vesktop=0 -spotifyplayer=0 -while :; do - case ${1:-} in - -k | --kitty) - kitty=1 - ;; - -e | --element) - element=1 - ;; - -d | --vesktop) - vesktop=1 - ;; - -s | --spotifyplayer) - spotifyplayer=1 - ;; - *) break ;; - esac - shift -done - -if [[ $kitty -eq 1 ]]; then - STR=$(swaymsg -t get_tree | jq -r 'recurse(.nodes[]) | select(.name == "__i3_scratch")' | grep kittyterm || true) - CHECK=$(swaymsg -t get_tree | grep kittyterm || true) - if [ "$CHECK" == "" ]; then - exec kitty --app-id kittyterm -T kittyterm -o confirm_os_window_close=0 zellij attach --create kittyterm & - sleep 1 - fi - if [ "$STR" == "" ]; then - exec swaymsg '[title="kittyterm"]' scratchpad show - else - exec swaymsg '[title="kittyterm"]' scratchpad show - fi -elif [[ $element -eq 1 ]]; then - STR=$(swaymsg -t get_tree | grep Element || true) - if [ "$STR" == "" ]; then - exec element-desktop - else - exec swaymsg '[app_id=Element]' kill - fi -elif [[ $vesktop -eq 1 ]]; then - STR=$(swaymsg -t get_tree | grep vesktop || true) - if [ "$STR" == "" ]; then - exec vesktop - else - exec swaymsg '[app_id=vesktop]' kill - fi -elif [[ $spotifyplayer -eq 1 ]]; then - STR=$(swaymsg -t get_tree | jq -r 'recurse(.nodes[]) | select(.name == "__i3_scratch")' | grep spotifytui || true) - CHECK=$(swaymsg -t get_tree | grep spotifytui || true) - if [ "$CHECK" == "" ]; then - exec kitty --add-id spotifytui -T spotifytui -o confirm_os_window_close=0 spotify_player & - sleep 1 - fi - if [ "$STR" == "" ]; then - exec swaymsg '[title="spotifytui"]' scratchpad show - else - exec swaymsg '[title="spotifytui"]' scratchpad show - fi -fi diff --git a/files/scripts/swarselzellij.sh b/files/scripts/swarselzellij.sh deleted file mode 100644 index 24a1ac6..0000000 --- a/files/scripts/swarselzellij.sh +++ /dev/null @@ -1,8 +0,0 @@ -# KITTIES=$(($(pgrep -P 1 kitty | wc -l) - 1)) - -# if ((KITTIES < 1)); then -# exec kitty -o confirm_os_window_close=0 zellij attach --create main -# else -# exec kitty -o confirm_os_window_close=0 zellij attach --create "temp $KITTIES" -# fi -exec kitty -o confirm_os_window_close=0 zellij diff --git a/files/scripts/waybarupdate.sh b/files/scripts/waybarupdate.sh deleted file mode 100644 index 02c6103..0000000 --- a/files/scripts/waybarupdate.sh +++ /dev/null @@ -1,24 +0,0 @@ -CFG=$(git --git-dir="$HOME"/.dotfiles/.git --work-tree="$HOME"/.dotfiles/ status -s | wc -l) -CSE=$(git --git-dir="$DOCUMENT_DIR_PRIV"/CSE_TUWIEN/.git --work-tree="$DOCUMENT_DIR_PRIV"/CSE_TUWIEN/ status -s | wc -l) -PASS=$(($(git --git-dir="$HOME"/.local/share/password-store/.git --work-tree="$HOME"/.local/share/password-store/ status -s | wc -l) + $(git --git-dir="$HOME"/.local/share/password-store/.git --work-tree="$HOME"/.local/share/password-store/ diff origin/main..HEAD | wc -l))) - -if [[ $CFG != 0 ]]; then - CFG_STR='CONFIG' -else - CFG_STR='' -fi - -if [[ $CSE != 0 ]]; then - CSE_STR=' CSE' -else - CSE_STR='' -fi - -if [[ $PASS != 0 ]]; then - PASS_STR=' PASS' -else - PASS_STR='' -fi - -OUT="$CFG_STR""$CSE_STR""$PASS_STR" -echo "$OUT" diff --git a/flake.lock b/flake.lock index 6fff583..b65777e 100644 --- a/flake.lock +++ b/flake.lock @@ -101,11 +101,11 @@ }, "crane": { "locked": { - "lastModified": 1771796463, - "narHash": "sha256-9bCDuUzpwJXcHMQYMS1yNuzYMmKO/CCwCexpjWOl62I=", + "lastModified": 1772080396, + "narHash": "sha256-84W9UNtSk9DNMh43WBkOjpkbfODlmg+RDi854PnNgLE=", "owner": "ipetkov", "repo": "crane", - "rev": "3d3de3313e263e04894f284ac18177bd26169bad", + "rev": "8525580bc0316c39dbfa18bd09a1331e98c9e463", "type": "github" }, "original": { @@ -250,11 +250,11 @@ "nixpkgs": "nixpkgs_2" }, "locked": { - "lastModified": 1772420042, - "narHash": "sha256-naZz40TUFMa0E0CutvwWsSPhgD5JldyTUDEgP9ADpfU=", + "lastModified": 1773889306, + "narHash": "sha256-PAqwnsBSI9SVC2QugvQ3xeYCB0otOwCacB1ueQj2tgw=", "owner": "nix-community", "repo": "disko", - "rev": "5af7af10f14706e4095bd6bc0d9373eb097283c6", + "rev": "5ad85c82cc52264f4beddc934ba57f3789f28347", "type": "github" }, "original": { @@ -322,11 +322,11 @@ "nixpkgs-stable": "nixpkgs-stable" }, "locked": { - "lastModified": 1772444130, - "narHash": "sha256-z0Qb935EOAxuQlMpL5FkM/cDERrHNNqNVvUG+f2M7d0=", + "lastModified": 1774086051, + "narHash": "sha256-GL/QwjrHRERpy7wXxPWrvR7AlBKa5315/Gf1e1Ykbyw=", "owner": "nix-community", "repo": "emacs-overlay", - "rev": "f99d61b5ee1831be80ef1369846493251f04a12f", + "rev": "c006890a36ebf27a31298eabb2dc31c515618dbe", "type": "github" }, "original": { @@ -746,7 +746,7 @@ }, "flake-utils_5": { "inputs": { - "systems": "systems_3" + "systems": "systems_4" }, "locked": { "lastModified": 1731533236, @@ -764,7 +764,7 @@ }, "flake-utils_6": { "inputs": { - "systems": "systems_9" + "systems": "systems_10" }, "locked": { "lastModified": 1731533236, @@ -809,11 +809,11 @@ ] }, "locked": { - "lastModified": 1769939035, - "narHash": "sha256-Fok2AmefgVA0+eprw2NDwqKkPGEI5wvR+twiZagBvrg=", + "lastModified": 1772893680, + "narHash": "sha256-JDqZMgxUTCq85ObSaFw0HhE+lvdOre1lx9iI6vYyOEs=", "owner": "cachix", "repo": "git-hooks.nix", - "rev": "a8ca480175326551d6c4121498316261cbb5b260", + "rev": "8baab586afc9c9b57645a734c820e4ac0a604af9", "type": "github" }, "original": { @@ -1049,11 +1049,11 @@ ] }, "locked": { - "lastModified": 1772380461, - "narHash": "sha256-O3ukj3Bb3V0Tiy/4LUfLlBpWypJ9P0JeUgsKl2nmZZY=", + "lastModified": 1774007980, + "narHash": "sha256-FOnZjElEI8pqqCvB6K/1JRHTE8o4rer8driivTpq2uo=", "owner": "nix-community", "repo": "home-manager", - "rev": "f140aa04d7d14f8a50ab27f3691b5766b17ae961", + "rev": "9670de2921812bc4e0452f6e3efd8c859696c183", "type": "github" }, "original": { @@ -1177,11 +1177,11 @@ "rust-overlay": "rust-overlay" }, "locked": { - "lastModified": 1772216104, - "narHash": "sha256-1TnGN26vnCEQk5m4AavJZxGZTb/6aZyphemRPRwFUfs=", + "lastModified": 1773344150, + "narHash": "sha256-JSsXufJy2zdg5XS5pRGlkwF1dqN+sWPmCgrvJsnhEzg=", "owner": "nix-community", "repo": "lanzaboote", - "rev": "dbe5112de965bbbbff9f0729a9789c20a65ab047", + "rev": "d21013305ef39e1d9d2d06b161c3785ffad82281", "type": "github" }, "original": { @@ -1196,11 +1196,11 @@ "spectrum": "spectrum" }, "locked": { - "lastModified": 1772338235, - "narHash": "sha256-9XcwtSIL/c+pkC3SBNuxCJuSktFOBV1TLvvkhekyB8I=", + "lastModified": 1773872447, + "narHash": "sha256-IWTp4EMUfZwnuF5S/AjWfOFzCbbgkMzRwNd0qHC/EMg=", "owner": "astro", "repo": "microvm.nix", - "rev": "9d1ff9b53532908a5eba7707931c9093508b6b92", + "rev": "b202882536b018a76f0b6e71a48677f41f4de9d8", "type": "github" }, "original": { @@ -1280,11 +1280,11 @@ "xwayland-satellite-unstable": "xwayland-satellite-unstable" }, "locked": { - "lastModified": 1772433239, - "narHash": "sha256-5pPusMALo7ZYEoW/iHUxK7rLk3Kg8sJ8Sdf7IcfK5HA=", + "lastModified": 1773889880, + "narHash": "sha256-cu23CGP+mD2wKPKaoGM7evZ1dXfjd+cjryqqqx2HloE=", "owner": "sodiboo", "repo": "niri-flake", - "rev": "c56af55f5563f7c7043ed45ed2566a69a638448d", + "rev": "63767d4572eb2e3da5e68f68de77d8f2cdeca8dd", "type": "github" }, "original": { @@ -1313,11 +1313,11 @@ "niri-unstable": { "flake": false, "locked": { - "lastModified": 1772207631, - "narHash": "sha256-Jkkg+KqshFO3CbTszVVpkKN2AOObYz+wMsM3ONo1z5g=", + "lastModified": 1773130184, + "narHash": "sha256-3bwx4WqCB06yfQIGB+OgIckOkEDyKxiTD5pOo4Xz2rI=", "owner": "YaLTeR", "repo": "niri", - "rev": "e708f546153f74acf33eb183b3b2992587a701e5", + "rev": "b07bde3ee82dd73115e6b949e4f3f63695da35ea", "type": "github" }, "original": { @@ -1369,11 +1369,11 @@ "nixpkgs": "nixpkgs_10" }, "locked": { - "lastModified": 1772379624, - "narHash": "sha256-NG9LLTWlz4YiaTAiRGChbrzbVxBfX+Auq4Ab/SWmk4A=", + "lastModified": 1773000227, + "narHash": "sha256-zm3ftUQw0MPumYi91HovoGhgyZBlM4o3Zy0LhPNwzXE=", "owner": "lnl7", "repo": "nix-darwin", - "rev": "52d061516108769656a8bd9c6e811c677ec5b462", + "rev": "da529ac9e46f25ed5616fd634079a5f3c579135f", "type": "github" }, "original": { @@ -1429,11 +1429,11 @@ ] }, "locked": { - "lastModified": 1772341813, - "narHash": "sha256-/PQ0ubBCMj/MVCWEI/XMStn55a8dIKsvztj4ZVLvUrQ=", + "lastModified": 1773552174, + "narHash": "sha256-mHSRNrT1rjeYBgkAlj07dW3+1nFEgAd8Gu6lgyfT9DU=", "owner": "nix-community", "repo": "nix-index-database", - "rev": "a2051ff239ce2e8a0148fa7a152903d9a78e854f", + "rev": "8faeb68130df077450451b6734a221ba0d6cde42", "type": "github" }, "original": { @@ -1449,11 +1449,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1772334875, - "narHash": "sha256-AveYVY2plEJ62Br6iAd4fB5PDYyjJoTEmgdWRV3m+Vo=", + "lastModified": 1774060651, + "narHash": "sha256-sZiam+rmNcOZGnlbnqDD9oTwfMdQUM+uQmFqqSoe194=", "owner": "Infinidoge", "repo": "nix-minecraft", - "rev": "a852ac73a4f9bf8270bdac90a72a28fef5df846b", + "rev": "46727bd27d32d63069ed26a690554373ae2b4702", "type": "github" }, "original": { @@ -1492,11 +1492,11 @@ "nixpkgs": "nixpkgs_13" }, "locked": { - "lastModified": 1771963727, - "narHash": "sha256-gFyFAFYYoNsvd6heI0XtDMIa4pnykjwDljS7dQm45uE=", + "lastModified": 1773727286, + "narHash": "sha256-n7gZKq9pJb0IoRsAPxZqjYWbm8/v2UdrZxARlmlKzvk=", "owner": "oddlama", "repo": "nix-topology", - "rev": "b493b9b970388d79129ce1a92a6b060c9305386f", + "rev": "49b439d8749703989a42f28a4bfe198b2b315894", "type": "github" }, "original": { @@ -1620,11 +1620,11 @@ }, "nixos-hardware": { "locked": { - "lastModified": 1771969195, - "narHash": "sha256-qwcDBtrRvJbrrnv1lf/pREQi8t2hWZxVAyeMo7/E9sw=", + "lastModified": 1774018263, + "narHash": "sha256-HHYEwK1A22aSaxv2ibhMMkKvrDGKGlA/qObG4smrSqc=", "owner": "NixOS", "repo": "nixos-hardware", - "rev": "41c6b421bdc301b2624486e11905c9af7b8ec68e", + "rev": "2d4b4717b2534fad5c715968c1cece04a172b365", "type": "github" }, "original": { @@ -1725,11 +1725,11 @@ }, "nixpkgs-bisect": { "locked": { - "lastModified": 1772456869, - "narHash": "sha256-dpJZDTBrJsVk5OPclGEx9UEkd07TCebPXpaOtQgbgDo=", + "lastModified": 1774100042, + "narHash": "sha256-pheWSPciFDxos5HX2ofPnfCpYOnaGhGM+cHsddQ2Rq8=", "owner": "nixos", "repo": "nixpkgs", - "rev": "7b25dc29ae2eb0e095ed0f9e9f1e3c1beda2dedc", + "rev": "21c7f0e6b0fe7fe7ca0872f2da461d4c07b8fe7d", "type": "github" }, "original": { @@ -1905,11 +1905,11 @@ }, "nixpkgs-oddlama": { "locked": { - "lastModified": 1769291456, - "narHash": "sha256-cYwgBqxRv9UIBe4VdLnT20Nzf7zfTjZuEnhY/Yh0PpU=", + "lastModified": 1772997209, + "narHash": "sha256-olkXDrnOgEqB+VdOF4urA1vJhW1TtasAB9Gmj8xDITw=", "owner": "oddlama", "repo": "nixpkgs", - "rev": "4424b66c4f70ec3f6c2be98f4bd852713906c6eb", + "rev": "240aff6ece97a54444b41b8bb30673615445ffa3", "type": "github" }, "original": { @@ -1921,16 +1921,16 @@ }, "nixpkgs-stable": { "locked": { - "lastModified": 1767313136, - "narHash": "sha256-16KkgfdYqjaeRGBaYsNrhPRRENs0qzkQVUooNHtoy2w=", + "lastModified": 1773814637, + "narHash": "sha256-GNU+ooRmrHLfjlMsKdn0prEKVa0faVanm0jrgu1J/gY=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "ac62194c3917d5f474c1a844b6fd6da2db95077d", + "rev": "fea3b367d61c1a6592bc47c72f40a9f3e6a53e96", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixos-25.05", + "ref": "nixos-25.11", "repo": "nixpkgs", "type": "github" } @@ -1985,11 +1985,11 @@ }, "nixpkgs-stable25_11": { "locked": { - "lastModified": 1772047000, - "narHash": "sha256-7DaQVv4R97cii/Qdfy4tmDZMB2xxtyIvNGSwXBBhSmo=", + "lastModified": 1773814637, + "narHash": "sha256-GNU+ooRmrHLfjlMsKdn0prEKVa0faVanm0jrgu1J/gY=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "1267bb4920d0fc06ea916734c11b0bf004bbe17e", + "rev": "fea3b367d61c1a6592bc47c72f40a9f3e6a53e96", "type": "github" }, "original": { @@ -2001,11 +2001,11 @@ }, "nixpkgs-stable_2": { "locked": { - "lastModified": 1772047000, - "narHash": "sha256-7DaQVv4R97cii/Qdfy4tmDZMB2xxtyIvNGSwXBBhSmo=", + "lastModified": 1773814637, + "narHash": "sha256-GNU+ooRmrHLfjlMsKdn0prEKVa0faVanm0jrgu1J/gY=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "1267bb4920d0fc06ea916734c11b0bf004bbe17e", + "rev": "fea3b367d61c1a6592bc47c72f40a9f3e6a53e96", "type": "github" }, "original": { @@ -2017,11 +2017,11 @@ }, "nixpkgs-stable_3": { "locked": { - "lastModified": 1772047000, - "narHash": "sha256-7DaQVv4R97cii/Qdfy4tmDZMB2xxtyIvNGSwXBBhSmo=", + "lastModified": 1773814637, + "narHash": "sha256-GNU+ooRmrHLfjlMsKdn0prEKVa0faVanm0jrgu1J/gY=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "1267bb4920d0fc06ea916734c11b0bf004bbe17e", + "rev": "fea3b367d61c1a6592bc47c72f40a9f3e6a53e96", "type": "github" }, "original": { @@ -2031,22 +2031,6 @@ "type": "github" } }, - "nixpkgs-update": { - "locked": { - "lastModified": 1772366254, - "narHash": "sha256-BEyksEod87WtnABqiwpqEpRbkpnZcdgnja8hWLajF6w=", - "owner": "r-ryantm", - "repo": "nixpkgs", - "rev": "b11492b3f4f5d1b1fd2a0cf05c0ebf90412c1086", - "type": "github" - }, - "original": { - "owner": "r-ryantm", - "ref": "auto-update/oauth2-proxy", - "repo": "nixpkgs", - "type": "github" - } - }, "nixpkgs_10": { "locked": { "lastModified": 1765934234, @@ -2175,11 +2159,11 @@ }, "nixpkgs_18": { "locked": { - "lastModified": 1772198003, - "narHash": "sha256-I45esRSssFtJ8p/gLHUZ1OUaaTaVLluNkABkk6arQwE=", + "lastModified": 1773821835, + "narHash": "sha256-TJ3lSQtW0E2JrznGVm8hOQGVpXjJyXY2guAxku2O9A4=", "owner": "nixos", "repo": "nixpkgs", - "rev": "dd9b079222d43e1943b6ebd802f04fd959dc8e61", + "rev": "b40629efe5d6ec48dd1efba650c797ddbd39ace0", "type": "github" }, "original": { @@ -2190,179 +2174,6 @@ } }, "nixpkgs_19": { - "locked": { - "lastModified": 1771848320, - "narHash": "sha256-0MAd+0mun3K/Ns8JATeHT1sX28faLII5hVLq0L3BdZU=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "2fc6539b481e1d2569f25f8799236694180c0993", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_2": { - "locked": { - "lastModified": 1772173633, - "narHash": "sha256-MOH58F4AIbCkh6qlQcwMycyk5SWvsqnS/TCfnqDlpj4=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "c0f3d81a7ddbc2b1332be0d8481a672b4f6004d6", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixpkgs-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_20": { - "locked": { - "lastModified": 1720957393, - "narHash": "sha256-oedh2RwpjEa+TNxhg5Je9Ch6d3W1NKi7DbRO1ziHemA=", - "owner": "nixos", - "repo": "nixpkgs", - "rev": "693bc46d169f5af9c992095736e82c3488bf7dbb", - "type": "github" - }, - "original": { - "owner": "nixos", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_21": { - "locked": { - "lastModified": 1772198003, - "narHash": "sha256-I45esRSssFtJ8p/gLHUZ1OUaaTaVLluNkABkk6arQwE=", - "owner": "nixos", - "repo": "nixpkgs", - "rev": "dd9b079222d43e1943b6ebd802f04fd959dc8e61", - "type": "github" - }, - "original": { - "owner": "nixos", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_22": { - "locked": { - "lastModified": 1767892417, - "narHash": "sha256-dhhvQY67aboBk8b0/u0XB6vwHdgbROZT3fJAjyNh5Ww=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "3497aa5c9457a9d88d71fa93a4a8368816fbeeba", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_23": { - "locked": { - "lastModified": 1770073757, - "narHash": "sha256-Vy+G+F+3E/Tl+GMNgiHl9Pah2DgShmIUBJXmbiQPHbI=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "47472570b1e607482890801aeaf29bfb749884f6", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixpkgs-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_24": { - "locked": { - "lastModified": 1770650459, - "narHash": "sha256-hGeOnueXorzwDD1V9ldZr+y+zad4SNyqMnQsa/mIlvI=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "fff0554c67696d76a0cdd9cfe14403fbdbf1f378", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-unstable-small", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_25": { - "locked": { - "lastModified": 1772173633, - "narHash": "sha256-MOH58F4AIbCkh6qlQcwMycyk5SWvsqnS/TCfnqDlpj4=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "c0f3d81a7ddbc2b1332be0d8481a672b4f6004d6", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixpkgs-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_26": { - "locked": { - "lastModified": 1772198003, - "narHash": "sha256-UCaQQ8zmHUocQIgCl+53Jj6NuwqrVKtmv7obE9r6wnw=", - "rev": "dd9b079222d43e1943b6ebd802f04fd959dc8e61", - "type": "tarball", - "url": "https://releases.nixos.org/nixos/unstable/nixos-26.05pre955442.dd9b079222d4/nixexprs.tar.xz" - }, - "original": { - "type": "tarball", - "url": "https://channels.nixos.org/nixos-unstable/nixexprs.tar.xz" - } - }, - "nixpkgs_27": { - "locked": { - "lastModified": 1767767207, - "narHash": "sha256-Mj3d3PfwltLmukFal5i3fFt27L6NiKXdBezC1EBuZs4=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "5912c1772a44e31bf1c63c0390b90501e5026886", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_28": { - "locked": { - "lastModified": 1759733170, - "narHash": "sha256-TXnlsVb5Z8HXZ6mZoeOAIwxmvGHp1g4Dw89eLvIwKVI=", - "owner": "nixos", - "repo": "nixpkgs", - "rev": "8913c168d1c56dc49a7718685968f38752171c3b", - "type": "github" - }, - "original": { - "owner": "nixos", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_29": { "locked": { "lastModified": 1770107345, "narHash": "sha256-tbS0Ebx2PiA1FRW8mt8oejR0qMXmziJmPaU1d4kYY9g=", @@ -2378,13 +2189,186 @@ "type": "github" } }, - "nixpkgs_3": { + "nixpkgs_2": { "locked": { - "lastModified": 1772198003, - "narHash": "sha256-I45esRSssFtJ8p/gLHUZ1OUaaTaVLluNkABkk6arQwE=", + "lastModified": 1773628058, + "narHash": "sha256-hpXH0z3K9xv0fHaje136KY872VT2T5uwxtezlAskQgY=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "dd9b079222d43e1943b6ebd802f04fd959dc8e61", + "rev": "f8573b9c935cfaa162dd62cc9e75ae2db86f85df", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_20": { + "locked": { + "lastModified": 1771848320, + "narHash": "sha256-0MAd+0mun3K/Ns8JATeHT1sX28faLII5hVLq0L3BdZU=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "2fc6539b481e1d2569f25f8799236694180c0993", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_21": { + "locked": { + "lastModified": 1720957393, + "narHash": "sha256-oedh2RwpjEa+TNxhg5Je9Ch6d3W1NKi7DbRO1ziHemA=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "693bc46d169f5af9c992095736e82c3488bf7dbb", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_22": { + "locked": { + "lastModified": 1773821835, + "narHash": "sha256-TJ3lSQtW0E2JrznGVm8hOQGVpXjJyXY2guAxku2O9A4=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "b40629efe5d6ec48dd1efba650c797ddbd39ace0", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_23": { + "locked": { + "lastModified": 1767892417, + "narHash": "sha256-dhhvQY67aboBk8b0/u0XB6vwHdgbROZT3fJAjyNh5Ww=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "3497aa5c9457a9d88d71fa93a4a8368816fbeeba", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_24": { + "locked": { + "lastModified": 1770073757, + "narHash": "sha256-Vy+G+F+3E/Tl+GMNgiHl9Pah2DgShmIUBJXmbiQPHbI=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "47472570b1e607482890801aeaf29bfb749884f6", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_25": { + "locked": { + "lastModified": 1773046814, + "narHash": "sha256-3CEw64UyzEk5QjfbcXNIl4TfmIpa2oY+duuo6aiawcU=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "0c6c0dd2469abaa216599bb19bbf77a328af6564", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable-small", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_26": { + "locked": { + "lastModified": 1773507054, + "narHash": "sha256-Q8U5VXgrcxmCxPtCCJCIZkcAX3FCZwGh1GNVIXxMND0=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "e80236013dc8b77aa49ca90e7a12d86f5d8d64c9", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_27": { + "locked": { + "lastModified": 1773389992, + "narHash": "sha256-wLdaFm1T0uzQya3eG/5+LPbmyB92jE/AnMtVY6re818=", + "rev": "c06b4ae3d6599a672a6210b7021d699c351eebda", + "type": "tarball", + "url": "https://releases.nixos.org/nixos/unstable/nixos-26.05pre962836.c06b4ae3d659/nixexprs.tar.xz" + }, + "original": { + "type": "tarball", + "url": "https://channels.nixos.org/nixos-unstable/nixexprs.tar.xz" + } + }, + "nixpkgs_28": { + "locked": { + "lastModified": 1767767207, + "narHash": "sha256-Mj3d3PfwltLmukFal5i3fFt27L6NiKXdBezC1EBuZs4=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "5912c1772a44e31bf1c63c0390b90501e5026886", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_29": { + "locked": { + "lastModified": 1759733170, + "narHash": "sha256-TXnlsVb5Z8HXZ6mZoeOAIwxmvGHp1g4Dw89eLvIwKVI=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "8913c168d1c56dc49a7718685968f38752171c3b", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_3": { + "locked": { + "lastModified": 1773821835, + "narHash": "sha256-TJ3lSQtW0E2JrznGVm8hOQGVpXjJyXY2guAxku2O9A4=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "b40629efe5d6ec48dd1efba650c797ddbd39ace0", "type": "github" }, "original": { @@ -2395,6 +2379,22 @@ } }, "nixpkgs_30": { + "locked": { + "lastModified": 1770107345, + "narHash": "sha256-tbS0Ebx2PiA1FRW8mt8oejR0qMXmziJmPaU1d4kYY9g=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "4533d9293756b63904b7238acb84ac8fe4c8c2c4", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_31": { "locked": { "lastModified": 1742268799, "narHash": "sha256-IhnK4LhkBlf14/F8THvUy3xi/TxSQkp9hikfDZRD4Ic=", @@ -2410,7 +2410,7 @@ "type": "github" } }, - "nixpkgs_31": { + "nixpkgs_32": { "locked": { "lastModified": 1765934234, "narHash": "sha256-pJjWUzNnjbIAMIc5gRFUuKCDQ9S1cuh3b2hKgA7Mc4A=", @@ -2460,11 +2460,11 @@ }, "nixpkgs_6": { "locked": { - "lastModified": 1771848320, - "narHash": "sha256-0MAd+0mun3K/Ns8JATeHT1sX28faLII5hVLq0L3BdZU=", + "lastModified": 1772198003, + "narHash": "sha256-I45esRSssFtJ8p/gLHUZ1OUaaTaVLluNkABkk6arQwE=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "2fc6539b481e1d2569f25f8799236694180c0993", + "rev": "dd9b079222d43e1943b6ebd802f04fd959dc8e61", "type": "github" }, "original": { @@ -2476,11 +2476,11 @@ }, "nixpkgs_7": { "locked": { - "lastModified": 1759381078, - "narHash": "sha256-gTrEEp5gEspIcCOx9PD8kMaF1iEmfBcTbO0Jag2QhQs=", + "lastModified": 1772773019, + "narHash": "sha256-E1bxHxNKfDoQUuvriG71+f+s/NT0qWkImXsYZNFFfCs=", "owner": "nixos", "repo": "nixpkgs", - "rev": "7df7ff7d8e00218376575f0acdcc5d66741351ee", + "rev": "aca4d95fce4914b3892661bcb80b8087293536c6", "type": "github" }, "original": { @@ -2492,11 +2492,11 @@ }, "nixpkgs_8": { "locked": { - "lastModified": 1772198003, - "narHash": "sha256-I45esRSssFtJ8p/gLHUZ1OUaaTaVLluNkABkk6arQwE=", + "lastModified": 1773821835, + "narHash": "sha256-TJ3lSQtW0E2JrznGVm8hOQGVpXjJyXY2guAxku2O9A4=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "dd9b079222d43e1943b6ebd802f04fd959dc8e61", + "rev": "b40629efe5d6ec48dd1efba650c797ddbd39ace0", "type": "github" }, "original": { @@ -2608,11 +2608,11 @@ "noctalia-qs": "noctalia-qs" }, "locked": { - "lastModified": 1772453415, - "narHash": "sha256-8TCMSFCBZdutKryFKX72GOb/NWL9/vB5rswgWXV/EuM=", + "lastModified": 1774097158, + "narHash": "sha256-FSh7z+ms3CW58S0HqR3gkGe8cY3H0y8+c9rvxwHUpR8=", "owner": "noctalia-dev", "repo": "noctalia-shell", - "rev": "8ebf2bf33220c62f3c5e937a318eceb25dd17228", + "rev": "5eaefd8bfdcc7bfa7695002e91815405442f4323", "type": "github" }, "original": { @@ -2626,14 +2626,16 @@ "nixpkgs": [ "noctalia", "nixpkgs" - ] + ], + "systems": "systems_3", + "treefmt-nix": "treefmt-nix_2" }, "locked": { - "lastModified": 1772227064, - "narHash": "sha256-f821ZSoGpa/aXrWq0gPpea9qBnX8KDyavGKkptz2Mog=", + "lastModified": 1773842483, + "narHash": "sha256-oRqz+5AbNKfUWWwN5c83CsSOsUWVGITh0HZg+wX5Q/8=", "owner": "noctalia-dev", "repo": "noctalia-qs", - "rev": "0741d27d2f7db567270f139c5d1684614ecf9863", + "rev": "3962ff1e0b59ef067c57199d31271ddbf23b29cd", "type": "github" }, "original": { @@ -2646,8 +2648,8 @@ "inputs": { "flake-parts": "flake-parts_5", "git-hooks-nix": "git-hooks-nix_2", - "nixpkgs": "nixpkgs_19", - "treefmt-nix": "treefmt-nix_2" + "nixpkgs": "nixpkgs_20", + "treefmt-nix": "treefmt-nix_3" }, "locked": { "lastModified": 1772055992, @@ -2682,7 +2684,7 @@ "nswitch-rcm-nix": { "inputs": { "flake-parts": "flake-parts_6", - "nixpkgs": "nixpkgs_20" + "nixpkgs": "nixpkgs_21" }, "locked": { "lastModified": 1721304043, @@ -2701,14 +2703,14 @@ "nur": { "inputs": { "flake-parts": "flake-parts_7", - "nixpkgs": "nixpkgs_21" + "nixpkgs": "nixpkgs_22" }, "locked": { - "lastModified": 1772457611, - "narHash": "sha256-kqmCdDMGk7zn6c0Sh2T3peyWPCbotMVp0FoWS+I2ISs=", + "lastModified": 1774099594, + "narHash": "sha256-/n1KJ0mAMgiv+uZ7gUwdGrXLyb+hYcsv4z1AfYCF/Cg=", "owner": "nix-community", "repo": "NUR", - "rev": "3b63a4c22748d5d0e9052c67f455cb138051ac33", + "rev": "d9b70fb882dfb03e93b9aaaacf18a9632a0d1e0f", "type": "github" }, "original": { @@ -2859,7 +2861,7 @@ "pia": { "inputs": { "flake-utils": "flake-utils_5", - "nixpkgs": "nixpkgs_22" + "nixpkgs": "nixpkgs_23" }, "locked": { "lastModified": 1772467409, @@ -2886,11 +2888,11 @@ ] }, "locked": { - "lastModified": 1771858127, - "narHash": "sha256-Gtre9YoYl3n25tJH2AoSdjuwcqij5CPxL3U3xysYD08=", + "lastModified": 1772024342, + "narHash": "sha256-+eXlIc4/7dE6EcPs9a2DaSY3fTA9AE526hGqkNID3Wg=", "owner": "cachix", "repo": "pre-commit-hooks.nix", - "rev": "49bbbfc218bf3856dfa631cead3b052d78248b83", + "rev": "6e34e97ed9788b17796ee43ccdbaf871a5c2b476", "type": "github" }, "original": { @@ -2926,14 +2928,14 @@ "inputs": { "flake-compat": "flake-compat_8", "gitignore": "gitignore_5", - "nixpkgs": "nixpkgs_23" + "nixpkgs": "nixpkgs_24" }, "locked": { - "lastModified": 1772024342, - "narHash": "sha256-+eXlIc4/7dE6EcPs9a2DaSY3fTA9AE526hGqkNID3Wg=", + "lastModified": 1772893680, + "narHash": "sha256-JDqZMgxUTCq85ObSaFw0HhE+lvdOre1lx9iI6vYyOEs=", "owner": "cachix", "repo": "git-hooks.nix", - "rev": "6e34e97ed9788b17796ee43ccdbaf871a5c2b476", + "rev": "8baab586afc9c9b57645a734c820e4ac0a604af9", "type": "github" }, "original": { @@ -2978,7 +2980,6 @@ "nixpkgs-stable24_11": "nixpkgs-stable24_11", "nixpkgs-stable25_05": "nixpkgs-stable25_05", "nixpkgs-stable25_11": "nixpkgs-stable25_11", - "nixpkgs-update": "nixpkgs-update", "noctalia": "noctalia", "noctoggle": "noctoggle", "nswitch-rcm-nix": "nswitch-rcm-nix", @@ -2991,9 +2992,9 @@ "spicetify-nix": "spicetify-nix", "stylix": "stylix", "swarsel-nix": "swarsel-nix", - "systems": "systems_7", + "systems": "systems_8", "topologyPrivate": "topologyPrivate", - "treefmt-nix": "treefmt-nix_3", + "treefmt-nix": "treefmt-nix_4", "vbc-nix": "vbc-nix", "zjstatus": "zjstatus" } @@ -3023,11 +3024,11 @@ ] }, "locked": { - "lastModified": 1771988922, - "narHash": "sha256-Fc6FHXtfEkLtuVJzd0B6tFYMhmcPLuxr90rWfb/2jtQ=", + "lastModified": 1772334676, + "narHash": "sha256-Jrc0J3AH+iNJDlUze3+FJZv2R0BZnhANFnD52V4kyvI=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "f4443dc3f0b6c5e6b77d923156943ce816d1fcb9", + "rev": "9879be11f30fd3bbf848e653a7f991549e8973b5", "type": "github" }, "original": { @@ -3111,14 +3112,14 @@ "blobs": "blobs", "flake-compat": "flake-compat_9", "git-hooks": "git-hooks", - "nixpkgs": "nixpkgs_24" + "nixpkgs": "nixpkgs_25" }, "locked": { - "lastModified": 1772064816, - "narHash": "sha256-ks1D9Rtmopd5F/8ENjEUJpSYYMxv603/v6TRen9Hq54=", + "lastModified": 1774001769, + "narHash": "sha256-6y8yLrMecnFq21wFlUSxHF7OsabVCCj2p104HEUosvI=", "owner": "simple-nixos-mailserver", "repo": "nixos-mailserver", - "rev": "ea4dc17f4bc0f65eed082fa394509e4543072b56", + "rev": "05968d7978faaa501836d6d2eb7f6cffb4140829", "type": "gitlab" }, "original": { @@ -3147,14 +3148,14 @@ }, "sops": { "inputs": { - "nixpkgs": "nixpkgs_25" + "nixpkgs": "nixpkgs_26" }, "locked": { - "lastModified": 1772401007, - "narHash": "sha256-YHykQg0h9hrlZGpMcywnaFzQ1Kn/5YNCCOSaaAl6z7Q=", + "lastModified": 1773889674, + "narHash": "sha256-+ycaiVAk3MEshJTg35cBTUa0MizGiS+bgpYw/f8ohkg=", "owner": "Mic92", "repo": "sops-nix", - "rev": "d8be5ea4cd3bc363492ab5bc6e874ccdc5465fe4", + "rev": "29b6519f3e0780452bca0ac0be4584f04ac16cc5", "type": "github" }, "original": { @@ -3166,11 +3167,11 @@ "spectrum": { "flake": false, "locked": { - "lastModified": 1759482047, - "narHash": "sha256-H1wiXRQHxxPyMMlP39ce3ROKCwI5/tUn36P8x6dFiiQ=", + "lastModified": 1772189877, + "narHash": "sha256-i1p90Rgssb//aNiTDFq46ZG/fk3LmyRLChtp/9lddyA=", "ref": "refs/heads/main", - "rev": "c5d5786d3dc938af0b279c542d1e43bce381b4b9", - "revCount": 996, + "rev": "fe39e122d898f66e89ffa17d4f4209989ccb5358", + "revCount": 1255, "type": "git", "url": "https://spectrum-os.org/git/spectrum" }, @@ -3181,15 +3182,15 @@ }, "spicetify-nix": { "inputs": { - "nixpkgs": "nixpkgs_26", - "systems": "systems_4" + "nixpkgs": "nixpkgs_27", + "systems": "systems_5" }, "locked": { - "lastModified": 1772494187, - "narHash": "sha256-6ksgNAFXVK+Cg/6ww7bB2nJUPZlnS75UwZC7G+L03EE=", + "lastModified": 1773619901, + "narHash": "sha256-Br8CQy4ht+a2OxyzaRwuP5+oIFfoRvCxYgsmdrgid40=", "owner": "Gerg-l", "repo": "spicetify-nix", - "rev": "915ab06b046d05613041780c575c62a32fe67cea", + "rev": "6f06ff05cd536b790b7662550a10b61a1ac4619e", "type": "github" }, "original": { @@ -3285,9 +3286,9 @@ "firefox-gnome-theme": "firefox-gnome-theme", "flake-parts": "flake-parts_8", "gnome-shell": "gnome-shell", - "nixpkgs": "nixpkgs_27", + "nixpkgs": "nixpkgs_28", "nur": "nur_2", - "systems": "systems_5", + "systems": "systems_6", "tinted-foot": "tinted-foot", "tinted-kitty": "tinted-kitty", "tinted-schemes": "tinted-schemes", @@ -3311,8 +3312,8 @@ "swarsel-nix": { "inputs": { "flake-parts": "flake-parts_9", - "nixpkgs": "nixpkgs_28", - "systems": "systems_6" + "nixpkgs": "nixpkgs_29", + "systems": "systems_7" }, "locked": { "lastModified": 1760190732, @@ -3344,6 +3345,21 @@ "type": "github" } }, + "systems_10": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, "systems_2": { "locked": { "lastModified": 1681028828, @@ -3361,16 +3377,16 @@ }, "systems_3": { "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "lastModified": 1689347949, + "narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=", "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "repo": "default-linux", + "rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68", "type": "github" }, "original": { "owner": "nix-systems", - "repo": "default", + "repo": "default-linux", "type": "github" } }, @@ -3435,21 +3451,6 @@ } }, "systems_8": { - "locked": { - "lastModified": 1689347949, - "narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=", - "owner": "nix-systems", - "repo": "default-linux", - "rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default-linux", - "type": "github" - } - }, - "systems_9": { "locked": { "lastModified": 1681028828, "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", @@ -3464,6 +3465,21 @@ "type": "github" } }, + "systems_9": { + "locked": { + "lastModified": 1689347949, + "narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=", + "owner": "nix-systems", + "repo": "default-linux", + "rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default-linux", + "type": "github" + } + }, "tinted-foot": { "flake": false, "locked": { @@ -3578,6 +3594,24 @@ } }, "treefmt-nix_2": { + "inputs": { + "nixpkgs": "nixpkgs_19" + }, + "locked": { + "lastModified": 1772660329, + "narHash": "sha256-IjU1FxYqm+VDe5qIOxoW+pISBlGvVApRjiw/Y/ttJzY=", + "owner": "numtide", + "repo": "treefmt-nix", + "rev": "3710e0e1218041bbad640352a0440114b1e10428", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "treefmt-nix", + "type": "github" + } + }, + "treefmt-nix_3": { "inputs": { "nixpkgs": [ "noctoggle", @@ -3598,16 +3632,16 @@ "type": "github" } }, - "treefmt-nix_3": { + "treefmt-nix_4": { "inputs": { - "nixpkgs": "nixpkgs_29" + "nixpkgs": "nixpkgs_30" }, "locked": { - "lastModified": 1770228511, - "narHash": "sha256-wQ6NJSuFqAEmIg2VMnLdCnUc0b7vslUohqqGGD+Fyxk=", + "lastModified": 1773297127, + "narHash": "sha256-6E/yhXP7Oy/NbXtf1ktzmU8SdVqJQ09HC/48ebEGBpk=", "owner": "numtide", "repo": "treefmt-nix", - "rev": "337a4fe074be1042a35086f15481d763b8ddc0e7", + "rev": "71b125cd05fbfd78cab3e070b73544abe24c5016", "type": "github" }, "original": { @@ -3618,15 +3652,15 @@ }, "vbc-nix": { "inputs": { - "nixpkgs": "nixpkgs_30", - "systems": "systems_8" + "nixpkgs": "nixpkgs_31", + "systems": "systems_9" }, "locked": { - "lastModified": 1772450324, - "narHash": "sha256-WVmVk/wBPq2MXKKOBdoRM0i+0o7Lx+mNQk5I/fUA1eo=", + "lastModified": 1772713934, + "narHash": "sha256-d4rorri6VU3GmotqebMpEd2QwV29AcAgtwqhkn91/2Y=", "ref": "main", - "rev": "cf687d4f2b9a3dd69de99555f5511ede05254919", - "revCount": 7, + "rev": "19aec02831b535175f1c1e0bf639ccc9eec68613", + "revCount": 8, "type": "git", "url": "ssh://git@github.com/vbc-it/vbc-nix.git" }, @@ -3656,11 +3690,11 @@ "xwayland-satellite-unstable": { "flake": false, "locked": { - "lastModified": 1772429643, - "narHash": "sha256-M+bAeCCcjBnVk6w/4dIVvXvpJwOKnXjwi/lDbaN6Yws=", + "lastModified": 1773622265, + "narHash": "sha256-wToKwH7IgWdGLMSIWksEDs4eumR6UbbsuPQ42r0oTXQ=", "owner": "Supreeeme", "repo": "xwayland-satellite", - "rev": "10f985b84cdbcc3bbf35b3e7e43d1b2a84fa9ce2", + "rev": "a879e5e0896a326adc79c474bf457b8b99011027", "type": "github" }, "original": { @@ -3696,15 +3730,15 @@ "inputs": { "crane": "crane_3", "flake-utils": "flake-utils_6", - "nixpkgs": "nixpkgs_31", + "nixpkgs": "nixpkgs_32", "rust-overlay": "rust-overlay_3" }, "locked": { - "lastModified": 1771148613, - "narHash": "sha256-nLzdw8jskekSRrunxBDCA0NCHr/2aJjcXqZ1Fcqm5eY=", + "lastModified": 1773119656, + "narHash": "sha256-AE6SthrvDyUU70myW7wAq4mzQbtmK5Spng7Y/OdCdhI=", "owner": "dj95", "repo": "zjstatus", - "rev": "7a039f56da80681408454d6e175fde3f54b9e592", + "rev": "e80d508ffbff6ab6b39a481ae9986109d3c313ac", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 04fbe8c..a8c316d 100644 --- a/flake.nix +++ b/flake.nix @@ -28,7 +28,7 @@ smallpkgs.url = "github:nixos/nixpkgs/08fcb0dcb59df0344652b38ea6326a2d8271baff?narHash=sha256-HXIQzULIG/MEUW2Q/Ss47oE3QrjxvpUX7gUl4Xp6lnc%3D&shallow=1"; nixpkgs-dev.url = "github:Swarsel/nixpkgs/main"; nixpkgs-bisect.url = "github:nixos/nixpkgs/master"; - nixpkgs-update.url = "github:r-ryantm/nixpkgs/auto-update/oauth2-proxy"; + # nixpkgs-update.url = "github:r-ryantm/nixpkgs/auto-update/oauth2-proxy"; # nixpkgs-kernel.url = "github:NixOS/nixpkgs/063f43f2dbdef86376cc29ad646c45c46e93234c?narHash=sha256-6m1Y3/4pVw1RWTsrkAK2VMYSzG4MMIj7sqUy7o8th1o%3D"; #specifically pinned for kernel version nixpkgs-kernel.url = "github:nixos/nixpkgs/dd9b079222d43e1943b6ebd802f04fd959dc8e61?narHash=sha256-I45esRSssFtJ8p/gLHUZ1OUaaTaVLluNkABkk6arQwE%3D"; #specifically pinned for kernel version nixpkgs-stable.url = "github:NixOS/nixpkgs/nixos-25.11"; diff --git a/install/installer-config.nix b/install/installer-config.nix index d89b749..4f9cbd3 100644 --- a/install/installer-config.nix +++ b/install/installer-config.nix @@ -108,7 +108,7 @@ in networking = { hostName = "drugstore"; - wireless.enable = false; + wireless.enable = lib.mkForce false; # dhcpcd.runHook = "${pkgs.utillinux}/bin/agetty --reload"; networkmanager.enable = true; usePredictableInterfaceNames = false; diff --git a/modules/home/common/gpg-agent.nix b/modules/home/common/gpg-agent.nix index 7a052bf..4229e8b 100644 --- a/modules/home/common/gpg-agent.nix +++ b/modules/home/common/gpg-agent.nix @@ -28,6 +28,9 @@ in programs.gpg = { enable = true; + scdaemonSettings = { + disable-ccid = true; # prevent conflicts between pcscd and scdameon + }; publicKeys = [ { source = "${self}/secrets/public/gpg/gpg-public-key-0x76FD3810215AE097.asc"; diff --git a/modules/home/common/nix-index.nix b/modules/home/common/nix-index.nix index b749bf8..b42b36a 100644 --- a/modules/home/common/nix-index.nix +++ b/modules/home/common/nix-index.nix @@ -1,4 +1,4 @@ -{ self, lib, config, pkgs, ... }: +{ lib, config, pkgs, ... }: { options.swarselmodules.nix-index = lib.mkEnableOption "nix-index settings"; config = lib.mkIf config.swarselmodules.nix-index { @@ -6,7 +6,43 @@ let commandNotFound = pkgs.runCommandLocal "command-not-found.sh" { } '' mkdir -p $out/etc/profile.d - substitute ${self + /files/scripts/command-not-found.sh} \ + cat > $out/etc/profile.d/command-not-found.sh <<'EOF' + # Adapted from https://github.com/bennofs/nix-index/blob/master/command-not-found.sh + command_not_found_handle() { + if [ -n "''${MC_SID-}" ] || ! [ -t 1 ]; then + >&2 echo "$1: command not found" + return 127 + fi + + echo -n "searching nix-index..." + ATTRS=$(@nix-locate@ --minimal --no-group --type x --type s --whole-name --at-root "/bin/$1") + + case $(echo -n "$ATTRS" | grep -c "^") in + 0) + >&2 echo -ne "$(@tput@ el1)\r" + >&2 echo "$1: command not found" + ;; + *) + >&2 echo -ne "$(@tput@ el1)\r" + >&2 echo "The program ‘$(@tput@ setaf 4)$1$(@tput@ sgr0)’ is currently not installed." + >&2 echo "It is provided by the following derivation(s):" + while read -r ATTR; do + ATTR=''${ATTR%.out} + >&2 echo " $(@tput@ setaf 12)nixpkgs#$(@tput@ setaf 4)$ATTR$(@tput@ sgr0)" + done <<< "$ATTRS" + ;; + esac + + return 127 + } + + command_not_found_handler() { + command_not_found_handle "$@" + return $? + } + EOF + + substitute $out/etc/profile.d/command-not-found.sh \ $out/etc/profile.d/command-not-found.sh \ --replace-fail @nix-locate@ ${pkgs.nix-index}/bin/nix-locate \ --replace-fail @tput@ ${pkgs.ncurses}/bin/tput diff --git a/modules/home/common/packages.nix b/modules/home/common/packages.nix index 40cb0b9..dc7f04f 100644 --- a/modules/home/common/packages.nix +++ b/modules/home/common/packages.nix @@ -171,13 +171,12 @@ }) # font stuff - nerd-fonts.fira-mono + cantarell-fonts nerd-fonts.fira-code + (iosevka-bin.override { variant = "Aile"; }) nerd-fonts.symbols-only noto-fonts-color-emoji font-awesome_5 - noto-fonts - noto-fonts-cjk-sans ]; }; } diff --git a/modules/nixos/client/hardwarecompatibility-yubikey.nix b/modules/nixos/client/hardwarecompatibility-yubikey.nix index 75f55bc..58b0078 100644 --- a/modules/nixos/client/hardwarecompatibility-yubikey.nix +++ b/modules/nixos/client/hardwarecompatibility-yubikey.nix @@ -8,7 +8,7 @@ in config = lib.mkIf config.swarselmodules.yubikey { programs.ssh.startAgent = false; - services.pcscd.enable = false; + services.pcscd.enable = true; hardware.gpgSmartcards.enable = true; diff --git a/modules/nixos/optional/hibernation.nix b/modules/nixos/optional/hibernation.nix index 29c9675..342afbf 100644 --- a/modules/nixos/optional/hibernation.nix +++ b/modules/nixos/optional/hibernation.nix @@ -22,9 +22,9 @@ }; systemd.services."systemd-suspend-then-hibernate".aliases = [ "systemd-suspend.service" ]; powerManagement.enable = true; - systemd.sleep.extraConfig = '' - HibernateDelaySec=120m - SuspendState=freeze - ''; + systemd.sleep.settings.Sleep = { + HibernateDelaySec = "120m"; + SuspendState = "freeze"; + }; }; } diff --git a/modules/nixos/optional/microvm-guest-shares.nix b/modules/nixos/optional/microvm-guest-shares.nix index f6ad083..9478898 100644 --- a/modules/nixos/optional/microvm-guest-shares.nix +++ b/modules/nixos/optional/microvm-guest-shares.nix @@ -1,4 +1,4 @@ -{ self, lib, config, inputs, microVMParent, nodes, ... }: +{ lib, config, microVMParent, nodes, ... }: { config = { microvm = { diff --git a/modules/nixos/server/disk-encrypt.nix b/modules/nixos/server/disk-encrypt.nix index d5dde08..cdc4823 100644 --- a/modules/nixos/server/disk-encrypt.nix +++ b/modules/nixos/server/disk-encrypt.nix @@ -1,11 +1,5 @@ -{ self, pkgs, lib, config, globals, minimal, ... }: +{ self, pkgs, lib, config, minimal, ... }: let - localIp = globals.networks.${config.swarselsystems.server.netConfigName}.hosts.${config.node.name}.ipv4; - subnetMask = globals.networks.${config.swarselsystems.server.netConfigName}.subnetMask4; - gatewayIp = globals.hosts.${config.node.name}.defaultGateway4; - - inherit (globals.general) routerServer; - isRouter = config.node.name == routerServer; hostKeyPathBase = "/etc/secrets/initrd/ssh_host_ed25519_key"; hostKeyPath = diff --git a/modules/nixos/server/oauth2-proxy.nix b/modules/nixos/server/oauth2-proxy.nix index 2f2af41..dfc89a3 100644 --- a/modules/nixos/server/oauth2-proxy.nix +++ b/modules/nixos/server/oauth2-proxy.nix @@ -165,7 +165,7 @@ in services = { ${serviceName} = { enable = true; - package = pkgs.update.oauth2-proxy; + package = pkgs.oauth2-proxy; cookie = { domain = ".${mainDomain}"; secure = true; diff --git a/modules/nixos/server/postgresql.nix b/modules/nixos/server/postgresql.nix index 0a4f9f9..d02e28e 100644 --- a/modules/nixos/server/postgresql.nix +++ b/modules/nixos/server/postgresql.nix @@ -1,4 +1,4 @@ -{ self, config, lib, pkgs, confLib, ... }: +{ config, lib, pkgs, confLib, ... }: let inherit (confLib.gen { name = "postgresql"; port = 3254; }) serviceName; postgresVersion = 14; diff --git a/modules/shared/vars.nix b/modules/shared/vars.nix index ce25ff7..869d26c 100644 --- a/modules/shared/vars.nix +++ b/modules/shared/vars.nix @@ -37,23 +37,27 @@ }; serif = { # package = (pkgs.nerdfonts.override { fonts = [ "FiraMono" "FiraCode"]; }); - package = pkgs.cantarell-fonts; + # package = pkgs.cantarell-fonts; # package = pkgs.montserrat; - name = "Cantarell"; + # name = "Cantarell"; + package = pkgs.iosevka-bin.override { variant = "Aile"; }; + name = "Iosevka Aile"; # name = "FiraCode Nerd Font Propo"; # name = "Montserrat"; }; sansSerif = { # package = (pkgs.nerdfonts.override { fonts = [ "FiraMono" "FiraCode"]; }); - package = pkgs.cantarell-fonts; + # package = pkgs.cantarell-fonts; # package = pkgs.montserrat; - name = "Cantarell"; + # name = "Cantarell"; + package = pkgs.iosevka-bin.override { variant = "Aile"; }; + name = "Iosevka Aile"; # name = "FiraCode Nerd Font Propo"; # name = "Montserrat"; }; monospace = { - package = pkgs.nerd-fonts.fira-mono; # has overrides - name = "FiraCode Nerd Font Mono"; + package = pkgs.nerd-fonts.fira-code; # has overrides + name = "FiraCode Nerd Font"; }; emoji = { package = pkgs.noto-fonts-color-emoji; diff --git a/nix/overlays.nix b/nix/overlays.nix index dff0d55..8179f9f 100644 --- a/nix/overlays.nix +++ b/nix/overlays.nix @@ -108,8 +108,6 @@ in "libreoffice" "libreoffice-qt" "nerd-fonts-symbols-only" - "noto-fonts" - "noto-fonts-cjk-sans" "noto-fonts-color-emoji" # "pipewire" "podman" diff --git a/pkgs/flake/cdb/default.nix b/pkgs/flake/cdb/default.nix index d657a18..f5518c8 100644 --- a/pkgs/flake/cdb/default.nix +++ b/pkgs/flake/cdb/default.nix @@ -1,5 +1,4 @@ { name, writeShellApplication, fzf, ... }: - writeShellApplication { inherit name; runtimeInputs = [ fzf ]; diff --git a/pkgs/flake/cdw/default.nix b/pkgs/flake/cdw/default.nix index b4b5bf7..33922dd 100644 --- a/pkgs/flake/cdw/default.nix +++ b/pkgs/flake/cdw/default.nix @@ -1,5 +1,4 @@ { name, writeShellApplication, fzf, ... }: - writeShellApplication { inherit name; runtimeInputs = [ fzf ]; diff --git a/pkgs/flake/cura5/default.nix b/pkgs/flake/cura5/default.nix index 68905d8..45635d4 100644 --- a/pkgs/flake/cura5/default.nix +++ b/pkgs/flake/cura5/default.nix @@ -1,7 +1,5 @@ # taken from https://github.com/NixOS/nixpkgs/issues/186570#issuecomment-1627797219 { appimageTools, fetchurl, writeScriptBin, pkgs, ... }: - - let cura5 = appimageTools.wrapType2 rec { pname = "cura5"; diff --git a/pkgs/flake/e/default.nix b/pkgs/flake/e/default.nix index 7043846..1a20a4b 100644 --- a/pkgs/flake/e/default.nix +++ b/pkgs/flake/e/default.nix @@ -1,6 +1,30 @@ -{ self, name, writeShellApplication, emacs30-pgtk, sway, jq }: +{ name, writeShellApplication, emacs30-pgtk, sway, jq, ... }: writeShellApplication { inherit name; runtimeInputs = [ emacs30-pgtk sway jq ]; - text = builtins.readFile "${self}/files/scripts/${name}.sh"; + text = '' + wait=0 + while :; do + case ''${1:-} in + -w | --wait) + wait=1 + ;; + *) break ;; + esac + shift + done + + STR=$(swaymsg -t get_tree | jq -r 'recurse(.nodes[]) | select(.name == "__i3_scratch")' | grep kittyterm || true) + if [ "$STR" == "" ]; then + swaymsg '[title="kittyterm"]' scratchpad show + emacsclient -c -a "" "$@" + swaymsg '[title="kittyterm"]' scratchpad show + else + if [[ $wait -eq 0 ]]; then + emacsclient -n -c -a "" "$@" + else + emacsclient -c -a "" "$@" + fi + fi + ''; } diff --git a/pkgs/flake/fs-diff/default.nix b/pkgs/flake/fs-diff/default.nix index 978ac41..acdc5b1 100644 --- a/pkgs/flake/fs-diff/default.nix +++ b/pkgs/flake/fs-diff/default.nix @@ -1,5 +1,26 @@ -{ self, name, writeShellApplication }: +{ name, writeShellApplication, ... }: writeShellApplication { inherit name; - text = builtins.readFile "${self}/files/scripts/${name}.sh"; + text = '' + set -euo pipefail + + OLD_TRANSID=$(sudo btrfs subvolume find-new /mnt/root-blank 9999999) + OLD_TRANSID=''${OLD_TRANSID#transid marker was } + + sudo btrfs subvolume find-new "/mnt/root" "$OLD_TRANSID" | + sed '$d' | + cut -f17- -d' ' | + sort | + uniq | + while read -r path; do + path="/$path" + if [ -L "$path" ]; then + : # The path is a symbolic link, so is probably handled by NixOS already + elif [ -d "$path" ]; then + : # The path is a directory, ignore + else + echo "$path" + fi + done + ''; } diff --git a/pkgs/flake/hm-specialisation/default.nix b/pkgs/flake/hm-specialisation/default.nix index bbe3809..c503b76 100644 --- a/pkgs/flake/hm-specialisation/default.nix +++ b/pkgs/flake/hm-specialisation/default.nix @@ -1,5 +1,4 @@ { name, writeShellApplication, fzf, findutils, home-manager, ... }: - writeShellApplication { inherit name; runtimeInputs = [ fzf findutils home-manager ]; diff --git a/pkgs/flake/niri-resize/default.nix b/pkgs/flake/niri-resize/default.nix index d01d97e..6ae46dd 100644 --- a/pkgs/flake/niri-resize/default.nix +++ b/pkgs/flake/niri-resize/default.nix @@ -1,6 +1,18 @@ -{ self, name, writeShellApplication, jq }: +{ name, writeShellApplication, jq, ... }: writeShellApplication { inherit name; runtimeInputs = [ jq ]; - text = builtins.readFile "${self}/files/scripts/${name}.sh"; + text = '' + WORKSPACE=$(niri msg -j workspaces | jq -r '.[] | select(.is_focused == true) | .id') + + COUNT=$(niri msg -j windows | jq --argjson ws "$WORKSPACE" -r '.[] | select(.workspace_id == $ws and .is_floating == false) | .app_id' | wc -l) + + while [[ $COUNT == "0" || $COUNT == "2" ]]; do + COUNT=$(niri msg -j windows | jq --argjson ws "$WORKSPACE" -r '.[] | select(.workspace_id == $ws and .is_floating == false) | .app_id' | wc -l) + done + + if [[ $COUNT == "1" ]]; then + niri msg action maximize-column + fi + ''; } diff --git a/pkgs/flake/opacitytoggle/default.nix b/pkgs/flake/opacitytoggle/default.nix index d6c547b..943f19d 100644 --- a/pkgs/flake/opacitytoggle/default.nix +++ b/pkgs/flake/opacitytoggle/default.nix @@ -1,6 +1,12 @@ -{ self, name, writeShellApplication, sway }: +{ name, writeShellApplication, sway, ... }: writeShellApplication { inherit name; runtimeInputs = [ sway ]; - text = builtins.readFile "${self}/files/scripts/${name}.sh"; + text = '' + if swaymsg opacity plus 0.01 -q; then + swaymsg opacity 1 + else + swaymsg opacity 0.95 + fi + ''; } diff --git a/pkgs/flake/pass-fuzzel/default.nix b/pkgs/flake/pass-fuzzel/default.nix index ae34790..ba12608 100644 --- a/pkgs/flake/pass-fuzzel/default.nix +++ b/pkgs/flake/pass-fuzzel/default.nix @@ -1,6 +1,58 @@ -{ self, name, writeShellApplication, libnotify, pass, fuzzel, wtype }: +{ name, writeShellApplication, libnotify, pass, fuzzel, wtype, ... }: writeShellApplication { inherit name; runtimeInputs = [ libnotify (pass.withExtensions (exts: [ exts.pass-otp ])) fuzzel wtype ]; - text = builtins.readFile "${self}/files/scripts/${name}.sh"; + text = '' + # Adapted from https://code.kulupu.party/thesuess/home-manager/src/branch/main/modules/river.nix + shopt -s nullglob globstar + + otp=0 + typeit=0 + while :; do + case ''${1:-} in + -t | --type) + typeit=1 + ;; + -o | --otp) + otp=1 + ;; + *) break ;; + esac + shift + done + + export PASSWORD_STORE_DIR=~/.local/share/password-store + prefix=''${PASSWORD_STORE_DIR-~/.local/share/password-store} + if [[ $otp -eq 0 ]]; then + password_files=("$prefix"/**/*.gpg) + else + password_files=("$prefix"/otp/**/*.gpg) + fi + password_files=("''${password_files[@]#"$prefix"/}") + password_files=("''${password_files[@]%.gpg}") + + password=$(printf '%s\n' "''${password_files[@]}" | fuzzel --dmenu "$@") + + [[ -n $password ]] || exit + if [[ $otp -eq 0 ]]; then + if [[ $typeit -eq 0 ]]; then + pass show -c "$password" &> /tmp/pass-fuzzel + else + pass show "$password" | { + IFS= read -r pass + printf %s "$pass" + } | wtype - + fi + else + if [[ $typeit -eq 0 ]]; then + pass otp -c "$password" &> /tmp/pass-fuzzel + else + pass otp "$password" | { + IFS= read -r pass + printf %s "$pass" + } | wtype - + fi + fi + notify-send -u critical -a pass -t 1000 "Copied/Typed Password" + ''; } diff --git a/pkgs/flake/project/default.nix b/pkgs/flake/project/default.nix index 978ac41..e0fb83c 100644 --- a/pkgs/flake/project/default.nix +++ b/pkgs/flake/project/default.nix @@ -1,5 +1,13 @@ -{ self, name, writeShellApplication }: +{ name, writeShellApplication, ... }: writeShellApplication { inherit name; - text = builtins.readFile "${self}/files/scripts/${name}.sh"; + text = '' + set -euo pipefail + + if [ ! -d "$(pwd)/.git" ]; then + git init + fi + nix flake init --template "$FLAKE"#"$1" + direnv allow + ''; } diff --git a/pkgs/flake/prstatus/default.nix b/pkgs/flake/prstatus/default.nix index b8a29fe..f36c146 100644 --- a/pkgs/flake/prstatus/default.nix +++ b/pkgs/flake/prstatus/default.nix @@ -1,5 +1,4 @@ { name, writeShellApplication, curl, ... }: - writeShellApplication { inherit name; runtimeInputs = [ curl ]; diff --git a/pkgs/flake/quickpass/default.nix b/pkgs/flake/quickpass/default.nix index c13b8c0..6ff3b2c 100644 --- a/pkgs/flake/quickpass/default.nix +++ b/pkgs/flake/quickpass/default.nix @@ -1,6 +1,19 @@ -{ self, name, writeShellApplication, libnotify, pass, wtype }: +{ name, writeShellApplication, libnotify, pass, wtype, ... }: writeShellApplication { inherit name; runtimeInputs = [ libnotify pass wtype ]; - text = builtins.readFile "${self}/files/scripts/${name}.sh"; + text = '' + shopt -s nullglob globstar + + notify-send "$(env | grep -E 'WAYLAND|SWAY')" + + password="$1" + + pass show "$password" | { + IFS= read -r pass + printf %s "$pass" + } | wtype - + + notify-send -u critical -a pass -t 1000 "Typed Password" + ''; } diff --git a/pkgs/flake/sshrm/default.nix b/pkgs/flake/sshrm/default.nix index 31f6957..2e4772a 100644 --- a/pkgs/flake/sshrm/default.nix +++ b/pkgs/flake/sshrm/default.nix @@ -1,6 +1,18 @@ -{ self, name, writeShellApplication, openssh }: +{ name, writeShellApplication, openssh, ... }: writeShellApplication { inherit name; runtimeInputs = [ openssh ]; - text = builtins.readFile "${self}/files/scripts/${name}.sh"; + text = '' + HISTFILE="$HOME"/.histfile + + last_ssh_cmd=$(grep -E "ssh " "$HISTFILE" | sed -E 's/^: [0-9]+:[0-9]+;//' | grep "^ssh " | tail -1) + host=$(echo "$last_ssh_cmd" | sed -E 's/.*ssh ([^@ ]+@)?([^ ]+).*/\2/') + + if [[ -n $host ]]; then + echo "Removing SSH host key for: $host" + ssh-keygen -R "$host" + else + echo "No valid SSH command found in history." + fi + ''; } diff --git a/pkgs/flake/swarsel-bootstrap/default.nix b/pkgs/flake/swarsel-bootstrap/default.nix index 31f6957..6aece13 100644 --- a/pkgs/flake/swarsel-bootstrap/default.nix +++ b/pkgs/flake/swarsel-bootstrap/default.nix @@ -1,6 +1,401 @@ -{ self, name, writeShellApplication, openssh }: +{ name, writeShellApplication, openssh, ... }: writeShellApplication { inherit name; runtimeInputs = [ openssh ]; - text = builtins.readFile "${self}/files/scripts/${name}.sh"; + text = '' + # highly inspired by https://github.com/EmergentMind/nix-config/blob/dev/files/scripts/bootstrap-nixos.sh + set -eo pipefail + + target_hostname="" + target_destination="" + target_arch="" + target_user="swarsel" + ssh_port="22" + persist_dir="" + disk_encryption=0 + disk_encryption_args="" + no_disko_deps="false" + temp=$(mktemp -d) + + function help_and_exit() { + echo + echo "Remotely installs SwarselSystem on a target machine including secret deployment." + echo + echo "USAGE: $0 -n -d [OPTIONS]" + echo + echo "ARGS:" + echo " -n specify target_hostname of the target host to deploy the nixos config on." + echo " -d specify ip or url to the target host." + echo " -a specify the architecture of the target host." + echo " target during install process." + echo + echo "OPTIONS:" + echo " -u specify target_user with sudo access. nix-config will be cloned to their home." + echo " Default=''${target_user}." + echo " --port specify the ssh port to use for remote access. Default=''${ssh_port}." + echo " --debug Enable debug mode." + echo " --no-disko-deps Upload only disk script and not dependencies (for use on low ram)." + echo " -h | --help Print this help." + exit 0 + } + + function cleanup() { + rm -rf "$temp" + rm -rf /tmp/disko-password + } + trap cleanup exit + + function red() { + echo -e "\x1B[31m[!] $1 \x1B[0m" + if [ -n "''${2-}" ]; then + echo -e "\x1B[31m[!] $($2) \x1B[0m" + fi + } + function green() { + echo -e "\x1B[32m[+] $1 \x1B[0m" + if [ -n "''${2-}" ]; then + echo -e "\x1B[32m[+] $($2) \x1B[0m" + fi + } + function yellow() { + echo -e "\x1B[33m[*] $1 \x1B[0m" + if [ -n "''${2-}" ]; then + echo -e "\x1B[33m[*] $($2) \x1B[0m" + fi + } + + function yes_or_no() { + echo -en "\x1B[32m[+] $* [y/n] (default: y): \x1B[0m" + while true; do + read -rp "" yn + yn=''${yn:-y} + case $yn in + [Yy]*) return 0 ;; + [Nn]*) return 1 ;; + esac + done + } + + function update_sops_file() { + key_name=$1 + key_type=$2 + key=$3 + + if [ ! "$key_type" == "hosts" ] && [ ! "$key_type" == "users" ]; then + red "Invalid key type passed to update_sops_file. Must be either 'hosts' or 'users'." + exit 1 + fi + cd "''${git_root}" + + SOPS_FILE=".sops.yaml" + sed -i "{ + # Remove any * and & entries for this host + /[*&]$key_name/ d; + # Inject a new age: entry + # n matches the first line following age: and p prints it, then we transform it while reusing the spacing + /age:/{n; p; s/\(.*- \*\).*/\1$key_name/}; + # Inject a new hosts or user: entry + /&$key_type/{n; p; s/\(.*- &\).*/\1$key_name $key/} + }" $SOPS_FILE + green "Updating .sops.yaml" + cd - + } + + while [[ $# -gt 0 ]]; do + case "$1" in + -n) + shift + target_hostname=$1 + ;; + -d) + shift + target_destination=$1 + ;; + -a) + shift + target_arch=$1 + ;; + -u) + shift + target_user=$1 + ;; + --port) + shift + ssh_port=$1 + ;; + --no-disko-deps) + no_disko_deps="true" + ;; + --debug) + set -x + ;; + -h | --help) help_and_exit ;; + *) + echo "Invalid option detected." + help_and_exit + ;; + esac + shift + done + + if [[ $target_arch == "" || $target_destination == "" || $target_hostname == "" ]]; then + red "error: target_arch, target_destination or target_hostname not set." + help_and_exit + fi + + LOCKED="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.node.lockFromBootstrapping)" + if [[ $LOCKED == "true" ]]; then + red "THIS SYSTEM IS LOCKED FROM BOOTSTRAPPING - set 'node.lockFromBootstrapping = lib.mkForce false;' to proceed" + exit + fi + + green "~SwarselSystems~ remote installer" + green "Reading system information for $target_hostname ..." + + DISK="$(nix eval --raw ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.rootDisk)" + green "Root Disk: $DISK" + + CRYPTED="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isCrypted)" + if [[ $CRYPTED == "true" ]]; then + green "Encryption: ✓" + disk_encryption=1 + disk_encryption_args=( + --disk-encryption-keys + /tmp/disko-password + /tmp/disko-password + ) + else + red "Encryption: X" + disk_encryption=0 + fi + + IMPERMANENCE="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isImpermanence)" + if [[ $IMPERMANENCE == "true" ]]; then + green "Impermanence: ✓" + persist_dir="/persist" + else + red "Impermanence: X" + persist_dir="" + fi + + SWAP="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isSwap)" + if [[ $SWAP == "true" ]]; then + green "Swap: ✓" + else + red "Swap: X" + fi + + SECUREBOOT="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isSecureBoot)" + if [[ $SECUREBOOT == "true" ]]; then + green "Secure Boot: ✓" + else + red "Secure Boot: X" + fi + + ssh_cmd="ssh -oport=''${ssh_port} -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -t $target_user@$target_destination" + # ssh_root_cmd=$(echo "$ssh_cmd" | sed "s|''${target_user}@|root@|") # uses @ in the sed switch to avoid it triggering on the $ssh_key value + ssh_root_cmd=''${ssh_cmd/''${target_user}@/root@} + scp_cmd="scp -oport=''${ssh_port} -o StrictHostKeyChecking=no" + + if [[ -z ''${FLAKE} ]]; then + FLAKE=/home/"$target_user"/.dotfiles + fi + if [ ! -d "$FLAKE" ]; then + cd /home/"$target_user" + yellow "Flake directory not found - cloning repository from GitHub" + git clone git@github.com:Swarsel/.dotfiles.git || (yellow "Could not clone repository via SSH - defaulting to HTTPS" && git clone https://github.com/Swarsel/.dotfiles.git) + FLAKE=/home/"$target_user"/.dotfiles + fi + + cd "$FLAKE" + + rm install/flake.lock || true + git_root=$(git rev-parse --show-toplevel) + # ------------------------ + green "Wiping known_hosts of $target_destination" + sed -i "/$target_hostname/d; /$target_destination/d" ~/.ssh/known_hosts + # ------------------------ + green "Preparing a new ssh_host_ed25519_key pair for $target_hostname." + # Create the directory where sshd expects to find the host keys + install -d -m755 "$temp/$persist_dir/etc/ssh" + # Generate host ssh key pair without a passphrase + ssh-keygen -t ed25519 -f "$temp/$persist_dir/etc/ssh/ssh_host_ed25519_key" -C root@"$target_hostname" -N "" + # Set the correct permissions so sshd will accept the key + chmod 600 "$temp/$persist_dir/etc/ssh/ssh_host_ed25519_key" + echo "Adding ssh host fingerprint at $target_destination to ~/.ssh/known_hosts" + # This will fail if we already know the host, but that's fine + ssh-keyscan -p "$ssh_port" "$target_destination" >> ~/.ssh/known_hosts || true + # ------------------------ + # when using luks, disko expects a passphrase on /tmp/disko-password, so we set it for now and will update the passphrase later + # via the config + if [ "$disk_encryption" -eq 1 ]; then + while true; do + green "Set disk encryption passphrase:" + read -rs luks_passphrase + green "Please confirm passphrase:" + read -rs luks_passphrase_confirm + if [[ $luks_passphrase == "$luks_passphrase_confirm" ]]; then + echo "$luks_passphrase" > /tmp/disko-password + $ssh_root_cmd "echo '$luks_passphrase' > /tmp/disko-password" + break + else + red "Passwords do not match" + fi + done + fi + # ------------------------ + green "Generating hardware-config.nix for $target_hostname and adding it to the nix-config." + $ssh_root_cmd "nixos-generate-config --force --no-filesystems --root /mnt" + + mkdir -p "$FLAKE"/hosts/nixos/"$target_arch"/"$target_hostname" + $scp_cmd root@"$target_destination":/mnt/etc/nixos/hardware-configuration.nix "''${git_root}"/hosts/nixos/"$target_arch"/"$target_hostname"/hardware-configuration.nix + # ------------------------ + green "Generating hostkey for ssh initrd" + $ssh_root_cmd "mkdir -p $temp/etc/secrets/initrd /etc/secrets/initrd" + $ssh_root_cmd "ssh-keygen -t ed25519 -N '''' -f $temp/etc/secrets/initrd/ssh_host_ed25519_key" + $ssh_root_cmd "cp $temp/etc/secrets/initrd/ssh_host_ed25519_key /etc/secrets/initrd/ssh_host_ed25519_key" + # ------------------------ + + green "Deploying minimal NixOS installation on $target_destination" + + if [[ $no_disko_deps == "true" ]]; then + green "Building without disko dependencies (using custom kexec)" + nix run github:nix-community/nixos-anywhere/1.10.0 -- "''${disk_encryption_args[@]}" --no-disko-deps --ssh-port "$ssh_port" --extra-files "$temp" --flake ./install#"$target_hostname" --kexec "$(nix build --print-out-paths .#packages."$target_arch".swarsel-kexec)/swarsel-kexec-$target_arch.tar.gz" root@"$target_destination" + else + green "Building with disko dependencies (using nixos-images kexec)" + nix run github:nix-community/nixos-anywhere/1.10.0 -- "''${disk_encryption_args[@]}" --ssh-port "$ssh_port" --extra-files "$temp" --flake ./install#"$target_hostname" root@"$target_destination" + fi + + echo "Updating ssh host fingerprint at $target_destination to ~/.ssh/known_hosts" + ssh-keyscan -p "$ssh_port" "$target_destination" >> ~/.ssh/known_hosts || true + # ------------------------ + + while true; do + read -rp "Press Enter to continue once the remote host has finished booting." + if nc -z "$target_destination" "''${ssh_port}" 2> /dev/null; then + green "$target_destination is booted. Continuing..." + break + else + yellow "$target_destination is not yet ready." + fi + done + + # ------------------------ + + if [[ $SECUREBOOT == "true" ]]; then + green "Setting up secure boot keys" + $ssh_root_cmd "mkdir -p /var/lib/sbctl" + read -ra scp_call <<< "''${scp_cmd}" + sudo "''${scp_call[@]}" -r /var/lib/sbctl root@"$target_destination":/var/lib/ + $ssh_root_cmd "sbctl enroll-keys --ignore-immutable --microsoft || true" + fi + # ------------------------ + + if [ -n "$persist_dir" ]; then + $ssh_root_cmd "cp /etc/machine-id $persist_dir/etc/machine-id || true" + $ssh_root_cmd "cp -R /etc/ssh/ $persist_dir/etc/ssh/ || true" + fi + # ------------------------ + green "Generating an age key based on the new ssh_host_ed25519_key." + target_key=$( + ssh-keyscan -p "$ssh_port" -t ssh-ed25519 "$target_destination" 2>&1 | + grep ssh-ed25519 | + cut -f2- -d" " || + ( + red "Failed to get ssh key. Host down?" + exit 1 + ) + ) + host_age_key=$(nix shell nixpkgs#ssh-to-age.out -c sh -c "echo $target_key | ssh-to-age") + + if grep -qv '^age1' <<< "$host_age_key"; then + red "The result from generated age key does not match the expected format." + yellow "Result: $host_age_key" + yellow "Expected format: age1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + exit 1 + else + echo "$host_age_key" + fi + + green "Updating nix-secrets/.sops.yaml" + update_sops_file "$target_hostname" "hosts" "$host_age_key" + yellow ".sops.yaml has been updated. There may be superfluous entries, you might need to edit manually." + if yes_or_no "Do you want to manually edit .sops.yaml now?"; then + vim "''${git_root}"/.sops.yaml + fi + green "Updating all secrets files to reflect updates .sops.yaml" + sops updatekeys --yes --enable-local-keyservice "''${git_root}"/hosts/nixos/"$target_arch"/"$target_hostname"/secrets/* || true + # -------------------------- + green "Making ssh_host_ed25519_key available to home-manager for user $target_user" + sed -i "/$target_hostname/d; /$target_destination/d" ~/.ssh/known_hosts + $ssh_root_cmd "mkdir -p /home/$target_user/.ssh; chown -R $target_user:users /home/$target_user/.ssh/" + $scp_cmd root@"$target_destination":/etc/ssh/ssh_host_ed25519_key root@"$target_destination":/home/"$target_user"/.ssh/ssh_host_ed25519_key + $ssh_root_cmd "chown $target_user:users /home/$target_user/.ssh/ssh_host_ed25519_key" + # __________________________ + + if yes_or_no "Add ssh host fingerprints for git upstream repositories? (This is needed for building the full config)"; then + green "Adding ssh host fingerprints for git{lab,hub}" + $ssh_cmd "mkdir -p /home/$target_user/.ssh/; ssh-keyscan -t ssh-ed25519 gitlab.com github.com | tee /home/$target_user/.ssh/known_hosts" + $ssh_root_cmd "mkdir -p /root/.ssh/; ssh-keyscan -t ssh-ed25519 gitlab.com github.com | tee /root/.ssh/known_hosts" + fi + # -------------------------- + + if yes_or_no "Do you want to copy your full nix-config and nix-secrets to $target_hostname?"; then + green "Adding ssh host fingerprint at $target_destination to ~/.ssh/known_hosts" + ssh-keyscan -p "$ssh_port" "$target_destination" >> ~/.ssh/known_hosts || true + green "Copying full nix-config to $target_hostname" + cd "''${git_root}" + just sync "$target_user" "$target_destination" + + if [ -n "$persist_dir" ]; then + $ssh_root_cmd "cp -r /home/$target_user/.dotfiles $persist_dir/.dotfiles || true" + $ssh_root_cmd "cp -r /home/$target_user/.ssh $persist_dir/.ssh || true" + fi + + if yes_or_no "Do you want to rebuild immediately?"; then + green "Building nix-config for $target_hostname" + # yellow "Reminder: The password is 'setup'" + $ssh_root_cmd "mkdir -p /root/.local/share/nix/; printf '{\"extra-substituters\":{\"https://nix-community.cachix.org\":true,\"https://nix-community.cachix.org https://cache.ngi0.nixos.org/\":true},\"extra-trusted-public-keys\":{\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=\":true,\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs= cache.ngi0.nixos.org-1:KqH5CBLNSyX184S9BKZJo1LxrxJ9ltnY2uAs5c/f1MA=\":true}}' | tee /root/.local/share/nix/trusted-settings.json" + # $ssh_cmd -oForwardAgent=yes "cd .dotfiles && sudo nixos-rebuild --show-trace --flake .#$target_hostname switch" + store_path=$(nix build --no-link --print-out-paths .#nixosConfigurations."$target_hostname".config.system.build.toplevel) + green "Copying generation to $target_hostname" + nix copy --to "ssh://root@$target_destination" "$store_path" + # prev_system=$($ssh_root_cmd " readlink -e /nix/var/nix/profiles/system") + green "Linking generation in bootloader" + $ssh_root_cmd "/run/current-system/sw/bin/nix-env --profile /nix/var/nix/profiles/system --set $store_path" + green "Setting generation to activate upon next boot" + $ssh_root_cmd "$store_path/bin/switch-to-configuration boot" + else + echo + green "NixOS was successfully installed!" + echo "Post-install config build instructions:" + echo "To copy nix-config from this machine to the $target_hostname, run the following command from ~/nix-config" + echo "just sync $target_user $target_destination" + echo "To rebuild, sign into $target_hostname and run the following command from ~/nix-config" + echo "cd nix-config" + # see above FIXME:(bootstrap) + echo "sudo nixos-rebuild .pre-commit-config.yaml show-trace --flake .#$target_hostname switch" + # echo "just rebuild" + echo + fi + fi + + green "NixOS was successfully installed!" + if yes_or_no "You can now commit and push the nix-config, which includes the hardware-configuration.nix for $target_hostname?"; then + cd "''${git_root}" + deadnix hosts/nixos/"$target_arch"/"$target_hostname"/hardware-configuration.nix -qe + nixpkgs--fmt hosts/nixos/"$target_arch"/"$target_hostname"/hardware-configuration.nix + (.pre-commit-config.yaml mit run --all-files 2> /dev/null || true) && + git add "$git_root/hosts/nixos/$target_arch/$target_hostname/hardware-configuration.nix" && + git add "$git_root/.sops.yaml" && + git add "$git_root/secrets" && + (git commit -m "feat: deployed $target_hostname" || true) && git push + fi + + if yes_or_no "Reboot now?"; then + $ssh_root_cmd "reboot" + fi + + rm -rf /tmp/disko-password + ''; } diff --git a/pkgs/flake/swarsel-displaypower/default.nix b/pkgs/flake/swarsel-displaypower/default.nix index d6c547b..df57ab9 100644 --- a/pkgs/flake/swarsel-displaypower/default.nix +++ b/pkgs/flake/swarsel-displaypower/default.nix @@ -1,6 +1,9 @@ -{ self, name, writeShellApplication, sway }: +{ name, writeShellApplication, sway, ... }: writeShellApplication { inherit name; runtimeInputs = [ sway ]; - text = builtins.readFile "${self}/files/scripts/${name}.sh"; + text = '' + swaymsg "output * power on" > /dev/null 2>&1 || true + swaymsg "output * dpms on" > /dev/null 2>&1 || true + ''; } diff --git a/pkgs/flake/swarsel-install/default.nix b/pkgs/flake/swarsel-install/default.nix index 41cc1ea..6bc3040 100644 --- a/pkgs/flake/swarsel-install/default.nix +++ b/pkgs/flake/swarsel-install/default.nix @@ -1,6 +1,195 @@ -{ self, name, writeShellApplication, git }: +{ name, writeShellApplication, git, ... }: writeShellApplication { inherit name; runtimeInputs = [ git ]; - text = builtins.readFile "${self}/files/scripts/${name}.sh"; + text = '' + set -eo pipefail + + target_config="hotel" + target_hostname="hotel" + target_user="swarsel" + target_arch="" + persist_dir="" + target_disk="/dev/vda" + disk_encryption=0 + + function help_and_exit() { + echo + echo "Locally installs SwarselSystem on this machine." + echo + echo "USAGE: $0 -n -d [OPTIONS]" + echo + echo "ARGS:" + echo " -n specify the nixos config to deploy." + echo " Default: hotel" + echo " -d specify disk to install on." + echo " Default: /dev/vda" + echo " -u specify user to deploy for." + echo " Default: swarsel" + echo " -a specify target architecture." + echo " -h | --help Print this help." + exit 0 + } + + function red() { + echo -e "\x1B[31m[!] $1 \x1B[0m" + if [ -n "''${2-}" ]; then + echo -e "\x1B[31m[!] $($2) \x1B[0m" + fi + } + function green() { + echo -e "\x1B[32m[+] $1 \x1B[0m" + if [ -n "''${2-}" ]; then + echo -e "\x1B[32m[+] $($2) \x1B[0m" + fi + } + function yellow() { + echo -e "\x1B[33m[*] $1 \x1B[0m" + if [ -n "''${2-}" ]; then + echo -e "\x1B[33m[*] $($2) \x1B[0m" + fi + } + + while [[ $# -gt 0 ]]; do + case "$1" in + -n) + shift + target_config=$1 + target_hostname=$1 + ;; + -u) + shift + target_user=$1 + ;; + -d) + shift + target_disk=$1 + ;; + -a) + shift + target_arch=$1 + ;; + -h | --help) help_and_exit ;; + *) + echo "Invalid option detected." + help_and_exit + ;; + esac + shift + done + + function cleanup() { + sudo rm -rf .cache/nix + sudo rm -rf /root/.cache/nix + } + trap cleanup exit + + if [[ $target_arch == "" || $target_hostname == "" ]]; then + red "error: target_arch or target_hostname not set." + help_and_exit + fi + + green "~SwarselSystems~ local installer" + + cd /home/"$target_user" + + sudo rm -rf /root/.cache/nix + sudo rm -rf .cache/nix + sudo rm -rf .dotfiles + + green "Cloning repository from GitHub" + git clone https://github.com/Swarsel/.dotfiles.git + + local_keys=$(ssh-add -L || true) + pub_key=$(cat /home/"$target_user"/.dotfiles/secrets/public/ssh/yubikey.pub) + read -ra pub_arr <<< "$pub_key" + + cd .dotfiles + if [[ $local_keys != *"''${pub_arr[1]}"* ]]; then + yellow "The ssh key for this configuration is not available." + green "Adjusting flake.nix so that the configuration is buildable ..." + sed -i '/vbc-nix = {/,/^[[:space:]]*};/d' flake.nix + sed -i '/[[:space:]]*\/\/ (inputs.vbc-nix.overlays.default final prev)/d' overlays/default.nix + nix flake update vbc-nix + git add . + else + green "Valid SSH key found! Continuing with installation" + fi + + green "Reading system information for $target_config ..." + DISK="$(nix eval --raw ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.rootDisk)" + green "Root Disk in config: $DISK - Root Disk passed in cli: $target_disk" + + CRYPTED="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isCrypted)" + if [[ $CRYPTED == "true" ]]; then + green "Encryption: ✓" + disk_encryption=1 + else + red "Encryption: X" + disk_encryption=0 + fi + + IMPERMANENCE="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isImpermanence)" + if [[ $IMPERMANENCE == "true" ]]; then + green "Impermanence: ✓" + persist_dir="/persist" + else + red "Impermanence: X" + persist_dir="" + fi + + SWAP="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isSwap)" + if [[ $SWAP == "true" ]]; then + green "Swap: ✓" + else + red "Swap: X" + fi + + SECUREBOOT="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isSecureBoot)" + if [[ $SECUREBOOT == "true" ]]; then + green "Secure Boot: ✓" + else + red "Secure Boot: X" + fi + + if [ "$disk_encryption" -eq 1 ]; then + while true; do + green "Set disk encryption passphrase:" + read -rs luks_passphrase + green "Please confirm passphrase:" + read -rs luks_passphrase_confirm + if [[ $luks_passphrase == "$luks_passphrase_confirm" ]]; then + echo "$luks_passphrase" > /tmp/disko-password + break + else + red "Passwords do not match" + fi + done + fi + + green "Setting up disk ..." + if [[ $target_config == "hotel" ]]; then + sudo nix --experimental-features "nix-command flakes" run github:nix-community/disko/v1.10.0 -- --mode destroy,format,mount --flake .#"$target_config" --yes-wipe-all-disks --arg diskDevice "$target_disk" + else + sudo nix --experimental-features "nix-command flakes" run github:nix-community/disko/latest -- --mode destroy,format,mount --flake .#"$target_config" --yes-wipe-all-disks + fi + sudo mkdir -p /mnt/"$persist_dir"/home/"$target_user"/ + sudo cp -r /home/"$target_user"/.dotfiles /mnt/"$persist_dir"/home/"$target_user"/ + sudo chown -R 1000:100 /mnt/"$persist_dir"/home/"$target_user" + + green "Generating hardware configuration ..." + sudo nixos-generate-config --root /mnt --no-filesystems --dir /home/"$target_user"/.dotfiles/hosts/nixos/"$target_arch"/"$target_config"/ + + git add /home/"$target_user"/.dotfiles/hosts/nixos/"$target_arch"/"$target_config"/hardware-configuration.nix + sudo mkdir -p /root/.local/share/nix/ + printf '{\"extra-substituters\":{\"https://nix-community.cachix.org\":true,\"https://nix-community.cachix.org https://cache.ngi0.nixos.org/\":true},\"extra-trusted-public-keys\":{\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=\":true,\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs= cache.ngi0.nixos.org-1:KqH5CBLNSyX184S9BKZJo1LxrxJ9ltnY2uAs5c/f1MA=\":true}}' | sudo tee /root/.local/share/nix/trusted-settings.json > /dev/null + green "Installing flake $target_config" + + store_path=$(nix build --no-link --print-out-paths .#nixosConfigurationsMinimal."$target_config".config.system.build.toplevel) + green "Linking generation in bootloader" + sudo "/run/current-system/sw/bin/nix-env --profile /nix/var/nix/profiles/system --set $store_path" + green "Setting generation to activate upon next boot" + sudo "$store_path/bin/switch-to-configuration boot" + green "Installation finished! Reboot to see changes" + ''; } diff --git a/pkgs/flake/swarsel-postinstall/default.nix b/pkgs/flake/swarsel-postinstall/default.nix index 41cc1ea..5ffe75b 100644 --- a/pkgs/flake/swarsel-postinstall/default.nix +++ b/pkgs/flake/swarsel-postinstall/default.nix @@ -1,6 +1,79 @@ -{ self, name, writeShellApplication, git }: +{ name, writeShellApplication, git, ... }: writeShellApplication { inherit name; runtimeInputs = [ git ]; - text = builtins.readFile "${self}/files/scripts/${name}.sh"; + text = '' + set -eo pipefail + + target_config="hotel" + target_user="swarsel" + + function help_and_exit() { + echo + echo "Locally installs SwarselSystem on this machine." + echo + echo "USAGE: $0 -d [OPTIONS]" + echo + echo "ARGS:" + echo " -d specify disk to install on." + echo " -n specify the nixos config to deploy." + echo " Default: hotel" + echo " Default: hotel" + echo " -u specify user to deploy for." + echo " Default: swarsel" + echo " -h | --help Print this help." + exit 0 + } + + function green() { + echo -e "\x1B[32m[+] $1 \x1B[0m" + if [ -n "''${2-}" ]; then + echo -e "\x1B[32m[+] $($2) \x1B[0m" + fi + } + + while [[ $# -gt 0 ]]; do + case "$1" in + -n) + shift + target_config=$1 + ;; + -u) + shift + target_user=$1 + ;; + -h | --help) help_and_exit ;; + *) + echo "Invalid option detected." + help_and_exit + ;; + esac + shift + done + + function cleanup() { + sudo rm -rf .cache/nix + sudo rm -rf /root/.cache/nix + } + trap cleanup exit + + sudo rm -rf .cache/nix + sudo rm -rf /root/.cache/nix + + green "~SwarselSystems~ remote post-installer" + + cd /home/"$target_user"/.dotfiles + + SECUREBOOT="$(nix eval ~/.dotfiles#nixosConfigurations."$target_config".config.swarselsystems.isSecureBoot)" + + if [[ $SECUREBOOT == "true" ]]; then + green "Setting up secure boot keys" + sudo mkdir -p /var/lib/sbctl + sbctl create-keys || true + sbctl enroll-keys --ignore-immutable --microsoft || true + fi + + sudo nixos-rebuild --flake .#"$target_config" switch + green "Post-install finished!" + ''; } diff --git a/pkgs/flake/swarsel-rebuild/default.nix b/pkgs/flake/swarsel-rebuild/default.nix index 41cc1ea..fec3d2b 100644 --- a/pkgs/flake/swarsel-rebuild/default.nix +++ b/pkgs/flake/swarsel-rebuild/default.nix @@ -1,6 +1,117 @@ -{ self, name, writeShellApplication, git }: +{ name, writeShellApplication, git, ... }: writeShellApplication { inherit name; runtimeInputs = [ git ]; - text = builtins.readFile "${self}/files/scripts/${name}.sh"; + text = '' + set -eo pipefail + + target_config="hotel" + target_arch="" + target_user="swarsel" + + function help_and_exit() { + echo + echo "Builds SwarselSystem configuration." + echo + echo "USAGE: $0 [OPTIONS]" + echo + echo "ARGS:" + echo " -n specify nixos config to build." + echo " Default: hotel" + echo " -u specify user to deploy for." + echo " Default: swarsel" + echo " -a specify target architecture." + echo " -h | --help Print this help." + exit 0 + } + + function red() { + echo -e "\x1B[31m[!] $1 \x1B[0m" + if [ -n "''${2-}" ]; then + echo -e "\x1B[31m[!] $($2) \x1B[0m" + fi + } + function green() { + echo -e "\x1B[32m[+] $1 \x1B[0m" + if [ -n "''${2-}" ]; then + echo -e "\x1B[32m[+] $($2) \x1B[0m" + fi + } + function yellow() { + echo -e "\x1B[33m[*] $1 \x1B[0m" + if [ -n "''${2-}" ]; then + echo -e "\x1B[33m[*] $($2) \x1B[0m" + fi + } + + while [[ $# -gt 0 ]]; do + case "$1" in + -n) + shift + target_config=$1 + ;; + -a) + shift + target_arch=$1 + ;; + -u) + shift + target_user=$1 + ;; + -h | --help) help_and_exit ;; + *) + echo "Invalid option detected." + help_and_exit + ;; + esac + shift + done + + if [[ $target_arch == "" ]]; then + red "error: target_arch not set." + help_and_exit + fi + + cd /home/"$target_user" + + if [ ! -d /home/"$target_user"/.dotfiles ]; then + green "Cloning repository from GitHub" + git clone https://github.com/Swarsel/.dotfiles.git + else + red "A .dotfiles repository is in the way. Please (re-)move the repository and try again." + exit 1 + fi + + local_keys=$(ssh-add -L || true) + pub_key=$(cat /home/"$target_user"/.dotfiles/secrets/public/ssh/yubikey.pub) + read -ra pub_arr <<< "$pub_key" + + cd .dotfiles + if [[ $local_keys != *"''${pub_arr[1]}"* ]]; then + yellow "The ssh key for this configuration is not available." + green "Adjusting flake.nix so that the configuration is buildable" + sed -i '/nix-secrets = {/,/^[[:space:]]*};/d' flake.nix + sed -i '/vbc-nix = {/,/^[[:space:]]*};/d' flake.nix + sed -i '/[[:space:]]*\/\/ (inputs.vbc-nix.overlays.default final prev)/d' overlays/default.nix + rm modules/home/common/env.nix + rm modules/home/common/gammastep.nix + rm modules/home/common/git.nix + rm modules/home/common/mail.nix + rm modules/home/common/yubikey.nix + rm modules/nixos/server/restic.nix + rm hosts/nixos/aarch64-linux/milkywell/default.nix + rm -rf modules/nixos/server + rm -rf modules/home/server + nix flake update vbc-nix + git add . + else + green "Valid SSH key found! Continuing with installation" + fi + sudo nixos-generate-config --dir /home/"$target_user"/.dotfiles/hosts/nixos/"$target_arch"/"$target_config"/ + git add /home/"$target_user"/.dotfiles/hosts/nixos/"$target_arch"/"$target_config"/hardware-configuration.nix + + green "Installing flake $target_config" + sudo nixos-rebuild --show-trace --flake .#"$target_config" boot + yellow "Please keep in mind that this is only a demo of the configuration. Things might break unexpectedly." + ''; } diff --git a/pkgs/flake/swarselcheck-niri/default.nix b/pkgs/flake/swarselcheck-niri/default.nix index 13dcb56..686838a 100644 --- a/pkgs/flake/swarselcheck-niri/default.nix +++ b/pkgs/flake/swarselcheck-niri/default.nix @@ -1,4 +1,4 @@ -{ self, name, writeShellApplication, kitty, element-desktop, vesktop, spotify-player, jq }: +{ self, name, writeShellApplication, kitty, element-desktop, vesktop, spotify-player, jq, ... }: writeShellApplication { inherit name; runtimeInputs = [ kitty element-desktop vesktop spotify-player jq ]; diff --git a/pkgs/flake/swarselcheck/default.nix b/pkgs/flake/swarselcheck/default.nix index 7504de3..f736659 100644 --- a/pkgs/flake/swarselcheck/default.nix +++ b/pkgs/flake/swarselcheck/default.nix @@ -1,6 +1,69 @@ -{ self, name, writeShellApplication, kitty, element-desktop, vesktop, spotify-player, jq }: +{ name, writeShellApplication, kitty, element-desktop, vesktop, spotify-player, jq, ... }: writeShellApplication { inherit name; runtimeInputs = [ kitty element-desktop vesktop spotify-player jq ]; - text = builtins.readFile "${self}/files/scripts/${name}.sh"; + text = '' + kitty=0 + element=0 + vesktop=0 + spotifyplayer=0 + while :; do + case ''${1:-} in + -k | --kitty) + kitty=1 + ;; + -e | --element) + element=1 + ;; + -d | --vesktop) + vesktop=1 + ;; + -s | --spotifyplayer) + spotifyplayer=1 + ;; + *) break ;; + esac + shift + done + + if [[ $kitty -eq 1 ]]; then + STR=$(swaymsg -t get_tree | jq -r 'recurse(.nodes[]) | select(.name == "__i3_scratch")' | grep kittyterm || true) + CHECK=$(swaymsg -t get_tree | grep kittyterm || true) + if [ "$CHECK" == "" ]; then + exec kitty --app-id kittyterm -T kittyterm -o confirm_os_window_close=0 zellij attach --create kittyterm & + sleep 1 + fi + if [ "$STR" == "" ]; then + exec swaymsg '[title="kittyterm"]' scratchpad show + else + exec swaymsg '[title="kittyterm"]' scratchpad show + fi + elif [[ $element -eq 1 ]]; then + STR=$(swaymsg -t get_tree | grep Element || true) + if [ "$STR" == "" ]; then + exec element-desktop + else + exec swaymsg '[app_id=Element]' kill + fi + elif [[ $vesktop -eq 1 ]]; then + STR=$(swaymsg -t get_tree | grep vesktop || true) + if [ "$STR" == "" ]; then + exec vesktop + else + exec swaymsg '[app_id=vesktop]' kill + fi + elif [[ $spotifyplayer -eq 1 ]]; then + STR=$(swaymsg -t get_tree | jq -r 'recurse(.nodes[]) | select(.name == "__i3_scratch")' | grep spotifytui || true) + CHECK=$(swaymsg -t get_tree | grep spotifytui || true) + if [ "$CHECK" == "" ]; then + exec kitty --add-id spotifytui -T spotifytui -o confirm_os_window_close=0 spotify_player & + sleep 1 + fi + if [ "$STR" == "" ]; then + exec swaymsg '[title="spotifytui"]' scratchpad show + else + exec swaymsg '[title="spotifytui"]' scratchpad show + fi + fi + ''; } diff --git a/pkgs/flake/swarselzellij/default.nix b/pkgs/flake/swarselzellij/default.nix index 1615bef..081d518 100644 --- a/pkgs/flake/swarselzellij/default.nix +++ b/pkgs/flake/swarselzellij/default.nix @@ -1,6 +1,15 @@ -{ self, name, writeShellApplication, kitty }: +{ name, writeShellApplication, kitty, ... }: writeShellApplication { inherit name; runtimeInputs = [ kitty ]; - text = builtins.readFile "${self}/files/scripts/${name}.sh"; + text = '' + # KITTIES=$(($(pgrep -P 1 kitty | wc -l) - 1)) + + # if ((KITTIES < 1)); then + # exec kitty -o confirm_os_window_close=0 zellij attach --create main + # else + # exec kitty -o confirm_os_window_close=0 zellij attach --create "temp $KITTIES" + # fi + exec kitty -o confirm_os_window_close=0 zellij + ''; } diff --git a/pkgs/flake/waybarupdate/default.nix b/pkgs/flake/waybarupdate/default.nix index 41cc1ea..7ad1518 100644 --- a/pkgs/flake/waybarupdate/default.nix +++ b/pkgs/flake/waybarupdate/default.nix @@ -1,6 +1,31 @@ -{ self, name, writeShellApplication, git }: +{ name, writeShellApplication, git, ... }: writeShellApplication { inherit name; runtimeInputs = [ git ]; - text = builtins.readFile "${self}/files/scripts/${name}.sh"; + text = '' + CFG=$(git --git-dir="$HOME"/.dotfiles/.git --work-tree="$HOME"/.dotfiles/ status -s | wc -l) + CSE=$(git --git-dir="$DOCUMENT_DIR_PRIV"/CSE_TUWIEN/.git --work-tree="$DOCUMENT_DIR_PRIV"/CSE_TUWIEN/ status -s | wc -l) + PASS=$(($(git --git-dir="$HOME"/.local/share/password-store/.git --work-tree="$HOME"/.local/share/password-store/ status -s | wc -l) + $(git --git-dir="$HOME"/.local/share/password-store/.git --work-tree="$HOME"/.local/share/password-store/ diff origin/main..HEAD | wc -l))) + + if [[ $CFG != 0 ]]; then + CFG_STR='CONFIG' + else + CFG_STR="" + fi + + if [[ $CSE != 0 ]]; then + CSE_STR=' CSE' + else + CSE_STR="" + fi + + if [[ $PASS != 0 ]]; then + PASS_STR=' PASS' + else + PASS_STR="" + fi + + OUT="$CFG_STR""$CSE_STR""$PASS_STR" + echo "$OUT" + ''; }