diff --git a/.github/README.md b/.github/README.md index db500e8..510d1f6 100644 --- a/.github/README.md +++ b/.github/README.md @@ -1,136 +1,296 @@ -[![nixos-unstable](https://img.shields.io/badge/unstable-nixos?style=flat&logo=nixos&logoColor=cdd6f4&label=NixOS&labelColor=11111b&color=b4befe)](https://github.com/NixOS/nixpkgs) [![Build Status](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Factions-badge.atrox.dev%2FSwarsel%2F.dotfiles%2Fbadge%3Fref%3Dmain&style=flat&labelColor=11111b)](https://actions-badge.atrox.dev/Swarsel/.dotfiles/goto?ref=main) -###### Disclaimer + ###### Disclaimer -You probably do not want to use this setup verbatim. This is made to fit my specific use cases, and I do not guarantee best practises everywhere. Changes are made on a daily basis. + You probably do not want to use this setup verbatim. This is made to fit my specific use cases, and I do not guarantee best practises everywhere. Changes are made on a daily basis. -That being said, there is a lot of general configuration that you *probably* can use without changes; if you only want to use this repository as a starting point for your own configuration, you should be fine. See below for more information. Also, if you see something that can be done more efficiently or better in general, please let me know! :) + That being said, there is a lot of general configuration that you *probably* can use without changes; if you only want to use this repository as a starting point for your own configuration, you should be fine. See below for more information. Also, if you see something that can be done more efficiently or better in general, please let me know! :) -# \~SwarselSystems\~ + # \~SwarselSystems\~ - +

+ swarselsystems_preview1 + swarselsystems_preview2 +

-| | | -|---------------|---------------------------------| -| **Shell:** | zsh | -| **DM:** | greetd | -| **WM:** | SwayFX | -| **Bar:** | Waybar | -| **Editor:** | Emacs | -| **Terminal:** | kitty | -| **Launcher:** | fuzzel | -| **Alerts:** | mako | -| **Browser:** | firefox | -| **Theme:** | city-lights (managed by stylix) | + ## Overview -## Overview + - [Literate configuration](https://swarsel.github.io/.dotfiles/) defining my entire infrastructure, including Emacs + - Configuration based on flakes for personal hosts as well as servers on: + - [NixOS](https://github.com/NixOS/nixpkgs) + - [home-manager](https://github.com/nix-community/home-manager) only (no full NixOS) with support from [nixGL](https://github.com/nix-community/nixGL) + - [nix-darwin](https://github.com/LnL7/nix-darwin) + - [nix-on-droid](https://github.com/nix-community/nix-on-droid) + - Streamlined configuration and deployment pipeline: + - Framework for [packages](https://github.com/Swarsel/.dotfiles/blob/main/pkgs/default.nix), [overlays](https://github.com/Swarsel/.dotfiles/blob/main/overlays/default.nix), [modules](https://github.com/Swarsel/.dotfiles/tree/main/modules), and [library functions](https://github.com/Swarsel/.dotfiles/tree/main/lib/default.nix) + - Dynamically generated host configurations + - Limited local installer (no secrets handling) with a supported demo build + - Fully autonomous remote deployment using [nixos-anywhere](https://github.com/nix-community/nixos-anywhere) and [disko](https://github.com/nix-community/disko) (with secrets handling) + - Improved nix tooling + - Support for advanced features: + - Secrets handling using [sops-nix](https://github.com/Mic92/sops-nix) (pls no pwn ❤️) + - Management of personally identifiable information using [nix-plugins](https://github.com/shlevy/nix-plugins) + - Full Yubikey support + - LUKS-encryption + - Secure boot using [Lanzaboote](https://github.com/nix-community/lanzaboote) + - BTRFS-based [Impermanence](https://github.com/nix-community/impermanence) + - Configuration shared between configurations (configuration for one nixosConfiguration can be defined in another nixosConfiguration) + - Global attributes shared between all configurations to reduce attribute redeclaration -- Literate configuration for Nix and Emacs ([SwarselSystems.org](../SwarselSystems.org)) -- Configuration based on flakes for personal hosts as well as servers on: - - [NixOS](https://github.com/NixOS/nixpkgs)) - - [home-manager](https://github.com/nix-community/home-manager) only (no full NixOS) with support from [nixGL](https://github.com/nix-community/nixGL) - - [nix-darwin](https://github.com/LnL7/nix-darwin) - - [nix-on-droid](https://github.com/nix-community/nix-on-droid) -- Streamlined configuration and deployment pipeline: - - Framework for [packages](https://github.com/Swarsel/.dotfiles/blob/main/pkgs/default.nix), [overlays](https://github.com/Swarsel/.dotfiles/blob/main/overlays/default.nix), and [modules](https://github.com/Swarsel/.dotfiles/tree/main/modules) - - Dynamically generated host configurations - - Limited local installer (no secrets handling) with a supported demo build - - Fully autonomous remote deployment using [nixos-anywhere](https://github.com/nix-community/nixos-anywhere) and [disko](https://github.com/nix-community/disko) (with secrets handling) - - Improved nix tooling -- Support for advanced features: - - Secrets handling using [sops-nix](https://github.com/Mic92/sops-nix) (pls don't pwn ❤️) - - Management of non-file-based secrets using private repo - - Full Yubikey support - - LUKS-encryption - - Secure boot using [lanzaboote](https://github.com/nix-community/lanzaboote) - - BTRFS-based [Impermanence](https://github.com/nix-community/impermanence) + ## Documentation + + If you are mainly interested in how I configured this system, check out this page: + + [SwarselSystems literate configuration](https://swarsel.github.io/.dotfiles/) + + This file will take you through my design process, in varying amounts of detail. + + Otherwise, the files that are possibly of biggest interest are found here: + + - [SwarselSystems.org](../SwarselSystems.org) + - [flake.nix](../flake.nix) + - [early-init.el](../files/emacs/early-init.el) + - [init.el](../files/emacs/init.el) -## Documentation + ### Getting started -If you are mainly interested in how I configured this system, check out this page: + #### Demo configuration -[SwarselSystems literate configuration](https://swarsel.github.io/.dotfiles/) +
+ Click here for instructions on how to install the demo system -This file will take you through my design process, in varying amounts of detail. + If you just want to see if this configuration is for you, run this command on any system that has `nix` installed: -Otherwise, the files that are possibly of biggest interest are found here: + ``` shell + nix run --experimental-features 'nix-command flakes' github:Swarsel/.dotfiles#swarsel-rebuild -- -u + ``` -- [SwarselSystems.org](../SwarselSystems.org) -- [flake.nix](../flake.nix) -- [early-init.el](../programs/emacs/early-init.el) -- [init.el](../programs/emacs/init.el) + This will activate the `hotel` configuration on your system, which is a de-facto mirror of my main configuration with secret-based settings removed. + Please keep in mind that this limited installer will make local changes to the cloned repository in order to be able to install it (otherwise the builder would fail at fetching my private secrets repository). As such, this should only be used to evaluate the system - if you want to use it longterm, you will need to create a fork and make some changes. +
+ ### Deployment -## Getting started +
+ Click here for deployment instructions -### Demo configuration -If you just want to see if this configuration is for you, run this command on any system that has `nix` installed: + The deployment process for this configuration is mostly automated, there are only a few steps that are needed to be done manually. You can choose between a remote deployment strategy that is also able to deploy new age keys for sops for you and a local installer that will only install the system without any secret handling. -``` shell -nix run --experimental-features 'nix-command flakes' github:Swarsel/.dotfiles#install -- -u -``` + #### Remote deployment (recommended if you have at least one running system) -This will install the `chaostheatre` configuration on your system, which is a de-facto mirror of my main configuration with secret-based settings removed. -Please keep in mind that this limited installer will make local changes to the cloned repository in order to be able to install it (otherwise the builder would fail at fetching my private secrets repository). As such, this should only be used to evaluate the system - if you want to use it longterm, you will need to create a fork and make some changes. + 0) Fork this repo, and write your own host config at `hosts/nixos///default.nix` (you can use one of the other configurations as a template. Also see https://github.com/Swarsel/.dotfiles/tree/main/modules for a list of all additional options). At the very least, you should replace the `secrets/` directory with your own secrets and replace the SSH public keys with your own ones (otherwise I will come visit you!🔓❤️). I personally recommend to use the literate configuration and `org-babel-tangle-file` in Emacs, but you can also simply edit the separate `.nix` files. + 1) Have a system with `nix` available booted (this does not need to be installed, i.e. you can use a NixOS installer image; a custom minimal installer ISO can be built by running `just iso` in the root of this repo) + 2) Make sure that your Yubikey is plugged in or that you have your SSH key available (and configured) + 3) Run `swarsel-bootstrap -n -d ` on your existing system. + - Alternatively (if you run this on a system that is not yet running this configuration), you can also run `nix run --experimental-features 'nix-command flakes' github:Swarsel/.dotfiles -- -n -d ` (this runs the same program as the command above). + 4) Follow the installers instructions: + - you will have to choose a disk encryption password (if you want that feature) + - you will have to confirm once that the target system has rebooted + - you will have to enter the root password once during the final system install + 5) That should be it! The installer will take care of setting up disks, secrets, and the rest of the hardware configuration! You will still have to sign in manually to some webservices etc. -## Deployment + #### Local deployment (recommended for setting up the first system) -The deployment process for this configuration is mostly automated, there are only a few steps that are needed to be done manually: + 1) Boot the latest install ISO from this repository on an UEFI system. + 2) Run `swarsel-install -n ` + 3) Reboot -0) Fork this repo, and write your own host config at `hosts/nixos//default.nix` (you can use one of the other configurations as a template. Also see https://github.com/Swarsel/.dotfiles/tree/main/modules for a list of all additional options). At the very least, you should replace the `secrets/` directory with your own secrets and replace the SSH public keys with your own ones. I personally recommend to use the literate configuration and `org-babel-tangle-file` in Emacs, but you can also simply edit the separate `.nix` files. -1) Have a system with `nix` available booted (this does not need to be installed, i.e. you can use a NixOS installer image; a custom minimal installer ISO can be built by running `just iso` in the root of this repo) -2) Make sure that your Yubikey is plugged in or that you have your SSH key available (and configured) -3) Run + Alternatively, to install this from any NixOS live ISO, run `nix run --experimental-features 'nix-command flakes' github:Swarsel/.dotfiles#install -- -n ` at step 2. +
-``` shell -nix run --experimental-features 'nix-command flakes' github:Swarsel/.dotfiles#install -- -n -d -``` + ## Infrastructure -Alternatively (if you already have this configuration installed), you can also run `bootstrap -n -d ` (this runs the same program as the command above). -4) Follow the installers instructions: - - you will have to choose a disk encryption password (if you want that feature) - - you will have to confirm once that the target system has rebooted - - you will have to enter the root password once during the final system install -5) That should be it! The installer will take care of setting up disks, secrets, and the rest of the hardware configuration! You will still have to sign in manually to some webservices etc. +
+ Click here for a summary of my infrastructure -## General Nix tips 8 useful links -Below is a small list of tips that should be helpful no matter if you are new to the nix ecosystem: +topology -- Once you have the experimental feature `nix-command` enabled, you can temporarily install any package using `nix shell nixpkgs#` - this can be e.g. useful if you accidentally removed home-manager from your packages on a non-NixOS machine. - - The `nix [...]` commands are generally very useful, more info can be found here: https://nixos.org/manual/nix/stable/command-ref/new-cli/nix -- These links are your best friends: - - https://search.nixos.org/packages - - https://search.nixos.org/options - - https://nix-community.github.io/home-manager/options.html / https://mipmip.github.io/home-manager-option-search/ -- Flake output reference: https://nixos-and-flakes.thiscute.world/other-usage-of-flakes/outputs - - or more general, the [NixOS & Flakes Book](https://nixos-and-flakes.thiscute.world/) -- Also useful is the [NixOS wiki](https://nixos.wiki/wiki/Main_Page), but some pages are outdated, so use with some care -- You can find public repositories with modules at https://nur.nix-community.org/ (you should check what you are installing however): - - I like to use this for rycee's firefox extensions: https://nur.nix-community.org/repos/rycee/ -- When you are trying to setup a new configuration part, GitHub code search can really help you to find a working configuration. -- getting packages at a different version than your target (or not packaged at all) can be done in most cases easily with fetchFromGithub (https://ryantm.github.io/nixpkgs/builders/fetchers/) -- you can easily install old revisions of packages using https://lazamar.co.uk/nix-versions/. You can conveniently spawn a shell with a chosen package available using `vershell `. Just make sure to pick a revision that has flakes enabled, otherwise you will need the legacy way of spawning the shell (see the link for more info) -- List of nerdfonts: https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/data/fonts/nerd-fonts/manifests/fonts.json -- List of pre-commit-hooks: https://devenv.sh/reference/options/#pre-commithooks -- Stylix configuration options: https://danth.github.io/stylix/ -- Waybar configuration: https://github.com/Alexays/Waybar/wiki + ### Programs + | Topic | Program | + |---------------|---------------------------------| + |🐚 **Shell** | [zsh](https://github.com/Swarsel/.dotfiles/tree/main/modules/home/common/zsh.nix) | + |🚪 **DM** | [greetd](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/common/login.nix) | + |🪟 **WM** | [SwayFX](https://github.com/Swarsel/.dotfiles/tree/main/modules/home/common/sway.nix) | + |⛩️ **Bar** | [Waybar](https://github.com/Swarsel/.dotfiles/tree/main/modules/home/common/waybar.nix) | + |✒️ **Editor** | [Emacs](https://github.com/Swarsel/.dotfiles/tree/main/files/emacs/init.el) | + |🖥️ **Terminal**| [Kitty](https://github.com/Swarsel/.dotfiles/tree/main/modules/home/common/kitty.nix) | + |🚀 **Launcher**| [Fuzzel](https://github.com/Swarsel/.dotfiles/tree/main/modules/home/common/fuzzel.nix) | + |🚨 **Alerts** | [Mako](https://github.com/Swarsel/.dotfiles/tree/main/modules/home/common/mako.nix) | + |🌐 **Browser** | [Firefox](https://github.com/Swarsel/.dotfiles/tree/main/modules/home/common/zsh.nix) | + |🎨 **Theme** | [City-Lights (managed by stylix)](https://github.com/Swarsel/.dotfiles/tree/main/modules/home/common/sharedsetup.nix)| -## Attributions, Acknowledgements, Inspirations, etc. + ### Services -These are in random order (also known as 'the order in which I discovered them'). I would like to express my gratitude to: + | Topic | Program | + |-----------------------|---------------------------------------------------------------------------------------------------------------------| + |📖 **Books** | [Kavita](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/kavita.nix) | + |📼 **Videos** | [Jellyfin](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/jellyfin.nix) | + |🎵 **Music** | [Navidrome](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/navidrome.nix) + [Spotifyd](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/spotifyd.nix) + [MPD](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/mpd.nix) | + |🗨️ **Messaging** | [Matrix](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/matrix.nix) | + |📁 **Filesharing** | [Nectcloud](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/nextcloud.nix) | + |🎞️ **Photos** | [Immich](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/immich.nix) | + |📄 **Documents** | [Paperless](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/paperless.nix) | + |🔄 **File Sync** | [Syncthing](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/syncthing.nix) | + |💾 **Backups** | [Restic](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/restic.nix) | + |👁️ **Monitoring** | [Grafana](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/monitoring.nix) | + |🍴 **RSS** | [FreshRss](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/freshrss.nix) | + |🌳 **Git** | [Forgejo](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/forgejo.nix) | + |⚓ **Anki Sync** | [Anki Sync Server](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/ankisync.nix) | + |🪪 **SSO** | [Kanidm](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/kanidm.nix) + [oauth2-proxy](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/oauth2-proxy.nix) | + |💸 **Finance** | [Firefly-III](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/firefly-iii.nix) | + |🃏 **Collections** | [Koillection](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/koillection.nix) | + |🗃️ **Shell History** | [Atuin](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/atuin.nix) | + |📅 **CalDav/CardDav** | [Radicale](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/radicale.nix) | + |↔️ **P2P Filesharing** | [Croc](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/croc.nix) | + |✂️ **Paste Tool** | [Microbin](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/microbin.nix) | + |📸 **Image Sharing** | [Slink](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/slink.nix) | + |🔗 **Link Shortener** | [Shlink](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/shlink.nix) | + + ### Hosts + + | Name | Hardware | Use | + |---------------------|-----------------------------------------------------|-----------------------------------------------------| + |💻 **pyramid** | Framework Laptop 16, AMD 7940HS, RX 7700S, 64GB RAM | Work laptop | + |💻 **bakery** | Lenovo Ideapad 720S-13IKB | Personal laptop | + |💻 **machpizza** | MacBook Pro 2016 | MacOS reference and build sandbox | + |🏠 **treehouse** | NVIDIA DGX Spark | AI Workstation, remote builder, hm-only-reference | + |🖥️ **summers** | ASUS Z10PA-D8, 2* Intel Xeon E5-2650 v4, 128GB RAM | Homeserver (microvms), remote builder, datastorage | + |🖥️ **winters** | ASRock J4105-ITX, 32GB RAM | Homeserver (IoT server in spe) | + |🖥️ **hintbooth** | HUNSN RM02, 8GB RAM | Router | + |☁️ **stoicclub** | Cloud Server: 1 vCPUs, 8GB RAM | Authoritative dns server | + |☁️ **liliputsteps** | Cloud Server: 1 vCPUs, 8GB RAM | SSH bastion | + |☁️ **twothreetunnel**| Cloud Server: 2 vCPUs, 8GB RAM | Service proxy | + |☁️ **eagleland** | Cloud Server: 2 vCPUs, 8GB RAM | Mailserver | + |☁️ **moonside** | Cloud Server: 4 vCPUs, 24GB RAM | Gaming server, syncthing + lightweight services | + |☁️ **belchsfactory** | Cloud Server: 4 vCPUs, 24GB RAM | Hydra builder and nix binarycache | + |📱 **magicant** | Samsung Galaxy Z Flip 6 | Phone | + |💿 **drugstore** | - | NixOS-installer ISO for bootstrapping new hosts | + |💿 **brickroad** | - | Kexec tarball for bootstrapping low-memory machines | + |❔ **chaotheatre** | - | Demo config for checking out this configuration | + |❔ **toto** | - | Helper configuration for testing purposes | +
+ + ## General Nix tips & useful links + +
+ Click here for a summary of nix tips & links + + - Below is a small list of tips that should be helpful if you are new to the nix ecosystem: + + - Temporarily install any package using `nix shell nixpkgs#` - this can be e.g. useful if you accidentally removed home-manager from your packages on a non-NixOS machine. + - if you need multiple packages, you can do `nix shell nixpkgs#{,,}`. + - you can set `nix.registry` to add more flakes to your registry. I use this to add a `n` shorthand to `nixpkgs`, which allows me to do `nix shell n#{,,}`. + - Alternatively, use [comma](https://github.com/nix-community/comma) + - More info on `nix [...]` commands: https://nixos.org/manual/nix/stable/command-ref/new-cli/nix + - some examples: + - `nix flake update ` lets you update a specific input only. + - `nix repl ` gives quick insight into your written configuration. + - `nix eval #` quickly returns an attribute in your written configuration + - `nix fmt` formats your flake using the formatter specified under `formatter` in your `flake.nix` + - When you are trying to setup a new configuration part, [GitHub code search](https://github.com/search?q=language%3ANix&type=code) can really help you to find a working configuration. Just filter for `.nix` files and the options you are trying to set up. + - getting packages at a different version than your target (or not packaged at all) can be done in most cases easily with fetchFromGithub (https://ryantm.github.io/nixpkgs/builders/fetchers/) + - you can easily install old revisions of packages using https://lazamar.co.uk/nix-versions/. You can conveniently spawn a shell with a chosen package available using `vershell `. Just make sure to pick a revision that has flakes enabled, otherwise you will need the legacy way of spawning the shell (see the link for more info) + - when developing modules in a dev branch of another flake, you can use `--override-input` to temporarily use the local directory as the flake source. + - including `nixosConfig ? config` in your module arguments is a smart way of enabling a module to pull in config from NixOS or home-manager config, no matter if it is a NixOS system or not. + - you can have a quick cli evaluation for nix commands with e.g. `nixpgks.lib` available using `nix-instantiate --strict --eval --expr "let lib = import ; in "`. + - if you are looking for a specific library, `nix-locate` makes it easy to look for them. + - to look at the dependencies pulled in by a tool, use `nix-tree` + - to find out which derivation uses another derivation, use `nix store --query --referrers ` + - to get a neat overview of your config changes in recent generations, use `nix profile diff-closures --profile /nix/var/nix/profiles/system` + - to get instead the changes since the last boot, use `nix profile diff-closures /run/*-system` + - if you just need the generation numbers, use `sudo nix-env --list-generations --profile /nix/var/nix/profiles/system` + - to then switch to another generation, you can use `sudo nix-env --switch-generation -p /nix/var/nix/profiles/system` followed by `sudo /nix/var/nix/profiles/system/bin/switch-to-configuration switch` + + - These links are your best friends: + - The nix documentation: https://nix.dev/ + - The nixpkgs reference manual: https://nixos.org/manual/nixpkgs/unstable/#buildpythonapplication-function + - the [nixpkgs repository](https://github.com/NixOS/nixpkgs) - especially useful to look at the various READMEs that are in various places in the repository (find using GitHub code search) as well as the [issues](https://github.com/Swarsel/.dotfiles/issues) and [PRs](https://github.com/Swarsel/.dotfiles/pulls) pages + - and the [nixpkgs Pull Request Tracker](https://nixpk.gs/pr-tracker.html) + - The NixOS manual: https://nixos.org/manual/nixos/stable/ + - The NixOS package search: https://search.nixos.org/packages + - and the nix package version search: https://lazamar.co.uk/nix-versions/ + - The NixOS option search https://search.nixos.org/options + - [mipmip](https://github.com/mipmip)'s home-manager option search: https://mipmip.github.io/home-manager-option-search/ + - [Alan Pearce](https://alanpearce.eu/)'s nix-darwin search: https://searchix.alanpearce.eu/options/darwin/search (which supports all of the other versions as well :o) + - For the above, you can use the CLI tool [manix](https://github.com/mlvzk/manix) + - Nix function search: https://noogle.dev/ + - Search for nix-community options: https://search.nüschtos.de/ + - But that is not all: + - Some nix resources + - A tour of Nix: https://nixcloud.io/tour/ + - The Nix One Pager: https://github.com/tazjin/nix-1p + - another one page introduction: https://learnxinyminutes.com/nix/ + - a very short introduction to Nix features: https://zaynetro.com/explainix + - introductory nix article: https://medium.com/@MrJamesFisher/nix-by-example-a0063a1a4c55 + - and another one: https://web.archive.org/web/20210121042658/https://ebzzry.io/en/nix/#nix + - How to learn nix: https://ianthehenry.com/posts/how-to-learn-nix/ + - the Nix Cookbook: https://github.com/functionalops/nix-cookbook?tab=readme-ov-file + - and the Nix Pills: https://nixos.org/guides/nix-pills/ + - Some resources on flakes + - Why to use flakes and introduction to flakes: https://www.tweag.io/blog/2020-05-25-flakes/ + - The [NixOS & Flakes Book](https://nixos-and-flakes.thiscute.world/) + - and [Wombat's book](https://mhwombat.codeberg.page/nix-book/) + - or the [Zero to Nix series](https://zero-to-nix.com/) + - Practical nix flakes article: https://serokell.io/blog/practical-nix-flakes + - A bit on Overlays: + - Overview on overlays: [Mastering Nixpkgs overlays article](https://nixcademy.com/posts/mastering-nixpkgs-overlays-techniques-and-best-practice/) + - Some examples on best practises: [Do's and Don'ts of overlays](https://flyingcircus.io/news/detailsansicht/nixos-the-dos-and-donts-of-nixpkgs-overlays) + - Blog article about overrides: https://bobvanderlinden.me/customizing-packages-in-nix/#using-modified-packages + - Also useful is the [official NixOS Wiki](https://wiki.nixos.org/wiki/NixOS_Wiki) + - there is also the [unofficial NixOS Wiki](https://nixos.wiki/) that tends to be a bit outdated, use with care + - Some resources for specific nix tools: + - Flake output reference: https://nixos-and-flakes.thiscute.world/other-usage-of-flakes/outputs + - You can find public repositories with modules at https://nur.nix-community.org/ (you should check what you are installing however): + - I like to use this for rycee's firefox extensions: https://nur.nix-community.org/repos/rycee/ + - List of nerdfonts: https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/data/fonts/nerd-fonts/manifests/fonts.json + - Stylix configuration options: https://danth.github.io/stylix/ + - nix-on-droid options: https://nix-community.github.io/nix-on-droid/nix-on-droid-options.html#sec-options + - Very useful tools that are mostly not directly used in configuration but instead called on need: + - Convert non-NixOS machines to NixOS using [nixos-infect](https://github.com/elitak/nixos-infect) + - Create various installation media with [nixos-generators](https://github.com/nix-community/nixos-generators) + - Remotely deploy NixOS using [nixos-anywhere](https://github.com/nix-community/nixos-anywhere) + - And a few links that are not directly nix-related, but may still serve you well: + - List of pre-commit-hooks: https://devenv.sh/reference/options/#pre-commithooks + - Waybar configuration: https://github.com/Alexays/Waybar/wiki +
+ + ## Attributions, Acknowledgements, Inspirations, etc. + + These are in random order (also known as 'the order in which I discovered them'). I would like to express my gratitude to: + + - All the great people who have contributed code for the nix-community, with special mentions for (this list is unfairly incomplete): +
+ Click here to expand... -- All the great people who have contributed code for the nix-community, with special mentions for (this list is unfairly incomplete): - [guibou](https://github.com/guibou/) + - [rycee](https://github.com/rycee) + - [adisbladis](https://github.com/adisbladis) - [Mic92](https://github.com/Mic92/sops-nix) - [lassulus](https://github.com/lassulus) - [danth](https://github.com/danth/) - [LnL7](https://github.com/LnL7) - [t184256](https://github.com/t184256) - [bennofs](https://github.com/bennofs) -- All the people who have inspired me with their configurations (sadly also highly incomplete): + - [Pandapip1](https://github.com/Pandapip1) + - [zowoq](https://github.com/zowoq) + - [numtide](https://github.com/numtide) + - [hsjobeki](https://github.com/hsjobeki) + - [blitz](https://github.com/blitz) + - [RaitoBezarius](https://github.com/RaitoBezarius) + - [nikstur](https://github.com/nikstur) + - [talyz](https://github.com/talyz) + - [infinisil](https://github.com/infinisil) + - [zhaofengli](https://github.com/zhaofengli) + - [Artturin](https://github.com/Artturin) + - [oddlama](https://github.com/oddlama) +
+ + - All the people who have inspired me with their configurations (sadly also highly incomplete): +
+ Click here to expand... + - [theSuess](https://github.com/theSuess) with their [home-manager](https://code.kulupu.party/thesuess/home-manager) - [hlissner](https://github.com/hlissner) with their [dotfiles](https://github.com/hlissner/dotfiles) - [drduh](https://github.com/drduh/YubiKey-Guide) with their [YubiKey-Guide](https://github.com/drduh/YubiKey-Guide) @@ -141,5 +301,8 @@ These are in random order (also known as 'the order in which I discovered them') - [0xdade](https://github.com/0xdade) with their [blog](https://0xda.de/blog/) - [EmergentMind](https://github.com/EmergentMind) with their [nix-config](https://github.com/EmergentMind/nix-config) - [librephoenix](https://github.com/librephoenix) with their [nixos-config](https://github.com/librephoenix/nixos-config) + - [Xe](https://github.com/Xe) with their [blog](https://xeiaso.net/blog/) + - [oddlama](https://github.com/oddlama) with their absolutely incredible [nix-config](https:/github.com/oddlama/nix-config) +
-If you feel that I forgot to pay you tribute for code that I used in this repository, please shoot me a message and I will fix it :) + If you feel that I forgot to pay you tribute for code that I used in this repository, please shoot me a message and I will fix it :) diff --git a/.github/swarselsystems_preview.png b/.github/swarselsystems_preview.png deleted file mode 100644 index a8b229a..0000000 Binary files a/.github/swarselsystems_preview.png and /dev/null differ diff --git a/.gitignore b/.gitignore index c833eeb..c664d49 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,9 @@ secrets/keys/pubring.kbx secrets/keys/private-keys-v1.d/ +install/flake.lock result *.~undo-tree~ *.iso +*.bak .pre-commit-config.yaml +.direnv diff --git a/.sops.yaml b/.sops.yaml index 13c8d99..4b38475 100644 --- a/.sops.yaml +++ b/.sops.yaml @@ -7,10 +7,17 @@ keys: - &swarsel 4BE7925262289B476DBBC17B76FD3810215AE097 - &hosts - &winters age1h72072slm2pthn9m2qwjsyy2dsazc6hz97kpzh4gksvv0r2jqecqul8w63 - - &toto age1qzh3u0804q3xtfz6ujp3ffqm38jxlwr2h720mqvnjg56scf96q9qn5wkk8 + - &twothreetunnel age1g7atkxdlt4ymeh7v7aa2yzr2hq2qkvzrc4r49ugttm3n582ymv9qrmpk8d + - &liliputsteps age1ly2endyt0y9xyddj6yuj4nw6fa3ltvzlvew4cr4lzs6dv8dkavpqadmyxx + - &stoicclub age15klj4t7gpfp69472mne4ue62pp6m4e04dmjyw7yf30qtqd3vl3uqjmcyxm + - &belchsfactory age1k73gy5em3js9zklnnkzp5hme9k04lny32fgahmzddknjw5c295asdyr4x6 + - &eagleland age1cmzh82q8k59yzceuuy2epmqu22g7m84gqvq056mhgehwpmvjadfsc3glc8 + - &hintbooth age1hsumymvh5mkqlaynrp9lv2w696yk3wtjzlyfmrpeuvh9u2tlwceqh3563x + - &bakery age1mjgw3nxlnqdj04mgjz3wn7fj2nl2nxla4p2r2fn4nkvayfgp09pqllxzyh + - &toto age16vzhcvz8tyxj8e0f47fy0z4p3dsg0ak4vl52ut3l07a0tz465cxslmhevl - &surface age1zlnxraee6tddr07xn59mx5rdexw8qxryd53eqlsajasfhfy78fkq705dfg - &nbl age16lnmuuxfuxxtty3atnhut8wseppwnhp7rdhmxqd5tdvs9qnjffjq42sqyy - - &sync age1glge4e97vgqzh332mqs5990vteezu2m8k4wq3z35jk0q8czw3gks2d7a3h + - &moonside age18quey88vge7xytclg2nuq4ncme86dg04lxwczqxczmdchnjg3p0saehsnh creation_rules: - path_regex: secrets/general/[^/]+\.(yaml|json|env|ini)$ key_groups: @@ -18,33 +25,191 @@ creation_rules: - *swarsel age: - *winters + - *twothreetunnel + - *liliputsteps + - *stoicclub + - *belchsfactory + - *eagleland + - *hintbooth + - *bakery - *toto - *surface - *nbl + - *moonside + - path_regex: secrets/repo/[^/]+$ + key_groups: + - pgp: + - *swarsel + age: + - *winters + - *twothreetunnel + - *liliputsteps + - *stoicclub + - *belchsfactory + - *eagleland + - *hintbooth + - *bakery + - *toto + - *surface + - *nbl + - *moonside - path_regex: secrets/certs/[^/]+\.(yaml|json|env|ini)$ key_groups: - pgp: - *swarsel age: - - *winters + - *nbl + - *twothreetunnel + - *liliputsteps + - *stoicclub + - *belchsfactory + - *eagleland + - *hintbooth + - *bakery - *toto - *surface - *winters - - path_regex: secrets/winters/[^/]+\.(yaml|json|env|ini)$ - key_groups: - - pgp: - - *swarsel - age: - - *winters + - *moonside - path_regex: secrets/work/[^/]+\.(yaml|json|env|ini)$ key_groups: - pgp: - *swarsel age: - *nbl - - path_regex: secrets/sync/[^/]+\.(yaml|json|env|ini)$ + + - path_regex: secrets/pyramid/[^/]+\.(yaml|json|env|ini)$ key_groups: - pgp: - *swarsel age: - - *sync + - *nbl + - path_regex: hosts/nixos/x86_64-linux/pyramid/secrets/pii.nix.enc + key_groups: + - pgp: + - *swarsel + age: + - *nbl + + - path_regex: secrets/moonside/secrets.yaml + key_groups: + - pgp: + - *swarsel + age: + - *moonside + - path_regex: hosts/nixos/aarch64-linux/moonside/secrets/pii.nix.enc + key_groups: + - pgp: + - *swarsel + age: + - *moonside + + - path_regex: secrets/belchsfactory/secrets.yaml + key_groups: + - pgp: + - *swarsel + age: + - *belchsfactory + - path_regex: hosts/nixos/aarch64-linux/belchsfactory/secrets/pii.nix.enc + key_groups: + - pgp: + - *swarsel + age: + - *belchsfactory + + - path_regex: secrets/bakery/secrets.yaml + key_groups: + - pgp: + - *swarsel + age: + - *bakery + - path_regex: hosts/nixos/x86_64-linux/bakery/secrets/pii.nix.enc + key_groups: + - pgp: + - *swarsel + age: + - *bakery + + - path_regex: secrets/winters/[^/]+\.(yaml|json|env|ini)$ + key_groups: + - pgp: + - *swarsel + age: + - *winters + - path_regex: hosts/nixos/x86_64-linux/winters/secrets/pii.nix.enc + key_groups: + - pgp: + - *swarsel + age: + - *winters + + - path_regex: secrets/eagleland/[^/]+\.(yaml|json|env|ini)$ + key_groups: + - pgp: + - *swarsel + age: + - *eagleland + + - path_regex: hosts/nixos/x86_64-linux/eagleland/secrets/pii.nix.enc + key_groups: + - pgp: + - *swarsel + age: + - *eagleland + + + + - path_regex: secrets/stoicclub/[^/]+\.(yaml|json|env|ini)$ + key_groups: + - pgp: + - *swarsel + age: + - *stoicclub + - path_regex: hosts/nixos/aarch64-linux/stoicclub/secrets/pii.nix.enc + key_groups: + - pgp: + - *swarsel + age: + - *stoicclub + + - path_regex: secrets/liliputsteps/[^/]+\.(yaml|json|env|ini)$ + key_groups: + - pgp: + - *swarsel + age: + - *liliputsteps + - path_regex: hosts/nixos/aarch64-linux/liliputsteps/secrets/pii.nix.enc + key_groups: + - pgp: + - *swarsel + age: + - *liliputsteps + + - path_regex: secrets/twothreetunnel/[^/]+\.(yaml|json|env|ini)$ + key_groups: + - pgp: + - *swarsel + age: + - *twothreetunnel + - path_regex: hosts/nixos/aarch64-linux/twothreetunnel/secrets/pii.nix.enc + key_groups: + - pgp: + - *swarsel + age: + - *twothreetunnel + + - path_regex: hosts/nixos/x86_64-linux/summers/secrets/ + key_groups: + - pgp: + - *swarsel + + - path_regex: hosts/nixos/x86_64-linux/hintbooth/secrets/ + key_groups: + - pgp: + - *swarsel + age: + - *hintbooth + + - path_regex: hosts/darwin/nbm-imba-166/secrets/pii.nix.enc + key_groups: + - pgp: + - *swarsel diff --git a/SwarselSystems.org b/SwarselSystems.org index bf900b5..61821f7 100644 --- a/SwarselSystems.org +++ b/SwarselSystems.org @@ -1,6 +1,8 @@ -#+title: SwarselSystems: NixOS + Emacs Configuration -#+PROPERTY: header-args:emacs-lisp :tangle programs/emacs/init.el :mkdirp yes +#+title: SwarselSystems: NixOS + Emacs Configurationo +#+PROPERTY: header-args:emacs-lisp :tangle files/emacs/init.el :mkdirp yes #+PROPERTY: header-args:nix :mkdirp yes +#+PROPERTY: header-args:nix-ts :mkdirp yes +#+PROPERTY: header-args:shell :mkdirp yes #+EXPORT_FILE_NAME: index.html #+OPTIONS: toc:6 #+macro: revision-date (eval (format-time-string "%F %T %z")) @@ -22,18 +24,30 @@ I used to have two separate files (=Emacs.org= and =Nixos.org=) because the NixO This configuration is part of a NixOS system that is (nearly) fully declarative and can be found here: - [[https:github.com/Swarsel/.dotfiles][~SwarselSystems~ on github.com]] -- [[https:swagit.swarsel.win/Swarsel/.dotfiles][~SwarselSystems~ on swagit.swarsel.win]] This literate configuration lets me explain my choices to my future self as well as you, the reader. I go to great lengths to explain the choices for all configuration steps that I take in order for me to pay due diligence in crafting my setup, and not simply copying big chunks of other peoples code. Also, the literate configuration approach is very convenient to me as I only need to keep of (ideally) a single file to manage all of my configuration. I hope that this documentation will make it easier for beginners to get into Emacs and NixOS as I know it can be a struggle in the beginning. +** How to use this document +:PROPERTIES: +:CUSTOM_ID: h:6f4b190c-fe69-47a3-9df2-ee429bd9b48b +:END: + +When I started out with nix, it was a painful time. For a beginner, the available resources tend to be too detailed or assume too much prior knowledge. Also, it is a (sad) fact that using nix requires the user to understand it pretty well before most things start to make sense. + +That is the reason why I keep this configuration as a literate one: so that I am able to explain how everything works. In the start, it was my goal to keep this repo simple, so that it would be easy to understand when seen by a beginner. However, over time I have implemented more and more complicated solutions. Still, I try to keep the prosaic descriptions sufficient. + +For a beginner, I recommend to read this file like a book, from start to finish. I will try to explain concepts whenever they first come up, and will regularly link to [[#h:8ea35dcc-ef94-4c10-9112-8be8efd6f424][Appendix C: Explanations to nix functions and operators]] when more context is needed. For the first few times that I am using a new function, I will place such a link again. However, to keep the writing of this file manageable, I will generally only do this no more than three times. + +** Structure of this file +:PROPERTIES: +:CUSTOM_ID: h:bcc3ebbe-df8a-46bd-b42d-73aad6fc66e5 +:END: + This file is structured as follows: - [[#h:a86fe971-f169-4052-aacf-15e0f267c6cd][Introduction (no code)]] This is the block you are currently in. It holds no code that actually builds the system, it just outlines the general approach and explains my rough mentality -- [[#h:d39b8dfb-536d-414f-9fc0-7d67df48cee4][Noweb-Ref blocks]] - This section hold code that can be templated at other parts of the configuration. This is mostly used for the NixOS side of the configuration where I define my host systems that usually have a lot in common. - - [[#h:c7588c0d-2528-485d-b2df-04d6336428d7][flake.nix]] This block holds everything related to the heart of the nix side of the configuration - the =flake.nix= file. @@ -54,7 +68,7 @@ This file is structured as follows: #+RESULTS: : --prefix=/nix/store/lymgpfqr5dp1wc0khbcbhhjnxq8ccsy9-emacs-pgtk-20240521.0 --disable-build-details --with-modules --with-pgtk --with-compress-install --with-toolkit-scroll-bars --with-native-compilation --without-imagemagick --with-mailutils --without-small-ja-dic --with-tree-sitter --without-xinput2 --with-xwidgets --with-dbus --with-selinux - This file is not loaded by Emacs directly as the configuration (even though this would be possible) - instead, it generates two more files: +This file is not loaded by Emacs directly as the configuration (even though this would be possible) - instead, it generates two more files: - =early-init.el= This file handle startup optimization and sets up the basic frame that I will be working in. @@ -64,19 +78,19 @@ This file is structured as follows: By using the configuration offered by this file, the file you are reading right now (=SwarselSystems.org=) will not be freshly tangled on every file save, as this slows down emacs over time. However, when you clone this configuration yourself and have not yet activated it, you need to tangle the file yourself. This can be done using the general keybind =C-c C-v t= or my personal chord =C-SPC o t=. Alternatively, execute the following block: - #+begin_src emacs-lisp :tangle no :export both :results silent +#+begin_src emacs-lisp :tangle no :export both :results silent - (org-babel-tangle) + (org-babel-tangle) - #+end_src +#+end_src The =.html= version of this page can be generated by calling the chord =C-SPC o e=, or by executing the below block - #+begin_src emacs-lisp :tangle no :export both :results silent +#+begin_src emacs-lisp :tangle no :export both :results silent - (org-html-export-to-html) + (org-html-export-to-html) - #+end_src +#+end_src The web version is useful because it allows navigation using org-mode links, which makes the configuration easier to follow (I hope!). Lastly, I add this javascript bit to the file in order to have a darkmode toggle when exporting to html: @@ -87,8 +101,8 @@ Lastly, I add this javascript bit to the file in order to have a darkmode toggle "") #+end_src @@ -103,687 +117,321 @@ window.addEventListener('load', addDarkmodeWidget); #+end_export -The rest of this file will now contain actual code that is used in the configuration. -* Noweb-Ref blocks and supplementary files -:PROPERTIES: -:CUSTOM_ID: h:d39b8dfb-536d-414f-9fc0-7d67df48cee4 -:END: + This section hold code that can be templated at other parts of the configuration. This is mostly used for the NixOS side of the configuration where I define my host systems that usually have a lot in common. -These blocks are used in several places throughout the configurations, but not on all machines necessarily. For example, the theming section needs to be in a NixOS block on NixOS machines but in a home-manager block on non-NixOS. +- [[#h:8fc9f66a-7412-4091-8dee-a06f897baf67][Appendix A: Supplementary Files]] + This section holds files that are not written in nix but are still referenced in the configuration in some way. This is mostly used for configuration of programs that have no native nix support, like tridactyl. Note that shell scripts are still defined under their respective entry in [[#h:64a5cc16-6b16-4802-b421-c67ccef853e1][Packages]]. -Originally, I used this method a lot throughout my configuration. However, as my knowledge of NixOS grew, I have been weeding these snippets out more and more as I find more efficient native solutions. Now, only the theming block remains. +- Historical Note: Noweb-Ref blocks -This serves only to reduce code duplication in this file. The tangled files experience no size reduction, since noweb-ref only substitutes these blocks in. +These blocks were used in several places throughout the configurations, but not on all machines necessarily. For example, the theming section used need to be in a NixOS block on NixOS machines but in a home-manager block on non-NixOS. -Also, this section now holds some of the longer configuration files that cannot be defined directly within NixOS configuration. These files are usually symlinked using =home.file=. +Originally, I used this method a lot throughout my configuration. However, as my knowledge of NixOS grew, I have been weeding these snippets out more and more as I find more efficient native solutions. Now, only the theming block remains. For example, the above problem can be solved by defining a =theme= attribute set and using =lib.recursiveUpdate= as shown in [[#h:79f7150f-b162-4f57-abdf-07f40dffd932][Shared Configuration Options (holds firefox & stylix config parts)]] and [[#h:a92318cd-413e-4e78-a478-e63b09df019c][Theme (stylix)]]. -** Theme (stylix) -:PROPERTIES: -:CUSTOM_ID: h:5bc1b0c9-dc59-4c81-b5b5-e60699deda78 -:END: +As such, this served to reduce code duplication in this file. The tangled files experienced no size reduction, since noweb-ref only substitutes these blocks in. -For styling, I am using the [[https://github.com/danth/stylix][stylix]] NixOS module, loaded by flake. This package is really great, as it adds nix expressions for basically everything. Ever since switching to this, I did not have to play around with theming anywhere else. - -The full list of nerd-fonts can be found here: https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/data/fonts/nerd-fonts/manifests/fonts.json - -This is where the theme for the whole OS is defined. Originally, this noweb-ref section could not be copied to the general NixOS config since they are on different folder structure levels in the config, which would have made the flake impure. By now, I have found out that using the =${self}= method for referencing the flake root, I could circumvent this problem. Also, the noweb-ref block could in general be replaced by a custom attribute set (see for example [[#h:e7f98ad8-74a6-4860-a368-cce154285ff0][firefox]]). The difference here is, however, that this block is used in a NixOS and a home-manager-only configuration, verbatim. If I were to use an attribute set, I would have to duplicate this block once each for NixOS and home-manager. Alas, this block stays (for now). +For archival reasons, here is shown how to use a noweb-ref block, in case I ever decide to use it again, or it is interesting to you: -#+begin_src nix :tangle no :noweb-ref theme - +#+begin_src nix-ts :tangle no :noweb-ref blockName enable = true; - base16Scheme = "${self}/wallpaper/swarsel.yaml"; - # base16Scheme = "${pkgs.base16-schemes}/share/themes/shapeshifter.yaml"; - polarity = "dark"; - opacity.popups = 0.5; - cursor = { - package = pkgs.capitaine-cursors; - name = "capitaine-cursors"; - size = 16; - }; - fonts = { - sizes = { - terminal = 10; - applications = 11; - }; - serif = { - # package = (pkgs.nerdfonts.override { fonts = [ "FiraMono" "FiraCode"]; }); - package = pkgs.cantarell-fonts; - # package = pkgs.montserrat; - name = "Cantarell"; - # name = "FiraCode Nerd Font Propo"; - # name = "Montserrat"; - }; - - sansSerif = { - # package = (pkgs.nerdfonts.override { fonts = [ "FiraMono" "FiraCode"]; }); - package = pkgs.cantarell-fonts; - # package = pkgs.montserrat; - name = "Cantarell"; - # name = "FiraCode Nerd Font Propo"; - # name = "Montserrat"; - }; - - monospace = { - package = pkgs.nerd-fonts.fira-mono; # has overrides - - name = "FiraCode Nerd Font Mono"; - }; - - emoji = { - package = pkgs.noto-fonts-emoji; - name = "Noto Color Emoji"; - }; - }; - #+end_src -** Server Emacs config + +which can then be used in a block like: + +#+begin_src nix-ts :tangle no :noweb yes + <> +#+end_src + +not that noweb-reffed blocks will not be indented correctly. You will want to account for that when checking your nix flake with the formatter of your choice. Personally, I have solved this issue using the functions defined in [[#h:59d4306e-9b73-4b2c-b039-6a6518c357fc][org-mode: Upon-save actions (Auto-tangle, export to html, formatting)]]. Originally, I also automatically exported to html there, but it incurred a too high memory penalty which made Emacs become sluggish over time. + +** TODO Structure of this flake :PROPERTIES: -:CUSTOM_ID: h:c1e53aed-fb47-4aff-930c-dc52f3c5dcb8 +:CUSTOM_ID: h:2c5529ed-e6d9-44b6-b0d3-5bf96a6bed64 :END: -On my server, I use a reduced, self-contained emacs configuration that only serves as an elfeed sync server. This is currently unused, however, I am keeping this in here for now as a reference. The big problem here was the bidirectional syncing using =bjm/elfeed-updater=. As I am using this both on a laptop client (using elfeed) as well as on a mobile phone (using elfeed-cljsrn over elfeed-web), I set up a Syncthing service to take care of the feeds as well as the db state. However, I could only either achieve changes propagating properly from the laptop to the server or from the phone to the server. Both would not work. This current state represents the state where from-laptop changes would propagate. To allow from-phone changes, change =(elfeed-db-load)= in =bjm/elfeed-updater= to =(elfeed-db-save)=. - - -#+begin_src emacs-lisp :tangle programs/emacs/server.el -(require 'package) - -(package-initialize nil) -(setq package-enable-at-startup nil) - -(add-to-list 'package-archives '("org" . "http://orgmode.org/elpa/") t) - -(add-to-list 'package-archives - '("melpa" . "https://melpa.org/packages/") t) - - -(package-initialize) - -(let ((default-directory "~/.emacs.d/elpa/")) - (normal-top-level-add-subdirs-to-load-path)) - -(unless (package-installed-p 'use-package) - (package-refresh-contents) - (package-install 'use-package)) - -(require 'use-package) - -(use-package elfeed - :ensure t - :bind (:map elfeed-search-mode-map - ("q" . bjm/elfeed-save-db-and-bury))) - -(require 'elfeed) - -(use-package elfeed-org - :ensure t - :config - (elfeed-org) - (setq rmh-elfeed-org-files (list "/var/lib/syncthing/.elfeed/elfeed.org"))) - -(use-package elfeed-goodies - :ensure t) - -(elfeed-goodies/setup) - -(use-package elfeed-web - :ensure t) - -(global-set-key (kbd "C-x w") 'bjm/elfeed-load-db-and-open) - -(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) - - -(defun bjm/elfeed-save-db-and-bury () - "Wrapper to save the elfeed db to disk before burying buffer" - (interactive) - (elfeed-db-save) - (quit-window)) - -(defun bjm/elfeed-load-db-and-open () - "Wrapper to load the elfeed db from disk before opening" - (interactive) - (elfeed-db-load) - (elfeed) - (elfeed-search-update--force) - (elfeed-update)) - -(defun bjm/elfeed-updater () - "Wrapper to load the elfeed db from disk before opening" - (interactive) - (elfeed-db-load)) - -(run-with-timer 0 (* 1 60) 'bjm/elfeed-updater) - -(setq httpd-port 9812) -(setq httpd-host "0.0.0.0") -(setq httpd-root "/root/.emacs.d/elpa/elfeed-web-20240729.1741/") -(setq elfeed-db-directory "/var/lib/syncthing/.elfeed/db/") - -(httpd-start) -(elfeed-web-start) - -#+end_src -** tridactylrc -:PROPERTIES: -:CUSTOM_ID: h:fc64f42f-e7cf-4829-89f6-2d0d58e04f51 -:END: - -This is the configuration file for tridactyl, which provides keyboard-driven navigation in firefox. Pay attention to the warnings in this file; depending on your browsing behaviour, you might expose yourself to some vulnerabilities by copying this configuration. - - -#+begin_src :tangle programs/firefox/tridactyl/tridactylrc :mkdirp yes - -sanitise tridactyllocal tridactylsync - -colourscheme base16-codeschool - -" General Settings -set update.lastchecktime 1720629386560 -set update.lastnaggedversion 1.24.1 -set update.nag true -set update.nagwait 7 -set update.checkintervalsecs 86400 -set configversion 2.0 -set searchurls.no https://search.nixos.org/options?query= -set searchurls.np https://search.nixos.org/packages?query= -set searchurls.hm https://home-manager-options.extranix.com/?query= -set completions.Tab.statusstylepretty true -set hintfiltermode vimperator-reflow -set hintnames numeric - -" Binds -bind buffer # -bind gd tabdetach -bind gD composite tabduplicate; tabdetach -bind d composite tabprev; tabclose # -bind D tabclose -bind c hint -bindurl ^http(s)?://www\.google\.com c hint -Jc [class="LC20lb MBeuO DKV0Md"],[class="YmvwI"],[class="YyVfkd"],[class="fl"] -bindurl ^http(s)?://news\.ycombinator\.com c hint -Jc [class="titleline"],[class="age"] -bindurl ^http(s)?://lobste\.rs c hint -Jc [class="u-url"],[class="comments_label"] -bindurl ^http(s)?://www\.google\.com gi composite focusinput -l ; text.end_of_line - -" Search in page -set findcase smart -bind / fillcmdline find -bind ? fillcmdline find -? -bind n findnext 1 -bind N findnext -1 - -bind j scrollline 4 -bind k scrollline -4 - - -" WARNING: This file defines and runs a command called fixamo_quiet. If you -" also have a malicious addon that operates on `` installed this -" will allow it to steal your firefox account credentials! -" -" With those credentials, an attacker can read anything in your sync account, -" publish addons to the AMO, etc, etc. -" -" Without this command a malicious addon can steal credentials from any site -" that you visit that is not in the restrictedDomains list. -" -" You should comment out the fixamo lines unless you are entirely sure that -" they are what you want. -command fixamo_quiet jsb tri.excmds.setpref("privacy.resistFingerprinting.block_mozAddonManager", "true").then(tri.excmds.setpref("extensions.webextensions.restrictedDomains", '""')) -command fixamo js tri.excmds.setpref("privacy.resistFingerprinting.block_mozAddonManager", "true").then(tri.excmds.setpref("extensions.webextensions.restrictedDomains", '""').then(tri.excmds.fillcmdline_tmp(3000, "Permissions added to user.js. Please restart Firefox to make them take affect."))) - -fixamo_quiet -set allowautofocus false - -" The following modification allows Tridactyl to function on more pages, e.g. raw GitHub pages. -" You may not wish to run this. Mozilla strongly feels that you shouldn't. -" Read https://wiki.mozilla.org/Security/CSP#Goals for more information. -" -" Equivalent to `set csp clobber` before it was removed. -" This weakens your defences against cross-site-scripting attacks -" and other types of code-injection by reducing the strictness -" of Content Security Policy on all sites in a couple of ways. -" -" We remove the sandbox directive -" https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/sandbox -" which allows our iframe (and anyone else's) to run on any website. -" -" We weaken the style-src directive -" https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/style-src -" to allow us to theme our elements. -" This exposes you to 'cross site styling' attacks -jsb browser.webRequest.onHeadersReceived.addListener(tri.request.clobberCSP,{urls:[""],types:["main_frame"]},["blocking","responseHeaders"]) - -" default is 300ms -set hintdelay 100 - -" Some pages like github break on the tridactyl quick search. have this as a fallback -unbind - -" Subconfig Settings -seturl www.google.com followpagepatterns.next Next -seturl www.google.com followpagepatterns.prev Previous - -" Autocmds -autocmd DocStart undefined mode ignore -autocmd DocStart pokerogue.net mode ignore -autocmd DocStart typelit.io mode ignore -autocmd DocStart vc-impimba-1.m.imp.ac.at/ui/webconsole mode ignore - -" For syntax highlighting see https://github.com/tridactyl/vim-tridactyl -" vim: set filetype=tridactyl - -#+end_src -** Waybar style.css -:PROPERTIES: -:CUSTOM_ID: h:77b1c523-5074-4610-b320-90af95e6134d -:END: - -This is the stylesheet used by waybar. - -#+begin_src css :tangle programs/waybar/style.css :mkdirp yes -@define-color foreground #fdf6e3; -@define-color background #1a1a1a; -@define-color background-alt #292b2e; -@define-color foreground-warning #268bd2; -@define-color background-warning @background; -@define-color foreground-error red; -@define-color background-error @background; -@define-color foreground-critical gold; -@define-color background-critical blue; - - - * { - border: none; - border-radius: 0; - font-family: "FiraCode Nerd Font Propo", "Font Awesome 5 Free"; - font-size: 14px; - min-height: 0; - margin: -1px 0px; -} - -window#waybar { - background: transparent; - color: @foreground; - transition-duration: .5s; -} - -window#waybar.hidden { - opacity: 0.2; -} - - -#mpris { - padding: 0 10px; - background-color: transparent; - color: #1DB954; - font-family: Monospace; - font-size: 12px; -} - -#custom-right-arrow-dark, -#custom-left-arrow-dark { - color: @background; - background: @background-alt; - font-size: 24px; -} - -#window { - font-size: 12px; - padding: 0 20px; -} - -#mode { - background: @background-critical; - color: @foreground-critical; - padding: 0 3px; -} - -#privacy, -#custom-configwarn { - color: black; - padding: 0 3px; - animation-name: configblink; - animation-duration: 0.5s; - animation-timing-function: linear; - animation-iteration-count: infinite; - animation-direction: alternate; -} - -#custom-nix-updates { - color: white; - padding: 0 3px; -} - -#custom-outer-right-arrow-dark, -#custom-outer-left-arrow-dark { - color: @background; - font-size: 24px; -} - -#custom-outer-left-arrow-dark, -#custom-left-arrow-dark, -#custom-left-arrow-light { - margin: 0 -1px; -} - -#custom-right-arrow-light, -#custom-left-arrow-light { - color: @background-alt; - background: @background; - font-size: 24px; -} - -#workspaces, -#clock.1, -#clock.2, -#clock.3, -#pulseaudio, -#memory, -#cpu, -#temperature, -#custom-scratchpad-indicator, -#power-profiles-daemon, -#idle_inhibitor, -#backlight-slider, -#mpris, -#tray { - background: @background; -} - -#network, -#custom-vpn, -#clock.2, -#battery, -#cpu, -#custom-pseudobat, -#disk { - background: @background-alt; -} - - -#workspaces button { - padding: 0 2px; - color: #fdf6e3; -} -#workspaces button.focused { - color: @foreground-warning; -} - -#workspaces button:hover { - background: @foreground; - color: @background; - border: @foreground; - padding: 0 2px; - box-shadow: inherit; - text-shadow: inherit; -} - -#workspaces button.urgent { - color: @background-critical; - background: @foreground-critical; -} - -#custom-vpn, -#network { - color: #cc99c9; -} - -#temperature, -#power-profiles-daemon { - color: #9ec1cf; -} - -#disk { - /*color: #b58900;*/ - color: #9ee09e; -} - -#custom-scratchpad-indicator { - color: #ffffff; -} - -#disk.warning { - color: @foreground-error; - background-color: @background-error; -} -#disk.critical, -#temperature.critical { - color: @foreground-critical; - background-color: @background-critical; - animation-name: blink; - animation-duration: 0.5s; - animation-timing-function: linear; - animation-iteration-count: infinite; - animation-direction: alternate; -} -#pulseaudio.muted { - color: @foreground-error; -} -#memory { - /*color: #2aa198;*/ - color: #fdfd97; -} -#cpu { - /*color: #6c71c4;*/ - color: #feb144; -} - -#pulseaudio { - /*color: #268bd2;*/ - color: #ff6663; -} - -#battery, -#custom-pseudobat { - color: cyan; -} -#battery.discharging { - color: #859900; -} - -@keyframes blink { - to { - color: @foreground-error; - background-color: @background-error; +The structure of this flake as seen many revisions, however lately I have settled on a system that I have grown to like: + + - =hosts=: This folder is used to house all configurations that are used across the infrastructure. At the top level, it splits into the subfolders =nixos=, =home=, =darwin=, and =android=. These folders specify the mode that the configuration is running in: + - nixos: Full NixOS host (may or may not also use home-manager) + - darwin: Host that uses NixOS on MacOS (may or may not use home-manager) + - home: Host that uses only home-manager (no full NixOS) + - android: Phone using nix-on-droid (may or may not use home-manager) + + The corresponding configurations are automatically generated by =mkFullHostConfigs= and =mkHalfHostConfigs=. A "full" host either in the nixos or darwin folder, while a "half" host is in either of home or android. This has to do with the scheme in which these configurations are generated. + + These folders hold in turn a number of folders, the actual configurations. At this time, the files stored in this folder are: + - default.nix: + This file holds the abstracted configuration of the host. This should mostly be enabling [[#h:f0f1c961-3e7a-47b8-99ab-1654bb45dffc][Profiles]] as well as setting some [[#h:f4f22166-e345-43e6-b15f-b7f5bb886554][Shared Configuration Options]]. + - hardware-config.nix: + It is not clearly defined what I hold in this file. Mostly it is just the attributes that nix originally sets when setting up the system for the first time (although at this time modified by me!), bar any filesystem configuration. This makes my deployment in [[#h:74db57ae-0bb9-4257-84be-eddbc85130dd][swarsel-bootstrap]] a little bit simpler. + - disk-config.nix + Holds the aforementioned filesystem configuration and is applied using [[https://github.com/nix-community/disko][disko]]. + + - The hosts// folders may also have a =secrets= folder, under which a single file =pii.nix.enc= can be stored. As the name suggests, this file should be encrypted. Specifically, it needs to be a [[https://github.com/getsops/sops][sops]]-encrypted file (sops does not seem to suggest a file ending other than .yml or others, which is not verbose enough for me, so I went with =.enc=). This file should have the structure of a nix expression, e.g.: + + #+begin_src nix-ts :tangle no + { + my_value = 2; + my_attrSet = { + enable = true; + }; } -} -@keyframes configblink { - to { - color: @foreground-error; - background-color: transparent; - } -} + #+end_src -#battery.critical:not(.charging) { - color: @foreground-critical; - background-color: @background-critical; - animation-name: blink; - animation-duration: 0.5s; - animation-timing-function: linear; - animation-iteration-count: infinite; - animation-direction: alternate; -} + Using the mechanisms in [[#h:82b8ede2-02d8-4c43-8952-7200ebd4dc23][PII management]] (which in turn uses [[#h:87c7893e-e946-4fc0-8973-1ca27d15cf0e][extra-builtins]] and [[#h:315e6ef6-27d5-4cd8-85ff-053eabe60ddb][sops-decrypt-and-cache]]), these files are decrypted during evaluation time and stored under a persistent directory. As the name suggests, I am using these files to store personally identifiable information - these "secrets" are stored world-readable in the nix store. As such, this should not be used to store important secrets, but rather information that you would not like everyone on the internet to easily find in your git repo. -#backlight-slider slider { - min-height: 0px; - min-width: 0px; - opacity: 0; - background-image: none; - border: none; - box-shadow: none; -} -#backlight-slider trough { - min-height: 5px; - min-width: 80px; - border-radius: 5px; - background-color: black; -} -#backlight-slider highlight { - min-width: 0px; - border-radius: 5px; - background-color: grey; -} + - =modules= + This folder holds the most part of the actual system configuration done in this repository. At some point I thought it was cool to have my whole configuration exposed under the flakes =nixosModules=, which is indeed achieved (its usefulness is however debatable). In any way, this folder splits up as: + - nixos: Holds true NixOS configuration + - home: Holds configuration to be used by home-manager (either as a NixOS submodule or not) + - darwin: Holds configuration for nix-darwin. This folder further splits up into a nixos and a home folder, which hold respective nix or home-manager configuration for nix-darwin. + - iso: Holds specific configuration for my installer ISO that I do not want to have loaded in the rest of the configuration. -#clock.1, -#clock.2, -#clock.3 { - font-family: Monospace; -} + The nixos and home folders further split up: -#clock, -#pulseaudio, -#memory, -#cpu, -#tray, -#temperature, -#power-profiles-daemon, -#network, -#custom-vpn, -#mpris, -#battery, -#custom-scratchpad-indicator, -#custom-pseudobat, -#disk { - padding: 0 3px; -} + - common: Configuration that can be used by all hosts (TODO: this currently includes configuration used by my user devices, which will mostly not be used by servers) + - server: Configuration to be used on servers + - optional: Configuration that will be used rather rarely + This structure is very optionated and highly subjective. I will possibly change this in the future. + + By themselves, most of the files in the modules folder will not do anything. In order for them to do something, their corresponding =config.swarselsystems.modules= attribute needs to be enabled. This is done using... + + - =profiles=: This folder splits up into =home= and =nixos= subfolders, where groupings of module enablers are stored for the respective home and nix setups. Note that =home= profiles are also used in NixOS setups (extensively even)! + + - =nix=: This special folder holds mostly =.nix= files that are not automatically loaded, but rather setup specific things that affect most of the flake. For example, here lies the aforementioned [[#h:87c7893e-e946-4fc0-8973-1ca27d15cf0e][extra-builtins]] as well as the setup for the [[*Globals][Globals]] system. TODO: Move flake-parts units there and explain them here. + + - =lib=: This folder holds utility functions that I add to the nixpkgs library under the =swarselsystems= attribute set. An example would be the =mkIfElse= function. + + - =pkgs=: This folder holds derivations (mostly packages) that I define myself. This is mostly used to grab versions that are not (yet) in nixpkgs, or modified versions of another package. Each derivation in this folder is in turn in its own folder which holds a defautlt.nix. Using the mechanism in [[#h:64a5cc16-6b16-4802-b421-c67ccef853e1][Packages]], these are automatically built and available to all configurations (packages still need to be installed e.g. in =environment.systemPackages=) + + - =checks=: Holds a file that defines my pre-commit-hook checks. TODO: move this to /nix probably + + - =scripts=: This folder holds a bunch of shell scripts that I use for various tasks. Nearly all of these are made into a derivation using =pkgs.writeShellApplication=. In the future (TODO?), I might convert these to native nix, but in the past I kept the as true shellfiles in case I ever wanted to move away from nix. This is becoming less and less likely, however. And even in case that this would happen, I could retrieve these files from the nix store and would simply have to remove the nix store paths. + + - =secrets=: Unlike the similar folder under =hosts=, this folder holds actual sops-encrypted secrets that are created at activation time and not in the nix store. The folder splits up into a bunch of folders, as well as a =repo= folder, which holds another =pii.nix.enc=, which holds global PII's, and a =certs= folder that holds some longer certificate style secrets. + + - =overlays=: This holds a single =default.nix= that defines the overlay I am using in my configuration. It is responsible for adding my defined packages and modifications to the final nixpkgs. Also I add some other conveniences like all past stable nixpkgs and some other package sets. + + - =programs=: This folder holds configurations for various programs (most notably emacs' =init.el= and =early-init.el=), that are being rendered using org-babel and loaded using nix. + + - =wallpaper=: Holds wallpapers and profile pictures. + + - =topology=: Holds the configuration used by [[https://github.com/oddlama/nix-topology][nix-topology]]. + +** Hosts +:PROPERTIES: +:CUSTOM_ID: h:48e0cb2c-e412-4ae3-a244-80a8c09dbb02 +:END: + +Here I give a brief overview over the hostmachines that I am using. This is held in markdown so that I can render it into my GitHub README. + +#+begin_src markdown :tangle no :noweb-ref hosts + | Name | Hardware | Use | + |---------------------|-----------------------------------------------------|-----------------------------------------------------| + |💻 **pyramid** | Framework Laptop 16, AMD 7940HS, RX 7700S, 64GB RAM | Work laptop | + |💻 **bakery** | Lenovo Ideapad 720S-13IKB | Personal laptop | + |💻 **machpizza** | MacBook Pro 2016 | MacOS reference and build sandbox | + |🏠 **treehouse** | NVIDIA DGX Spark | AI Workstation, remote builder, hm-only-reference | + |🖥️ **summers** | ASUS Z10PA-D8, 2* Intel Xeon E5-2650 v4, 128GB RAM | Homeserver (microvms), remote builder, datastorage | + |🖥️ **winters** | ASRock J4105-ITX, 32GB RAM | Homeserver (IoT server in spe) | + |🖥️ **hintbooth** | HUNSN RM02, 8GB RAM | Router | + |☁️ **stoicclub** | Cloud Server: 1 vCPUs, 8GB RAM | Authoritative dns server | + |☁️ **liliputsteps** | Cloud Server: 1 vCPUs, 8GB RAM | SSH bastion | + |☁️ **twothreetunnel**| Cloud Server: 2 vCPUs, 8GB RAM | Service proxy | + |☁️ **eagleland** | Cloud Server: 2 vCPUs, 8GB RAM | Mailserver | + |☁️ **moonside** | Cloud Server: 4 vCPUs, 24GB RAM | Gaming server, syncthing + lightweight services | + |☁️ **belchsfactory** | Cloud Server: 4 vCPUs, 24GB RAM | Hydra builder and nix binarycache | + |📱 **magicant** | Samsung Galaxy Z Flip 6 | Phone | + |💿 **drugstore** | - | NixOS-installer ISO for bootstrapping new hosts | + |💿 **brickroad** | - | Kexec tarball for bootstrapping low-memory machines | + |❔ **chaotheatre** | - | Demo config for checking out this configuration | + |❔ **toto** | - | Helper configuration for testing purposes | #+end_src + +** Programs +:PROPERTIES: +:CUSTOM_ID: h:3bb92528-c61c-4b8d-8214-bf2a40baaa32 +:END: + +#+begin_src markdown :tangle no :noweb-ref programs + | Topic | Program | + |---------------|---------------------------------| + |🐚 **Shell** | [zsh](https://github.com/Swarsel/.dotfiles/tree/main/modules/home/common/zsh.nix) | + |🚪 **DM** | [greetd](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/common/login.nix) | + |🪟 **WM** | [SwayFX](https://github.com/Swarsel/.dotfiles/tree/main/modules/home/common/sway.nix) | + |⛩️ **Bar** | [Waybar](https://github.com/Swarsel/.dotfiles/tree/main/modules/home/common/waybar.nix) | + |✒️ **Editor** | [Emacs](https://github.com/Swarsel/.dotfiles/tree/main/files/emacs/init.el) | + |🖥️ **Terminal**| [Kitty](https://github.com/Swarsel/.dotfiles/tree/main/modules/home/common/kitty.nix) | + |🚀 **Launcher**| [Fuzzel](https://github.com/Swarsel/.dotfiles/tree/main/modules/home/common/fuzzel.nix) | + |🚨 **Alerts** | [Mako](https://github.com/Swarsel/.dotfiles/tree/main/modules/home/common/mako.nix) | + |🌐 **Browser** | [Firefox](https://github.com/Swarsel/.dotfiles/tree/main/modules/home/common/zsh.nix) | + |🎨 **Theme** | [City-Lights (managed by stylix)](https://github.com/Swarsel/.dotfiles/tree/main/modules/home/common/sharedsetup.nix)| +#+end_src + +** Services +:PROPERTIES: +:CUSTOM_ID: h:191e82b6-6ae5-4ec8-ae6d-dc683ce325d9 +:END: + +#+begin_src markdown :tangle no :noweb-ref services + | Topic | Program | + |-----------------------|---------------------------------------------------------------------------------------------------------------------| + |📖 **Books** | [Kavita](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/kavita.nix) | + |📼 **Videos** | [Jellyfin](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/jellyfin.nix) | + |🎵 **Music** | [Navidrome](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/navidrome.nix) + [Spotifyd](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/spotifyd.nix) + [MPD](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/mpd.nix) | + |🗨️ **Messaging** | [Matrix](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/matrix.nix) | + |📁 **Filesharing** | [Nectcloud](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/nextcloud.nix) | + |🎞️ **Photos** | [Immich](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/immich.nix) | + |📄 **Documents** | [Paperless](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/paperless.nix) | + |🔄 **File Sync** | [Syncthing](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/syncthing.nix) | + |💾 **Backups** | [Restic](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/restic.nix) | + |👁️ **Monitoring** | [Grafana](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/monitoring.nix) | + |🍴 **RSS** | [FreshRss](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/freshrss.nix) | + |🌳 **Git** | [Forgejo](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/forgejo.nix) | + |⚓ **Anki Sync** | [Anki Sync Server](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/ankisync.nix) | + |🪪 **SSO** | [Kanidm](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/kanidm.nix) + [oauth2-proxy](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/oauth2-proxy.nix) | + |💸 **Finance** | [Firefly-III](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/firefly-iii.nix) | + |🃏 **Collections** | [Koillection](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/koillection.nix) | + |🗃️ **Shell History** | [Atuin](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/atuin.nix) | + |📅 **CalDav/CardDav** | [Radicale](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/radicale.nix) | + |↔️ **P2P Filesharing** | [Croc](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/croc.nix) | + |✂️ **Paste Tool** | [Microbin](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/microbin.nix) | + |📸 **Image Sharing** | [Slink](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/slink.nix) | + |🔗 **Link Shortener** | [Shlink](https://github.com/Swarsel/.dotfiles/tree/main/modules/nixos/server/shlink.nix) | +#+end_src + +** Manual steps when setting up a new machine +:PROPERTIES: +:CUSTOM_ID: h:ed34ee4d-31f9-4d27-bc6e-ba37ee502d5a +:END: + +#+begin_src markdown :noweb yes :exports both :results html + These steps are required when setting up a normal NixOS host: + + <> + + If the new machine is a work machine, these steps are additionally needed: + + <> + + If the new machine is home-manager only, perform these steps: + + <> +#+end_src + +#+RESULTS: +#+begin_export html +These steps are required when setting up a normal NixOS host: + +- setup yubikey (automatic yubikey enrollment is not yet supported by `disko`): + - `systemd-cryptenroll --fido2-device=auto /dev/` + +If the new machine is a work machine, these steps are additionally needed: + +- setup the work VPN: + - using the laptop certificate `.pem` as User cert and private key (CA cert: none) + - vpn gateway is found in `nixosConfig.repo.secrets.local.work.vpnGateway` +- setup gpgsm for signing of mails using S/MIME: + - `gpgsm --import ~/Certificates/.p12` + - `gpgsm --import ~/Certificates/harica-root.pem` + - `gpgsm --import ~/Certificates/harica-intermediate.pem` + - `gpgsm --list-keys --with-validation "HARICA Client RSA Root CA 2021"` + - trust the certificate and set passphrase +- setup pizauth for microsoft mail sync (account names are possibly `uni` and `work`): + - `pizauth auth ` + - `pizauth dump > ~/.pizauth.state` + +If the new machine is home-manager only, perform these steps: + +- (Optional) Install openssh-server +- Set hostname to the name specified in the home-manager configuration +- Install nix, either: + - (if upgrading existing nix) Install nix version matching with version that `nix-plugins` is compiled against: `nix-env --install --file '' cacert -I nixpkgs=channel:nixpkgs-unstable --attr nixVersions.nix_x_yy` + - (or installing nix freshly): + - Grab the link to the install script of the needed nix version from https://releases.nixos.org/?prefix=nix, e.g. https://releases.nixos.org/nix/nix-2.30.1/install + - `bash <(curl -L https://releases.nixos.org/nix/nix-x-yy-y/install) --daemon` +- add the following to /etc/nix/nix.conf to become a trusted user: `trusted-users = @wheel root swarsel` +- For the first build: + 1) Clone dotfile repo & change into it + 2) `nix --extra-experimental-features 'nix-command flakes' develop` + 3) `home-manager --extra-experimental-features 'nix-command flakes' switch --flake .#$(hostname) --show-trace` +#+end_export + +** Current issues +:PROPERTIES: +:CUSTOM_ID: h:b562adaf-536c-4267-88a5-026d8a0cda61 +:END: + +#+begin_src markdown :noweb yes :exports both :results html + Currently, these adaptions are made to the configuration to account for bugs in upstream repos: + + <> +#+end_src + +#+RESULTS: +#+begin_export html +Currently, these adaptions are made to the configuration to account for bugs in upstream repos: + +- 202501102: + - flake: + - emacs-overlay: + - : version pinned because emacsclient is currently broken on latest + - niri-flake: + - currently not using the sugared version of screenshot-[,window], as it is currently broken + - home-manager: + - emacs-tramp: + - using stable version in extraPackages (broken in unstable) + - :ensure nil in emacs tramp settings to use package in extraPackages + - emacs-calfwL + - pinned to version not in nixpkgs (is in latest emacs-overlay, but that is broken) + - vesktop: + - running stable version (broken in unstable) + - batgrep: + - running stable version (broken in unstable) + - swayosd: + - pinned to version not in nixpkgs (fixes https://github.com/ErikReider/SwayOSD/issues/175) +#+end_export + * flake.nix :PROPERTIES: :CUSTOM_ID: h:c7588c0d-2528-485d-b2df-04d6336428d7 :END: -Handling the flake.nix file used to be a bit of a chore, since it felt like writing so much boilerplate code just to define new systems. The noweb-approach here makes this a little bit less painful. +Handling the flake.nix file used to be a bit of a chore, since it felt like writing so much boilerplate code just to define new systems. For a while, I used noweb-ref in order to alleviate this problem (see [[#h:dae0c5bb-edb7-4fe4-ae31-9f8f064cc53c][Appendix A: Noweb-Ref blocks]], an example of the repository at that time would be =acc0ad6: Add several NixOS hosts on Proxmox and Oracle Cloud=.). However, the true answer laid in making use of builtin nix functionality. -These blocks are later inserted here: [[#h:aee5ec75-7ca6-40d8-b6ac-a3e7e33a474b][flake.nix template]]. Adding new flake inputs is very easy, you just add them to [[#h:8a411ee2-a58e-4b5b-99bd-4ba772f8f0a2][Inputs & Inputs@Outputs]] first by name in the first source-block, and then the path in the second source-block. Any variables to be set for the host configuration are done in [[#h:df0072bc-853f-438f-bd85-bfc869501015][let]], and the specific setup is done in either [[#h:9c9b9e3b-8771-44fa-ba9e-5056ae809655][nixosConfigurations]] (for NixOS systems), [[#h:f881aa05-a670-48dd-a57b-2916abdcb692][homeConfigurations]] (for home-manager systems), or [[#h:5f6ef553-59f9-4239-b6f3-63d33b57f335][nixOnDroidConfigurations]] (for Nix on Android) and [[#h:f881aa05-a670-48dd-a57b-2916abdcb692][darwinConfigurations]] (for Darwin systems, also known as Macs). There also used to be a [[#h:6a08495a-8566-4bb5-9fac-b03df01f6c81][nixos-generators]] section that used to define a Proxmox LXC image when I was still using Proxmox as my main server. An example of the repository at that time would be =acc0ad6 main Add several NixOS hosts on Proxmox and Oracle Cloud=. +Nowadays, I use flake-parts to manage my flake. It allows me to conveniently split the actual flake into multiple files ("parts") using the following mechanism: +- =imports= are files pulled in to build the flake configuration (similar to the imports in the module system) +- =systems= defines the architectures that the flake should be provided for - I go here for the four "main" architectures, although true support is only provided for linux systems (see [[#h:6ed1a641-dba8-4e85-a62e-be93264df57a][Packages (pkgs)]] for the main reason) - -** flake.nix template +** flake.nix skeleton :PROPERTIES: :CUSTOM_ID: h:aee5ec75-7ca6-40d8-b6ac-a3e7e33a474b :END: -This sections puts together the =flake.nix= file from the [[#h:d39b8dfb-536d-414f-9fc0-7d67df48cee4][Noweb-Ref blocks]] section. This tangles the flake.nix file; This block only needs to be touched when updating the general structure of the flake. For everything else, see the respective noweb-ref block. +In general, a nix flake consists of one or more inputs and several outputs. The inputs are used to define where nix should be looking for packages, modules, and more. The outputs generate expressions that can be used in .nix files as well as system configurations using these files. -In general, a nix flake consists of one or more inputs and several outputs. The inputs are used to define where nix should be looking for packages, options, and more. The outputs generate expressions that can be used in .nix files as well as system configurations using these files. +In the start, I enable some public cache repositories. This saves some time during rebuilds because it avoids building as many packages from scratch - this is mainly important for community flakes like =emacs-overlay=, which basically would trigger a rebuild whenever updating the flake. The repository does of course not hold everything, but it lightens the pain. It would look cleaner if this were to be used only inside a nix configuration block of an actual system, but I want these caches to be used for e.g. app calls as well. -In the start, I enable some public cache repositories. This saves some time during rebuilds because it avoids building as many packages from scratch - this is mainly important for community flakes like =emacs-overlay=, which basically would trigger a rebuild whenever updating the flake. The repository does of course not hold everything, but it lightens the pain. +In many flakes, you see a structure like this: =outputs = inputs@ [...]=, the =inputs@= makes it so that all inputs are automatically passed to the outputs and can be called as =inputs.=, whereas explicit arguments may just be called by using ==. For most flakes this is fully sufficient, as they do not need to be called often and it saves me maintainance effort with this file. In fact, I also used to make use of this mechanism. However, using flake-parts, all I really need for the outputs function is inputs, which is why my outputs = inputs: inputs.flake-parts.lib.mkFlake { inherit inputs; } { [...] ). Note that flake-parts must inherit these inputs and no other arguments are expected. -In =outputs = inputs@ [...]=, the =inputs@= makes it so that all inputs are automatically passed to the outputs and can be called as =inputs.=, whereas explicit arguments may just be called by using ==. For most flakes this is fully sufficient, as they do not need to be called often and it saves me maintainance effort with this file. +In this section I am creating some attributes that define general concepts of my configuration: -#+begin_src nix :noweb yes :tangle flake.nix - - { - description = "SwarseFlake - Nix Flake for all SwarselSystems"; - - nixConfig = { - extra-substituters = [ - "https://nix-community.cachix.org" - "https://cache.ngi0.nixos.org/" - ]; - - extra-trusted-public-keys = [ - "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" - "cache.ngi0.nixos.org-1:KqH5CBLNSyX184S9BKZJo1LxrxJ9ltnY2uAs5c/f1MA=" - ]; - }; - - inputs = { - <> - }; - - outputs = - inputs@{ self - , nixpkgs - , home-manager - , nix-darwin - , systems - , ... - }: - let - <> - in - { - <> - - nixosConfigurations = - <> - - homeConfigurations = { - <> - }; - - darwinConfigurations = - <> - - nixOnDroidConfigurations = { - <> - }; - - }; - } - - - -#+end_src -** Pre-commit-hooks (Checks) -:PROPERTIES: -:CUSTOM_ID: h:cbd5002c-e0fa-434a-951b-e05b179e4e3f -:END: - -This file defines a number of checks that can either be run by calling =nix flake check= or while in a =nix-shell= or =nix develop=. This helps me make sure that my flake confirms to my self-imposed standards. The GitHub actions perform less checks than are being done here (they are only checking the formatting, as well as =statix= and =deadnix=) - -#+begin_src nix :tangle checks/default.nix - { self, inputs, pkgs, system, ... }: - { - pre-commit-check = inputs.pre-commit-hooks.lib.${system}.run { - src = "${self}"; - hooks = { - check-added-large-files.enable = true; - check-case-conflicts.enable = true; - check-executables-have-shebangs.enable = true; - check-shebang-scripts-are-executable.enable = false; - check-merge-conflicts.enable = true; - deadnix.enable = true; - detect-private-keys.enable = true; - end-of-file-fixer.enable = true; - fix-byte-order-marker.enable = true; - flake-checker.enable = true; - forbid-new-submodules.enable = true; - mixed-line-endings.enable = true; - nixpkgs-fmt.enable = true; - statix.enable = true; - trim-trailing-whitespace.enable = true; - - destroyed-symlinks = { - enable = true; - entry = "${inputs.pre-commit-hooks.checks.${system}.pre-commit-hooks}/bin/destroyed-symlinks"; - }; - - shellcheck = { - enable = true; - entry = "${pkgs.shellcheck}/bin/shellcheck --shell=bash"; - }; - - shfmt = { - enable = true; - entry = "${pkgs.shfmt}/bin/shfmt -i 4 -sr -d -s -l"; - }; - - }; - }; - } -#+end_src - -** Inputs -:PROPERTIES: -:CUSTOM_ID: h:8a411ee2-a58e-4b5b-99bd-4ba772f8f0a2 -:END: +- =nixosModules= imports self-defined options that I only want to use on NixOS systems. All modules are held as separately as possible, to allow for easier sharing with other people mostly. +- =homeModules= imports modules that are to be used on NixOS and non-NixOS systems. These are mostly used to define outputs (monitors), keyboards and special commands for machines. +- =packages= holds packages that I am building myself. These are mostly shell scripts, but also a few others such as AppImages and firefox addons. +- =devShells= provides a development shell that can be used as a bootstrap for new installs using =nix develop= while inside the flake directory. It received an overhaul in =0a6cf0e feat: add checks to devShell=, since when it is handled using =forAllSystems= and now including pre-commit-hook checks. +- =formatter= provides the formatter that is to be used on =.nix= files. It can be called by using =nix fmt=. +- =check= provides the pre-commit-hook checks that I have explained in [[#h:cbd5002c-e0fa-434a-951b-e05b179e4e3f][Pre-commit-hooks (Checks)]]. +- =overlays= imports a few community overlays (such as the emacs-overlay) and also three overlays of my own: + 1) =additions= holds derivations that I am adding myself to nixpkgs - i.e. this is where the packages defined in =/pkgs= get added to nixpkgs. + 2) =modifications= holds derivations that I have performed overrides on. The list of interesting attribute overrides can be found by looking at the source code of a derivation and looking at the start of the file for lines of the form = ? =. But this can also be used to, for example, fetch a different version of a package instead. + 3) =nixpkgs-stable= holds the newest version of stable nixpkgs. I only use this on packages that seem broken on unstable, which are not many. + 4) =zjstatus= holds some options for =zellij=, but I have stopped using it since I prefer =tmux=. + They are defined in [[#h:5e3e21e0-57af-4dad-b32f-6400af9b7aab][Overlays (additions, overrides, nixpkgs-stable)]]. The way this is handled was simplified in =647a2ae feat: simplify overlay structure=; however, the old structure might be easier to understand as a reference. Here we define inputs and outputs of the flake. First, the following list is for the outputs of the flake. @@ -798,6 +446,8 @@ A short overview over each input and what it does: This is the base repository that I am following for all packages. I follow the unstable branch. - [[https://github.com/nix-community/home-manager][home-manager]] This handles user-level configuration and mostly provides dotfiles that are generated and symlinked to =~/.config/=. +- [[https://github.com/Swarsel/.dotfiles][swarsel]] + This pulls in the very dotfiles you are currently reading. I am adding this to the flake registry in order to have easier access to my customizations in nix calls, for example =nix-instantiate= - [[https://github.com/nix-community/NUR][NUR]] The nix user repository contains user provided modules, packages and expressions. These are not audited by the nix community, so be aware of supply chain vulnerabilities when using those. I am only really using rycee's firefox addons from there which saves me a lot of hassle, and it seems to be a safe resource. - [[https://github.com/nix-community/nixGL][nixGL]] @@ -812,8 +462,6 @@ A short overview over each input and what it does: This brings nix to android in an app that is similar to tmux! Of course most of the configuration does not apply to this, but it is still neat to have! - [[https://github.com/NixOS/nixos-hardware][nixos-hardware]] Provides specific hardware setting for some hardware configurations. For example, this sets some better defaults for my Lenovo Thinkpad P14s Gen2. -- [[https://github.com/thiagokokada/nix-alien][nix-alien]] - This is supposed to allow me to run unpatched libraries directly without a need for ELF patching or resorting to =steam-run=. However, I have not yet gotten this to work. - [[https://github.com/nix-community/nixos-generators][nixos-generators]] Provides me with images that I can use to create LXCs on Proxmox. - [[https://github.com/Swarsel/nswitch-rcm-nix][nswitch-rcm-nix]] @@ -832,342 +480,1437 @@ A short overview over each input and what it does: After learning that MacOS systems can also be configured using nix, I managed to get access to an old MacBook for testing. This allows to set most general settings that can otherwise be set using the Mac GUI. - [[https://github.com/cachix/git-hooks.nix][pre-commit-hooks]] Provides access to several checks that can be hooked to be run before several stages in the process. -- nix-secrets - This is a private repository that I use for settings in modules that do not expose a =secretsFile= (or similar) option. An example is the =LastFM.ApiKey= option in [[#h:f347f3ad-5100-4c4f-8616-cfd7f8e14a72][navidrome]]: - =LastFM.ApiKey = builtins.readFile "${secretsDirectory}/navidrome/lastfm-secret";= -When setting this option normally, the password would normally be written world-readable not only in the nix store, but also in the configuration. Hence, I put such passwords into a private repository. This allows me to keep purity of the flake while keeping a level of security on these secrets. +- [[https://github.com/oddlama/nix-topology][nix-topology]] + This automatically creates a topology diagram of my configuration. +- flake-parts + The aforementioned system that allows for more convenient flake crafting. +- devshell + This provides devshell support for flake-parts -#+begin_src nix :tangle no :noweb-ref flakeinputs +#+begin_src nix :noweb yes :tangle flake.nix + { + description = "SwarseFlake - Nix Flake for all SwarselSystems"; - nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; + nixConfig = { + extra-substituters = [ + "https://nix-community.cachix.org" + ]; + extra-trusted-public-keys = [ + "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" + ]; + }; + inputs = { + nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; + smallpkgs.url = "github:nixos/nixpkgs/08fcb0dcb59df0344652b38ea6326a2d8271baff?narHash=sha256-HXIQzULIG/MEUW2Q/Ss47oE3QrjxvpUX7gUl4Xp6lnc%3D&shallow=1"; + nixpkgs-dev.url = "github:Swarsel/nixpkgs/main"; + nixpkgs-kernel.url = "github:NixOS/nixpkgs/063f43f2dbdef86376cc29ad646c45c46e93234c?narHash=sha256-6m1Y3/4pVw1RWTsrkAK2VMYSzG4MMIj7sqUy7o8th1o%3D"; #specifically pinned for kernel version + nixpkgs-stable.url = "github:NixOS/nixpkgs/nixos-25.05"; + nixpkgs-stable24_05.url = "github:NixOS/nixpkgs/nixos-24.05"; + nixpkgs-stable24_11.url = "github:NixOS/nixpkgs/nixos-24.11"; + nixpkgs-stable25_05.url = "github:NixOS/nixpkgs/nixos-25.05"; - nixpkgs-stable.url = "github:NixOS/nixpkgs/nixos-24.05"; - - systems.url = "github:nix-systems/default-linux"; - - # user-level configuration - home-manager = { - url = "github:nix-community/home-manager"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - - # overlay to access bleeding edge emacs - emacs-overlay = { - url = "github:nix-community/emacs-overlay"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - - # nix user repository - # i use this mainly to not have to build all firefox extensions - # myself as well as for the emacs-init package (tbd) - nur.url = "github:nix-community/NUR"; - - # provides GL to non-NixOS hosts - nixgl.url = "github:guibou/nixGL"; - - # manages all theming using Home-Manager - stylix.url = "github:danth/stylix"; - - # nix secrets management - sops-nix.url = "github:Mic92/sops-nix"; - - # enable secure boot on NixOS - lanzaboote.url = "github:nix-community/lanzaboote"; - - # nix for android - nix-on-droid = { - url = "github:nix-community/nix-on-droid/release-24.05"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - - # generate NixOS images - nixos-generators = { - url = "github:nix-community/nixos-generators"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - - # hardware quirks on nix - nixos-hardware = { - url = "github:NixOS/nixos-hardware/master"; - }; - - # dynamic library loading - nix-alien = { - url = "github:thiagokokada/nix-alien"; - }; - - # automatic nintendo switch payload injection - nswitch-rcm-nix = { - url = "github:Swarsel/nswitch-rcm-nix"; - }; - - # weekly updated nix-index database - nix-index-database = { - url = "github:nix-community/nix-index-database"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - - disko = { - url = "github:nix-community/disko"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - - impermanence.url = "github:nix-community/impermanence"; - - zjstatus = { - url = "github:dj95/zjstatus"; - }; - - fw-fanctrl = { - url = "github:TamtamHero/fw-fanctrl/packaging/nix"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - - nix-darwin = { - url = "github:lnl7/nix-darwin"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - - pre-commit-hooks = { - url = "github:cachix/git-hooks.nix"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - - nix-secrets = { - url = "git+ssh://git@github.com/Swarsel/nix-secrets.git?ref=main&shallow=1"; - flake = false; - inputs = { }; - }; - -#+end_src -** let -:PROPERTIES: -:CUSTOM_ID: h:df0072bc-853f-438f-bd85-bfc869501015 -:END: - -Here I define a few variables that I need for my system specifications. First and foremost, =pkgs=, which gets passed the emacs-overlay, nur, and nixgl modules to it. With this, I can grab all these packages by referencing =pkgs.= instead of having to put e.g. =nixgl.auto.nixGLDefault=. - -I also define some common module lists that I can simply load depending on the fundamental system (NixOS vs. non-NixOS) - =nixModules=, =homeModules=, and =mixedModules=. - -The interesting part is in the start: -- first, I define =pkgsFor=. This function reads all available systems from nixpkgs and generates pkgs for them. -- next, =forEachSystem= is a function that can be called to declare an output for each such defined system. -- =forAllSystems= is a crude function that I use for expressions that depend on =system=, as the prior two attributes already consumed it at that stage. This is only really used to generate the checks in their own file. -- =mkFullHost= is a function that takes a hostname as well as a boolean whether it is NixOS or not, and returns a matching =nixosSystem= or =darwinSystem=. This function is only used for systems that can use both NixOS and home-manager options (darwin still counts here as it can use some NixOS options). -- =mkFullHostConfigs= is the function that dynamically creates all definded hosts. The hosts are defined by placing a directory in =hosts/= under either the =nixos/= or =darwin/= directory. These directories are being read by =readHosts= and delivered to this funtion in the later call in [[#h:9c9b9e3b-8771-44fa-ba9e-5056ae809655][nixosConfigurations]] or [[#h:f881aa05-a670-48dd-a57b-2916abdcb692][darwinConfigurations]]. - -#+begin_src nix :tangle no :noweb-ref flakelet - - inherit (self) outputs; - lib = nixpkgs.lib // home-manager.lib; - - pkgsFor = lib.genAttrs (import systems) ( - system: - import nixpkgs { - inherit system; - config.allowUnfree = true; - } - ); - forEachSystem = f: lib.genAttrs (import systems) (system: f pkgsFor.${system}); - forAllSystems = lib.genAttrs [ - "x86_64-linux" - "aarch64-linux" - "x86_64-darwin" - "aarch64-darwin" - ]; - mkFullHost = host: isNixos: { - ${host} = - let - func = if isNixos then lib.nixosSystem else inputs.nix-darwin.lib.darwinSystem; - systemFunc = func; - in - systemFunc { - specialArgs = { inherit inputs outputs self; }; - modules = [ ./hosts/${if isNixos then "nixos" else "darwin"}/${host} ]; + home-manager = { + # url = "github:nix-community/home-manager"; + url = "github:Swarsel/home-manager/main"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + nix-index-database = { + url = "github:nix-community/nix-index-database"; + inputs.nixpkgs.follows = "nixpkgs"; }; - }; - mkFullHostConfigs = hosts: isNixos: lib.foldl (acc: set: acc // set) { } (lib.map (host: mkFullHost host isNixos) hosts); - readHosts = folder: lib.attrNames (builtins.readDir ./hosts/${folder}); - # NixOS modules that can only be used on NixOS systems - nixModules = [ - inputs.stylix.nixosModules.stylix - inputs.lanzaboote.nixosModules.lanzaboote - inputs.disko.nixosModules.disko - # inputs.impermanence.nixosModules.impermanence - inputs.sops-nix.nixosModules.sops - inputs.nswitch-rcm-nix.nixosModules.nswitch-rcm - ./profiles/common/nixos - ]; - - # Home-Manager modules wanted on non-NixOS systems - homeModules = [ - inputs.stylix.homeManagerModules.stylix - ]; - - # Home-Manager modules wanted on both NixOS and non-NixOS systems - mixedModules = [ - inputs.sops-nix.homeManagerModules.sops - inputs.nix-index-database.hmModules.nix-index - ./profiles/common/home - ]; - - # For adding things to _module.args (making arguments available globally) - # moduleArgs = [ - # { - # _module.args = { inherit self; }; - # } - # ]; + # emacs-overlay.url = "github:nix-community/emacs-overlay"; + emacs-overlay.url = "github:nix-community/emacs-overlay/aba8daa237dc07a3bb28a61c252a718e8eb38057?narHash=sha256-4OXXccXsY1sBXTXjYIthdjXLAotozSh4F8StGRuLyMQ%3D"; + swarsel-nix.url = "github:Swarsel/swarsel-nix/main"; + systems.url = "github:nix-systems/default"; + nur.url = "github:nix-community/NUR"; + nixgl.url = "github:guibou/nixGL"; + stylix.url = "github:danth/stylix"; + sops-nix.url = "github:Mic92/sops-nix"; + lanzaboote.url = "github:nix-community/lanzaboote"; + nix-on-droid.url = "github:nix-community/nix-on-droid/release-24.05"; + nixos-generators.url = "github:nix-community/nixos-generators"; + nixos-images.url = "github:Swarsel/nixos-images/main"; + nixos-hardware.url = "github:NixOS/nixos-hardware/master"; + nswitch-rcm-nix.url = "github:Swarsel/nswitch-rcm-nix"; + disko.url = "github:nix-community/disko"; + impermanence.url = "github:nix-community/impermanence"; + zjstatus.url = "github:dj95/zjstatus"; + nix-darwin.url = "github:lnl7/nix-darwin"; + pre-commit-hooks.url = "github:cachix/git-hooks.nix"; + vbc-nix.url = "git+ssh://git@github.com/vbc-it/vbc-nix.git?ref=main"; + nix-topology.url = "github:oddlama/nix-topology"; + flake-parts.url = "github:hercules-ci/flake-parts"; + devshell.url = "github:numtide/devshell"; + spicetify-nix.url = "github:Gerg-l/spicetify-nix"; + niri-flake.url = "github:sodiboo/niri-flake"; + nixos-extra-modules.url = "github:oddlama/nixos-extra-modules/main"; + microvm.url = "github:astro/microvm.nix"; + treefmt-nix.url = "github:numtide/treefmt-nix"; + dns.url = "github:kirelagin/dns.nix"; + nix-minecraft.url = "github:Infinidoge/nix-minecraft"; + simple-nixos-mailserver.url = "gitlab:simple-nixos-mailserver/nixos-mailserver/master"; + }; + outputs = + inputs: + inputs.flake-parts.lib.mkFlake { inherit inputs; } { + imports = [ + ./nix/globals.nix + ./nix/hosts.nix + ./nix/topology.nix + ./nix/devshell.nix + ./nix/apps.nix + ./nix/packages.nix + ./nix/overlays.nix + ./nix/lib.nix + ./nix/templates.nix + ./nix/formatter.nix + ./nix/modules.nix + ./nix/iso.nix + ]; + systems = [ + "x86_64-linux" + "aarch64-linux" + "x86_64-darwin" + "aarch64-darwin" + ]; + }; + } #+end_src -** General (outputs) +** Auxiliary files :PROPERTIES: -:CUSTOM_ID: h:54cd8f65-a3ba-43c3-ae37-5f04383fe720 +:CUSTOM_ID: h:23602ad9-91f6-4eba-943a-2308070fbaec :END: -In this section I am creating some attributes that define general concepts of my configuration: +Here I define some extra files that are crucial for success in building my configurations. These are not pulled in by the flake directly, but I still feel like they should be mentioned at the flake level. -- =nixosModules= imports self-defined options that I only want to use on NixOS systems. All modules are held as separately as possible, to allow for easier sharing with other people mostly. -- =homeManagerModules= imports modules that are to be used on NixOS and non-NixOS systems. These are mostly used to define outputs (monitors), keyboards and special commands for machines. -- =packages= holds packages that I am building myself. These are mostly shell scripts, but also a few others such as AppImages and firefox addons. -- =devShells= provides a development shell that can be used as a bootstrap for new installs using =nix develop= while inside the flake directory. It received an overhaul in =0a6cf0e feat: add checks to devShell=, since when it is handled using =forAllSystems= and now including pre-commit-hook checks. -- =formatter= provides the formatter that is to be used on =.nix= files. It can be called by using =nix fmt=. -- =check= provides the pre-commit-hook checks that I have explained in [[#h:cbd5002c-e0fa-434a-951b-e05b179e4e3f][Pre-commit-hooks (Checks)]]. -- =overlays= imports a few community overlays (such as the emacs-overlay) and also three overlays of my own: - 1) =additions= holds derivations that I am adding myself to nixpkgs - i.e. this is where the packages defined in =/pkgs= get added to nixpkgs. - 2) =modifications= holds derivations that I have performed overrides on. The list of interesting attribute overrides can be found by looking at the source code of a derivation and looking at the start of the file for lines of the form = ? =. But this can also be used to, for example, fetch a different version of a package instead. - 3) =nixpkgs-stable= holds the newest version of stable nixpkgs. I only use this on packages that seem broken on unstable, which are not many. - 4) =zjstatus= holds some options for =zellij=, but I have stopped using it since I prefer =tmux=. - They are defined in [[#h:5e3e21e0-57af-4dad-b32f-6400af9b7aab][Overlays (additions, overrides, nixpkgs-stable)]]. The way this is handled was simplified in =647a2ae feat: simplify overlay structure=; however, the old structure might be easier to understand as a reference. +*** extra-builtins +:PROPERTIES: +:CUSTOM_ID: h:87c7893e-e946-4fc0-8973-1ca27d15cf0e +:END: -#+begin_src nix :tangle no :noweb-ref flakeoutputgeneral +This file is used by [[https://github.com/shlevy/nix-plugins][nix-plugins]]. nix-plugins generally allows for the introduction of arbitrary functions into the =builtins= set. However, I do not want to allow just any function to be added there. Instead, I only add a single function called =sopsImportEncrypted=. This function is used in order to help me store PII (personally identifiable information) in my repo without having to resort to either: - inherit lib; - inherit mixedModules; - inherit nixModules; +- [[https://github.com/AGWA/git-crypt][git-crypt]] +- a separate repo containing my secrets - nixosModules = import ./modules/nixos; - homeManagerModules = import ./modules/home; + As for the second approach, I actually used this up to some point (see for example =7e11641: feat: add initial oauth2-proxy and freshrss oidc= as one of the lasts commits still using this system). However, it is quite bothersome to constantly have to keep two repositories up to date and in sync. Also, having a repo that every configuration relied upon that was also a private repo led to the problem that my demo configuration ([[#h:e1498bef-ec67-483d-bf02-76264e30be8e][Hotel (Demo Physical/VM)]]) would fail to build with that present, and I had to take several extra steps to make it buildable. Ever since deleting that dependency I also got rid of that problem. The whole system is inspired by [[https://oddlama.org/blog/evaluation-time-secrets-in-nix/][this blog article]] and large parts of it are adapted from [[https://github.com/oddlama/nix-config][oddlama's nix-config]]. - packages = forEachSystem (pkgs: import ./pkgs { inherit pkgs; }); - apps = forAllSystems (system: { - default = self.apps.${system}.bootstrap; +The builtin that is added is a simple call to the =exec= function that calls a bash script. In order to keep some sanity, we are checking that we are actually calling it no an encryted nix file (even though there is no syntax check inside) and that the path given is a true nix path. Note that a string path will not be accepted, as that can have impurity implications. - bootstrap = { - type = "app"; - program = "${self.packages.${system}.bootstrap}/bin/bootstrap"; - }; +#+begin_src nix-ts :tangle nix/extra-builtins.nix + # adapted from https://github.com/oddlama/nix-config/blob/main/nix/extra-builtins.nix + { exec, ... }: + let + assertMsg = pred: msg: pred || builtins.throw msg; + hasSuffix = + suffix: content: + let + lenContent = builtins.stringLength content; + lenSuffix = builtins.stringLength suffix; + in + lenContent >= lenSuffix && builtins.substring (lenContent - lenSuffix) lenContent content == suffix; + in + { + # Instead of calling sops directly here, we call a wrapper script that will cache the output + # in a predictable path in /tmp, which allows us to only require the password for each encrypted + # file once. + sopsImportEncrypted = + nixFile: + assert assertMsg (builtins.isPath nixFile) + "The file to decrypt must be given as a path (not a string) to prevent impurity."; + assert assertMsg (hasSuffix ".nix.enc" nixFile) + "The content of the decrypted file must be a nix expression and should therefore end in .nix.enc"; + exec [ + ./sops-decrypt-and-cache.sh + nixFile + ]; + } - install = { - type = "app"; - program = "${self.packages.${system}.swarsel-install}/bin/swarsel-install"; - }; +#+end_src +*** sops-decrypt-and-cache +:PROPERTIES: +:CUSTOM_ID: h:315e6ef6-27d5-4cd8-85ff-053eabe60ddb +:END: - rebuild = { - type = "app"; - program = "${self.packages.${system}.swarsel-rebuild}/bin/swarsel-rebuild"; - }; - }); - devShells = forAllSystems ( - system: - let - pkgs = nixpkgs.legacyPackages.${system}; - checks = self.checks.${system}; - in - { - default = pkgs.mkShell { - NIX_CONFIG = "experimental-features = nix-command flakes"; - inherit (checks.pre-commit-check) shellHook; - buildInputs = checks.pre-commit-check.enabledPackages; - nativeBuildInputs = [ - pkgs.nix - pkgs.home-manager - pkgs.git - pkgs.just - pkgs.age - pkgs.ssh-to-age - pkgs.sops - ]; +This is the file that manages the actual decryption of the files mentioned in [[#h:87c7893e-e946-4fc0-8973-1ca27d15cf0e][extra-builtins]]. We simply fetch the appropriate system age key from the ssh host key and then call =sops decrypt=. Since it would be a bother to decrypt these files on every build, I keep the result cached and only re-decrypt if it changes. Keeping it cached outside the nix store incurrs a theoretical bit of impurity. However, this is easier to manage and also nothing really relies on these files being present. + +#+begin_src shell :tangle nix/sops-decrypt-and-cache.sh :shebang #!/usr/bin/env bash + # adapted from https://github.com/oddlama/nix-config/blob/main/nix/rage-decrypt-and-cache.sh + set -euo pipefail + + print_out_path=false + if [[ $1 == "--print-out-path" ]]; then + print_out_path=true + shift + fi + + file="$1" + shift + + basename="${file%".enc"}" + # store path prefix or ./ if applicable + [[ $file == "/nix/store/"* ]] && basename="${basename#*"-"}" + [[ $file == "./"* ]] && basename="${basename#"./"}" + + # Calculate a unique content-based identifier (relocations of + # the source file in the nix store should not affect caching) + new_name="$(sha512sum "$file")" + new_name="${new_name:0:32}-${basename//"/"/"%"}" + + # Derive the path where the decrypted file will be stored + out="/var/tmp/nix-import-encrypted/$UID/$new_name" + umask 077 + mkdir -p "$(dirname "$out")" + + # Decrypt only if necessary + if [[ ! -e $out ]]; then + agekey=$(sudo ssh-to-age -private-key -i /etc/ssh/sops || sudo ssh-to-age -private-key -i /etc/ssh/ssh_host_ed25519_key) + SOPS_AGE_KEY="$agekey" sops decrypt --output "$out" "$file" + fi + + # Print out path or decrypted content + if [[ $print_out_path == true ]]; then + echo "$out" + else + cat "$out" + fi +#+end_src +** Library functions +:PROPERTIES: +:CUSTOM_ID: h:f9b7ffba-b7e2-4554-9a35-ece0bf173e1c +:END: + +This section defines all functions of my own that I add to =lib=. These are used in all places over the config, however mainly in the files responsible for handling various imports. + +A breakdown for the functions that have a non-obvious purpose: + +- =pkgsFor=: This function reads all available systems from nixpkgs and generates pkgs for them. This is needed for my generation of home-manager and nix-on-droid systems in [[#h:5c5bf78a-9a66-436f-bd85-85871d9d402b][Hosts]]. + - uses [[#h:94690fcb-e039-49da-9bd3-610fa80fa08b][nixpkgs.lib.genAttrs]] + - Also, in that function I am defining the =pkgs= that should be used when I reference =pkgs= in the actual configuration. I want to make sure that the correct system is used (keep in mind this is for home-manager configurations, which need that info! As a remark, you would not set this for a NixOS host), that I load my [[#h:7a059bd9-13f8-4005-b270-b41eeb6a4af2][Overlays]] (extra packages and modifications that I add to =pkgs=), as well as a setting that allows me to install unfree software. As a base package set I choose =nixpkgs= from my inputs (and so does nearly every configuration out there. Keep in mind however that you could use any package set here! =nixpkgs= however also comes with a lot of useful =lib= functions (that are not =builtins= to the nix language!)) +- =mkTrueOption=: Defines a nixos module option that is by default enables (as opposed to =mkEnableOption= which are per default disabled). +- =mkStrong=: + - An alias for ([[#h:9e81b727-1436-4228-82b1-1edec5c50e06][nixpkgs.lib.mkOverride]] 60), which is higher than setting an option normally (i.e. =option = value=; which has priority 100), but being of lower priority than using [[#h:16599d68-0ca5-40fa-810e-76b5c739b2b1][nixpkgs.lib.mkForce]], which has priority 50 (lower priority takes precedence). For completeness' sake, the priority set when using [[#h:41180e6c-2a13-4b46-89b2-791562b4b816][nixpkgs.lib.mkDefault]] is 1000 (a very low value). +- =forEachLinuxSystem=: performs the =pkgsFor= function for a set of =systems= (here: =x86_64-linux= and =aarch64-linux=). I need to use this in the [[#h:6ed1a641-dba8-4e85-a62e-be93264df57a][Packages (pkgs)]] section in order to avoid trying to build those packages for darwin systems. + - uses [[#h:94690fcb-e039-49da-9bd3-610fa80fa08b][nixpkgs.lib.genAttrs]] +- =readHosts=: Reads the names of directories under the =hosts/= folder for a particular system type + - uses [[#h:1fb6ff92-7cc1-4447-8a63-460f24633053][builtins.readDir]] + - uses [[#h:0fded8e7-6160-4fcd-a491-42f0debfec52][nixpkgs.lib.attrNames]] to acquire attribute names from the outputs of =builtins.readDir= +- =readNix=: reads all files in a directory that are not =default.nix= (usually used to simply load everything from a folder and is called inside that respective =default.nix=). + - uses [[#h:1fb6ff92-7cc1-4447-8a63-460f24633053][builtins.readDir]] + - uses [[#h:0fded8e7-6160-4fcd-a491-42f0debfec52][nixpkgs.lib.attrNames]] to acquire attribute names from the outputs of =builtins.readDir= +- =mkImports=: These are used to help with importing files mostly: + - uses [[#h:a4f9752a-33a6-4dd4-97ea-ef6bf340bd8e][nixpkgs.lib.map]] to actually import the list of modules that are passed to =mkImports= in names. + +Concerning the =flake = _:= part: + - this is a mechanism introduced by [[https://flake.parts/][flake-parts]]. A =flake= output is akin to a 'normal' output of a standard nix flake (meaning, it will not be built specifically for each system defined by =mkFlake=) + - =lib= is then defined as the merged set of the =nixpkgs= and =home-manager= lib's, as well as some extra functions that I defined in the let-block (the =.extend()= method adds attributes to a set) + +#+begin_src nix-ts :tangle nix/lib.nix + { self, inputs, ... }: + let + swarselsystems = + let + inherit (inputs) systems; + inherit (inputs.nixpkgs) lib; + in + rec { + cidrToSubnetMask = cidr: + let + prefixLength = lib.toInt (lib.last (lib.splitString "/" cidr)); + bits = lib.genList (i: if i < prefixLength then 1 else 0) 32; + octets = lib.genList + (i: + let + octetBits = lib.sublist (i * 8) 8 bits; + octetValue = lib.foldl (acc: bit: acc * 2 + bit) 0 octetBits; + in + octetValue + ) 4; + subnetMask = lib.concatStringsSep "." (map toString octets); + in + subnetMask; + + mkIfElseList = p: yes: no: lib.mkMerge [ + (lib.mkIf p yes) + (lib.mkIf (!p) no) + ]; + + mkIfElse = p: yes: no: if p then yes else no; + + getSubDomain = domain: + let + parts = builtins.split "\\." domain; + domainParts = builtins.filter (x: builtins.isString x && x != "") parts; + in + if builtins.length domainParts > 0 + then builtins.head domainParts + else ""; + + getBaseDomain = domain: + let + parts = builtins.split "\\." domain; + domainParts = builtins.filter (x: builtins.isString x && x != "") parts; + baseParts = builtins.tail domainParts; + in + builtins.concatStringsSep "." baseParts; + + pkgsFor = lib.genAttrs (import systems) (system: + import inputs.nixpkgs { + inherit system; + overlays = [ self.overlays.default ]; + config.allowUnfree = true; + } + ); + + toCapitalized = str: + if builtins.stringLength str == 0 then + "" + else + let + first = builtins.substring 0 1 str; + rest = builtins.substring 1 (builtins.stringLength str - 1) str; + upper = lib.toUpper first; + lower = lib.toLower rest; + in + upper + lower; + + + mkTrueOption = lib.mkOption { + type = lib.types.bool; + default = true; }; - }); - formatter = forEachSystem (pkgs: pkgs.nixpkgs-fmt); - checks = forAllSystems ( - system: + mkStrong = lib.mkOverride 60; + + # forEachSystem = f: lib.genAttrs (import systems) (system: f pkgsFor.${system}); + forEachLinuxSystem = f: lib.genAttrs [ "x86_64-linux" "aarch64-linux" ] (system: f pkgsFor.${system}); + + readHosts = type: lib.attrNames (builtins.readDir "${self}/hosts/${type}"); + readNix = type: lib.filter (name: name != "default.nix" && name != "optional" && name != "darwin") (lib.attrNames (builtins.readDir "${self}/${type}")); + + mkImports = names: baseDir: lib.map (name: "${self}/${baseDir}/${name}") names; + }; + in + { + flake = _: + { + lib = inputs.nixpkgs.lib.extend (_: _: { + inherit (inputs.home-manager.lib) hm; + inherit swarselsystems; + }); + + swarselsystemsLib = swarselsystems; + homeLib = self.outputs.lib; + }; + } +#+end_src +** Packages (pkgs) +:PROPERTIES: +:CUSTOM_ID: h:6ed1a641-dba8-4e85-a62e-be93264df57a +:END: + +This does not use =perSystem= from =flake-parts= since some of my custom packages are not able to be built on darwin systems, and I was not yet interested in writing logic for handling that. Instead I use =forEachLinuxSystem= as described in [[#h:f9b7ffba-b7e2-4554-9a35-ece0bf173e1c][Library functions]] in roder to only build this for linux hosts. + +Other nix users can make use of these packages either by installing them directly in their config (using my flake as an input and then installing =.=) or by making use of the overlay that I provide in [[#h:7a059bd9-13f8-4005-b270-b41eeb6a4af2][Overlays]]. In the latter case all packages will be made available to the consuming flake + +More information on the actual packages build can be found in [[#h:64a5cc16-6b16-4802-b421-c67ccef853e1][Packages]]. + +#+begin_src nix-ts :tangle nix/packages.nix +{ self, inputs, ... }: +{ + imports = [ + ( + { lib, flake-parts-lib, ... }: + flake-parts-lib.mkTransposedPerSystemModule { + name = "pkgs"; + file = ./packages.nix; + option = lib.mkOption { + type = lib.types.unspecified; + }; + } + ) + ]; + flake = _: + let + inherit (self.outputs) lib; + in + { + packages = lib.swarselsystems.forEachLinuxSystem (pkgs: import "${self}/pkgs/flake" { inherit self lib pkgs; }); + }; + + perSystem = { pkgs, system, ... }: + { + # see https://flake.parts/module-arguments.html?highlight=modulewith#persystem-module-parameters + _module.args.pkgs = import inputs.nixpkgs { + inherit system; + config.allowUnfree = true; + overlays = [ + self.overlays.default + ]; + }; + inherit pkgs; + }; +} +#+end_src +** Globals +:PROPERTIES: +:CUSTOM_ID: h:af83893d-c0f9-4b45-b816-4849110d41b3 +:END: + +This file is used to parse each =nixosConfiguration= present in this flake and scan them for options set under the =globals= attribute set. I use =lib.evalModules= to evaluate a mini module system that only consists of these globals options and then load them into the actual configuration by providing a =globals= output to the flake. This treads a dangerous ground of infinite recursions, which is why both the module system as well as the inherited attributes are kept to the minimal size. Each module has a globals option loaded from a module file which will be separately loaded by this mini-evaluation. + - uses [[#h:b9663237-2232-4554-bc81-843be28a707c][nixpkgs.lib.mapAttrsToList]] on =config.nodes= + - uses [[#h:21389cc9-fd89-45ca-9836-592f84a45bb4][nixpkgs.lib.flip]] to reverse the function argument order of the =mapAttrsToList= call, so that we can give the attribute set (=config.nodes=) first. Alternatively, we could have written =lib.mapAttrsToList (name: cfg: [...]) config.nodes= but it would be harder to read since there would be a big block between the arguments. + - uses [[#h:22264e49-b6d0-4c1f-8d05-2ef1f3da3d54][nixpkgs.lib.concatLists]]. =options.config._globalDefs= holds the =options.globals.definitions= for each node (which in turn basically holds the information that has been set for each node under the =globals= option), so the concatenated list will look something like =[ { services.kanidm.domain = "foo"; }; } { services.freshrss.domain = "bar"; } ]=. + - uses [[#h:82c26445-2af4-4a6c-ae91-c804325fdf11][nixpkgs.lib.mkMerge]] to merge these seperate attribute sets in the list into one big attribute set (the above attribute set example would become then ={ services = { kanidm.domain = "foo"; freshrss.domain = "bar"; }; }=. You can see how this can now be referenced as a "global" set. + +I also have a file for global values that cannot be attributed to one =nixosConfiguration= alsone; the structure of this =globals.nix.enc= requires a toplevel =globals= - that means, =globals.nix.enc= has the structure ={ globals = [...] }=. + +Lastly, in order make this actually available to my configurations, i use the =inherit (globalsSystem.config.globals) [...]= which produces the =globals= output which I will pass to the =specialArgs= of my =nixosConfigurations=, which is when I will be finally able to use these definitions in my config. + +#+begin_src nix-ts :tangle nix/globals.nix + # adapted from https://github.com/oddlama/nix-config/blob/main/nix/globals.nix + { inputs, ... }: + { + flake = { config, lib, ... }: + { + globals = + let + globalsSystem = lib.evalModules { + prefix = [ "globals" ]; + specialArgs = { + inherit (inputs.self.pkgs.x86_64-linux ) lib; # fuck + # inherit (self.outputs) lib; + inherit inputs; + inherit (config) nodes; + }; + modules = [ + ../modules/nixos/common/globals.nix + ( + { lib, ... }: + let + # Try to access the extra builtin we loaded via nix-plugins. + # Throw an error if that doesn't exist. + sopsImportEncrypted = + assert lib.assertMsg (builtins ? extraBuiltins.sopsImportEncrypted) + "The extra builtin 'sopsImportEncrypted' is not available, so repo.secrets cannot be decrypted. Did you forget to add nix-plugins and point it to `./nix/extra-builtins.nix` ?"; + builtins.extraBuiltins.sopsImportEncrypted; + in + + { + imports = [ + (sopsImportEncrypted ../secrets/repo/globals.nix.enc) + ]; + + } + ) + ( + { lib, ... }: + { + globals = lib.mkMerge ( + lib.concatLists ( + lib.flip lib.mapAttrsToList config.nodes ( + name: cfg: + builtins.addErrorContext "while aggregating globals from nixosConfigurations.${name} into flake-level globals:" cfg.config._globalsDefs + ) + ) + ); + } + ) + ]; + }; + in + { + # Make sure the keys of this attrset are trivially evaluatable to avoid infinite recursion, + # therefore we inherit relevant attributes from the config. + inherit (globalsSystem.config.globals) + domains + services + networks + hosts + user + root + ; + }; + }; + } + +#+end_src + +** Hosts +:PROPERTIES: +:CUSTOM_ID: h:5c5bf78a-9a66-436f-bd85-85871d9d402b +:END: + +Here I define my hosts. Earlier (in [[#h:aee5ec75-7ca6-40d8-b6ac-a3e7e33a474b][flake.nix skeleton]]), I told you how I used to use noweb-ref blocks to achieve this task. You see, a single =nixosConfiguration= uses =nixpkgs.lib.nixosSystem=, passing modules and arguments to define itself. I have automated this process by reading all directories in the =hosts/= directory and then applying =nixpkgs.lib.nixosSystem= as a function on these returns. I also provide a =nixosConfigurationsMinimal= output which is ingested by the flake in =install/flake.nix= to be used during the initial deployment of a new system (it basically just disables most modules). + +- =mkNixosHost=: Very much akin to a simple call of =nixpkgs.lib.nixosSystem=, I simply define =specialArgs= and =modules= that I want to use for every configuration. Here, I load all the extra modules from my other input flakes. Also, I add the =globals= output from [[#h:af83893d-c0f9-4b45-b816-4849110d41b3][Globals]] and the =nodes= output that I define right here (it simply mirrors all "full" configurations - nixOS and darwin. I like to refer to home-manager only and nix-on-droid as a "half" configurations). It is also here that I set the node name for the configuration (I prefer this explicit call over referencing =networking.hostName= or such) and the directory that should be used for secrets of a configuration. +- =mkDarwinHost= works in the same way but for darwin machines. + +- =mkHalfHost= is a function that either creates a pure home-manager configuration or a nix-on-droid one. The type must be explicitly passed when calling the function. Here, again, we make use of =pkgsFor= that we defined in [[#h:f9b7ffba-b7e2-4554-9a35-ece0bf173e1c][Library functions]]. Also, we make sure to pass =extraSpecialArgs= (the pendant to =specialArgs=, just for home-manager configurations). + +- =diskoConfigurations=: specifies a default disko configuration that is to be used if someone pulls in my flake as a disko configuration. This is not used by me, but I think it is kind of neat. + +- =nodes=: As stated above, a shorthand for my configurations. Is built using the [[#h:b1fe7a9a-661b-4446-aefa-98373108f8fd][The '//' operator]] + +The rest of the outputs either define or help define the actual configurations: + - =mkHalfHostConfigs= works by calling the =nixpkgs.lib.foldl= function to build an attribute set of home-manager/nix-on-droidd configurations + - uses [[#h:e21d17fb-0c98-42d5-b08f-1c7584afa07f][nixpkgs.lib.foldl]] on the list created by [[#h:a4f9752a-33a6-4dd4-97ea-ef6bf340bd8e][nixpkgs.lib.map]] over =mkHalfHost=. In each step of the fold, I receive an attribute set. This attribute set is then merged to the resulting set using the =(acc: set: acc // set)= expression + - uses [[#h:b1fe7a9a-661b-4446-aefa-98373108f8fd][The '//' operator]] to merge the sets of the fold operation. + +#+begin_src nix-ts :tangle nix/hosts.nix + { self, inputs, ... }: + { + flake = { config, ... }: + let + inherit (self) outputs; + inherit (outputs) lib homeLib; + # lib = (inputs.nixpkgs.lib // inputs.home-manager.lib).extend (_: _: { swarselsystems = import "${self}/lib" { inherit self lib inputs outputs; inherit (inputs) systems; }; }); + + mkNixosHost = { minimal }: configName: arch: + inputs.nixpkgs.lib.nixosSystem { + specialArgs = { + inherit inputs outputs self minimal configName homeLib; + inherit (config.pkgs.${arch}) lib; + inherit (config) globals nodes; + }; + modules = [ + inputs.disko.nixosModules.disko + inputs.home-manager.nixosModules.home-manager + inputs.impermanence.nixosModules.impermanence + inputs.lanzaboote.nixosModules.lanzaboote + inputs.microvm.nixosModules.host + inputs.microvm.nixosModules.microvm + inputs.nix-index-database.nixosModules.nix-index + inputs.nix-minecraft.nixosModules.minecraft-servers + inputs.nix-topology.nixosModules.default + inputs.nswitch-rcm-nix.nixosModules.nswitch-rcm + inputs.simple-nixos-mailserver.nixosModules.default + inputs.sops-nix.nixosModules.sops + inputs.stylix.nixosModules.stylix + inputs.swarsel-nix.nixosModules.default + (inputs.nixos-extra-modules + "/modules/guests") + (inputs.nixos-extra-modules + "/modules/interface-naming.nix") + "${self}/hosts/nixos/${arch}/${configName}" + "${self}/profiles/nixos" + "${self}/modules/nixos" + { + _module.args.dns = inputs.dns; + + microvm.guest.enable = lib.mkDefault false; + + networking.hostName = lib.swarselsystems.mkStrong configName; + + node = { + name = lib.mkForce configName; + secretsDir = ../hosts/nixos/${arch}/${configName}/secrets; + lockFromBootstrapping = lib.mkIf (!minimal) (lib.swarselsystems.mkStrong true); + }; + + swarselprofiles = { + minimal = lib.mkIf minimal (lib.swarselsystems.mkStrong true); + }; + + swarselmodules.server = { + ssh = lib.mkIf (!minimal) (lib.swarselsystems.mkStrong true); + }; + + swarselsystems = { + mainUser = lib.swarselsystems.mkStrong "swarsel"; + }; + } + ]; + }; + + mkDarwinHost = { minimal }: configName: arch: + inputs.nix-darwin.lib.darwinSystem { + specialArgs = { + inherit inputs lib outputs self minimal configName; + inherit (config) globals nodes; + }; + modules = [ + # inputs.disko.nixosModules.disko + # inputs.sops-nix.nixosModules.sops + # inputs.impermanence.nixosModules.impermanence + # inputs.lanzaboote.nixosModules.lanzaboote + # inputs.fw-fanctrl.nixosModules.default + # inputs.nix-topology.nixosModules.default + inputs.home-manager.darwinModules.home-manager + "${self}/hosts/darwin/${arch}/${configName}" + "${self}/modules/nixos/darwin" + # needed for infrastructure + "${self}/modules/nixos/common/meta.nix" + "${self}/modules/nixos/common/globals.nix" + { + node.name = lib.mkForce configName; + node.secretsDir = ../hosts/darwin/${arch}/${configName}/secrets; + + } + ]; + }; + + mkHalfHost = configName: type: arch: + let + systemFunc = if (type == "home") then inputs.home-manager.lib.homeManagerConfiguration else inputs.nix-on-droid.lib.nixOnDroidConfiguration; + pkgs = lib.swarselsystems.pkgsFor.${arch}; + in + systemFunc { + inherit pkgs; + extraSpecialArgs = { + inherit inputs lib outputs self configName; + inherit (config) globals nodes; + minimal = false; + }; + modules = [ + inputs.stylix.homeModules.stylix + inputs.nix-index-database.homeModules.nix-index + # inputs.sops-nix.homeManagerModules.sops + inputs.spicetify-nix.homeManagerModules.default + inputs.swarsel-nix.homeModules.default + "${self}/hosts/${type}/${arch}/${configName}" + "${self}/profiles/home" + ]; + }; + + linuxArches = [ "x86_64-linux" "aarch64-linux" ]; + darwinArches = [ "x86_64-darwin" "aarch64-darwin" ]; + mkArches = type: if (type == "nixos") then linuxArches else if (type == "darwin") then darwinArches else linuxArches ++ darwinArches; + + readHostDirs = hostDir: + if builtins.pathExists hostDir then + builtins.attrNames + ( + lib.filterAttrs (_: type: type == "directory") + (builtins.readDir hostDir) + ) else [ ]; + + mkHalfHostsForArch = type: arch: + let + hostDir = "${self}/hosts/${type}/${arch}"; + hosts = readHostDirs hostDir; + in + lib.genAttrs hosts (host: mkHalfHost host type arch); + + mkHostsForArch = type: arch: minimal: + let + hostDir = "${self}/hosts/${type}/${arch}"; + hosts = readHostDirs hostDir; + in + if (type == "nixos") then + lib.genAttrs hosts (host: mkNixosHost { inherit minimal; } host arch) + else if (type == "darwin") then + lib.genAttrs hosts (host: mkDarwinHost { inherit minimal; } host arch) + else { }; + + mkConfigurationsPerArch = type: minimal: + let + arches = mkArches type; + toMake = if (minimal == null) then (arch: _: mkHalfHostsForArch type arch) else (arch: _: mkHostsForArch type arch minimal); + in + lib.concatMapAttrs toMake + (lib.listToAttrs (map (a: { name = a; value = { }; }) arches)); + + halfConfigurationsPerArch = type: mkConfigurationsPerArch type null; + configurationsPerArch = type: minimal: mkConfigurationsPerArch type minimal; + + in + { + nixosConfigurations = configurationsPerArch "nixos" false; + nixosConfigurationsMinimal = configurationsPerArch "nixos" true; + darwinConfigurations = configurationsPerArch "darwin" false; + darwinConfigurationsMinimal = configurationsPerArch "darwin" true; + homeConfigurations = halfConfigurationsPerArch "home"; + nixOnDroidConfigurations = halfConfigurationsPerArch "android"; + + guestConfigurations = lib.flip lib.concatMapAttrs config.nixosConfigurations ( + _: node: + lib.flip lib.mapAttrs' (node.config.microvm.vms or { }) ( + guestName: guestDef: + lib.nameValuePair guestDef.nodeName node.config.microvm.vms.${guestName}.config + ) + ); + + diskoConfigurations.default = import "${self}/files/templates/hosts/nixos/disk-config.nix"; + + nodes = config.nixosConfigurations + // config.darwinConfigurations + // config.guestConfigurations; + }; + } +#+end_src + +** Topology +:PROPERTIES: +:CUSTOM_ID: h:391e7712-fef3-4f13-a3ed-d36e228166fd +:END: + +This defines some topology for the [[https://github.com/oddlama/nix-topology][nix-topology]] modole that can not otherwise be parsed from the config (or is global). For example, this is used to define a number of switches, printers and routers. The topology graph is built from left to right, meaning that =nodes.internet = mkInternet { connections = [ (mkConnection "moonside" "wan") ]; };= means that the node =internet= 'initiates' the connection to the node =moonside= (=internet= will be on the left). + +Another note concerning [[https://flake.parts/][flake-parts]]: + - =perSystem= is a mechanism that tells flake-parts to build the following attribute set for all systems. This replaces the need to handle myself any =system= or =pkgs= variables, this is done by flake-parts. + +#+begin_src nix-ts :tangle nix/topology.nix + { self, inputs, ... }: + { + imports = [ + inputs.nix-topology.flakeModule + ]; + + perSystem.topology.modules = [ + ({ config, ... }: let - pkgs = nixpkgs.legacyPackages.${system}; + inherit (config.lib.topology) + mkInternet + mkDevice + mkSwitch + mkRouter + mkConnection + ; in - import ./checks { inherit self inputs system pkgs; } - ); - overlays = import ./overlays { inherit inputs; }; + { + renderer = "elk"; -#+end_src + networks = { + home-lan = { + name = "Home LAN"; + cidrv4 = "192.168.1.0/24"; + }; + wg = { + name = "Wireguard Tunnel"; + cidrv4 = "192.168.3.0/24"; + }; + }; -** nixosConfigurations -:PROPERTIES: -:CUSTOM_ID: h:9c9b9e3b-8771-44fa-ba9e-5056ae809655 -:END: + nodes = { + internet = mkInternet { + connections = [ + (mkConnection "moonside" "wan") + (mkConnection "pfsense" "wan") + (mkConnection "milkywell" "wan") + (mkConnection "magicant" "wifi") + (mkConnection "toto" "bootstrapper") + (mkConnection "hotel" "demo host") + ]; + }; -This section used to be much longer, since I performed all of my imports right here in the past. Since then, I have however refactored and now my important hosts can be defined in little space. Once I have fully transitioned my server to NixOS too this section will become even smaller once more. + hotel.interfaces."demo host" = { }; + toto.interfaces."bootstrapper" = { }; + milkywell.interfaces.wan = { }; + moonside.interfaces.wan = { }; -Note: The preceding =nixosConfigurations= is found in [[#h:aee5ec75-7ca6-40d8-b6ac-a3e7e33a474b][flake.nix template]]. Also, the method of generating the hosts was changed in commit -=3a272b1 feat!: dynamically create hosts=, and the deprecated system definitions removed in =7457109 main chore: remove deprecated static host config=. See those commits for a state with a simpler config. + pfsense = mkRouter "pfSense" { + info = "HUNSN RM02"; + image = "${self}/files/topology-images/hunsn.png"; + interfaceGroups = [ + [ + "eth2" + "eth3" + "eth4" + "eth5" + "eth6" + ] + [ "wan" ] + ]; + interfaces.wg = { + addresses = [ "192.168.3.1" ]; + network = "wg"; + virtual = true; + type = "wireguard"; + }; + + connections = { + eth2 = mkConnection "switch-livingroom" "eth1"; + eth4 = mkConnection "winters" "eth1"; + eth3 = mkConnection "switch-bedroom" "eth1"; + eth6 = mkConnection "wifi-ap" "eth1"; + wg = mkConnection "moonside" "wg"; + }; + interfaces = { + eth2 = { + addresses = [ "192.168.1.1" ]; + network = "home-lan"; + }; + eth3 = { + addresses = [ "192.168.1.1" ]; + network = "home-lan"; + }; + eth4 = { + addresses = [ "192.168.1.1" ]; + network = "home-lan"; + }; + eth6 = { + addresses = [ "192.168.1.1" ]; + network = "home-lan"; + }; + }; + }; + + winters.interfaces."eth1" = { }; + bakery.interfaces = { + "eth1" = { }; + "wifi" = { }; + }; + + wifi-ap = mkSwitch "Wi-Fi AP" { + info = "Huawei"; + image = "${self}/files/topology-images/huawei.png"; + interfaceGroups = [ + [ + "eth1" + "wifi" + ] + ]; + connections = { + wifi = mkConnection "bakery" "wifi"; + }; + }; + + switch-livingroom = mkSwitch "Switch Livingroom" { + info = "TL-SG108"; + image = "${self}/files/topology-images/TL-SG108.png"; + interfaceGroups = [ + [ + "eth1" + "eth2" + "eth3" + "eth4" + "eth5" + "eth6" + "eth7" + "eth8" + ] + ]; + connections = { + eth2 = mkConnection "nswitch" "eth1"; + eth7 = mkConnection "pc" "eth1"; + eth8 = mkConnection "pyramid" "eth1"; + }; + }; + + nswitch = mkDevice "Nintendo Switch" { + info = "Nintendo Switch"; + image = "${self}/files/topology-images/nintendo-switch.png"; + interfaces.eth1 = { }; + }; + + magicant = mkDevice "magicant" { + icon = "${self}/files/topology-images/phone.png"; + info = "Samsung Z Flip 6"; + image = "${self}/files/topology-images/zflip6.png"; + interfaces.wifi = { }; + }; + + machpizza = mkDevice "machpizza" { + info = "MacBook Pro 2016"; + icon = "${self}/files/topology-images/mac.png"; + interfaces."eth1" = { }; + }; + + pc = mkDevice "Windows Gaming Server" { + info = "i7-4790k, GTX970, 32GB RAM"; + image = "${self}/files/topology-images/pc.png"; + interfaces.eth1 = { }; + }; + + pyramid.interfaces.eth1 = { }; + + switch-bedroom = mkSwitch "Switch Bedroom" { + info = "TL-SG1005D"; + image = "${self}/files/topology-images/TL-SG1005D.png"; + interfaceGroups = [ + [ + "eth1" + "eth2" + "eth3" + "eth4" + "eth5" + ] + ]; + connections.eth2 = mkConnection "printer" "eth1"; + connections.eth3 = mkConnection "machpizza" "eth1"; + }; + + printer = mkDevice "Printer" { + info = "DELL C2665dnf"; + image = "${self}/files/topology-images/DELL-C2665dnf.png"; + interfaces.eth1 = { }; + }; + + }; + + }) -#+begin_src nix :tangle no :noweb-ref flakenixosconf - mkFullHostConfigs (readHosts "nixos") true; -#+end_src -** darwinConfigurations -:PROPERTIES: -:CUSTOM_ID: h:f881aa05-a670-48dd-a57b-2916abdcb692 -:END: - -And this defines darwin systems (MacOS), which I only have one of, that serves as a template mostly. - -Note: The preceding =darwinConfigurations= is found in [[#h:aee5ec75-7ca6-40d8-b6ac-a3e7e33a474b][flake.nix template]]. Also, the method of generating the hosts was changed in commit -=3a272b1 feat!: dynamically create hosts=, and the deprecated system definitions removed in =7457109 main chore: remove deprecated static host config=. See those commits for a state with a simpler config. - -#+begin_src nix :tangle no :noweb-ref flakedarwinconf - mkFullHostConfigs (readHosts "darwin") false; -#+end_src - -** homeConfigurations -:PROPERTIES: -:CUSTOM_ID: h:f881aa05-a670-48dd-a57b-2916abdcb692 -:END: - -In contrast, this defines home-manager systems, which I only have one of, that serves as a template mostly. - -#+begin_src nix :tangle no :noweb-ref flakehomeconf - - "swarsel@home-manager" = inputs.home-manager.lib.homeManagerConfiguration { - pkgs = pkgsFor.x86_64-linux; - extraSpecialArgs = { inherit inputs outputs; }; - modules = homeModules ++ mixedModules ++ [ - ./hosts/home-manager ]; - }; + } #+end_src -** nixOnDroidConfigurations +** Devshell (checks) :PROPERTIES: -:CUSTOM_ID: h:5f6ef553-59f9-4239-b6f3-63d33b57f335 +:CUSTOM_ID: h:4d0548db-99b2-4e07-b762-6d86fbb26d4c :END: -Nix on Android also demands an own flake output, which is provided here. +This file defines a number of checks that can either be run by calling =nix flake check= or while in a =nix-shell= or =nix develop=. This helps me make sure that my flake confirms to my self-imposed standards. The GitHub actions perform less checks than are being done here (they are only checking the formatting, as well as =statix= and =deadnix=). -#+begin_src nix :tangle no :noweb-ref flakedroidconf +The devshell also provides a number of useful shorthand commands, as well as a 'safe' version of nixpkgs that I can use to rebuild from in case a version bump in nixpkgs suddenly breaks [[https://github.com/shlevy/nix-plugins][nix-plugins]]. - magicant = inputs.nix-on-droid.lib.nixOnDroidConfiguration { - pkgs = pkgsFor.aarch64-linux; - modules = [ - ./hosts/magicant +Lastly, in the =perSystem= attribute set, we see that it is actually passed some values here. These expose to the scoped expressions the enclosed values, which makes it possible to still reference e.g. =system= and =pkgs= even when they are actually handled by flake-parts. + +#+begin_src nix-ts :tangle nix/devshell.nix + { self, inputs, ... }: + { + imports = [ + inputs.devshell.flakeModule + inputs.pre-commit-hooks.flakeModule ]; - }; + perSystem = { pkgs, config, system, ... }: + { + pre-commit = { + check.enable = true; + settings = { + addGcRoot = true; + hooks = { + check-added-large-files.enable = true; + check-case-conflicts.enable = true; + check-executables-have-shebangs.enable = true; + check-shebang-scripts-are-executable.enable = false; + check-merge-conflicts.enable = true; + deadnix.enable = true; + detect-private-keys.enable = true; + end-of-file-fixer.enable = true; + fix-byte-order-marker.enable = true; + flake-checker.enable = true; + forbid-new-submodules.enable = true; + mixed-line-endings.enable = true; + nixpkgs-fmt.enable = true; + statix.enable = true; + trim-trailing-whitespace.enable = true; + treefmt.enable = true; + + destroyed-symlinks = { + enable = true; + entry = "${inputs.pre-commit-hooks.checks.${system}.pre-commit-hooks}/bin/destroyed-symlinks"; + }; + + shellcheck = { + enable = true; + entry = "${pkgs.shellcheck}/bin/shellcheck --shell=bash"; + }; + + shfmt = { + enable = true; + entry = "${pkgs.shfmt}/bin/shfmt -i 4 -sr -d -s -l"; + }; + }; + }; + }; + + devshells = { + 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} + ''; + } + ]; + }; + default = + let + nix-version = "2_30"; + in + { + packages = [ + (builtins.trace "alarm: pinned nix_${nix-version}" pkgs.nixVersions."nix_${nix-version}") + pkgs.git + pkgs.just + pkgs.age + pkgs.ssh-to-age + pkgs.sops + pkgs.nixpkgs-fmt + self.packages.${system}.swarsel-build + self.packages.${system}.swarsel-deploy + (pkgs.symlinkJoin { + name = "home-manager"; + buildInputs = [ pkgs.makeWrapper ]; + paths = [ pkgs.home-manager ]; + postBuild = '' + wrapProgram $out/bin/home-manager \ + --append-flags '--flake .#$(hostname)' + ''; + }) + ]; + + commands = [ + { + package = pkgs.statix; + help = "Lint flake"; + } + { + package = pkgs.deadnix; + help = "Check flake for dead code"; + } + { + package = pkgs.nix-tree; + help = "Interactively browse dependency graphs of Nix derivations"; + } + { + package = pkgs.nvd; + help = "Diff two nix toplevels and show which packages were upgraded"; + } + { + package = pkgs.nix-diff; + help = "Explain why two Nix derivations differ"; + } + { + package = pkgs.nix-output-monitor; + help = "Nix Output Monitor (a drop-in alternative for `nix` which shows a build graph)"; + name = "nom \"$@\""; + } + { + name = "hm"; + help = "Manage home-manager config"; + command = "home-manager \"$@\""; + } + { + name = "fmt"; + help = "Format flake"; + command = "nixpkgs-fmt --check \"$FLAKE\""; + } + { + name = "sd"; + help = "Build and deploy this nix config to nodes"; + command = "swarsel-deploy \"$@\""; + } + { + name = "sl"; + help = "Build and deploy a config to nodes"; + command = "swarsel-deploy \${1} switch"; + } + { + name = "sw"; + help = "Build and switch to the host's config locally"; + command = "swarsel-deploy $(hostname) switch"; + } + { + name = "bld"; + help = "Build a number of configurations"; + command = "swarsel-build \"$@\""; + } + { + name = "c"; + help = "Work with the flake git repository"; + command = "git --git-dir=$FLAKE/.git --work-tree=$FLAKE/ \"$@\""; + } + ]; + + # devshell.startup.pre-commit-install.text = "pre-commit install"; + devshell.startup.pre-commit.text = config.pre-commit.installationScript; + + env = + let + nix-plugins = pkgs.nix-plugins.override { + nixComponents = pkgs.nixVersions."nixComponents_${nix-version}"; + }; + in + [ + { + name = "NIX_CONFIG"; + value = '' + plugin-files = ${nix-plugins}/lib/nix/plugins + extra-builtins-file = ${self + /nix/extra-builtins.nix} + ''; + } + ]; + }; + }; + }; + } #+end_src +** Templates +:PROPERTIES: +:CUSTOM_ID: h:e817f769-9aa9-4192-b649-c269080f4fee +:END: + +This file defines the templates that are being exposed by the flake. These can be used by running =nix flake init -t github:Swarsel/.dotfiles#= by others. Personally, I mostly use these as part of the [[#h:154b6df4-dd50-4f60-9794-05a140d02994][project]] utility. + +Otherwise, I define the function =mkTemplates= here which builds a named attribute set for each type of template that I have. + +- uses [[#h:c63cd469-7724-4a05-b932-8843722a00f0][builtins.listToAttrs]] + +#+begin_src nix-ts :tangle nix/templates.nix + { self, ... }: + { + flake = _: { + templates = + let + mkTemplates = names: builtins.listToAttrs (map + (name: { + inherit name; + value = { + path = "${self}/files/templates/${name}"; + description = "${name} project "; + }; + }) + names); + templateNames = [ + "python" + "rust" + "go" + "cpp" + "latex" + "default" + ]; + in + mkTemplates templateNames; + }; + } + +#+end_src +** Formatter (treefmt-nix) +:PROPERTIES: +:CUSTOM_ID: h:5fce36ae-715d-42d3-9ad4-46137d85083f +:END: + +Defines a formatter that can be called using =nix flake format=. While a nice utility, I have stronger tools to perform this job. + +#+begin_src nix-ts :tangle nix/formatter.nix + { inputs, ... }: + { + imports = [ + inputs.treefmt-nix.flakeModule + ]; + + perSystem = { pkgs, ... }: { + # formatter = pkgs.nixpkgs-fmt; + # formatter is set by treefmt to: + # formatter = lib.mkIf config.treefmt.flakeFormatter (lib.mkDefault config.treefmt.build.wrapper); + treefmt = { + projectRootFile = "flake.nix"; + programs = { + nixfmt = { + enable = true; + package = pkgs.nixpkgs-fmt; + }; + deadnix.enable = true; + statix.enable = true; + shfmt = { + enable = true; + indent_size = 4; + simplify = true; + # needed to replicate what my Emacs shfmt does + # there is no builtin option for space-redirects + package = pkgs.symlinkJoin { + name = "shfmt"; + buildInputs = [ pkgs.makeWrapper ]; + paths = [ pkgs.shfmt ]; + postBuild = '' + wrapProgram $out/bin/shfmt \ + --add-flags '-sr' + ''; + }; + }; + shellcheck.enable = true; + }; + settings.formatter.shellcheck.options = [ + "--shell" + "bash" + ]; + }; + }; + } + +#+end_src +** TODO Modules +:PROPERTIES: +:CUSTOM_ID: h:e8eb0617-3441-421d-9b44-716ed40159ab +:END: + +This exposes all of my modular configuration as modules. Other people can use them in their flake using =imports = [ inputs..nixosModules ];=. Per default, this enables some mechanisms like config sharing between nodes and the globals system. TODO: make it so that nothing is enabled upon initial import. + +=nixosModules= is a `defined` flake output, where external tools might expect some sort of structure; hence, I call the default output =default=, which will, in many cases, allow the user to just reference to the flake itself (which will then use =nixosModules.default= automatically. + +=homeModules= on the other hand is not standardized in this way (for example, many flakes refere to =homeManagerModules= instead); in order not to unnecessarily break things, I leave it as is. + +#+begin_src nix-ts :tangle nix/modules.nix + { self, ... }: + { + flake = _: + let + inherit (self.outputs) lib; + in + { + nixosModules.default = import "${self}/modules/nixos" { inherit lib; }; + homeModules = import "${self}/modules/home" { inherit lib; }; + }; + } + +#+end_src +** Apps +:PROPERTIES: +:CUSTOM_ID: h:52e1fae8-0e8c-4be6-a6ce-758ada652dd3 +:END: + +This defines some apps; they differ from normal packages in that they can be called using =nix run =. So, for example, I can call my deployment script using =nix run --experimental-features 'nix-command flakes' github:Swarsel/.dotfiles -- -n -d = (here I did not specify =#swarsel-bootstrap= since it is set as the default. In general, whenever the =#...= part is ommitted, the object under the default attribute will be used. This is also true for =nixosConfigurations=: in that case, the default will be the current hostname of the machine). + +- uses [[#h:c63cd469-7724-4a05-b932-8843722a00f0][builtins.listToAttrs]] +- uses [[#h:b1fe7a9a-661b-4446-aefa-98373108f8fd][The '//' operator]] to add the default output to thte set of built apps. + +#+begin_src nix-ts :tangle nix/apps.nix + { self, ... }: + { + perSystem = { system, ... }: + let + mkApps = system: names: self: builtins.listToAttrs (map + (name: { + inherit name; + value = { + type = "app"; + program = "${self.packages.${system}.${name}}/bin/${name}"; + meta = { + description = "Custom app ${name}."; + }; + }; + }) + names); + + appNames = [ + "swarsel-bootstrap" + "swarsel-install" + "swarsel-rebuild" + "swarsel-postinstall" + ]; + + appSet = mkApps system appNames self; + in + { + apps = appSet // { + default = appSet.swarsel-bootstrap; + }; + }; + } +#+end_src +** Overlays +:PROPERTIES: +:CUSTOM_ID: h:7a059bd9-13f8-4005-b270-b41eeb6a4af2 +:END: + +In this section I define packages that I manually add to nixpkgs, or that I want to use in a modified way. This can be useful for packages that are currently awaiting a PR or public packages that I do not want to maintain. + +As such, I also define three additional overlays: + +1) =additions= + These are for the aforementioned added packages. + NOTE: The packages themselves are built in [[#h:6ed1a641-dba8-4e85-a62e-be93264df57a][Packages (pkgs)]]; here, we just add them to the overlay that we then use in the configuration. +2) =modification= + These are for packages that are on nixpkgs, but do not fit my usecase, meaning I need to perform modifications on them. +3) =nixpkgs-stable-versions= + These are simply mirrors of other branches of nixpkgs (mostly past stable branches). Useful for packages that are broken on nixpkgs, but do not need to be on bleeding edge anyways. Automatically fetches all inputs names =nixpkgs-= and adds them under the name in ==. + +Also, this is where I define all of my own modules. These are mostly used for setting some host-specifics directly than opposed to through multiple options. + +Lastly, I add some of my own library functions to be used alongside the functions provided by =nixpkgs= and =home-manager=. + +On the structure of overlays: as you notice, all of the attributes within overlays are functions which take =final= and =prev= as arguments. This is a convention (sometimes you also see =super= instead of =final=) that aims to tell you that =final= represents the =pkgs= set after it has gone over all modifications, while =prev= is the =pkgs= set before the current modification. + - So, in =additions=, the =final= set is the same as in =modifications=, but their =prev= sets might differ (in this case, I believe they will be the same since all modifications are done at the same step). #TODO: fact check + - This starts to make a difference when you use multiple overlays and have one overlay depend on the modifications in another overlay. + +- The =_= argument is used like in a number of other programing languages and signals that the argument is never actually used in the function. + +#+begin_src nix-ts :tangle nix/overlays.nix + { self, inputs, ... }: + let + inherit (self) outputs; + inherit (outputs) lib; + in + { + flake = _: + { + overlays = { + default = 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.system}.default; + }; + + 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; + + 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 + ]); + + }; + + nixpkgs-stable-versions = final: _: + let + nixpkgsInputs = + lib.filterAttrs + (name: _v: builtins.match "^nixpkgs-.*" name != null) + inputs; + + rename = name: builtins.replaceStrings [ "nixpkgs-" ] [ "" ] name; + + mkPkgs = src: + import src { + inherit (final) system; + config.allowUnfree = true; + }; + in + builtins.listToAttrs (map + (name: { + name = rename name; + value = mkPkgs nixpkgsInputs.${name}; + }) + (builtins.attrNames nixpkgsInputs)); + + in + lib.recursiveUpdate + ( + (additions final prev) + // (nixpkgs-stable-versions final prev) + // (inputs.niri-flake.overlays.niri 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) + ) + (modifications final prev); + }; + }; + } +#+end_src +** Installer iso +:PROPERTIES: +:CUSTOM_ID: h:1d1ccae5-62ca-4d37-a28e-c59987850ed2 +:END: + +This sections makes use of [[https://github.com/nix-community/nixos-generators][nixos-generators]] in order to easily allow me to build a live ISO of my installer system. It can be built using =nix build --print-out-paths --no-link #images..live-iso=, and can then be copied to a USB drive using, for example, =dd=. + +This is an improvement to what I did earlier, where I did not use =nixos-generators= but instead manually imported the needed modules to make this configration into a bootable USB image. Now, I can just write this in the same way that I would to write any other configuration. + +- =perSystem= is again a =flake-parts= construct. + +#+begin_src nix-ts :tangle nix/iso.nix + { self, inputs, ... }: + { + perSystem = { pkgs, system, ... }: + { + packages = { + # nix build --print-out-paths --no-link .#live-iso + live-iso = inputs.nixos-generators.nixosGenerate { + inherit pkgs; + specialArgs = { inherit self; }; + modules = [ + inputs.home-manager.nixosModules.home-manager + "${self}/install/installer-config.nix" + ]; + format = + { + x86_64-linux = "install-iso"; + aarch64-linux = "sd-aarch64-installer"; + }.${system}; + }; + + # nix build --print-out-paths --no-link .#pnap-kexec --system + swarsel-kexec = (inputs.smallpkgs.legacyPackages.${system}.nixos [ + { + imports = [ "${self}/install/kexec.nix" ]; + _file = __curPos.file; + system.kexec-installer.name = "swarsel-kexec"; + } + inputs.nixos-images.nixosModules.kexec-installer + ]).config.system.build.kexecInstallerTarball; + + }; + }; + } +#+end_src +** Installer flake +:PROPERTIES: +:CUSTOM_ID: h:1d4514b4-e952-4faf-b30e-d89e73a526c6 +:END: + +When using tools like (the builtin) =nixos-rebuild= or =nixos-anywhere=, these tools expect the flake to have a certain structure; namely, they expect to find an output named =nixosConfigurations=, which is implicitely used when passing =--flake .#= (it is used in front of ==). + +When I define my configurations, I am actually defining two versions for each actual system: + - One 'regular' config that should be used by all rebuild tools such as =nixos-rebuild= + - One 'minimal' config that should be used by =nixos=anywhere= during initial deployment of a system + +Now, I could of course define a == and =-minimal= attribute for each configuration and just put these under =nixosConfigurations=, but that would have several drawbacks: + - evaluation time would increase + - my =nodes= output (that holds information for all actual systems) would bloat + - it is actually not clear that == and =-minimal= represent the same config + +Hence, what I instead do is to define another output =nixosConfigurationsMinimal= as an output to this flakes' config, and then use it to set the =nixosConfigurations= of another, minimal, flake that I keep in =install/=. When using =nixos-anywhere= during initial deployment, I will then point it to that minimal flake, where the minimal configs can be found. + +#+begin_src nix-ts :tangle install/flake.nix + { + description = "Minimal installer flake - not to be used manually"; + + inputs.swarsel.url = "./.."; + + outputs = { swarsel, ... }: { nixosConfigurations = swarsel.nixosConfigurationsMinimal; }; + } +#+end_src * System :PROPERTIES: :CUSTOM_ID: h:02cd20be-1ffa-4904-9d5a-da5a89ba1421 @@ -1180,9 +1923,217 @@ This holds most of the NixOS side of configuration. :CUSTOM_ID: h:88bf4b90-e94b-46fb-aaf1-a381a512860d :END: -This section mainly exists house different `default.nix` files to define some modules that should be loaded on respective systems. +This section mainly exists to house different =default.nix= files to define some modules that should be loaded on respective systems. Every host is housed in the =hosts/= directory, which is then subdivided by each respective system (=nixos/=, =home-manager/=, =nix-on-droid/=, =darwin/=). As described earlier, some of these configurations (nixos and darwin) can be defined automatically in this flake. For home-manager and nix-on-droid, the system architecture must be defined manually. +*** TODO Template +:PROPERTIES: +:CUSTOM_ID: h:373bd9e8-616e-434e-bfab-c216ce4470e9 +:END: + +This is the template that I use for new deployments of personal machines. Servers are usually highly tailored to their specific task and I do not consider it worth a time to craft a template for that. Also, at least at the current time, I only provide a template for NixOS hosts, as I rarely ever use anything else. + +TODO: I dont think this template would currently work out of the box + +**** Main Configuration +:PROPERTIES: +:CUSTOM_ID: h:859aec97-65a2-4633-b7d8-73d4ccf89cc5 +:END: + +#+begin_src nix-ts :tangle files/templates/hosts/nixos/default.nix + { self, config, inputs, pkgs, lib, ... }: + let + primaryUser = config.swarselsystems.mainUser; + modulesPath = "${self}/modules"; + sharedOptions = { + isBtrfs = true; + }; + in + { + + imports = [ + # ---- nixos-hardware here ---- + + ./hardware-configuration.nix + ./disk-config.nix + + "${modulesPath}/nixos/optional/virtualbox.nix" + # "${modulesPath}/nixos/optional/vmware.nix" + "${modulesPath}/nixos/optional/autologin.nix" + "${modulesPath}/nixos/optional/nswitch-rcm.nix" + "${modulesPath}/nixos/optional/gaming.nix" + + inputs.home-manager.nixosModules.home-manager + { + home-manager.users."${primaryUser}".imports = [ + "${modulesPath}/home/optional/gaming.nix" + ]; + } + ]; + + boot = { + kernelPackages = lib.mkDefault pkgs.linuxPackages_latest; + }; + + networking = { + hostName = "TEMPLATE"; + firewall.enable = true; + }; + + swarselsystems = lib.recursiveUpdate + { + wallpaper = self + /files/wallpaper/lenovowp.png; + hasBluetooth = true; + hasFingerprint = true; + isImpermanence = true; + isSecureBoot = true; + isCrypted = true; + isSwap = true; + swapSize = "32G"; + rootDisk = "TEMPLATE"; + } + sharedOptions; + + home-manager.users."${primaryUser}".swarselsystems = lib.recursiveUpdate + { + isLaptop = true; + isNixos = true; + cpuCount = 16; + } + sharedOptions; + } +#+end_src +**** disko +:PROPERTIES: +:CUSTOM_ID: h:24757d1e-6e88-4843-ab20-5e0c1b7ae29e +:END: + +Acceptance of arbitraty argumments is here needed because =disko= passes =diskoFile= to this file. + +#+begin_src nix-ts :tangle files/templates/hosts/nixos/disk-config.nix + { lib, pkgs, config, ... }: + let + type = "btrfs"; + extraArgs = [ "-L" "nixos" "-f" ]; # force overwrite + subvolumes = { + "/root" = { + mountpoint = "/"; + mountOptions = [ + "subvol=root" + "compress=zstd" + "noatime" + ]; + }; + "/home" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/home"; + mountOptions = [ + "subvol=home" + "compress=zstd" + "noatime" + ]; + }; + "/persist" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/persist"; + mountOptions = [ + "subvol=persist" + "compress=zstd" + "noatime" + ]; + }; + "/log" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/var/log"; + mountOptions = [ + "subvol=log" + "compress=zstd" + "noatime" + ]; + }; + "/nix" = { + mountpoint = "/nix"; + mountOptions = [ + "subvol=nix" + "compress=zstd" + "noatime" + ]; + }; + "/swap" = lib.mkIf config.swarselsystems.isSwap { + mountpoint = "/.swapvol"; + swap.swapfile.size = config.swarselsystems.swapSize; + }; + }; + in + { + disko.devices = { + disk = { + disk0 = { + type = "disk"; + device = config.swarselsystems.rootDisk; + content = { + type = "gpt"; + partitions = { + ESP = { + priority = 1; + name = "ESP"; + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "defaults" ]; + }; + }; + root = lib.mkIf (!config.swarselsystems.isCrypted) { + size = "100%"; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/disk/by-label/nixos" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + luks = lib.mkIf config.swarselsystems.isCrypted { + size = "100%"; + content = { + type = "luks"; + name = "cryptroot"; + passwordFile = "/tmp/disko-password"; # this is populated by bootstrap.sh + settings = { + allowDiscards = true; + # https://github.com/hmajid2301/dotfiles/blob/a0b511c79b11d9b4afe2a5e2b7eedb2af23e288f/systems/x86_64-linux/framework/disks.nix#L36 + crypttabExtraOpts = [ + "fido2-device=auto" + "token-timeout=10" + ]; + }; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/mapper/cryptroot" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + }; + }; + }; + }; + }; + }; + + fileSystems."/persist".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + fileSystems."/home".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + + environment.systemPackages = [ + pkgs.yubikey-manager + ]; + } +#+end_src *** Physical hosts :PROPERTIES: :CUSTOM_ID: h:58dc6384-0d19-4f71-9043-4014bd033ba2 @@ -1190,359 +2141,1194 @@ Every host is housed in the =hosts/= directory, which is then subdivided by each This is a list of all physical machines that I maintain. -**** nbl-imba-2 (Framework Laptop 16) +**** pyramid (Framework Laptop 16) :PROPERTIES: :CUSTOM_ID: h:6c6e9261-dfa1-42d8-ab2a-8b7c227be6d9 :END: My work machine. Built for more security, this is the gold standard of my configurations at the moment. - -#+begin_src nix :tangle hosts/nixos/nbl-imba-2/default.nix - { self, inputs, outputs, config, pkgs, lib, ... }: +***** Main Configuration +:PROPERTIES: +:CUSTOM_ID: h:567c0055-f5f7-4e53-8f13-d767d7166e9d +:END: +#+begin_src nix-ts :tangle hosts/nixos/x86_64-linux/pyramid/default.nix + { self, config, inputs, lib, minimal, ... }: let - profilesPath = "${self}/profiles"; + primaryUser = config.swarselsystems.mainUser; in { - imports = outputs.nixModules ++ [ + imports = [ inputs.nixos-hardware.nixosModules.framework-16-7040-amd - inputs.fw-fanctrl.nixosModules.default - ./hardware-configuration.nix ./disk-config.nix + ./hardware-configuration.nix - "${profilesPath}/optional/nixos/virtualbox.nix" - # "${profilesPath}/optional/nixos/vmware.nix" - "${profilesPath}/optional/nixos/autologin.nix" - "${profilesPath}/optional/nixos/nswitch-rcm.nix" - "${profilesPath}/optional/nixos/gaming.nix" - "${profilesPath}/optional/nixos/work.nix" + "${self}/modules/nixos/optional/amdcpu.nix" + "${self}/modules/nixos/optional/amdgpu.nix" + "${self}/modules/nixos/optional/framework.nix" + "${self}/modules/nixos/optional/gaming.nix" + "${self}/modules/nixos/optional/hibernation.nix" + "${self}/modules/nixos/optional/nswitch-rcm.nix" + "${self}/modules/nixos/optional/virtualbox.nix" + "${self}/modules/nixos/optional/work.nix" - inputs.home-manager.nixosModules.home-manager - { - home-manager.users.swarsel.imports = outputs.mixedModules ++ [ - "${profilesPath}/optional/home/gaming.nix" - "${profilesPath}/optional/home/work.nix" - ] ++ (builtins.attrValues outputs.homeManagerModules); - } - ] ++ (builtins.attrValues outputs.nixosModules); - - - nixpkgs = { - overlays = [ outputs.overlays.default ]; - config = { - allowUnfree = true; - }; - }; - - networking.networkmanager.wifi.scanRandMacAddress = false; - - boot = { - loader.systemd-boot.enable = lib.mkForce false; - loader.efi.canTouchEfiVariables = true; - lanzaboote = { - enable = true; - pkiBundle = "/etc/secureboot"; - }; - supportedFilesystems = [ "btrfs" ]; - kernelPackages = lib.mkDefault pkgs.linuxPackages_latest; - kernelParams = [ - "resume_offset=533760" - ]; - resumeDevice = "/dev/disk/by-label/nixos"; - }; - - hardware = { - amdgpu = { - opencl.enable = true; - amdvlk = { - enable = true; - support32Bit.enable = true; - }; - }; - }; - - programs.fw-fanctrl.enable = true; - - networking = { - hostName = "nbl-imba-2"; - fqdn = "nbl-imba-2.imp.univie.ac.at"; - firewall.enable = true; - }; - - - services = { - fwupd.enable = true; - udev.extraRules = '' - ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="0bda", ATTR{idProduct}=="8156", ATTR{power/autosuspend}="20" - ''; - }; + ]; swarselsystems = { - wallpaper = self + /wallpaper/lenovowp.png; - hasBluetooth = true; - hasFingerprint = true; - impermanence = false; - isBtrfs = true; - }; - - home-manager.users.swarsel.swarselsystems = { + lowResolution = "1280x800"; + highResolution = "2560x1600"; isLaptop = true; isNixos = true; isBtrfs = true; - flakePath = "/home/swarsel/.dotfiles"; - cpuCount = 16; - # temperatureHwmon = { - # isAbsolutePath = true; - # path = "/sys/devices/platform/thinkpad_hwmon/hwmon/"; - # input-filename = "temp1_input"; - # }; - # ------ ----- - # | DP-4 | |eDP-1| - # ------ ----- - startup = [ - { command = "nextcloud --background"; } - { command = "vesktop --start-minimized --enable-speech-dispatcher --ozone-platform-hint=auto --enable-features=WaylandWindowDecorations --enable-wayland-ime"; } - { command = "element-desktop --hidden --enable-features=UseOzonePlatform --ozone-platform=wayland --disable-gpu-driver-bug-workarounds"; } - { command = "ANKI_WAYLAND=1 anki"; } - { command = "OBSIDIAN_USE_WAYLAND=1 obsidian"; } - { command = "nm-applet"; } - { command = "teams-for-linux"; } - { command = "1password"; } - { command = "feishin"; } - ]; + isLinux = true; sharescreen = "eDP-2"; + info = "Framework Laptop 16, 7940HS, RX7700S, 64GB RAM"; + firewall = lib.mkForce true; + wallpaper = self + /files/wallpaper/lenovowp.png; + hasBluetooth = true; + hasFingerprint = true; + isImpermanence = false; + isSecureBoot = true; + isCrypted = true; + inherit (config.repo.secrets.local) hostName; + inherit (config.repo.secrets.local) fqdn; + hibernation.offset = 533760; + }; + + home-manager.users."${primaryUser}" = { + swarselsystems = { + isSecondaryGpu = true; + SecondaryGpuCard = "pci-0000_03_00_0"; + cpuCount = 16; + temperatureHwmon = { + isAbsolutePath = true; + path = "/sys/devices/virtual/thermal/thermal_zone0/"; + input-filename = "temp4_input"; + }; + monitors = { + main = { + # name = "BOE 0x0BC9 Unknown"; + name = "BOE 0x0BC9"; + mode = "2560x1600"; # TEMPLATE + scale = "1"; + position = "2560,0"; + workspace = "15:L"; + output = "eDP-2"; + }; + }; + }; + }; + } // lib.optionalAttrs (!minimal) { + swarselprofiles = { + personal = true; + }; + } + +#+end_src + +***** hardware-configuration +:PROPERTIES: +:CUSTOM_ID: h:25115a54-c634-4896-9a41-254064ce9fcc +:END: + +#+begin_src nix-ts :tangle hosts/nixos/x86_64-linux/pyramid/hardware-configuration.nix + { config, lib, pkgs, modulesPath, ... }: + { + imports = + [ + (modulesPath + "/installer/scan/not-detected.nix") + ]; + + # Fix Wlan after suspend or Hibernate + # environment.etc."systemd/system-sleep/fix-wifi.sh".source = + # pkgs.writeShellScript "fix-wifi.sh" '' + # case $1/$2 in + # pre/*) + # ${pkgs.kmod}/bin/modprobe -r mt7921e mt792x_lib mt76 + # echo 1 > /sys/bus/pci/devices/0000:04:00.0/remove + # ;; + + # post/*) + # ${pkgs.kmod}/bin/modprobe mt7921e + # echo 1 > /sys/bus/pci/rescan + # ;; + # esac + # ''; + + boot = { + kernelPackages = lib.mkDefault pkgs.kernel.linuxPackages; + # kernelPackages = lib.mkDefault pkgs.linuxPackages_latest; + binfmt.emulatedSystems = [ "aarch64-linux" ]; + initrd = { + availableKernelModules = [ "nvme" "xhci_pci" "thunderbolt" "usb_storage" "cryptd" "usbhid" "sd_mod" "r8152" ]; + # allow to remote build on arm (needed for moonside) + kernelModules = [ "sg" ]; + luks.devices."cryptroot" = { + # improve performance on ssds + bypassWorkqueues = true; + preLVM = true; + # crypttabExtraOpts = ["fido2-device=auto"]; + }; + }; + + kernelModules = [ "kvm-amd" ]; + kernelParams = [ + # deep sleep is discontinued by amd + # "mem_sleep_default=deep" + # supposedly, this helps save power on laptops + # in reality (at least on this model), this just generate excessive heat on the CPUs + # "amd_pstate=passive" + + # Fix screen flickering issue at the cost of battery life (disable PSR and PSR-SU, keep PR enabled) + # TODO: figure out if this is worth it + # test PSR/PR state with 'sudo grep '' /sys/kernel/debug/dri/0000*/eDP-2/*_capability' + # ref: + # https://old.reddit.com/r/framework/comments/1goh7hc/anyone_else_get_this_screen_flickering_issue/ + # https://www.reddit.com/r/NixOS/comments/1hjruq1/graphics_corruption_on_kernel_6125_and_up/ + # https://gitlab.freedesktop.org/drm/amd/-/issues/3797 + "amdgpu.dcdebugmask=0x410" + ]; + + extraModulePackages = [ ]; + }; + + # Enables DHCP on each ethernet and wireless interface. In case of scripted networking + # (the default) this is the recommended approach. When using systemd-networkd it's + # still possible to use this option, but it's recommended to use it in conjunction + # with explicit per-interface declarations with `networking.interfaces..useDHCP`. + networking.useDHCP = lib.mkDefault true; + # networking.interfaces.enp196s0f3u1c2.useDHCP = lib.mkDefault true; + # networking.interfaces.wlp4s0.useDHCP = lib.mkDefault true; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; + } + + +#+end_src +***** disko +:PROPERTIES: +:CUSTOM_ID: h:e0da04c7-4199-44b0-b525-6cfc64072b45 +:END: + +#+begin_src nix-ts :tangle hosts/nixos/x86_64-linux/pyramid/disk-config.nix + { + disko.devices = { + disk = { + nvme0n1 = { + type = "disk"; + device = "/dev/nvme0n1"; + content = { + type = "gpt"; + partitions = { + ESP = { + label = "boot"; + name = "ESP"; + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ + "defaults" + ]; + }; + }; + luks = { + size = "100%"; + label = "luks"; + content = { + type = "luks"; + name = "cryptroot"; + extraOpenArgs = [ + "--allow-discards" + "--perf-no_read_workqueue" + "--perf-no_write_workqueue" + ]; + # https://0pointer.net/blog/unlocking-luks2-volumes-with-tpm2-fido2-pkcs11-security-hardware-on-systemd-248.html + settings = { crypttabExtraOpts = [ "fido2-device=auto" "token-timeout=10" ]; }; + content = { + type = "btrfs"; + extraArgs = [ "-L" "nixos" "-f" ]; + subvolumes = { + "/root" = { + mountpoint = "/"; + mountOptions = [ "subvol=root" "compress=zstd" "noatime" ]; + }; + "/home" = { + mountpoint = "/home"; + mountOptions = [ "subvol=home" "compress=zstd" "noatime" ]; + }; + "/nix" = { + mountpoint = "/nix"; + mountOptions = [ "subvol=nix" "compress=zstd" "noatime" ]; + }; + "/persist" = { + mountpoint = "/persist"; + mountOptions = [ "subvol=persist" "compress=zstd" "noatime" ]; + }; + "/log" = { + mountpoint = "/var/log"; + mountOptions = [ "subvol=log" "compress=zstd" "noatime" ]; + }; + "/swap" = { + mountpoint = "/swap"; + swap.swapfile.size = "64G"; + }; + }; + }; + }; + }; + }; + }; + }; + }; + }; + + fileSystems = { + "/persist".neededForBoot = true; + "/home".neededForBoot = true; + "/var/log".neededForBoot = true; + }; + } + +#+end_src +**** Bakery (Lenovo ThinkPad) +:PROPERTIES: +:CUSTOM_ID: h:a320569e-7bf0-4552-9039-b2a8e0939a12 +:END: + +My personal laptop. Closely follows the =pyramid= config, but leaves out some security features that I consider a bother on my work machine. + +***** Main Configuration +:PROPERTIES: +:CUSTOM_ID: h:6f80d614-d76a-433b-8956-78d7b323b68c +:END: +#+begin_src nix-ts :tangle hosts/nixos/x86_64-linux/bakery/default.nix + { self, config, inputs, lib, minimal, ... }: + let + primaryUser = config.swarselsystems.mainUser; + in + { + + imports = [ + inputs.nixos-hardware.nixosModules.common-cpu-intel + + ./disk-config.nix + ./hardware-configuration.nix + + "${self}/modules/nixos/optional/gaming.nix" + "${self}/modules/nixos/optional/nswitch-rcm.nix" + "${self}/modules/nixos/optional/virtualbox.nix" + + ]; + + swarselsystems = { + isLaptop = true; + isNixos = true; + isBtrfs = true; + isLinux = true; lowResolution = "1280x800"; - highResolution = "2560x1600"; - monitors = { - main = { - name = "BOE 0x0BC9 Unknown"; - mode = "2560x1600"; # TEMPLATE - scale = "1"; - position = "2560,0"; - workspace = "15:L"; - output = "eDP-2"; - }; - homedesktop = { - name = "Philips Consumer Electronics Company PHL BDM3270 AU11806002320"; - mode = "2560x1440"; - scale = "1"; - position = "0,0"; - workspace = "1:一"; - output = "DP-11"; - }; - work_back_middle = { - name = "LG Electronics LG Ultra HD 0x000305A6"; - mode = "2560x1440"; - scale = "1"; - position = "5120,0"; - workspace = "1:一"; - output = "DP-10"; - }; - work_front_left = { - name = "LG Electronics LG Ultra HD 0x0007AB45"; - mode = "3840x2160"; - scale = "1"; - position = "5120,0"; - workspace = "1:一"; - output = "DP-7"; - }; - work_back_right = { - name = "HP Inc. HP Z32 CN41212T55"; - mode = "3840x2160"; - scale = "1"; - position = "5120,0"; - workspace = "1:一"; - output = "DP-3"; - }; - work_middle_middle_main = { - name = "HP Inc. HP 732pk CNC4080YL5"; - mode = "3840x2160"; - scale = "1"; - position = "-1280,0"; - workspace = "11:M"; - output = "DP-8"; - }; - work_middle_middle_side = { - name = "Hewlett Packard HP Z24i CN44250RDT"; - mode = "1920x1200"; - transform = "270"; - scale = "1"; - position = "-2480,0"; - workspace = "12:S"; - output = "DP-9"; - }; - work_seminary = { - name = "Applied Creative Technology Transmitter QUATTRO201811"; - mode = "1280x720"; - scale = "1"; - position = "10000,10000"; # i.e. this screen is inaccessible by moving the mouse - workspace = "12:S"; - output = "DP-4"; + highResolution = "1920x1080"; + sharescreen = "eDP-1"; + info = "Lenovo Ideapad 720S-13IKB"; + firewall = lib.mkForce true; + wallpaper = self + /files/wallpaper/lenovowp.png; + hasBluetooth = true; + hasFingerprint = true; + isImpermanence = true; + isSecureBoot = false; + isCrypted = true; + isSwap = true; + rootDisk = "/dev/nvme0n1"; + swapSize = "4G"; + }; + + home-manager.users."${primaryUser}" = { + # home.stateVersion = lib.mkForce "23.05"; + swarselsystems = { + monitors = { + main = { + name = "LG Display 0x04EF Unknown"; + mode = "1920x1080"; # TEMPLATE + scale = "1"; + position = "1920,0"; + workspace = "15:L"; + output = "eDP-1"; + }; }; }; - inputs = { - "12972:18:Framework_Laptop_16_Keyboard_Module_-_ANSI_Keyboard" = { - xkb_layout = "us"; - xkb_variant = "altgr-intl"; - }; - "1133:45081:MX_Master_2S_Keyboard" = { - xkb_layout = "us"; - xkb_variant = "altgr-intl"; - }; - "2362:628:PIXA3854:00_093A:0274_Touchpad" = { - dwt = "enabled"; - tap = "enabled"; - natural_scroll = "enabled"; - middle_emulation = "enabled"; - }; - "1133:50504:Logitech_USB_Receiver" = { - xkb_layout = "us"; - xkb_variant = "altgr-intl"; - }; - "1133:45944:MX_KEYS_S" = { - xkb_layout = "us"; - xkb_variant = "altgr-intl"; - }; - }; - keybindings = { - "Mod4+Ctrl+Shift+p" = "exec screenshare"; - }; - shellAliases = { - ans2-15_3-9 = ". ~/.venvs/ansible39_2_15_0/bin/activate"; - ans3-9 = ". ~/.venvs/ansible39/bin/activate"; - ans = ". ~/.venvs/ansible/bin/activate"; - ans2-15 = ". ~/.venvs/ansible2.15.0/bin/activate"; - }; + }; + } // lib.optionalAttrs (!minimal) { + swarselprofiles = { + personal = true; }; } #+end_src -**** Winters (Server) +***** hardware-configuration +:PROPERTIES: +:CUSTOM_ID: h:bbba1646-fb5f-4d04-baf0-f606037a8b39 +:END: + +#+begin_src nix-ts :tangle hosts/nixos/x86_64-linux/bakery/hardware-configuration.nix + # Do not modify this file! It was generated by ‘nixos-generate-config’ + # and may be overwritten by future invocations. Please make changes + # to /etc/nixos/configuration.nix instead. + { config, lib, modulesPath, ... }: + + { + imports = + [ + (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot = { + initrd = { + availableKernelModules = [ "xhci_pci" "nvme" "usb_storage" "sd_mod" ]; + kernelModules = [ ]; + }; + kernelModules = [ ]; + extraModulePackages = [ ]; + }; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; + } +#+end_src +***** disko +:PROPERTIES: +:CUSTOM_ID: h:72444f85-7951-47c0-858f-b51d8299de8c +:END: + +#+begin_src nix-ts :tangle hosts/nixos/x86_64-linux/bakery/disk-config.nix + { lib, pkgs, config, ... }: + let + type = "btrfs"; + extraArgs = [ "-L" "nixos" "-f" ]; # force overwrite + subvolumes = { + "/root" = { + mountpoint = "/"; + mountOptions = [ + "subvol=root" + "compress=zstd" + "noatime" + ]; + }; + "/home" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/home"; + mountOptions = [ + "subvol=home" + "compress=zstd" + "noatime" + ]; + }; + "/persist" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/persist"; + mountOptions = [ + "subvol=persist" + "compress=zstd" + "noatime" + ]; + }; + "/log" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/var/log"; + mountOptions = [ + "subvol=log" + "compress=zstd" + "noatime" + ]; + }; + "/nix" = { + mountpoint = "/nix"; + mountOptions = [ + "subvol=nix" + "compress=zstd" + "noatime" + ]; + }; + "/swap" = lib.mkIf config.swarselsystems.isSwap { + mountpoint = "/.swapvol"; + swap.swapfile.size = config.swarselsystems.swapSize; + }; + }; + in + { + disko.devices = { + disk = { + disk0 = { + type = "disk"; + device = config.swarselsystems.rootDisk; + content = { + type = "gpt"; + partitions = { + ESP = { + priority = 1; + name = "ESP"; + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "defaults" ]; + }; + }; + root = lib.mkIf (!config.swarselsystems.isCrypted) { + size = "100%"; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/disk/by-label/nixos" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + luks = lib.mkIf config.swarselsystems.isCrypted { + size = "100%"; + content = { + type = "luks"; + name = "cryptroot"; + passwordFile = "/tmp/disko-password"; # this is populated by bootstrap.sh + settings = { + allowDiscards = true; + # https://github.com/hmajid2301/dotfiles/blob/a0b511c79b11d9b4afe2a5e2b7eedb2af23e288f/systems/x86_64-linux/framework/disks.nix#L36 + crypttabExtraOpts = [ + "fido2-device=auto" + "token-timeout=10" + ]; + }; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/mapper/cryptroot" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + }; + }; + }; + }; + }; + }; + + fileSystems."/persist".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + fileSystems."/home".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + + environment.systemPackages = [ + pkgs.yubikey-manager + ]; + } + +#+end_src +**** Winters (Server: ASRock J4105-ITX) :PROPERTIES: :CUSTOM_ID: h:932ef6b0-4c14-4200-8e3f-2e208e748746 :END: This is my main server that I run at home. It handles most tasks that require bigger amounts of storage than I can receive for free at OCI. Also it houses some data that I find too sensitive to hand over to Oracle. -#+begin_src nix :tangle hosts/nixos/winters/default.nix - { self, inputs, outputs, config, ... }: - let - profilesPath = "${self}/profiles"; - in +***** Main Configuration +:PROPERTIES: +:CUSTOM_ID: h:8ad68406-4a75-45ba-97ad-4c310b921124 +:END: +#+begin_src nix-ts :tangle hosts/nixos/x86_64-linux/winters/default.nix + { lib, minimal, ... }: { imports = [ - inputs.sops-nix.nixosModules.sops - ./hardware-configuration.nix - - "${profilesPath}/optional/nixos/autologin.nix" - "${profilesPath}/server/nixos" - - inputs.home-manager.nixosModules.home-manager - { - home-manager.users.swarsel.imports = [ - "${profilesPath}/server/home" - ] ++ (builtins.attrValues outputs.homeManagerModules); - } - - ] ++ (builtins.attrValues outputs.nixosModules); - - - nixpkgs = { - overlays = [ outputs.overlays.default ]; - config = { - allowUnfree = true; - }; - }; + ]; boot = { loader.systemd-boot.enable = true; loader.efi.canTouchEfiVariables = true; }; - networking = { - hostName = "winters"; - hostId = "b7778a4a"; - firewall.enable = true; - enableIPv6 = false; - firewall.allowedTCPPorts = [ 80 443 ]; - }; - + # globals.hosts.${config.node.name}.ipv4 = config.repo.secrets.local.ipv4; + # globals.networks.home.hosts.${config.node.name} = { + # ipv4 = config.repo.secrets.local.home-ipv4; + # mac = config.repo.secrets.local.home-mac; + # }; swarselsystems = { - hasBluetooth = false; - hasFingerprint = false; - impermanence = false; + info = "ASRock J4105-ITX, 32GB RAM"; + flakePath = "/root/.dotfiles"; + isImpermanence = false; + isSecureBoot = false; + isCrypted = false; isBtrfs = false; - flakePath = "/home/swarsel/.dotfiles"; + isLinux = true; + isNixos = true; + proxyHost = "moonside"; server = { - enable = true; - kavita = true; - navidrome = true; - jellyfin = true; - spotifyd = true; + restic = { + bucketName = "SwarselWinters"; + paths = [ + "/Vault/data/paperless" + "/Vault/data/koillection" + "/Vault/data/postgresql" + "/Vault/data/firefly-iii" + "/Vault/data/radicale" + "/Vault/data/matrix-synapse" + "/Vault/Eternor/Paperless" + "/Vault/Eternor/Bilder" + "/Vault/Eternor/Immich" + ]; + }; + garage = { + data_dir = { + capacity = "200G"; + path = "/Vault/data/garage/data"; + }; + }; + }; + }; + + } // lib.optionalAttrs (!minimal) { + + swarselprofiles = { + server = true; + }; + + swarselmodules.server = { + diskEncryption = lib.mkForce false; + nfs = lib.mkDefault true; + nginx = lib.mkDefault true; + kavita = lib.mkDefault true; + restic = lib.mkDefault true; + jellyfin = lib.mkDefault true; + navidrome = lib.mkDefault true; + spotifyd = lib.mkDefault true; + mpd = lib.mkDefault true; + postgresql = lib.mkDefault true; + matrix = lib.mkDefault true; + nextcloud = lib.mkDefault true; + immich = lib.mkDefault true; + paperless = lib.mkDefault true; + transmission = lib.mkDefault true; + syncthing = lib.mkDefault true; + grafana = lib.mkDefault true; + emacs = lib.mkDefault true; + freshrss = lib.mkDefault true; + jenkins = lib.mkDefault false; + kanidm = lib.mkDefault true; + firefly-iii = lib.mkDefault true; + koillection = lib.mkDefault true; + radicale = lib.mkDefault true; + atuin = lib.mkDefault true; + forgejo = lib.mkDefault true; + ankisync = lib.mkDefault true; + # snipeit = lib.mkDefault false; + homebox = lib.mkDefault true; + opkssh = lib.mkDefault true; + garage = lib.mkDefault false; + }; + + } + +#+end_src + +***** hardware-configuration +:PROPERTIES: +:CUSTOM_ID: h:0fdefb4f-ce53-4caf-89ed-5d79646f70f0 +:END: +#+begin_src nix-ts :tangle hosts/nixos/x86_64-linux/winters/hardware-configuration.nix + { config, lib, modulesPath, ... }: + + { + imports = + [ + (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot = { + initrd.availableKernelModules = [ "ahci" "xhci_pci" "usbhid" "usb_storage" "sd_mod" ]; + initrd.kernelModules = [ ]; + kernelModules = [ "kvm-intel" ]; + extraModulePackages = [ ]; + + supportedFilesystems = [ "zfs" ]; + zfs.extraPools = [ "Vault" ]; + }; + + fileSystems = { + "/" = + { + device = "/dev/disk/by-uuid/30e2f96a-b01d-4c27-9ebb-d5d7e9f0031f"; + fsType = "ext4"; + }; + + "/boot" = + { + device = "/dev/disk/by-uuid/F0D8-8BD1"; + fsType = "vfat"; + }; + }; + + swapDevices = + [{ device = "/dev/disk/by-uuid/a8eb6f3b-69bf-4160-90aa-9247abc108e0"; }]; + + # Enables DHCP on each ethernet and wireless interface. In case of scripted networking + # (the default) this is the recommended approach. When using systemd-networkd it's + # still possible to use this option, but it's recommended to use it in conjunction + # with explicit per-interface declarations with `networking.interfaces..useDHCP`. + networking.useDHCP = lib.mkDefault true; + # networking.interfaces.enp3s0.useDHCP = lib.mkDefault true; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; + } +#+end_src +**** Summers (Server: ASUS Z10PA-D8) +:PROPERTIES: +:CUSTOM_ID: h:82bf7fb1-631b-4acd-966b-d0c71a9eb463 +:END: + +***** Main Configuration +:PROPERTIES: +:CUSTOM_ID: h:dc2233df-cd78-43cc-bb45-57568a83fb24 +:END: +#+begin_src nix-ts :tangle hosts/nixos/x86_64-linux/summers/default.nix + { self, inputs, lib, config, minimal, nodes, globals, ... }: + { + + imports = [ + ./hardware-configuration.nix + ./disk-config.nix + + "${self}/modules/nixos/optional/microvm-host.nix" + ]; + + boot = { + loader.systemd-boot.enable = true; + loader.efi.canTouchEfiVariables = true; + }; + + swarselsystems = { + info = "ASUS Z10PA-D8, 2* Intel Xeon E5-2650 v4, 128GB RAM"; + flakePath = "/root/.dotfiles"; + isImpermanence = true; + isSecureBoot = true; + isCrypted = true; + isBtrfs = true; + isLinux = true; + isNixos = true; + withMicroVMs = false; + }; + + } // lib.optionalAttrs (!minimal) { + + swarselprofiles = { + server = true; + }; + + swarselmodules = { + server = { + diskEncryption = lib.mkForce false; # TODO: disable + nfs = false; + nginx = false; + kavita = false; + restic = false; + jellyfin = false; + navidrome = false; + spotifyd = false; mpd = false; - matrix = true; - nextcloud = true; - immich = true; - paperless = true; - transmission = true; - syncthing = true; - monitoring = true; - freshrss = true; + postgresql = false; + matrix = false; + nextcloud = false; + immich = false; + paperless = false; + transmission = false; + syncthing = false; + grafana = false; + emacs = false; + freshrss = false; + jenkins = false; + kanidm = false; + firefly-iii = false; + koillection = false; + radicale = false; + atuin = false; + forgejo = false; + ankisync = false; + homebox = false; + opkssh = false; + garage = false; + }; + }; + + microvm.vms = + let + mkMicrovm = guestName: { + ${guestName} = { + backend = "microvm"; + autostart = true; + modules = [ + ./guests/${guestName}.nix + { + node.secretsDir = ./secrets/${guestName}; + } + ]; + microvm = { + system = "x86_64-linux"; + # baseMac = config.repo.secrets.local.networking.interfaces.lan.mac; + # interfaces.vlan-services = { }; + }; + specialArgs = { + inherit (config) nodes globals; + inherit lib; + inherit inputs minimal; + }; + }; + }; + in + lib.mkIf (!minimal && config.swarselsystems.withMicroVMs) ( + { } + // mkMicrovm "guest1" + ); + + } + +#+end_src + +***** hardware-configuration +:PROPERTIES: +:CUSTOM_ID: h:394b1f22-a61b-41da-9fe7-7625f164ed57 +:END: +#+begin_src nix-ts :tangle hosts/nixos/x86_64-linux/summers/hardware-configuration.nix + { config, lib, modulesPath, ... }: + + { + imports = + [ + (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot = { + initrd.availableKernelModules = [ "ahci" "xhci_pci" "usbhid" "usb_storage" "sd_mod" ]; + initrd.kernelModules = [ ]; + kernelModules = [ "kvm-intel" ]; + extraModulePackages = [ ]; + + supportedFilesystems = [ "zfs" ]; + zfs.extraPools = [ "Vault" ]; + }; + + # Enables DHCP on each ethernet and wireless interface. In case of scripted networking + # (the default) this is the recommended approach. When using systemd-networkd it's + # still possible to use this option, but it's recommended to use it in conjunction + # with explicit per-interface declarations with `networking.interfaces..useDHCP`. + networking.useDHCP = lib.mkDefault true; + # networking.interfaces.enp3s0.useDHCP = lib.mkDefault true; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; + } +#+end_src +***** disko +:PROPERTIES: +:CUSTOM_ID: h:664b45fd-bd7e-4fff-bfc5-29f7a0657be6 +:END: + +#+begin_src nix-ts :tangle hosts/nixos/x86_64-linux/summers/disk-config.nix + { lib, config, ... }: + let + type = "btrfs"; + extraArgs = [ "-L" "nixos" "-f" ]; # force overwrite + subvolumes = { + "/root" = { + mountpoint = "/"; + mountOptions = [ + "subvol=root" + "compress=zstd" + "noatime" + ]; + }; + "/home" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/home"; + mountOptions = [ + "subvol=home" + "compress=zstd" + "noatime" + ]; + }; + "/persist" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/persist"; + mountOptions = [ + "subvol=persist" + "compress=zstd" + "noatime" + ]; + }; + "/log" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/var/log"; + mountOptions = [ + "subvol=log" + "compress=zstd" + "noatime" + ]; + }; + "/nix" = { + mountpoint = "/nix"; + mountOptions = [ + "subvol=nix" + "compress=zstd" + "noatime" + ]; + }; + "/swap" = lib.mkIf config.swarselsystems.isSwap { + mountpoint = "/.swapvol"; + swap.swapfile.size = config.swarselsystems.swapSize; + }; + }; + in + { + disko.devices = { + disk = { + disk0 = { + type = "disk"; + device = config.swarselsystems.rootDisk; + content = { + type = "gpt"; + partitions = { + ESP = { + priority = 1; + name = "ESP"; + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "defaults" ]; + }; + }; + root = lib.mkIf (!config.swarselsystems.isCrypted) { + size = "100%"; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/disk/by-label/nixos" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + luks = lib.mkIf config.swarselsystems.isCrypted { + size = "100%"; + content = { + type = "luks"; + name = "cryptroot"; + passwordFile = "/tmp/disko-password"; # this is populated by bootstrap.sh + settings = { + allowDiscards = true; + # https://github.com/hmajid2301/dotfiles/blob/a0b511c79b11d9b4afe2a5e2b7eedb2af23e288f/systems/x86_64-linux/framework/disks.nix#L36 + crypttabExtraOpts = [ + "fido2-device=auto" + "token-timeout=10" + ]; + }; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/mapper/cryptroot" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + }; + }; + }; + }; + }; + }; + + fileSystems."/persist".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + fileSystems."/home".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + } +#+end_src +***** Guests +:PROPERTIES: +:CUSTOM_ID: h:5e571d89-6590-4aa4-a5f4-5c871683d09b +:END: +****** Guest 1 +:PROPERTIES: +:CUSTOM_ID: h:b9af4b1c-f35a-48a5-afa7-030c2be9c808 +:END: +#+begin_src nix-ts :tangle hosts/nixos/x86_64-linux/summers/guests/guest1/default.nix + { self,lib, minimal, ... }: + { + imports = [ + "${self}/modules/nixos/optional/microvm-guest.nix" + ]; + + swarselsystems = { + info = "ASUS Z10PA-D8, 2* Intel Xeon E5-2650 v4, 128GB RAM"; + }; + + } // lib.optionalAttrs (!minimal) { + + swarselprofiles = { + server = false; + }; + + microvm = { + mem = 1024 * 4; + vcpu = 2; + }; + + } + +#+end_src + +**** Hintbooth (Router: HUNSN RM02) +:PROPERTIES: +:CUSTOM_ID: h:58c7563e-6954-42e6-a622-9d06523e8e24 +:END: + +***** Main Configuration +:PROPERTIES: +:CUSTOM_ID: h:624b3c6a-6e31-4734-a6ea-7c5b461a3429 +:END: +#+begin_src nix-ts :tangle hosts/nixos/x86_64-linux/hintbooth/default.nix + { lib, minimal, ... }: + { + + imports = [ + ./hardware-configuration.nix + ./disk-config.nix + ]; + + swarselsystems = { + info = "HUNSN RM02, 8GB RAM"; + flakePath = "/root/.dotfiles"; + isImpermanence = true; + isSecureBoot = true; + isCrypted = true; + isBtrfs = true; + isLinux = true; + isNixos = true; + rootDisk = "/dev/sda"; + swapSize = "8G"; + networkKernelModules = [ "igb" ]; + }; + + } // lib.optionalAttrs (!minimal) { + + swarselprofiles = { + server = true; + router = false; + }; + + swarselmodules = { + server = { + nginx = lib.mkForce false; # we get this from the server profile }; }; } - #+end_src -**** nbm-imba-166 (MacBook Pro) +***** hardware-configuration +:PROPERTIES: +:CUSTOM_ID: h:b4a0b41c-52eb-4f0b-ba0b-64036c52e594 +:END: +#+begin_src nix-ts :tangle hosts/nixos/x86_64-linux/hintbooth/hardware-configuration.nix + { config, lib, modulesPath, ... }: + + { + imports = + [ + (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot = { + initrd.availableKernelModules = [ "ahci" "xhci_pci" "usbhid" "usb_storage" "sd_mod" ]; + initrd.kernelModules = [ ]; + extraModulePackages = [ ]; + }; + + # Enables DHCP on each ethernet and wireless interface. In case of scripted networking + # (the default) this is the recommended approach. When using systemd-networkd it's + # still possible to use this option, but it's recommended to use it in conjunction + # with explicit per-interface declarations with `networking.interfaces..useDHCP`. + networking.useDHCP = lib.mkDefault true; + # networking.interfaces.enp3s0.useDHCP = lib.mkDefault true; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; + } +#+end_src +***** disko +:PROPERTIES: +:CUSTOM_ID: h:1500fb57-334b-4f1b-92de-566ea07924d1 +:END: + +#+begin_src nix-ts :tangle hosts/nixos/x86_64-linux/hintbooth/disk-config.nix + { lib, config, ... }: + let + type = "btrfs"; + extraArgs = [ "-L" "nixos" "-f" ]; # force overwrite + subvolumes = { + "/root" = { + mountpoint = "/"; + mountOptions = [ + "subvol=root" + "compress=zstd" + "noatime" + ]; + }; + "/home" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/home"; + mountOptions = [ + "subvol=home" + "compress=zstd" + "noatime" + ]; + }; + "/persist" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/persist"; + mountOptions = [ + "subvol=persist" + "compress=zstd" + "noatime" + ]; + }; + "/log" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/var/log"; + mountOptions = [ + "subvol=log" + "compress=zstd" + "noatime" + ]; + }; + "/nix" = { + mountpoint = "/nix"; + mountOptions = [ + "subvol=nix" + "compress=zstd" + "noatime" + ]; + }; + "/swap" = lib.mkIf config.swarselsystems.isSwap { + mountpoint = "/.swapvol"; + swap.swapfile.size = config.swarselsystems.swapSize; + }; + }; + in + { + disko.devices = { + disk = { + disk0 = { + type = "disk"; + device = config.swarselsystems.rootDisk; + content = { + type = "gpt"; + partitions = { + ESP = { + priority = 1; + name = "ESP"; + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "defaults" ]; + }; + }; + root = lib.mkIf (!config.swarselsystems.isCrypted) { + size = "100%"; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/disk/by-label/nixos" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + luks = lib.mkIf config.swarselsystems.isCrypted { + size = "100%"; + content = { + type = "luks"; + name = "cryptroot"; + passwordFile = "/tmp/disko-password"; # this is populated by bootstrap.sh + settings = { + allowDiscards = true; + # https://github.com/hmajid2301/dotfiles/blob/a0b511c79b11d9b4afe2a5e2b7eedb2af23e288f/systems/x86_64-linux/framework/disks.nix#L36 + crypttabExtraOpts = [ + "fido2-device=auto" + "token-timeout=10" + ]; + }; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/mapper/cryptroot" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + }; + }; + }; + }; + }; + }; + + fileSystems."/persist".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + fileSystems."/home".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + } +#+end_src +**** machpizza (MacBook Pro) :PROPERTIES: :CUSTOM_ID: h:28e1a7eb-356b-4015-83f7-9c552c8c0e9d :END: -A Mac notebook that I have received from work. I use this machine for getting accustomed to the Apple ecosystem as well as as a sandbox for nix-darwin configurations. +A Mac notebook that I have received from work. I use this machine for getting accustomed to the Apple ecosystem as well as as a sandbox for nix-darwin configurations (the darwin configuration is severely under-developed). -#+begin_src nix :tangle hosts/darwin/nbm-imba-166/default.nix - { self, inputs, outputs, ... }: +#+begin_src nix-ts :tangle hosts/darwin/x86_64-darwin/machpizza/default.nix + { lib, config, ... }: let - profilesPath = "${self}/profiles"; + inherit (config.repo.secrets.local) workUser; in { - imports = [ - "${profilesPath}/darwin/common/nixos" - - inputs.home-manager.darwinModules.home-manager - { - home-manager.users."leon.schwarzaeugl".imports = [ - "${profilesPath}/darwin/common/home" - ] ++ (builtins.attrValues outputs.homeManagerModules); - } - ] ++ (builtins.attrValues outputs.nixosModules); - # Auto upgrade nix package and the daemon service. services.nix-daemon.enable = true; services.karabiner-elements.enable = true; - home-manager.users."leon.schwarzaeugl".home = { - username = lib.mkForce "leon.schwarzaeugl"; + home-manager.users.workUser.home = { + username = lib.mkForce workUser; swarselsystems = { isDarwin = true; isLaptop = true; isNixos = false; isBtrfs = false; + mainUser = workUser; + homeDir = "/home/${workUser}"; + flakePath = "/home/${workUser}/.dotfiles"; }; }; - - } #+end_src @@ -1553,7 +3339,7 @@ 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 :tangle hosts/nix-on-droid/magicant/default.nix +#+begin_src nix-ts :tangle hosts/android/aarch64-linux/magicant/default.nix { pkgs, ... }: { environment = { @@ -1603,343 +3389,22 @@ My phone. I use only a minimal config for remote debugging here. #+end_src -*** Virtual hosts +**** Treehouse (DGX Spark) :PROPERTIES: -:CUSTOM_ID: h:4dc59747-9598-4029-aa7d-92bf186d6c06 +:CUSTOM_ID: h:ced1795a-9884-4277-bcde-6f7b9b1cc2f0 :END: -My server setup was originally built on Proxmox VE; back when I started, I created all kinds of wild Debian/Ubuntu/etc. KVMs and LXCs on there. However, the root disk has suffered a weird failure where it has become unable to be cloned, but it is still functional for now. I was for a long time rewriting all machines on there to use NixOS instead; this process is now finished. - -I have removed most of the machines from this section. What remains are some hosts that I have deployed on OCI (mostly sync for medium-important data) and one other machine that I left for now as a reference. - -**** Toto (QEMU VM) - -#+begin_src nix :tangle hosts/nixos/toto/default.nix - { self, inputs, outputs, config, pkgs, lib, ... }: - let - profilesPath = "${self}/profiles"; - in - { - - imports = [ - inputs.disko.nixosModules.disko - "${self}/hosts/nixos/toto/disk-config.nix" - { - _module.args = { - withSwap = false; - }; - } - ./hardware-configuration.nix - - inputs.sops-nix.nixosModules.sops - - "${profilesPath}/optional/nixos/autologin.nix" - "${profilesPath}/common/nixos/settings.nix" - "${profilesPath}/common/nixos/home-manager.nix" - "${profilesPath}/common/nixos/xserver.nix" - "${profilesPath}/common/nixos/users.nix" - "${profilesPath}/common/nixos/sops.nix" - "${profilesPath}/server/nixos/ssh.nix" - - inputs.home-manager.nixosModules.home-manager - { - home-manager.users.swarsel.imports = [ - inputs.sops-nix.homeManagerModules.sops - "${profilesPath}/common/home/settings.nix" - "${profilesPath}/common/home/sops.nix" - "${profilesPath}/common/home/ssh.nix" - - ] ++ (builtins.attrValues outputs.homeManagerModules); - } - ] ++ (builtins.attrValues outputs.nixosModules); - - - nixpkgs = { - overlays = [ outputs.overlays.default ]; - config = { - allowUnfree = true; - }; - }; - - environment.systemPackages = with pkgs; [ - curl - git - gnupg - rsync - ssh-to-age - sops - vim - just - ]; - - system.stateVersion = lib.mkForce "23.05"; - - boot = { - loader.systemd-boot.enable = lib.mkForce true; - loader.efi.canTouchEfiVariables = true; - supportedFilesystems = [ "btrfs" ]; - kernelPackages = lib.mkDefault pkgs.linuxPackages_latest; - }; - - - networking = { - hostName = "toto"; - firewall.enable = false; - }; - - swarselsystems = { - wallpaper = self + /wallpaper/lenovowp.png; - impermanence = false; - isBtrfs = false; - initialSetup = true; - }; - - home-manager.users.swarsel.swarselsystems = { - isLaptop = false; - isNixos = true; - isBtrfs = false; - flakePath = "/home/swarsel/.dotfiles"; - }; - - } - - -#+end_src - -**** Sync (OCI) -:PROPERTIES: -:CUSTOM_ID: h:4c5febb0-fdf6-44c5-8d51-7ea0f8930abf -:END: - -This machine mainly acts as an external sync helper. It manages the following things: -- Anki syncing -- Forgejo git server -- Elfeed sync server (RSS) -- Syncthing backup of replaceable data - - All of these are processes that use little cpu but can take a lot of storage. For this I use a free Ampere instance from OCI with 50G of space. In case my account gets terminated, all of this data is easily replaceable or backed up regularly anyways. - -***** NixOS -:PROPERTIES: -:CUSTOM_ID: h:e5fbb73a-799a-438f-a88c-fc14d110ac9c -:END: - -#+begin_src nix :tangle hosts/nixos/sync/default.nix - { self, inputs, outputs, lib, ... }: - let - profilesPath = "${self}/profiles"; - in - { - imports = [ - - inputs.sops-nix.nixosModules.sops - "${profilesPath}/server/nixos" - ./hardware-configuration.nix - - inputs.home-manager.nixosModules.home-manager - { - home-manager.users.swarsel.imports = [ - "${profilesPath}/server/home" - ] ++ (builtins.attrValues outputs.homeManagerModules); - } - - ] ++ (builtins.attrValues outputs.nixosModules); - - sops = { - defaultSopsFile = lib.mkForce "/root/.dotfiles/secrets/sync/secrets.yaml"; - }; - - - services.nginx = { - virtualHosts = { - "sync.swarsel.win" = { - enableACME = true; - forceSSL = true; - acmeRoot = null; - locations = { - "/" = { - proxyPass = "http://localhost:8384/"; - extraConfig = '' - client_max_body_size 0; - ''; - }; - }; - }; - }; - }; - - boot = { - tmp.cleanOnBoot = true; - loader.grub.device = "nodev"; - }; - zramSwap.enable = false; - - networking = { - firewall.allowedTCPPorts = [ 8384 22000 ]; - firewall.allowedUDPPorts = [ 21027 22000 ]; - hostName = "sync"; - enableIPv6 = false; - domain = "subnet03112148.vcn03112148.oraclevcn.com"; - firewall.extraCommands = '' - iptables -I INPUT -m state --state NEW -p tcp --dport 80 -j ACCEPT - iptables -I INPUT -m state --state NEW -p tcp --dport 443 -j ACCEPT - iptables -I INPUT -m state --state NEW -p tcp --dport 27701 -j ACCEPT - iptables -I INPUT -m state --state NEW -p tcp --dport 8384 -j ACCEPT - iptables -I INPUT -m state --state NEW -p tcp --dport 3000 -j ACCEPT - iptables -I INPUT -m state --state NEW -p tcp --dport 22000 -j ACCEPT - iptables -I INPUT -m state --state NEW -p udp --dport 22000 -j ACCEPT - iptables -I INPUT -m state --state NEW -p udp --dport 21027 -j ACCEPT - iptables -I INPUT -m state --state NEW -p tcp --dport 9812 -j ACCEPT - ''; - }; - - # system.stateVersion = "23.11"; # TEMPLATE - but probably no need to change - - # do not manage OCI syncthing through nix config - services.syncthing = { - enable = true; - guiAddress = "0.0.0.0:8384"; - openDefaultPorts = true; - }; - - - swarselsystems = { - hasBluetooth = false; - hasFingerprint = false; - impermanence = false; - isBtrfs = false; - flakePath = "/root/.dotfiles"; - server = { - enable = true; - forgejo = true; - ankisync = true; - }; - }; - - } - -#+end_src -*** Utility hosts -**** drugstore (ISO) -:PROPERTIES: -:CUSTOM_ID: h:8583371d-5d47-468b-84ba-210aad7e2c90 -:END: - -This is a live environment ISO that I use to bootstrap new systems. It only loads a minimal configuration and no graphical interface. After booting this image on a host, find out its IP and bootstrap the system using the =bootstrap= utility. - -#+begin_src nix :tangle hosts/nixos/iso/default.nix - { self, pkgs, inputs, config, lib, modulesPath, ... }: - let - pubKeys = lib.filesystem.listFilesRecursive "${self}/secrets/keys/ssh"; - in +#+begin_src nix-ts :tangle hosts/home/aarch64-linux/treehouse/default.nix + { self, pkgs, ... }: { imports = [ - - inputs.lanzaboote.nixosModules.lanzaboote - inputs.disko.nixosModules.disko - inputs.impermanence.nixosModules.impermanence - inputs.sops-nix.nixosModules.sops - "${modulesPath}/installer/cd-dvd/installation-cd-minimal.nix" - "${modulesPath}/installer/cd-dvd/channel.nix" - - "${self}/profiles/iso/minimal.nix" - + # inputs.sops-nix.homeManagerModules.sops + "${self}/modules/home" + "${self}/modules/nixos/common/pii.nix" + "${self}/modules/nixos/common/meta.nix" ]; - environment.etc."issue".text = "\\4\n"; - networking.dhcpcd.runHook = "${pkgs.utillinux}/bin/agetty --reload"; - - isoImage = { - makeEfiBootable = true; - makeUsbBootable = true; - squashfsCompression = "zstd -Xcompression-level 3"; - }; - - nixpkgs = { - hostPlatform = lib.mkDefault "x86_64-linux"; - config.allowUnfree = true; - }; - - services.getty.autologinUser = lib.mkForce "swarsel"; - - users = { - allowNoPasswordLogin = true; - groups.swarsel = { }; - users = { - swarsel = { - name = "swarsel"; - group = "swarsel"; - isNormalUser = true; - password = "setup"; # this is overwritten after install - openssh.authorizedKeys.keys = lib.lists.forEach pubKeys (key: builtins.readFile key); - extraGroups = [ "wheel" ]; - }; - root = { - # password = lib.mkForce config.users.users.swarsel.password; # this is overwritten after install - openssh.authorizedKeys.keys = config.users.users.swarsel.openssh.authorizedKeys.keys; - }; - }; - }; - - boot = { - loader.systemd-boot.enable = lib.mkForce true; - loader.efi.canTouchEfiVariables = true; - }; - - programs.bash.shellAliases = { - "swarsel-install" = "nix run github:Swarsel/.dotfiles#install --"; - }; - - system.activationScripts.cache = { - text = '' - mkdir -p /home/swarsel/.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 /home/swarsel/.local/share/nix/trusted-settings.json > /dev/null - 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 > /dev/null - ''; - }; - systemd = { - services.sshd.wantedBy = lib.mkForce [ "multi-user.target" ]; - targets = { - sleep.enable = false; - suspend.enable = false; - hibernate.enable = false; - hybrid-sleep.enable = false; - }; - }; - - system.stateVersion = lib.mkForce "23.05"; - - networking = { - hostName = "drugstore"; - wireless.enable = false; - }; - - } - - -#+end_src - -**** Home-manager only (non-NixOS) -:PROPERTIES: -:CUSTOM_ID: h:7056b9a0-f38b-4bca-b2ba-ab34e2d73493 -:END: - -This is the "reference implementation" of a setup that runs without NixOS, only relying on home-manager. I try to test this every now and then and keep it supported. However, manual steps are needed to get the system to work fully, depending on what distribution you are running on. - -#+begin_src nix :tangle hosts/home-manager/default/default.nix - { self, inputs, outputs, config, ... }: - { - - imports = builtins.attrValues outputs.homeManagerModules; - - nixpkgs = { - overlays = [ outputs.overlays.default ]; - config = { - allowUnfree = true; - }; - }; services.xcape = { enable = true; @@ -1948,39 +3413,24 @@ This is the "reference implementation" of a setup that runs without NixOS, only }; }; - programs.zsh.initExtra = " - export GPG_TTY=\"$(tty)\" - export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket) - gpgconf --launch gpg-agent - "; + home.packages = with pkgs; [ + attic-client + ]; + # programs.zsh.initContent = " + # export GPG_TTY=\"$(tty)\" + # export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket) + # gpgconf --launch gpg-agent + # "; + swarselmodules.pii = true; swarselsystems = { - isLaptop = true; + isLaptop = false; isNixos = false; - wallpaper = self + /wallpaper/surfacewp.png; - temperatureHwmon = { - isAbsolutePath = true; - path = "/sys/devices/platform/thinkpad_hwmon/hwmon/"; - input-filename = "temp1_input"; - }; - monitors = { - main = { - name = "California Institute of Technology 0x1407 Unknown"; - mode = "1920x1080"; # TEMPLATE - scale = "1"; - position = "2560,0"; - workspace = "2:二"; - output = "eDP-1"; - }; - }; - inputs = { - "1:1:AT_Translated_Set_2_keyboard" = { - xkb_layout = "us"; - xkb_options = "grp:win_space_toggle"; - xkb_variant = "altgr-intl"; - }; - }; - keybindings = { }; + wallpaper = self + /files/wallpaper/surfacewp.png; + }; + + swarselprofiles = { + dgxspark = true; }; } @@ -1988,39 +3438,1863 @@ This is the "reference implementation" of a setup that runs without NixOS, only #+end_src -**** ChaosTheatre (Demo) +*** Virtual hosts +:PROPERTIES: +:CUSTOM_ID: h:4dc59747-9598-4029-aa7d-92bf186d6c06 +:END: + +My server setup was originally built on Proxmox VE; back when I started, I created all kinds of wild Debian/Ubuntu/etc. KVMs and LXCs on there. However, the root disk has suffered a weird failure where it has become unable to be cloned, but was still functional. I was for a long time rewriting all machines on there to use NixOS instead; this process is now finished. + +I have removed most of the machines from this section. What remains are some hosts that I have deployed on OCI: + - =MilkyWell=: cloud server used for very lightweight sync tasks of non-critical data + - =Moonside=: Proxy server + some lightweight services + +**** Moonside (OCI) +:PROPERTIES: +:CUSTOM_ID: h:f547ed16-5e6e-4744-9e33-af090e0a175b +:END: + +This machine mainly acts as my proxy server to stand before my local machines. + +***** Main Configuration +:PROPERTIES: +:CUSTOM_ID: h:a8f20a56-ce92-43d8-8bfe-3edccebf2bf9 +:END: + +#+begin_src nix-ts :tangle hosts/nixos/aarch64-linux/moonside/default.nix + { lib, config, minimal, ... }: + let + inherit (config.repo.secrets.local.syncthing) dev1 dev2 dev3 loc1; + inherit (config.swarselsystems) sopsFile; + in + { + imports = [ + ./hardware-configuration.nix + ./disk-config.nix + ]; + + sops = { + age.sshKeyPaths = lib.mkDefault [ "/etc/ssh/ssh_host_ed25519_key" ]; + secrets = { + wireguard-private-key = { inherit sopsFile; }; + wireguard-home-preshared-key = { inherit sopsFile; }; + }; + }; + + boot = { + loader.systemd-boot.enable = true; + tmp.cleanOnBoot = true; + }; + + environment = { + etc."issue".text = "\4"; + }; + + topology.self = { + icon = "devices.cloud-server"; + interfaces.wg = { + addresses = [ "192.168.3.4" ]; + renderer.hidePhysicalConnections = true; + virtual = true; + type = "wireguard"; + }; + }; + + networking = { + domain = "subnet03291956.vcn03291956.oraclevcn.com"; + firewall = { + allowedTCPPorts = [ 8384 ]; + }; + wireguard = { + enable = true; + interfaces = { + home-vpn = { + privateKeyFile = config.sops.secrets.wireguard-private-key.path; + # ips = [ "192.168.3.4/32" ]; + ips = [ "192.168.178.201/24" ]; + peers = [ + { + # publicKey = "NNGvakADslOTCmN9HJOW/7qiM+oJ3jAlSZGoShg4ZWw="; + publicKey = "PmeFInoEJcKx+7Kva4dNnjOEnJ8lbudSf1cbdo/tzgw="; + presharedKeyFile = config.sops.secrets.wireguard-home-preshared-key.path; + name = "moonside"; + persistentKeepalive = 25; + # endpoint = "${config.repo.secrets.common.ipv4}:51820"; + endpoint = "${config.repo.secrets.common.wireguardEndpoint}"; + # allowedIPs = [ + # "192.168.3.0/24" + # "192.168.1.0/24" + # ]; + allowedIPs = [ + "192.168.178.0/24" + ]; + } + ]; + }; + }; + }; + }; + + hardware = { + enableAllFirmware = lib.mkForce false; + }; + + system.stateVersion = "23.11"; + + services.syncthing = { + dataDir = lib.mkForce "/sync"; + settings = { + devices = config.swarselsystems.syncthing.devices // { + "${dev1}" = { + id = "OCCDGDF-IPZ6HHQ-5SSLQ3L-MSSL5ZW-IX5JTAM-PW4PYEK-BRNMJ7E-Q7YDMA7"; + }; + "${dev2}" = { + id = "LPCFIIB-ENUM2V6-F2BWVZ6-F2HXCL2-BSBZXUF-TIMNKYB-7CATP7H-YU5D3AH"; + }; + "${dev3}" = { + id = "LAUT2ZP-KEZY35H-AHR3ARD-URAREJI-2B22P5T-PIMUNWW-PQRDETU-7KIGNQR"; + }; + }; + folders = { + "Documents" = { + path = "/sync/Documents"; + type = "receiveonly"; + versioning = { + type = "simple"; + params.keep = "2"; + }; + devices = [ "pyramid" ]; + id = "hgr3d-pfu3w"; + }; + "runandbun" = { + path = "/sync/runandbun"; + type = "receiveonly"; + versioning = { + type = "simple"; + params.keep = "5"; + }; + devices = [ "winters" "magicant" ]; + id = "kwnql-ev64v"; + }; + "${loc1}" = { + path = "/sync/${loc1}"; + type = "receiveonly"; + versioning = { + type = "simple"; + params.keep = "3"; + }; + devices = [ dev1 dev2 dev3 ]; + id = "5gsxv-rzzst"; + }; + }; + }; + }; + + swarselsystems = { + flakePath = "/root/.dotfiles"; + info = "VM.Standard.A1.Flex, 4 vCPUs, 24GB RAM"; + isImpermanence = true; + isSecureBoot = false; + isCrypted = false; + isSwap = false; + rootDisk = "/dev/sda"; + isBtrfs = true; + isNixos = true; + isLinux = true; + server = { + restic = { + bucketName = "SwarselMoonside"; + paths = [ + "/persist/opt/minecraft" + ]; + }; + }; + syncthing = { + serviceDomain = config.repo.secrets.common.services.domains.syncthing3; + }; + }; + } // lib.optionalAttrs (!minimal) { + swarselprofiles = { + server = true; + }; + + swarselmodules.server = { + oauth2-proxy = true; + croc = true; + microbin = true; + shlink = true; + slink = true; + syncthing = true; + minecraft = true; + restic = true; + diskEncryption = lib.mkForce false; + }; + } + +#+end_src +***** hardware-configuration +:PROPERTIES: +:CUSTOM_ID: h:f99c05ab-f047-4350-b80a-4c1ff55b91bf +:END: + +#+begin_src nix-ts :tangle hosts/nixos/aarch64-linux/moonside/hardware-configuration.nix + { lib, modulesPath, ... }: + { + imports = [ (modulesPath + "/profiles/qemu-guest.nix") ]; + + boot = { + initrd = { + availableKernelModules = [ "xhci_pci" "virtio_pci" "virtio_scsi" "usbhid" ]; + kernelModules = [ ]; + }; + kernelModules = [ ]; + extraModulePackages = [ ]; + }; + + nixpkgs.hostPlatform = lib.mkForce "aarch64-linux"; + } +#+end_src +***** disko +:PROPERTIES: +:CUSTOM_ID: h:cec82b06-39ca-4c0e-b4f5-c1fda9b14e6d +:END: + +#+begin_src nix-ts :tangle hosts/nixos/aarch64-linux/moonside/disk-config.nix + # NOTE: ... is needed because dikso passes diskoFile + { lib + , config + , ... + }: + let + type = "btrfs"; + extraArgs = [ "-L" "nixos" "-f" ]; # force overwrite + subvolumes = { + "/root" = { + mountpoint = "/"; + mountOptions = [ + "subvol=root" + "compress=zstd" + "noatime" + ]; + }; + "/home" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/home"; + mountOptions = [ + "subvol=home" + "compress=zstd" + "noatime" + ]; + }; + "/persist" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/persist"; + mountOptions = [ + "subvol=persist" + "compress=zstd" + "noatime" + ]; + }; + "/log" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/var/log"; + mountOptions = [ + "subvol=log" + "compress=zstd" + "noatime" + ]; + }; + "/nix" = { + mountpoint = "/nix"; + mountOptions = [ + "subvol=nix" + "compress=zstd" + "noatime" + ]; + }; + "/swap" = lib.mkIf config.swarselsystems.isSwap { + mountpoint = "/.swapvol"; + swap.swapfile.size = config.swarselsystems.swapSize; + }; + }; + in + { + disko.devices = { + disk = { + disk0 = { + type = "disk"; + device = config.swarselsystems.rootDisk; + content = { + type = "gpt"; + partitions = { + ESP = { + priority = 1; + name = "ESP"; + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "defaults" ]; + }; + }; + root = { + size = "100%"; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/disk/by-label/nixos" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + }; + }; + }; + disk1 = { + type = "disk"; + device = "/dev/sdb"; + content = { + type = "gpt"; + partitions = { + sync = { + size = "100%"; + content = { + type = "btrfs"; + extraArgs = [ "-L" "sync" "-f" ]; # force overwrite + subvolumes = { + "/sync" = { + mountpoint = "/sync"; + mountOptions = [ + "subvol=root" + "compress=zstd" + "noatime" + ]; + }; + }; + }; + }; + }; + }; + }; + }; + }; + + fileSystems."/persist".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + fileSystems."/home".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + } + + +#+end_src +**** Belchsfactory (OCI) +:PROPERTIES: +:CUSTOM_ID: h:90457194-6b97-4cd6-90bc-4f42d0d69f51 +:END: + +***** Main Configuration +:PROPERTIES: +:CUSTOM_ID: h:cb78799c-d47a-43d4-88ad-d32fcc0abd0b +:END: + +#+begin_src nix-ts :tangle hosts/nixos/aarch64-linux/belchsfactory/default.nix + { self, lib, minimal, ... }: + { + imports = [ + ./hardware-configuration.nix + ./disk-config.nix + + "${self}/modules/nixos/optional/systemd-networkd-server.nix" + ]; + + node.lockFromBootstrapping = lib.mkForce false; + + topology.self = { + icon = "devices.cloud-server"; + }; + swarselmodules.server.nginx = false; + + swarselsystems = { + flakePath = "/root/.dotfiles"; + info = "VM.Standard.A1.Flex, 4 vCPUs, 24GB RAM"; + isImpermanence = true; + isSecureBoot = false; + isCrypted = true; + isSwap = false; + rootDisk = "/dev/sda"; + isBtrfs = true; + isNixos = true; + isLinux = true; + isCloud = true; + server = { + garage = { + data_dir = { + capacity = "150G"; + path = "/var/lib/garage/data"; + }; + keys = { + nixos = [ + "attic" + ]; + }; + buckets = [ + "attic" + ]; + }; + }; + }; + } // lib.optionalAttrs (!minimal) { + swarselprofiles = { + server = true; + }; + + swarselmodules.server = { + ssh-builder = lib.mkDefault true; + postgresql = lib.mkDefault true; + attic = lib.mkDefault true; + garage = lib.mkDefault true; + }; + + } + +#+end_src +***** hardware-configuration +:PROPERTIES: +:CUSTOM_ID: h:e9e29520-5800-4756-ad13-1ec9747ab911 +:END: + +#+begin_src nix-ts :tangle hosts/nixos/aarch64-linux/belchsfactory/hardware-configuration.nix + { lib, modulesPath, ... }: + { + imports = [ (modulesPath + "/profiles/qemu-guest.nix") ]; + + boot = { + initrd = { + availableKernelModules = [ "xhci_pci" "virtio_pci" "virtio_scsi" "usbhid" ]; + kernelModules = [ ]; + }; + kernelModules = [ ]; + extraModulePackages = [ ]; + }; + + nixpkgs.hostPlatform = lib.mkForce "aarch64-linux"; + } +#+end_src +***** disko +:PROPERTIES: +:CUSTOM_ID: h:19a83f57-9e7a-44b9-ae7f-2f021f21abf7 +:END: + +#+begin_src nix-ts :tangle hosts/nixos/aarch64-linux/belchsfactory/disk-config.nix + { lib, pkgs, config, ... }: + let + type = "btrfs"; + extraArgs = [ "-L" "nixos" "-f" ]; # force overwrite + subvolumes = { + "/root" = { + mountpoint = "/"; + mountOptions = [ + "subvol=root" + "compress=zstd" + "noatime" + ]; + }; + "/home" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/home"; + mountOptions = [ + "subvol=home" + "compress=zstd" + "noatime" + ]; + }; + "/persist" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/persist"; + mountOptions = [ + "subvol=persist" + "compress=zstd" + "noatime" + ]; + }; + "/log" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/var/log"; + mountOptions = [ + "subvol=log" + "compress=zstd" + "noatime" + ]; + }; + "/nix" = { + mountpoint = "/nix"; + mountOptions = [ + "subvol=nix" + "compress=zstd" + "noatime" + ]; + }; + "/swap" = lib.mkIf config.swarselsystems.isSwap { + mountpoint = "/.swapvol"; + swap.swapfile.size = config.swarselsystems.swapSize; + }; + }; + in + { + disko = { + imageBuilder.extraDependencies = [ pkgs.kmod ]; + devices = { + disk = { + disk0 = { + type = "disk"; + device = config.swarselsystems.rootDisk; + content = { + type = "gpt"; + partitions = { + ESP = { + priority = 1; + name = "ESP"; + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "defaults" ]; + }; + }; + root = lib.mkIf (!config.swarselsystems.isCrypted) { + size = "100%"; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/disk/by-label/nixos" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + luks = lib.mkIf config.swarselsystems.isCrypted { + size = "100%"; + content = { + type = "luks"; + name = "cryptroot"; + passwordFile = "/tmp/disko-password"; # this is populated by bootstrap.sh + settings = { + allowDiscards = true; + # https://github.com/hmajid2301/dotfiles/blob/a0b511c79b11d9b4afe2a5e2b7eedb2af23e288f/systems/x86_64-linux/framework/disks.nix#L36 + crypttabExtraOpts = [ + "fido2-device=auto" + "token-timeout=10" + ]; + }; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/mapper/cryptroot" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + }; + }; + }; + }; + }; + }; + }; + + fileSystems."/persist".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + fileSystems."/home".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + } + +#+end_src +**** Stoicclub (OCI) + +***** Main Configuration + +#+begin_src nix-ts :tangle hosts/nixos/aarch64-linux/stoicclub/default.nix + { self, lib, minimal, ... }: + { + imports = [ + ./hardware-configuration.nix + ./disk-config.nix + + "${self}/modules/nixos/optional/systemd-networkd-server.nix" + ]; + + topology.self = { + icon = "devices.cloud-server"; + }; + swarselmodules.server.nginx = false; + + + swarselsystems = { + flakePath = "/root/.dotfiles"; + info = "VM.Standard.A1.Flex, 1 vCPUs, 8GB RAM"; + isImpermanence = true; + isSecureBoot = false; + isCrypted = true; + isSwap = false; + rootDisk = "/dev/disk/by-id/scsi-360e1a5236f034316a10a97cc703ce9e3"; + isBtrfs = true; + isNixos = true; + isLinux = true; + isCloud = true; + isBastionTarget = true; + }; + } // lib.optionalAttrs (!minimal) { + swarselprofiles = { + server = true; + }; + + swarselmodules.server = { + nsd = true; + nginx = false; + }; + } + +#+end_src +***** hardware-configuration + +#+begin_src nix-ts :tangle hosts/nixos/aarch64-linux/stoicclub/hardware-configuration.nix + { lib, modulesPath, ... }: + { + imports = [ (modulesPath + "/profiles/qemu-guest.nix") ]; + + boot = { + initrd = { + availableKernelModules = [ "xhci_pci" "virtio_pci" "virtio_scsi" "usbhid" ]; + kernelModules = [ ]; + }; + kernelModules = [ ]; + extraModulePackages = [ ]; + }; + + nixpkgs.hostPlatform = lib.mkForce "aarch64-linux"; + } +#+end_src +***** disko + +#+begin_src nix-ts :tangle hosts/nixos/aarch64-linux/stoicclub/disk-config.nix + { lib, pkgs, config, ... }: + let + type = "btrfs"; + extraArgs = [ "-L" "nixos" "-f" ]; # force overwrite + subvolumes = { + "/root" = { + mountpoint = "/"; + mountOptions = [ + "subvol=root" + "compress=zstd" + "noatime" + ]; + }; + "/home" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/home"; + mountOptions = [ + "subvol=home" + "compress=zstd" + "noatime" + ]; + }; + "/persist" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/persist"; + mountOptions = [ + "subvol=persist" + "compress=zstd" + "noatime" + ]; + }; + "/log" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/var/log"; + mountOptions = [ + "subvol=log" + "compress=zstd" + "noatime" + ]; + }; + "/nix" = { + mountpoint = "/nix"; + mountOptions = [ + "subvol=nix" + "compress=zstd" + "noatime" + ]; + }; + "/swap" = lib.mkIf config.swarselsystems.isSwap { + mountpoint = "/.swapvol"; + swap.swapfile.size = config.swarselsystems.swapSize; + }; + }; + in + { + disko = { + imageBuilder.extraDependencies = [ pkgs.kmod ]; + devices = { + disk = { + disk0 = { + type = "disk"; + device = config.swarselsystems.rootDisk; + content = { + type = "gpt"; + partitions = { + ESP = { + priority = 1; + name = "ESP"; + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "defaults" ]; + }; + }; + root = lib.mkIf (!config.swarselsystems.isCrypted) { + size = "100%"; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/disk/by-label/nixos" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + luks = lib.mkIf config.swarselsystems.isCrypted { + size = "100%"; + content = { + type = "luks"; + name = "cryptroot"; + passwordFile = "/tmp/disko-password"; # this is populated by bootstrap.sh + settings = { + allowDiscards = true; + # https://github.com/hmajid2301/dotfiles/blob/a0b511c79b11d9b4afe2a5e2b7eedb2af23e288f/systems/x86_64-linux/framework/disks.nix#L36 + crypttabExtraOpts = [ + "fido2-device=auto" + "token-timeout=10" + ]; + }; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/mapper/cryptroot" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + }; + }; + }; + }; + }; + }; + }; + + fileSystems."/persist".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + fileSystems."/home".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + } + +#+end_src +**** Liliputsteps (OCI) + +***** Main Configuration + +#+begin_src nix-ts :tangle hosts/nixos/aarch64-linux/liliputsteps/default.nix + { self, lib, minimal, ... }: + { + imports = [ + ./hardware-configuration.nix + ./disk-config.nix + + "${self}/modules/nixos/optional/systemd-networkd-server.nix" + ]; + + topology.self = { + icon = "devices.cloud-server"; + }; + + swarselsystems = { + flakePath = "/root/.dotfiles"; + info = "VM.Standard.A1.Flex, 1 vCPUs, 8GB RAM"; + isImpermanence = true; + isSecureBoot = false; + isCrypted = true; + isSwap = false; + rootDisk = "/dev/disk/by-id/scsi-360fb180663ec4f2793a763a087d46885"; + isBtrfs = true; + isNixos = true; + isLinux = true; + isCloud = true; + mainUser = "jump"; + }; + } // lib.optionalAttrs (!minimal) { + swarselprofiles = { + server = true; + }; + + swarselmodules.server = { + nginx = false; + bastion = true; + # ssh = false; + }; + + # users.users.swarsel.enable = lib.mkForce false; + # home-manager.users.swarsel.enable = lib.mkForce false + } + +#+end_src +***** hardware-configuration + +#+begin_src nix-ts :tangle hosts/nixos/aarch64-linux/liliputsteps/hardware-configuration.nix + { lib, modulesPath, ... }: + { + imports = [ (modulesPath + "/profiles/qemu-guest.nix") ]; + + boot = { + initrd = { + availableKernelModules = [ "xhci_pci" "virtio_pci" "virtio_scsi" "usbhid" ]; + kernelModules = [ ]; + }; + kernelModules = [ ]; + extraModulePackages = [ ]; + }; + + nixpkgs.hostPlatform = lib.mkForce "aarch64-linux"; + } +#+end_src +***** disko + +#+begin_src nix-ts :tangle hosts/nixos/aarch64-linux/liliputsteps/disk-config.nix + { lib, pkgs, config, ... }: + let + type = "btrfs"; + extraArgs = [ "-L" "nixos" "-f" ]; # force overwrite + subvolumes = { + "/root" = { + mountpoint = "/"; + mountOptions = [ + "subvol=root" + "compress=zstd" + "noatime" + ]; + }; + "/home" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/home"; + mountOptions = [ + "subvol=home" + "compress=zstd" + "noatime" + ]; + }; + "/persist" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/persist"; + mountOptions = [ + "subvol=persist" + "compress=zstd" + "noatime" + ]; + }; + "/log" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/var/log"; + mountOptions = [ + "subvol=log" + "compress=zstd" + "noatime" + ]; + }; + "/nix" = { + mountpoint = "/nix"; + mountOptions = [ + "subvol=nix" + "compress=zstd" + "noatime" + ]; + }; + "/swap" = lib.mkIf config.swarselsystems.isSwap { + mountpoint = "/.swapvol"; + swap.swapfile.size = config.swarselsystems.swapSize; + }; + }; + in + { + disko = { + imageBuilder.extraDependencies = [ pkgs.kmod ]; + devices = { + disk = { + disk0 = { + type = "disk"; + device = config.swarselsystems.rootDisk; + content = { + type = "gpt"; + partitions = { + ESP = { + priority = 1; + name = "ESP"; + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "defaults" ]; + }; + }; + root = lib.mkIf (!config.swarselsystems.isCrypted) { + size = "100%"; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/disk/by-label/nixos" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + luks = lib.mkIf config.swarselsystems.isCrypted { + size = "100%"; + content = { + type = "luks"; + name = "cryptroot"; + passwordFile = "/tmp/disko-password"; # this is populated by bootstrap.sh + settings = { + allowDiscards = true; + # https://github.com/hmajid2301/dotfiles/blob/a0b511c79b11d9b4afe2a5e2b7eedb2af23e288f/systems/x86_64-linux/framework/disks.nix#L36 + crypttabExtraOpts = [ + "fido2-device=auto" + "token-timeout=10" + ]; + }; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/mapper/cryptroot" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + }; + }; + }; + }; + }; + }; + }; + + fileSystems."/persist".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + fileSystems."/home".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + } + +#+end_src +**** Twothreetunnel (OCI) + +***** Main Configuration + +#+begin_src nix-ts :tangle hosts/nixos/aarch64-linux/twothreetunnel/default.nix + { self, lib, minimal, ... }: + { + imports = [ + ./hardware-configuration.nix + ./disk-config.nix + + "${self}/modules/nixos/optional/systemd-networkd-server.nix" + ]; + + topology.self = { + icon = "devices.cloud-server"; + }; + + swarselsystems = { + flakePath = "/root/.dotfiles"; + info = "VM.Standard.A1.Flex, 2 vCPUs, 8GB RAM"; + isImpermanence = true; + isSecureBoot = false; + isCrypted = true; + isSwap = false; + rootDisk = "/dev/disk/by-id/scsi-3608deb9b0d4244de95c6620086ff740d"; + isBtrfs = true; + isNixos = true; + isLinux = true; + isCloud = true; + }; + } // lib.optionalAttrs (!minimal) { + swarselprofiles = { + server = true; + }; + + swarselmodules.server = { + nginx = false; + }; + + } + +#+end_src +***** hardware-configuration + +#+begin_src nix-ts :tangle hosts/nixos/aarch64-linux/twothreetunnel/hardware-configuration.nix + { lib, modulesPath, ... }: + { + imports = [ (modulesPath + "/profiles/qemu-guest.nix") ]; + + boot = { + initrd = { + availableKernelModules = [ "xhci_pci" "virtio_pci" "virtio_scsi" "usbhid" ]; + kernelModules = [ ]; + }; + kernelModules = [ ]; + extraModulePackages = [ ]; + }; + + nixpkgs.hostPlatform = lib.mkForce "aarch64-linux"; + } +#+end_src +***** disko + +#+begin_src nix-ts :tangle hosts/nixos/aarch64-linux/twothreetunnel/disk-config.nix + { lib, pkgs, config, ... }: + let + type = "btrfs"; + extraArgs = [ "-L" "nixos" "-f" ]; # force overwrite + subvolumes = { + "/root" = { + mountpoint = "/"; + mountOptions = [ + "subvol=root" + "compress=zstd" + "noatime" + ]; + }; + "/home" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/home"; + mountOptions = [ + "subvol=home" + "compress=zstd" + "noatime" + ]; + }; + "/persist" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/persist"; + mountOptions = [ + "subvol=persist" + "compress=zstd" + "noatime" + ]; + }; + "/log" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/var/log"; + mountOptions = [ + "subvol=log" + "compress=zstd" + "noatime" + ]; + }; + "/nix" = { + mountpoint = "/nix"; + mountOptions = [ + "subvol=nix" + "compress=zstd" + "noatime" + ]; + }; + "/swap" = lib.mkIf config.swarselsystems.isSwap { + mountpoint = "/.swapvol"; + swap.swapfile.size = config.swarselsystems.swapSize; + }; + }; + in + { + disko = { + imageBuilder.extraDependencies = [ pkgs.kmod ]; + devices = { + disk = { + disk0 = { + type = "disk"; + device = config.swarselsystems.rootDisk; + content = { + type = "gpt"; + partitions = { + ESP = { + priority = 1; + name = "ESP"; + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "defaults" ]; + }; + }; + root = lib.mkIf (!config.swarselsystems.isCrypted) { + size = "100%"; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/disk/by-label/nixos" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + luks = lib.mkIf config.swarselsystems.isCrypted { + size = "100%"; + content = { + type = "luks"; + name = "cryptroot"; + passwordFile = "/tmp/disko-password"; # this is populated by bootstrap.sh + settings = { + allowDiscards = true; + # https://github.com/hmajid2301/dotfiles/blob/a0b511c79b11d9b4afe2a5e2b7eedb2af23e288f/systems/x86_64-linux/framework/disks.nix#L36 + crypttabExtraOpts = [ + "fido2-device=auto" + "token-timeout=10" + ]; + }; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/mapper/cryptroot" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + }; + }; + }; + }; + }; + }; + }; + + fileSystems."/persist".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + fileSystems."/home".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + } + +#+end_src +**** Eagleland (Hetzner) +:PROPERTIES: +:CUSTOM_ID: h:81bc8746-b46b-4d29-87de-ddbd77788b43 +:END: + +***** Main Configuration +:PROPERTIES: +:CUSTOM_ID: h:96540b9c-1610-45f2-ba19-916051ab5e10 +:END: + +#+begin_src nix-ts :tangle hosts/nixos/x86_64-linux/eagleland/default.nix + { self, lib, minimal, ... }: + { + imports = [ + ./hardware-configuration.nix + ./disk-config.nix + + "${self}/modules/nixos/optional/systemd-networkd-server.nix" + ]; + + topology.self = { + icon = "devices.cloud-server"; + }; + + + swarselsystems = { + flakePath = "/root/.dotfiles"; + info = "2vCPU, 4GB Ram"; + isImpermanence = true; + isSecureBoot = false; + isCrypted = true; + isCloud = true; + isSwap = true; + swapSize = "4G"; + rootDisk = "/dev/sda"; + isBtrfs = true; + isNixos = true; + isLinux = true; + proxyHost = "eagleland"; + }; + } // lib.optionalAttrs (!minimal) { + + swarselmodules.server.mailserver = true; + + swarselprofiles = { + server = true; + }; + + } + +#+end_src +***** hardware-configuration +:PROPERTIES: +:CUSTOM_ID: h:44c29a70-d5fc-49c1-b02e-a5cd2ec6119b +:END: + +#+begin_src nix-ts :tangle hosts/nixos/x86_64-linux/eagleland/hardware-configuration.nix + { lib, modulesPath, ... }: + + { + imports = + [ + (modulesPath + "/profiles/qemu-guest.nix") + ]; + + boot = { + initrd = { + availableKernelModules = [ "ahci" "xhci_pci" "virtio_pci" "virtio_scsi" "sd_mod" "sr_mod" ]; + kernelModules = [ ]; + }; + kernelModules = [ ]; + extraModulePackages = [ ]; + }; + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + } + +#+end_src +***** disko +:PROPERTIES: +:CUSTOM_ID: h:5c77e384-fdae-4994-bce3-ca736722529c +:END: + +#+begin_src nix-ts :tangle hosts/nixos/x86_64-linux/eagleland/disk-config.nix + { lib, pkgs, config, ... }: + let + type = "btrfs"; + extraArgs = [ "-L" "nixos" "-f" ]; # force overwrite + subvolumes = { + "/root" = { + mountpoint = "/"; + mountOptions = [ + "subvol=root" + "compress=zstd" + "noatime" + ]; + }; + "/home" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/home"; + mountOptions = [ + "subvol=home" + "compress=zstd" + "noatime" + ]; + }; + "/persist" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/persist"; + mountOptions = [ + "subvol=persist" + "compress=zstd" + "noatime" + ]; + }; + "/log" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/var/log"; + mountOptions = [ + "subvol=log" + "compress=zstd" + "noatime" + ]; + }; + "/nix" = { + mountpoint = "/nix"; + mountOptions = [ + "subvol=nix" + "compress=zstd" + "noatime" + ]; + }; + "/swap" = lib.mkIf config.swarselsystems.isSwap { + mountpoint = "/.swapvol"; + swap.swapfile.size = config.swarselsystems.swapSize; + }; + }; + in + { + disko = { + imageBuilder.extraDependencies = [ pkgs.kmod ]; + devices = { + disk = { + disk0 = { + type = "disk"; + device = config.swarselsystems.rootDisk; + content = { + type = "gpt"; + partitions = { + ESP = { + priority = 1; + name = "ESP"; + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "defaults" ]; + }; + }; + root = lib.mkIf (!config.swarselsystems.isCrypted) { + size = "100%"; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/disk/by-label/nixos" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + luks = lib.mkIf config.swarselsystems.isCrypted { + size = "100%"; + content = { + type = "luks"; + name = "cryptroot"; + passwordFile = "/tmp/disko-password"; # this is populated by bootstrap.sh + settings = { + allowDiscards = true; + # https://github.com/hmajid2301/dotfiles/blob/a0b511c79b11d9b4afe2a5e2b7eedb2af23e288f/systems/x86_64-linux/framework/disks.nix#L36 + crypttabExtraOpts = [ + "fido2-device=auto" + "token-timeout=10" + ]; + }; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/mapper/cryptroot" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + }; + }; + }; + }; + }; + }; + }; + + fileSystems."/persist".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + fileSystems."/home".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + } +#+end_src +*** Utility hosts +:PROPERTIES: +:CUSTOM_ID: h:89ce533d-4856-4988-b456-0951d4453db8 +:END: +**** Toto (Physical/VM) +:PROPERTIES: +:CUSTOM_ID: h:6b495f0e-fc11-44c8-a9e8-83f3d95c8857 +:END: + +This is a slim setup for developing base configuration. I do not track the hardware-configuration for this host here because I often switch this configuration between running on a QEMU VM and a physical laptop and do not want to constantly adapt the config here to reflect the current state. + +***** Main Configuration +:PROPERTIES: +:CUSTOM_ID: h:4e53b40b-98b2-4615-b1b0-3696a75edd6e +:END: +#+begin_src nix-ts :tangle hosts/nixos/x86_64-linux/toto/default.nix + { self, lib, ... }: + { + + imports = [ + ./disk-config.nix + ./hardware-configuration.nix + ]; + + networking = { + hostName = "toto"; + firewall.enable = false; + }; + + swarselprofiles = { + minimal = lib.mkForce true; + }; + + swarselmodules = { + server = { + network = lib.mkForce false; + diskEncryption = lib.mkForce false; + }; + }; + + swarselsystems = { + info = "~SwarselSystems~ remote install helper"; + wallpaper = self + /files/wallpaper/lenovowp.png; + isImpermanence = true; + isCrypted = true; + isSecureBoot = false; + isSwap = true; + swapSize = "2G"; + # rootDisk = "/dev/nvme0n1"; + rootDisk = "/dev/vda"; + # rootDisk = "/dev/vda"; + isBtrfs = true; + isLinux = true; + isLaptop = false; + isNixos = true; + }; + + } + + +#+end_src + +***** disko +:PROPERTIES: +:CUSTOM_ID: h:cec82b06-39ca-4c0e-b4f5-c1fda9b14e6d +:END: + +#+begin_src nix-ts :tangle hosts/nixos/x86_64-linux/toto/disk-config.nix + # NOTE: ... is needed because dikso passes diskoFile + { lib + , pkgs + , config + , ... + }: + let + type = "btrfs"; + extraArgs = [ "-L" "nixos" "-f" ]; # force overwrite + subvolumes = { + "/root" = { + mountpoint = "/"; + mountOptions = [ + "subvol=root" + "compress=zstd" + "noatime" + ]; + }; + "/home" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/home"; + mountOptions = [ + "subvol=home" + "compress=zstd" + "noatime" + ]; + }; + "/persist" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/persist"; + mountOptions = [ + "subvol=persist" + "compress=zstd" + "noatime" + ]; + }; + "/log" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/var/log"; + mountOptions = [ + "subvol=log" + "compress=zstd" + "noatime" + ]; + }; + "/nix" = { + mountpoint = "/nix"; + mountOptions = [ + "subvol=nix" + "compress=zstd" + "noatime" + ]; + }; + "/swap" = lib.mkIf config.swarselsystems.isSwap { + mountpoint = "/.swapvol"; + swap.swapfile.size = config.swarselsystems.swapSize; + }; + }; + in + { + disko.devices = { + disk = { + disk0 = { + type = "disk"; + device = config.swarselsystems.rootDisk; + content = { + type = "gpt"; + partitions = { + ESP = { + priority = 1; + name = "ESP"; + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "defaults" ]; + }; + }; + root = lib.mkIf (!config.swarselsystems.isCrypted) { + size = "100%"; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/disk/by-label/nixos" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + luks = lib.mkIf config.swarselsystems.isCrypted { + size = "100%"; + content = { + type = "luks"; + name = "cryptroot"; + passwordFile = "/tmp/disko-password"; # this is populated by bootstrap.sh + settings = { + allowDiscards = true; + # https://github.com/hmajid2301/dotfiles/blob/a0b511c79b11d9b4afe2a5e2b7eedb2af23e288f/systems/x86_64-linux/framework/disks.nix#L36 + crypttabExtraOpts = [ + "fido2-device=auto" + "token-timeout=10" + ]; + }; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/mapper/cryptroot" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + }; + }; + }; + }; + }; + }; + + fileSystems."/persist".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + fileSystems."/home".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + + environment.systemPackages = [ + pkgs.yubikey-manager + ]; + } + + +#+end_src +**** TODO Drugstore (ISO installer config) +:PROPERTIES: +:CUSTOM_ID: h:8583371d-5d47-468b-84ba-210aad7e2c90 +:END: + +This is a live environment ISO that I use to bootstrap new systems. It only loads a minimal configuration and no graphical interface. After booting this image on a host, find out its IP and bootstrap the system using the =bootstrap= utility. + +NOTE: Yes, the path to this system does not follow the scheme outlined above - I still consider this a 'config' however, so I keep it here. + +TODO: cleanup this mess + + +#+begin_src nix-ts :tangle install/installer-config.nix + { self, config, pkgs, lib, ... }: + let + pubKeys = lib.filesystem.listFilesRecursive "${self}/secrets/keys/ssh"; + stateVersion = lib.mkDefault "23.05"; + homeFiles = { + ".bash_history" = { + text = '' + swarsel-install -n hotel + ''; + }; + }; + in + { + + config = { + home-manager.users.root.home = { + inherit stateVersion; + file = homeFiles; + }; + home-manager.users.swarsel = { + home = { + username = "swarsel"; + homeDirectory = lib.mkDefault "/home/swarsel"; + inherit stateVersion; + keyboard.layout = "us"; + sessionVariables = { + FLAKE = "/home/swarsel/.dotfiles"; + }; + file = homeFiles; + }; + }; + + security.sudo.extraConfig = '' + Defaults env_keep+=SSH_AUTH_SOCK + Defaults lecture = never + ''; + security.pam = { + sshAgentAuth.enable = true; + services = { + sudo.u2fAuth = true; + }; + }; + + nix = { + channel.enable = false; + package = pkgs.nixVersions.nix_2_28; + extraOptions = '' + plugin-files = ${pkgs.nix-plugins.overrideAttrs (o: { + buildInputs = [config.nix.package pkgs.boost]; + patches = o.patches or []; + })}/lib/nix/plugins + extra-builtins-file = ${../nix/extra-builtins.nix} + ''; + + settings.experimental-features = [ "nix-command" "flakes" ]; + }; + + boot = { + supportedFilesystems = lib.mkForce [ "brtfs" "vfat" ]; + loader.systemd-boot = { + enable = true; + }; + }; + + services = { + qemuGuest.enable = true; + openssh = { + enable = true; + settings.PermitRootLogin = "yes"; + authorizedKeysFiles = lib.mkForce [ + "/etc/ssh/authorized_keys.d/%u" + ]; + }; + }; + + environment.systemPackages = with pkgs; [ + curl + git + gnupg + networkmanager + rsync + ssh-to-age + sops + vim + just + sbctl + ]; + + programs = { + git.enable = true; + }; + + fileSystems."/boot".options = [ "umask=0077" ]; + + environment.etc."issue".text = '' + ~SwarselSystems~ + IP of primary interface: \4 + These IPs were also found: \4{eth0} \4{eth1} \4{eth2} \4{eth3} \4{eth4} \4{eth5} \4{wlan0} + The Password for all users & root is 'setup'. + Install the system remotely by running 'bootstrap -n -d ' on a machine with deployed secrets. + Alternatively, run 'swarsel-install -n ' for a local install. For your convenience, an example call is in the bash history (press up on the keyboard to access). + ''; + + networking = { + hostName = "drugstore"; + wireless.enable = false; + # dhcpcd.runHook = "${pkgs.utillinux}/bin/agetty --reload"; + networkmanager.enable = true; + usePredictableInterfaceNames = false; + }; + + services.getty.autologinUser = lib.mkForce "root"; + + users = { + allowNoPasswordLogin = true; + groups.swarsel = { }; + users = { + swarsel = { + name = "swarsel"; + group = "swarsel"; + isNormalUser = true; + password = "setup"; # this is overwritten after install + openssh.authorizedKeys.keys = lib.lists.forEach pubKeys (key: builtins.readFile key); + extraGroups = [ "wheel" ]; + }; + root = { + initialHashedPassword = lib.mkForce null; + password = lib.mkForce config.users.users.swarsel.password; # this is overwritten after install + openssh.authorizedKeys.keys = config.users.users.swarsel.openssh.authorizedKeys.keys; + }; + }; + }; + + programs.bash.shellAliases = { + "swarsel-install" = "nix run github:Swarsel/.dotfiles#swarsel-install --"; + "swarsel-net-manufacturer" = "lspci -nn | grep -i 'network\\|ethernet'"; + "swarsel-kernel-module" = "lspci -k -d"; + }; + + system.activationScripts.cache = { + text = '' + mkdir -p -m=0777 /home/swarsel/.local/state/nix/profiles + mkdir -p -m=0777 /home/swarsel/.local/state/home-manager/gcroots + mkdir -p -m=0777 /home/swarsel/.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 /home/swarsel/.local/share/nix/trusted-settings.json > /dev/null + 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 > /dev/null + ''; + }; + systemd = { + services.sshd.wantedBy = lib.mkForce [ "multi-user.target" ]; + targets = { + sleep.enable = false; + suspend.enable = false; + hibernate.enable = false; + hybrid-sleep.enable = false; + }; + }; + + system.stateVersion = lib.mkForce "23.05"; + + }; + } + + + #+end_src + +**** Brick Road (kexec image) +:PROPERTIES: +:CUSTOM_ID: h:e9fe580c-f1b2-4d7b-aaff-bbdf89a8c9f9 +:END: + +#+begin_src nix-ts :tangle install/kexec.nix + { lib, pkgs, modulesPath, options, ... }: + { + disabledModules = [ + # This module adds values to multiple lists (systemPackages, supportedFilesystems) + # which are impossible/unpractical to remove, so we disable the entire module. + "profiles/base.nix" + ]; + + imports = [ + # reduce closure size by removing perl + "${modulesPath}/profiles/perlless.nix" + # FIXME: we still are left with nixos-generate-config due to nixos-install-tools + { system.forbiddenDependenciesRegexes = lib.mkForce [ ]; } + ]; + + config = { + networking.hostName = "brickroad"; + + system = { + # nixos-option is mainly useful for interactive installations + tools.nixos-option.enable = false; + # among others, this prevents carrying a stdenv with gcc in the image + extraDependencies = lib.mkForce [ ]; + }; + # prevents shipping nixpkgs, unnecessary if system is evaluated externally + nix.registry = lib.mkForce { }; + + # would pull in nano + programs.nano.enable = false; + + # prevents strace + environment = { + defaultPackages = lib.mkForce [ + pkgs.parted + pkgs.gptfdisk + pkgs.e2fsprogs + ]; + + systemPackages = with pkgs; [ + cryptsetup.bin + ]; + + # Don't install the /lib/ld-linux.so.2 stub. This saves one instance of nixpkgs. + ldso32 = null; + }; + + # included in systemd anyway + systemd.sysusers.enable = true; + + # normal users are not allowed with sys-users + # see https://github.com/NixOS/nixpkgs/pull/328926 + users.users.nixos = { + isSystemUser = true; + isNormalUser = lib.mkForce false; + shell = "/run/current-system/sw/bin/bash"; + group = "nixos"; + }; + users.groups.nixos = { }; + + security = { + # we have still run0 from systemd and most of the time we just use root + sudo.enable = false; + polkit.enable = lib.mkForce false; + # introduces x11 dependencies + pam.services.su.forwardXAuth = lib.mkForce false; + }; + + documentation = { + enable = false; + man.enable = false; + nixos.enable = false; + info.enable = false; + doc.enable = false; + }; + + services = { + # no dependency on x11 + dbus.implementation = "broker"; + # we prefer root as this is also what we use in nixos-anywhere + getty.autologinUser = lib.mkForce "root"; + # included in systemd anyway + userborn.enable = false; + }; + + + + # we are missing this from base.nix + boot.supportedFilesystems = [ + "ext4" + "btrfs" + "xfs" + ]; + } // lib.optionalAttrs (options.hardware ? firmwareCompression) { + hardware.firmwareCompression = "xz"; + }; + } + +#+end_src + +**** Hotel (Demo Physical/VM) +:PROPERTIES: +:CUSTOM_ID: h:e1498bef-ec67-483d-bf02-76264e30be8e +:END: This is just a demo host. It applies all the configuration found in the common parts of the flake, but disables all secrets-related features (as they would not work without the proper SSH keys). I also set the =WLR_RENDERER_ALLOW_SOFTWARE=1= to allow this configuration to run in a virtualized environment. I also enable =qemuGuest= for a smoother experience when testing on QEMU. +***** Main configuration +:PROPERTIES: +:CUSTOM_ID: h:9f1f3439-b0af-4dcd-a96f-b6aa7b6cd2ab +:END: - -#+begin_src nix :tangle hosts/nixos/chaostheatre/default.nix - { self, inputs, outputs, config, pkgs, lib, ... }: +#+begin_src nix-ts :tangle hosts/nixos/x86_64-linux/hotel/default.nix + { self, config, pkgs, lib, minimal, ... }: let - profilesPath = "${self}/profiles"; + mainUser = "demo"; in { - imports = outputs.nixModules ++ [ - + imports = [ ./hardware-configuration.nix - - "${profilesPath}/optional/nixos/autologin.nix" - - inputs.home-manager.nixosModules.home-manager + ./disk-config.nix { - home-manager.users.swarsel.imports = outputs.mixedModules ++ (builtins.attrValues outputs.homeManagerModules); + _module.args.diskDevice = config.swarselsystems.rootDisk; } - ] ++ (builtins.attrValues outputs.nixosModules); - - - nixpkgs = { - overlays = [ outputs.overlays.default ]; - config = { - allowUnfree = true; - }; - }; + ]; environment.variables = { WLR_RENDERER_ALLOW_SOFTWARE = 1; @@ -2035,42 +5309,16451 @@ I also set the =WLR_RENDERER_ALLOW_SOFTWARE=1= to allow this configuration to ru }; networking = { - hostName = "chaostheatre"; + hostName = "hotel"; firewall.enable = true; }; - - swarselsystems = { - wallpaper = self + /wallpaper/lenovowp.png; - initialSetup = true; - isPublic = true; + swarselmodules = { + server = { + network = lib.mkForce false; + diskEncryption = lib.mkForce false; + }; }; - home-manager.users.swarsel.swarselsystems = { - isNixos = true; + swarselsystems = { + info = "~SwarselSystems~ demo host"; + wallpaper = self + /files/wallpaper/lenovowp.png; + isImpermanence = true; + isCrypted = true; + isSecureBoot = false; + isSwap = true; + swapSize = "4G"; + rootDisk = "/dev/vda"; + isBtrfs = false; + inherit mainUser; + isLinux = true; isPublic = true; - flakePath = "/home/swarsel/.dotfiles"; + isNixos = true; + }; + + } // lib.optionalAttrs (!minimal) { + swarselprofiles = { + hotel = true; + minimal = true; }; } #+end_src -** Additions and modifications +***** disko :PROPERTIES: -:CUSTOM_ID: h:ab272ab4-3c93-48b1-8f1e-f710aa9aae5d +:CUSTOM_ID: h:849e4233-ba40-4fec-acfe-0d76e1e4371b :END: -In this section I define packages that I manually want to nixpkgs. This can be useful for packages that are currently awaiting a PR or public packages that I do not want to maintain. +#+begin_src nix-ts :tangle hosts/nixos/x86_64-linux/hotel/disk-config.nix + # NOTE: ... is needed because dikso passes diskoFile + { lib + , pkgs + , config + , diskDevice ? config.swarselsystem.rootDisk + , ... + }: + let + type = "btrfs"; + extraArgs = [ "-L" "nixos" "-f" ]; # force overwrite + subvolumes = { + "/root" = { + mountpoint = "/"; + mountOptions = [ + "subvol=root" + "compress=zstd" + "noatime" + ]; + }; + "/home" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/home"; + mountOptions = [ + "subvol=home" + "compress=zstd" + "noatime" + ]; + }; + "/persist" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/persist"; + mountOptions = [ + "subvol=persist" + "compress=zstd" + "noatime" + ]; + }; + "/log" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/var/log"; + mountOptions = [ + "subvol=log" + "compress=zstd" + "noatime" + ]; + }; + "/nix" = { + mountpoint = "/nix"; + mountOptions = [ + "subvol=nix" + "compress=zstd" + "noatime" + ]; + }; + "/swap" = lib.mkIf config.swarselsystems.isSwap { + mountpoint = "/.swapvol"; + swap.swapfile.size = config.swarselsystems.swapSize; + }; + }; + in + { + disko.devices = { + disk = { + disk0 = { + type = "disk"; + device = diskDevice; + content = { + type = "gpt"; + partitions = { + ESP = { + priority = 1; + name = "ESP"; + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "defaults" ]; + }; + }; + root = lib.mkIf (!config.swarselsystems.isCrypted) { + size = "100%"; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/disk/by-label/nixos" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + luks = lib.mkIf config.swarselsystems.isCrypted { + size = "100%"; + content = { + type = "luks"; + name = "cryptroot"; + passwordFile = "/tmp/disko-password"; # this is populated by bootstrap.sh + settings = { + allowDiscards = true; + # https://github.com/hmajid2301/dotfiles/blob/a0b511c79b11d9b4afe2a5e2b7eedb2af23e288f/systems/x86_64-linux/framework/disks.nix#L36 + crypttabExtraOpts = [ + "fido2-device=auto" + "token-timeout=10" + ]; + }; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/mapper/cryptroot" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + }; + }; + }; + }; + }; + }; -As such, I also define three additional overlays: + fileSystems."/persist".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + fileSystems."/home".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; -1) =additions= - These are for the aforementioned added packages -2) =modification= - These are for packages that are on nixpkgs, but do not fit my usecase, meaning I need to perform modifications on them. -3) =nixpkgs-stable= - This is simply a mirror of the most recent stable branch of nixpkgs. Useful for packages that are broken on nixpkgs, but do not need to be on bleeding edge anyways. + environment.systemPackages = [ + pkgs.yubikey-manager + ]; + } +#+end_src + +***** NixOS dummy options configuration +:PROPERTIES: +:CUSTOM_ID: h:6f9c1a3b-452e-4944-86e8-cb17603cc3f9 +:END: + +#+begin_src nix-ts :tangle hosts/nixos/x86_64-linux/hotel/options.nix + _: + { } + +#+end_src + +***** home-manager dummy options configuration +:PROPERTIES: +:CUSTOM_ID: h:88ccb198-74b9-4269-8e22-af1277f44667 +:END: + +#+begin_src nix-ts :tangle hosts/nixos/x86_64-linux/hotel/options-home.nix + _: + { } + +#+end_src + +** NixOS +:PROPERTIES: +:CUSTOM_ID: h:6da812f5-358c-49cb-aff2-0a94f20d70b3 +:END: + +Here we have NixOS options. All options are split into smaller files that are loaded by the general =default.nix=. Common files are used by all user hosts equally, optionals need to be added to the machine's =default.nix= on a case-by-case basis. + +#+begin_src nix-ts :tangle modules/nixos/default.nix + { lib, ... }: + let + importNames = lib.swarselsystems.readNix "modules/nixos"; + in + { + imports = lib.swarselsystems.mkImports importNames "modules/nixos"; + } + +#+end_src + +*** Common +:PROPERTIES: +:CUSTOM_ID: h:1c1250cd-e9b4-4715-8d9f-eb09e64bfc7f +:END: + +These are system-level settings specific to NixOS machines. All settings that are required on all machines go here. + +**** Imports +:PROPERTIES: +:CUSTOM_ID: h:4acbe063-188b-42e7-b75c-b6d2e232e784 +:END: + +This section is for setting things that should be used on hosts that are using the default NixOS configuration. This means that servers should NOT import this, as much of these imported modules are user-configured. + +#+begin_src nix-ts :tangle modules/nixos/common/default.nix +{ lib, ... }: +let + importNames = lib.swarselsystems.readNix "modules/nixos/common"; + sharedNames = lib.swarselsystems.readNix "modules/shared"; +in +{ + imports = lib.swarselsystems.mkImports importNames "modules/nixos/common" ++ + lib.swarselsystems.mkImports sharedNames "modules/shared"; +} + +#+end_src + +**** Share configuration between nodes (automatically active) +:PROPERTIES: +:CUSTOM_ID: h:5c3027b4-ba66-445e-9c5f-c27e332c90e5 +:END: + +#+begin_src nix-ts :tangle modules/nixos/common/nodes.nix + # adapted from https://github.com/oddlama/nix-config/blob/main/modules/distributed-config.nix + { config, lib, outputs, ... }: + let + nodeName = config.node.name; + mkForwardedOption = + path: + lib.mkOption { + type = lib.mkOptionType { + name = "Same type that the receiving option `${lib.concatStringsSep "." path}` normally accepts."; + merge = + _loc: defs: + builtins.filter (x: builtins.isAttrs x -> ((x._type or "") != "__distributed_config_empty")) ( + map (x: x.value) defs + ); + }; + default = { + _type = "__distributed_config_empty"; + }; + description = '' + Anything specified here will be forwarded to `${lib.concatStringsSep "." path}` + on the given node. Forwarding happens as-is to the raw values, + so validity can only be checked on the receiving node. + ''; + }; + + forwardedOptions = [ + [ + "services" + "nginx" + "upstreams" + ] + [ + "services" + "nginx" + "virtualHosts" + ] + [ + "swarselsystems" + "server" + "dns" + ] + ]; + + attrsForEachOption = + f: lib.foldl' (acc: path: lib.recursiveUpdate acc (lib.setAttrByPath path (f path))) { } forwardedOptions; + in + { + options.nodes = lib.mkOption { + description = "Options forwarded to the given node."; + default = { }; + type = lib.types.attrsOf ( + lib.types.submodule { + options = attrsForEachOption mkForwardedOption; + } + ); + }; + + config = + let + getConfig = + path: otherNode: + let + cfg = outputs.nixosConfigurations.${otherNode}.config.nodes.${nodeName} or null; + in + lib.optionals (cfg != null) (lib.getAttrFromPath path cfg); + mergeConfigFromOthers = path: lib.mkMerge (lib.concatMap (getConfig path) (lib.attrNames outputs.nixosConfigurations)); + in + attrsForEachOption mergeConfigFromOthers; + } +#+end_src + +**** Global options (automatically active) +:PROPERTIES: +:CUSTOM_ID: h:85c9b83f-40c3-4558-bb28-a37b6f8597b9 +:END: + +#+begin_src nix-ts :tangle modules/nixos/common/globals.nix + { lib, options, ... }: + let + inherit (lib) + mkOption + types + ; + + networkOptions = netSubmod: { + cidrv4 = mkOption { + type = types.nullOr types.net.cidrv4; + description = "The CIDRv4 of this network"; + default = null; + }; + + subnetMask4 = mkOption { + type = types.nullOr types.net.ipv4; + description = "The dotted decimal form of the subnet mask of this network"; + readOnly = true; + default = lib.swarselsystems.cidrToSubnetMask netSubmod.config.cidrv4; + }; + + cidrv6 = mkOption { + type = types.nullOr types.net.cidrv6; + description = "The CIDRv6 of this network"; + default = null; + }; + + hosts = mkOption { + default = { }; + type = types.attrsOf ( + types.submodule (hostSubmod: { + options = { + id = mkOption { + type = types.int; + description = "The id of this host in the network"; + }; + + mac = mkOption { + type = types.nullOr types.net.mac; + description = "The MAC of the interface on this host that belongs to this network."; + default = null; + }; + + ipv4 = mkOption { + type = types.nullOr types.net.ipv4; + description = "The IPv4 of this host in this network"; + readOnly = true; + default = + if netSubmod.config.cidrv4 == null then + null + else + lib.net.cidr.host hostSubmod.config.id netSubmod.config.cidrv4; + }; + + ipv6 = mkOption { + type = types.nullOr types.net.ipv6; + description = "The IPv6 of this host in this network"; + readOnly = true; + default = + if netSubmod.config.cidrv6 == null then + null + else + lib.net.cidr.host hostSubmod.config.id netSubmod.config.cidrv6; + }; + + cidrv4 = mkOption { + type = types.nullOr types.str; # FIXME: this is not types.net.cidr because it would zero out the host part + description = "The IPv4 of this host in this network, including CIDR mask"; + readOnly = true; + default = + if netSubmod.config.cidrv4 == null then + null + else + lib.net.cidr.hostCidr hostSubmod.config.id netSubmod.config.cidrv4; + }; + + cidrv6 = mkOption { + type = types.nullOr types.str; # FIXME: this is not types.net.cidr because it would zero out the host part + description = "The IPv6 of this host in this network, including CIDR mask"; + readOnly = true; + default = + if netSubmod.config.cidrv6 == null then + null + else + # if we use the /32 wan address as local address directly, do not use the network address in ipv6 + lib.net.cidr.hostCidr (if hostSubmod.config.id == 0 then 1 else hostSubmod.config.id) netSubmod.config.cidrv6; + }; + }; + }) + ); + }; + }; + in + { + options = { + globals = mkOption { + default = { }; + type = types.submodule { + options = { + root = { + hashedPassword = mkOption { + type = types.str; + }; + }; + + user = { + name = mkOption { + type = types.str; + }; + work = mkOption { + type = types.str; + }; + }; + + + services = mkOption { + type = types.attrsOf ( + types.submodule (serviceSubmod: { + options = { + domain = mkOption { + type = types.str; + }; + subDomain = mkOption { + readOnly = true; + type = types.str; + default = lib.swarselsystems.getSubDomain serviceSubmod.config.domain; + }; + baseDomain = mkOption { + readOnly = true; + type = types.str; + default = lib.swarselsystems.getBaseDomain serviceSubmod.config.domain; + }; + proxyAddress4 = mkOption { + type = types.nullOr types.str; + default = null; + }; + proxyAddress6 = mkOption { + type = types.nullOr types.str; + default = null; + }; + }; + }) + ); + }; + + networks = mkOption { + default = { }; + type = types.attrsOf ( + types.submodule (netSubmod: { + options = networkOptions netSubmod // { + vlans = mkOption { + default = { }; + type = types.attrsOf ( + types.submodule (vlanNetSubmod: { + options = networkOptions vlanNetSubmod // { + id = mkOption { + type = types.ints.between 1 4094; + description = "The VLAN id"; + }; + + name = mkOption { + description = "The name of this VLAN"; + default = vlanNetSubmod.config._module.args.name; + type = types.str; + }; + }; + }) + ); + }; + }; + }) + ); + }; + + hosts = mkOption { + type = types.attrsOf ( + types.submodule { + options = { + defaultGateway4 = mkOption { + type = types.nullOr types.net.ipv4; + }; + defaultGateway6 = mkOption { + type = types.nullOr types.net.ipv6; + }; + wanAddress4 = mkOption { + type = types.nullOr types.net.ipv4; + }; + wanAddress6 = mkOption { + type = types.nullOr types.net.ipv6; + }; + }; + } + ); + }; + + domains = { + main = mkOption { + type = types.str; + }; + externalDns = mkOption { + type = types.listOf types.str; + description = "List of external dns nameservers"; + }; + }; + }; + }; + }; + + _globalsDefs = mkOption { + type = types.unspecified; + default = options.globals.definitions; + readOnly = true; + internal = true; + }; + }; + } +#+end_src + +**** Meta options (options only) +:PROPERTIES: +:CUSTOM_ID: h:30b81bf9-1e69-4ce8-88af-5592896bcee4 +:END: + + +#+begin_src nix-ts :tangle modules/nixos/common/meta.nix + { lib, ... }: + { + options = { + node = { + secretsDir = lib.mkOption { + description = "Path to the secrets directory for this node."; + type = lib.types.path; + default = ./.; + }; + name = lib.mkOption { + description = "Node Name."; + type = lib.types.str; + }; + lockFromBootstrapping = lib.mkOption { + description = "Whether this host should be marked to not be bootstrapped again using swarsel-bootstrap."; + type = lib.types.bool; + }; + }; + }; + } +#+end_src + +**** Expose home-manager sops secrets in NixOS (automatically active) +:PROPERTIES: +:CUSTOM_ID: h:a8bbe15f-a7dd-4e6d-ba49-26206c38e9c8 +:END: + +#+begin_src nix-ts :tangle modules/nixos/common/home-manager-secrets.nix + { self, lib, config, globals, ... }: + let + inherit (config.swarselsystems) mainUser homeDir; + inherit (config.repo.secrets.common.emacs) radicaleUser; + modules = config.home-manager.users.${mainUser}.swarselmodules; + + certsSopsFile = self + /secrets/certs/secrets.yaml; + in + { + config = lib.mkIf config.swarselsystems.withHomeManager { + sops = { + secrets = (lib.optionalAttrs modules.mail + { + address1-token = { owner = mainUser; }; + address2-token = { owner = mainUser; }; + address3-token = { owner = mainUser; }; + address4-token = { owner = mainUser; }; + }) // (lib.optionalAttrs modules.waybar { + github-notifications-token = { owner = mainUser; }; + }) // (lib.optionalAttrs modules.emacs { + fever-pw = { path = "${homeDir}/.emacs.d/.fever"; owner = mainUser; }; + }) // (lib.optionalAttrs modules.zsh { + croc-password = { owner = mainUser; }; + github-nixpkgs-review-token = { owner = mainUser; }; + }) // (lib.optionalAttrs modules.emacs { + emacs-radicale-pw = { owner = mainUser; }; + github-forge-token = { owner = mainUser; }; + }) // (lib.optionalAttrs (modules ? optional-work) { + harica-root-ca = { sopsFile = certsSopsFile; path = "${homeDir}/.aws/certs/harica-root.pem"; owner = mainUser; }; + }) // (lib.optionalAttrs modules.anki { + anki-user = { owner = mainUser; }; + anki-pw = { owner = mainUser; }; + }); + templates = { + authinfo = lib.mkIf modules.emacs { + path = "${homeDir}/.emacs.d/.authinfo"; + content = '' + machine ${globals.services.radicale.domain} login ${radicaleUser} password ${config.sops.placeholder.emacs-radicale-pw} + ''; + owner = mainUser; + }; + }; + }; + }; + } +#+end_src + +**** Topology (automatically active) +:PROPERTIES: +:CUSTOM_ID: h:e2e7444b-cb85-4719-b154-e5f37274d02d +:END: + +#+begin_src nix-ts :tangle modules/nixos/common/topology.nix + { lib, config, ... }: + { + options.swarselsystems.info = lib.mkOption { + type = lib.types.str; + default = ""; + }; + config.topology = { + id = config.node.name; + self = { + hardware.info = config.swarselsystems.info; + icon = lib.mkIf config.swarselsystems.isLaptop "devices.laptop"; + }; + }; + } +#+end_src +**** General NixOS settings (nix config, stateVersion) +:PROPERTIES: +:CUSTOM_ID: h:24c9146f-2147-4fd5-bafc-d5853e15cf12 +:END: + + +We disable the warnings that trigger when rebuilding with a dirty flake. At this point, I am also disabling channels and pinning the flake registry - the latter lets me use the local version of nixpkgs for commands like =nix shell= (without it, we will always download the newest version of nixpkgs for these commands). + +Also, the system state version is set here. No need to touch it. + +A breakdown of the flags being set: +- =nixpgks.config.allowUnfree=: allows packages with an unfree license to be built +- nix.settings: + - experimental-features: + - nix-command: Enables the =nix= command from nix 2.4 + - flakes: Enables flakes to be used + - ca-derivations: Enables content-addressed derivations, which stops unnecessary rebuiluds - to be used with my TODO private hydra and the binary cache =cache.ngi0.nixos.org= in [[#h:aee5ec75-7ca6-40d8-b6ac-a3e7e33a474b][flake.nix template]] + - cgroups: allows the use of cgroups in builds + - pipe-operators: Enables 'piping' instead of the classic currying syntax - =fun arg= can be expressed as =arg |> fun=. Associatively, it is weaker than functions: =a |> b |> d c |> e = e ((d c) (b a))= + - trusted-users: these users have elevated privileges in nix (mostly used to acknowledge binary caches) - root is added per default here + - connect-timeout: normally, nix tries to reach the cache for 300 seconds for each derivation per cache. This setting lets me change that + - bash-prompt-prefix: adds a prefix to shells spawned by =nix develop= + - [min,max]-free: amounts of space where intermittent GC will be run during builds + - flake registry: URI of the global flake registry (I disable it) + - auto-optimise-store: create hardlinks in the nix store to save space + - warn-dirty: I do not need to see the warning when I have uncommited changes + - max-jobs: How many build jobs should be run in parallel. =auto= sets this to the number of CPUs (which is all) - on systems with many cores this can lead to OOM situations. The default is now =1=, but used to be =auto=, I set this manually just to be safe in the future. + - use-cgroups: Actually run builds within cgroups +- nix.channel.enable: whether to use channels +- nix.registry: Sets the registry for this flake, which I set to its inputs. This allows me to use e.g. =nixpkgs= directly in =nix repl= +- nix.nixPath: Basically the same as =nix.registry=, but for the legacy nix commands + +#+begin_src nix-ts :tangle modules/nixos/common/settings.nix + { self, lib, pkgs, config, outputs, inputs, minimal, globals, ... }: + let + inherit (config.swarselsystems) mainUser; + inherit (config.repo.secrets.common) atticPublicKey; + settings = if minimal then { } else { + environment.etc."nixos/configuration.nix".source = pkgs.writeText "configuration.nix" '' + assert builtins.trace "This location is not used. The config is found in ${config.swarselsystems.flakePath}!" false; + { } + ''; + + nix = + let + flakeInputs = lib.filterAttrs (_: lib.isType "flake") inputs; + in + { + settings = { + connect-timeout = 5; + bash-prompt-prefix = "$SHLVL:\\w "; + bash-prompt = "$(if [[ $? -gt 0 ]]; then printf \"\"; else printf \"\"; fi)λ "; + fallback = true; + min-free = 128000000; + max-free = 1000000000; + flake-registry = ""; + auto-optimise-store = true; + warn-dirty = false; + max-jobs = 1; + use-cgroups = lib.mkIf config.swarselsystems.isLinux true; + }; + gc = { + automatic = true; + dates = "weekly"; + options = "--delete-older-than 10d"; + }; + optimise = { + automatic = true; + dates = "weekly"; + }; + channel.enable = false; + registry = rec { + nixpkgs.flake = inputs.nixpkgs; + # swarsel.flake = inputs.swarsel; + swarsel.flake = self; + n = nixpkgs; + s = swarsel; + }; + nixPath = lib.mapAttrsToList (n: _: "${n}=flake:${n}") flakeInputs; + }; + + services.dbus.implementation = "broker"; + + systemd.services.nix-daemon = { + environment.TMPDIR = "/var/tmp"; + }; + + }; + in + { + options.swarselmodules.general = lib.mkEnableOption "general nix settings"; + config = lib.mkIf config.swarselmodules.general + (lib.recursiveUpdate + { + sops.secrets = lib.mkIf (!minimal) { + github-api-token = { owner = mainUser; }; + }; + + nix = + let + nix-version = "2_30"; + in + { + package = pkgs.nixVersions."nix_${nix-version}"; + settings = { + experimental-features = [ + "nix-command" + "flakes" + "ca-derivations" + "cgroups" + "pipe-operators" + ]; + substituters = [ + "https://${globals.services.attic.domain}/${mainUser}" + ]; + trusted-public-keys = [ + atticPublicKey + ]; + trusted-users = [ + "@wheel" + "${config.swarselsystems.mainUser}" + (lib.mkIf config.swarselmodules.server.ssh-builder "builder") + ]; + }; + # extraOptions = '' + # plugin-files = ${pkgs.dev.nix-plugins}/lib/nix/plugins + # extra-builtins-file = ${self + /nix/extra-builtins.nix} + # '' + lib.optionalString (!minimal) '' + # !include ${config.sops.secrets.github-api-token.path} + # ''; + # extraOptions = '' + # plugin-files = ${pkgs.nix-plugins.overrideAttrs (o: { + # buildInputs = [config.nix.package pkgs.boost]; + # patches = o.patches or []; + # })}/lib/nix/plugins + # extra-builtins-file = ${self + /nix/extra-builtins.nix} + # ''; + + extraOptions = + let + nix-plugins = pkgs.nix-plugins.override { + nixComponents = pkgs.nixVersions."nixComponents_${nix-version}"; + }; + in + '' + plugin-files = ${nix-plugins}/lib/nix/plugins + extra-builtins-file = ${self + /nix/extra-builtins.nix} + '' + lib.optionalString (!minimal) '' + !include ${config.sops.secrets.github-api-token.path} + ''; + }; + + system.stateVersion = lib.mkDefault "23.05"; + + nixpkgs = { + overlays = [ + outputs.overlays.default + (final: prev: + let + additions = final: _: import "${self}/pkgs/config" { + inherit self config lib; + pkgs = final; + homeConfig = config.home-manager.users.${config.swarselsystems.mainUser}; + }; + in + additions final prev + ) + ]; + config = { + allowUnfree = true; + }; + }; + + } + settings); + } +#+end_src + +**** Setup home-manager base +:PROPERTIES: +:CUSTOM_ID: h:7f6d6908-4d02-4907-9c70-f802f4358520 +:END: + +We enable the use of =home-manager= as a NixoS module. A nice trick here is the =extraSpecialArgs = inputs= line, which enables the use of =seflf= in most parts of the configuration. This is useful to refer to the root of the flake (which is otherwise quite hard while maintaining flake purity). + +#+begin_src nix-ts :tangle modules/nixos/common/home-manager.nix + { self, inputs, config, lib, homeLib, outputs, globals, nodes, minimal, configName, ... }: + { + options.swarselmodules.home-manager = lib.mkEnableOption "home-manager"; + config = lib.mkIf config.swarselmodules.home-manager { + home-manager = lib.mkIf config.swarselsystems.withHomeManager { + useGlobalPkgs = true; + useUserPackages = true; + verbose = true; + backupFileExtension = "hm-bak"; + overwriteBackup = true; + users.${config.swarselsystems.mainUser}.imports = [ + inputs.nix-index-database.homeModules.nix-index + inputs.sops-nix.homeManagerModules.sops + inputs.spicetify-nix.homeManagerModules.default + inputs.swarsel-nix.homeModules.default + { + imports = [ + "${self}/profiles/home" + "${self}/modules/home" + { + swarselprofiles = { + minimal = lib.mkIf minimal true; + }; + } + ]; + # node = { + # secretsDir = if (!config.swarselsystems.isNixos) then ../../../hosts/home/${configName}/secrets else ../../../hosts/nixos/${configName}/secrets; + # }; + home.stateVersion = lib.mkDefault config.system.stateVersion; + } + ]; + extraSpecialArgs = { + inherit (inputs) self nixgl; + inherit inputs outputs globals nodes minimal configName; + lib = homeLib; + }; + }; + }; + } +#+end_src + +**** User setup, Make users non-mutable +:PROPERTIES: +:CUSTOM_ID: h:48959890-fbc7-4d28-b33c-f33e028ab473 +:END: + +This ensures that all user-configuration happens here in the config file. +In case of using a fully setup system, this makes also sure that no further user level modifications can be made using CLI utilities (e.g. usermod etc.). Everything must be defined in the flake. + +For that reason, make sure that =sops-nix= is properly working before finishing the minimal setup, otherwise we might lose user access. The bootstrapping script takes care of this. + +#+begin_src nix-ts :tangle modules/nixos/common/users.nix + { pkgs, config, lib, globals, minimal, ... }: + { + options.swarselmodules.users = lib.mkEnableOption "user config"; + config = lib.mkIf config.swarselmodules.users { + sops.secrets.main-user-hashed-pw = lib.mkIf (!config.swarselsystems.isPublic) { neededForUsers = true; }; + + users = { + mutableUsers = lib.mkIf (!minimal) false; + users = { + root = { + inherit (globals.root) hashedPassword; + # shell = pkgs.zsh; + }; + "${config.swarselsystems.mainUser}" = { + isNormalUser = true; + description = "Leon S"; + password = lib.mkIf (minimal || config.swarselsystems.isPublic) "setup"; + hashedPasswordFile = lib.mkIf (!minimal && !config.swarselsystems.isPublic) config.sops.secrets.main-user-hashed-pw.path; + extraGroups = [ "wheel" ] ++ lib.optionals (!minimal) [ "networkmanager" "syncthing" "docker" "lp" "audio" "video" "vboxusers" "libvirtd" "scanner" ]; + packages = with pkgs; [ ]; + }; + }; + }; + }; + } +#+end_src + +**** Setup login keymap +:PROPERTIES: +:CUSTOM_ID: h:7248f338-8cad-4443-9060-deae7955b26f +:END: + +Next, we setup the keymap in case we are not in a graphical session. At this point, I always resort to us/altgr-intl, as it is comfortable to use and I do not write too much German anyways. + +#+begin_src nix-ts :tangle modules/nixos/common/xserver.nix + { lib, config, ... }: + { + options.swarselmodules.xserver = lib.mkEnableOption "xserver keymap"; + config = lib.mkIf config.swarselmodules.packages { + services.xserver = { + xkb = { + layout = "us"; + variant = "altgr-intl"; + }; + }; + }; + } +#+end_src + +**** Time, locale settings +:PROPERTIES: +:CUSTOM_ID: h:852d59ab-63c3-4831-993d-b5e23b877796 +:END: + +Setup timezone and locale. I want to use the US layout, but have the rest adapted to my country and timezone. Also, there is an issue with running Windows/Linux dualboot on the same machine where the hardware clock desyncs between the two OS'es. We fix that bug here as well. + +#+begin_src nix-ts :tangle modules/nixos/common/time.nix + { lib, config, ... }: + { + options.swarselmodules.time = lib.mkEnableOption "time config"; + config = lib.mkIf config.swarselmodules.time { + time = { + timeZone = "Europe/Vienna"; + # hardwareClockInLocalTime = true; + }; + + i18n = { + defaultLocale = "en_US.UTF-8"; + extraLocaleSettings = { + LC_ADDRESS = "de_AT.UTF-8"; + LC_IDENTIFICATION = "de_AT.UTF-8"; + LC_MEASUREMENT = "de_AT.UTF-8"; + LC_MONETARY = "de_AT.UTF-8"; + LC_NAME = "de_AT.UTF-8"; + LC_NUMERIC = "de_AT.UTF-8"; + LC_PAPER = "de_AT.UTF-8"; + LC_TELEPHONE = "de_AT.UTF-8"; + LC_TIME = "de_AT.UTF-8"; + }; + }; + }; + } +#+end_src + +**** PII management +:PROPERTIES: +:CUSTOM_ID: h:82b8ede2-02d8-4c43-8952-7200ebd4dc23 +:END: + +This is also exposed to home-manager configurations, in case this ever breaks, I can also go back to importing =nixosConfig= as an attribute in the input attribute set and call the secrets using =nixosConfig.repo.secrets=. + +#+begin_src nix-ts :tangle modules/nixos/common/pii.nix + # largely based on https://github.com/oddlama/nix-config/blob/main/modules/secrets.nix + { config, inputs, lib, ... }: + let + # If the given expression is a bare set, it will be wrapped in a function, + # so that the imported file can always be applied to the inputs, similar to + # how modules can be functions or sets. + constSet = x: if builtins.isAttrs x then (_: x) else x; + + # Try to access the extra builtin we loaded via nix-plugins. + # Throw an error if that doesn't exist. + sopsImportEncrypted = + assert lib.assertMsg (builtins ? extraBuiltins.sopsImportEncrypted) + "The extra builtin 'sopsImportEncrypted' is not available, so repo.secrets cannot be decrypted. Did you forget to add nix-plugins and point it to `/nix/extra-builtins.nix` ?"; + builtins.extraBuiltins.sopsImportEncrypted; + + # This "imports" an encrypted .nix.age file by evaluating the decrypted content. + importEncrypted = + path: + constSet ( + if builtins.pathExists path then + sopsImportEncrypted path + else + { } + ); + in + { + options = { + repo = { + secretFiles = lib.mkOption { + default = { }; + type = lib.types.attrsOf lib.types.path; + example = lib.literalExpression "{ local = ./pii.nix.enc; }"; + description = '' + This file manages the origin for this machine's repository-secrets. Anything that is + technically not a secret in the classical sense (i.e. that it has to be protected + after it has been deployed), but something you want to keep secret from the public; + Anything that you wouldn't want people to see on GitHub, but that can live unencrypted + on your own devices. Consider it a more ergonomic nix alternative to using git-crypt. + + All of these secrets may (and probably will be) put into the world-readable nix-store + on the build and target hosts. You'll most likely want to store personally identifiable + information here, such as: + - MAC Addreses + - Static IP addresses + - Your full name (when configuring your users) + - Your postal address (when configuring e.g. home-assistant) + - ... + + Each path given here must be an sops-encrypted .nix file. For each attribute ``, + the corresponding file will be decrypted, imported and exposed as {option}`repo.secrets.`. + ''; + }; + + secrets = lib.mkOption { + readOnly = true; + default = lib.mapAttrs (_: x: importEncrypted x inputs) config.repo.secretFiles; + type = lib.types.unspecified; + description = "Exposes the loaded repo secrets. This option is read-only."; + }; + }; + swarselmodules.pii = lib.mkEnableOption "enable pii management"; + }; + config = lib.mkIf config.swarselmodules.pii { + repo.secretFiles = + let + local = config.node.secretsDir + "/pii.nix.enc"; + in + (lib.optionalAttrs (lib.pathExists local) { inherit local; }) // lib.optionalAttrs true { + common = ../../../secrets/repo/pii.nix.enc; + }; + }; + } + +#+end_src + +**** Lanzaboote (secure boot) +:PROPERTIES: +:CUSTOM_ID: h:d9a89071-b3ba-44d1-b5e0-e9ca6270d377 +:END: + +This dynamically uses systemd boot or Lanzaboote depending on the minimal system state and `config.swarselsystems.isSecureBoot`. + +#+begin_src nix-ts :tangle modules/nixos/common/lanzaboote.nix + { lib, pkgs, config, minimal, ... }: + { + options.swarselmodules.lanzaboote = lib.mkEnableOption "lanzaboote config"; + config = lib.mkIf config.swarselmodules.lanzaboote { + + environment.systemPackages = lib.mkIf config.swarselsystems.isSecureBoot [ + pkgs.sbctl + ]; + + boot = { + loader = { + efi.canTouchEfiVariables = true; + systemd-boot.enable = lib.swarselsystems.mkIfElse (minimal || !config.swarselsystems.isSecureBoot) (lib.mkForce true) (lib.mkForce false); + }; + lanzaboote = lib.mkIf (!minimal && config.swarselsystems.isSecureBoot) { + enable = true; + pkiBundle = "/var/lib/sbctl"; + configurationLimit = 6; + }; + }; + }; + } +#+end_src + +**** Boot +:PROPERTIES: +:CUSTOM_ID: h:a1311b07-2a8d-4c1f-addc-8572fc184e0d +:END: + +#+begin_src nix-ts :tangle modules/nixos/common/boot.nix + { lib, pkgs, config, globals, ... }: + { + options.swarselmodules.boot = lib.mkEnableOption "boot config"; + config = lib.mkIf config.swarselmodules.boot { + boot = { + initrd.systemd = { + enable = true; + emergencyAccess = globals.root.hashedPassword; + users.root.shell = "${pkgs.bashInteractive}/bin/bash"; + storePaths = [ "${pkgs.bashInteractive}/bin/bash" ]; + extraBin = { + ip = "${pkgs.iproute2}/bin/ip"; + ping = "${pkgs.iputils}/bin/ping"; + cryptsetup = "${pkgs.cryptsetup}/bin/cryptsetup"; + }; + }; + kernelParams = [ "log_buf_len=16M" ]; + tmp.useTmpfs = true; + loader.timeout = lib.mkDefault 2; + }; + + console.earlySetup = true; + + }; + } +#+end_src + +**** Impermanence +:PROPERTIES: +:CUSTOM_ID: h:e7668594-fa8b-4d36-a695-a58222478988 +:END: + +This is where the impermanence magic happens. When this is enabled, the root directory is rolled back to a blanket state on each reboot. + +Normally, doing that also resets the lecture that happens on the first use of =sudo=, so we disable that at this point. Also, here we can set files to be persisted. Do note that you should still pay attention to files that need sudo access, as these need to be copied manually. + +#+begin_src nix-ts :tangle modules/nixos/common/impermanence.nix + { config, lib, ... }: + let + mapperTarget = lib.swarselsystems.mkIfElse config.swarselsystems.isCrypted "/dev/mapper/cryptroot" "/dev/disk/by-label/nixos"; + inherit (config.swarselsystems) isImpermanence isCrypted; + in + { + options.swarselmodules.impermanence = lib.mkEnableOption "impermanence config"; + config = lib.mkIf config.swarselmodules.impermanence { + + + security.sudo.extraConfig = lib.mkIf isImpermanence '' + # rollback results in sudo lectures after each reboot + Defaults lecture = never + ''; + + # This script does the actual wipe of the system + # So if it doesn't run, the btrfs system effectively acts like a normal system + # Taken from https://github.com/NotAShelf/nyx/blob/2a8273ed3f11a4b4ca027a68405d9eb35eba567b/modules/core/common/system/impermanence/default.nix + boot.tmp.useTmpfs = lib.mkIf (!isImpermanence) true; + boot.initrd.systemd = lib.mkIf isImpermanence { + enable = true; + services.rollback = { + description = "Rollback BTRFS root subvolume to a pristine state"; + wantedBy = [ "initrd.target" ]; + # make sure it's done after encryption + # i.e. LUKS/TPM process + after = lib.swarselsystems.mkIfElseList isCrypted [ "systemd-cryptsetup@cryptroot.service" ] [ "dev-disk-by\\x2dlabel-nixos.device" ]; + requires = lib.mkIf (!isCrypted) [ "dev-disk-by\\x2dlabel-nixos.device" ]; + # mount the root fs before clearing + before = [ "sysroot.mount" ]; + unitConfig.DefaultDependencies = "no"; + serviceConfig.Type = "oneshot"; + script = '' + mkdir -p /mnt + + # We first mount the btrfs root to /mnt + # so we can manipulate btrfs subvolumes. + mount -o subvolid=5 -t btrfs ${mapperTarget} /mnt + btrfs subvolume list -o /mnt/root + + # While we're tempted to just delete /root and create + # a new snapshot from /root-blank, /root is already + # populated at this point with a number of subvolumes, + # which makes `btrfs subvolume delete` fail. + # So, we remove them first. + # + # /root contains subvolumes: + # - /root/var/lib/portables + # - /root/var/lib/machines + + btrfs subvolume list -o /mnt/root | + cut -f9 -d' ' | + while read subvolume; do + echo "deleting /$subvolume subvolume..." + btrfs subvolume delete "/mnt/$subvolume" + done && + echo "deleting /root subvolume..." && + btrfs subvolume delete /mnt/root + + echo "restoring blank /root subvolume..." + btrfs subvolume snapshot /mnt/root-blank /mnt/root + + # Once we're done rolling back to a blank snapshot, + # we can unmount /mnt and continue on the boot process. + umount /mnt + ''; + }; + }; + + + environment.persistence."/persist" = lib.mkIf isImpermanence { + hideMounts = true; + directories = + [ + "/root/.dotfiles" + "/etc/nix" + "/etc/NetworkManager/system-connections" + "/var/lib/nixos" + "/var/tmp" + { + directory = "/var/tmp/nix-import-encrypted"; # Decrypted repo-secrets can be kept + mode = "1777"; + } + # "/etc/secureboot" + ]; + + files = [ + "/etc/ssh/ssh_host_ed25519_key" + "/etc/ssh/ssh_host_ed25519_key.pub" + "/etc/machine-id" + ]; + }; + }; + + } +#+end_src + +*** Client +:PROPERTIES: +:CUSTOM_ID: h:1bb03c4c-7749-47c1-9af6-1b3d748cebf4 +:END: + +This section is to be used for modules that are most likely only used on client PCs (like my laptops) but no on servers. + +**** Imports +:PROPERTIES: +:CUSTOM_ID: h:4acbe063-188b-42e7-b75c-b6d2e232e784 +:END: + +This section is for setting things that should be used on hosts that are using the default NixOS configuration. This means that servers should NOT import this, as much of these imported modules are user-configured. + +#+begin_src nix-ts :tangle modules/nixos/client/default.nix + { lib, ... }: + let + importNames = lib.swarselsystems.readNix "modules/nixos/client"; + in + { + imports = lib.swarselsystems.mkImports importNames "modules/nixos/client"; + } + +#+end_src + +**** System Packages +:PROPERTIES: +:CUSTOM_ID: h:0e7e8bea-ec58-499c-9731-09dddfc39532 +:END: + +Mostly used to install some compilers and lsp's that I want to have available when not using a devShell flake. Most other packages should go in [[#h:893a7f33-7715-415b-a895-2687ded31c18][Installed packages]]. + +#+begin_src nix-ts :tangle modules/nixos/client/packages.nix + { lib, config, pkgs, minimal, ... }: + { + options.swarselmodules.packages = lib.mkEnableOption "install packages"; + config = lib.mkIf config.swarselmodules.packages { + + environment.systemPackages = with pkgs; lib.optionals (!minimal) [ + # yubikey packages + gnupg + yubikey-personalization + yubico-pam + yubioath-flutter + yubikey-manager + yubikey-touch-detector + yubico-piv-tool + cfssl + pcsc-tools + pcscliteWithPolkit.out + + # ledger packages + ledger-live-desktop + + # pinentry + dbus + # swaylock-effects + syncthingtray-minimal + swayosd + + # secure boot + sbctl + + libsForQt5.qt5.qtwayland + + # do not do this! clashes with the flake + # nix-index + + nixos-generators + + # commit hooks + pre-commit + + # proc info + acpi + + # pci info + pciutils + usbutils + + # better make for general tasks + just + + # sops + ssh-to-age + sops + + # keyboards + qmk + vial + via + + # theme related + adwaita-icon-theme + + # kde-connect + xdg-desktop-portal + xdg-desktop-portal-gtk + xdg-desktop-portal-wlr + + # bluetooth + bluez + ghostscript_headless + wireguard-tools + nixd + zig + zls + + elk-to-svg + + ] ++ lib.optionals minimal [ + networkmanager + curl + git + gnupg + rsync + ssh-to-age + sops + vim + just + sbctl + ]; + + nixpkgs.config.permittedInsecurePackages = lib.mkIf (!minimal) [ + "jitsi-meet-1.0.8043" + "electron-29.4.6" + "SDL_ttf-2.0.11" + # audacity? + "mbedtls-2.28.10" + # "qtwebengine-5.15.19" + ]; + }; + } +#+end_src + +**** Environment setup +:PROPERTIES: +:CUSTOM_ID: h:f4006367-0965-4b4f-a3b0-45f63b07d2b8 +:END: + +Next, we will setup some environment variables that need to be set on the system-side. We apply some compatibility options for chromium apps on wayland, enable the wordlist and make metadata reading possible for my file explorer (nautilus). + +#+begin_src nix-ts :tangle modules/nixos/client/env.nix + { lib, config, pkgs, ... }: + { + options.swarselmodules.env = lib.mkEnableOption "environment config"; + config = lib.mkIf config.swarselmodules.env { + + environment = { + wordlist.enable = true; + sessionVariables = { + NIXOS_OZONE_WL = "1"; + SWARSEL_LO_RES = config.swarselsystems.lowResolution; + SWARSEL_HI_RES = config.swarselsystems.highResolution; + GST_PLUGIN_SYSTEM_PATH_1_0 = lib.makeSearchPathOutput "lib" "lib/gstreamer-1.0" (with pkgs.gst_all_1; [ + gst-plugins-good + gst-plugins-bad + gst-plugins-ugly + gst-libav + ]); + } // (lib.optionalAttrs (!config.swarselsystems.isPublic) { }); + }; + }; + } +#+end_src + +**** Security (polkit) +:PROPERTIES: +:CUSTOM_ID: h:e2d40df9-0026-4caa-8476-9dc2353055a1 +:END: + +Needed for control over system-wide privileges etc. Also I make sure that the root user has access to =SSH_AUTH_SOCK= (without this, root will not be able to read my =nix-secrets= repository). + +#+begin_src nix-ts :tangle modules/nixos/client/polkit.nix + { lib, config, minimal, ... }: + { + options.swarselmodules.security = lib.mkEnableOption "security config"; + config = lib.mkIf config.swarselmodules.security { + + security = { + pam.services = lib.mkIf (!minimal) { + login.u2fAuth = true; + sudo.u2fAuth = true; + sshd.u2fAuth = false; + swaylock = { + u2fAuth = true; + fprintAuth = false; + }; + }; + polkit.enable = lib.mkIf (!minimal) true; + + sudo.extraConfig = '' + Defaults env_keep+=SSH_AUTH_SOCK + '' + lib.optionalString (!minimal) '' + Defaults env_keep+=XDG_RUNTIME_DIR + Defaults env_keep+=WAYLAND_DISPLAY + ''; + }; + }; + } +#+end_src + +**** Reduce systemd timeouts +:PROPERTIES: +:CUSTOM_ID: h:12858442-c129-4aa1-9c9c-a0916e36b302 +:END: + +There is a persistent bug over Linux kernels that makes the user wait 1m30s on system shutdown due to the reason =a stop job is running for session 1 of user ...=. I do not want to wait that long and am confident no important data is lost by doing this. + +#+begin_src nix-ts :tangle modules/nixos/client/systemd.nix + { lib, config, ... }: + { + options.swarselmodules.systemdTimeout = lib.mkEnableOption "systemd timeout config"; + config = lib.mkIf config.swarselmodules.systemdTimeout { + # systemd + systemd.settings.Manager = { + DefaultTimeoutStartSec = "60s"; + DefaultTimeoutStopSec = "15s"; + }; + }; + } +#+end_src + +**** Hardware settings +:PROPERTIES: +:CUSTOM_ID: h:1fa7cf61-5c03-43a3-a7f0-3d6ee246b31b +:END: + +Enable OpenGL, Sound, Bluetooth and various drivers. + +#+begin_src nix-ts :tangle modules/nixos/client/hardware.nix + { pkgs, config, lib, ... }: + { + + options.swarselmodules.hardware = lib.mkEnableOption "hardware config"; + options.swarselsystems = { + hasBluetooth = lib.mkEnableOption "bluetooth availability"; + hasFingerprint = lib.mkEnableOption "fingerprint sensor availability"; + trackpoint = { + isAvailable = lib.mkEnableOption "trackpoint availability"; + trackpoint.device = lib.mkOption { + type = lib.types.str; + default = ""; + }; + }; + }; + config = lib.mkIf config.swarselmodules.hardware { + hardware = { + # opengl.driSupport32Bit = true is replaced with graphics.enable32Bit and hence redundant + graphics = { + enable = true; + enable32Bit = true; + }; + + + trackpoint = lib.mkIf config.swarselsystems.trackpoint.isAvailable { + enable = true; + inherit (config.swarselsystems.trackpoint) device; + }; + + keyboard.qmk.enable = true; + + enableAllFirmware = lib.mkDefault true; + + bluetooth = lib.mkIf config.swarselsystems.hasBluetooth { + enable = true; + package = pkgs.stable.bluez; + powerOnBoot = true; + settings = { + General = { + Enable = "Source,Sink,Media,Socket"; + }; + }; + }; + }; + + services.fprintd.enable = lib.mkIf config.swarselsystems.hasFingerprint true; + }; + } +#+end_src + +**** Pulseaudio +:PROPERTIES: +:CUSTOM_ID: h:63f6773e-b321-4b1d-a206-3913658cf62d +:END: + +This is only used on systems not running Pipewire. + + +#+begin_src nix-ts :tangle modules/nixos/client/pulseaudio.nix + { config, pkgs, lib, ... }: { + + options.swarselmodules.pulseaudio = lib.mkEnableOption "pulseaudio config"; + config = lib.mkIf config.swarselmodules.pulseaudio { + services.pulseaudio = { + enable = lib.mkIf (!config.services.pipewire.enable) true; + package = pkgs.pulseaudioFull; + }; + }; + + } +#+end_src +**** Pipewire +:PROPERTIES: +:CUSTOM_ID: h:aa433f5e-a455-4414-b76b-0a2692fa06aa +:END: + +Pipewire handles communication on Wayland. This enables several sound tools as well as screen sharing in combinaton with =xdg-desktop-portal-wlr=. + +#+begin_src nix-ts :tangle modules/nixos/client/pipewire.nix + { lib, config, pkgs, ... }: + { + options.swarselmodules.pipewire = lib.mkEnableOption "pipewire config"; + config = lib.mkIf config.swarselmodules.pipewire { + security.rtkit.enable = true; # this is required for pipewire real-time access + + services.pipewire = { + enable = true; + package = pkgs.stable.pipewire; + pulse.enable = true; + jack.enable = true; + audio.enable = true; + wireplumber.enable = true; + alsa = { + enable = true; + support32Bit = true; + }; + }; + }; + } +#+end_src +**** Common network settings +:PROPERTIES: +:CUSTOM_ID: h:7d696b64-debe-4a95-80b5-1e510156a6c6 +:END: + +Here I only enable =networkmanager= and a few default networks. The rest of the network config is done separately in [[#h:88bf4b90-e94b-46fb-aaf1-a381a512860d][System specific configuration]]. + +#+begin_src nix-ts :tangle modules/nixos/client/network.nix + { self, lib, pkgs, config, globals, ... }: + let + certsSopsFile = self + /secrets/certs/secrets.yaml; + clientSopsFile = self + /secrets/${config.node.name}/secrets.yaml; + + inherit (config.repo.secrets.common.network) wlan1 mobile1 vpn1-location vpn1-cipher vpn1-address eduroam-anon; + + iwd = config.networking.networkmanager.wifi.backend == "iwd"; + in + { + options.swarselsystems = { + firewall = lib.swarselsystems.mkTrueOption; + }; + options.swarselmodules.network = lib.mkEnableOption "network config"; + config = lib.mkIf config.swarselmodules.network { + + sops = { + secrets = lib.mkIf (!config.swarselsystems.isPublic) { + wlan1-pw = { }; + wlan2-pw = { }; + laptop-hotspot-pw = { }; + mobile-hotspot-pw = { }; + eduroam-user = { }; + eduroam-pw = { }; + pia-vpn-user = { }; + pia-vpn-pw = { }; + home-wireguard-client-private-key = { sopsFile = clientSopsFile; }; + home-wireguard-server-public-key = { }; + home-wireguard-endpoint = { }; + pia-vpn1-crl-pem = { sopsFile = certsSopsFile; }; + pia-vpn1-ca-pem = { sopsFile = certsSopsFile; }; + }; + templates = lib.mkIf (!config.swarselsystems.isPublic) { + "network-manager.env".content = '' + WLAN1_PW=${config.sops.placeholder.wlan1-pw} + WLAN2_PW=${config.sops.placeholder.wlan2-pw} + LAPTOP_HOTSPOT_PW=${config.sops.placeholder.laptop-hotspot-pw} + MOBILE_HOTSPOT_PW=${config.sops.placeholder.mobile-hotspot-pw} + EDUROAM_USER=${config.sops.placeholder.eduroam-user} + EDUROAM_PW=${config.sops.placeholder.eduroam-pw} + PIA_VPN_USER=${config.sops.placeholder.pia-vpn-user} + PIA_VPN_PW=${config.sops.placeholder.pia-vpn-pw} + HOME_WIREGUARD_CLIENT_PRIVATE_KEY=${config.sops.placeholder.home-wireguard-client-private-key} + HOME_WIREGUARD_SERVER_PUBLIC_KEY=${config.sops.placeholder.home-wireguard-server-public-key} + HOME_WIREGUARD_ENDPOINT=${config.sops.placeholder.home-wireguard-endpoint} + ''; + }; + }; + + networking = { + inherit (config.swarselsystems) hostName; + hosts = { + "${globals.networks.home-lan.hosts.winters.ipv4}" = [ globals.services.transmission.domain ]; + }; + wireless.iwd = { + enable = true; + settings = { + IPv6 = { + Enabled = true; + }; + Settings = { + AutoConnect = true; + }; + # DriverQuirks = { + # UseDefaultInterface = true; + # }; + }; + }; + nftables.enable = lib.mkDefault true; + enableIPv6 = lib.mkDefault true; + firewall = { + enable = lib.swarselsystems.mkStrong config.swarselsystems.firewall; + checkReversePath = lib.mkDefault false; + allowedUDPPorts = [ 51820 ]; # 51820: wireguard + allowedTCPPortRanges = [ + { from = 1714; to = 1764; } # kde-connect + ]; + allowedUDPPortRanges = [ + { from = 1714; to = 1764; } # kde-connect + ]; + }; + + networkmanager = { + enable = true; + wifi.backend = "iwd"; + plugins = [ + # list of plugins: https://search.nixos.org/packages?query=networkmanager- + # docs https://networkmanager.dev/docs/vpn/ + pkgs.networkmanager-openconnect + pkgs.networkmanager-openvpn + ]; + ensureProfiles = lib.mkIf (!config.swarselsystems.isPublic) { + environmentFiles = [ + "${config.sops.templates."network-manager.env".path}" + ]; + profiles = + let + inherit (config.repo.secrets.local.network) home-wireguard-address home-wireguard-allowed-ips; + in + { + ${wlan1} = { + connection = { + id = wlan1; + # permissions = ""; + type = "wifi"; + autoconnect-priority = "999"; + }; + ipv4 = { + # dns-search = ""; + method = "auto"; + }; + ipv6 = { + addr-gen-mode = "stable-privacy"; + # dns-search = ""; + method = "auto"; + }; + wifi = { + # mac-address-blacklist = ""; + mode = "infrastructure"; + # band = "a"; + ssid = wlan1; + }; + wifi-security = { + # auth-alg = "open"; + key-mgmt = "wpa-psk"; + psk = "$WLAN1_PW"; + }; + }; + + LAN-Party = { + connection = { + autoconnect = "false"; + id = "LAN-Party"; + type = "ethernet"; + }; + ethernet = { + auto-negotiate = "true"; + cloned-mac-address = "preserve"; + }; + ipv4 = { method = "shared"; }; + ipv6 = { + addr-gen-mode = "stable-privacy"; + method = "auto"; + }; + proxy = { }; + }; + + eduroam = { + "802-1x" = { + eap = if (!iwd) then "ttls;" else "peap;"; + identity = "$EDUROAM_USER"; + password = "$EDUROAM_PW"; + phase2-auth = "mschapv2"; + anonymous-identity = lib.mkIf iwd eduroam-anon; + }; + connection = { + id = "eduroam"; + type = "wifi"; + }; + ipv4 = { method = "auto"; }; + ipv6 = { + addr-gen-mode = "default"; + method = "auto"; + }; + proxy = { }; + wifi = { + mode = "infrastructure"; + ssid = "eduroam"; + }; + wifi-security = { + auth-alg = "open"; + key-mgmt = "wpa-eap"; + }; + }; + + local = { + connection = { + autoconnect = "false"; + id = "local"; + type = "ethernet"; + }; + ethernet = { }; + ipv4 = { + address1 = "10.42.1.1/24"; + method = "shared"; + }; + ipv6 = { + addr-gen-mode = "stable-privacy"; + method = "auto"; + }; + proxy = { }; + }; + + ${mobile1} = { + connection = { + id = mobile1; + type = "wifi"; + autoconnect-priority = "500"; + }; + ipv4 = { method = "auto"; }; + ipv6 = { + addr-gen-mode = "default"; + method = "auto"; + }; + proxy = { }; + wifi = { + mode = "infrastructure"; + ssid = mobile1; + }; + wifi-security = { + auth-alg = "open"; + key-mgmt = "wpa-psk"; + psk = "$MOBILE_HOTSPOT_PW"; + }; + }; + + home-wireguard = { + connection = { + id = "HomeVPN"; + type = "wireguard"; + autoconnect = "false"; + interface-name = "wg1"; + }; + wireguard = { private-key = "$HOME_WIREGUARD_CLIENT_PRIVATE_KEY"; }; + "wireguard-peer.$HOME_WIREGURARD_SERVER_PUBLIC_KEY" = { + endpoint = "$HOME_WIREGUARD_ENDPOINT"; + allowed-ips = home-wireguard-allowed-ips; + }; + ipv4 = { + method = "ignore"; + address1 = home-wireguard-address; + }; + ipv6 = { + addr-gen-mode = "stable-privacy"; + method = "ignore"; + }; + proxy = { }; + }; + + pia-vpn1 = { + connection = { + autoconnect = "false"; + id = "PIA ${vpn1-location}"; + type = "vpn"; + }; + ipv4 = { method = "auto"; }; + ipv6 = { + addr-gen-mode = "stable-privacy"; + method = "auto"; + }; + proxy = { }; + vpn = { + auth = "sha1"; + ca = config.sops.secrets."pia-vpn1-ca-pem".path; + challenge-response-flags = "2"; + cipher = vpn1-cipher; + compress = "yes"; + connection-type = "password"; + crl-verify-file = config.sops.secrets."pia-vpn1-crl-pem".path; + dev = "tun"; + password-flags = "0"; + remote = vpn1-address; + remote-cert-tls = "server"; + reneg-seconds = "0"; + service-type = "org.freedesktop.NetworkManager.openvpn"; + username = "$PIA_VPN_USER"; + }; + vpn-secrets = { password = "$PIA_VPN_PW"; }; + }; + + Hotspot = { + connection = { + autoconnect = "false"; + id = "Hotspot"; + type = "wifi"; + }; + ipv4 = { method = "shared"; }; + ipv6 = { + addr-gen-mode = "default"; + method = "ignore"; + }; + proxy = { }; + wifi = { + mode = "ap"; + ssid = "Hotspot-${config.swarselsystems.mainUser}"; + }; + wifi-security = { + group = "ccmp;"; + key-mgmt = "wpa-psk"; + pairwise = "ccmp;"; + proto = "rsn;"; + psk = "$MOBILE_HOTSPOT_PW"; + }; + }; + + }; + }; + }; + }; + + systemd.services.NetworkManager-ensure-profiles.after = [ "NetworkManager.service" ]; + }; + } +#+end_src + +**** sops +:PROPERTIES: +:CUSTOM_ID: h:d87d80fd-2ac7-4f29-b338-0518d06b4deb +:END: + +I use sops-nix to handle secrets that I want to have available on my machines at all times. Procedure to add a new machine: +- `ssh-keygen -t ed25519 -C "NAME sops"` in .ssh directory (or wherever) - name e.g. "sops" +- cat ~/.ssh/sops.pub | ssh-to-age | wl-copy +- add the output to .sops.yaml +- cp ~/.ssh/sops.pub ~/.dotfiles/secrets/keys/NAME.pub +- update entry for sops.age.sshKeyPaths + +#+begin_src nix-ts :tangle modules/nixos/client/sops.nix + { config, lib, ... }: + { + options.swarselmodules.sops = lib.mkEnableOption "sops config"; + config = lib.mkIf config.swarselmodules.sops { + sops = { + + # age.sshKeyPaths = lib.swarselsystems.mkIfElseList config.swarselsystems.isBtrfs [ "/persist/.ssh/sops" "/persist/.ssh/ssh_host_ed25519_key" ] [ "${config.swarselsystems.homeDir}/.ssh/sops" "/etc/ssh/sops" "/etc/ssh/ssh_host_ed25519_key" ]; + age.sshKeyPaths = [ "${config.swarselsystems.homeDir}/.ssh/sops" "/etc/ssh/sops" "${if config.swarselsystems.isImpermanence then "/persist" else ""}/etc/ssh/ssh_host_ed25519_key" ]; + defaultSopsFile = "${if config.swarselsystems.isImpermanence then "/persist" else ""}${config.swarselsystems.flakePath}/secrets/general/secrets.yaml"; + + validateSopsFiles = false; + + }; + }; + } +#+end_src + +**** Remote building + +#+begin_src nix-ts :tangle modules/nixos/client/remotebuild.nix + { lib, config, globals, ... }: + let + inherit (config.swarselsystems) homeDir mainUser isClient; + in + { + options.swarselmodules.remotebuild = lib.mkEnableOption "enable remote builds on this machine"; + config = lib.mkIf config.swarselmodules.remotebuild { + + sops.secrets = { + builder-key = lib.mkIf isClient { owner = mainUser; path = "${homeDir}/.ssh/builder"; mode = "0600"; }; + nixbuild-net-key = { owner = mainUser; path = "${homeDir}/.ssh/nixbuild-net"; mode = "0600"; }; + }; + + nix = { + settings.builders-use-substitutes = true; + distributedBuilds = true; + buildMachines = [ + (lib.mkIf isClient { + hostName = config.repo.secrets.common.builder1-ip; + system = "aarch64-linux"; + maxJobs = 20; + speedFactor = 10; + }) + (lib.mkIf isClient { + hostName = globals.hosts.belchsfactory.wanAddress4; + system = "aarch64-linux"; + maxJobs = 4; + speedFactor = 2; + protocol = "ssh-ng"; + }) + { + hostName = "eu.nixbuild.net"; + system = "x86_64-linux"; + maxJobs = 100; + speedFactor = 2; + supportedFeatures = [ "big-parallel" ]; + } + ]; + }; + programs.ssh = { + knownHosts = { + nixbuild = { + hostNames = [ "eu.nixbuild.net" ]; + publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPIQCZc54poJ8vqawd8TraNryQeJnvH1eLpIDgbiqymM"; + }; + builder1 = lib.mkIf isClient { + hostNames = [ config.repo.secrets.common.builder1-ip ]; + publicKey = config.repo.secrets.common.builder1-pubHostKey; + }; + jump = lib.mkIf isClient { + hostNames = [ globals.hosts.liliputsteps.wanAddress4 ]; + publicKey = config.repo.secrets.common.jump-pubHostKey; + }; + builder2 = lib.mkIf isClient { + hostNames = [ globals.hosts.belchsfactory.wanAddress4 ]; + publicKey = config.repo.secrets.common.builder2-pubHostKey; + }; + }; + extraConfig = '' + Host eu.nixbuild.net + ConnectTimeout 1 + PubkeyAcceptedKeyTypes ssh-ed25519 + ServerAliveInterval 60 + IPQoS throughput + IdentityFile ${config.sops.secrets.nixbuild-net-key.path} + '' + lib.optionalString isClient '' + Host ${config.repo.secrets.common.builder1-ip} + ConnectTimeout 1 + User ${mainUser} + IdentityFile ${config.sops.secrets.builder-key.path} + + Host ${globals.hosts.belchsfactory.wanAddress4} + ConnectTimeout 5 + ProxyJump ${globals.hosts.liliputsteps.wanAddress4} + User builder + IdentityFile ${config.sops.secrets.builder-key.path} + + Host ${globals.hosts.liliputsteps.wanAddress4} + ConnectTimeout 1 + User jump + IdentityFile ${config.sops.secrets.builder-key.path} + ''; + }; + }; + } +#+end_src + +**** Theme (stylix) +:PROPERTIES: +:CUSTOM_ID: h:e6e44705-94af-49fe-9ca0-0629d0f7d932 +:END: + +By default, [[https://github.com/danth/stylix][stylix]] wants to style GRUB as well. However, I think that looks horrible. +=theme= is defined in [[#h:5bc1b0c9-dc59-4c81-b5b5-e60699deda78][Theme (stylix)]]. + +#+begin_src nix-ts :noweb yes :tangle modules/nixos/client/stylix.nix + { self, lib, config, vars, ... }: + { + options.swarselmodules.stylix = lib.mkEnableOption "stylix config"; + config = { + stylix = { + enable = true; + base16Scheme = "${self}/files/stylix/swarsel.yaml"; + } // lib.optionalAttrs config.swarselmodules.stylix + (lib.recursiveUpdate + { + targets.grub.enable = false; # the styling makes grub more ugly + image = config.swarselsystems.wallpaper; + } + vars.stylix); + home-manager.users."${config.swarselsystems.mainUser}" = { + stylix = { + targets = vars.stylixHomeTargets; + }; + }; + }; + } +#+end_src + +**** Programs (including zsh setup) +:PROPERTIES: +:CUSTOM_ID: h:2bbf5f31-246d-4738-925f-eca40681f7b6 +:END: + +Some programs profit from being installed through dedicated NixOS settings on system-level; these go here. Notably the zsh setup goes here and cannot be deleted under any circumstances. + +#+begin_src nix-ts :tangle modules/nixos/client/programs.nix + { lib, config, ... }: + { + options.swarselmodules.programs = lib.mkEnableOption "small program modules config"; + config = lib.mkIf config.swarselmodules.programs { + programs = { + dconf.enable = true; + evince.enable = true; + kdeconnect.enable = true; + }; + }; + } +#+end_src + +***** zsh +:PROPERTIES: +:CUSTOM_ID: h:7daa06ff-d3b0-4491-97ce-770b749c52f9 +:END: +Here I disable global completion to prevent redundant compinit calls and cache invalidation that slow down shell startup (enabled on the home-manager side). + +#+begin_src nix-ts :tangle modules/nixos/client/zsh.nix + { lib, config, pkgs, ... }: + { + options.swarselmodules.zsh = lib.mkEnableOption "zsh base config"; + config = lib.mkIf config.swarselmodules.zsh { + programs.zsh = { + enable = true; + enableCompletion = false; + }; + users.defaultUserShell = pkgs.zsh; + environment.shells = with pkgs; [ zsh ]; + environment.pathsToLink = [ "/share/zsh" ]; + }; + } +#+end_src +***** syncthing +:PROPERTIES: +:CUSTOM_ID: h:1e6d3d56-e415-43a2-8e80-3bad8062ecf8 +:END: + +#+begin_src nix-ts :tangle modules/nixos/client/syncthing.nix + { lib, config, pkgs, ... }: + let + inherit (config.swarselsystems) mainUser homeDir; + devices = config.swarselsystems.syncthing.syncDevices; + servicePort = 8384; + in + { + options.swarselmodules.syncthing = lib.mkEnableOption "syncthing config"; + config = lib.mkIf config.swarselmodules.syncthing { + services.syncthing = { + enable = true; + systemService = true; + guiAddress = "127.0.0.1:${builtins.toString servicePort}"; + package = pkgs.syncthing; + user = mainUser; + dataDir = homeDir; + configDir = "${homeDir}/.config/syncthing"; + openDefaultPorts = true; + overrideDevices = true; + overrideFolders = true; + settings = { + options = { + urAccepted = -1; + }; + inherit (config.swarselsystems.syncthing) devices; + folders = { + "Default Folder" = lib.mkDefault { + path = "${homeDir}/Sync"; + inherit devices; + id = "default"; + }; + "Obsidian" = { + path = "${homeDir}/Obsidian"; + inherit devices; + id = "yjvni-9eaa7"; + }; + "Org" = { + path = "${homeDir}/Org"; + inherit devices; + id = "a7xnl-zjj3d"; + }; + "Vpn" = { + path = "${homeDir}/Vpn"; + inherit devices; + id = "hgp9s-fyq3p"; + }; + }; + }; + }; + }; + } +#+end_src + +**** Services +:PROPERTIES: +:CUSTOM_ID: h:79f3258f-ed9d-434d-b50a-e58d57ade2a7 +:END: + +Setting up some hardware services as well as keyboard related settings. Here we make sure that we can use the CAPS key as a ESC/CTRL double key, which is a lifesaver. + +***** blueman +:PROPERTIES: +:CUSTOM_ID: h:b91df05b-113d-4d09-93d1-b271e5b76810 +:END: + +Enables the blueman service including the nice system tray icon. + +#+begin_src nix-ts :tangle modules/nixos/client/blueman.nix + { lib, config, ... }: + { + options.swarselmodules.blueman = lib.mkEnableOption "blueman config"; + config = lib.mkIf config.swarselmodules.blueman { + services.blueman.enable = true; + services.hardware.bolt.enable = true; + }; + } +#+end_src + +***** Network devices +:PROPERTIES: +:CUSTOM_ID: h:73ed28cb-2f82-47b2-8bc5-208278b55788 +:END: + +In this section we enable compatibility with several network devices I have at home, mainly printers and scanners. + +This allows me to use my big scanner/printer's scanning function over the network. +This also allows me to use my big scanner/printer's printing function over the network. Most of the settings are driver related. +Avahi is the service used for the network discovery. + +#+begin_src nix-ts :tangle modules/nixos/client/networkdevices.nix + { lib, config, pkgs, ... }: + { + options.swarselmodules.networkDevices = lib.mkEnableOption "network device config"; + config = lib.mkIf config.swarselmodules.networkDevices { + # enable scanners over network + hardware.sane = { + enable = true; + extraBackends = [ pkgs.sane-airscan ]; + }; + + # enable discovery and usage of network devices (esp. printers) + services.printing = { + enable = true; + drivers = [ + pkgs.gutenprint + pkgs.gutenprintBin + ]; + browsedConf = '' + BrowseDNSSDSubTypes _cups,_print + BrowseLocalProtocols all + BrowseRemoteProtocols all + CreateIPPPrinterQueues All + BrowseProtocols all + ''; + }; + + services.avahi = { + enable = true; + nssmdns4 = true; + openFirewall = true; + }; + }; + } +#+end_src + +***** enable GVfs +:PROPERTIES: +:CUSTOM_ID: h:f101daa2-604d-4553-99e2-f64b9c207f51 +:END: + +This is being set to allow myself to use all functions of nautilus in NixOS + +#+begin_src nix-ts :tangle modules/nixos/client/gvfs.nix + { lib, config, ... }: + { + options.swarselmodules.gvfs = lib.mkEnableOption "gvfs config for nautilus"; + config = lib.mkIf config.swarselmodules.gvfs { + services.gvfs.enable = true; + }; + } +#+end_src + +***** interception-tools: Make CAPS work as ESC/CTRL +:PROPERTIES: +:CUSTOM_ID: h:08d213d5-a9f4-4309-8635-ba557b01dc7d +:END: + +This is a super-convenient package that lets my remap my =CAPS= key to =ESC= if pressed shortly, and =CTRL= if being held. + +#+begin_src nix-ts :tangle modules/nixos/client/interceptiontools.nix + { lib, config, pkgs, ... }: + { + options.swarselmodules.interceptionTools = lib.mkEnableOption "interception tools config"; + config = lib.mkIf config.swarselmodules.interceptionTools { + # Make CAPS work as a dual function ESC/CTRL key + services.interception-tools = { + enable = true; + udevmonConfig = + let + dualFunctionKeysConfig = builtins.toFile "dual-function-keys.yaml" '' + TIMING: + TAP_MILLISEC: 200 + DOUBLE_TAP_MILLISEC: 0 + + MAPPINGS: + - KEY: KEY_CAPSLOCK + TAP: KEY_ESC + HOLD: KEY_LEFTCTRL + ''; + in + '' + - JOB: | + ${pkgs.interception-tools}/bin/intercept -g $DEVNODE \ + | ${pkgs.interception-tools-plugins.dual-function-keys}/bin/dual-function-keys -c ${dualFunctionKeysConfig} \ + | ${pkgs.interception-tools}/bin/uinput -d $DEVNODE + DEVICE: + EVENTS: + EV_KEY: [KEY_CAPSLOCK] + ''; + }; + }; + } +#+end_src + +***** keyd: remap SUPER +:PROPERTIES: +:CUSTOM_ID: h:6a0fb66c-dfda-47e9-87b2-8b02d58dd68b +:END: + + +#+begin_src nix-ts :tangle modules/nixos/client/keyd.nix + { lib, config, ... }: + let + moduleName = "keyd"; + in + { + options.swarselmodules.${moduleName} = lib.mkEnableOption "${moduleName} tools config"; + config = lib.mkIf config.swarselmodules.${moduleName} { + services.keyd = { + enable = true; + keyboards = { + default = { + ids = [ "*" ]; + settings = { + main = { + leftmeta = "overload(meta, macro(rightmeta+z))"; + rightmeta = "overload(meta, macro(rightmeta+z))"; + }; + }; + }; + }; + }; + }; + } +#+end_src + +***** power-profiles-daemon +:PROPERTIES: +:CUSTOM_ID: h:82fbba41-3a46-4db7-aade-49e4c23fc475 +:END: + +This enables power profile management. The available modes are: + +- power-saver +- balanced +- performance + +Most of the time I am using =power-saver=, however, it is good to be able to choose. + +#+begin_src nix-ts :tangle modules/nixos/client/power-profiles-daemon.nix + { lib, config, ... }: + { + options.swarselmodules.ppd = lib.mkEnableOption "power profiles daemon config"; + config = lib.mkIf config.swarselmodules.ppd { + services.power-profiles-daemon.enable = true; + }; + } +#+end_src + +***** SwayOSD +:PROPERTIES: +:CUSTOM_ID: h:5db15758-17d8-4bde-811d-d11ccdd3f3d3 +:END: + +#+begin_src nix-ts :tangle modules/nixos/client/swayosd.nix + { lib, pkgs, config, ... }: + { + options.swarselmodules.swayosd = lib.mkEnableOption "swayosd settings"; + config = lib.mkIf config.swarselmodules.swayosd { + environment.systemPackages = [ pkgs.dev.swayosd ]; + services.udev.packages = [ pkgs.dev.swayosd ]; + systemd.services.swayosd-libinput-backend = { + description = "SwayOSD LibInput backend for listening to certain keys like CapsLock, ScrollLock, VolumeUp, etc."; + documentation = [ "https://github.com/ErikReider/SwayOSD" ]; + wantedBy = [ "graphical.target" ]; + partOf = [ "graphical.target" ]; + after = [ "graphical.target" ]; + + serviceConfig = { + Type = "dbus"; + BusName = "org.erikreider.swayosd"; + ExecStart = "${pkgs.dev.swayosd}/bin/swayosd-libinput-backend"; + Restart = "on-failure"; + }; + }; + }; + } +#+end_src + +**** Hardware compatibility settings (Yubikey, Ledger, Keyboards) - udev rules +:PROPERTIES: +:CUSTOM_ID: h:7a89b5e3-b700-4167-8b14-2b8172f33936 +:END: +***** Yubikey +:PROPERTIES: +:CUSTOM_ID: h:49aa792d-edfb-4eac-ae31-ecf23c4dca00 +:END: + +This takes care of the main Yubikey related configuration on the NixOS side - note that the starting of the gpg-agent is done in the sway settings, to also perform this step of the setup for non NixOS-machines at the same time. + +I want to use the ssh-agent from gpg-agent's ssh compatibility, which is why we disable ssh-agent. Also, we load some extra udev rules using =hardware.gpgSmartcards.enable=. + +Many guides state that it is needed to enable =pcscd= to use the smartcard mode (CCID) of the Yubikey. However, enabling it causes some problems when locking the screen and unplugging the Yubikey, after which the Yubikey only becomes available again as a smart card after about one minute. I found that is is sufficient to enable =services.gpg-agent.enableScDaemon= in home-manager instead. + +Also, since I use a GPG key in sops, it seems that scdaemon creates an instance at boot which sometimes hogs the Yubikey, which leads to significant delays after e.g. locking the screen and unplugging the Yubikey. Since I do not need the GPG key for the actual sops secrets (I use machine age keys instead), I kill that process. + +#+begin_src nix-ts :tangle modules/nixos/client/hardwarecompatibility-yubikey.nix + { lib, config, pkgs, ... }: + let + inherit (config.swarselsystems) mainUser; + inherit (config.repo.secrets.common.yubikeys) cfg1 cfg2; + in + { + options.swarselmodules.yubikey = lib.mkEnableOption "yubikey config"; + config = lib.mkIf config.swarselmodules.yubikey { + programs.ssh.startAgent = false; + + services.pcscd.enable = false; + + hardware.gpgSmartcards.enable = true; + + security.pam.u2f = { + enable = true; + control = "sufficient"; + settings = { + interactive = false; # displays a prompt BEFORE asking for presence + cue = true; # prints a message that a touch is requrired + origin = "pam://${mainUser}"; # make the keys work on all machines + authfile = pkgs.writeText "u2f-mappings" (lib.concatStrings [ + mainUser + cfg1 + cfg2 + ]); + }; + }; + + services.udev.packages = with pkgs; [ + yubikey-personalization + ]; + + }; + } +#+end_src + +***** Ledger +:PROPERTIES: +:CUSTOM_ID: h:c3cba64c-cdd7-4d58-a2c2-6a7fb36ad6c4 +:END: + +This performs the necessary configuration to support this hardware. + +#+begin_src nix-ts :tangle modules/nixos/client/hardwarecompatibility-ledger.nix + { lib, config, pkgs, ... }: + { + options.swarselmodules.ledger = lib.mkEnableOption "ledger config"; + config = lib.mkIf config.swarselmodules.ledger { + hardware.ledger.enable = true; + + services.udev.packages = with pkgs; [ + ledger-udev-rules + ]; + }; + + } +#+end_src + +***** Keyboards +:PROPERTIES: +:CUSTOM_ID: h:103b68b6-33a1-4369-a534-5f36dfa95e03 +:END: + +This loads some udev rules that I need for my split keyboards. + +#+begin_src nix-ts :tangle modules/nixos/client/hardwarecompatibility-keyboards.nix + { lib, config, pkgs, ... }: + { + options.swarselmodules.keyboards = lib.mkEnableOption "keyboards config"; + config = lib.mkIf config.swarselmodules.keyboards { + services.udev.packages = with pkgs; [ + qmk-udev-rules + vial + via + ]; + }; + } +#+end_src + +**** System Login (greetd) +:PROPERTIES: +:CUSTOM_ID: h:eae45839-223a-4027-bce3-e26e092c9096 +:END: + +This section houses the greetd related settings. I do not really want to use a display manager, but it is useful to have setup in some ways - in my case for starting sway on system startup. Notably the default user login setting that is commented out here goes into the *system specific* settings, make sure to update it there + +#+begin_src nix-ts :tangle modules/nixos/client/login.nix + { lib, config, pkgs, ... }: + { + options.swarselmodules.login = lib.mkEnableOption "login config"; + config = lib.mkIf config.swarselmodules.login { + services.greetd = { + enable = true; + settings = { + # initial_session.command = "sway"; + initial_session.command = "uwsm start -- sway-uwsm.desktop"; + # --cmd sway + default_session.command = '' + ${pkgs.tuigreet}/bin/tuigreet \ + --time \ + --asterisks \ + --user-menu \ + --cmd "uwsm start -- sway-uwsm.desktop" + ''; + }; + }; + + # environment.etc."greetd/environments".text = '' + # sway + # ''; + }; + } +#+end_src + +**** nix-ld +:PROPERTIES: +:CUSTOM_ID: h:404cc18b-b5f8-48d9-a407-a0fd70d57f46 +:END: + +This provides libraries for binaries that are not patched for use on NixOS. This really makes the biggest gripe with NixOS go away, that being having to run a binary that is only found in a single spot. It is most of the times possible to patch such a file, but this makes such a situation take much less time to resolve. + +Only some binaries that touch system settings might still not work, apart from that, the list of libraries I have curated here should be quite exhaustive. + +When a program does not work, start with =nix-ldd =. This will tell you which library is missing. Afterwards, continue with =nix-locate = to find which packages provide that library. Add it to libraries below and rebuild. After a reboot, it will be visible using =nix-ldd=. It can also be useful to take a look at =ldd= to see which libraries are needed in general. + +#+begin_src nix-ts :tangle modules/nixos/client/nix-ld.nix + { lib, config, pkgs, ... }: + { + options.swarselmodules.nix-ld = lib.mkEnableOption "nix-ld config"; + config = lib.mkIf config.swarselmodules.nix-ld { + programs.nix-ld = { + enable = true; + libraries = with pkgs; [ + SDL + SDL2 + SDL2_image + SDL2_mixer + SDL2_ttf + SDL_image + SDL_mixer + SDL_ttf + alsa-lib + at-spi2-atk + at-spi2-core + atk + bzip2 + cairo + cups + curl + dbus + dbus-glib + expat + ffmpeg + flac + fontconfig + freeglut + freetype + fuse3 + gdk-pixbuf + glew110 + glib + gnome2.GConf + pango + gtk2 + gtk3 + icu + libGL + libappindicator-gtk2 + libappindicator-gtk3 + libcaca + libcanberra + libcap + libdbusmenu-gtk2 + libdrm + libelf + libgbm + libgcrypt + libglvnd + libidn + libindicator-gtk2 + libjpeg + libmikmod + libnotify + libogg + libpng + libpng12 + libpulseaudio + librsvg + libsamplerate + libtheora + libtiff + libudev0-shim + libunwind + libusb1 + libuuid + libva + libvdpau + libvorbis + libvpx + libxkbcommon + libxml2 + libz + mesa + nspr + nss + openssl + pango + pipewire + pixman + speex + # stable.cc.cc + stable25_05.steam-fhsenv-without-steam + systemd + tbb + vulkan-loader + xorg.libICE + xorg.libSM + xorg.libX11 + xorg.libXScrnSaver + xorg.libXcomposite + xorg.libXcursor + xorg.libXdamage + xorg.libXext + xorg.libXfixes + xorg.libXft + xorg.libXi + xorg.libXinerama + xorg.libXmu + xorg.libXrandr + xorg.libXrender + xorg.libXt + xorg.libXtst + xorg.libXxf86vm + xorg.libxcb + xorg.libxshmfence + zlib + ]; + }; + }; + } +#+end_src + +**** Summary of nixos-rebuild diff +:PROPERTIES: +:CUSTOM_ID: h:b751d77d-246c-4bd6-b689-3467d82bf9c3 +:END: + +This snipped is added to the activation script that is run after every rebuild and shows what packages have been added and removed. This is actually not the optimal place to add that snipped, but the correct spot is in some perl file that I have not had the leisure to take a look at yet. + +#+begin_src nix-ts :tangle modules/nixos/client/nvd-rebuild.nix + { lib, config, pkgs, ... }: + { + options.swarselmodules.nvd = lib.mkEnableOption "nvd config"; + config = lib.mkIf config.swarselmodules.nvd { + + environment.systemPackages = [ + pkgs.nvd + ]; + + # system.activationScripts.diff = { + # supportsDryActivation = true; + # text = '' + # ${pkgs.nvd}/bin/nvd --color=always --nix-bin-dir=${pkgs.nix}/bin diff \ + # /run/current-system "$systemConfig" + # ''; + # }; + }; + } +#+end_src + +**** gnome-keyring +:PROPERTIES: +:CUSTOM_ID: h:ce50eb90-8bf4-4203-b502-c3165d2fbf1f +:END: + +Used for storing sessions in e.g. Nextcloud. Using this on a system level keeps the login information when logging out of the session as well. + +#+begin_src nix-ts :tangle modules/nixos/client/gnome-keyring.nix + { lib, config, ... }: + { + options.swarselmodules.gnome-keyring = lib.mkEnableOption "gnome-keyring config"; + config = lib.mkIf config.swarselmodules.gnome-keyring { + services.gnome.gnome-keyring = { + enable = true; + }; + + programs.seahorse.enable = true; + }; + } +#+end_src + +**** Sway +:PROPERTIES: +:CUSTOM_ID: h:f78ffdd3-232b-4313-bd89-d6fb331fef22 +:END: + +This is used to better integrate Sway into the system on NixOS hosts. On the home-manager side, the =package= attribute will be =null= for such an host, using the systems derivation instead. + +#+begin_src nix-ts :tangle modules/nixos/client/sway.nix + { lib, config, pkgs, ... }: + let + inherit (config.swarselsystems) mainUser; + in + { + options.swarselmodules.sway = lib.mkEnableOption "sway config"; + config = lib.mkIf config.swarselmodules.sway { + programs.sway = { + enable = true; + package = pkgs.swayfx; + wrapperFeatures = { + base = true; + gtk = true; + }; + + inherit (config.home-manager.users.${mainUser}.wayland.windowManager.sway) extraSessionCommands; + }; + }; + } +#+end_src + +**** xdg-portal (Screensharing) +:PROPERTIES: +:CUSTOM_ID: h:872d5f46-2ffd-4076-9a2c-98783dd29434 +:END: + +This allows me to use screen sharing on Wayland. The implementation is a bit crude and only the whole screen can be shared. However, most of the time that is all I need to do anyways. + +#+begin_src nix-ts :tangle modules/nixos/client/xdg-portal.nix + { lib, config, pkgs, ... }: + { + options.swarselmodules.xdg-portal = lib.mkEnableOption "xdg portal config"; + config = lib.mkIf config.swarselmodules.xdg-portal { + xdg.portal = { + enable = true; + config = { + common = { + default = "wlr"; + }; + }; + wlr.enable = true; + wlr.settings.screencast = { + output_name = "eDP-1"; + chooser_type = "simple"; + chooser_cmd = "${pkgs.slurp}/bin/slurp -f %o -or"; + }; + }; + }; + } +#+end_src + +**** Podman (distrobox) +:PROPERTIES: +:CUSTOM_ID: h:1bef3914-a258-4585-b232-e0fbe9e7a9b5 +:END: + +I am using distrobox to quickly circumvent isses that I cannot immediately solve on NixOS. It is always the goal to quickly get things working on NixOS, but this prevents me from getting completely stuck. + +#+begin_src nix-ts :tangle modules/nixos/client/distrobox.nix + { lib, config, pkgs, ... }: + { + options.swarselmodules.distrobox = lib.mkEnableOption "distrobox config"; + config = lib.mkIf config.swarselmodules.distrobox { + environment.systemPackages = with pkgs; [ + distrobox + boxbuddy + ]; + + virtualisation.podman = { + enable = true; + dockerCompat = true; + package = pkgs.stable.podman; + }; + }; + } +#+end_src + +**** Appimage +:PROPERTIES: +:CUSTOM_ID: h:cfc22f8d-251e-4636-98d6-a43cdb112b68 +:END: +Adds the necessary tools to allow .appimage programs easily. + +#+begin_src nix-ts :tangle modules/nixos/client/appimage.nix + { lib, config, ... }: + { + options.swarselmodules.appimage = lib.mkEnableOption "appimage config"; + config = lib.mkIf config.swarselmodules.appimage { + programs.appimage = { + enable = true; + binfmt = true; + }; + }; + + } +#+end_src + +**** Handle lid switch correctly +:PROPERTIES: +:CUSTOM_ID: h:a5a0d84e-c7b3-4164-a4c7-2e2d8ada69cd +:END: + +This turns off the display when the lid is closed. + +#+begin_src nix-ts :tangle modules/nixos/client/lid.nix + { lib, config, ... }: + { + options.swarselmodules.lid = lib.mkEnableOption "lid config"; + config = lib.mkIf config.swarselmodules.lid { + services.logind.settings.Login = { + HandleLidSwitch = "suspend"; + HandleLidSwitchDocked = "ignore"; + }; + services.acpid = { + enable = true; + handlers.lidClosed = { + event = "button/lid \\w+ close"; + action = '' + cat /sys/class/backlight/amdgpu_bl1/device/enabled + if grep -Fxq disabled /sys/class/backlight/amdgpu_bl1/device/enabled + then + echo "Lid closed. Disabling fprintd." + systemctl stop fprintd + ln -s /dev/null /run/systemd/transient/fprintd.service + systemctl daemon-reload + fi + ''; + }; + handlers.lidOpen = { + event = "button/lid \\w+ open"; + action = '' + if ! $(systemctl is-active --quiet fprintd); then + echo "Lid open. Enabling fprintd." + rm -f /run/systemd/transient/fprintd.service + systemctl daemon-reload + systemctl start fprintd + fi + ''; + }; + }; + }; + } +#+end_src + +**** Low battery notification +:PROPERTIES: +:CUSTOM_ID: h:adf894d7-b3c6-4b8b-b13f-c28b3a5e1e17 +:END: + +Since I hide the waybar completely during normal operation, I run the risk of not noticing when my battery is about to run out. This module sends a notification when the battery level falls below 10%. Written by [[https://gist.github.com/cafkafk][cafkafk]]. + +#+begin_src nix-ts :tangle modules/nixos/client/lowbattery.nix + { pkgs, lib, config, ... }: + { + options.swarselmodules.lowBattery = lib.mkEnableOption "low battery notification config"; + config = lib.mkIf config.swarselmodules.lowBattery { + systemd.user.services."battery-low" = { + enable = true; + description = "Timer for battery check that alerts at 10% or less"; + partOf = [ "graphical-session.target" ]; + wantedBy = [ "graphical-session.target" ]; + serviceConfig = { + Type = "simple"; + ExecStart = pkgs.writeShellScript "battery-low-notification" + '' + if (( 10 >= $(${lib.getExe pkgs.acpi} -b | head -n 1 | ${lib.getExe pkgs.ripgrep} -o "\d+%" | ${lib.getExe pkgs.ripgrep} -o "\d+") && $(${lib.getExe pkgs.acpi} -b | head -n 1 | ${lib.getExe pkgs.ripgrep} -o "\d+%" | ${lib.getExe pkgs.ripgrep} -o "\d+") > 0 )); + then ${lib.getExe pkgs.libnotify} --urgency=critical "low battery" "$(${lib.getExe pkgs.acpi} -b | head -n 1 | ${lib.getExe pkgs.ripgrep} -o "\d+%")"; + fi; + ''; + }; + }; + systemd.user.timers."battery-low" = { + wantedBy = [ "timers.target" ]; + timerConfig = { + # Every Minute + OnCalendar = "*-*-* *:*:00"; + Unit = "battery-low.service"; + }; + }; + }; + } +#+end_src + +**** Auto-login +:PROPERTIES: +:CUSTOM_ID: h:fa8d9ec4-3e22-458a-9239-859cffe7f55c +:END: + +Auto login for the initial session. + +#+begin_src nix-ts :tangle modules/nixos/client/autologin.nix + { lib, config, ... }: + let + inherit (config.swarselsystems) mainUser; + in + { + options.swarselmodules.autologin = lib.mkEnableOption "optional autologin settings"; + config = lib.mkIf config.swarselmodules.autologin { + services = { + getty.autologinUser = mainUser; + greetd.settings.initial_session.user = mainUser; + }; + }; + } +#+end_src + +**** UWSM +:PROPERTIES: +:CUSTOM_ID: h:74f5961d-2881-4a42-b99f-94c8f70c8196 +:END: + +Auto login for the initial session. + +#+begin_src nix-ts :tangle modules/nixos/client/uwsm.nix + { lib, config, ... }: + let + moduleName = "uwsm"; + in + { + options.swarselmodules.${moduleName} = lib.mkEnableOption "${moduleName} settings"; + config = lib.mkIf config.swarselmodules.${moduleName} { + programs.uwsm = { + enable = true; + waylandCompositors = { + sway = { + prettyName = "Sway"; + comment = "Sway compositor managed by UWSM"; + binPath = "/run/current-system/sw/bin/sway"; + }; + niri = lib.mkIf (config.swarselmodules ? niri) { + prettyName = "Niri"; + comment = "Niri compositor managed by UWSM"; + binPath = "/run/current-system/sw/bin/niri-session"; + }; + }; + }; + }; + } +#+end_src + +*** Server +:PROPERTIES: +:CUSTOM_ID: h:e492c24a-83a0-4bcb-a084-706f49318651 +:END: + +In a similar way as the [[#h:1bb03c4c-7749-47c1-9af6-1b3d748cebf4][Client]] section, these modules are to be used mostly on servers. + +**** Imports +:PROPERTIES: +:CUSTOM_ID: h:4e64e564-b7cb-469f-bd79-cd3efb3caa62 +:END: + +First, we enable the use of =home-manager= as a NixoS module. + +Also, we disable the warnings that trigger when rebuilding with a dirty flake. At this point, I am also disabling channels and pinning the flake registry - the latter lets me use the local version of nixpkgs for commands like =nix shell= (without it, we will always download the newest version of nixpkgs for these commands). + +Also, the system state version is set here. No need to touch it. + +#+begin_src nix-ts :tangle modules/nixos/server/default.nix + { lib, ... }: + let + importNames = lib.swarselsystems.readNix "modules/nixos/server"; + in + { + imports = lib.swarselsystems.mkImports importNames "modules/nixos/server"; + } +#+end_src + +**** General NixOS Server settings +:PROPERTIES: +:CUSTOM_ID: h:dc365e83-f6c8-4d05-a390-b5f2d01649b4 +:END: + +Here we just define some aliases for rebuilding the system, and we allow some insecure packages that are needed by some server derivations. It would be more elegant to define these in the respective module, but nixpkgs needs to be defined before we can evaluate modules within it, so this must be a top-level configuration. + +#+begin_src nix-ts :tangle modules/nixos/server/settings.nix + { lib, config, ... }: + let + inherit (config.swarselsystems) flakePath; + in + { + + options.swarselmodules.server.general = lib.mkEnableOption "general setting on server"; + options.swarselsystems = { + shellAliases = lib.mkOption { + type = lib.types.attrsOf lib.types.str; + default = { }; + }; + }; + config = lib.mkIf config.swarselmodules.server.general { + + environment.shellAliases = lib.recursiveUpdate + { + nswitch = "cd ${flakePath}; swarsel-deploy $(hostname) switch; cd -;"; + ntest = "cd ${flakePath}; swarsel-deploy $(hostname) test; cd -;"; + nboot = "cd ${flakePath}; swarsel-deploy $(hostname) boot; cd -;"; + ndry = "cd ${flakePath}; swarsel-deploy $(hostname) dry-activate; cd -;"; + } + config.swarselsystems.shellAliases; + + nixpkgs.config.permittedInsecurePackages = [ + # matrix + "olm-3.2.16" + # sonarr + "aspnetcore-runtime-wrapped-6.0.36" + "aspnetcore-runtime-6.0.36" + "dotnet-sdk-wrapped-6.0.428" + "dotnet-sdk-6.0.428" + # + "SDL_ttf-2.0.11" + ]; + }; + } +#+end_src + +**** System Packages +:PROPERTIES: +:CUSTOM_ID: h:6f2967d9-7e32-4605-bb5c-5e27770bec0f +:END: + +#+begin_src nix-ts :tangle modules/nixos/server/packages.nix + { lib, config, pkgs, ... }: + { + options.swarselmodules.server.packages = lib.mkEnableOption "enable packages on server"; + config = lib.mkIf config.swarselmodules.server.packages { + environment.systemPackages = with pkgs; [ + gnupg + nvd + nix-output-monitor + ssh-to-age + git + emacs + vim + sops + swarsel-deploy + tmux + ]; + }; + } +#+end_src + +**** nfs/samba (smb) +:PROPERTIES: +:CUSTOM_ID: h:d6840d31-110c-465f-93fa-0306f755de28 +:END: + +#+begin_src nix-ts :tangle modules/nixos/server/nfs.nix + { lib, config, pkgs, globals, ... }: + let + nfsUser = globals.user.name; + in + { + options.swarselmodules.server.nfs = lib.mkEnableOption "enable nfs on server"; + config = lib.mkIf config.swarselmodules.server.nfs { + services = { + # add a user with sudo smbpasswd -a + samba = { + # package = pkgs.samba4Full; + package = pkgs.samba4; + # extraConfig = '' + # workgroup = WORKGROUP + # server role = standalone server + # dns proxy = no + + # pam password change = yes + # map to guest = bad user + # create mask = 0664 + # force create mode = 0664 + # directory mask = 0775 + # force directory mode = 0775 + # follow symlinks = yes + # ''; + + enable = true; + openFirewall = true; + settings.Eternor = { + browseable = "yes"; + "read only" = "no"; + "guest ok" = "no"; + path = "/Vault/Eternor"; + writable = "true"; + comment = "Eternor"; + "valid users" = nfsUser; + }; + }; + + avahi = { + publish.enable = true; + publish.userServices = true; # Needed to allow samba to automatically register mDNS records without the need for an `extraServiceFile` + nssmdns4 = true; + enable = true; + openFirewall = true; + }; + + # This enables autodiscovery on windows since SMB1 (and thus netbios) support was discontinued + samba-wsdd = { + enable = true; + openFirewall = true; + }; + }; + }; + } +#+end_src + +**** NGINX +:PROPERTIES: +:CUSTOM_ID: h:302468d2-106a-41c8-b2bc-9fdc40064a9c +:END: + +#+begin_src nix-ts :tangle modules/nixos/server/nginx.nix + { pkgs, lib, config, ... }: + let + inherit (config.repo.secrets.common) dnsProvider dnsBase; + inherit (config.repo.secrets.common.mail) address3; + + serviceUser = "nginx"; + serviceGroup = serviceUser; + + sslBasePath = "/etc/ssl"; + dhParamsPathBase = "${sslBasePath}/dhparams.pem"; + dhParamsPath = + if config.swarselsystems.isImpermanence then + "/persist/${dhParamsPathBase}" + else + "${dhParamsPathBase}"; + in + { + options.swarselmodules.server.nginx = lib.mkEnableOption "enable nginx on server"; + options.services.nginx = { + recommendedSecurityHeaders = lib.mkEnableOption "additional security headers by default in each location block."; + virtualHosts = lib.mkOption { + type = lib.types.attrsOf ( + lib.types.submodule { + options.locations = lib.mkOption { + type = lib.types.attrsOf ( + lib.types.submodule (submod: { + options = { + recommendedSecurityHeaders = lib.mkOption { + type = lib.types.bool; + default = config.services.nginx.recommendedSecurityHeaders; + description = "Whether to add additional security headers to this location."; + }; + + X-Frame-Options = lib.mkOption { + type = lib.types.str; + default = "DENY"; + description = "The value to use for X-Frame-Options"; + }; + }; + config = lib.mkIf submod.config.recommendedSecurityHeaders { + extraConfig = lib.mkBefore '' + # Enable HTTP Strict Transport Security (HSTS) + add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload"; + + # Minimize information leaked to other domains + add_header Referrer-Policy "origin-when-cross-origin"; + + add_header X-XSS-Protection "1; mode=block"; + add_header X-Frame-Options "${submod.config.X-Frame-Options}"; + add_header X-Content-Type-Options "nosniff"; + ''; + }; + }) + ); + }; + } + ); + }; + }; + config = lib.mkIf config.swarselmodules.server.nginx { + environment.systemPackages = with pkgs; [ + lego + ]; + + sops = { + secrets = { + acme-dns-token = { inherit (config.swarselsystems) sopsFile; }; + }; + templates."certs.secret".content = '' + ACME_DNS_API_BASE=${dnsBase} + ACME_DNS_STORAGE_PATH=${config.sops.placeholder.acme-dns-token} + ''; + }; + + users.groups.acme.members = [ "nginx" ]; + + security.acme = { + acceptTerms = true; + defaults = { + inherit dnsProvider; + email = address3; + environmentFile = "${config.sops.templates."certs.secret".path}"; + reloadServices = [ "nginx" ]; + dnsPropagationCheck = true; + }; + }; + + networking.firewall.allowedTCPPorts = [ 80 443 ]; + + environment.persistence."/persist" = lib.mkIf config.swarselsystems.isImpermanence { + directories = [ { directory = "/var/lib/acme"; } ]; + files = [ dhParamsPathBase ]; + }; + + services.nginx = { + enable = true; + user = serviceUser; + group = serviceGroup; + statusPage = true; + recommendedProxySettings = true; + recommendedTlsSettings = true; + recommendedOptimisation = true; + recommendedGzipSettings = true; + recommendedBrotliSettings = true; + recommendedSecurityHeaders = true; + sslCiphers = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:!aNULL"; + sslDhparam = dhParamsPathBase; + virtualHosts.fallback = { + default = true; + rejectSSL = true; + locations."/".extraConfig = '' + deny all; + ''; + }; + }; + systemd.services.generateDHParams = { + before = [ "nginx.service" ]; + requiredBy = [ "nginx.service" ]; + after = [ "local-fs.target" ]; + requires = [ "local-fs.target" ]; + serviceConfig = { + Type = "oneshot"; + }; + + script = '' + set -eu + + install -d -m 0755 ${sslBasePath} + ${if config.swarselsystems.isImpermanence then "${pkgs.coreutils}/bin/install -d -m 0755 /persist${sslBasePath}" else ""} + + if [ ! -f "${dhParamsPath}" ]; then + ${pkgs.openssl}/bin/openssl dhparam -out "${dhParamsPath}" 4096 + chmod 0644 "${dhParamsPath}" + chown ${serviceUser}:${serviceGroup} "${dhParamsPath}" + else + echo 'Already generated DHParams' + fi + ''; + }; + + # system.activationScripts."createPersistentStorageDirs" = lib.mkIf config.swarselsystems.isImpermanence { + # deps = [ "generateDHParams" "users" "groups" ]; + # }; + # system.activationScripts."generateDHParams" = + # { + # text = '' + # set -eu + + # ${if config.swarselsystems.isImpermanence then "${pkgs.coreutils}/bin/install -d -m 0755 /persist${sslBasePath}" else "${pkgs.coreutils}/bin/install -d -m 0755 ${sslBasePath}"} + + # if [ ! -f "${dhParamsPath}" ]; then + # ${pkgs.openssl}/bin/openssl dhparam -out ${dhParamsPath} 4096 + # chmod 0644 ${dhParamsPath} + # chown ${serviceUser}:${serviceGroup} ${dhParamsPath} + # fi + # ''; + # deps = [ + # (lib.mkIf config.swarselsystems.isImpermanence "specialfs") + # (lib.mkIf (!config.swarselsystems.isImpermanence) "etc") + # ]; + # }; + }; + } +#+end_src + +**** ssh +:PROPERTIES: +:CUSTOM_ID: h:f3db197d-1d03-4bf8-b59f-f9891b358f0b +:END: + +Here I am forcing =startWhenNeeded= to false so that the value will not be set to true in containers = this would be a problem because it would delay ssh host key generation. + +#+begin_src nix-ts :tangle modules/nixos/server/ssh.nix + { self, lib, config, ... }: + { + options.swarselmodules.server.ssh = lib.mkEnableOption "enable ssh on server"; + config = lib.mkIf config.swarselmodules.server.ssh { + services.openssh = { + enable = true; + startWhenNeeded = lib.mkForce false; + settings = { + PasswordAuthentication = false; + KbdInteractiveAuthentication = false; + PermitRootLogin = "yes"; + AllowUsers = [ + "root" + config.swarselsystems.mainUser + ]; + }; + hostKeys = [ + { + path = "/etc/ssh/ssh_host_ed25519_key"; + type = "ed25519"; + } + ]; + }; + users.users."${config.swarselsystems.mainUser}".openssh.authorizedKeys.keyFiles = [ + (self + /secrets/keys/ssh/yubikey.pub) + (self + /secrets/keys/ssh/magicant.pub) + # (lib.mkIf config.swarselsystems.isBastionTarget (self + /secrets/keys/ssh/jump.pub)) + ]; + users.users.root.openssh.authorizedKeys.keyFiles = [ + (self + /secrets/keys/ssh/yubikey.pub) + (self + /secrets/keys/ssh/magicant.pub) + # (lib.mkIf config.swarselsystems.isBastionTarget (self + /secrets/keys/ssh/jump.pub)) + ]; + security.sudo.extraConfig = '' + Defaults env_keep+=SSH_AUTH_SOCK + ''; + }; + } +#+end_src + +**** Bastion + +#+begin_src nix-ts :tangle modules/nixos/server/bastion.nix + { self, lib, config, ... }: + { + options.swarselmodules.server.bastion = lib.mkEnableOption "enable bastion on server"; + config = lib.mkIf config.swarselmodules.server.bastion { + + users = { + groups = { + jump = { }; + }; + users = { + "jump" = { + isNormalUser = true; + useDefaultShell = true; + group = lib.mkForce "jump"; + createHome = lib.mkForce true; + openssh.authorizedKeys.keyFiles = [ + (self + /secrets/keys/ssh/yubikey.pub) + (self + /secrets/keys/ssh/magicant.pub) + (self + /secrets/keys/ssh/builder.pub) + ]; + }; + }; + }; + + + services.openssh = { + enable = true; + startWhenNeeded = lib.mkForce false; + authorizedKeysInHomedir = false; + extraConfig = '' + Match User jump + PermitTTY no + X11Forwarding no + PermitTunnel no + GatewayPorts no + AllowAgentForwarding no + ''; + settings = { + PasswordAuthentication = false; + KbdInteractiveAuthentication = false; + PermitRootLogin = lib.mkDefault "no"; + AllowUsers = [ + "jump" + ]; + }; + hostKeys = lib.mkIf (!config.swarselmodules.server.ssh) [ + { + path = "/etc/ssh/ssh_host_ed25519_key"; + type = "ed25519"; + } + ]; + }; + + home-manager.users.jump.config = { + home.stateVersion = lib.mkDefault "23.05"; + programs.ssh = { + enable = true; + enableDefaultConfig = false; + matchBlocks = { + "*" = { + forwardAgent = false; + }; + } // config.repo.secrets.local.ssh.hosts; + }; + }; + }; + } +#+end_src + +**** ssh builder config + +Restricts access to the system by the nix build user as per https://discourse.nixos.org/t/wrapper-to-restrict-builder-access-through-ssh-worth-upstreaming/25834. + +#+begin_src nix-ts :tangle modules/nixos/server/ssh-builder.nix + { self, pkgs, lib, config, ... }: + let + ssh-restrict = "restrict,pty,command=\"${wrapper-dispatch-ssh-nix}/bin/wrapper-dispatch-ssh-nix\" "; + + wrapper-dispatch-ssh-nix = pkgs.writeShellScriptBin "wrapper-dispatch-ssh-nix" '' + case $SSH_ORIGINAL_COMMAND in + "nix-daemon --stdio") + exec env NIX_SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt ${config.nix.package}/bin/nix-daemon --stdio + ;; + "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 + ''; + in + { + options.swarselmodules.server.ssh-builder = lib.mkEnableOption "enable ssh-builder config on server"; + config = lib.mkIf config.swarselmodules.server.ssh-builder { + users = { + groups.builder = { }; + users.builder = { + useDefaultShell = true; + isSystemUser = true; + group = "builder"; + openssh.authorizedKeys.keys = [ + ''${ssh-restrict} ${builtins.readFile "${self}/secrets/keys/ssh/builder.pub"}'' + ]; + }; + }; + + }; + } +#+end_src + +**** Network settings +:PROPERTIES: +:CUSTOM_ID: h:0ff3acc5-9ce8-4b22-a2e2-f6f1e69d47a5 +:END: + +Generate hostId using =head -c4 /dev/urandom | od -A none -t x4= + +#+begin_src nix-ts :tangle modules/nixos/server/network.nix + { lib, config, ... }: + let + netConfig = config.repo.secrets.local.networking; + netName = "${if config.swarselsystems.isCloud then config.node.name else "home"}-${config.swarselsystems.server.localNetwork}"; + in + { + options = { + swarselmodules.server.network = lib.mkEnableOption "enable server network config"; + swarselsystems.server = { + localNetwork = lib.mkOption { + type = lib.types.str; + default = ""; + }; + netConfigName = lib.mkOption { + type = lib.types.str; + default = netName; + readOnly = true; + }; + }; + }; + config = lib.mkIf config.swarselmodules.server.network { + + swarselsystems.server.localNetwork = netConfig.localNetwork or ""; + + globals.networks.${netName}.hosts.${config.node.name} = { + inherit (netConfig.networks.${netConfig.localNetwork}) id; + mac = netConfig.networks.${netConfig.localNetwork}.mac or null; + }; + + globals.hosts.${config.node.name} = { + inherit (config.repo.secrets.local.networking) defaultGateway4; + wanAddress4 = netConfig.wanAddress4 or null; + wanAddress6 = netConfig.wanAddress6 or null; + }; + + networking = { + inherit (netConfig) hostId; + hostName = config.node.name; + nftables.enable = lib.mkDefault false; + enableIPv6 = lib.mkDefault true; + firewall = { + enable = lib.mkDefault true; + }; + }; + + }; + } +#+end_src + +**** Disk encryption +:PROPERTIES: +:CUSTOM_ID: h:19d829f6-580f-4e04-8776-2bfd83c3c3dd +:END: + +The hostkey can be generated with =ssh-keygen -t ed25519 -N "" -f /etc/secrets/initrd/ssh_host_ed25519_key=. +Use =lspci -v | grep -iA8 'network\|ethernet'= to supposedly find out which kernel module is needed for networking in initrd. However I prefer a different approach: + +Use =lspci -nn | grep -i network= to find out manufacturer info: + +#+begin_src shell :exports both +lspci -nn | grep -i 'network\|ethernet' +#+end_src + +#+RESULTS: +: 04:00.0 Network controller [0280]: MEDIATEK Corp. MT7922 802.11ax PCI Express Wireless Network Adapter [14c3:0616] + +From the last bracket you then find out the correct kernel module: + +#+begin_src shell :exports both +lspci -k -d 14c3:0616 +#+end_src + +#+RESULTS: +| 04:00.0 | Network | controller: | MEDIATEK | Corp. | MT7922 | 802.11ax | PCI | Express | Wireless | Network | Adapter | +| | Subsystem: | MEDIATEK | Corp. | Device | e616 | | | | | | | +| | Kernel | driver | in | use: | mt7921e | | | | | | | +| | Kernel | modules: | mt7921e | | | | | | | | | + +#+begin_src nix-ts :tangle modules/nixos/server/disk-encrypt.nix + { self, pkgs, lib, config, globals, 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; + + hostKeyPathBase = "/etc/secrets/initrd/ssh_host_ed25519_key"; + hostKeyPath = + if config.swarselsystems.isImpermanence then + "/persist/${hostKeyPathBase}" + else + "${hostKeyPathBase}"; + in + { + options.swarselmodules.server.diskEncryption = lib.mkEnableOption "enable disk encryption config"; + options.swarselsystems.networkKernelModules = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ ]; + }; + config = lib.mkIf (config.swarselmodules.server.diskEncryption && config.swarselsystems.isCrypted) { + + + system.activationScripts."createPersistentStorageDirs" = lib.mkIf config.swarselsystems.isImpermanence { + deps = [ "ensureInitrdHostkey" ]; + }; + system.activationScripts.ensureInitrdHostkey = lib.mkIf (config.swarselprofiles.server || minimal) { + text = '' + [[ -e ${hostKeyPath} ]] || ${pkgs.openssh}/bin/ssh-keygen -t ed25519 -N "" -f ${hostKeyPath} + ''; + deps = [ + "etc" + ]; + }; + + environment.persistence."/persist" = lib.mkIf (config.swarselsystems.isImpermanence && (config.swarselprofiles.server || minimal)) { + files = [ hostKeyPathBase ]; + }; + + boot = lib.mkIf (!config.swarselsystems.isClient) { + kernelParams = lib.mkIf (!config.swarselsystems.isCloud) [ + "ip=${localIp}::${gatewayIp}:${subnetMask}:${config.networking.hostName}::none" + ]; + initrd = { + availableKernelModules = config.swarselsystems.networkKernelModules; + network = { + enable = true; + flushBeforeStage2 = true; + ssh = { + enable = true; + port = 2222; # avoid hostkey changed nag + authorizedKeys = [ + ''command="/bin/systemctl default" ${builtins.readFile "${self}/secrets/keys/ssh/yubikey.pub"}'' + ''command="/bin/systemctl default" ${builtins.readFile "${self}/secrets/keys/ssh/magicant.pub"}'' + ]; + hostKeys = [ hostKeyPathBase ]; + }; + # postCommands = '' + # echo 'cryptsetup-askpass || echo "Unlock was successful; exiting SSH session" && exit 1' >> /root/.profile + # ''; + }; + systemd = { + initrdBin = with pkgs; [ + cryptsetup + ]; + # NOTE: the below does put the text into /root/.profile, but the command will not be run + # services = { + # unlock-luks = { + # wantedBy = [ "initrd.target" ]; + # after = [ "network.target" ]; + # before = [ "systemd-cryptsetup@cryptroot.service" ]; + # path = [ "/bin" ]; + + # serviceConfig = { + # Type = "oneshot"; + # RemainAfterExit = true; + # }; + + # script = '' + # echo "systemctl default" >> /root/.profile + # ''; + # }; + # }; + }; + }; + }; + }; + + } +#+end_src + +**** BTRFS + +#+begin_src nix-ts :tangle modules/nixos/server/btrfs.nix + { lib, config, ... }: + { + options.swarselmodules.btrfs = lib.mkEnableOption "optional btrfs settings"; + config = lib.mkIf config.swarselmodules.btrfs { + boot = { + supportedFilesystems = lib.mkIf config.swarselsystems.isBtrfs [ "btrfs" ]; + }; + }; + } +#+end_src + +**** Router +:PROPERTIES: +:CUSTOM_ID: h:b54f2bbb-0088-46b2-957d-fd8234b772c3 +:END: + +#+begin_src nix-ts :tangle modules/nixos/server/router.nix + { lib, config, ... }: + let + serviceName = "router"; + in + { + options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselmodules.server.${serviceName} { + + systemd.network = { + wait-online.anyInterface = true; + networks = { + "30-lan0" = { + matchConfig.Name = "lan0"; + linkConfig.RequiredForOnline = "enslaved"; + networkConfig = { + ConfigureWithoutCarrier = true; + }; + }; + "30-lan1" = { + matchConfig.Name = "lan1"; + linkConfig.RequiredForOnline = "enslaved"; + networkConfig = { + ConfigureWithoutCarrier = true; + }; + }; + "30-lan2" = { + matchConfig.Name = "lan2"; + linkConfig.RequiredForOnline = "enslaved"; + networkConfig = { + ConfigureWithoutCarrier = true; + }; + }; + "30-lan3" = { + matchConfig.Name = "lan3"; + linkConfig.RequiredForOnline = "enslaved"; + networkConfig = { + ConfigureWithoutCarrier = true; + }; + }; + "10-wan" = { + matchConfig.Name = "wan"; + networkConfig = { + # start a DHCP Client for IPv4 Addressing/Routing + DHCP = "ipv4"; + DNSOverTLS = true; + DNSSEC = true; + IPv6PrivacyExtensions = false; + IPForward = true; + }; + # make routing on this interface a dependency for network-online.target + linkConfig.RequiredForOnline = "routable"; + }; + }; + }; + }; + } +#+end_src + +**** kavita +:PROPERTIES: +:CUSTOM_ID: h:d33f5982-dfe6-42d0-9cf2-2cd8c7b04295 +:END: + +#+begin_src nix-ts :tangle modules/nixos/server/kavita.nix + { self, lib, config, pkgs, globals, dns, confLib, ... }: + let + inherit (config.swarselsystems) sopsFile; + + inherit (confLib.gen { name = "kavita"; port = 8080; }) servicePort serviceName serviceUser serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6; + in + { + options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselmodules.server.${serviceName} { + environment.systemPackages = with pkgs; [ + calibre + ]; + + nodes.stoicclub.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + + users.users.${serviceUser} = { + extraGroups = [ "users" ]; + }; + + sops.secrets.kavita-token = { inherit sopsFile; owner = serviceUser; }; + + networking.firewall.allowedTCPPorts = [ servicePort ]; + + topology.self.services.${serviceName} = { + name = "Kavita"; + info = "https://${serviceDomain}"; + icon = "${self}/files/topology-images/${serviceName}.png"; + }; + + globals.services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6; + }; + + services.${serviceName} = { + enable = true; + user = serviceUser; + settings.Port = servicePort; + tokenKeyFile = config.sops.secrets.kavita-token.path; + dataDir = "/Vault/data/${serviceName}"; + }; + + nodes.${serviceProxy}.services.nginx = { + upstreams = { + ${serviceName} = { + servers = { + "${serviceAddress}:${builtins.toString servicePort}" = { }; + }; + }; + }; + virtualHosts = { + "${serviceDomain}" = { + enableACME = true; + forceSSL = true; + acmeRoot = null; + locations = { + "/" = { + proxyPass = "http://${serviceName}"; + extraConfig = '' + client_max_body_size 0; + ''; + }; + }; + }; + }; + }; + }; + } +#+end_src + +**** jellyfin +:PROPERTIES: +:CUSTOM_ID: h:e0d4c16e-ab64-48ac-9734-1ab62953ad4b +:END: + +#+begin_src nix-ts :tangle modules/nixos/server/jellyfin.nix + { pkgs, lib, config, globals, dns, confLib, ... }: + let + inherit (confLib.gen { name = "jellyfin"; port = 8096; }) servicePort serviceName serviceUser serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6; + in + { + options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselmodules.server.${serviceName} { + + nodes.stoicclub.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + + users.users.${serviceUser} = { + extraGroups = [ "video" "render" "users" ]; + }; + + nixpkgs.config.packageOverrides = pkgs: { + intel-vaapi-driver = pkgs.intel-vaapi-driver.override { enableHybridCodec = true; }; + }; + + hardware.graphics = { + enable = true; + extraPackages = with pkgs; [ + intel-media-driver # LIBVA_DRIVER_NAME=iHD + intel-vaapi-driver # LIBVA_DRIVER_NAME=i965 (older but works better for Firefox/Chromium) + libva-vdpau-driver + libvdpau-va-gl + ]; + }; + + topology.self.services.${serviceName}.info = "https://${serviceDomain}"; + + globals.services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6; + }; + + services.${serviceName} = { + enable = true; + user = serviceUser; + openFirewall = true; # this works only for the default ports + }; + + nodes.${serviceProxy}.services.nginx = { + upstreams = { + ${serviceName} = { + servers = { + "${serviceAddress}:${builtins.toString servicePort}" = { }; + }; + }; + }; + virtualHosts = { + "${serviceDomain}" = { + enableACME = true; + forceSSL = true; + acmeRoot = null; + locations = { + "/" = { + proxyPass = "http://${serviceName}"; + extraConfig = '' + client_max_body_size 0; + ''; + }; + }; + }; + }; + }; + }; + + } +#+end_src + +**** navidrome +:PROPERTIES: +:CUSTOM_ID: h:f347f3ad-5100-4c4f-8616-cfd7f8e14a72 +:END: + +#+begin_src nix-ts :tangle modules/nixos/server/navidrome.nix + { pkgs, config, lib, globals, dns, confLib, ... }: + let + inherit (confLib.gen { name = "navidrome"; port = 4040; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6; + in + { + options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselmodules.server.${serviceName} { + + nodes.stoicclub.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + + environment.systemPackages = with pkgs; [ + pciutils + alsa-utils + mpv + ]; + + users = { + groups = { + ${serviceGroup} = { + gid = 61593; + }; + }; + + users = { + ${serviceUser} = { + isSystemUser = true; + uid = 61593; + group = serviceGroup; + extraGroups = [ "audio" "utmp" "users" "pipewire" ]; + }; + }; + }; + + hardware = { + enableAllFirmware = lib.mkForce true; + }; + + networking.firewall.allowedTCPPorts = [ servicePort ]; + + globals.services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6; + }; + + services.snapserver = { + enable = true; + settings = { + stream = { + port = 1704; + source = "pipe:///tmp/snapfifo?name=default"; + bind_to_address = "0.0.0.0"; + }; + }; + }; + + systemd.services = { + ${serviceName}.serviceConfig = { + PrivateDevices = lib.mkForce false; + PrivateUsers = lib.mkForce false; + RestrictRealtime = lib.mkForce false; + SystemCallFilter = lib.mkForce null; + RootDirectory = lib.mkForce null; + }; + }; + + services.${serviceName} = { + enable = true; + openFirewall = true; + settings = { + LogLevel = "debug"; + Address = "0.0.0.0"; + Port = servicePort; + MusicFolder = "/Vault/Eternor/Music"; + PlaylistsPath = "./Playlists"; + AutoImportPlaylists = false; + EnableSharing = true; + EnableTranscodingConfig = true; + Scanner.GroupAlbumReleases = true; + ScanSchedule = "@every 24h"; + # MPVPath = ""; + # MPVCommandTemplate = "${pkgs.mpv}/bin/mpv --audio-device=%d --input-ipc-server=%s --no-audio-display --log-file=/tmp/mpv.log --pause %f"; + # MPVCmdTemplate = "${pkgs.mpv}/bin/mpv --no-audio-display --pause %f --input-ipc-server=%s --audio-channels=stereo --audio-samplerate=48000 --audio-format=s16 --ao=pcm --ao-pcm-file=/tmp/snapfifo --log-file=/tmp/mpv.log"; + ReverseProxyWhitelist = "0.0.0.0/0"; + ReverseProxyUserHeader = "X-User"; + Jukebox = { + Enabled = true; + Default = "default"; + Devices = [ + # use mpv --audio-device=help to get these + [ "default" "alsa/sysdefault:CARD=PCH" ] + ]; + }; + # Switch using --impure as these credential files are not stored within the flake + # sops-nix is not supported for these which is why we need to resort to these + LastFM = { + inherit (config.repo.secrets.local.LastFM) ApiKey Secret; + }; + Spotify = { + inherit (config.repo.secrets.local.Spotify) ID Secret; + }; + UILoginBackgroundUrl = "https://i.imgur.com/OMLxi7l.png"; + UIWelcomeMessage = "~SwarselSound~"; + EnableInsightsCollector = false; + }; + }; + + nodes.${serviceProxy}.services.nginx = { + upstreams = { + ${serviceName} = { + servers = { + "${serviceAddress}:${builtins.toString servicePort}" = { }; + }; + }; + }; + virtualHosts = { + "${serviceDomain}" = { + enableACME = true; + forceSSL = true; + acmeRoot = null; + oauth2.enable = true; + oauth2.allowedGroups = [ "navidrome_access" ]; + locations = + let + extraConfig = '' + proxy_redirect http:// https://; + proxy_read_timeout 600s; + proxy_send_timeout 600s; + proxy_buffering off; + proxy_request_buffering off; + client_max_body_size 0; + ''; + in + { + "/" = { + proxyPass = "http://${serviceName}"; + proxyWebsockets = true; + inherit extraConfig; + }; + "/share" = { + proxyPass = "http://${serviceName}"; + proxyWebsockets = true; + setOauth2Headers = false; + bypassAuth = true; + inherit extraConfig; + }; + "/rest" = { + proxyPass = "http://${serviceName}"; + proxyWebsockets = true; + setOauth2Headers = false; + bypassAuth = true; + inherit extraConfig; + }; + }; + }; + }; + }; + }; + + + } +#+end_src + +**** spotifyd +:PROPERTIES: +:CUSTOM_ID: h:ec9c5a7d-ea8b-46d5-809c-163c917f5c41 +:END: + +#+begin_src nix-ts :tangle modules/nixos/server/spotifyd.nix + { lib, config, confLib, ... }: + let + inherit (confLib.gen { name = "spotifyd"; port = 1025; }) servicePort serviceName serviceUser serviceGroup; + in + { + options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselmodules.server.${serviceName} { + users.groups.${serviceGroup} = { + gid = 65136; + }; + + users.users.${serviceUser} = { + isSystemUser = true; + uid = 65136; + group = serviceGroup; + extraGroups = [ "audio" "utmp" "pipewire" ]; + }; + + networking.firewall.allowedTCPPorts = [ servicePort ]; + + services.pipewire.systemWide = true; + + # https://github.com/Spotifyd/spotifyd/issues/1366 + networking.hosts."0.0.0.0" = [ "apresolve.spotify.com" ]; + + # hacky way to enable multi-session + # when another user connects, the service will crash and the new user will login + systemd.services.spotifyd.serviceConfig.RestartSec = lib.mkForce 1; + + services.spotifyd = { + enable = true; + settings = { + global = { + dbus_type = "session"; + use_mpris = false; + device = "sysdefault:CARD=PCH"; + # device = "default"; + device_name = "SwarselSpot"; + # backend = "pulseaudio"; + backend = "alsa"; + # mixer = "alsa"; + zeroconf_port = servicePort; + }; + }; + }; + }; + + } +#+end_src + +**** mpd +:PROPERTIES: +:CUSTOM_ID: h:baa4149b-3788-4b05-87ec-0ee9d0726117 +:END: + +#+begin_src nix-ts :tangle modules/nixos/server/mpd.nix + { self, lib, config, pkgs, confLib, ... }: + let + inherit (config.swarselsystems) sopsFile; + inherit (confLib.gen { name = "mpd"; port = 3254; }) servicePort serviceName serviceUser serviceGroup; + in + { + options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselmodules.server.${serviceName} { + users = { + groups = { + mpd = { }; + }; + + users = { + ${serviceUser} = { + isSystemUser = true; + group = serviceGroup; + extraGroups = [ "audio" "utmp" ]; + }; + }; + }; + + sops = { + secrets.mpd-pw = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + }; + + environment.systemPackages = with pkgs; [ + pciutils + alsa-utils + mpv + ]; + + topology.self.services.${serviceName} = { + name = lib.toUpper serviceName; + info = "http://localhost:${builtins.toString servicePort}"; + icon = "${self}/files/topology-images/${serviceName}.png"; + }; + + services.${serviceName} = { + enable = true; + musicDirectory = "/media"; + user = serviceUser; + group = serviceGroup; + network = { + port = servicePort; + listenAddress = "any"; + }; + credentials = [ + { + passwordFile = config.sops.secrets.mpd-pw.path; + permissions = [ + "read" + "add" + "control" + "admin" + ]; + } + ]; + }; + }; + + } +#+end_src + +**** pipewire +:PROPERTIES: +:CUSTOM_ID: h:ce6a4371-e44f-419a-be9e-e17c7abdaf3a +:END: + +#+begin_src nix-ts :tangle modules/nixos/server/pipewire.nix + { lib, config, ... }: + { + config = lib.mkIf (config?swarselmodules.server.mpd || config?swarselmodules.server.navidrome) { + + security.rtkit.enable = true; # this is required for pipewire real-time access + + services.pipewire = { + enable = true; + pulse.enable = true; + jack.enable = true; + audio.enable = true; + wireplumber.enable = true; + alsa = { + enable = true; + support32Bit = true; + }; + }; + }; + + } +#+end_src + +**** postgresql +:PROPERTIES: +:CUSTOM_ID: h:6ca43d5a-8ba6-4cd1-96b9-f088f11662c0 +:END: + +#+begin_src nix-ts :tangle modules/nixos/server/postgresql.nix + { config, lib, pkgs, confLib, ... }: + let + inherit (confLib.gen { name = "postgresql"; port = 3254; }) serviceName; + postgresVersion = 14; + postgresDirPrefix = if config.swarselsystems.isCloud then "/var/lib" else "/Vault/data" ; + in + { + options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselmodules.server.${serviceName} { + services = { + ${serviceName} = { + enable = true; + package = pkgs."postgresql_${builtins.toString postgresVersion}"; + dataDir = "${postgresDirPrefix}/${serviceName}/${builtins.toString postgresVersion}"; + }; + }; + environment.persistence."/persist".directories = lib.mkIf (config.swarselsystems.isImpermanence && config.swarselsystems.isCloud) [ + { directory = "/var/lib/postgresql"; user = "postgres"; group = "postgres"; mode = "0750"; } + ]; + + }; + } +#+end_src + +**** matrix +:PROPERTIES: +:CUSTOM_ID: h:1e68d84a-8f99-422f-89ac-78f664ac0013 +:END: + +#+begin_src nix-ts :tangle modules/nixos/server/matrix.nix + { lib, config, pkgs, globals, dns, confLib, ... }: + let + inherit (config.swarselsystems) sopsFile; + inherit (confLib.gen { name = "matrix"; user = "matrix-synapse"; port = 8008; }) servicePort serviceName serviceUser serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6; + + federationPort = 8448; + whatsappPort = 29318; + telegramPort = 29317; + signalPort = 29328; + baseUrl = "https://${serviceDomain}"; + clientConfig."m.homeserver".base_url = baseUrl; + serverConfig."m.server" = "${serviceDomain}:443"; + mkWellKnown = data: '' + default_type application/json; + add_header Access-Control-Allow-Origin *; + return 200 '${builtins.toJSON data}'; + ''; + in + { + options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselmodules.server.${serviceName} { + + nodes.stoicclub.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + + environment.systemPackages = with pkgs; [ + matrix-synapse + lottieconverter + ffmpeg + ]; + + sops = { + secrets = { + matrix-shared-secret = { inherit sopsFile; owner = serviceUser; }; + mautrix-telegram-as-token = { inherit sopsFile; owner = serviceUser; }; + mautrix-telegram-hs-token = { inherit sopsFile; owner = serviceUser; }; + mautrix-telegram-api-id = { inherit sopsFile; owner = serviceUser; }; + mautrix-telegram-api-hash = { inherit sopsFile; owner = serviceUser; }; + }; + templates = { + "matrix_user_register.sh".content = '' + register_new_matrix_user -k ${config.sops.placeholder.matrix-shared-secret} http://localhost:${builtins.toString servicePort} + ''; + matrixshared = { + owner = serviceUser; + content = '' + registration_shared_secret: ${config.sops.placeholder.matrix-shared-secret} + ''; + }; + mautrixtelegram = { + owner = serviceUser; + content = '' + MAUTRIX_TELEGRAM_APPSERVICE_AS_TOKEN=${config.sops.placeholder.mautrix-telegram-as-token} + MAUTRIX_TELEGRAM_APPSERVICE_HS_TOKEN=${config.sops.placeholder.mautrix-telegram-hs-token} + MAUTRIX_TELEGRAM_TELEGRAM_API_ID=${config.sops.placeholder.mautrix-telegram-api-id} + MAUTRIX_TELEGRAM_TELEGRAM_API_HASH=${config.sops.placeholder.mautrix-telegram-api-hash} + ''; + }; + }; + }; + + networking.firewall.allowedTCPPorts = [ servicePort federationPort ]; + + systemd = { + timers."restart-bridges" = { + wantedBy = [ "timers.target" ]; + timerConfig = { + OnBootSec = "1d"; + OnUnitActiveSec = "1d"; + Unit = "restart-bridges.service"; + }; + }; + + services = { + "restart-bridges" = { + script = '' + systemctl restart mautrix-whatsapp.service + systemctl restart mautrix-signal.service + systemctl restart mautrix-telegram.service + ''; + serviceConfig = { + Type = "oneshot"; + User = "root"; + }; + }; + mautrix-telegram.path = with pkgs; [ + lottieconverter # for animated stickers conversion, unfree package + ffmpeg # if converting animated stickers to webm (very slow!) + ]; + }; + }; + + globals.services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6; + }; + + services = { + postgresql = { + enable = true; + initialScript = pkgs.writeText "synapse-init.sql" '' + CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD 'synapse'; + CREATE DATABASE "matrix-synapse" WITH OWNER "matrix-synapse" + TEMPLATE template0 + LC_COLLATE = "C" + LC_CTYPE = "C"; + CREATE ROLE "mautrix-telegram" WITH LOGIN PASSWORD 'telegram'; + CREATE DATABASE "mautrix-telegram" WITH OWNER "mautrix-telegram" + TEMPLATE template0 + LC_COLLATE = "C" + LC_CTYPE = "C"; + CREATE ROLE "mautrix-whatsapp" WITH LOGIN PASSWORD 'whatsapp'; + CREATE DATABASE "mautrix-whatsapp" WITH OWNER "mautrix-whatsapp" + TEMPLATE template0 + LC_COLLATE = "C" + LC_CTYPE = "C"; + CREATE ROLE "mautrix-signal" WITH LOGIN PASSWORD 'signal'; + CREATE DATABASE "mautrix-signal" WITH OWNER "mautrix-signal" + TEMPLATE template0 + LC_COLLATE = "C" + LC_CTYPE = "C"; + ''; + }; + + matrix-synapse = { + enable = true; + dataDir = "/Vault/data/matrix-synapse"; + settings = { + app_service_config_files = + let + inherit (config.services.matrix-synapse) dataDir; + in + [ + "${dataDir}/telegram-registration.yaml" + "${dataDir}/whatsapp-registration.yaml" + "${dataDir}/signal-registration.yaml" + "${dataDir}/doublepuppet.yaml" + ]; + server_name = serviceDomain; + public_baseurl = "https://${serviceDomain}"; + listeners = [ + { + port = servicePort; + bind_addresses = [ + "0.0.0.0" + # "::1" + ]; + type = "http"; + tls = false; + x_forwarded = true; + resources = [ + { + names = [ "client" "federation" ]; + compress = true; + } + ]; + } + ]; + }; + extraConfigFiles = [ + config.sops.templates.matrixshared.path + ]; + }; + + mautrix-telegram = { + enable = true; + environmentFile = config.sops.templates.mautrixtelegram.path; + registerToSynapse = false; + settings = { + homeserver = { + address = "http://localhost:${builtins.toString servicePort}"; + domain = serviceDomain; + }; + appservice = { + address = "http://localhost:${builtins.toString telegramPort}"; + hostname = "0.0.0.0"; + port = telegramPort; + provisioning.enabled = true; + id = "telegram"; + # ephemeral_events = true; # not needed due to double puppeting + public = { + enabled = false; + }; + database = "postgresql:///mautrix-telegram?host=/run/postgresql"; + }; + bridge = { + relaybot.authless_portals = true; + allow_avatar_remove = true; + allow_contact_info = true; + sync_channel_members = true; + startup_sync = true; + sync_create_limit = 0; + sync_direct_chats = true; + telegram_link_preview = true; + permissions = { + "*" = "relaybot"; + "@swarsel:${serviceDomain}" = "admin"; + }; + animated_sticker = { + target = "gif"; + args = { + width = 256; + height = 256; + fps = 30; # only for webm + background = "020202"; # only for gif, transparency not supported + }; + }; + }; + }; + }; + + mautrix-whatsapp = { + enable = true; + registerToSynapse = false; + settings = { + homeserver = { + address = "http://localhost:${builtins.toString servicePort}"; + domain = serviceDomain; + }; + database = { + type = "postgres"; + uri = "postgresql:///mautrix-whatsapp?host=/run/postgresql"; + }; + appservice = { + address = "http://localhost:${builtins.toString whatsappPort}"; + hostname = "0.0.0.0"; + port = whatsappPort; + }; + bridge = { + displayname_template = "{{or .FullName .PushName .JID}} (WA)"; + history_sync = { + backfill = true; + max_initial_conversations = -1; + message_count = -1; + request_full_sync = true; + full_sync_config = { + days_limit = 900; + size_mb_limit = 5000; + storage_quota_mb = 5000; + }; + }; + login_shared_secret_map = { + ${serviceDomain} = "as_token:doublepuppet"; + }; + sync_manual_marked_unread = true; + send_presence_on_typing = true; + parallel_member_sync = true; + url_previews = true; + caption_in_message = true; + extev_polls = true; + permissions = { + "*" = "relay"; + "@swarsel:${serviceDomain}" = "admin"; + }; + }; + }; + }; + + mautrix-signal = { + enable = true; + registerToSynapse = false; + settings = { + homeserver = { + address = "http://localhost:${builtins.toString servicePort}"; + domain = serviceDomain; + }; + database = { + type = "postgres"; + uri = "postgresql:///mautrix-signal?host=/run/postgresql"; + }; + appservice = { + address = "http://localhost:${builtins.toString signalPort}"; + hostname = "0.0.0.0"; + port = signalPort; + }; + bridge = { + displayname_template = "{{or .ContactName .ProfileName .PhoneNumber}} (Signal)"; + login_shared_secret_map = { + ${serviceDomain} = "as_token:doublepuppet"; + }; + caption_in_message = true; + permissions = { + "*" = "relay"; + "@swarsel:${serviceDomain}" = "admin"; + }; + }; + }; + }; + }; + + # restart the bridges daily. this is done for the signal bridge mainly which stops carrying + # messages out after a while. + + + nodes.${serviceProxy}.services.nginx = { + upstreams = { + ${serviceName} = { + servers = { + "${serviceAddress}:${builtins.toString servicePort}" = { }; + }; + }; + }; + virtualHosts = { + "${serviceDomain}" = { + enableACME = true; + forceSSL = true; + acmeRoot = null; + listen = [ + { + addr = "0.0.0.0"; + port = 8448; + ssl = true; + extraParameters = [ + "default_server" + ]; + } + { + addr = "[::0]"; + port = 8448; + ssl = true; + extraParameters = [ + "default_server" + ]; + } + { + addr = "0.0.0.0"; + port = 443; + ssl = true; + } + { + addr = "[::0]"; + port = 443; + ssl = true; + } + ]; + locations = { + "~ ^(/_matrix|/_synapse/client)" = { + proxyPass = "http://${serviceName}"; + extraConfig = '' + client_max_body_size 0; + ''; + }; + "= /.well-known/matrix/server".extraConfig = mkWellKnown serverConfig; + "= /.well-known/matrix/client".extraConfig = mkWellKnown clientConfig; + }; + }; + }; + }; + }; + } +#+end_src + +**** nextcloud +:PROPERTIES: +:CUSTOM_ID: h:d11ad8d5-25d7-4691-b319-61c16ccef715 +:END: + +#+begin_src nix-ts :tangle modules/nixos/server/nextcloud.nix + { pkgs, lib, config, globals, dns, confLib, ... }: + let + inherit (config.repo.secrets.local.nextcloud) adminuser; + inherit (config.swarselsystems) sopsFile; + inherit (confLib.gen { name = "nextcloud"; port = 80; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6; + + nextcloudVersion = "32"; + in + { + options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselmodules.server.${serviceName} { + + nodes.stoicclub.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + + sops.secrets = { + nextcloud-admin-pw = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + kanidm-nextcloud-client = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + }; + + globals.services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6; + }; + + services = { + ${serviceName} = { + enable = true; + settings = { + trusted_proxies = [ "0.0.0.0" ]; + overwriteprotocol = "https"; + }; + package = pkgs."nextcloud${nextcloudVersion}"; + hostName = serviceDomain; + home = "/Vault/data/${serviceName}"; + datadir = "/Vault/data/${serviceName}"; + https = true; + configureRedis = true; + maxUploadSize = "4G"; + extraApps = { + inherit (pkgs."nextcloud${nextcloudVersion}Packages".apps) mail calendar contacts cospend phonetrack polls tasks sociallogin; + }; + extraAppsEnable = true; + config = { + inherit adminuser; + adminpassFile = config.sops.secrets.nextcloud-admin-pw.path; + dbtype = "sqlite"; + }; + }; + }; + + nodes.${serviceProxy}.services.nginx = { + upstreams = { + ${serviceName} = { + servers = { + "${serviceAddress}:${builtins.toString servicePort}" = { }; + }; + }; + }; + virtualHosts = { + "${serviceDomain}" = { + enableACME = true; + forceSSL = true; + acmeRoot = null; + locations = { + "/" = { + proxyPass = "http://${serviceName}"; + extraConfig = '' + client_max_body_size 0; + ''; + }; + }; + }; + }; + }; + }; + } +#+end_src + +**** immich +:PROPERTIES: +:CUSTOM_ID: h:33bad8ad-b362-4bf1-8a49-b9df92329aed +:END: + +#+begin_src nix-ts :tangle modules/nixos/server/immich.nix + { lib, pkgs, config, globals, dns, confLib, ... }: + let + inherit (confLib.gen { name = "immich"; port = 3001; }) servicePort serviceName serviceUser serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6; + in + { + options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselmodules.server.${serviceName} { + + nodes.stoicclub.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + + users.users.${serviceUser} = { + extraGroups = [ "video" "render" "users" ]; + }; + + topology.self.services.${serviceName}.info = "https://${serviceDomain}"; + + globals.services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6; + }; + + services.${serviceName} = { + enable = true; + package = pkgs.immich; + host = "0.0.0.0"; + port = servicePort; + openFirewall = true; + mediaLocation = "/Vault/Eternor/Immich"; # dataDir + environment = { + IMMICH_MACHINE_LEARNING_URL = lib.mkForce "http://localhost:3003"; + }; + }; + + networking.firewall.allowedTCPPorts = [ servicePort ]; + + nodes.${serviceProxy}.services.nginx = { + upstreams = { + ${serviceName} = { + servers = { + "${serviceAddress}:${builtins.toString servicePort}" = { }; + }; + }; + }; + virtualHosts = { + "${serviceDomain}" = { + enableACME = true; + forceSSL = true; + acmeRoot = null; + locations = { + "/" = { + proxyPass = "http://${serviceName}"; + extraConfig = '' + client_max_body_size 0; + + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_redirect off; + + proxy_read_timeout 600s; + proxy_send_timeout 600s; + send_timeout 600s; + ''; + }; + }; + }; + }; + }; + + }; + + } +#+end_src + +**** paperless (tika, gotenberg) +:PROPERTIES: +:CUSTOM_ID: h:89638fb5-0593-4420-9567-f85f0223e341 +:END: + +This is my personal document management system. It automatically pulls documents from several sources, the only manual step for physical documents is to put them in my scanner and use email delivery. + +Also I install Tika and Gotenberg, which are needed to create PDFs out of =.eml='s. This is needed for e.g. online services that only send their invoices through email body text. + +#+begin_src nix-ts :tangle modules/nixos/server/paperless.nix + { lib, pkgs, config, dns, globals, confLib, ... }: + let + inherit (config.swarselsystems) sopsFile; + inherit (confLib.gen { name = "paperless"; port = 28981; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6; + + tikaPort = 9998; + 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} { + + nodes.stoicclub.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + + users.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.services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6; + }; + + services = { + ${serviceName} = { + enable = true; + mediaDir = "/Vault/Eternor/Paperless"; + dataDir = "/Vault/data/${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"; + } + ]; + }; + }; + }; + }; + + tika = { + enable = true; + port = tikaPort; + openFirewall = false; + listenAddress = "127.0.0.1"; + enableOcr = true; + }; + + gotenberg = { + enable = true; + package = pkgs.stable.gotenberg; + port = gotenbergPort; + bindIP = "127.0.0.1"; + timeout = "600s"; + chromium.package = pkgs.stable.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.${serviceProxy}.services.nginx = { + upstreams = { + ${serviceName} = { + servers = { + "${serviceAddress}:${builtins.toString servicePort}" = { }; + }; + }; + }; + virtualHosts = { + "${serviceDomain}" = { + enableACME = true; + forceSSL = true; + acmeRoot = null; + locations = { + "/" = { + proxyPass = "http://${serviceName}"; + extraConfig = '' + client_max_body_size 0; + proxy_connect_timeout 300; + proxy_send_timeout 300; + proxy_read_timeout 300; + send_timeout 300; + ''; + }; + }; + }; + }; + }; + }; + + } +#+end_src + +**** transmission +:PROPERTIES: +:CUSTOM_ID: h:5afeb311-ab86-4029-be53-2160f6d836c3 +:END: + +#+begin_src nix-ts :tangle modules/nixos/server/transmission.nix + { self, pkgs, lib, config, confLib, ... }: + let + inherit (confLib.gen { name = "transmission"; }) serviceName serviceDomain; + + lidarrUser = "lidarr"; + lidarrGroup = lidarrUser; + lidarrPort = 8686; + radarrUser = "radarr"; + radarrGroup = radarrUser; + radarrPort = 7878; + sonarrUser = "sonarr"; + sonarrGroup = sonarrUser; + sonarrPort = 8989; + readarrUser = "readarr"; + readarrGroup = readarrUser; + readarrPort = 8787; + prowlarrUser = "prowlarr"; + prowlarrGroup = prowlarrUser; + prowlarrPort = 9696; + in + { + options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} and friends on server"; + config = lib.mkIf config.swarselmodules.server.${serviceName} { + + # this user/group section is probably unneeded + 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; + + services = { + radarr = { + enable = true; + user = radarrUser; + group = radarrGroup; + settings.server.port = radarrPort; + openFirewall = true; + dataDir = "/Vault/data/radarr"; + }; + readarr = { + enable = true; + user = readarrUser; + group = readarrGroup; + settings.server.port = readarrPort; + openFirewall = true; + dataDir = "/Vault/data/readarr"; + }; + sonarr = { + enable = true; + user = sonarrUser; + group = sonarrGroup; + settings.server.port = sonarrPort; + openFirewall = true; + dataDir = "/Vault/data/sonarr"; + }; + lidarr = { + enable = true; + user = lidarrUser; + group = lidarrGroup; + settings.server.port = lidarrPort; + openFirewall = true; + dataDir = "/Vault/data/lidarr"; + }; + prowlarr = { + enable = true; + settings.server.port = prowlarrPort; + openFirewall = true; + }; + + nginx = { + virtualHosts = { + "${serviceDomain}" = { + enableACME = false; + forceSSL = false; + acmeRoot = null; + locations = { + "/" = { + proxyPass = "http://localhost:9091"; + extraConfig = '' + client_max_body_size 0; + ''; + }; + "/radarr" = { + proxyPass = "http://localhost:${builtins.toString radarrPort}"; + extraConfig = '' + client_max_body_size 0; + ''; + }; + "/readarr" = { + proxyPass = "http://localhost:${builtins.toString readarrPort}"; + extraConfig = '' + client_max_body_size 0; + ''; + }; + "/sonarr" = { + proxyPass = "http://localhost:${builtins.toString sonarrPort}"; + extraConfig = '' + client_max_body_size 0; + ''; + }; + "/lidarr" = { + proxyPass = "http://localhost:${builtins.toString lidarrPort}"; + extraConfig = '' + client_max_body_size 0; + ''; + }; + "/prowlarr" = { + proxyPass = "http://localhost:${builtins.toString prowlarrPort}"; + extraConfig = '' + client_max_body_size 0; + ''; + }; + }; + }; + }; + }; + }; + }; + } + +#+end_src + +**** syncthing +:PROPERTIES: +:CUSTOM_ID: h:ad2787a2-7b1c-4326-aeff-9d8d6c3f591d +:END: + +#+begin_src nix-ts :tangle modules/nixos/server/syncthing.nix + { lib, config, globals, dns, confLib, ... }: + let + inherit (config.swarselsystems.syncthing) serviceDomain; + inherit (confLib.gen { name = "syncthing"; port = 8384; }) servicePort serviceName serviceUser serviceGroup serviceAddress serviceProxy proxyAddress4 proxyAddress6; + + specificServiceName = "${serviceName}-${config.node.name}"; + + cfg = config.services.${serviceName}; + devices = config.swarselsystems.syncthing.syncDevices; + in + { + options = { + swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; + + swarselsystems.syncthing = { + serviceDomain = lib.mkOption { + type = lib.types.str; + default = config.repo.secrets.common.services.domains.syncthing1; + }; + syncDevices = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ "magicant" "winters" "pyramid" "moonside@oracle" ]; + }; + devices = lib.mkOption { + type = lib.types.attrs; + default = { + "magicant" = { + id = "VMWGEE2-4HDS2QO-KNQOVGN-LXLX6LA-666E4EK-ZBRYRRO-XFEX6FB-6E3XLQO"; + }; + "winters" = { + id = "O7RWDMD-AEAHPP7-7TAVLKZ-BSWNBTU-2VA44MS-EYGUNBB-SLHKB3C-ZSLMOAA"; + }; + "moonside@oracle" = { + id = "VPCDZB6-MGVGQZD-Q6DIZW3-IZJRJTO-TCC3QUQ-2BNTL7P-AKE7FBO-N55UNQE"; + }; + "pyramid" = { + id = "YAPV4BV-I26WPTN-SIP32MV-SQP5TBZ-3CHMTCI-Z3D6EP2-MNDQGLP-53FT3AB"; + }; + }; + }; + }; + }; + config = lib.mkIf config.swarselmodules.server.${serviceName} { + + nodes.stoicclub.swarselsystems.server.dns.${globals.services.${specificServiceName}.baseDomain}.subdomainRecords = { + "${globals.services.${specificServiceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + + users.users.${serviceUser} = { + extraGroups = [ "users" ]; + group = serviceGroup; + isSystemUser = true; + }; + + users.groups.${serviceGroup} = { }; + + networking.firewall.allowedTCPPorts = [ servicePort ]; + + globals.services.${specificServiceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6; + }; + + services.${serviceName} = rec { + enable = true; + user = serviceUser; + group = serviceGroup; + dataDir = lib.mkDefault "/Vault/data/${serviceName}"; + configDir = "${cfg.dataDir}/.config/${serviceName}"; + guiAddress = "0.0.0.0:${builtins.toString servicePort}"; + openDefaultPorts = true; # opens ports TCP/UDP 22000 and UDP 21027 for discovery + relay.enable = false; + settings = { + urAccepted = -1; + inherit (config.swarselsystems.syncthing) devices; + folders = { + "Default Folder" = lib.mkForce { + path = "${cfg.dataDir}/Sync"; + type = "receiveonly"; + versioning = null; + inherit devices; + id = "default"; + }; + "Obsidian" = { + path = "${cfg.dataDir}/Obsidian"; + type = "receiveonly"; + versioning = { + type = "simple"; + params.keep = "5"; + }; + inherit devices; + id = "yjvni-9eaa7"; + }; + "Org" = { + path = "${cfg.dataDir}/Org"; + type = "receiveonly"; + versioning = { + type = "simple"; + params.keep = "5"; + }; + inherit devices; + id = "a7xnl-zjj3d"; + }; + "Vpn" = { + path = "${cfg.dataDir}/Vpn"; + type = "receiveonly"; + versioning = { + type = "simple"; + params.keep = "5"; + }; + inherit devices; + id = "hgp9s-fyq3p"; + }; + }; + }; + }; + + nodes.${serviceProxy}.services.nginx = { + upstreams = { + ${specificServiceName} = { + servers = { + "${serviceAddress}:${builtins.toString servicePort}" = { }; + }; + }; + }; + virtualHosts = { + "${serviceDomain}" = { + enableACME = true; + forceSSL = true; + acmeRoot = null; + locations = { + "/" = { + proxyPass = "http://${specificServiceName}"; + extraConfig = '' + client_max_body_size 0; + ''; + }; + }; + }; + }; + }; + }; + } +#+end_src + +**** restic +:PROPERTIES: +:CUSTOM_ID: h:b73ac8bf-b721-4563-9eff-973925c99a39 +:END: + +This manages backups for my pictures and obsidian files. +Note: you still need to run =restic- init= once on the host to get the bucket running. + +#+begin_src nix-ts :tangle modules/nixos/server/restic.nix + { lib, pkgs, config, ... }: + let + inherit (config.swarselsystems) sopsFile; + in + { + options.swarselmodules.server.restic = lib.mkEnableOption "enable restic backups on server"; + options.swarselsystems.server.restic = { + bucketName = lib.mkOption { + type = lib.types.str; + }; + paths = lib.mkOption { + type = lib.types.listOf lib.types.str; + }; + }; + config = lib.mkIf config.swarselmodules.server.restic { + + sops = { + secrets = { + resticpw = { inherit sopsFile; }; + resticaccesskey = { inherit sopsFile; }; + resticsecretaccesskey = { inherit sopsFile; }; + }; + templates = { + "restic-env".content = '' + AWS_ACCESS_KEY_ID=${config.sops.placeholder.resticaccesskey} + AWS_SECRET_ACCESS_KEY=${config.sops.placeholder.resticsecretaccesskey} + ''; + }; + }; + + services.restic = + let + inherit (config.repo.secrets.local) resticRepo; + in + { + backups = { + "${config.swarselsystems.server.restic.bucketName}" = { + environmentFile = config.sops.templates."restic-env".path; + passwordFile = config.sops.secrets.resticpw.path; + inherit (config.swarselsystems.server.restic) paths; + pruneOpts = [ + "--keep-daily 3" + "--keep-weekly 2" + "--keep-monthly 3" + "--keep-yearly 100" + ]; + backupPrepareCommand = '' + ${pkgs.restic}/bin/restic prune + ''; + repository = "${resticRepo}"; + initialize = true; + timerConfig = { + OnCalendar = "03:00"; + }; + }; + + }; + }; + + }; + } +#+end_src + +**** monitoring (Grafana, Prometheus) +:PROPERTIES: +:CUSTOM_ID: h:a31c7192-e11d-4a26-915d-1bbc38e373d3 +:END: + +This section exposes several metrics that I use to check the health of my server. I need to expand on the exporters section at some point, but for now I have everything I need. + +#+begin_src nix-ts :tangle modules/nixos/server/monitoring.nix + { self, lib, config, globals, dns, confLib, ... }: + let + inherit (confLib.gen { name = "grafana"; port = 3000; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6; + + prometheusPort = 9090; + prometheusUser = "prometheus"; + prometheusGroup = prometheusUser; + grafanaUpstream = "grafana"; + prometheusUpstream = "prometheus"; + prometheusWebRoot = "prometheus"; + kanidmDomain = globals.services.kanidm.domain; + + inherit (config.swarselsystems) sopsFile; + in + { + options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselmodules.server.${serviceName} { + + nodes.stoicclub.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + + sops = { + secrets = { + grafana-admin-pw = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + prometheus-admin-pw = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + kanidm-grafana-client = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + prometheus-admin-hash = { sopsFile = self + /secrets/winters/secrets2.yaml; owner = prometheusUser; group = prometheusGroup; mode = "0440"; }; + + }; + templates = { + "web-config" = { + content = '' + basic_auth_users: + admin: ${config.sops.placeholder.prometheus-admin-hash} + ''; + owner = prometheusUser; + group = prometheusGroup; + mode = "0440"; + }; + }; + }; + + users = { + users = { + nextcloud-exporter = { + extraGroups = [ "nextcloud" ]; + }; + + ${serviceUser} = { + extraGroups = [ "users" ]; + }; + }; + }; + + networking.firewall.allowedTCPPorts = [ servicePort prometheusPort ]; + + topology.self.services.prometheus.info = "https://${serviceDomain}/${prometheusWebRoot}"; + + globals.services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6; + }; + + services = { + ${serviceName} = { + enable = true; + dataDir = "/Vault/data/${serviceName}"; + provision = { + enable = true; + datasources.settings = { + datasources = [ + { + name = "prometheus"; + type = "prometheus"; + url = "https://${serviceDomain}/prometheus"; + editable = false; + access = "proxy"; + basicAuth = true; + basicAuthUser = "admin"; + jsonData = { + httpMethod = "POST"; + manageAlerts = true; + prometheusType = "Prometheus"; + prometheusVersion = "> 2.50.x"; + cacheLevel = "High"; + disableRecordingRules = false; + incrementalQueryOverlapWindow = "10m"; + }; + secureJsonData = { + basicAuthPassword = "$__file{/run/secrets/prometheus-admin-pw}"; + }; + } + ]; + }; + }; + + settings = { + analytics.reporting_enabled = false; + users.allow_sign_up = false; + security = { + admin_password = "$__file{/run/secrets/grafana-admin-pw}"; + cookie_secure = true; + disable_gravatar = true; + }; + server = { + domain = serviceDomain; + root_url = "https://${serviceDomain}"; + http_port = servicePort; + http_addr = "0.0.0.0"; + protocol = "http"; + enforce_domain = true; + enable_gzip = true; + }; + "auth.generic_oauth" = { + enabled = true; + name = "Kanidm"; + icon = "signin"; + allow_sign_up = true; + #auto_login = true; + client_id = "grafana"; + client_secret = "$__file{${config.sops.secrets.kanidm-grafana-client.path}}"; + scopes = "openid email profile"; + login_attribute_path = "preferred_username"; + auth_url = "https://${kanidmDomain}/ui/oauth2"; + token_url = "https://${kanidmDomain}/oauth2/token"; + api_url = "https://${kanidmDomain}/oauth2/openid/grafana/userinfo"; + use_pkce = true; + use_refresh_token = true; + # Allow mapping oauth2 roles to server admin + allow_assign_grafana_admin = true; + role_attribute_path = "contains(groups[*], 'server_admin') && 'GrafanaAdmin' || contains(groups[*], 'admin') && 'Admin' || contains(groups[*], 'editor') && 'Editor' || 'Viewer'"; + }; + }; + }; + + prometheus = + let + nextcloudUser = config.repo.secrets.local.nextcloud.adminuser; + in + { + enable = true; + webExternalUrl = "https://${serviceDomain}/${prometheusWebRoot}"; + port = prometheusPort; + listenAddress = "0.0.0.0"; + globalConfig = { + scrape_interval = "10s"; + }; + webConfigFile = config.sops.templates.web-config.path; + scrapeConfigs = [ + { + job_name = "node"; + static_configs = [{ + targets = [ "localhost:${toString config.services.prometheus.exporters.node.port}" ]; + }]; + } + { + job_name = "zfs"; + static_configs = [{ + targets = [ "localhost:${toString config.services.prometheus.exporters.zfs.port}" ]; + }]; + } + { + job_name = "nginx"; + static_configs = [{ + targets = [ "localhost:${toString config.services.prometheus.exporters.nginx.port}" ]; + }]; + } + { + job_name = "nextcloud"; + static_configs = [{ + targets = [ "localhost:${toString config.services.prometheus.exporters.nextcloud.port}" ]; + }]; + } + ]; + exporters = { + node = { + enable = true; + port = 9000; + enabledCollectors = [ "systemd" ]; + extraFlags = [ "--collector.ethtool" "--collector.softirqs" "--collector.tcpstat" "--collector.wifi" ]; + }; + zfs = { + enable = true; + port = 9134; + pools = [ + "Vault" + ]; + }; + restic = { + enable = false; + port = 9753; + }; + nginx = { + enable = true; + port = 9113; + sslVerify = false; + scrapeUri = "http://localhost/nginx_status"; + }; + nextcloud = lib.mkIf config.swarselmodules.server.nextcloud { + enable = true; + port = 9205; + url = "https://${serviceDomain}/ocs/v2.php/apps/serverinfo/api/v1/info"; + username = nextcloudUser; + passwordFile = config.sops.secrets.nextcloud-admin-pw.path; + }; + }; + }; + }; + + + nodes.${serviceProxy}.services.nginx = { + upstreams = { + "${grafanaUpstream}" = { + servers = { + "${serviceAddress}:${builtins.toString servicePort}" = { }; + }; + }; + "${prometheusUpstream}" = { + servers = { + "${serviceAddress}:${builtins.toString prometheusPort}" = { }; + }; + }; + }; + virtualHosts = { + "${serviceDomain}" = { + enableACME = true; + forceSSL = true; + acmeRoot = null; + locations = { + "/" = { + proxyPass = "http://${grafanaUpstream}"; + proxyWebsockets = true; + extraConfig = '' + client_max_body_size 0; + ''; + }; + "/${prometheusWebRoot}" = { + proxyPass = "http://${prometheusUpstream}"; + extraConfig = '' + client_max_body_size 0; + ''; + }; + }; + }; + }; + }; + }; + } +#+end_src + +**** Jenkins +:PROPERTIES: +:CUSTOM_ID: h:23452a18-a0a1-4515-8612-ceb19bb5fc22 +:END: + +This is a WIP Jenkins instance. It is used to automatically build a new system when pushes to the main repository are detected. I have turned this service off for now however, as I actually prefer to start my builds manually. + +#+begin_src nix-ts :tangle modules/nixos/server/jenkins.nix + { pkgs, lib, config, globals, dns, confLib, ... }: + let + inherit (confLib.gen { name = "jenkins"; port = 8088; }) servicePort serviceName serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6; + in + { + options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselmodules.server.${serviceName} { + + nodes.stoicclub.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + + globals.services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6; + }; + + services.jenkins = { + enable = true; + withCLI = true; + port = servicePort; + packages = [ pkgs.stdenv pkgs.git pkgs.jdk17 config.programs.ssh.package pkgs.nix ]; + listenAddress = "0.0.0.0"; + home = "/Vault/apps/${serviceName}"; + }; + + nodes.${serviceProxy}.services.nginx = { + upstreams = { + ${serviceName} = { + servers = { + "${serviceAddress}:${builtins.toString servicePort}" = { }; + }; + }; + }; + virtualHosts = { + "${serviceDomain}" = { + enableACME = true; + forceSSL = true; + acmeRoot = null; + locations = { + "/" = { + proxyPass = "http://${serviceName}"; + extraConfig = '' + client_max_body_size 0; + ''; + }; + }; + }; + }; + }; + }; + + } +#+end_src + +**** Emacs elfeed (RSS Server) +:PROPERTIES: +:CUSTOM_ID: h:4e6824bc-c3db-485d-b543-4072e6283b62 +:END: + +This was an approach of hosting an RSS server from within emacs. That would have been useful as it would have allowed me to allow my feeds from any device. However, it proved impossible to do bidirectional syncing, so I abandoned this configuration in favor of [[#h:9da3df74-6fc5-4ee1-a345-23ab4e8a613d][FreshRSS]]. + +#+begin_src nix-ts :tangle modules/nixos/server/emacs.nix + { lib, config, confLib, ... }: + let + inherit (confLib.gen { name = "emacs"; port = 9812; }) servicePort serviceName; + in + { + options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} server on server"; + config = lib.mkIf config.swarselmodules.server.${serviceName} { + + networking.firewall.allowedTCPPorts = [ servicePort ]; + + services.${serviceName} = { + enable = true; + install = true; + startWithGraphical = false; + }; + + }; + + } +#+end_src + +**** FreshRSS +:PROPERTIES: +:CUSTOM_ID: h:9da3df74-6fc5-4ee1-a345-23ab4e8a613d +:END: + +FreshRSS is a more 'classical' RSS aggregator that I can just host as a distinct service. This also has its upsides because I jave more control over the state this way. + +It serves both a Greader API at https://${serviceName}/api/greader.php, as well as a Fever API at https://${serviceName}/api/fever.php. + +I am using this with CapyReader on my phone, set it up as a FreshRSS account with Server URL =https://${serviceName}/api/greader.php + +FreshRSS claims to support HTTP header auth, but at least it does not work with my oauth2-proxy setup. Until this is fixed, I resorted to the "form" login, since I mostly do not use the web version anyways. + +#+begin_src nix-ts :tangle modules/nixos/server/freshrss.nix + { self, lib, config, globals, dns, confLib, ... }: + let + inherit (confLib.gen { name = "freshrss"; port = 80; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6; + + inherit (config.swarselsystems) sopsFile; + in + { + options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselmodules.server.${serviceName} { + + nodes.stoicclub.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + + users.users.${serviceUser} = { + extraGroups = [ "users" ]; + group = serviceGroup; + isSystemUser = true; + }; + + users.groups.${serviceGroup} = { }; + + sops = { + secrets = { + freshrss-pw = { inherit sopsFile; owner = serviceUser; }; + kanidm-freshrss-client = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + # freshrss-oidc-crypto-key = { owner = serviceUser; group = serviceGroup; mode = "0440"; }; + }; + + # templates = { + # "freshrss-env" = { + # content = '' + # DATA_PATH=${config.services.freshrss.dataDir} + # OIDC_ENABLED=1 + # OIDC_PROVIDER_METADATA_URL=https://${kanidmDomain}/.well-known/openid-configuration + # OIDC_CLIENT_ID=freshrss + # OIDC_CLIENT_SECRET=${config.sops.placeholder.kanidm-freshrss-client} + # OIDC_CLIENT_CRYPTO_KEY=${config.sops.placeholder.oidc-crypto-key} + # OIDC_REMOTE_USER_CLAIM=preferred_username + # OIDC_SCOPES=openid groups email profile + # OIDC_X_FORWARDED_HEADERS=X-Forwarded-Host X-Forwarded-Port X-Forwarded-Proto + # ''; + # owner = "freshrss"; + # group = "freshrss"; + # mode = "0440"; + # }; + # }; + }; + + topology.self.services.${serviceName} = { + name = "FreshRSS"; + info = "https://${serviceDomain}"; + icon = "${self}/files/topology-images/${serviceName}.png"; + }; + + globals.services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6; + }; + + services.${serviceName} = + let + inherit (config.repo.secrets.local.freshrss) defaultUser; + in + { + inherit defaultUser; + enable = true; + virtualHost = serviceDomain; + baseUrl = "https://${serviceDomain}"; + authType = "form"; + dataDir = "/Vault/data/tt-rss"; + passwordFile = config.sops.secrets.freshrss-pw.path; + }; + + # systemd.services.freshrss-config.serviceConfig.EnvironmentFile = [ + # config.sops.templates.freshrss-env.path + # ]; + + nodes.${serviceProxy}.services.nginx = { + upstreams = { + ${serviceName} = { + servers = { + "${serviceAddress}:${builtins.toString servicePort}" = { }; + }; + }; + }; + virtualHosts = { + "${serviceDomain}" = { + enableACME = true; + forceSSL = true; + acmeRoot = null; + oauth2.enable = true; + oauth2.allowedGroups = [ "ttrss_access" ]; + locations = { + "/" = { + proxyPass = "http://${serviceName}"; + }; + "/api" = { + proxyPass = "http://${serviceName}"; + setOauth2Headers = false; + bypassAuth = true; + }; + }; + }; + }; + }; + }; + } +#+end_src + +**** forgejo (git server) +:PROPERTIES: +:CUSTOM_ID: h:a9965660-4358-4b9a-8c46-d55f28598344 +:END: + +#+begin_src nix-ts :tangle modules/nixos/server/forgejo.nix + { lib, config, pkgs, globals, dns, confLib, ... }: + let + inherit (config.swarselsystems) sopsFile; + inherit (confLib.gen { name = "forgejo"; port = 3004; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6; + + kanidmDomain = globals.services.kanidm.domain; + in + { + options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselmodules.server.${serviceName} { + + nodes.stoicclub.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + + networking.firewall.allowedTCPPorts = [ servicePort ]; + + users.users.${serviceUser} = { + group = serviceGroup; + isSystemUser = true; + }; + + users.groups.${serviceGroup} = { }; + + sops.secrets = { + kanidm-forgejo-client = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + }; + + globals.services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6; + }; + + services.${serviceName} = { + enable = true; + stateDir = "/Vault/data/${serviceName}"; + user = serviceUser; + group = serviceGroup; + lfs.enable = lib.mkDefault true; + settings = { + DEFAULT = { + APP_NAME = "~SwaGit~"; + }; + server = { + PROTOCOL = "http"; + HTTP_PORT = servicePort; + HTTP_ADDR = "0.0.0.0"; + DOMAIN = serviceDomain; + ROOT_URL = "https://${serviceDomain}"; + }; + # federation.ENABLED = true; + service = { + DISABLE_REGISTRATION = false; + ALLOW_ONLY_INTERNAL_REGISTRATION = false; + ALLOW_ONLY_EXTERNAL_REGISTRATION = true; + SHOW_REGISTRATION_BUTTON = false; + }; + session.COOKIE_SECURE = true; + oauth2_client = { + # Never use auto account linking with this, otherwise users cannot change + # their new user name and they could potentially overtake other users accounts + # by setting their email address to an existing account. + # With "login" linking the user must choose a non-existing username first or login + # with the existing account to link. + ACCOUNT_LINKING = "login"; + USERNAME = "nickname"; + # This does not mean that you cannot register via oauth, but just that there should + # be a confirmation dialog shown to the user before the account is actually created. + # This dialog allows changing user name and email address before creating the account. + ENABLE_AUTO_REGISTRATION = false; + REGISTER_EMAIL_CONFIRM = false; + UPDATE_AVATAR = true; + }; + }; + }; + + systemd.services.${serviceName} = { + serviceConfig.RestartSec = "60"; # Retry every minute + preStart = + let + exe = lib.getExe config.services.forgejo.package; + providerName = "kanidm"; + clientId = serviceName; + args = lib.escapeShellArgs ( + lib.concatLists [ + [ + "--name" + providerName + ] + [ + "--provider" + "openidConnect" + ] + [ + "--key" + clientId + ] + [ + "--auto-discover-url" + "https://${kanidmDomain}/oauth2/openid/${clientId}/.well-known/openid-configuration" + ] + [ + "--scopes" + "email" + ] + [ + "--scopes" + "profile" + ] + [ + "--group-claim-name" + "groups" + ] + [ + "--admin-group" + "admin" + ] + [ "--skip-local-2fa" ] + ] + ); + in + lib.mkAfter '' + provider_id=$(${exe} admin auth list | ${pkgs.gnugrep}/bin/grep -w '${providerName}' | cut -f1) + SECRET="$(< ${config.sops.secrets.kanidm-forgejo-client.path})" + if [[ -z "$provider_id" ]]; then + ${exe} admin auth add-oauth ${args} --secret "$SECRET" + else + ${exe} admin auth update-oauth --id "$provider_id" ${args} --secret "$SECRET" + fi + ''; + }; + + nodes.${serviceProxy}.services.nginx = { + upstreams = { + ${serviceName} = { + servers = { + "${serviceAddress}:${builtins.toString servicePort}" = { }; + }; + }; + }; + virtualHosts = { + "${serviceDomain}" = { + enableACME = true; + forceSSL = true; + acmeRoot = null; + locations = { + "/" = { + proxyPass = "http://${serviceName}"; + extraConfig = '' + client_max_body_size 0; + ''; + }; + }; + }; + }; + }; + }; + + } +#+end_src + +**** Anki Sync Server +:PROPERTIES: +:CUSTOM_ID: h:cb3f6552-7751-4f9a-b4c7-8d8ba5b255c4 +:END: + +#+begin_src nix-ts :tangle modules/nixos/server/ankisync.nix + { self, lib, config, globals, dns, confLib, ... }: + let + inherit (config.swarselsystems) sopsFile; + inherit (confLib.gen { name = "ankisync"; port = 27701; }) servicePort serviceName serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6; + + ankiUser = globals.user.name; + in + { + options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselmodules.server.${serviceName} { + + nodes.stoicclub.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + + networking.firewall.allowedTCPPorts = [ servicePort ]; + + sops.secrets.anki-pw = { inherit sopsFile; owner = "root"; }; + + topology.self.services.anki = { + name = lib.mkForce "Anki Sync Server"; + icon = lib.mkForce "${self}/files/topology-images/${serviceName}.png"; + info = "https://${serviceDomain}"; + }; + + globals.services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6; + }; + + services.anki-sync-server = { + enable = true; + port = servicePort; + address = "0.0.0.0"; + openFirewall = true; + users = [ + { + username = ankiUser; + passwordFile = config.sops.secrets.anki-pw.path; + } + ]; + }; + + nodes.${serviceProxy}.services.nginx = { + upstreams = { + ${serviceName} = { + servers = { + "${serviceAddress}:${builtins.toString servicePort}" = { }; + }; + }; + }; + virtualHosts = { + "${serviceDomain}" = { + enableACME = true; + forceSSL = true; + acmeRoot = null; + locations = { + "/" = { + proxyPass = "http://${serviceName}"; + extraConfig = '' + client_max_body_size 0; + ''; + }; + }; + }; + }; + }; + }; + + } +#+end_src + +**** kanidm +:PROPERTIES: +:CUSTOM_ID: h:ee625136-29ab-4696-919f-7b0d0042f6dd +:END: + +The forgejo configuration is a little broken and will show a 500 error when signing in through kanidm. However, when pressing back and refreshing the page, I am logged in. Currently I cannot be bothered to fix this. + +A stupid (but simple) way to get the =originUrl= is to simply set any URL there and try to auth using kanidm. Then check the logs (=journalctl -eu kanidm=) and check for the line that says something along the lines of + `🚧 [warn]: Invalid OAuth2 redirect_uri (must be an exact match to a redirect-url) - got ` + +To get other URLs (token, etc.), use https:///oauth2/openid//.well-known/oauth-authorization-server, e.g. https:///oauth2/openid/nextcloud/.well-known/oauth-authorization-server, with clienID being the client name as specified in kanidm. + +#+begin_src nix-ts :tangle modules/nixos/server/kanidm.nix + { self, lib, pkgs, config, globals, dns, confLib, ... }: + let + certsSopsFile = self + /secrets/certs/secrets.yaml; + inherit (config.swarselsystems) sopsFile; + inherit (confLib.gen { name = "kanidm"; port = 8300; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6; + + oauth2ProxyDomain = globals.services.oauth2-proxy.domain; + immichDomain = globals.services.immich.domain; + paperlessDomain = globals.services.paperless.domain; + forgejoDomain = globals.services.forgejo.domain; + grafanaDomain = globals.services.grafana.domain; + nextcloudDomain = globals.services.nextcloud.domain; + + certBase = "/etc/ssl"; + certsDir = "${certBase}/certs"; + privateDir = "${certBase}/private"; + certPathBase = "${certsDir}/${serviceName}.crt"; + certPath = + if config.swarselsystems.isImpermanence then + "/persist${certPathBase}" + else + "${certPathBase}"; + keyPathBase = "${privateDir}/${serviceName}.key"; + keyPath = + if config.swarselsystems.isImpermanence then + "/persist${keyPathBase}" + else + "${keyPathBase}"; + in + { + options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselmodules.server.${serviceName} { + + nodes.stoicclub.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + + users.users.${serviceUser} = { + group = serviceGroup; + isSystemUser = true; + }; + + users.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.services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6; + }; + + environment.persistence."/persist" = lib.mkIf config.swarselsystems.isImpermanence { + files = [ + certPathBase + keyPathBase + ]; + }; + 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=1 + else + echo 'Certificate exists and is still valid' + 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}" + + chmod 0644 "${certPath}" + chmod 0600 "${keyPath}" + chown ${serviceUser}:${serviceGroup} "${certPath}" "${keyPath}" + fi + ''; + }; + + + # 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 ""} + + # 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}" + + # 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_7; + enableServer = true; + serverSettings = { + 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; + }; + enableClient = true; + clientSettings = { + uri = config.services.kanidm.serverSettings.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" = { }; + }; + + 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" + ]; + }; + 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" ]; + }; + }; + }; + 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" + ]; + "navidrome.access" = [ + "openid" + "email" + "profile" + ]; + "firefly.access" = [ + "openid" + "email" + "profile" + ]; + "radicale.access" = [ + "openid" + "email" + "profile" + ]; + "slink.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" ]; + }; + }; + }; + }; + }; + }; + }; + }; + + systemd.services = { + ${serviceName}.serviceConfig.RestartSec = "30"; + }; + + nodes.${serviceProxy}.services.nginx = { + upstreams = { + ${serviceName} = { + servers = { + "${serviceAddress}:${builtins.toString servicePort}" = { }; + }; + }; + }; + virtualHosts = { + "${serviceDomain}" = { + enableACME = true; + forceSSL = true; + acmeRoot = null; + locations = { + "/" = { + proxyPass = "https://${serviceName}"; + }; + }; + extraConfig = '' + proxy_ssl_verify off; + ''; + }; + }; + }; + }; + } +#+end_src + +**** oauth2-proxy +:PROPERTIES: +:CUSTOM_ID: h:605f5974-e985-4572-b353-fd1d3ccbadae +:END: + + +#+begin_src nix-ts :tangle modules/nixos/server/oauth2-proxy.nix + { lib, config, globals, dns, confLib, ... }: + let + inherit (confLib.gen { name = "oauth2-proxy"; port = 3004; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6; + + kanidmDomain = globals.services.kanidm.domain; + mainDomain = globals.domains.main; + + inherit (config.swarselsystems) sopsFile; + in + { + options = { + swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; + # largely based on https://github.com/oddlama/nix-config/blob/main/modules/oauth2-proxy.nix + services.nginx.virtualHosts = lib.mkOption { + type = lib.types.attrsOf ( + lib.types.submodule ( + { config, ... }: + { + options.oauth2 = { + enable = lib.mkEnableOption "access protection of this virtualHost using oauth2-proxy."; + allowedGroups = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ ]; + description = '' + A list of kanidm groups that are allowed to access this resource, or the + empty list to allow any authenticated client. + ''; + }; + X-User = lib.mkOption { + type = lib.types.str; + default = "$upstream_http_x_auth_request_user"; + description = "The variable to set as X-User"; + }; + X-Email = lib.mkOption { + type = lib.types.str; + default = "$upstream_http_x_auth_request_email"; + description = "The variable to set as X-Email"; + }; + X-Access-Token = lib.mkOption { + type = lib.types.str; + default = "$upstream_http_x_auth_request_access_token"; + description = "The variable to set as X-Access-Token"; + }; + }; + options.locations = lib.mkOption { + type = lib.types.attrsOf ( + lib.types.submodule (locationSubmodule: { + options = { + setOauth2Headers = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Whether to add oauth2 headers to this location. Only takes effect is oauth2 is actually enabled on the parent vhost."; + }; + bypassAuth = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Whether to set auth_request off for this location. Only takes effect is oauth2 is actually enabled on the parent vhost."; + }; + }; + config = lib.mkIf config.oauth2.enable { + extraConfig = lib.optionalString locationSubmodule.config.setOauth2Headers '' + proxy_set_header X-User $user; + proxy_set_header Remote-User $user; + proxy_set_header X-Remote-User $user; + proxy_set_header X-Email $email; + # proxy_set_header X-Access-Token $token; + add_header Set-Cookie $auth_cookie; + '' + lib.optionalString locationSubmodule.config.bypassAuth '' + auth_request off; + ''; + }; + }) + ); + }; + config = lib.mkIf config.oauth2.enable { + extraConfig = '' + auth_request /oauth2/auth; + error_page 401 = /oauth2/sign_in; + + # set variables that can be used in locations..extraConfig + # pass information via X-User and X-Email headers to backend, + # requires running with --set-xauthrequest flag + auth_request_set $user ${config.oauth2.X-User}; + auth_request_set $email ${config.oauth2.X-Email}; + # if you enabled --pass-access-token, this will pass the token to the backend + # auth_request_set $token ${config.oauth2.X-Access-Token}; + # if you enabled --cookie-refresh, this is needed for it to work with auth_request + auth_request_set $auth_cookie $upstream_http_set_cookie; + ''; + locations = { + "/oauth2/" = { + proxyPass = "http://oauth2-proxy"; + setOauth2Headers = false; + bypassAuth = true; + extraConfig = '' + proxy_set_header X-Scheme $scheme; + proxy_set_header X-Auth-Request-Redirect $scheme://$host$request_uri; + ''; + }; + "= /oauth2/auth" = { + proxyPass = "http://oauth2-proxy/oauth2/auth" + lib.optionalString (config.oauth2.allowedGroups != [ ]) "?allowed_groups=${lib.concatStringsSep "," config.oauth2.allowedGroups}"; + setOauth2Headers = false; + bypassAuth = true; + extraConfig = '' + internal; + + proxy_set_header X-Scheme $scheme; + # nginx auth_request includes headers but not body + proxy_set_header Content-Length ""; + proxy_pass_request_body off; + ''; + }; + }; + }; + } + ) + ); + }; + }; + config = lib.mkIf config.swarselmodules.server.${serviceName} { + + nodes.stoicclub.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + + sops = { + secrets = { + "oauth2-cookie-secret" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + "kanidm-oauth2-proxy-client" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + }; + + templates = { + "kanidm-oauth2-proxy-client-env" = { + content = '' + OAUTH2_PROXY_CLIENT_SECRET="${config.sops.placeholder.kanidm-oauth2-proxy-client}" + OAUTH2_PROXY_COOKIE_SECRET=${config.sops.placeholder.oauth2-cookie-secret} + ''; + owner = serviceUser; + group = serviceGroup; + mode = "0440"; + }; + }; + }; + + networking.firewall.allowedTCPPorts = [ servicePort ]; + + globals.services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6; + }; + + services = { + ${serviceName} = { + enable = true; + cookie = { + domain = ".${mainDomain}"; + secure = true; + expire = "900m"; + secret = null; # set by service EnvironmentFile + }; + clientSecret = null; # set by service EnvironmentFile + reverseProxy = true; + httpAddress = "0.0.0.0:${builtins.toString servicePort}"; + redirectURL = "https://${serviceDomain}/oauth2/callback"; + setXauthrequest = true; + extraConfig = { + code-challenge-method = "S256"; + whitelist-domain = ".${mainDomain}"; + set-authorization-header = true; + pass-access-token = true; + skip-jwt-bearer-tokens = true; + upstream = "static://202"; + oidc-issuer-url = "https://${kanidmDomain}/oauth2/openid/oauth2-proxy"; + provider-display-name = "Kanidm"; + }; + provider = "oidc"; + scope = "openid email"; + loginURL = "https://${kanidmDomain}/ui/oauth2"; + redeemURL = "https://${kanidmDomain}/oauth2/token"; + validateURL = "https://${kanidmDomain}/oauth2/openid/oauth2-proxy/userinfo"; + clientID = serviceName; + email.domains = [ "*" ]; + }; + }; + + systemd.services = { + ${serviceName} = { + # after = [ "kanidm.service" ]; + serviceConfig = { + RuntimeDirectory = serviceName; + RuntimeDirectoryMode = "0750"; + UMask = "007"; # TODO remove once https://github.com/oauth2-proxy/oauth2-proxy/issues/2141 is fixed + RestartSec = "60"; # Retry every minute + EnvironmentFile = [ + config.sops.templates.kanidm-oauth2-proxy-client-env.path + ]; + }; + }; + }; + + nodes.${serviceProxy}.services.nginx = { + upstreams = { + ${serviceName} = { + servers = { + "${serviceAddress}:${builtins.toString servicePort}" = { }; + }; + }; + }; + virtualHosts = { + "${serviceDomain}" = { + enableACME = true; + forceSSL = true; + acmeRoot = null; + locations = { + "/" = { + proxyPass = "http://${serviceName}"; + }; + }; + extraConfig = '' + proxy_set_header X-Scheme $scheme; + proxy_set_header X-Auth-Request-Redirect $scheme://$host$request_uri; + ''; + }; + }; + }; + }; + } +#+end_src + +**** Firefly-III +:PROPERTIES: +:CUSTOM_ID: h:4248e9eb-4b9f-4771-bbfb-7186ef7a8331 +:END: + +#+begin_src nix-ts :tangle modules/nixos/server/firefly-iii.nix + { self, lib, config, globals, dns, confLib, ... }: + let + inherit (confLib.gen { name = "firefly-iii"; port = 80; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6; + + nginxGroup = "nginx"; + + inherit (config.swarselsystems) sopsFile; + cfg = config.services.firefly-iii; + in + { + options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselmodules.server.${serviceName} { + + nodes.stoicclub.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + + users = { + groups.${serviceGroup} = { }; + users.${serviceUser} = { + group = lib.mkForce serviceGroup; + extraGroups = lib.mkIf cfg.enableNginx [ nginxGroup ]; + isSystemUser = true; + }; + }; + + sops = { + secrets = { + "firefly-iii-app-key" = { inherit sopsFile; owner = serviceUser; group = if cfg.enableNginx then nginxGroup else serviceGroup; mode = "0440"; }; + }; + }; + + topology.self.services.${serviceName} = { + name = "Firefly-III"; + info = "https://${serviceDomain}"; + icon = "${self}/files/topology-images/${serviceName}.png"; + }; + + globals.services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6; + }; + + services = { + ${serviceName} = { + enable = true; + user = serviceUser; + group = if cfg.enableNginx then nginxGroup else serviceGroup; + dataDir = "/Vault/data/${serviceName}"; + settings = { + TZ = config.repo.secrets.common.location.timezone; + APP_URL = "https://${serviceDomain}"; + APP_KEY_FILE = config.sops.secrets.firefly-iii-app-key.path; + APP_ENV = "local"; + DB_CONNECTION = "sqlite"; + TRUSTED_PROXIES = "**"; + # turning these on breaks api access using the waterfly app + # AUTHENTICATION_GUARD = "remote_user_guard"; + # AUTHENTICATION_GUARD_HEADER = "X-User"; + # AUTHENTICATION_GUARD_EMAIL = "X-Email"; + }; + enableNginx = true; + virtualHost = serviceDomain; + }; + + nginx = { + virtualHosts = { + "${serviceDomain}" = { + locations = { + "/api" = { + setOauth2Headers = false; + extraConfig = '' + index index.php; + try_files $uri $uri/ /index.php?$query_string; + add_header Access-Control-Allow-Methods 'GET, POST, HEAD, OPTIONS'; + ''; + }; + }; + }; + }; + }; + }; + + nodes.${serviceProxy}.services.nginx = { + upstreams = { + ${serviceName} = { + servers = { + "${serviceAddress}:${builtins.toString servicePort}" = { }; + }; + }; + }; + virtualHosts = { + "${serviceDomain}" = { + enableACME = true; + forceSSL = true; + acmeRoot = null; + oauth2.enable = true; + oauth2.allowedGroups = [ "firefly_access" ]; + # main config is automatically added by nixos firefly config. + # hence, only provide certificate + locations = { + "/" = { + proxyPass = "http://${serviceName}"; + }; + "/api" = { + proxyPass = "http://${serviceName}"; + setOauth2Headers = false; + bypassAuth = true; + }; + }; + }; + }; + }; + }; + } +#+end_src + +**** Koillection +:PROPERTIES: +:CUSTOM_ID: h:09c0fed3-b9c6-487f-a5f6-49be039e5fa2 +:END: + +#+begin_src nix-ts :tangle modules/nixos/server/koillection.nix + { self, lib, config, globals, dns, confLib, ... }: + let + inherit (confLib.gen { name = "koillection"; port = 2282; dir = "/Vault/data/koillection"; }) servicePort serviceName serviceUser serviceDir serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6; + serviceDB = "koillection"; + + postgresUser = config.systemd.services.postgresql.serviceConfig.User; # postgres + postgresPort = config.services.postgresql.settings.port; # 5432 + containerRev = "sha256:96693e41a6eb2aae44f96033a090378270f024ddf4e6095edf8d57674f21095d"; + + inherit (config.swarselsystems) sopsFile; + in + { + options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselmodules.server.${serviceName} { + + + nodes.stoicclub.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + sops.secrets = { + koillection-db-password = { inherit sopsFile; owner = postgresUser; group = postgresUser; mode = "0440"; }; + koillection-env-file = { inherit sopsFile; }; + }; + + topology.self.services.${serviceName} = { + name = lib.swarselsystems.toCapitalized serviceName; + info = "https://${serviceDomain}"; + icon = "${self}/files/topology-images/${serviceName}.png"; + }; + + globals.services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6; + }; + + virtualisation.oci-containers.containers = { + koillection = { + image = "koillection/koillection@${containerRev}"; + + ports = [ + "${toString servicePort}:80" + ]; + + volumes = [ + "${serviceDir}/uploads:/uploads" + ]; + + environment = { + APP_DEBUG = "0"; + APP_ENV = "prod"; + HTTPS_ENABLED = "1"; + UPLOAD_MAX_FILESIZE = "512M"; + PHP_MEMORY_LIMIT = "512M"; + PHP_TZ = config.repo.secrets.common.location.timezone; + + CORS_ALLOW_ORIGIN = "https?://(localhost|swag\\.swarsel\\.win)(:[0-9]+)?$"; + + DB_DRIVER = "pdo_pgsql"; + DB_NAME = serviceDB; + DB_HOST = "host.docker.internal"; + DB_USER = serviceUser; + # DB_PASSWORD set in koillection-env-file + DB_PORT = "${toString postgresPort}"; + DB_VERSION = "16"; + }; + + environmentFiles = [ + config.sops.secrets.koillection-env-file.path + ]; + + extraOptions = [ + "--add-host=host.docker.internal:host-gateway" # podman + ]; + }; + }; + + networking.firewall.allowedTCPPorts = [ servicePort postgresPort ]; + + systemd.services.postgresql.postStart = + let + passwordPath = config.sops.secrets.koillection-db-password.path; + in + '' + ${config.services.postgresql.package}/bin/psql -tA <<'EOF' + DO $$ + DECLARE password TEXT; + BEGIN + password := trim(both from replace(pg_read_file('${passwordPath}'), E'\n', ''')); + EXECUTE format('ALTER ROLE ${serviceDB} WITH PASSWORD '''%s''';', password); + END $$; + EOF + ''; + services = { + postgresql = { + enable = true; + enableTCPIP = true; + ensureDatabases = [ serviceDB ]; + ensureUsers = [ + { + name = serviceDB; + ensureDBOwnership = true; + } + ]; + authentication = '' + host ${serviceDB} ${serviceDB} 10.88.0.0/16 scram-sha-256 + ''; + }; + }; + + nodes.${serviceProxy}.services.nginx = { + upstreams = { + ${serviceName} = { + servers = { + "${serviceAddress}:${builtins.toString servicePort}" = { }; + }; + }; + }; + virtualHosts = { + "${serviceDomain}" = { + enableACME = true; + forceSSL = true; + acmeRoot = null; + locations = { + "/" = { + proxyPass = "http://${serviceName}"; + extraConfig = '' + proxy_buffer_size 128k; + proxy_buffers 4 256k; + proxy_busy_buffers_size 256k; + ''; + }; + }; + }; + }; + }; + }; + } +#+end_src + +**** Atuin +:PROPERTIES: +:CUSTOM_ID: h:27eac8b9-c202-4e45-9b80-42592f1e41c8 +:END: + +#+begin_src nix-ts :tangle modules/nixos/server/atuin.nix + { lib, config, globals, dns, confLib, ... }: + let + inherit (confLib.gen { name = "atuin"; port = 8888; }) servicePort serviceName serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6; + in + { + options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselmodules.server.${serviceName} { + + nodes.stoicclub.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + + topology.self.services.${serviceName}.info = "https://${serviceDomain}"; + + globals.services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6; + }; + + services.${serviceName} = { + enable = true; + host = "0.0.0.0"; + port = servicePort; + openFirewall = true; + openRegistration = false; + }; + + nodes.${serviceProxy}.services.nginx = { + upstreams = { + ${serviceName} = { + servers = { + "${serviceAddress}:${builtins.toString servicePort}" = { }; + }; + }; + }; + virtualHosts = { + "${serviceDomain}" = { + enableACME = true; + forceSSL = true; + acmeRoot = null; + locations = { + "/" = { + proxyPass = "http://${serviceName}"; + extraConfig = '' + client_max_body_size 0; + ''; + }; + }; + }; + }; + }; + + }; + + } +#+end_src + +**** Radicale +:PROPERTIES: +:CUSTOM_ID: h:c1ca2d28-51d2-45bd-83b5-05007ae94ae6 +:END: + +#+begin_src nix-ts :tangle modules/nixos/server/radicale.nix + { self, lib, config, globals, dns, confLib, ... }: + let + inherit (confLib.gen { name = "radicale"; port = 8000; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6; + sopsFile = self + /secrets/winters/secrets2.yaml; + + cfg = config.services.${serviceName}; + in + { + options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselmodules.server.${serviceName} { + + nodes.stoicclub.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + + sops = { + secrets.radicale-user = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + + templates = + let + inherit (config.repo.secrets.local.radicale) user1; + in + { + "radicale-users" = { + content = '' + ${user1}:${config.sops.placeholder.radicale-user} + ''; + owner = serviceUser; + group = serviceGroup; + mode = "0440"; + }; + }; + }; + + topology.self.services.${serviceName}.info = "https://${serviceDomain}"; + + globals.services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6; + }; + + services.${serviceName} = { + enable = true; + settings = { + server = { + hosts = [ + "0.0.0.0:${builtins.toString servicePort}" + "[::]:${builtins.toString servicePort}" + ]; + }; + auth = + { + type = "htpasswd"; + htpasswd_filename = config.sops.templates.radicale-users.path; + htpasswd_encryption = "autodetect"; + }; + storage = { + filesystem_folder = "/Vault/data/radicale/collections"; + }; + }; + rights = { + # all: match authenticated users only + root = { + user = ".+"; + collection = ""; + permissions = "R"; + }; + principal = { + user = ".+"; + collection = "{user}"; + permissions = "RW"; + }; + calendars = { + user = ".+"; + collection = "{user}/[^/]+"; + permissions = "rw"; + }; + }; + }; + + systemd.tmpfiles.settings."10-radicale" = { + "${cfg.settings.storage.filesystem_folder}" = { + d = { + group = serviceGroup; + user = serviceUser; + mode = "0750"; + }; + }; + }; + + networking.firewall.allowedTCPPorts = [ servicePort ]; + + nodes.${serviceProxy}.services.nginx = { + upstreams = { + ${serviceName} = { + servers = { + "${serviceAddress}:${builtins.toString servicePort}" = { }; + }; + }; + }; + virtualHosts = { + "${serviceDomain}" = { + enableACME = true; + forceSSL = true; + acmeRoot = null; + oauth2.enable = false; + locations = { + "/" = { + proxyPass = "http://${serviceName}"; + extraConfig = '' + client_max_body_size 16M; + ''; + }; + }; + }; + }; + }; + + }; + + } +#+end_src + +**** croc +:PROPERTIES: +:CUSTOM_ID: h:f922e8d6-f6e8-4779-a7ad-4037229c9bf0 +:END: + +#+begin_src nix-ts :tangle modules/nixos/server/croc.nix + { self, lib, config, pkgs, dns, globals, confLib, ... }: + let + inherit (confLib.gen { name = "croc"; }) serviceName serviceDomain proxyAddress4 proxyAddress6; + servicePorts = [ + 9009 + 9010 + 9011 + 9012 + 9013 + ]; + + inherit (config.swarselsystems) sopsFile; + + cfg = config.services.croc; + in + { + options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselmodules.server.${serviceName} { + + nodes.stoicclub.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + + sops = { + secrets = { + croc-password = { inherit sopsFile; }; + }; + + templates = { + "croc-env" = { + content = '' + CROC_PASS="${config.sops.placeholder.croc-password}" + ''; + }; + }; + }; + + + topology.self.services.${serviceName} = { + name = lib.swarselsystems.toCapitalized serviceName; + info = "https://${serviceDomain}"; + icon = "${self}/files/topology-images/${serviceName}.png"; + }; + + globals.services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6; + }; + + services.${serviceName} = { + enable = true; + ports = servicePorts; + pass = config.sops.secrets.croc-password.path; + openFirewall = true; + }; + + + systemd.services = { + ${serviceName} = { + serviceConfig = { + ExecStart = lib.mkForce "${pkgs.croc}/bin/croc ${lib.optionalString cfg.debug "--debug"} relay --ports ${ + lib.concatMapStringsSep "," toString cfg.ports}"; + EnvironmentFile = [ + config.sops.templates.croc-env.path + ]; + }; + }; + }; + + # ports are opened on the firewall for croc, no nginx config + + }; + + } +#+end_src + +**** microbin +:PROPERTIES: +:CUSTOM_ID: h:13071cc3-5cba-44b5-8b5b-2a27be22e021 +:END: + +#+begin_src nix-ts :tangle modules/nixos/server/microbin.nix + { self, lib, config, dns, globals, confLib, ... }: + let + inherit (confLib.gen { name = "microbin"; port = 8777; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6; + + inherit (config.swarselsystems) sopsFile; + + cfg = config.services.${serviceName}; + in + { + options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselmodules.server.${serviceName} { + + nodes.stoicclub.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + + users = { + groups.${serviceGroup} = { }; + + users.${serviceUser} = { + isSystemUser = true; + group = serviceGroup; + }; + }; + + sops = { + secrets = { + microbin-admin-username = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + microbin-admin-password = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + microbin-uploader-password = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + }; + + templates = { + "microbin-env" = { + content = '' + MICROBIN_ADMIN_USERNAME="${config.sops.placeholder.microbin-admin-username}" + MICROBIN_ADMIN_PASSWORD="${config.sops.placeholder.microbin-admin-password}" + MICROBIN_UPLOADER_PASSWORD="${config.sops.placeholder.microbin-uploader-password}" + ''; + owner = serviceUser; + group = serviceGroup; + mode = "0440"; + }; + }; + }; + + topology.self.services.${serviceName} = { + name = lib.swarselsystems.toCapitalized serviceName; + info = "https://${serviceDomain}"; + icon = "${self}/files/topology-images/${serviceName}.png"; + }; + + globals.services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6; + }; + + services.${serviceName} = { + enable = true; + passwordFile = config.sops.templates.microbin-env.path; + dataDir = "/var/lib/microbin"; + settings = { + MICROBIN_HIDE_LOGO = true; + MICROBIN_PORT = servicePort; + MICROBIN_EDITABLE = true; + MICROBIN_HIDE_HEADER = true; + MICROBIN_HIDE_FOOTER = true; + MICROBIN_NO_LISTING = false; + MICROBIN_HIGHLIGHTSYNTAX = true; + MICROBIN_BIND = "0.0.0.0"; + MICROBIN_PRIVATE = true; + MICROBIN_PUBLIC_PATH = "https://${serviceDomain}"; + MICROBIN_READONLY = true; + MICROBIN_SHOW_READ_STATS = true; + MICROBIN_TITLE = "~SwarselScratch~"; + MICROBIN_THREADS = 1; + MICROBIN_GC_DAYS = 30; + MICROBIN_ENABLE_BURN_AFTER = true; + MICROBIN_QR = true; + MICROBIN_ETERNAL_PASTA = true; + MICROBIN_ENABLE_READONLY = true; + MICROBIN_DEFAULT_EXPIRY = "1week"; + MICROBIN_NO_FILE_UPLOAD = false; + MICROBIN_MAX_FILE_SIZE_ENCRYPTED_MB = 256; + MICROBIN_MAX_FILE_SIZE_UNENCRYPTED_MB = 1024; + MICROBIN_DISABLE_UPDATE_CHECKING = true; + MICROBIN_DISABLE_TELEMETRY = true; + MICROBIN_LIST_SERVER = false; + }; + }; + + systemd.services = { + ${serviceName} = { + serviceConfig = { + DynamicUser = lib.mkForce false; + User = serviceUser; + Group = serviceGroup; + }; + }; + }; + + networking.firewall.allowedTCPPorts = [ servicePort ]; + + environment.persistence."/persist".directories = lib.mkIf config.swarselsystems.isImpermanence [ + { directory = cfg.dataDir; user = serviceUser; group = serviceGroup; mode = "0700"; } + ]; + + nodes.${serviceProxy}.services.nginx = { + upstreams = { + ${serviceName} = { + servers = { + "${serviceAddress}:${builtins.toString servicePort}" = { }; + }; + }; + }; + virtualHosts = { + "${serviceDomain}" = { + enableACME = true; + forceSSL = true; + acmeRoot = null; + locations = { + "/" = { + proxyPass = "http://${serviceName}"; + extraConfig = '' + client_max_body_size 1G; + ''; + }; + }; + }; + }; + }; + + }; + + } +#+end_src + +**** shlink +:PROPERTIES: +:CUSTOM_ID: h:4ccdcd5c-a4dd-49e4-94e7-d81db970059c +:END: + + + +#+begin_src nix-ts :tangle modules/nixos/server/shlink.nix + { self, lib, config, dns, globals, confLib, ... }: + let + inherit (confLib.gen { name = "shlink"; port = 8081; dir = "/var/lib/shlink";}) servicePort serviceName serviceDomain serviceDir serviceAddress serviceProxy proxyAddress4 proxyAddress6; + + containerRev = "sha256:1a697baca56ab8821783e0ce53eb4fb22e51bb66749ec50581adc0cb6d031d7a"; + + inherit (config.swarselsystems) sopsFile; + in + { + options = { + swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; + }; + config = lib.mkIf config.swarselmodules.server.${serviceName} { + + nodes.stoicclub.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + + sops = { + secrets = { + shlink-api = { inherit sopsFile; }; + }; + + templates = { + "shlink-env" = { + content = '' + INITIAL_API_KEY=${config.sops.placeholder.shlink-api} + ''; + }; + }; + }; + + virtualisation.oci-containers.containers.${serviceName} = { + image = "shlinkio/shlink@${containerRev}"; + environment = { + "DEFAULT_DOMAIN" = serviceDomain; + "PORT" = "${builtins.toString servicePort}"; + "USE_HTTPS" = "false"; + "DEFAULT_SHORT_CODES_LENGTH" = "4"; + "WEB_WORKER_NUM" = "1"; + "TASK_WORKER_NUM" = "1"; + }; + environmentFiles = [ + config.sops.templates.shlink-env.path + ]; + ports = [ "${builtins.toString servicePort}:${builtins.toString servicePort}" ]; + volumes = [ + "${serviceDir}/data:/etc/shlink/data" + ]; + }; + + systemd.tmpfiles.settings."11-shlink" = builtins.listToAttrs ( + map + (path: { + name = "${serviceDir}/${path}"; + value = { + d = { + group = "root"; + user = "1001"; + mode = "0750"; + }; + }; + }) [ + "data" + "data/cache" + "data/locks" + "data/log" + "data/proxies" + ] + ); + + networking.firewall.allowedTCPPorts = [ servicePort ]; + + environment.persistence."/persist".directories = lib.mkIf config.swarselsystems.isImpermanence [ + { directory = serviceDir; } + { directory = "/var/lib/containers"; } + ]; + + topology.self.services.${serviceName} = { + name = lib.swarselsystems.toCapitalized serviceName; + info = "https://${serviceDomain}"; + icon = "${self}/files/topology-images/${serviceName}.png"; + }; + + globals.services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6; + }; + + nodes.${serviceProxy}.services.nginx = { + upstreams = { + ${serviceName} = { + servers = { + "${serviceAddress}:${builtins.toString servicePort}" = { }; + }; + }; + }; + virtualHosts = { + "${serviceDomain}" = { + enableACME = true; + forceSSL = true; + acmeRoot = null; + locations = { + "/" = { + proxyPass = "http://${serviceName}"; + }; + }; + }; + }; + }; + }; + } +#+end_src + +**** slink +:PROPERTIES: +:CUSTOM_ID: h:e46c37ac-5610-4603-8afc-2f5f008fc14d +:END: + +Deployment notes: + - enable user: =podman exec -it slink slink user:activate --email== + - make user admin: =podman exec -it slink slink user:grant:role --email= ROLE_ADMIN= + - finally, disable new user registration in web ui + +#+begin_src nix-ts :tangle modules/nixos/server/slink.nix + { self, lib, config, dns, globals, confLib, ... }: + let + inherit (confLib.gen { name = "slink"; port = 3000; dir = "/var/lib/slink";}) servicePort serviceName serviceDomain serviceDir serviceAddress serviceProxy proxyAddress4 proxyAddress6; + + containerRev = "sha256:98b9442696f0a8cbc92f0447f54fa4bad227af5dcfd6680545fedab2ed28ddd9"; + in + { + options = { + swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; + }; + config = lib.mkIf config.swarselmodules.server.${serviceName} { + + nodes.stoicclub.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + + virtualisation.oci-containers.containers.${serviceName} = { + image = "anirdev/slink@${containerRev}"; + environment = { + "ORIGIN" = "https://${serviceDomain}"; + "TZ" = config.repo.secrets.common.location.timezone; + "STORAGE_PROVIDER" = "local"; + "IMAGE_MAX_SIZE" = "50M"; + "USER_APPROVAL_REQUIRED" = "true"; + }; + ports = [ "${builtins.toString servicePort}:${builtins.toString servicePort}" ]; + volumes = [ + "${serviceDir}/var/data:/app/var/data" + "${serviceDir}/images:/app/slink/images" + ]; + }; + + systemd.tmpfiles.settings."12-slink" = builtins.listToAttrs ( + map + (path: { + name = "${serviceDir}/${path}"; + value = { + d = { + group = "root"; + user = "root"; + mode = "0750"; + }; + }; + }) [ + "var/data" + "images" + ] + ); + + networking.firewall.allowedTCPPorts = [ servicePort ]; + + environment.persistence."/persist".directories = lib.mkIf config.swarselsystems.isImpermanence [ + { directory = serviceDir; } + ]; + + topology.self.services.${serviceName} = { + name = lib.swarselsystems.toCapitalized serviceName; + info = "https://${serviceDomain}"; + icon = "${self}/files/topology-images/shlink.png"; + }; + + globals.services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6; + }; + + nodes.${serviceProxy}.services.nginx = { + upstreams = { + ${serviceName} = { + servers = { + "${serviceAddress}:${builtins.toString servicePort}" = { }; + }; + }; + }; + virtualHosts = { + "${serviceDomain}" = { + enableACME = true; + forceSSL = true; + acmeRoot = null; + oauth2.enable = true; + oauth2.allowedGroups = [ "slink_access" ]; + locations = { + "/" = { + proxyPass = "http://${serviceName}"; + }; + "/image" = { + proxyPass = "http://${serviceName}"; + setOauth2Headers = false; + bypassAuth = true; + }; + }; + }; + }; + }; + }; + } +#+end_src + +**** Snipe-IT +:PROPERTIES: +:CUSTOM_ID: h:470f7ee3-3307-4949-b0fa-403171e3859a +:END: + +#+begin_src nix-ts :tangle modules/nixos/server/snipe-it.nix + { self, lib, config, globals, dns, confLib, ... }: + let + inherit (confLib.gen { name = "snipeit"; port = 80; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6; + sopsFile = self + /secrets/winters/secrets2.yaml; + + serviceDB = "snipeit"; + + mysqlPort = 3306; + in + { + options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselmodules.server.${serviceName} { + + nodes.stoicclub.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + + sops = { + secrets = { + snipe-it-appkey = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; + }; + }; + + topology.self.services.${serviceName}.info = "https://${serviceDomain}"; + + globals.services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6; + }; + + services.snipe-it = { + enable = true; + appKeyFile = config.sops.secrets.snipe-it-appkey.path; + appURL = "https://${serviceDomain}"; + hostName = serviceDomain; + user = serviceUser; + group = serviceGroup; + dataDir = "/Vault/data/snipeit"; + database = { + user = serviceUser; + port = mysqlPort; + name = serviceDB; + host = "localhost"; + createLocally = true; + }; + }; + + nodes.${serviceProxy}.services.nginx = { + upstreams = { + ${serviceName} = { + servers = { + "${serviceAddress}:${builtins.toString servicePort}" = { }; + }; + }; + }; + virtualHosts = { + "${serviceDomain}" = { + enableACME = true; + forceSSL = true; + acmeRoot = null; + oauth2.enable = false; + locations = { + "/" = { + proxyPass = "http://${serviceName}"; + }; + }; + }; + }; + }; + + }; + + } +#+end_src +**** Homebox +:PROPERTIES: +:CUSTOM_ID: h:5b4feb1b-e7a3-43f1-9930-8d00012742ad +:END: + +#+begin_src nix-ts :tangle modules/nixos/server/homebox.nix + { lib, pkgs, config, globals, dns, confLib, ... }: + let + inherit (confLib.gen { name = "homebox"; port = 7745; }) servicePort serviceName serviceDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6; + in + { + options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselmodules.server.${serviceName} { + + nodes.stoicclub.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + + topology.self.services.${serviceName}.info = "https://${serviceDomain}"; + + globals.services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6; + }; + + services.${serviceName} = { + enable = true; + package = pkgs.dev.homebox; + database.createLocally = true; + settings = { + HBOX_WEB_PORT = builtins.toString servicePort; + HBOX_OPTIONS_ALLOW_REGISTRATION = "false"; + HBOX_STORAGE_CONN_STRING = "file:///Vault/data/homebox"; + HBOX_STORAGE_PREFIX_PATH = ".data"; + }; + }; + + networking.firewall.allowedTCPPorts = [ servicePort ]; + + nodes.${serviceProxy}.services.nginx = { + upstreams = { + ${serviceName} = { + servers = { + "${serviceAddress}:${builtins.toString servicePort}" = { }; + }; + }; + }; + virtualHosts = { + "${serviceDomain}" = { + enableACME = true; + forceSSL = true; + acmeRoot = null; + oauth2.enable = false; + locations = { + "/" = { + proxyPass = "http://${serviceName}"; + }; + }; + }; + }; + }; + + }; + + } +#+end_src +**** OPKSSH +:PROPERTIES: +:CUSTOM_ID: h:6e30509a-1320-4993-a9c7-70d28ef2906a +:END: + +#+begin_src nix-ts :tangle modules/nixos/server/opkssh.nix + { lib, config, globals, confLib, ... }: + let + inherit (confLib.gen { name = "opkssh"; user = "opksshuser"; group = "opksshuser"; }) serviceName serviceUser serviceGroup; + + kanidmDomain = globals.services.kanidm.domain; + + inherit (config.swarselsystems) mainUser; + inherit (config.repo.secrets.local) persons; + in + { + options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselmodules.server.${serviceName} { + + services.${serviceName} = { + enable = true; + user = serviceUser; + group = serviceGroup; + providers = { + kanidm = { + lifetime = "oidc"; + issuer = "https://${kanidmDomain}/oauth2/openid/${serviceName}"; + clientId = serviceName; + }; + }; + authorizations = [ + { + user = mainUser; + principal = builtins.head persons.${mainUser}.mailAddresses; + inherit (config.services.opkssh.providers.kanidm) issuer; + } + ]; + }; + + }; + + } +#+end_src +**** Garage +:PROPERTIES: +:CUSTOM_ID: h:81c76be4-45f1-44e5-890d-6d082a95ab51 +:END: + +Garage acts as my s3 endpoint. I use it on two of my servers: + - [[#h:932ef6b0-4c14-4200-8e3f-2e208e748746][Winters (Server: ASRock J4105-ITX)]]: General s3 storage + - [[#h:90457194-6b97-4cd6-90bc-4f42d0d69f51][Belchsfactory (OCI)]]: s3 storage for nix binary cache (used by [[#h:092593d2-0ca0-4f86-9951-6127a3594e25][Attic (nix binary cache)]]) + +Generate the admin token using =openssl rand -base64 32=. +Generate the rpc token using =openssl rand -hex 32=. + +If a website is to be deployed using a s3 bucket, add the corresponding files in one of two ways: + +either 1) use vhost addressing: =aws s3 cp s3:// --endpoint-url https://. --region swarsel= + +or 2) use classic path addressing =aws s3 cp s3:/// --endpoint-url https:// --region swarsel= + +#+begin_src nix-ts :tangle modules/nixos/server/garage.nix + # inspired by https://github.com/atropos112/nixos/blob/7fef652006a1c939f4caf9c8a0cb0892d9cdfe21/modules/garage.nix + { lib, pkgs, config, globals, dns, confLib, ... }: + let + inherit (confLib.gen { + name = "garage"; + port = 3900; + domain = config.repo.secrets.common.services.domains."garage-${config.node.name}"; + }) servicePort serviceName specificServiceName serviceDomain subDomain baseDomain serviceAddress serviceProxy proxyAddress4 proxyAddress6; + + cfg = lib.recursiveUpdate config.services.${serviceName} config.swarselsystems.server.${serviceName}; + inherit (config.swarselsystems) sopsFile mainUser; + + # needs SSD + metadata_dir = "/var/lib/garage/meta"; + # metadata_dir = if config.swarselsystems.isCloud then "/var/lib/garage/meta" else "/Vault/data/garage/meta"; + + garageRpcPort = 3901; + garageWebPort = 3902; + garageAdminPort = 3903; + garageK2VPort = 3904; + + adminDomain = "${subDomain}admin.${baseDomain}"; + webDomain = "${subDomain}web.${baseDomain}"; + in + { + options = { + swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; + swarselsystems.server.${serviceName} = { + data_dir = { + path = lib.mkOption { + type = lib.types.str; + description = "Directory where Garage stores its metadata"; + }; + capacity = lib.mkOption { + type = lib.types.str; + }; + }; + buckets = lib.mkOption { + type = lib.types.listOf lib.types.str; + description = "List of buckets to create"; + }; + keys = lib.mkOption { + type = lib.types.attrsOf (lib.types.listOf lib.types.str); + default = { }; + description = "Keys and their associated buckets. Each key gets full access (read/write/owner) to its listed buckets."; + example = { + my_key_name = [ "bucket1" "bucket2" ]; + my_other_key = [ "bucket2" "bucket3" ]; + }; + }; + }; + }; + config = lib.mkIf config.swarselmodules.server.${serviceName} { + assertions = [ + { + assertion = config.swarselsystems.server.${serviceName}.buckets != [ ]; + message = "If Garage is enabled, at least one bucket must be specified in swarselsystems.server.${serviceName}.buckets"; + } + { + assertion = builtins.length (lib.attrsToList config.swarselsystems.server.${serviceName}.keys) > 0; + message = "If Garage is enabled, at least one key must be specified in swarselsystems.server.${serviceName}.keys"; + } + { + assertion = + let + allKeyBuckets = lib.flatten (lib.attrValues config.swarselsystems.server.${serviceName}.keys); + invalidBuckets = builtins.filter (bucket: !(lib.elem bucket config.swarselsystems.server.${serviceName}.buckets)) allKeyBuckets; + in + invalidBuckets == [ ]; + message = "All buckets referenced in keys must exist in the buckets list"; + } + ]; + + nodes.stoicclub.swarselsystems.server.dns.${baseDomain}.subdomainRecords = { + "${subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + "${subDomain}admin" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + "${subDomain}web" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + "*.${subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + "*.${subDomain}web" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + + sops = { + secrets.garage-admin-token = { inherit sopsFile; }; + secrets.garage-rpc-secret = { inherit sopsFile; }; + }; + + # DynamicUser cannot read above secrets + systemd.services.${serviceName}.serviceConfig = { + DynamicUser = false; + ProtectHome = lib.mkForce false; + }; + + environment = { + persistence."/persist".directories = lib.mkIf config.swarselsystems.isImpermanence [ + { directory = "/var/lib/garage"; } + (lib.mkIf config.swarselsystems.isCloud { directory = config.swarselsystems.server.${serviceName}.data_dir.path; }) + ]; + systemPackages = [ + cfg.package + ]; + }; + + globals.services.${specificServiceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6; + }; + + + services.${serviceName} = { + enable = true; + package = pkgs.garage_2; + settings = { + data_dir = [ config.swarselsystems.server.${serviceName}.data_dir ]; + inherit metadata_dir; + db_engine = "lmdb"; + block_size = "128M"; + use_local_tz = false; + disable_scrub = true; + replication_factor = 1; + compression_level = "none"; + + rpc_bind_addr = "[::]:${builtins.toString garageRpcPort}"; + # we are not joining our nodes, just use the private ipv4 + rpc_public_addr = "${globals.networks.${config.swarselsystems.server.netConfigName}.hosts.${config.node.name}.ipv4}:${builtins.toString garageRpcPort}"; + + rpc_secret_file = config.sops.secrets.garage-rpc-secret.path; + + s3_api = { + s3_region = mainUser; + api_bind_addr = "[::]:${builtins.toString servicePort}"; + root_domain = ".${serviceDomain}"; + }; + + s3_web = { + bind_addr = "[::]:${builtins.toString garageWebPort}"; + root_domain = ".${config.repo.secrets.common.services.domains."garage-web-${config.node.name}"}"; + add_host_to_metrics = true; + }; + + admin = { + api_bind_addr = "[::]:${builtins.toString garageAdminPort}"; + admin_token_file = config.sops.secrets.garage-admin-token.path; + }; + + k2v_api = { + api_bind_addr = "[::]:${builtins.toString garageK2VPort}"; + }; + }; + }; + + + systemd.services = { + garage-buckets = { + description = "Create Garage buckets"; + after = [ "garage.service" ]; + wants = [ "garage.service" ]; + wantedBy = [ "multi-user.target" ]; + + path = [ cfg.package pkgs.gawk pkgs.coreutils ]; + + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + User = "root"; + Group = "root"; + }; + + script = '' + garage status + + # Checking repeatedly with garage status until getting 0 exit code + while ! garage status >/dev/null 2>&1; do + echo "Garage not yet operational, waiting..." + echo "Current garage status output:" + garage status 2>&1 || true + echo "---" + sleep 5 + done + + # Now we check if garage status shows any failed nodes by checking for ==== FAILED NODES ==== + while garage status | grep -q "==== FAILED NODES ===="; do + echo "Garage has failed nodes, waiting..." + echo "Current garage status output:" + garage status 2>&1 || true + echo "---" + sleep 5 + done + + echo "Garage is operational, proceeding with bucket management." + + # Get list of existing buckets + existing_buckets=$(garage bucket list | tail -n +2 | awk '{print $3}' | grep -v '^$' || true) + + # Create buckets that should exist + ${lib.concatMapStringsSep "\n" (bucket: '' + if [[ "$(garage bucket info ${lib.escapeShellArg bucket} 2>&1 >/dev/null)" == *"Bucket not found"* ]]; then + echo "Creating bucket ${lib.escapeShellArg bucket}" + garage bucket create ${lib.escapeShellArg bucket} + else + echo "Bucket ${lib.escapeShellArg bucket} already exists" + fi + '') + cfg.buckets} + + # Remove buckets that shouldn't exist + for bucket in $existing_buckets; do + should_exist=false + ${lib.concatMapStringsSep "\n" (bucket: '' + if [[ "$bucket" == ${lib.escapeShellArg bucket} ]]; then + should_exist=true + fi + '') + cfg.buckets} + + if [[ "$should_exist" == "false" ]]; then + echo "Removing bucket $bucket" + garage bucket delete --yes "$bucket" + fi + done + ''; + }; + + garage-keys = { + description = "Create Garage keys and set permissions"; + after = [ "garage-buckets.service" ]; + wants = [ "garage-buckets.service" ]; + requires = [ "garage-buckets.service" ]; + wantedBy = [ "multi-user.target" ]; + + path = [ cfg.package pkgs.gawk pkgs.coreutils ]; + + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + User = "root"; + Group = "root"; + }; + + script = '' + garage key list + echo "Managing keys..." + + # Get list of existing keys + existing_keys=$(garage key list | tail -n +2 | awk '{print $3}' | grep -v '^$' || true) + + # Create keys that should exist + ${lib.concatStringsSep "\n" (lib.mapAttrsToList (keyName: _: '' + if [[ "$(garage key info ${lib.escapeShellArg keyName} 2>&1)" == *"0 matching keys"* ]]; then + echo "Creating key ${lib.escapeShellArg keyName}" + garage key create ${lib.escapeShellArg keyName} + else + echo "Key ${lib.escapeShellArg keyName} already exists" + fi + '') + cfg.keys)} + + # Set up key permissions for buckets + ${lib.concatStringsSep "\n" (lib.mapAttrsToList ( + keyName: buckets: + lib.concatMapStringsSep "\n" (bucket: '' + echo "Granting full access to key ${lib.escapeShellArg keyName} for bucket ${lib.escapeShellArg bucket}" + garage bucket allow --read --write --owner --key ${lib.escapeShellArg keyName} ${lib.escapeShellArg bucket} + '') + buckets + ) + cfg.keys)} + + # Remove permissions from buckets that are no longer associated with keys + ${lib.concatStringsSep "\n" (lib.mapAttrsToList (keyName: buckets: '' + # Get current buckets this key has access to + current_buckets=$(garage key info ${lib.escapeShellArg keyName} | grep -A 1000 "==== BUCKETS FOR THIS KEY ====" | tail -n +3 | awk '{print $3}' | grep -v '^$' || true) + + # Remove access from buckets not in the desired list + for current_bucket in $current_buckets; do + should_have_access=false + ${lib.concatMapStringsSep "\n" (bucket: '' + if [[ "$current_bucket" == ${lib.escapeShellArg bucket} ]]; then + should_have_access=true + fi + '') + buckets} + + if [[ "$should_have_access" == "false" ]]; then + echo "Removing access for key ${lib.escapeShellArg keyName} from bucket $current_bucket" + garage bucket deny --key ${lib.escapeShellArg keyName} $current_bucket + fi + done + '') + cfg.keys)} + + # Remove keys that shouldn't exist + for key in $existing_keys; do + should_exist=false + ${lib.concatStringsSep "\n" (lib.mapAttrsToList (keyName: _: '' + if [[ "$key" == ${lib.escapeShellArg keyName} ]]; then + should_exist=true + fi + '') + cfg.keys)} + + if [[ "$should_exist" == "false" ]]; then + echo "Removing key $key" + garage key delete --yes "$key" + fi + done + ''; + }; + }; + + security.acme.certs."${webDomain}" = { + domain = "*.${webDomain}"; + }; + + nodes.${serviceProxy}.services.nginx = { + upstreams = { + ${serviceName} = { + servers = { + "${serviceAddress}:${builtins.toString servicePort}" = { }; + }; + }; + "${serviceName}Web" = { + servers = { + "${serviceAddress}:${builtins.toString garageWebPort}" = { }; + }; + }; + "${serviceName}Admin" = { + servers = { + "${serviceAddress}:${builtins.toString garageAdminPort}" = { }; + }; + }; + }; + virtualHosts = { + "${adminDomain}" = { + enableACME = true; + forceSSL = true; + acmeRoot = null; + oauth2.enable = false; + locations = { + "/" = { + proxyPass = "http://${serviceName}Admin"; + }; + }; + }; + "*.${webDomain}" = { + useACMEHost = webDomain; + forceSSL = true; + acmeRoot = null; + oauth2.enable = false; + locations = { + "/" = { + proxyPass = "http://${serviceName}Web"; + }; + }; + }; + "${serviceDomain}" = { + serverAliases = [ "*.${serviceDomain}" ]; + enableACME = true; + forceSSL = true; + acmeRoot = null; + oauth2.enable = false; + locations = { + "/" = { + proxyPass = "http://${serviceName}"; + extraConfig = '' + client_max_body_size 0; + ''; + }; + }; + }; + }; + }; + + }; + } +#+end_src +**** nsd (dns) +:PROPERTIES: +:CUSTOM_ID: h:ef5b7ace-4870-4dfa-9532-9a9d2722dc9a +:END: + +#+begin_src nix-ts :tangle modules/nixos/server/nsd/default.nix + { lib, config, globals, dns, confLib, ... }: + let + inherit (confLib.gen { name = "nsd"; port = 53; }) serviceName servicePort proxyAddress4 proxyAddress6; + inherit (config.swarselsystems) sopsFile; + in + { + options = { + swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; + swarselsystems.server.dns = lib.mkOption { + type = lib.types.attrsOf ( + lib.types.submodule { + options = { + subdomainRecords = lib.mkOption { + type = lib.types.attrsOf dns.lib.types.subzone; + default = { }; + }; + }; + } + ); + }; + }; + config = lib.mkIf config.swarselmodules.server.${serviceName} { + + sops.secrets = { + tsig-key = { inherit sopsFile; }; + }; + + # services.resolved.enable = false; + networking = { + # nameservers = [ "1.1.1.1" "8.8.8.8" ]; + firewall = { + allowedUDPPorts = [ servicePort ]; + allowedTCPPorts = [ servicePort ]; + }; + }; + + services.nsd = { + enable = true; + keys = { + "${globals.domains.main}.${proxyAddress4}" = { + algorithm = "hmac-sha256"; + keyFile = config.sops.secrets.tsig-key.path; + }; + "${globals.domains.main}.${proxyAddress6}" = { + algorithm = "hmac-sha256"; + keyFile = config.sops.secrets.tsig-key.path; + }; + "${globals.domains.main}" = { + algorithm = "hmac-sha256"; + keyFile = config.sops.secrets.tsig-key.path; + }; + }; + interfaces = [ + "10.1.2.157" + "2603:c020:801f:a0cc::9d" + ]; + zones = { + "${globals.domains.main}" = + let + keyName4 = "${globals.domains.main}.${proxyAddress4}"; + keyName6 = "${globals.domains.main}.${proxyAddress6}"; + keyName = "${globals.domains.main}"; + transferList = [ + "213.239.242.238 ${keyName4}" + "2a01:4f8:0:a101::a:1 ${keyName6}" + "213.133.100.103 ${keyName4}" + "2a01:4f8:0:1::5ddc:2 ${keyName6}" + "193.47.99.3 ${keyName4}" + "2001:67c:192c::add:a3 ${keyName6}" + ]; + + in + { + outgoingInterface = "2603:c020:801f:a0cc::9d"; + notify = transferList ++ [ + "216.218.130.2 ${keyName}" + ]; + provideXFR = transferList ++ [ + "216.218.133.2 ${keyName}" + "2001:470:600::2 ${keyName}" + ]; + + # dnssec = true; + data = dns.lib.toString "${globals.domains.main}" (import ./site1.nix { inherit config globals dns proxyAddress4 proxyAddress6; }); + }; + }; + }; + + }; + } +#+end_src +**** nsd (dns) - site1 +:PROPERTIES: +:CUSTOM_ID: h:dc1dbc54-46f7-406d-a551-527e97439614 +:END: + +#+begin_src nix-ts :tangle modules/nixos/server/nsd/site1.nix + { config, globals, dns, proxyAddress4, proxyAddress6, ... }: + with dns.lib.combinators; { + SOA = { + nameServer = "soa"; + adminEmail = "admin@${globals.domains.main}"; # this option is not parsed as domain (we cannot just write "admin") + serial = 2025120201; # update this on changes for secondary dns + }; + + useOrigin = false; + + NS = [ + "soa" + "srv" + ] ++ globals.domains.externalDns; + + + A = [ config.repo.secrets.local.dns.homepage-ip ]; + + SRV = [ + { + service = "_matrix"; + proto = "_tcp"; + port = 443; + target = "${globals.services.matrix.subDomain}"; + priority = 10; + weight = 5; + } + { + service = "_submissions"; + proto = "_tcp"; + port = 465; + target = "${globals.services.mailserver.subDomain}"; + priority = 5; + weight = 0; + ttl = 3600; + } + { + service = "_submission"; + proto = "_tcp"; + port = 587; + target = "${globals.services.mailserver.subDomain}"; + priority = 5; + weight = 0; + ttl = 3600; + } + { + service = "_imap"; + proto = "_tcp"; + port = 143; + target = "${globals.services.mailserver.subDomain}"; + priority = 5; + weight = 0; + ttl = 3600; + } + { + service = "_imaps"; + proto = "_tcp"; + port = 993; + target = "${globals.services.mailserver.subDomain}"; + priority = 5; + weight = 0; + ttl = 3600; + } + ]; + + MX = [ + { + preference = 10; + exchange = "${globals.services.mailserver.subDomain}"; + } + ]; + + DKIM = [ + { + selector = "mail"; + k = "rsa"; + p = config.repo.secrets.local.dns.mailserver.dkim-public; + ttl = 10800; + } + ]; + + TXT = [ + (with spf; strict [ "a:${globals.services.mailserver.subDomain}.${globals.domains.main}" ]) + "google-site-verification=${config.repo.secrets.local.dns.google-site-verification}" + ]; + + DMARC = [ + { + p = "none"; + ttl = 10800; + } + ]; + + subdomains = config.swarselsystems.server.dns.${globals.domains.main}.subdomainRecords // { + "www".CNAME = [ "${globals.domains.main}." ]; + "_acme-challenge".CNAME = [ "${config.repo.secrets.local.dns.acme-challenge-domain}." ]; + "soa" = host proxyAddress4 proxyAddress6; + "srv" = host proxyAddress4 proxyAddress6; + }; + } +#+end_src +**** Minecraft +:PROPERTIES: +:CUSTOM_ID: h:948d4f4e-b752-4e2e-b8a9-35d9d7f246c6 +:END: + +#+begin_src nix-ts :tangle modules/nixos/server/minecraft/default.nix + { lib, config, pkgs, globals, dns, confLib, ... }: + let + inherit (confLib.gen { name = "minecraft"; port = 25565; dir = "/opt/minecraft"; }) serviceName servicePort serviceDir serviceDomain proxyAddress4 proxyAddress6; + inherit (config.swarselsystems) mainUser; + worldName = "${mainUser}craft"; + in + { + options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; + config = lib.mkIf config.swarselmodules.server.${serviceName} { + + nodes.stoicclub.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + + topology.self.services.${serviceName}.info = "https://${serviceDomain}"; + + globals.services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6; + }; + + networking.firewall.allowedTCPPorts = [ servicePort ]; + + environment.persistence."/persist".directories = lib.mkIf config.swarselsystems.isImpermanence [ + { directory = serviceDir; mode = "0755"; } + ]; + + systemd.services.minecraft-swarselcraft = { + description = "Minecraft Server"; + wants = [ "network-online.target" ]; + after = [ "network-online.target" ]; + + serviceConfig = { + User = "root"; + WorkingDirectory = "${serviceDir}/${worldName}"; + + ExecStart = "${lib.getExe pkgs.temurin-jre-bin-17} @user_jvm_args.txt @libraries/net/minecraftforge/forge/1.20.1-47.2.20/unix_args.txt nogui"; + + Restart = "always"; + RestartSec = 30; + StandardInput = "null"; + }; + + wantedBy = [ "multi-user.target" ]; + }; + + + }; + + } +#+end_src +**** Mailserver +:PROPERTIES: +:CUSTOM_ID: h:64cbeb7e-0773-4eb5-8e52-6b97c8f685e2 +:END: + +#+begin_src nix-ts :tangle modules/nixos/server/mailserver.nix + { lib, config, globals, dns, confLib, ... }: + let + inherit (config.swarselsystems) sopsFile; + inherit (confLib.gen { name = "mailserver"; dir = "/var/lib/dovecot"; user = "virtualMail"; group = "virtualMail"; port = 443; }) serviceName serviceDir servicePort serviceUser serviceGroup serviceDomain serviceProxy proxyAddress4 proxyAddress6; + inherit (config.repo.secrets.local.mailserver) user1 alias1_1 alias1_2 alias1_3 alias1_4 user2 alias2_1 user3; + baseDomain = globals.domains.main; + in + { + options = { + swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; + }; + config = lib.mkIf config.swarselmodules.server.${serviceName} { + + nodes.stoicclub.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + + globals.services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6; + }; + + sops.secrets = { + user1-hashed-pw = { inherit sopsFile; owner = serviceUser; }; + user2-hashed-pw = { inherit sopsFile; owner = serviceUser; }; + user3-hashed-pw = { inherit sopsFile; owner = serviceUser; }; + }; + + environment.persistence."/persist".directories = lib.mkIf config.swarselsystems.isImpermanence [ + { directory = "/var/vmail"; user = serviceUser; group = serviceGroup; mode = "0770"; } + { directory = "/var/sieve"; user = serviceUser; group = serviceGroup; mode = "0770"; } + { directory = "/var/dkim"; user = "rspamd"; group = "rspamd"; mode = "0700"; } + { directory = serviceDir; user = serviceUser; group = serviceGroup; mode = "0700"; } + { directory = "/var/lib/postgresql"; user = "postgres"; group = "postgres"; mode = "0750"; } + { directory = "/var/lib/rspamd"; user = "rspamd"; group = "rspamd"; mode = "0700"; } + { directory = "/var/lib/roundcube"; user = "roundcube"; group = "roundcube"; mode = "0700"; } + { directory = "/var/lib/redis-rspamd"; user = "redis-rspamd"; group = "redis-rspamd"; mode = "0700"; } + { directory = "/var/lib/postfix"; user = "root"; group = "root"; mode = "0755"; } + { directory = "/var/lib/knot-resolver"; user = "knot-resolver"; group = "knot-resolver"; mode = "0770"; } + ]; + + mailserver = { + enable = true; + stateVersion = 3; + fqdn = serviceDomain; + domains = [ baseDomain ]; + indexDir = "${serviceDir}/indices"; + openFirewall = true; + certificateScheme = "acme"; + dmarcReporting.enable = true; + + loginAccounts = { + "${user1}@${baseDomain}" = { + hashedPasswordFile = config.sops.secrets.user1-hashed-pw.path; + aliases = [ + "${alias1_1}@${baseDomain}" + "${alias1_2}@${baseDomain}" + "${alias1_3}@${baseDomain}" + "${alias1_4}@${baseDomain}" + ]; + }; + "${user2}@${baseDomain}" = { + hashedPasswordFile = config.sops.secrets.user2-hashed-pw.path; + aliases = [ + "${alias2_1}@${baseDomain}" + ]; + sendOnly = true; + }; + "${user3}@${baseDomain}" = { + hashedPasswordFile = config.sops.secrets.user3-hashed-pw.path; + aliases = [ + "@${baseDomain}" + ]; + catchAll = [ + baseDomain + ]; + }; + }; + }; + + services.roundcube = { + enable = true; + # this is the url of the vhost, not necessarily the same as the fqdn of + # the mailserver + hostName = serviceDomain; + extraConfig = '' + $config['imap_host'] = "ssl://${config.mailserver.fqdn}"; + $config['smtp_host'] = "ssl://${config.mailserver.fqdn}"; + $config['smtp_user'] = "%u"; + $config['smtp_pass'] = "%p"; + ''; + configureNginx = true; + }; + + # the rest of the ports are managed by snm + networking.firewall.allowedTCPPorts = [ 80 servicePort ]; + + nodes.${serviceProxy}.services.nginx = { + virtualHosts = { + "${serviceDomain}" = { + enableACME = true; + forceSSL = true; + acmeRoot = null; + locations = { + "/".recommendedSecurityHeaders = false; + "~ ^/(SQL|bin|config|logs|temp|vendor)/".recommendedSecurityHeaders = false; + "~ ^/(CHANGELOG.md|INSTALL|LICENSE|README.md|SECURITY.md|UPGRADING|composer.json|composer.lock)".recommendedSecurityHeaders = false; + "~* \\.php(/|$)".recommendedSecurityHeaders = false; + }; + }; + }; + }; + + }; + } +#+end_src +**** Attic (nix binary cache) +:PROPERTIES: +:CUSTOM_ID: h:092593d2-0ca0-4f86-9951-6127a3594e25 +:END: + +Generate the attic server token using =openssl genrsa -traditional 4096 | base64 -w0= + +# Copy and paste from the atticd output +$ attic login local http://localhost:8080 eyJ... +✍️ Configuring server "local" + +$ attic cache create hello +✨ Created cache "hello" on "local" + +#+begin_src nix-ts :tangle modules/nixos/server/attic.nix + { lib, config, globals, dns, confLib, ... }: + let + inherit (confLib.gen { name = "attic"; port = 8091; }) serviceName serviceDir servicePort serviceAddress serviceDomain serviceProxy proxyAddress4 proxyAddress6; + inherit (config.swarselsystems) mainUser isPublic sopsFile; + serviceDB = "atticd"; + in + { + options = { + swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; + }; + config = lib.mkIf config.swarselmodules.server.${serviceName} { + + nodes.stoicclub.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { + "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; + }; + + globals.services.${serviceName} = { + domain = serviceDomain; + inherit proxyAddress4 proxyAddress6; + }; + + sops = lib.mkIf (!isPublic) { + secrets = { + attic-server-token = { inherit sopsFile; }; + attic-garage-access-key = { inherit sopsFile; }; + attic-garage-secret-key = { inherit sopsFile; }; + }; + templates = { + "attic.env" = { + content = '' + ATTIC_SERVER_TOKEN_RS256_SECRET_BASE64=${config.sops.placeholder.attic-server-token} + AWS_ACCESS_KEY_ID=${config.sops.placeholder.attic-garage-access-key} + AWS_SECRET_ACCESS_KEY=${config.sops.placeholder.attic-garage-secret-key} + ''; + }; + }; + }; + + services.atticd = { + enable = true; + environmentFile = config.sops.templates."attic.env".path; + settings = { + listen = "[::]:${builtins.toString servicePort}"; + api-endpoint = "https://${serviceDomain}/"; + allowed-hosts = [ + serviceDomain + ]; + require-proof-of-possession = false; + compression = { + type = "zstd"; + level = 3; + }; + database.url = "postgresql:///atticd?host=/run/postgresql"; + + storage = + if config.swarselmodules.server.garage then { + type = "s3"; + region = mainUser; + bucket = serviceName; + # attic must be patched to never serve pre-signed s3 urls directly + # otherwise it will redirect clients to this localhost endpoint + endpoint = "http://127.0.0.1:3900"; + } else { + type = "local"; + path = serviceDir; + # attic must be patched to never serve pre-signed s3 urls directly + # otherwise it will redirect clients to this localhost endpoint + }; + + garbage-collection = { + interval = "1 day"; + default-retention-period = "3 months"; + }; + + chunking = { + nar-size-threshold = if config.swarselmodules.server.garage then 0 else 64 * 1024; # 64 KiB + + min-size = 16 * 1024; # 16 KiB + avg-size = 64 * 1024; # 64 KiB + max-size = 256 * 1024; # 256 KiBize = 262144; + }; + }; + }; + + services.postgresql = { + enable = true; + enableTCPIP = true; + ensureDatabases = [ serviceDB ]; + ensureUsers = [ + { + name = serviceDB; + ensureDBOwnership = true; + } + ]; + }; + + systemd.services.atticd = lib.mkIf config.swarselmodules.server.garage { + requires = [ "garage.service" ]; + after = [ "garage.service" ]; + }; + + nodes.${serviceProxy}.services.nginx = { + upstreams = { + ${serviceName} = { + servers = { + "${serviceAddress}:${builtins.toString servicePort}" = { }; + }; + }; + }; + virtualHosts = { + "${serviceDomain}" = { + enableACME = true; + forceSSL = true; + acmeRoot = null; + oauth2.enable = false; + locations = { + "/" = { + proxyPass = "http://${serviceName}"; + extraConfig = '' + client_max_body_size 0; + ''; + }; + }; + }; + }; + }; + + }; + } +#+end_src +*** Darwin +:PROPERTIES: +:CUSTOM_ID: h:ac0cd8b3-06cf-4dca-ba73-6100c8fedb47 +:END: + +This section is to be used for darwin modules, in case I can ever be bothered to actually write them. + +**** Imports +:PROPERTIES: +:CUSTOM_ID: h:25a95a30-8e4f-4fe3-9b8e-508a82e0a1b4 +:END: + +This section sets up all the imports that are used in the home-manager section. + +#+begin_src nix-ts :tangle modules/nixos/darwin/default.nix + { self, lib, config, outputs, globals, ... }: + let + macUser = globals.user.work; + in + { + imports = [ + ]; + + options.swarselmodules.optional.darwin = lib.mkEnableOption "optional darwin settings"; + config = lib.mkIf config.swarselmodules.optional.darwin { + nix.settings.experimental-features = "nix-command flakes"; + nixpkgs = { + hostPlatform = "x86_64-darwin"; + overlays = [ outputs.overlays.default ]; + config = { + allowUnfree = true; + }; + }; + + home-manager.users."${macUser}".imports = [ + "${self}/modules/home/darwin" + ]; + + system.stateVersion = 4; + }; + } +#+end_src + +*** TODO Optional +:PROPERTIES: +:CUSTOM_ID: h:f9aa9af0-9b8d-43ff-901d-9ffccdd70589 +:END: + +These sets of configuration do not need to be deployed on every host, for a multitude of reasons. + +- The gaming set is not needed on weak machines, and also not on my work machine. +- The VirtualBox package takes forever to build, and I do not need virtual machines on every host. +- There are some hosts that I do not want to autologin to. +- =nswitch-rcm= is a tool I wrote for easy payload flashing of a Nintendo Switch in RCM mode. However, that is not needed on every machine. +- The work profile is only used on my work laptop. + +TODO: evaluate whether I should keep using this structure. + + #+begin_src nix-ts :tangle modules/nixos/optional/default.nix + { lib, ... }: + let + importNames = lib.swarselsystems.readNix "modules/nixos/optional"; + in + { + imports = lib.swarselsystems.mkImports importNames "modules/nixos/optional"; + } + #+end_src + + +**** Niri +:PROPERTIES: +:CUSTOM_ID: h:58162d08-3ded-441d-861e-2ebf30e32538 +:END: + +Auto login for the initial session. + +#+begin_src nix-ts :tangle modules/nixos/optional/niri.nix + { inputs, lib, config, pkgs, ... }: + let + moduleName = "niri"; + in + { + imports = [ + inputs.niri-flake.nixosModules.niri + ]; + options.swarselmodules.${moduleName} = lib.mkEnableOption "${moduleName} settings"; + config = lib.mkIf config.swarselmodules.${moduleName} { + + environment.systemPackages = with pkgs; [ + wl-clipboard + wayland-utils + libsecret + cage + gamescope + xwayland-satellite-unstable + ]; + + + programs.niri = { + enable = true; + package = pkgs.niri-unstable; # the actual niri that will be installed and used + }; + } // { + niri-flake.cache.enable = true; + programs.niri = { + package = null; + }; + }; + } +#+end_src + +**** gaming +:PROPERTIES: +:CUSTOM_ID: h:fb3f3e01-7df4-4b06-9e91-aa9cac61a431 +:END: + +This opens a few gaming ports and installs the steam configuration suite for gaming. There are more options in [[#h:84fd7029-ecb6-4131-9333-289982f24ffa][Gaming]] (home-manager side). + +#+begin_src nix-ts :tangle modules/nixos/optional/gaming.nix + { self, pkgs, config, ... }: + { + config = { + + home-manager.users."${config.swarselsystems.mainUser}" = { + imports = [ + "${self}/modules/home/optional/gaming.nix" + ]; + }; + + programs.steam = { + enable = true; + package = pkgs.steam; + extraCompatPackages = [ + pkgs.proton-ge-bin + ]; + }; + # specialisation = { + # gaming.configuration = { + # networking = { + # firewall.enable = lib.mkForce false; + # firewall = { + # allowedUDPPorts = [ 4380 27036 14242 34197 ]; # 34197: factorio; 4380 27036 14242: barotrauma; + # allowedTCPPorts = [ ]; # 34197: factorio; 4380 27036 14242: barotrauma; 51820: wireguard + # allowedTCPPortRanges = [ + # { from = 27015; to = 27030; } # barotrauma + # { from = 27036; to = 27037; } # barotrauma + # ]; + # allowedUDPPortRanges = [ + # { from = 27000; to = 27031; } # barotrauma + # { from = 58962; to = 58964; } # barotrauma + # ]; + # }; + # }; + + + # hardware.xone.enable = true; + + # environment.systemPackages = [ + # pkgs.linuxKernel.packages.linux_6_12.xone + # ]; + # }; + # }; + }; + + } + + +#+end_src + +**** VirtualBox +:PROPERTIES: +:CUSTOM_ID: h:b3523246-14e9-4284-ba22-cebc5ca36732 +:END: + +This sets the VirtualBox configuration. Guest should not be enabled if not direly needed, it will make rebuilds unbearably slow. I only use this privately to run an old editor that does not run well under wine, so I put it into it's own specialisation. + +#+begin_src nix-ts :tangle modules/nixos/optional/virtualbox.nix + { lib, config, pkgs, ... }: + { + config = { + # specialisation = { + # VBox.configuration = { + virtualisation.virtualbox = { + host = { + enable = true; + enableKvm = true; + addNetworkInterface = lib.mkIf config.virtualisation.virtualbox.host.enableKvm false; + package = pkgs.stable.virtualbox; + enableExtensionPack = true; + }; + # leaving this here for future notice. setting guest.enable = true will make 'restarting sysinit-reactivation.target' take till timeout on nixos-rebuild switch + guest = { + enable = false; + }; + }; + # run an older kernel to provide compatibility with windows vm + # boot = { + # kernelPackages = lib.mkForce pkgs.stable24_05.linuxPackages; + # # kernelParams = [ + # # "amd_iommu=on" + # # ]; + # }; + + + # fixes the issue of running together with QEMU + # NOTE: once you start a QEMU VM (use kvm) VirtualBox will fail to start VMs + # boot.kernelParams = [ "kvm.enable_virt_at_load=0" ]; + # }; + # }; + }; + + } +#+end_src + +**** VmWare +:PROPERTIES: +:CUSTOM_ID: h:34db28fb-62f7-4597-a9ff-0de2991a8415 +:END: + + +This sets the VirtualBox configuration. Guest should not be enabled if not direly needed, it will make rebuilds unbearably slow. + +#+begin_src nix-ts :tangle modules/nixos/optional/vmware.nix + _: + { + + config = { + virtualisation.vmware.host.enable = true; + virtualisation.vmware.guest.enable = true; + }; + } +#+end_src + +**** nswitch-rcm +:PROPERTIES: +:CUSTOM_ID: h:5c41c4ee-22ca-405b-9e4f-cc4051634edd +:END: + +This smashes Atmosphere 1.3.2 on the switch, which is what I am currenty using. + +#+begin_src nix-ts :tangle modules/nixos/optional/nswitch-rcm.nix + { pkgs, ... }: + { + config = { + services.nswitch-rcm = { + enable = true; + package = pkgs.fetchurl { + url = "https://github.com/Atmosphere-NX/Atmosphere/releases/download/1.3.2/fusee.bin"; + hash = "sha256-5AXzNsny45SPLIrvWJA9/JlOCal5l6Y++Cm+RtlJppI="; + }; + }; + }; + } +#+end_src + +**** Framework +:PROPERTIES: +:CUSTOM_ID: h:bb542fa6-b087-4c1c-838e-d9ec14e4eb85 +:END: + +This holds configuration that is specific to framework laptops. + +#+begin_src nix-ts :tangle modules/nixos/optional/framework.nix + { self, config, ... }: + { + config = { + + home-manager.users."${config.swarselsystems.mainUser}" = { + imports = [ + "${self}/modules/home/optional/framework.nix" + ]; + }; + + services = { + fwupd = { + enable = true; + # framework also uses lvfs-testing, but I do not want to use it + extraRemotes = [ "lvfs" ]; + }; + udev.extraRules = '' + # disable Wakeup on Framework Laptop 16 Keyboard (ANSI) + ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="32ac", ATTRS{idProduct}=="0012", ATTR{power/wakeup}="disabled" + # disable Wakeup on Framework Laptop 16 Numpad Module + ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="32ac", ATTRS{idProduct}=="0014", ATTR{power/wakeup}="disabled" + # disable Wakeup on Framework Laptop 16 Trackpad + ACTION=="add", SUBSYSTEM=="i2c", DRIVERS=="i2c_hid_acpi", ATTRS{name}=="PIXA3854:00", ATTR{power/wakeup}="disabled" + ''; + }; + hardware.fw-fanctrl = { + enable = true; + config = { + defaultStrategy = "lazy"; + }; + }; + }; + } +#+end_src + +**** AMD CPU +:PROPERTIES: +:CUSTOM_ID: h:b64b8988-94fa-440f-8cf1-ee5568bfd75e +:END: + +#+begin_src nix-ts :tangle modules/nixos/optional/amdcpu.nix + _: + { + config = { + hardware = { + cpu.amd.updateMicrocode = true; + }; + }; + } +#+end_src + +**** AMD GPU +:PROPERTIES: +:CUSTOM_ID: h:0dc68d4f-72b3-465a-8d73-4453d06e7853 +:END: + + +#+begin_src nix-ts :tangle modules/nixos/optional/amdgpu.nix + _: + { + config = { + hardware = { + amdgpu = { + opencl.enable = true; + initrd.enable = true; + # amdvlk = { + # enable = true; + # support32Bit.enable = true; + # }; + }; + }; + }; + } +#+end_src + +**** Hibernation +:PROPERTIES: +:CUSTOM_ID: h:15b581ab-09fe-4f84-af26-2f1fbf7d726b +:END: + +#+begin_src nix-ts :tangle modules/nixos/optional/hibernation.nix + { lib, config, ... }: + { + options.swarselsystems = { + hibernation = { + offset = lib.mkOption { + type = lib.types.int; + default = 0; + }; + resumeDevice = lib.mkOption { + type = lib.types.str; + default = "/dev/disk/by-label/nixos"; + }; + }; + }; + config = { + boot = { + kernelParams = [ + "resume_offset=${builtins.toString config.swarselsystems.hibernation.offset}" + # "mem_sleep_default=deep" + ]; + inherit (config.swarselsystems.hibernation) resumeDevice; + }; + systemd.services."systemd-suspend-then-hibernate".aliases = [ "systemd-suspend.service" ]; + powerManagement.enable = true; + systemd.sleep.extraConfig = '' + HibernateDelaySec=120m + SuspendState=freeze + ''; + }; + } +#+end_src + +**** work +:PROPERTIES: +:CUSTOM_ID: h:bbf2ecb6-c8ff-4462-b5d5-d45b28604ddf +:END: + +Options that I need specifically at work. There are more options at [[#h:f0b2ea93-94c8-48d8-8d47-6fe58f58e0e6][Work]] (home-manager side). + +When setting up a new machine: + +#+begin_src markdown :noweb-ref worksetup :exports both :results html + - setup the work VPN: + - using the laptop certificate `.pem` as User cert and private key (CA cert: none) + - vpn gateway is found in `nixosConfig.repo.secrets.local.work.vpnGateway` +#+end_src + +#+begin_src nix-ts :tangle modules/nixos/optional/work.nix + { self, lib, pkgs, config, ... }: + let + inherit (config.swarselsystems) mainUser homeDir; + iwd = config.networking.networkmanager.wifi.backend == "iwd"; + owner = mainUser; + sopsFile = self + /secrets/work/secrets.yaml; + in + { + options.swarselsystems = { + hostName = lib.mkOption { + type = lib.types.str; + default = config.node.name; + }; + fqdn = lib.mkOption { + type = lib.types.str; + default = ""; + }; + }; + config = { + + home-manager.users."${config.swarselsystems.mainUser}" = { + imports = [ + "${self}/modules/home/optional/work.nix" + ]; + }; + + sops = + let + secretNames = [ + "vcuser" + "vcpw" + "govcuser" + "govcpw" + "govcurl" + "govcdc" + "govcds" + "govchost" + "govcnetwork" + "govcpool" + "baseuser" + "basepw" + ]; + in + { + secrets = builtins.listToAttrs ( + map + (name: { + inherit name; + value = { inherit owner sopsFile; }; + }) + secretNames + ); + templates = { + "network-manager-work.env".content = '' + BASEUSER=${config.sops.placeholder.baseuser} + BASEPASS=${config.sops.placeholder.basepw} + ''; + }; + }; + + boot.initrd = { + systemd.enable = lib.mkForce true; # make sure we are using initrd systemd even when not using Impermanence + luks = { + # disable "support" since we use systemd-cryptenroll + # make sure yubikeys are enrolled using + # sudo systemd-cryptenroll --fido2-device=auto --fido2-with-user-verification=no --fido2-with-user-presence=true --fido2-with-client-pin=no /dev/nvme0n1p2 + yubikeySupport = false; + fido2Support = false; + }; + }; + + programs = { + + browserpass.enable = true; + _1password.enable = true; + _1password-gui = { + enable = true; + polkitPolicyOwners = [ "${mainUser}" ]; + }; + }; + + networking = { + inherit (config.swarselsystems) hostName fqdn; + + networkmanager = { + wifi.scanRandMacAddress = false; + ensureProfiles = { + environmentFiles = [ + "${config.sops.templates."network-manager-work.env".path}" + ]; + profiles = { + VBC = { + "802-1x" = { + eap = if (!iwd) then "ttls;" else "peap;"; + identity = "$BASEUSER"; + password = "$BASEPASS"; + phase2-auth = "mschapv2"; + }; + connection = { + id = "VBC"; + type = "wifi"; + autoconnect-priority = "500"; + uuid = "3988f10e-6451-381f-9330-a12e66f45051"; + secondaries = "48d09de4-0521-47d7-9bd5-43f97e23ff82"; # vpn uuid + }; + ipv4 = { method = "auto"; }; + ipv6 = { + # addr-gen-mode = "default"; + addr-gen-mode = "stable-privacy"; + method = "auto"; + }; + proxy = { }; + wifi = { + cloned-mac-address = "permanent"; + mac-address = "E8:65:38:52:63:FF"; + mac-address-randomization = "1"; + mode = "infrastructure"; + band = "a"; + ssid = "VBC"; + }; + wifi-security = { + # auth-alg = "open"; + key-mgmt = "wpa-eap"; + }; + }; + }; + }; + }; + + + firewall = { + enable = lib.mkDefault true; + trustedInterfaces = [ "virbr0" ]; + }; + search = [ + "vbc.ac.at" + "clip.vbc.ac.at" + "imp.univie.ac.at" + ]; + }; + + virtualisation = { + docker.enable = lib.mkIf (!config.virtualisation.podman.dockerCompat) true; + spiceUSBRedirection.enable = true; + libvirtd = { + enable = true; + qemu = { + package = pkgs.qemu_kvm; + runAsRoot = true; + swtpm.enable = true; + vhostUserPackages = with pkgs; [ virtiofsd ]; + # ovmf = { + # enable = true; + # packages = [ + # (pkgs.OVMFFull.override { + # secureBoot = true; + # tpmSupport = true; + # }).fd + # ]; + # }; + }; + }; + }; + + environment.systemPackages = with pkgs; [ + remmina + # gp-onsaml-gui + stable24_11.python39 + qemu + packer + gnumake + libisoburn + govc + terraform + opentofu + # dev.terragrunt + terragrunt + graphviz + azure-cli + + # vm + virt-manager + virt-viewer + virtiofsd + spice + spice-gtk + spice-protocol + virtio-win + win-spice + + powershell + gh + ]; + + services = { + spice-vdagentd.enable = true; + openssh = { + enable = true; + extraConfig = '' + ''; + }; + + syncthing = { + settings = { + "winters" = { + id = "O7RWDMD-AEAHPP7-7TAVLKZ-BSWNBTU-2VA44MS-EYGUNBB-SLHKB3C-ZSLMOAA"; + }; + "moonside@oracle" = { + id = "VPCDZB6-MGVGQZD-Q6DIZW3-IZJRJTO-TCC3QUQ-2BNTL7P-AKE7FBO-N55UNQE"; + }; + folders = { + "Documents" = { + path = "${homeDir}/Documents"; + devices = [ "moonside@oracle" ]; + id = "hgr3d-pfu3w"; + }; + }; + }; + }; + + # ACTION=="remove", ENV{PRODUCT}=="3/1050/407/110", RUN+="${pkgs.kanshi}/bin/kanshictl switch laptoponly" + udev.extraRules = '' + # lock screen when yubikey removed + ACTION=="remove", ENV{PRODUCT}=="3/1050/407/110", RUN+="${pkgs.systemd}/bin/systemctl suspend" + ''; + + }; + + # cgroups v1 is required for centos7 dockers + # specialisation = { + # cgroup_v1.configuration = { + # boot.kernelParams = [ + # "SYSTEMD_CGROUP_ENABLE_LEGACY_FORCE=1" + # "systemd.unified_cgroup_hierarchy=0" + # ]; + # }; + # }; + }; + + } +#+end_src + +**** Uni + +#+begin_src nix-ts :tangle modules/nixos/optional/uni.nix :noweb yes + { self, config, ... }: + { + config = { + + home-manager.users."${config.swarselsystems.mainUser}" = { + imports = [ + "${self}/modules/home/optional/work.nix" + ]; + }; + }; + } + +#+end_src + +**** microvm-host +:PROPERTIES: +:CUSTOM_ID: h:ded3276e-3e97-4863-a29e-b978d8aae1c9 +:END: + +Some standard options that should be set for every microvm host. + +#+begin_src nix-ts :tangle modules/nixos/optional/microvm-host.nix + { config, lib, ... }: + { + # imports = [ + # inputs.microvm.nixosModules.host + # ]; + + config = lib.mkIf (config.guests != { }) { + + microvm = { + hypervisor = lib.mkDefault "qemu"; + }; + }; + } +#+end_src + +**** microvm-guest +:PROPERTIES: +:CUSTOM_ID: h:46419b40-c40b-4b55-ac6f-a30169322bd6 +:END: + +Some standard options that should be set vor every microvm guest. We set the default + +#+begin_src nix-ts :tangle modules/nixos/optional/microvm-guest.nix + _: + { + # imports = [ + # inputs.microvm.nixosModules.microvm + # ]; + + config = + { }; + } + +#+end_src + +**** systemd-networkd (server) + +Some standard options that should be set vor every microvm guest. We set the default + +#+begin_src nix-ts :tangle modules/nixos/optional/systemd-networkd-server.nix + { lib, config, globals, ... }: + { + networking = { + useDHCP = lib.mkForce false; + useNetworkd = true; + dhcpcd.enable = false; + renameInterfacesByMac = lib.mapAttrs (_: v: v.mac) ( + config.repo.secrets.local.networking.networks or { } + ); + }; + boot.initrd.systemd.network = { + enable = true; + networks."10-${config.swarselsystems.server.localNetwork}" = config.systemd.network.networks."10-${config.swarselsystems.server.localNetwork}"; + }; + + systemd = { + network = { + enable = true; + wait-online.enable = false; + networks = + let + netConfig = config.repo.secrets.local.networking; + in + { + "10-${config.swarselsystems.server.localNetwork}" = { + address = [ + "${globals.networks.${config.swarselsystems.server.netConfigName}.hosts.${config.node.name}.cidrv4}" + "${globals.networks.${config.swarselsystems.server.netConfigName}.hosts.${config.node.name}.cidrv6}" + ]; + routes = [ + { + Gateway = netConfig.defaultGateway6; + GatewayOnLink = true; + } + { + Gateway = netConfig.defaultGateway4; + GatewayOnLink = true; + } + ]; + networkConfig = { + IPv6PrivacyExtensions = true; + IPv6AcceptRA = false; + }; + matchConfig.MACAddress = netConfig.networks.${config.swarselsystems.server.localNetwork}.mac; + linkConfig.RequiredForOnline = "routable"; + }; + }; + }; + }; + } + +#+end_src + + +** Home-manager +:PROPERTIES: +:CUSTOM_ID: h:08ded95b-9c43-475d-a0b2-fc088a512287 +:END: + +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 + { lib, ... }: + let + importNames = lib.swarselsystems.readNix "modules/home"; + in + { + imports = lib.swarselsystems.mkImports importNames "modules/home"; + } + +#+end_src + +*** Steps to setup/upgrade home-manager only +:PROPERTIES: +:CUSTOM_ID: h:360f9da1-334e-4b04-b049-45085db8f10c +:END: +Steps to get a home-manager only setup up and running: + +#+begin_src markdown :noweb-ref homemanageronlysetup :exports both :results html + - (Optional) Install openssh-server + - Set hostname to the name specified in the home-manager configuration + - Install nix, either: + - (if upgrading existing nix) Install nix version matching with version that `nix-plugins` is compiled against: `nix-env --install --file '' cacert -I nixpkgs=channel:nixpkgs-unstable --attr nixVersions.nix_x_yy` + - (or installing nix freshly): + - Grab the link to the install script of the needed nix version from https://releases.nixos.org/?prefix=nix, e.g. https://releases.nixos.org/nix/nix-2.30.1/install + - `bash <(curl -L https://releases.nixos.org/nix/nix-x-yy-y/install) --daemon` + - add the following to /etc/nix/nix.conf to become a trusted user: `trusted-users = @wheel root swarsel` + - For the first build: + 1) Clone dotfile repo & change into it + 2) `nix --extra-experimental-features 'nix-command flakes' develop` + 3) `home-manager --extra-experimental-features 'nix-command flakes' switch --flake .#$(hostname) --show-trace` +#+end_src + +*** TODO Common +:PROPERTIES: +:CUSTOM_ID: h:f0a6b5e0-2157-4522-b5e1-3f0abd91c05e +:END: + +TODO: split this into actual common and client sections + +**** Imports +:PROPERTIES: +:CUSTOM_ID: h:16fd2e85-fdd4-440a-81f0-65b9b098a43a +:END: + +This section sets up all the imports that are used in the home-manager section. + +#+begin_src nix-ts :tangle modules/home/common/default.nix + { lib, ... }: + let + importNames = lib.swarselsystems.readNix "modules/home/common"; + sharedNames = lib.swarselsystems.readNix "modules/shared"; + in + { + imports = lib.swarselsystems.mkImports importNames "modules/home/common" ++ + lib.swarselsystems.mkImports sharedNames "modules/shared"; + } +#+end_src + +**** Mirror home-manager shared options (automatically active) +:PROPERTIES: +:CUSTOM_ID: h:30b81bf9-1e69-4ce8-88af-5592896bcee4 +:END: + + +#+begin_src nix-ts :tangle modules/home/common/sharedoptions.nix + { lib, config, nixosConfig ? null, ... }: + let + # mirrorAttrs = lib.mapAttrs (_: v: lib.mkDefault v) nixosConfig.swarselsystems; + mkDefaultCommonAttrs = base: defaults: + lib.mapAttrs (_: v: lib.mkDefault v) + (lib.filterAttrs (k: _: base ? ${k}) defaults); + in + { + # config.swarselsystems = mirrorAttrs; + config.swarselsystems = lib.mkIf (nixosConfig != null) (mkDefaultCommonAttrs config.swarselsystems (nixosConfig.swarselsystems or {})); + } +#+end_src + +**** General home-manager-settings (nix) +:PROPERTIES: +:CUSTOM_ID: h:4af4f67f-7c48-4754-b4bd-6800e3a66664 +:END: + +Again, we adapt =nix= to our needs, enable the home-manager command for non-NixOS machines (NixOS machines are using it as a module) and setting user information that I always keep the same. + +#+begin_src nix-ts :tangle modules/home/common/settings.nix + { self, outputs, lib, pkgs, config, globals, confLib, ... }: + let + inherit (config.swarselsystems) mainUser flakePath isNixos isLinux; + inherit (confLib.getConfig.repo.secrets.common) atticPublicKey; + in + { + options.swarselmodules.general = lib.mkEnableOption "general nix settings"; + config = + let + nix-version = "2_30"; + in + lib.mkIf config.swarselmodules.general { + nix = lib.mkIf (!config.swarselsystems.isNixos) { + package = lib.mkForce pkgs.nixVersions."nix_${nix-version}"; + # extraOptions = '' + # plugin-files = ${pkgs.dev.nix-plugins}/lib/nix/plugins + # extra-builtins-file = ${self + /nix/extra-builtins.nix} + # ''; + extraOptions = + let + nix-plugins = pkgs.nix-plugins.override { + nixComponents = pkgs.nixVersions."nixComponents_${nix-version}"; + }; + in + '' + plugin-files = ${nix-plugins}/lib/nix/plugins + extra-builtins-file = ${self + /nix/extra-builtins.nix} + ''; + settings = { + experimental-features = [ + "nix-command" + "flakes" + "ca-derivations" + "cgroups" + "pipe-operators" + ]; + substituters = [ + "https://${globals.services.attic.domain}/${mainUser}" + ]; + trusted-public-keys = [ + atticPublicKey + ]; + trusted-users = [ + "@wheel" + "${mainUser}" + (lib.mkIf config.swarselmodules.server.ssh-builder "builder") + ]; + connect-timeout = 5; + bash-prompt-prefix = "$SHLVL:\\w "; + bash-prompt = "$(if [[ $? -gt 0 ]]; then printf \"\"; else printf \"\"; fi)λ "; + fallback = true; + min-free = 128000000; + max-free = 1000000000; + auto-optimise-store = true; + warn-dirty = false; + max-jobs = 1; + use-cgroups = lib.mkIf isLinux true; + }; + }; + + nixpkgs = lib.mkIf (!isNixos) { + overlays = [ + outputs.overlays.default + (final: prev: + let + additions = final: _: import "${self}/pkgs/config" { + inherit self config lib; + pkgs = final; + homeConfig = config; + }; + in + additions final prev + ) + ]; + config = { + allowUnfree = true; + }; + }; + + programs = { + # home-manager.enable = lib.mkIf (!isNixos) true; + man = { + enable = true; + generateCaches = true; + }; + }; + + targets.genericLinux.enable = lib.mkIf (!isNixos) true; + + home = { + username = lib.mkDefault mainUser; + homeDirectory = lib.mkDefault "/home/${mainUser}"; + stateVersion = lib.mkDefault "23.05"; + keyboard.layout = "us"; + sessionVariables = { + FLAKE = "/home/${mainUser}/.dotfiles"; + }; + extraOutputsToInstall = [ + "doc" + "info" + "devdoc" + ]; + packages = lib.mkIf (!isNixos) [ + (pkgs.symlinkJoin { + name = "home-manager"; + buildInputs = [ pkgs.makeWrapper ]; + paths = [ pkgs.home-manager ]; + postBuild = '' + wrapProgram $out/bin/home-manager \ + --append-flags '--flake ${flakePath}#$(hostname)' + ''; + }) + ]; + }; + }; + + } +#+end_src + +**** nixGL +:PROPERTIES: +:CUSTOM_ID: h:90af1862-90b3-4c93-8730-2443bc62986a +:END: + +This integrates nixGL into home-manager. NixGL provies OpenGL and Vulkan APIs to nix installed utilities. This is needed for graphical applications on non-NixOS systems. + +to get the info for the secondary gpu, use `lspci -nn | grep VGA` +It can be set to either: + - a number, selecting the n-th non-default GPU + - a PCI bus id in the form =pci-XXX_YY_ZZ_U= + - a PCI id in the form =vendor_id:device_id= + +#+begin_src nix-ts :tangle modules/home/common/nixgl.nix + { lib, config, inputs, ... }: + { + options.swarselmodules.nixgl = lib.mkEnableOption "nixgl settings"; + options.swarselsystems = { + isSecondaryGpu = lib.mkEnableOption "device has a secondary GPU"; + SecondaryGpuCard = lib.mkOption { + type = lib.types.str; + default = ""; + }; + }; + config = lib.mkIf config.swarselmodules.nixgl { + nixGL = lib.mkIf (!config.swarselsystems.isNixos) { + inherit (inputs.nixgl) packages; + defaultWrapper = lib.mkDefault "mesa"; + vulkan.enable = lib.mkDefault false; + prime = lib.mkIf config.swarselsystems.isSecondaryGpu { + card = config.swarselsystems.secondaryGpuCard; + installScript = "mesa"; + }; + offloadWrapper = lib.mkIf config.swarselsystem.isSecondaryGpu "mesaPrime"; + installScripts = [ + "mesa" + "mesaPrime" + ]; + }; + }; + } +#+end_src + +**** Installed packages +:PROPERTIES: +:CUSTOM_ID: h:893a7f33-7715-415b-a895-2687ded31c18 +:END: + +Here are defined some packages that I would like to use across all my machines. Most of these should not require further setup. Notably the cura package is severely outdated on nixpkgs, so I just fetch a more recent AppImage and run that instead. + +Also, I define some useful shell scripts here. + +Programming languages and default lsp's are defined here: [[#h:0e7e8bea-ec58-499c-9731-09dddfc39532][System Packages]] + +***** Packaged +:PROPERTIES: +:CUSTOM_ID: h:6ef9bb5f-c5ee-496e-86e2-d8d271a34d75 +:END: + +This holds packages that I can use as provided, or with small modifications (as in the =texlive= package that needs special configuration). + +#+begin_src nix-ts :tangle modules/home/common/packages.nix + { lib, config, pkgs, ... }: + + { + options.swarselmodules.packages = lib.mkEnableOption "packages settings"; + config = lib.mkIf config.swarselmodules.packages { + home.packages = with pkgs; [ + + # audio stuff + spek # spectrum analyzer + losslessaudiochecker + ffmpeg_7-full + flac + mediainfo + picard-tools + audacity + sox + # stable.feishin # does not work with oauth2-proxy + calibre + + # printing + cups + simple-scan + cura-appimage + + # ssh login using idm + opkssh + + # cache + attic-client + + # dict + (aspellWithDicts (dicts: with dicts; [ de en en-computers en-science ])) + + # browser + stable24_11.vieb + mgba + + # utilities + util-linux + nmap + lsof + nvd + nix-output-monitor + hyprpicker # color picker + findutils + units + vim + sshfs + fuse + # ventoy + poppler-utils + vdhcoapp + + # nix + alejandra + nixpkgs-fmt + deadnix + statix + nix-tree + nix-diff + nix-visualize + nix-init + nix-inspect + nixpkgs-review + manix + + # shellscripts + shfmt + + # local file sharing + wormhole-rs + croc + + # b2 backup @backblaze + restic + + # "big" programs + # obs-studio + gimp + inkscape + zoom-us + # nomacs + libreoffice-qt + xournalpp + # obsidian + # spotify + # vesktop # discord client + # nextcloud-client # enables a systemd service that I do not want + # spotify-player + # element-desktop + + nicotine-plus + stable.transmission_3 + mktorrent + hugo + + # kyria + qmk + qmk-udev-rules + + # firefox related + tridactyl-native + + # mako related + mako + libnotify + + # general utilities + unrar + # samba + cifs-utils + zbar # qr codes + readline + autotiling + brightnessctl + libappindicator-gtk3 + sqlite + speechd + networkmanagerapplet + psmisc # kill etc + lm_sensors + # jq # used for searching the i3 tree in check.sh files + + # specifically needed for anki + # mpv + # anki-bin + + # dirvish file previews + fd + imagemagick + # poppler + ffmpegthumbnailer + mediainfo + gnutar + unzip + + #nautilus + nautilus + xfce.tumbler + libgsf + + # wayland stuff + wtype + wl-mirror + wl-clipboard + wf-recorder + kanshi + + # screenshotting tools + grim + slurp + + # the following packages are used (in some way) by waybar + # playerctl + pavucontrol + # stable.pamixer + # gnome.gnome-clocks + # wlogout + # jdiskreport + # monitor + + #keychain + qalculate-gtk + gcr # needed for gnome-secrets to work + seahorse + + # sops-related + sops + ssh-to-age + + # mail related packages + mu + + # latex and related packages + (texlive.combine { + inherit (pkgs.texlive) scheme-full + dvisvgm dvipng# for preview and export as html + wrapfig amsmath ulem hyperref capt-of; + }) + + # font stuff + nerd-fonts.fira-mono + nerd-fonts.fira-code + nerd-fonts.symbols-only + noto-fonts-color-emoji + font-awesome_5 + noto-fonts + noto-fonts-cjk-sans + ]; + }; + } + #+end_src + +***** Self-defined +:PROPERTIES: +:CUSTOM_ID: h:96cbea91-ff13-4120-b8a9-496b2fa96e70 +:END: + +This is just a separate container for derivations defined in [[#h:64a5cc16-6b16-4802-b421-c67ccef853e1][Packages]]. This is a good idea so that I do not lose track of package names I have defined myself, as this was once a problem in the past already. + +#+begin_src nix-ts :tangle modules/home/common/custom-packages.nix + { lib, config, pkgs, ... }: + + { + options.swarselmodules.ownpackages = lib.mkEnableOption "own packages settings"; + config = lib.mkIf config.swarselmodules.ownpackages { + home.packages = with pkgs; lib.mkIf (!config.swarselsystems.isPublic) [ + pass-fuzzel + cdw + cdb + cdr + bak + timer + e + swarselcheck + swarselcheck-niri + waybarupdate + opacitytoggle + fs-diff + github-notifications + hm-specialisation + t2ts + ts2t + vershell + eontimer + project + fhs + swarsel-bootstrap + swarsel-displaypower + swarsel-deploy + swarsel-instantiate + swarselzellij + sshrm + endme + git-replace + ]; + }; + } +#+end_src + +**** sops +:PROPERTIES: +:CUSTOM_ID: h:d87d80fd-2ac7-4f29-b338-0518d06b4deb +:END: + +I use sops-nix to handle secrets that I want to have available on my machines at all times. Procedure to add a new machine: +- `ssh-keygen -t ed25519 -C "NAME sops"` in .ssh directory (or wherever) - name e.g. "sops" +- cat ~/.ssh/sops.pub | ssh-to-age | wl-copy +- add the output to .sops.yaml +- cp ~/.ssh/sops.pub ~/.dotfiles/secrets/keys/NAME.pub +- update entry for sops.age.sshKeyPaths + + Since we are using the home-manager implementation here, we need to specify the runtime path. + +#+begin_src nix-ts :tangle modules/home/common/sops.nix + { config, lib, inputs, ... }: + let + inherit (config.swarselsystems) homeDir; + in + { + options.swarselmodules.sops = lib.mkEnableOption "sops settings"; + config = lib.optionalAttrs (inputs ? sops) { + sops = { + age.sshKeyPaths = [ "${homeDir}/.ssh/sops" "${if config.swarselsystems.isImpermanence then "/persist" else ""}${homeDir}/.ssh/ssh_host_ed25519_key" ]; + defaultSopsFile = "${if config.swarselsystems.isImpermanence then "/persist" else ""}${homeDir}/.dotfiles/secrets/general/secrets.yaml"; + + validateSopsFiles = false; + }; + }; + } +#+end_src + +**** Yubikey +:PROPERTIES: +:CUSTOM_ID: h:4c850b80-56e0-437b-b564-2dd897027b2f +:END: + +#+begin_src nix-ts :tangle modules/home/common/yubikey.nix + { lib, config, inputs, confLib, ... }: + let + inherit (config.swarselsystems) homeDir; + in + { + options.swarselmodules.yubikey = lib.mkEnableOption "yubikey settings"; + + config = lib.mkIf config.swarselmodules.yubikey ({ + + pam.yubico.authorizedYubiKeys = lib.mkIf (config.swarselsystems.isNixos && !config.swarselsystems.isPublic) { + ids = [ + confLib.getConfig.repo.secrets.common.yubikeys.dev1 + confLib.getConfig.secrets.common.yubikeys.dev2 + ]; + }; + } // lib.optionalAttrs (inputs ? sops) { + sops.secrets = lib.mkIf (!config.swarselsystems.isPublic) { + u2f-keys = { path = "${homeDir}/.config/Yubico/u2f_keys"; }; + }; + }); + } +#+end_src + +**** SSH Machines +:PROPERTIES: +:CUSTOM_ID: h:edd6720e-1f90-40bf-b6f9-30a19d4cae08 +:END: + +It is very convenient to have SSH aliases in place for machines that I use. This is mainly used for some server machines and some university clusters. We also enable agent forwarding to have our Yubikey SSH key accessible on the remote host. + +#+begin_src nix-ts :tangle modules/home/common/ssh.nix + { inputs, lib, config, confLib, ... }: + { + options.swarselmodules.ssh = lib.mkEnableOption "ssh settings"; + config = lib.mkIf config.swarselmodules.ssh ({ + programs.ssh = { + enable = true; + enableDefaultConfig = false; + extraConfig = '' + SetEnv TERM=xterm-256color + ServerAliveInterval 20 + ''; + matchBlocks = { + "*" = { + forwardAgent = true; + addKeysToAgent = "no"; + compression = false; + serverAliveInterval = 0; + serverAliveCountMax = 3; + hashKnownHosts = false; + userKnownHostsFile = "~/.ssh/known_hosts"; + controlMaster = "auto"; + controlPath = "~/.ssh/master-%r@%n:%p"; + controlPersist = "5m"; + }; + } // confLib.getConfig.repo.secrets.common.ssh.hosts; + }; + } // lib.optionalAttrs (inputs ? sops) { + sops.secrets = lib.mkIf (!config.swarselsystems.isPublic && !config.swarselsystems.isNixos) { + builder-key = { path = "${config.home.homeDirectory}/.ssh/builder"; mode = "0600"; }; + }; + }); + } +#+end_src + +**** Theme (stylix) +:PROPERTIES: +:CUSTOM_ID: h:a92318cd-413e-4e78-a478-e63b09df019c +:END: + +These section allows home-manager to allow theme settings, and handles some other appearance-related settings like cursor styles. Interestingly, system icons (adwaita) still need to be setup on system-level, and will break if defined here. + +This section has been notably empty ever since switching to stylix. Only Emacs is not allowed to be styled by it, because it becomes more ugly compared to my handcrafted setup. + +=theme= is defined in [[#h:5bc1b0c9-dc59-4c81-b5b5-e60699deda78][Theme (stylix)]]. + +#+begin_src nix-ts :noweb yes :tangle modules/home/common/stylix.nix + { self, lib, config, vars, ... }: + { + options.swarselmodules.stylix = lib.mkEnableOption "stylix settings"; + config = lib.mkIf config.swarselmodules.stylix { + stylix = lib.mkIf (!config.swarselsystems.isNixos && config.swarselmodules.stylix) (lib.recursiveUpdate + { + enable = true; + base16Scheme = "${self}/files/stylix/swarsel.yaml"; + targets = vars.stylixHomeTargets; + } + vars.stylix); + }; + } +#+end_src + +**** Desktop Entries, MIME types (xdg) +:PROPERTIES: +:CUSTOM_ID: h:867556e6-5a24-4c43-9d47-3edca2f16488 +:END: + +Some programs lack a dmenu launcher - I define them myself here. + +TODO: Non-NixOS machines (=sp3) should not use these by default, but instead the programs prefixed with "nixGL". I need to figure out how to automate this process, as it is not feasible to write desktop entries for all programs installed on that machine. + +#+begin_src nix-ts :tangle modules/home/common/desktop.nix + { lib, config, ... }: + { + options.swarselmodules.desktop = lib.mkEnableOption "desktop settings"; + config = lib.mkIf config.swarselmodules.desktop { + xdg.desktopEntries = { + + cura = { + name = "Ultimaker Cura"; + genericName = "Cura"; + exec = "cura"; + terminal = false; + categories = [ "Application" ]; + }; + + teamsNoGpu = { + name = "Microsoft Teams (no GPU)"; + genericName = "Teams (no GPU)"; + exec = "teams-for-linux --disableGpu=true --trayIconEnabled=true"; + terminal = false; + categories = [ "Application" ]; + }; + + rustdesk-vbc = { + name = "Rustdesk VBC"; + genericName = "rustdesk-vbc"; + exec = "rustdesk-vbc"; + terminal = false; + categories = [ "Application" ]; + }; + + anki = { + name = "Anki Flashcards"; + genericName = "Anki"; + exec = "anki"; + terminal = false; + categories = [ "Application" ]; + }; + + element = { + name = "Element Matrix Client"; + genericName = "Element"; + exec = "element-desktop -enable-features=UseOzonePlatform -ozone-platform=wayland --disable-gpu-driver-bug-workarounds"; + terminal = false; + categories = [ "Application" ]; + }; + + emacsclient-newframe = { + name = "Emacs (Client, New Frame)"; + genericName = "Emacs (Client, New Frame)"; + exec = "emacsclient -r %u"; + icon = "emacs"; + terminal = false; + categories = [ "Development" "TextEditor" ]; + }; + + }; + + xdg = { + configFile."mimeapps.list".force = true; + mimeApps = { + enable = true; + defaultApplications = { + "application/epub+zip" = [ "calibre-ebook-viewer.desktop" ]; + "application/metalink+xml" = [ "emacsclient.desktop" ]; + "application/msword" = [ "writer.desktop" ]; + "application/pdf" = [ "org.gnome.Evince.desktop" ]; + "application/sql" = [ "emacsclient.desktop" ]; + "application/vnd.ms-excel" = [ "calc.desktop" ]; + "application/vnd.ms-powerpoint" = [ "impress.desktop" ]; + "application/x-extension-htm" = [ "firefox.desktop" ]; + "application/x-extension-html" = [ "firefox.desktop" ]; + "application/x-extension-shtml" = [ "firefox.desktop" ]; + "application/x-extension-xht" = [ "firefox.desktop" ]; + "application/x-extension-xhtml" = [ "firefox.desktop" ]; + "application/xhtml+xml" = [ "firefox.desktop" ]; + "audio/flac" = [ "mpv.desktop" ]; + "audio/mp3" = [ "mpv.desktop" ]; + "audio/ogg" = [ "mpv.desktop" ]; + "audio/wav" = [ "mpv.desktop" ]; + "image/gif" = [ "imv.desktop" ]; + "image/jpeg" = [ "imv.desktop" ]; + "image/png" = [ "imv.desktop" ]; + "image/svg" = [ "imv.desktop" ]; + "image/vnd.adobe.photoshop" = [ "gimp.desktop" ]; + "image/vnd.dxf" = [ "org.inkscape.Inkscape.desktop" ]; + "image/webp" = [ "firefox.desktop" ]; + "text/csv" = [ "emacsclient.desktop" ]; + "text/html" = [ "firefox.desktop" ]; + "text/plain" = [ "emacsclient.desktop" ]; + "video/3gp" = [ "umpv.desktop" ]; + "video/flv" = [ "umpv.desktop" ]; + "video/mkv" = [ "umpv.desktop" ]; + "video/mp4" = [ "umpv.desktop" ]; + "x-scheme-handler/chrome" = [ "firefox.desktop" ]; + "x-scheme-handler/http" = [ "firefox.desktop" ]; + "x-scheme-handler/https" = [ "firefox.desktop" ]; + }; + associations = { + added = { + "application/x-zerosize" = [ "emacsclient.desktop" ]; + "application/epub+zip" = [ "calibre-ebook-viewer.desktop" ]; + }; + }; + }; + }; + }; + } +#+end_src + +**** Linking dotfiles (Symlinks home.file) +:PROPERTIES: +:CUSTOM_ID: h:5ef03803-e150-41bc-b603-e80d60d96efc +:END: + +This section should be used in order to symlink already existing configuration files using `home.file` and setting session variables using `home.sessionVariables`. + +As for the `home.sessionVariables`, it should be noted that environment variables that are needed at system start should NOT be loaded here, but instead in `programs.zsh.config.extraSessionCommands` (in the home-manager programs section). This is also where all the wayland related variables are stored. + +Also, we link some files to the users XDG configuration home: +Also in firefox `about:config > toolkit.legacyUserProfileCustomizations.stylesheets` to true. + +#+begin_src nix-ts :tangle modules/home/common/symlink.nix + { self, lib, config, ... }: + { + options.swarselmodules.symlink = lib.mkEnableOption "symlink settings"; + config = lib.mkIf config.swarselmodules.symlink { + home.file = { + "init.el" = lib.mkDefault { + source = self + /files/emacs/init.el; + target = ".emacs.d/init.el"; + }; + "early-init.el" = { + source = self + /files/emacs/early-init.el; + target = ".emacs.d/early-init.el"; + }; + # on NixOS, Emacs does not find the aspell dicts easily. Write the configuration manually + ".aspell.conf" = { + source = self + /files/config/.aspell.conf; + target = ".aspell.conf"; + }; + ".gitmessage" = { + source = self + /files/git/.gitmessage; + target = ".gitmessage"; + }; + }; + + xdg.configFile = { + "tridactyl/tridactylrc".source = self + /files/firefox/tridactyl/tridactylrc; + "tridactyl/themes/base16-codeschool.css".source = self + /files/firefox/tridactyl/themes/base16-codeschool.css; + "tridactyl/themes/swarsel.css".source = self + /files/firefox/tridactyl/themes/swarsel.css; + # "swayidle/config".source = self + /files/swayidle/config; + }; + }; + } +#+end_src + +**** Sourcing environment variables +:PROPERTIES: +:CUSTOM_ID: h:4486b02f-4fb8-432b-bfa2-2e786206341d +:END: + +Sets environment variables. Here I am only setting the EDITOR variable, most variables are set in the [[#h:02df9dfc-d1af-4a37-a7a0-d8da0af96a20][Sway]] section. + +#+begin_src nix-ts :tangle modules/home/common/env.nix + { lib, config, confLib, globals, ... }: + let + inherit (confLib.getConfig.repo.secrets.common.mail) address1 address2 address3 address4 allMailAddresses; + inherit (confLib.getConfig.repo.secrets.common.calendar) source1 source1-name source2 source2-name source3 source3-name; + inherit (confLib.getConfig.repo.secrets.common) fullName openrouterApi instaDomain sportDomain; + inherit (config.swarselsystems) isPublic homeDir; + + DISPLAY = ":0"; + in + { + options.swarselmodules.env = lib.mkEnableOption "env settings"; + config = lib.mkIf config.swarselmodules.env { + home.sessionVariables = { + inherit DISPLAY; + EDITOR = "e -w"; + } // (lib.optionalAttrs (!isPublic) { }); + systemd.user.sessionVariables = { + DOCUMENT_DIR_PRIV = lib.mkForce "${homeDir}/Documents/Private"; + FLAKE = "${config.home.homeDirectory}/.dotfiles"; + } // lib.optionalAttrs (!isPublic) { + SWARSEL_DOMAIN = globals.domains.main; + SWARSEL_RSS_DOMAIN = globals.services.freshrss.domain; + SWARSEL_MUSIC_DOMAIN = globals.services.navidrome.domain; + SWARSEL_FILES_DOMAIN = globals.services.nextcloud.domain; + SWARSEL_INSTA_DOMAIN = instaDomain; + SWARSEL_SPORT_DOMAIN = sportDomain; + SWARSEL_MAIL1 = address1; + SWARSEL_MAIL2 = address2; + SWARSEL_MAIL3 = address3; + SWARSEL_MAIL4 = address4; + SWARSEL_CAL1 = source1; + SWARSEL_CAL1NAME = source1-name; + SWARSEL_CAL2 = source2; + SWARSEL_CAL2NAME = source2-name; + SWARSEL_CAL3 = source3; + SWARSEL_CAL3NAME = source3-name; + SWARSEL_FULLNAME = fullName; + SWARSEL_MAIL_ALL = lib.mkDefault allMailAddresses; + GITHUB_NOTIFICATION_TOKEN_PATH = confLib.getConfig.sops.secrets.github-notifications-token.path; + OPENROUTER_API_KEY = openrouterApi; + }; + }; + } +#+end_src + +**** General Programs: bottom, imv, less, lesspipe, sioyek, bat, carapace, wlogout, swayr, yt-dlp, mpv, jq, nix-index, ripgrep, pandoc, fzf, zoxide, timidity +:PROPERTIES: +:CUSTOM_ID: h:f0e0b580-2e1c-4ca6-a983-f05d3ebbbcde +:END: + +This section is for programs that require no further configuration. zsh Integration is enabled by default for these. + +#+begin_src nix-ts :tangle modules/home/common/programs.nix + { lib, config, pkgs, ... }: + { + options.swarselmodules.programs = lib.mkEnableOption "programs settings"; + config = lib.mkIf config.swarselmodules.programs { + programs = { + bat = { + enable = true; + extraPackages = [ + pkgs.bat-extras.batdiff + pkgs.bat-extras.batman + pkgs.bat-extras.batwatch + ] ++ [ + pkgs.stable.bat-extras.batgrep + ]; + # extraPackages = with pkgs.bat-extras; [ batdiff batman batgrep batwatch ]; + }; + bottom.enable = true; + carapace.enable = true; + fzf = { + enable = true; + enableBashIntegration = false; + enableZshIntegration = false; + }; + imv.enable = true; + jq.enable = true; + less.enable = true; + lesspipe.enable = true; + mpv.enable = true; + pandoc.enable = true; + rclone.enable = true; + ripgrep.enable = true; + sioyek.enable = true; + swayr.enable = true; + timidity.enable = true; + wlogout = { + enable = true; + layout = [ + { + label = "lock"; + action = "loginctl lock-session"; + text = "Lock"; + keybind = "l"; + circular = true; + } + { + label = "hibernate"; + action = "systemctl hibernate"; + text = "Hibernate"; + keybind = "h"; + circular = true; + } + { + label = "logout"; + action = "loginctl terminate-user $USER"; + text = "Logout"; + keybind = "u"; + circular = true; + } + { + label = "shutdown"; + action = "systemctl poweroff"; + text = "Shutdown"; + keybind = "p"; + circular = true; + } + { + label = "suspend"; + action = "systemctl suspend"; + text = "Suspend"; + keybind = "s"; + circular = true; + } + { + label = "reboot"; + action = "systemctl reboot"; + text = "Reboot"; + keybind = "r"; + circular = true; + } + ]; + }; + yt-dlp.enable = true; + zoxide = { + enable = true; + enableZshIntegration = true; + options = [ + "--cmd cd" + ]; + }; + }; + }; + } +#+end_src + +**** nix-index +:PROPERTIES: +:CUSTOM_ID: h:64dbbb9e-8097-4c1b-813c-8c10cf9b9748 +:END: + +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 + + { + + enable = true; + package = pkgs.symlinkJoin { + name = "nix-index"; + paths = [ commandNotFound ]; + }; + }; + programs.nix-index-database.comma.enable = true; + }; + } +#+end_src + +**** nix-your-shell +:PROPERTIES: +:CUSTOM_ID: h:3fd72021-e174-49d0-a42e-58f6ed3682f2 +:END: + +#+begin_src nix-ts :tangle modules/home/common/nix-your-shell.nix + { lib, config, ... }: + let + moduleName = "nix-your-shell"; + in + { + options.swarselmodules.${moduleName} = lib.mkEnableOption "enable ${moduleName} and settings"; + config = lib.mkIf config.swarselmodules.${moduleName} { + programs.${moduleName} = { + enable = true; + enableZshIntegration = true; + }; + }; + } +#+end_src + +**** password-store +:PROPERTIES: +:CUSTOM_ID: h:ac0e5e62-0dbf-4782-9a96-9e558eae86ae +:END: + +Enables password store with the =pass-otp= extension which allows me to store and generate one-time-passwords. + +#+begin_src nix-ts :tangle modules/home/common/password-store.nix + { lib, config, pkgs, ... }: + { + options.swarselmodules.passwordstore = lib.mkEnableOption "passwordstore settings"; + config = lib.mkIf config.swarselmodules.passwordstore { + programs.password-store = { + enable = true; + settings = { + PASSWORD_STORE_DIR = "$HOME/.local/share/password-store"; + }; + package = pkgs.pass.withExtensions (exts: [ exts.pass-otp ]); + }; + }; + } +#+end_src + +**** direnv +:PROPERTIES: +:CUSTOM_ID: h:1ab84307-b3fb-4c32-9def-4b89a53a8547 +:END: + +Enables direnv, which I use for nearly all of my nix dev flakes. + +#+begin_src nix-ts :tangle modules/home/common/direnv.nix + { lib, config, ... }: + { + options.swarselmodules.direnv = lib.mkEnableOption "direnv settings"; + config = lib.mkIf config.swarselmodules.direnv { + programs.direnv = { + enable = true; + silent = true; + nix-direnv.enable = true; + }; + }; + } +#+end_src + +**** eza +:PROPERTIES: +:CUSTOM_ID: h:1bd6b0c7-f201-43e2-9624-6c50de00a1f6 +:END: + +Eza provides me with a better =ls= command and some other useful aliases. + +#+begin_src nix-ts :tangle modules/home/common/eza.nix + { lib, config, ... }: + { + options.swarselmodules.eza = lib.mkEnableOption "eza settings"; + config = lib.mkIf config.swarselmodules.eza { + programs.eza = { + enable = true; + icons = "auto"; + git = true; + extraOptions = [ + "-l" + "--group-directories-first" + ]; + }; + }; + } +#+end_src + +**** atuin +:PROPERTIES: +:CUSTOM_ID: h:38f127f3-003b-418b-85ba-a3bcf44bf16c +:END: + +#+begin_src nix-ts :tangle modules/home/common/atuin.nix + { lib, config, globals, ... }: + let + atuinDomain = globals.services.atuin.domain; + in + { + options.swarselmodules.atuin = lib.mkEnableOption "atuin settings"; + config = lib.mkIf config.swarselmodules.atuin { + programs.atuin = { + enable = true; + enableZshIntegration = true; + enableBashIntegration = true; + settings = { + auto_sync = true; + sync_frequency = "5m"; + sync_address = "https://${atuinDomain}"; + }; + }; + }; + } +#+end_src + +**** git +:PROPERTIES: +:CUSTOM_ID: h:419675ec-3310-438e-80ae-9eaa798a319d +:END: + +Here I set up my git config, automatic signing of commits, useful aliases for my ost used commands (for when I am not using [[#h:d2c7323d-f8c6-4f23-b70a-930e3e4ecce5][Magit]]) as well as a git template defined in [[#h:5ef03803-e150-41bc-b603-e80d60d96efc][Linking dotfiles]]. + +#+begin_src nix-ts :tangle modules/home/common/git.nix + { lib, config, globals, minimal, confLib, ... }: + let + inherit (confLib.getConfig.repo.secrets.common.mail) address1; + inherit (confLib.getConfig.repo.secrets.common) fullName; + + gitUser = globals.user.name; + in + { + options.swarselmodules.git = lib.mkEnableOption "git settings"; + config = lib.mkIf config.swarselmodules.git { + programs.git = { + enable = true; + } // lib.optionalAttrs (!minimal) { + settings = { + alias = { + a = "add"; + c = "commit"; + cl = "clone"; + co = "checkout"; + b = "branch"; + i = "init"; + m = "merge"; + s = "status"; + r = "restore"; + p = "pull"; + pp = "push"; + }; + user = { + email = lib.mkIf (config.swarselsystems.isNixos && !config.swarselsystems.isPublic) (lib.mkDefault address1); + name = lib.mkIf (config.swarselsystems.isNixos && !config.swarselsystems.isPublic) fullName; + }; + }; + signing = { + key = "0x76FD3810215AE097"; + signByDefault = true; + }; + lfs.enable = true; + includes = [ + { + contents = { + github = { + user = gitUser; + }; + commit = { + template = "~/.gitmessage"; + }; + }; + } + ]; + }; + programs.difftastic.enable = lib.mkIf (!minimal) true; + }; + } +#+end_src + +**** Fuzzel +:PROPERTIES: +:CUSTOM_ID: h:069cabf3-df14-49ba-8d17-75f2bcf34fbf +:END: + +Here I only need to set basic layout options - the rest is being managed by stylix. + +#+begin_src nix-ts :tangle modules/home/common/fuzzel.nix + { lib, config, ... }: + { + options.swarselmodules.fuzzel = lib.mkEnableOption "fuzzel settings"; + config = lib.mkIf config.swarselmodules.fuzzel { + programs.fuzzel = { + enable = true; + settings = { + main = { + layer = "overlay"; + lines = "10"; + width = "40"; + }; + border.radius = "0"; + }; + }; + }; + } +#+end_src + +**** Starship +:PROPERTIES: +:CUSTOM_ID: h:55212502-c8f6-43af-ae99-55c8377ef34e +:END: + +Starship makes my =zsh= look cooler! I have symbols for most programming languages and toolchains, also I build my own powerline. + +#+begin_src nix-ts :tangle modules/home/common/starship.nix + { lib, config, ... }: + { + options.swarselmodules.starship = lib.mkEnableOption "starship settings"; + config = lib.mkIf config.swarselmodules.starship { + programs.starship = { + enable = true; + enableZshIntegration = true; + settings = { + add_newline = false; + format = "$shlvl$character"; + right_format = "$all"; + command_timeout = 3000; + + directory.substitutions = { + "Documents" = "󰈙 "; + "Downloads" = " "; + "Music" = " "; + "Pictures" = " "; + }; + + git_status = { + style = "bg:#394260"; + format = "[[($all_status$ahead_behind)](fg:#769ff0 bg:#394260)]($style) "; + }; + + character = { + success_symbol = "[λ](bold green)"; + error_symbol = "[λ](bold red)"; + }; + + shlvl = { + disabled = false; + symbol = "↳"; + format = "[$symbol]($style) "; + repeat = true; + repeat_offset = 1; + style = "blue"; + }; + + nix_shell = { + disabled = false; + heuristic = true; + format = "[$symbol$name]($style)"; + symbol = " "; + }; + + aws.symbol = " "; + buf.symbol = " "; + c.symbol = " "; + conda.symbol = " "; + dart.symbol = " "; + directory.read_only = " 󰌾"; + docker_context.symbol = " "; + elixir.symbol = " "; + elm.symbol = " "; + fossil_branch.symbol = " "; + git_branch.symbol = " "; + golang.symbol = " "; + guix_shell.symbol = " "; + haskell.symbol = " "; + haxe.symbol = " "; + hg_branch.symbol = " "; + hostname.ssh_symbol = " "; + java.symbol = " "; + julia.symbol = " "; + lua.symbol = " "; + memory_usage.symbol = "󰍛 "; + meson.symbol = "󰔷 "; + nim.symbol = "󰆥 "; + nodejs.symbol = " "; + + os.symbols = { + Alpaquita = " "; + Alpine = " "; + Amazon = " "; + Android = " "; + Arch = " "; + Artix = " "; + CentOS = " "; + Debian = " "; + DragonFly = " "; + Emscripten = " "; + EndeavourOS = " "; + Fedora = " "; + FreeBSD = " "; + Garuda = "󰛓 "; + Gentoo = " "; + HardenedBSD = "󰞌 "; + Illumos = "󰈸 "; + Linux = " "; + Mabox = " "; + Macos = " "; + Manjaro = " "; + Mariner = " "; + MidnightBSD = " "; + Mint = " "; + NetBSD = " "; + NixOS = " "; + OpenBSD = "󰈺 "; + openSUSE = " "; + OracleLinux = "󰌷 "; + Pop = " "; + Raspbian = " "; + Redhat = " "; + RedHatEnterprise = " "; + Redox = "󰀘 "; + Solus = "󰠳 "; + SUSE = " "; + Ubuntu = " "; + Unknown = " "; + Windows = "󰍲 "; + }; + + package.symbol = "󰏗 "; + pijul_channel.symbol = " "; + python.symbol = " "; + rlang.symbol = "󰟔 "; + ruby.symbol = " "; + rust.symbol = " "; + scala.symbol = " "; + }; + }; + }; + } +#+end_src + +**** Kitty +:PROPERTIES: +:CUSTOM_ID: h:5f1287db-d2e8-49aa-8c58-730129c7795c +:END: + +Kitty is the terminal emulator of choice for me, it is nice to configure using nix, fast, and has a nice style. + +The theme is handled by stylix. + +#+begin_src nix-ts :tangle modules/home/common/kitty.nix + { lib, config, ... }: + { + options.swarselmodules.kitty = lib.mkEnableOption "kitty settings"; + config = lib.mkIf config.swarselmodules.kitty { + programs.kitty = { + enable = true; + keybindings = let + bindWithModifier = lib.mapAttrs' (key: lib.nameValuePair ("ctrl+shift" + key)); + in bindWithModifier { + "page_up" = "scroll_page_up"; + "up" = "scroll_page_up"; + "page_down" = "scroll_page_down"; + "down" = "scroll_page_down"; + "w" = "no_op"; + }; + settings = { + cursor_blink_interval = 0; + disable_ligatures = "cursor"; + enable_audio_bell = false; + notify_on_cmd_finish = "always 20"; + open_url_with = "xdg-open"; + scrollback_lines = 100000; + scrollback_pager_history_size = 512; + }; + }; + }; + } +#+end_src + +**** zsh +:PROPERTIES: +:CUSTOM_ID: h:91dd4cc4-aada-4e74-be23-0cc69ed85af5 +:END: + +zsh is the most convenient shell for me and it happens to be super neat to configure within home manager. + +Here we set some aliases (some of them should be shellApplications instead) as well as some zsh plugins like =fzf-tab=. +Concerning the shell extensions, =zle = will run an existing widget and =zle -N = will make a function available for use. The =my-= functions all remove =.= =/= and =:= from the =WORDCHARS= so that functions will stop there. The keycodes can be found using =showkeys -a= + +Regarding =initContent=: +To specify the order, use lib.mkOrder. + +Common order values: +- 500 (mkBefore: Early initialization (replaces initExtraFirst +- 550: Before completion initialization (replaces initExtraBeforeCompInit +- 1000 (default: General configuration (replaces initExtra +- 1500 (mkAfter: Last to run configuration + +To specify both content in Early initialization and General configuration, use lib.mkMerge: + +#+begin_src nix +initContent = let +zshConfigEarlyInit = lib.mkOrder 500 "do something"; +zshConfig = lib.mkOrder 1000 "do something"; +in +lib.mkMerge [ zshConfigEarlyInit zshConfig ]; +#+end_src + +Currently I only use it as before with =initExtra= though. + +#+begin_src nix-ts :tangle modules/home/common/zsh.nix + { config, pkgs, lib, minimal, inputs, globals, confLib, ... }: + let + inherit (config.swarselsystems) flakePath isNixos; + crocDomain = globals.services.croc.domain; + in + { + options.swarselmodules.zsh = lib.mkEnableOption "zsh settings"; + options.swarselsystems = { + shellAliases = lib.mkOption { + type = lib.types.attrsOf lib.types.str; + default = { }; + }; + }; + config = lib.mkIf config.swarselmodules.zsh + ({ + + programs.zsh = { + enable = true; + } + // lib.optionalAttrs (!minimal) { + shellAliases = lib.recursiveUpdate + { + hg = "history | grep"; + hmswitch = lib.mkIf (!isNixos) "${lib.getExe pkgs.home-manager} --flake ${flakePath}#$(hostname) switch |& nom"; + nswitch = lib.mkIf isNixos "cd ${flakePath}; swarsel-deploy $(hostname) switch; cd -;"; + ntest = lib.mkIf isNixos "cd ${flakePath}; swarsel-deploy $(hostname) test; cd -;"; + nboot = lib.mkIf isNixos "cd ${flakePath}; swarsel-deploy $(hostname) boot; cd -;"; + ndry = lib.mkIf isNixos "cd ${flakePath}; swarsel-deploy $(hostname) dry-activate; cd -;"; + magit = "emacsclient -nc -e \"(magit-status)\""; + config = "git --git-dir=$HOME/.cfg/ --work-tree=$HOME"; + g = "git"; + c = "git --git-dir=$FLAKE/.git --work-tree=$FLAKE/"; + passpush = "cd ~/.local/share/password-store; git add .; git commit -m 'pass file changes'; git push; cd -;"; + passpull = "cd ~/.local/share/password-store; git pull; cd -;"; + hotspot = "nmcli connection up local; nmcli device wifi hotspot;"; + youtube-dl = "yt-dlp"; + cat-orig = "cat"; + # cdr = "cd \"$( (find $DOCUMENT_DIR_WORK $DOCUMENT_DIR_PRIV -maxdepth 1 && echo $FLAKE) | fzf )\""; + cdr = "source cdr"; + nix-ldd-ldd = "LD_LIBRARY_PATH=$NIX_LD_LIBRARY_PATH ldd"; + nix-ldd = "LD_LIBRARY_PATH=$NIX_LD_LIBRARY_PATH ldd"; + nix-ldd-locate = "nix-locate --minimal --top-level -w "; + nix-store-search = "ls /nix/store | grep"; + fs-diff = "sudo mount -o subvol=/ /dev/mapper/cryptroot /mnt ; fs-diff"; + lt = "eza -las modified --total-size"; + boot-diff = "nix store diff-closures /run/*-system"; + gen-diff = "nix profile diff-closures --profile /nix/var/nix/profiles/system"; + cc = "wl-copy"; + build-topology = "nix build .#topology.x86_64-linux.config.output"; + build-iso = "nix build --print-out-paths .#live-iso"; + nix-review-local = "nix run nixpkgs#nixpkgs-review -- rev HEAD"; + nix-review-post = "nix run nixpkgs#nixpkgs-review -- pr --post-result --systems linux"; + } + config.swarselsystems.shellAliases; + autosuggestion.enable = true; + enableCompletion = true; + syntaxHighlighting.enable = true; + autocd = false; + cdpath = [ + "~/.dotfiles" + # "~/Documents/GitHub" + ]; + defaultKeymap = "emacs"; + dirHashes = { + dl = "$HOME/Downloads"; + gh = "$HOME/Documents/GitHub"; + }; + history = { + expireDuplicatesFirst = true; + append = true; + ignoreSpace = true; + ignoreDups = true; + path = "${config.home.homeDirectory}/.histfile"; + save = 100000; + size = 100000; + }; + historySubstringSearch = { + enable = true; + searchDownKey = "^[OB"; + searchUpKey = "^[OA"; + }; + plugins = [ + # { + # name = "fzf-tab"; + # src = pkgs.zsh-fzf-tab; + # } + ]; + initContent = '' + my-forward-word() { + local WORDCHARS=$WORDCHARS + WORDCHARS="''${WORDCHARS//:}" + WORDCHARS="''${WORDCHARS//\/}" + WORDCHARS="''${WORDCHARS//.}" + zle forward-word + } + zle -N my-forward-word + # ctrl + right + bindkey "^[[1;5C" my-forward-word + + # shift + right + bindkey "^[[1;2C" forward-word + + my-backward-word() { + local WORDCHARS=$WORDCHARS + WORDCHARS="''${WORDCHARS//:}" + WORDCHARS="''${WORDCHARS//\/}" + WORDCHARS="''${WORDCHARS//.}" + zle backward-word + } + zle -N my-backward-word + # ctrl + left + bindkey "^[[1;5D" my-backward-word + + # shift + left + bindkey "^[[1;2D" backward-word + + my-backward-delete-word() { + local WORDCHARS=$WORDCHARS + WORDCHARS="''${WORDCHARS//:}" + WORDCHARS="''${WORDCHARS//\/}" + WORDCHARS="''${WORDCHARS//.}" + zle backward-delete-word + } + zle -N my-backward-delete-word + # ctrl + del + bindkey '^H' my-backward-delete-word + ''; + sessionVariables = lib.mkIf (!config.swarselsystems.isPublic) { + CROC_RELAY = crocDomain; + CROC_PASS = "$(cat ${confLib.getConfig.sops.secrets.croc-password.path or ""})"; + GITHUB_TOKEN = "$(cat ${confLib.getConfig.sops.secrets.github-nixpkgs-review-token.path or ""})"; + QT_QPA_PLATFORM_PLUGIN_PATH = "${pkgs.libsForQt5.qt5.qtbase.bin}/lib/qt-${pkgs.libsForQt5.qt5.qtbase.version}/plugins"; + # QTWEBENGINE_CHROMIUM_FLAGS = "--no-sandbox"; + }; + }; + } // lib.optionalAttrs (inputs ? sops) { + + sops.secrets = lib.mkIf (!config.swarselsystems.isPublic && !config.swarselsystems.isNixos) { + croc-password = { }; + github-nixpkgs-review-token = { }; + }; + + }); + } +#+end_src + +**** bash +:PROPERTIES: +:CUSTOM_ID: h:ab30e218-665c-46ad-9708-9d92ebc34fed +:END: + + +#+begin_src nix-ts :tangle modules/home/common/bash.nix + { config, lib, ... }: + { + options.swarselmodules.bash = lib.mkEnableOption "bash settings"; + config = lib.mkIf config.swarselmodules.bash { + + programs.bash = { + enable = true; + # needed for remote builders + bashrcExtra = lib.mkIf (!config.swarselsystems.isNixos) '' + export PATH="/nix/var/nix/profiles/default/bin:$PATH" + ''; + historyFile = "${config.home.homeDirectory}/.histfile"; + historySize = 100000; + historyFileSize = 100000; + historyControl = [ + "ignoreboth" + ]; + }; + }; + } +#+end_src + +**** zellij +:PROPERTIES: +:CUSTOM_ID: h:87a28654-8377-41c9-8e6c-2d488e62575f +:END: +***** Main config +:PROPERTIES: +:CUSTOM_ID: h:00de4901-631c-4b4c-86ce-d9d6e62ed8c7 +:END: +#+begin_src nix-ts :tangle modules/home/common/zellij.nix + { self, lib, config, pkgs, ... }: + { + options.swarselmodules.zellij = lib.mkEnableOption "zellij settings"; + config = lib.mkIf config.swarselmodules.zellij { + programs.zellij = { + enable = true; + enableZshIntegration = true; + settings = { + pane_frames = false; + simplified_ui = false; + default_shell = "zsh"; + copy_on_select = true; + on_force_close = "detach"; + show_startup_tips = false; + support_kitty_keyboard_protocol = true; + default_layout = "swarsel"; + layout_dir = "${config.home.homeDirectory}/.config/zellij/layouts"; + theme_dir = "${config.home.homeDirectory}/.config/zellij/themes"; + scrollback_lines_to_serialize = config.programs.kitty.settings.scrollback_lines; + session_serialization = true; + + copy_command = + if pkgs.stdenv.hostPlatform.isLinux then + "wl-copy" + else if pkgs.stdenv.hostPlatform.isDarwin then + "pbcopy" + else + ""; + ui.pane_frames = { + rounded_corners = true; + hide_session_name = true; + }; + plugins = { + tab-bar.path = "tab-bar"; + status-bar.path = "status-bar"; + strider.path = "strider"; + compact-bar.path = "compact-bar"; + # configuration.path = "configuration"; + # filepicker.path = "strider"; + # plugin-manager.path = "plugin-manager"; + # session-manager.path = "session-manager"; + # welcome-screen.path = "session-manager"; + }; + }; + }; + + home.packages = with pkgs; [ + zjstatus + ]; + + xdg.configFile = { + # "zellij/config.kdl".text = import "${self}/files/zellij/config.kdl.nix" { inherit config; }; + "zellij/layouts/swarsel.kdl".text = import "${self}/files/zellij/layouts/swarsel.kdl.nix" { inherit config pkgs; }; + }; + }; + + } +#+end_src +***** Keybinds +:PROPERTIES: +:CUSTOM_ID: h:f65f9574-3b50-472d-8e24-2023271d1887 +:END: +#+begin_src nix-ts :tangle modules/home/common/zellij-keybinds.nix + { lib, config, ... }: + { + config = lib.mkIf config.swarselmodules.zellij { + programs.zellij = { + settings.keybinds = { + _props.clear-defaults = true; + + locked = { + _children = [ + { + bind = { + _args = [ "Ctrl g" ]; + _children = [{ SwitchToMode._args = [ "normal" ]; }]; + }; + } + ]; + }; + + pane = { + _children = [ + { + bind = { + _args = [ "Ctrl p" ]; + _children = [{ SwitchToMode._args = [ "normal" ]; }]; + }; + } + { + bind = { + _args = [ "left" ]; + _children = [{ MoveFocus._args = [ "left" ]; }]; + }; + } + { + bind = { + _args = [ "down" ]; + _children = [{ MoveFocus._args = [ "down" ]; }]; + }; + } + { + bind = { + _args = [ "up" ]; + _children = [{ MoveFocus._args = [ "up" ]; }]; + }; + } + { + bind = { + _args = [ "right" ]; + _children = [{ MoveFocus._args = [ "right" ]; }]; + }; + } + { + bind = { + _args = [ "h" ]; + _children = [{ MoveFocus._args = [ "left" ]; }]; + }; + } + { + bind = { + _args = [ "j" ]; + _children = [{ MoveFocus._args = [ "down" ]; }]; + }; + } + { + bind = { + _args = [ "k" ]; + _children = [{ MoveFocus._args = [ "up" ]; }]; + }; + } + { + bind = { + _args = [ "l" ]; + _children = [{ MoveFocus._args = [ "right" ]; }]; + }; + } + { + bind = { + _args = [ "d" ]; + _children = [ + { NewPane._args = [ "down" ]; } + { SwitchToMode._args = [ "normal" ]; } + ]; + }; + } + { + bind = { + _args = [ "e" ]; + _children = [ + { TogglePaneEmbedOrFloating = { }; } + { SwitchToMode._args = [ "normal" ]; } + ]; + }; + } + { + bind = { + _args = [ "f" ]; + _children = [ + { ToggleFocusFullscreen = { }; } + { SwitchToMode._args = [ "normal" ]; } + ]; + }; + } + { + bind = { + _args = [ "n" ]; + _children = [ + { NewPane = { }; } + { SwitchToMode._args = [ "normal" ]; } + ]; + }; + } + { + bind = { + _args = [ "p" ]; + _children = [{ SwitchFocus = { }; }]; + }; + } + { + bind = { + _args = [ "f12" ]; + _children = [ + { ToggleFloatingPanes = { }; } + { SwitchToMode._args = [ "normal" ]; } + ]; + }; + } + ]; + }; + + tab = { + _children = [ + { + bind = { + _args = [ "Ctrl t" ]; + _children = [{ SwitchToMode._args = [ "normal" ]; }]; + }; + } + { + bind = { + _args = [ "left" ]; + _children = [{ GoToPreviousTab = { }; }]; + }; + } + { + bind = { + _args = [ "down" ]; + _children = [{ GoToNextTab = { }; }]; + }; + } + { + bind = { + _args = [ "up" ]; + _children = [{ GoToPreviousTab = { }; }]; + }; + } + { + bind = { + _args = [ "right" ]; + _children = [{ GoToNextTab = { }; }]; + }; + } + { + bind = { + _args = [ "1" ]; + _children = [ + { GoToTab._args = [ 1 ]; } + { SwitchToMode._args = [ "normal" ]; } + ]; + }; + } + { + bind = { + _args = [ "2" ]; + _children = [ + { GoToTab._args = [ 2 ]; } + { SwitchToMode._args = [ "normal" ]; } + ]; + }; + } + { + bind = { + _args = [ "3" ]; + _children = [ + { GoToTab._args = [ 3 ]; } + { SwitchToMode._args = [ "normal" ]; } + ]; + }; + } + { + bind = { + _args = [ "4" ]; + _children = [ + { GoToTab._args = [ 4 ]; } + { SwitchToMode._args = [ "normal" ]; } + ]; + }; + } + { + bind = { + _args = [ "5" ]; + _children = [ + { GoToTab._args = [ 5 ]; } + { SwitchToMode._args = [ "normal" ]; } + ]; + }; + } + { + bind = { + _args = [ "6" ]; + _children = [ + { GoToTab._args = [ 6 ]; } + { SwitchToMode._args = [ "normal" ]; } + ]; + }; + } + { + bind = { + _args = [ "7" ]; + _children = [ + { GoToTab._args = [ 7 ]; } + { SwitchToMode._args = [ "normal" ]; } + ]; + }; + } + { + bind = { + _args = [ "8" ]; + _children = [ + { GoToTab._args = [ 8 ]; } + { SwitchToMode._args = [ "normal" ]; } + ]; + }; + } + { + bind = { + _args = [ "9" ]; + _children = [ + { GoToTab._args = [ 9 ]; } + { SwitchToMode._args = [ "normal" ]; } + ]; + }; + } + { + bind = { + _args = [ "h" ]; + _children = [{ GoToPreviousTab = { }; }]; + }; + } + { + bind = { + _args = [ "j" ]; + _children = [{ GoToNextTab = { }; }]; + }; + } + { + bind = { + _args = [ "k" ]; + _children = [{ GoToPreviousTab = { }; }]; + }; + } + { + bind = { + _args = [ "l" ]; + _children = [{ GoToNextTab = { }; }]; + }; + } + { + bind = { + _args = [ "n" ]; + _children = [ + { NewTab = { }; } + { SwitchToMode._args = [ "normal" ]; } + ]; + }; + } + { + bind = { + _args = [ "r" ]; + _children = [ + { SwitchToMode._args = [ "renametab" ]; } + { TabNameInput._args = [ 0 ]; } + ]; + }; + } + { + bind = { + _args = [ "s" ]; + _children = [ + { ToggleActiveSyncTab = { }; } + { SwitchToMode._args = [ "normal" ]; } + ]; + }; + } + { + bind = { + _args = [ "x" ]; + _children = [ + { CloseTab = { }; } + { SwitchToMode._args = [ "normal" ]; } + ]; + }; + } + ]; + }; + + resize = { + _children = [ + { + bind = { + _args = [ "Ctrl n" ]; + _children = [{ SwitchToMode._args = [ "normal" ]; }]; + }; + } + { + bind = { + _args = [ "left" ]; + _children = [{ Resize._args = [ "Increase left" ]; }]; + }; + } + { + bind = { + _args = [ "down" ]; + _children = [{ Resize._args = [ "Increase down" ]; }]; + }; + } + { + bind = { + _args = [ "up" ]; + _children = [{ Resize._args = [ "Increase up" ]; }]; + }; + } + { + bind = { + _args = [ "right" ]; + _children = [{ Resize._args = [ "Increase right" ]; }]; + }; + } + { + bind = { + _args = [ "+" ]; + _children = [{ Resize._args = [ "Increase" ]; }]; + }; + } + { + bind = { + _args = [ "-" ]; + _children = [{ Resize._args = [ "Decrease" ]; }]; + }; + } + { + bind = { + _args = [ "=" ]; + _children = [{ Resize._args = [ "Increase" ]; }]; + }; + } + { + bind = { + _args = [ "H" ]; + _children = [{ Resize._args = [ "Decrease left" ]; }]; + }; + } + { + bind = { + _args = [ "J" ]; + _children = [{ Resize._args = [ "Decrease down" ]; }]; + }; + } + { + bind = { + _args = [ "K" ]; + _children = [{ Resize._args = [ "Decrease up" ]; }]; + }; + } + { + bind = { + _args = [ "L" ]; + _children = [{ Resize._args = [ "Decrease right" ]; }]; + }; + } + { + bind = { + _args = [ "h" ]; + _children = [{ Resize._args = [ "Increase left" ]; }]; + }; + } + { + bind = { + _args = [ "j" ]; + _children = [{ Resize._args = [ "Increase down" ]; }]; + }; + } + { + bind = { + _args = [ "k" ]; + _children = [{ Resize._args = [ "Increase up" ]; }]; + }; + } + { + bind = { + _args = [ "l" ]; + _children = [{ Resize._args = [ "Increase right" ]; }]; + }; + } + ]; + }; + + move = { + _children = [ + { + bind = { + _args = [ "Ctrl h" ]; + _children = [{ SwitchToMode._args = [ "normal" ]; }]; + }; + } + { + bind = { + _args = [ "left" ]; + _children = [{ MovePane._args = [ "left" ]; }]; + }; + } + { + bind = { + _args = [ "down" ]; + _children = [{ MovePane._args = [ "down" ]; }]; + }; + } + { + bind = { + _args = [ "up" ]; + _children = [{ MovePane._args = [ "up" ]; }]; + }; + } + { + bind = { + _args = [ "right" ]; + _children = [{ MovePane._args = [ "right" ]; }]; + }; + } + { + bind = { + _args = [ "h" ]; + _children = [{ MovePane._args = [ "left" ]; }]; + }; + } + { + bind = { + _args = [ "j" ]; + _children = [{ MovePane._args = [ "down" ]; }]; + }; + } + { + bind = { + _args = [ "k" ]; + _children = [{ MovePane._args = [ "up" ]; }]; + }; + } + { + bind = { + _args = [ "l" ]; + _children = [{ MovePane._args = [ "right" ]; }]; + }; + } + ]; + }; + + scroll = { + _children = [ + { + bind = { + _args = [ "e" ]; + _children = [ + { EditScrollback = { }; } + { SwitchToMode._args = [ "normal" ]; } + ]; + }; + } + { + bind = { + _args = [ "s" ]; + _children = [ + { SwitchToMode._args = [ "entersearch" ]; } + { SearchInput._args = [ 0 ]; } + ]; + }; + } + ]; + }; + + search = { + _children = [ + { + bind = { + _args = [ "c" ]; + _children = [{ SearchToggleOption._args = [ "CaseSensitivity" ]; }]; + }; + } + { + bind = { + _args = [ "n" ]; + _children = [{ Search._args = [ "down" ]; }]; + }; + } + { + bind = { + _args = [ "o" ]; + _children = [{ SearchToggleOption._args = [ "WholeWord" ]; }]; + }; + } + { + bind = { + _args = [ "p" ]; + _children = [{ Search._args = [ "up" ]; }]; + }; + } + { + bind = { + _args = [ "w" ]; + _children = [{ SearchToggleOption._args = [ "Wrap" ]; }]; + }; + } + ]; + }; + + session = { + _children = [ + { + bind = { + _args = [ "Ctrl o" ]; + _children = [{ SwitchToMode._args = [ "normal" ]; }]; + }; + } + { + bind = { + _args = [ "c" ]; + _children = [ + { + LaunchOrFocusPlugin._args = [ "configuration" ]; + LaunchOrFocusPlugin._children = [ + { floating._args = [ true ]; } + { move_to_focused_tab._args = [ true ]; } + ]; + } + { SwitchToMode._args = [ "normal" ]; } + ]; + }; + } + { + bind = { + _args = [ "p" ]; + _children = [ + { + LaunchOrFocusPlugin._args = [ "plugin-manager" ]; + LaunchOrFocusPlugin._children = [ + { floating._args = [ true ]; } + { move_to_focused_tab._args = [ true ]; } + ]; + } + { SwitchToMode._args = [ "normal" ]; } + ]; + }; + } + { + bind = { + _args = [ "w" ]; + _children = [ + { + LaunchOrFocusPlugin._args = [ "session-manager" ]; + LaunchOrFocusPlugin._children = [ + { floating._args = [ true ]; } + { move_to_focused_tab._args = [ true ]; } + ]; + } + { SwitchToMode._args = [ "normal" ]; } + ]; + }; + } + ]; + }; + + "shared_except \"locked\"" = { + _children = [ + { + bind = { + _args = [ "Alt left" ]; + _children = [{ MoveFocusOrTab._args = [ "left" ]; }]; + }; + } + { + bind = { + _args = [ "Alt down" ]; + _children = [{ MoveFocus._args = [ "down" ]; }]; + }; + } + { + bind = { + _args = [ "Alt up" ]; + _children = [{ MoveFocus._args = [ "up" ]; }]; + }; + } + { + bind = { + _args = [ "Alt right" ]; + _children = [{ MoveFocusOrTab._args = [ "right" ]; }]; + }; + } + { + bind = { + _args = [ "Alt +" ]; + _children = [{ Resize._args = [ "Increase" ]; }]; + }; + } + { + bind = { + _args = [ "Alt -" ]; + _children = [{ Resize._args = [ "Decrease" ]; }]; + }; + } + { + bind = { + _args = [ "Alt =" ]; + _children = [{ Resize._args = [ "Increase" ]; }]; + }; + } + { + bind = { + _args = [ "Alt r" ]; + _children = [ + { + WriteChars._args = [ "source cdr" ]; + } + { + WriteChars._args = [ "\n" ]; + } + ]; + }; + } + { + bind = { + _args = [ "Alt f" ]; + _children = [{ ToggleFloatingPanes = { }; }]; + }; + } + { + bind = { + _args = [ "Ctrl g" ]; + _children = [{ SwitchToMode._args = [ "locked" ]; }]; + }; + } + { + bind = { + _args = [ "Alt h" ]; + _children = [{ MoveFocusOrTab._args = [ "left" ]; }]; + }; + } + { + bind = { + _args = [ "Alt i" ]; + _children = [{ MoveTab._args = [ "left" ]; }]; + }; + } + { + bind = { + _args = [ "Alt j" ]; + _children = [{ MoveFocus._args = [ "down" ]; }]; + }; + } + { + bind = { + _args = [ "Alt k" ]; + _children = [{ MoveFocus._args = [ "up" ]; }]; + }; + } + { + bind = { + _args = [ "Alt p" ]; + _children = [{ NewPane = { }; }]; + }; + } + { + bind = { + _args = [ "Alt n" ]; + _children = [{ NewTab = { }; }]; + }; + } + ]; + }; + + "shared_except \"locked\" \"move\"" = { + _children = [ + { + bind = { + _args = [ "Ctrl h" ]; + _children = [{ SwitchToMode._args = [ "move" ]; }]; + }; + } + ]; + }; + + "shared_except \"locked\" \"session\"" = { + _children = [ + { + bind = { + _args = [ "Ctrl o" ]; + _children = [{ SwitchToMode._args = [ "session" ]; }]; + }; + } + ]; + }; + + "shared_except \"locked\" \"scroll\" \"search\" \"tmux\"" = { + _children = [ + { + bind = { + _args = [ "Ctrl b" ]; + _children = [{ SwitchToMode._args = [ "tmux" ]; }]; + }; + } + ]; + }; + + "shared_except \"locked\" \"scroll\" \"search\"" = { + _children = [ + { + bind = { + _args = [ "Ctrl s" ]; + _children = [{ SwitchToMode._args = [ "scroll" ]; }]; + }; + } + ]; + }; + + "shared_except \"locked\" \"tab\"" = { + _children = [ + { + bind = { + _args = [ "Ctrl t" ]; + _children = [{ SwitchToMode._args = [ "tab" ]; }]; + }; + } + ]; + }; + + "shared_except \"locked\" \"pane\"" = { + _children = [ + { + bind = { + _args = [ "Ctrl p" ]; + _children = [{ SwitchToMode._args = [ "pane" ]; }]; + }; + } + ]; + }; + + "shared_except \"locked\" \"resize\"" = { + _children = [ + { + bind = { + _args = [ "Ctrl n" ]; + _children = [{ SwitchToMode._args = [ "resize" ]; }]; + }; + } + ]; + }; + + "shared_except \"normal\" \"locked\" \"entersearch\"" = { + _children = [ + { + bind = { + _args = [ "enter" ]; + _children = [{ SwitchToMode._args = [ "normal" ]; }]; + }; + } + ]; + }; + + "shared_except \"normal\" \"locked\" \"entersearch\" \"renametab\" \"renamepane\"" = { + _children = [ + { + bind = { + _args = [ "esc" ]; + _children = [{ SwitchToMode._args = [ "normal" ]; }]; + }; + } + ]; + }; + + "shared_among \"pane\" \"tmux\"" = { + _children = [ + { + bind = { + _args = [ "x" ]; + _children = [ + { CloseFocus = { }; } + { SwitchToMode._args = [ "normal" ]; } + ]; + }; + } + ]; + }; + + "shared_among \"scroll\" \"search\"" = { + _children = [ + { + bind = { + _args = [ "PageDown" ]; + _children = [{ PageScrollDown = { }; }]; + }; + } + { + bind = { + _args = [ "PageUp" ]; + _children = [{ PageScrollUp = { }; }]; + }; + } + { + bind = { + _args = [ "left" ]; + _children = [{ PageScrollUp = { }; }]; + }; + } + { + bind = { + _args = [ "down" ]; + _children = [{ ScrollDown = { }; }]; + }; + } + { + bind = { + _args = [ "up" ]; + _children = [{ ScrollUp = { }; }]; + }; + } + { + bind = { + _args = [ "right" ]; + _children = [{ PageScrollDown = { }; }]; + }; + } + { + bind = { + _args = [ "Ctrl b" ]; + _children = [{ PageScrollUp = { }; }]; + }; + } + { + bind = { + _args = [ "Ctrl c" ]; + _children = [ + { ScrollToBottom = { }; } + { SwitchToMode._args = [ "normal" ]; } + ]; + }; + } + { + bind = { + _args = [ "d" ]; + _children = [{ HalfPageScrollDown = { }; }]; + }; + } + { + bind = { + _args = [ "Ctrl f" ]; + _children = [{ PageScrollDown = { }; }]; + }; + } + { + bind = { + _args = [ "h" ]; + _children = [{ PageScrollUp = { }; }]; + }; + } + { + bind = { + _args = [ "j" ]; + _children = [{ ScrollDown = { }; }]; + }; + } + { + bind = { + _args = [ "k" ]; + _children = [{ ScrollUp = { }; }]; + }; + } + { + bind = { + _args = [ "l" ]; + _children = [{ PageScrollDown = { }; }]; + }; + } + { + bind = { + _args = [ "Ctrl s" ]; + _children = [{ SwitchToMode._args = [ "normal" ]; }]; + }; + } + { + bind = { + _args = [ "u" ]; + _children = [{ HalfPageScrollUp = { }; }]; + }; + } + ]; + }; + + entersearch = { + _children = [ + { + bind = { + _args = [ "Ctrl c" ]; + _children = [{ SwitchToMode._args = [ "scroll" ]; }]; + }; + } + { + bind = { + _args = [ "esc" ]; + _children = [{ SwitchToMode._args = [ "scroll" ]; }]; + }; + } + { + bind = { + _args = [ "enter" ]; + _children = [{ SwitchToMode._args = [ "search" ]; }]; + }; + } + ]; + }; + + renametab = { + _children = [ + { + bind = { + _args = [ "esc" ]; + _children = [ + { UndoRenameTab = { }; } + { SwitchToMode._args = [ "tab" ]; } + ]; + }; + } + ]; + }; + + "shared_among \"renametab\" \"renamepane\"" = { + _children = [ + { + bind = { + _args = [ "Ctrl c" ]; + _children = [{ SwitchToMode._args = [ "normal" ]; }]; + }; + } + ]; + }; + + renamepane = { + _children = [ + { + bind = { + _args = [ "esc" ]; + _children = [ + { UndoRenamePane = { }; } + { SwitchToMode._args = [ "pane" ]; } + ]; + }; + } + ]; + }; + + "shared_among \"session\" \"tmux\"" = { + _children = [ + { + bind = { + _args = [ "d" ]; + _children = [{ Detach = { }; }]; + }; + } + ]; + }; + + tmux = { + _children = [ + { + bind = { + _args = [ "left" ]; + _children = [ + { MoveFocus._args = [ "left" ]; } + { SwitchToMode._args = [ "normal" ]; } + ]; + }; + } + { + bind = { + _args = [ "down" ]; + _children = [ + { MoveFocus._args = [ "down" ]; } + { SwitchToMode._args = [ "normal" ]; } + ]; + }; + } + { + bind = { + _args = [ "up" ]; + _children = [ + { MoveFocus._args = [ "up" ]; } + { SwitchToMode._args = [ "normal" ]; } + ]; + }; + } + { + bind = { + _args = [ "right" ]; + _children = [ + { MoveFocus._args = [ "right" ]; } + { SwitchToMode._args = [ "normal" ]; } + ]; + }; + } + { + bind = { + _args = [ "space" ]; + _children = [{ NextSwapLayout = { }; }]; + }; + } + { + bind = { + _args = [ "\"" ]; + _children = [ + { NewPane._args = [ "down" ]; } + { SwitchToMode._args = [ "normal" ]; } + ]; + }; + } + { + bind = { + _args = [ "%" ]; + _children = [ + { NewPane._args = [ "right" ]; } + { SwitchToMode._args = [ "normal" ]; } + ]; + }; + } + { + bind = { + _args = [ "," ]; + _children = [{ SwitchToMode._args = [ "renametab" ]; }]; + }; + } + { + bind = { + _args = [ "[" ]; + _children = [{ SwitchToMode._args = [ "scroll" ]; }]; + }; + } + { + bind = { + _args = [ "Ctrl b" ]; + _children = [ + { Write._args = [ 2 ]; } + { SwitchToMode._args = [ "normal" ]; } + ]; + }; + } + { + bind = { + _args = [ "c" ]; + _children = [ + { NewTab = { }; } + { SwitchToMode._args = [ "normal" ]; } + ]; + }; + } + { + bind = { + _args = [ "h" ]; + _children = [ + { MoveFocus._args = [ "left" ]; } + { SwitchToMode._args = [ "normal" ]; } + ]; + }; + } + { + bind = { + _args = [ "j" ]; + _children = [ + { MoveFocus._args = [ "down" ]; } + { SwitchToMode._args = [ "normal" ]; } + ]; + }; + } + { + bind = { + _args = [ "k" ]; + _children = [ + { MoveFocus._args = [ "up" ]; } + { SwitchToMode._args = [ "normal" ]; } + ]; + }; + } + { + bind = { + _args = [ "l" ]; + _children = [ + { MoveFocus._args = [ "right" ]; } + { SwitchToMode._args = [ "normal" ]; } + ]; + }; + } + { + bind = { + _args = [ "n" ]; + _children = [ + { GoToNextTab = { }; } + { SwitchToMode._args = [ "normal" ]; } + ]; + }; + } + { + bind = { + _args = [ "o" ]; + _children = [{ FocusNextPane = { }; }]; + }; + } + { + bind = { + _args = [ "p" ]; + _children = [ + { GoToPreviousTab = { }; } + { SwitchToMode._args = [ "normal" ]; } + ]; + }; + } + { + bind = { + _args = [ "z" ]; + _children = [ + { ToggleFocusFullscreen = { }; } + { SwitchToMode._args = [ "normal" ]; } + ]; + }; + } + ]; + }; + }; + }; + }; + + } +#+end_src +**** tmux +:PROPERTIES: +:CUSTOM_ID: h:45de9430-f925-4df6-9db6-bffb5b8f1604 +:END: +#+begin_src nix-ts :tangle modules/home/common/tmux.nix + { lib, config, pkgs, ... }: + let + tmux-super-fingers = pkgs.tmuxPlugins.mkTmuxPlugin + { + pluginName = "tmux-super-fingers"; + version = "unstable-2023-01-06"; + src = pkgs.fetchFromGitHub { + owner = "artemave"; + repo = "tmux_super_fingers"; + rev = "2c12044984124e74e21a5a87d00f844083e4bdf7"; + sha256 = "sha256-cPZCV8xk9QpU49/7H8iGhQYK6JwWjviL29eWabuqruc="; + }; + }; + in + { + options.swarselmodules.tmux = lib.mkEnableOption "tmux settings"; + config = lib.mkIf config.swarselmodules.tmux { + home.packages = with pkgs; [ + lsof + sesh + ]; + + programs.tmux = { + enable = true; + shell = "${pkgs.zsh}/bin/zsh"; + terminal = "tmux-256color"; + historyLimit = 100000; + plugins = with pkgs; + [ + tmuxPlugins.tmux-thumbs + { + plugin = tmux-super-fingers; + extraConfig = "set -g @super-fingers-key f"; + } + + tmuxPlugins.sensible + # must be before continuum edits right status bar + { + plugin = tmuxPlugins.catppuccin; + extraConfig = '' + set -g @catppuccin_flavour 'frappe' + set -g @catppuccin_window_tabs_enabled on + set -g @catppuccin_date_time "%H:%M" + ''; + } + { + plugin = tmuxPlugins.resurrect; + extraConfig = '' + set -g @resurrect-strategy-vim 'session' + set -g @resurrect-strategy-nvim 'session' + set -g @resurrect-capture-pane-contents 'on' + ''; + } + { + plugin = tmuxPlugins.continuum; + extraConfig = '' + set -g @continuum-restore 'on' + set -g @continuum-boot 'on' + set -g @continuum-save-interval '10' + ''; + } + tmuxPlugins.better-mouse-mode + tmuxPlugins.yank + ]; + extraConfig = '' + set -g default-terminal "tmux-256color" + set -ag terminal-overrides ",xterm-256color:RGB" + + set-option -g prefix C-a + unbind-key C-b + bind-key C-a send-prefix + + set -g mouse on + + # Open new split at cwd of current split + bind | split-window -h -c "#{pane_current_path}" + bind - split-window -v -c "#{pane_current_path}" + + # Use vim keybindings in copy mode + set-window-option -g mode-keys vi + + # v in copy mode starts making selection + bind-key -T copy-mode-vi v send-keys -X begin-selection + bind-key -T copy-mode-vi C-v send-keys -X rectangle-toggle + bind-key -T copy-mode-vi y send-keys -X copy-selection-and-cancel + + # Escape turns on copy mode + bind Escape copy-mode + + set-option -g status-position top + + # make Prefix p paste the buffer. + unbind p + bind p paste-buffer + + ''; + }; + }; + } + + +#+end_src +**** Mail +:PROPERTIES: +:CUSTOM_ID: h:506d01fc-c20b-473a-ac78-bce4b53fe0e3 +:END: + +Normally I use 4 mail accounts - here I set them all up. Three of them are Google accounts (sadly), which are a chore to setup. The last is just a sender account that I setup SMTP for here. + +#+begin_src nix-ts :tangle modules/home/common/mail.nix + { lib, config, inputs, globals, confLib, ... }: + let + inherit (confLib.getConfig.repo.secrets.common.mail) address1 address2 address2-name address3 address3-name address4; + inherit (confLib.getConfig.repo.secrets.common) fullName; + inherit (config.swarselsystems) xdgDir; + in + { + options.swarselmodules.mail = lib.mkEnableOption "mail settings"; + config = lib.mkIf config.swarselmodules.mail + ({ + + programs = { + mbsync = { + enable = true; + }; + msmtp = { + enable = true; + }; + mu = { + enable = true; + }; + }; + + services.mbsync = { + enable = true; + }; + # this is needed so that mbsync can use the passwords from sops + systemd.user.services.mbsync.Unit.After = [ "sops-nix.service" ]; + + programs.thunderbird = { + enable = true; + profiles.default = { + isDefault = true; + withExternalGnupg = true; + settings = { + "mail.identity.default.archive_enabled" = true; + "mail.identity.default.archive_keep_folder_structure" = true; + "mail.identity.default.compose_html" = false; + "mail.identity.default.protectSubject" = true; + "mail.identity.default.reply_on_top" = 1; + "mail.identity.default.sig_on_reply" = false; + "mail.identity.default.sig_bottom" = false; + + "gfx.webrender.all" = true; + "gfx.webrender.enabled" = true; + }; + }; + + settings = { + "mail.server.default.allow_utf8_accept" = true; + "mail.server.default.max_articles" = 1000; + "mail.server.default.check_all_folders_for_new" = true; + "mail.show_headers" = 1; + "mail.identity.default.auto_quote" = true; + "mail.identity.default.attachPgpKey" = true; + "mailnews.default_sort_order" = 2; + "mailnews.default_sort_type" = 18; + "mailnews.default_view_flags" = 0; + "mailnews.sort_threads_by_root" = true; + "mailnews.headers.showMessageId" = true; + "mailnews.headers.showOrganization" = true; + "mailnews.headers.showReferences" = true; + "mailnews.headers.showUserAgent" = true; + "mail.imap.expunge_after_delete" = true; + "mail.server.default.delete_model" = 2; + "mail.warn_on_delete_from_trash" = false; + "mail.warn_on_shift_delete" = false; + "toolkit.telemetry.enabled" = false; + "toolkit.telemetry.rejected" = true; + "toolkit.telemetry.prompted" = 2; + "app.update.auto" = false; + "privacy.donottrackheader.enabled" = true; + }; + }; + + xdg.mimeApps.defaultApplications = { + "x-scheme-handler/mailto" = [ "thunderbird.desktop" ]; + "x-scheme-handler/mid" = [ "thunderbird.desktop" ]; + "message/rfc822" = [ "thunderbird.desktop" ]; + }; + + accounts = lib.mkIf (config.swarselsystems.isNixos && !config.swarselsystems.isPublic) { + email = + let + defaultSettings = { + imap = { + host = "imap.gmail.com"; + port = 993; + tls.enable = true; # SSL/TLS + }; + smtp = { + host = "smtp.gmail.com"; + port = 465; + tls.enable = true; # SSL/TLS + }; + thunderbird = { + enable = true; + profiles = [ "default" ]; + }; + mu.enable = true; + msmtp = { + enable = true; + }; + mbsync = { + enable = true; + create = "maildir"; + expunge = "both"; + patterns = [ "*" "![Gmail]*" "[Gmail]/Sent Mail" "[Gmail]/Starred" "[Gmail]/All Mail" ]; + extraConfig = { + channel = { + Sync = "All"; + }; + account = { + Timeout = 120; + PipelineDepth = 1; + AuthMechs = "LOGIN"; + }; + }; + }; + }; + in + { + maildirBasePath = "Mail"; + accounts = { + swarsel = { + imap = { + host = globals.services.mailserver.domain; + port = 993; + tls.enable = true; # SSL/TLS + }; + smtp = { + host = globals.services.mailserver.domain; + port = 465; + tls.enable = true; # SSL/TLS + }; + thunderbird = { + enable = true; + profiles = [ "default" ]; + }; + address = address4; + userName = address4; + realName = fullName; + passwordCommand = "cat ${confLib.getConfig.sops.secrets.address4-token.path}"; + mu.enable = true; + msmtp = { + enable = true; + }; + mbsync = { + enable = true; + create = "maildir"; + expunge = "both"; + patterns = [ "*" ]; + extraConfig = { + channel = { + Sync = "All"; + }; + account = { + Timeout = 120; + PipelineDepth = 1; + AuthMechs = "LOGIN"; + }; + }; + }; + }; + + leon = lib.recursiveUpdate + { + primary = true; + address = address1; + userName = address1; + realName = fullName; + passwordCommand = "cat ${confLib.getConfig.sops.secrets.address1-token.path}"; + gpg = { + key = "0x76FD3810215AE097"; + signByDefault = true; + }; + } + defaultSettings; + + nautilus = lib.recursiveUpdate + { + primary = false; + address = address2; + userName = address2; + realName = address2-name; + passwordCommand = "cat ${confLib.getConfig.sops.secrets.address2-token.path}"; + } + defaultSettings; + + mrswarsel = lib.recursiveUpdate + { + primary = false; + address = address3; + userName = address3; + realName = address3-name; + passwordCommand = "cat ${confLib.getConfig.sops.secrets.address3-token.path}"; + } + defaultSettings; + + }; + }; + }; + } // lib.optionalAttrs (inputs ? sops) { + sops.secrets = lib.mkIf (!config.swarselsystems.isPublic && !config.swarselsystems.isNixos) { + address1-token = { path = "${xdgDir}/secrets/address1-token"; }; + address2-token = { path = "${xdgDir}/secrets/address2-token"; }; + address3-token = { path = "${xdgDir}/secrets/address3-token"; }; + address4-token = { path = "${xdgDir}/secrets/address4-token"; }; + }; + }); + } +#+end_src + +**** Home-manager: Emacs +:PROPERTIES: +:CUSTOM_ID: h:c05d1b64-7110-4151-b436-46bc447113b4 +:END: + +By using the emacs-overlay NixOS module, I can install all Emacs packages that I want to use right through NixOS. This is done by passing my =init.el= file to the configuration which will then be parsed upon system rebuild, looking for =use-package= sections in the Elisp code. Also I define here the style of Emacs that I want to run - I am going with native Wayland Emacs here (=emacs-pgtk=). All of the nice options such as =tree-sitter= support are enabled by default, so I do not need to adjust the build process. + +Lastly, I am defining some more packages here that the parser has problems finding. Also there are some packages that are not in ELPA or MELPA that I still want to use, like =calfw= and =fast-scroll=, so I build them here. + +#+begin_src nix-ts :tangle modules/home/common/emacs.nix + { self, lib, config, pkgs, globals, inputs, ... }: + let + inherit (config.swarselsystems) homeDir mainUser isPublic isNixos; + inherit (config.repo.secrets.common.emacs) radicaleUser; + in + { + options.swarselmodules.emacs = lib.mkEnableOption "emacs settings"; + config = lib.mkIf config.swarselmodules.emacs ({ + # needed for elfeed + # enable emacs overlay for bleeding edge features + # also read init.el file and install use-package packages + + home.activation.setupEmacsOrgFiles = + lib.hm.dag.entryAfter [ "writeBoundary" ] '' + set -eu + + if [ ! -d ${homeDir}/Org ]; then + ${pkgs.coreutils}/bin/install -d -m 0755 ${homeDir}/Org + ${pkgs.coreutils}/bin/chown ${mainUser}:syncthing ${homeDir}/Org + fi + + # create dummy files to make Emacs calendar work + # these have low modified dates and should be marked as sync-conflicts + for file in "Tasks" "Archive" "Journal"; do + if [ ! -f ${homeDir}/Org/"$file".org ]; then + ${pkgs.coreutils}/bin/touch --time=access --time=modify -t 197001010000.00 ${homeDir}/Org/"$file".org + ${pkgs.coreutils}/bin/chown ${mainUser}:syncthing ${homeDir}/Org/"$file".org + fi + done + + # when the configuration is build again, these sync-conflicts will be cleaned up + for file in $(find ${homeDir}/Org/ -name "*sync-conflict*"); do + ${pkgs.coreutils}/bin/rm "$file" + done + ''; + + programs.emacs = { + enable = true; + package = pkgs.emacsWithPackagesFromUsePackage { + config = self + /files/emacs/init.el; + package = pkgs.emacs-git-pgtk; + alwaysEnsure = true; + alwaysTangle = true; + extraEmacsPackages = epkgs: [ + epkgs.mu4e + epkgs.use-package + epkgs.lsp-bridge + epkgs.doom-themes + epkgs.vterm + # pkgs.stable.emacs.pkgs.elpaPackages.tramp # use the unstable version from elpa + epkgs.treesit-grammars.with-all-grammars + + # build the rest of the packages myself + # org-calfw is severely outdated on MELPA and throws many warnings on emacs startup + # build the package from the haji-ali fork, which is well-maintained + + (epkgs.trivialBuild rec { + pname = "eglot-booster"; + version = "main-29-10-2024"; + + src = pkgs.fetchFromGitHub { + owner = "jdtsmith"; + repo = "eglot-booster"; + rev = "e6daa6bcaf4aceee29c8a5a949b43eb1b89900ed"; + hash = "sha256-PLfaXELkdX5NZcSmR1s/kgmU16ODF8bn56nfTh9g6bs="; + }; + + packageRequires = [ epkgs.jsonrpc epkgs.eglot ]; + }) + (inputs.nixpkgs-dev.legacyPackages.${pkgs.system}.emacsPackagesFor pkgs.emacs-git-pgtk).calfw + # epkgs.calfw + # (epkgs.trivialBuild rec { + # pname = "calfw"; + # version = "1.0.0-20231002"; + # src = pkgs.fetchFromGitHub { + # owner = "haji-ali"; + # repo = "emacs-calfw"; + # rev = "bc99afee611690f85f0cd0bd33300f3385ddd3d3"; + # hash = "sha256-0xMII1KJhTBgQ57tXJks0ZFYMXIanrOl9XyqVmu7a7Y="; + # }; + # packageRequires = [ epkgs.howm ]; + # }) + + (epkgs.trivialBuild rec { + pname = "fast-scroll"; + version = "1.0.0-20191016"; + src = pkgs.fetchFromGitHub { + owner = "ahungry"; + repo = "fast-scroll"; + rev = "3f6ca0d5556fe9795b74714304564f2295dcfa24"; + hash = "sha256-w1wmJW7YwXyjvXJOWdN2+k+QmhXr4IflES/c2bCX3CI="; + }; + packageRequires = [ ]; + }) + + ]; + }; + }; + + services.emacs = { + enable = true; + socketActivation.enable = false; + startWithUserSession = "graphical"; + }; + + } // lib.optionalAttrs (inputs ? sops) { + + sops = lib.mkIf (!isPublic && !isNixos) { + secrets = { + fever-pw = { path = "${homeDir}/.emacs.d/.fever"; }; + emacs-radicale-pw = { }; + github-forge-token = { }; + }; + templates = { + authinfo = { + path = "${homeDir}/.emacs.d/.authinfo"; + content = '' + machine ${globals.services.radicale.domain} login ${radicaleUser} password ${config.sops.placeholder.emacs-radicale-pw} + machine api.github.com login ${mainUser}^forge password ${config.sops.placeholder.github-forge-token} + ''; + }; + }; + }; + + }); + } +#+end_src + +**** Waybar +:PROPERTIES: +:CUSTOM_ID: h:0bf51f63-01c0-4053-a591-7f0c5697c690 +:END: + +Again I am just using the first bar option here that I was able to find good understandable documentation for. Of note is that the `cpu` section's `format` is not defined here, but in section 1 (since not every machine has the same number of cores) + +This section is mostly used to deliver the correct information to Waybar. AMD systems have changing hwmon paths that can be specifically set here. Also the cpu count can be set here for Waybars cpu module, but 8 is usually a good setting to show + +These are explicit waybar options. Laptops do not need the battery module. However, this leads to a slight problem with theming: my waybar modules alternate their background-color between black and grey. The battery module is usually on grey background. If I were to simply delete that, I would now have two modules on black background. To avoid this, I define a pseudo-module =custom/pseudobat= that simply shows a static image and calls =wlogout= on right click. This wastes a little bit of screen space, but that is a price I am willing to pay for consistency. + +The rest of the related configuration is found here: +- [[#h:a9530c81-1976-442b-b597-0b4bed6baf25][Waybar]] +- [[#h:f93f66f9-6b8b-478e-b139-b2f382c1f25e][waybarupdate]] + +#+begin_src nix-ts :tangle modules/home/common/waybar.nix + { self, config, lib, inputs, pkgs, ... }: + let + inherit (config.swarselsystems) xdgDir; + generateIcons = n: lib.concatStringsSep " " (builtins.map (x: "{icon" + toString x + "}") (lib.range 0 (n - 1))); + modulesLeft = [ + "custom/outer-left-arrow-dark" + "mpris" + "custom/left-arrow-light" + "network" + "custom/vpn" + "custom/left-arrow-dark" + "pulseaudio" + "custom/left-arrow-light" + ]; + modulesRight = [ + "custom/left-arrow-dark" + "group/hardware" + "custom/left-arrow-light" + "clock#2" + "custom/left-arrow-dark" + "clock#1" + ]; + in + { + options.swarselmodules.waybar = lib.mkEnableOption "waybar settings"; + options.swarselsystems = { + cpuCount = lib.mkOption { + type = lib.types.int; + default = 8; + }; + temperatureHwmon = { + isAbsolutePath = lib.mkEnableOption "absolute temperature path"; + path = lib.mkOption { + type = lib.types.str; + default = ""; + }; + input-filename = lib.mkOption { + type = lib.types.str; + default = ""; + }; + }; + waybarModules = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = modulesLeft ++ [ + "custom/pseudobat" + ] ++ modulesRight; + }; + cpuString = lib.mkOption { + type = lib.types.str; + default = generateIcons config.swarselsystems.cpuCount; + description = "The generated icons string for use by Waybar."; + internal = true; + }; + }; + config = lib.mkIf config.swarselmodules.waybar ({ + + swarselsystems = { + waybarModules = lib.mkIf config.swarselsystems.isLaptop (modulesLeft ++ [ + "battery" + ] ++ modulesRight); + }; + + services.playerctld.enable = true; + + programs.waybar = { + enable = true; + systemd = { + enable = false; + # target = "sway-session.target"; + inherit (config.wayland.systemd) target; + }; + settings = { + mainBar = { + ipc = true; + id = "bar-0"; + # mode = "hide"; + # mode = "overlay"; + # passthrough = false; + # start_hidden = true; + layer = "top"; + position = "top"; + modules-left = [ "sway/workspaces" "niri/workspaces" "custom/outer-right-arrow-dark" "niri/window" "sway/window" ]; + modules-center = [ "sway/mode" "privacy" "custom/github" "custom/configwarn" "custom/nix-updates" ]; + "sway/mode" = { + format = "{}"; + }; + + "niri/window" = { + format = "{title} ({app_id})"; + }; + + modules-right = config.swarselsystems.waybarModules; + + "custom/pseudobat" = lib.mkIf (!config.swarselsystems.isLaptop) { + format = ""; + on-click-right = "${pkgs.wlogout}/bin/wlogout -p layer-shell"; + }; + + "custom/configwarn" = { + exec = "${pkgs.waybarupdate}/bin/waybarupdate"; + interval = 60; + }; + + "custom/scratchpad-indicator" = { + interval = 3; + exec = "${pkgs.swayfx}/bin/swaymsg -t get_tree | ${pkgs.jq}/bin/jq 'recurse(.nodes[]) | first(select(.name==\"__i3_scratch\")) | .floating_nodes | length | select(. >= 1)'"; + format = "{} "; + on-click = "${pkgs.swayfx}/bin/swaymsg 'scratchpad show'"; + on-click-right = "${pkgs.swayfx}/bin/swaymsg 'move scratchpad'"; + }; + + "custom/github" = { + format = "{}  "; + return-type = "json"; + interval = 60; + exec = "${pkgs.github-notifications}/bin/github-notifications"; + on-click = "${pkgs.xdg-utils}/bin/xdg-open https://github.com/notifications"; + }; + + idle_inhibitor = { + format = "{icon}"; + format-icons = { + activated = ""; + deactivated = ""; + }; + }; + + "group/hardware" = { + orientation = "inherit"; + drawer = { + "transition-left-to-right" = false; + }; + modules = [ + "tray" + "temperature" + "power-profiles-daemon" + "custom/left-arrow-light" + "custom/left-arrow-dark" + "custom/scratchpad-indicator" + "custom/left-arrow-light" + "disk" + "custom/left-arrow-dark" + "memory" + "custom/left-arrow-light" + "cpu" + "custom/left-arrow-dark" + "backlight/slider" + "idle_inhibitor" + ]; + }; + + "backlight/slider" = { + min = 0; + max = 100; + orientation = "horizontal"; + device = "intel_backlight"; + }; + + power-profiles-daemon = { + format = "{icon}"; + tooltip-format = "Power profile: {profile}\nDriver: {driver}"; + tooltip = true; + format-icons = { + "default" = ""; + "performance" = ""; + "balanced" = ""; + "power-saver" = ""; + }; + }; + + temperature = { + hwmon-path = lib.mkIf (!config.swarselsystems.temperatureHwmon.isAbsolutePath) config.swarselsystems.temperatureHwmon.path; + hwmon-path-abs = lib.mkIf config.swarselsystems.temperatureHwmon.isAbsolutePath config.swarselsystems.temperatureHwmon.path; + input-filename = lib.mkIf config.swarselsystems.temperatureHwmon.isAbsolutePath config.swarselsystems.temperatureHwmon.input-filename; + critical-threshold = 80; + format-critical = " {temperatureC}°C"; + format = " {temperatureC}°C"; + + }; + + mpris = { + format = "{player_icon} {title} [{position}/{length}]"; + format-paused = "{player_icon} {title} [{position}/{length}]"; + player-icons = { + "default" = "▶ "; + "mpv" = "🎵 "; + "spotify" = " "; + }; + status-icons = { + "paused" = " "; + }; + interval = 1; + title-len = 20; + artist-len = 20; + album-len = 10; + }; + "custom/left-arrow-dark" = { + format = ""; + tooltip = false; + }; + "custom/outer-left-arrow-dark" = { + format = ""; + tooltip = false; + }; + "custom/left-arrow-light" = { + format = ""; + tooltip = false; + }; + "custom/right-arrow-dark" = { + format = ""; + tooltip = false; + }; + "custom/outer-right-arrow-dark" = { + format = ""; + tooltip = false; + }; + "custom/right-arrow-light" = { + format = ""; + tooltip = false; + }; + "sway/workspaces" = { + disable-scroll = true; + format = "{name}"; + }; + + "clock#1" = { + min-length = 8; + interval = 1; + format = "{:%H:%M:%S}"; + # on-click-right= "gnome-clocks"; + tooltip-format = "{:%Y %B}\n{calendar}"; + }; + + "clock#2" = { + format = "{:%d. %B %Y}"; + # on-click-right= "gnome-clocks"; + tooltip-format = "{:%Y %B}\n{calendar}"; + }; + + pulseaudio = { + format = "{icon} {volume:2}%"; + format-bluetooth = "{icon} {volume}%"; + format-muted = "MUTE"; + format-icons = { + headphones = ""; + default = [ + "" + "" + ]; + }; + scroll-step = 1; + on-click = "${pkgs.pamixer}/bin/pamixer -t"; + on-click-right = "${pkgs.pavucontrol}/bin/pavucontrol"; + }; + + memory = { + interval = 5; + format = " {}%"; + tooltip-format = "Memory: {used:0.1f}G/{total:0.1f}G\nSwap: {swapUsed}G/{swapTotal}G"; + }; + cpu = { + format = config.swarselsystems.cpuString; + min-length = 6; + interval = 5; + format-icons = [ "▁" "▂" "▃" "▄" "▅" "▆" "▇" "█" ]; + # on-click-right= "com.github.stsdc.monitor"; + on-click-right = "${pkgs.kitty}/bin/kitty -o confirm_os_window_close=0 btm"; + + }; + "custom/vpn" = { + format = "()"; + exec = "echo '{\"class\": \"connected\"}'"; + exec-if = "${pkgs.toybox}/bin/test -d /proc/sys/net/ipv4/conf/tun0"; + return-type = "json"; + interval = 5; + }; + battery = { + states = { + "warning" = 60; + "error" = 30; + "critical" = 15; + }; + interval = 5; + format = "{icon} {capacity}%"; + format-charging = "{capacity}% "; + format-plugged = "{capacity}% "; + format-icons = [ + "" + "" + "" + "" + "" + ]; + on-click-right = "wlogout -p layer-shell"; + }; + disk = { + interval = 30; + format = "Disk {percentage_used:2}%"; + path = "/"; + states = { + "warning" = 80; + "critical" = 90; + }; + tooltip-format = "{used} used out of {total} on {path} ({percentage_used}%)\n{free} free on {path} ({percentage_free}%)"; + }; + tray = { + icon-size = 20; + }; + network = { + interval = 5; + format-wifi = "{signalStrength}% "; + format-ethernet = ""; + format-linked = "{ifname} (No IP) "; + format-disconnected = "Disconnected ⚠"; + format-alt = "{ifname}: {ipaddr}/{cidr}"; + tooltip-format-ethernet = "{ifname} via {gwaddr}: {essid} {ipaddr}/{cidr}\n\n⇡{bandwidthUpBytes} ⇣{bandwidthDownBytes}"; + tooltip-format-wifi = "{ifname} via {gwaddr}: {essid} {ipaddr}/{cidr} \n{signaldBm}dBm @ {frequency}MHz\n\n⇡{bandwidthUpBytes} ⇣{bandwidthDownBytes}"; + }; + }; + }; + style = builtins.readFile (self + /files/waybar/style.css); + }; + } // lib.optionalAttrs (inputs ? sops) { + sops.secrets = lib.mkIf (!config.swarselsystems.isPublic && !config.swarselsystems.isNixos) { + github-notifications-token = { path = "${xdgDir}/secrets/github-notifications-token"; }; + }; + }); + } +#+end_src + +**** Firefox +:PROPERTIES: +:CUSTOM_ID: h:fbec0bd4-690b-4f79-8b2b-a40263760a96 +:END: + +Setting up firefox along with some policies that are important to me (mostly disabling telemetry related stuff as well as Pocket). I also enable some integrations that enable super useful packages, namely =tridactyl= and =browserpass=. + +Also, using NUR with rycee's firefox addons, it is very convenient for me to add firefox addons here that will be automatically installed. + +Also, I setup some search aliases for functions I often use, such as NixOS options search (=@no=) + +I used to build the firefox addon =bypass-paywalls-clean= myself here, but the maintainer always deletes old packages, and it became a chore for me to maintain here, so I no longer do that. + +#+begin_src nix-ts :tangle modules/home/common/firefox.nix + { config, pkgs, lib, vars, ... }: + { + options.swarselmodules.firefox = lib.mkEnableOption "firefox settings"; + config = lib.mkIf config.swarselmodules.firefox { + + programs.zsh.sessionVariables = { + MOZ_DISABLE_RDD_SANDBOX = "1"; + }; + + programs.firefox = { + enable = true; + package = pkgs.firefox; # uses overrides + policies = { + # CaptivePortal = false; + AppAutoUpdate = false; + BackgroundAppUpdate = false; + DisableBuiltinPDFViewer = true; + DisableFirefoxStudies = true; + DisablePocket = true; + DisableFirefoxScreenshots = true; + DisableTelemetry = true; + DisableFirefoxAccounts = false; + DisableProfileImport = true; + DisableProfileRefresh = true; + DisplayBookmarksToolbar = "always"; + DontCheckDefaultBrowser = true; + NoDefaultBookmarks = true; + OfferToSaveLogins = false; + OfferToSaveLoginsDefault = false; + PasswordManagerEnabled = false; + DisableMasterPasswordCreation = true; + ExtensionUpdate = false; + EnableTrackingProtection = { + Value = true; + Locked = true; + Cryptomining = true; + Fingerprinting = true; + EmailTracking = true; + # Exceptions = ["https://example.com"] + }; + PDFjs = { + Enabled = false; + EnablePermissions = false; + }; + Handlers = { + mimeTypes."application/pdf".action = "saveToDisk"; + }; + extensions = { + pdf = { + action = "useHelperApp"; + ask = true; + handlers = [ + { + name = "GNOME Document Viewer"; + path = "${pkgs.evince}/bin/evince"; + } + ]; + }; + }; + FirefoxHome = { + Search = true; + TopSites = true; + SponsoredTopSites = false; + Highlights = true; + Pocket = false; + SponsoredPocket = false; + Snippets = false; + Locked = true; + }; + FirefoxSuggest = { + WebSuggestions = false; + SponsoredSuggestions = false; + ImproveSuggest = false; + Locked = true; + }; + SanitizeOnShutdown = { + Cache = true; + Cookies = false; + Downloads = true; + FormData = true; + History = false; + Sessions = false; + SiteSettings = false; + OfflineApps = true; + Locked = true; + }; + SearchEngines = { + PreventInstalls = true; + Remove = [ + "Bing" # Fuck you + ]; + }; + UserMessaging = { + ExtensionRecommendations = false; # Don’t recommend extensions while the user is visiting web pages + FeatureRecommendations = false; # Don’t recommend browser features + Locked = true; # Prevent the user from changing user messaging preferences + MoreFromMozilla = false; # Don’t show the “More from Mozilla” section in Preferences + SkipOnboarding = true; # Don’t show onboarding messages on the new tab page + UrlbarInterventions = false; # Don’t offer suggestions in the URL bar + WhatsNew = false; # Remove the “What’s New” icon and menuitem + }; + ExtensionSettings = { + "3rdparty".Extensions = { + # https://github.com/gorhill/uBlock/blob/master/platform/common/managed_storage.json + "uBlock0@raymondhill.net".adminSettings = { + userSettings = rec { + uiTheme = "dark"; + uiAccentCustom = true; + uiAccentCustom0 = "#0C8084"; + cloudStorageEnabled = lib.mkForce false; + importedLists = [ + "https://filters.adtidy.org/extension/ublock/filters/3.txt" + "https://github.com/DandelionSprout/adfilt/raw/master/LegitimateURLShortener.txt" + ]; + externalLists = lib.concatStringsSep "\n" importedLists; + }; + selectedFilterLists = [ + "CZE-0" + "adguard-generic" + "adguard-annoyance" + "adguard-social" + "adguard-spyware-url" + "easylist" + "easyprivacy" + "https://github.com/DandelionSprout/adfilt/raw/master/LegitimateURLShortener.txt" + "plowe-0" + "ublock-abuse" + "ublock-badware" + "ublock-filters" + "ublock-privacy" + "ublock-quick-fixes" + "ublock-unbreak" + "urlhaus-1" + ]; + }; + }; + + }; + + }; + + profiles = { + default = lib.recursiveUpdate + { + id = 0; + isDefault = true; + settings = { + "browser.startup.homepage" = "https://lobste.rs"; + }; + } + vars.firefox; + }; + }; + }; + } +#+end_src + +**** Services +:PROPERTIES: +:CUSTOM_ID: h:387c3a82-1fb1-4c0f-8051-874e2acb8804 +:END: + +Services that can be defined through home-manager should be defined here. + +***** gnome-keyring +:PROPERTIES: +:CUSTOM_ID: h:cb812c8a-247c-4ce5-a00c-59332c2f5fb9 +:END: + +Used for storing sessions in e.g. Nextcloud + +#+begin_src nix-ts :tangle modules/home/common/gnome-keyring.nix + { lib, config, ... }: + { + options.swarselmodules.gnome-keyring = lib.mkEnableOption "gnome keyring settings"; + config = lib.mkIf config.swarselmodules.gnome-keyring { + services.gnome-keyring = lib.mkIf (!config.swarselsystems.isNixos) { + enable = true; + }; + }; + } +#+end_src + +***** KDE Connect +:PROPERTIES: +:CUSTOM_ID: h:be6afd89-9e1e-40b6-8542-5c07a0ab780d +:END: + +This enables phone/computer communication, including sending clipboard, files etc. Sadly on Wayland many of the features are broken (like remote control). + +#+begin_src nix-ts :tangle modules/home/common/kdeconnect.nix + { lib, config, ... }: + { + options.swarselmodules.kdeconnect = lib.mkEnableOption "kdeconnect settings"; + config = lib.mkIf config.swarselmodules.kdeconnect { + services.kdeconnect = { + enable = true; + indicator = true; + }; + }; + + } +#+end_src + +***** Mako +:PROPERTIES: +:CUSTOM_ID: h:99d05729-df35-4958-9940-3319d6a41359 +:END: + +Desktop notifications! + +The `extraConfig` section here CANNOT be reindented. This has something to do with how nix handles multiline strings, when indented Mako will fail to start. This might be a mako bug as well. + +#+begin_src nix-ts :tangle modules/home/common/mako.nix + { lib, config, ... }: + { + options.swarselmodules.mako = lib.mkEnableOption "mako settings"; + config = lib.mkIf config.swarselmodules.mako { + services.mako = { + enable = true; + settings = { + border-radius = 15; + border-size = 1; + default-timeout = 5000; + ignore-timeout = false; + icons = 1; + layer = "overlay"; + sort = "-time"; + height = 150; + width = 300; + "urgency=low" = { + border-color = lib.mkForce "#cccccc"; + }; + "urgency=normal" = { + border-color = lib.mkForce "#d08770"; + }; + "urgency=high" = { + border-color = lib.mkForce "#bf616a"; + default-timeout = 3000; + }; + "category=mpd" = { + default-timeout = 2000; + group-by = "category"; + }; + "mode=do-not-disturb" = { + invisible = true; + }; + }; + }; + }; + + } +#+end_src + +***** SwayOSD +:PROPERTIES: +:CUSTOM_ID: h:388e71be-f00a-4d45-ade1-218ce942057d +:END: + +#+begin_src nix-ts :tangle modules/home/common/swayosd.nix + { lib, pkgs, config, ... }: + { + options.swarselmodules.swayosd = lib.mkEnableOption "swayosd settings"; + config = lib.mkIf config.swarselmodules.swayosd { + services.swayosd = { + enable = true; + package = pkgs.dev.swayosd; + topMargin = 0.5; + }; + }; + } +#+end_src + +***** yubikey-touch-detector +:PROPERTIES: +:CUSTOM_ID: h:1598c90b-f195-41a0-9132-94612edf3586 +:END: + +#+begin_src nix-ts :tangle modules/home/common/yubikey-touch-detector.nix + { lib, config, pkgs, ... }: + { + options.swarselmodules.yubikeytouch = lib.mkEnableOption "yubikey touch detector service settings"; + config = lib.mkIf config.swarselmodules.yubikeytouch { + systemd.user.services.yubikey-touch-detector = { + Unit = { + Description = "Detects when your YubiKey is waiting for a touch"; + Requires = [ "yubikey-touch-detector.socket" ]; + }; + Service = { + ExecStart = "${pkgs.yubikey-touch-detector}/bin/yubikey-touch-detector --libnotify"; + EnvironmentFile = "-%E/yubikey-touch-detector/service.conf"; + }; + Install = { + Also = [ "yubikey-touch-detector.socket" ]; + WantedBy = [ "default.target" ]; + }; + }; + systemd.user.sockets.yubikey-touch-detector = { + Unit = { + Description = "Unix socket activation for YubiKey touch detector service"; + }; + Socket = { + ListenStream = "%t/yubikey-touch-detector.socket"; + RemoveOnStop = true; + }; + Install = { + WantedBy = [ "sockets.target" ]; + }; + }; + }; + } +#+end_src + +***** blueman-applet +:PROPERTIES: +:CUSTOM_ID: h:06aceb90-3b97-4d77-9e13-b1a8af26dd50 +:END: + +#+begin_src nix-ts :tangle modules/home/common/blueman-applet.nix + { lib, config, ... }: + { + options.swarselmodules.blueman-applet = lib.mkEnableOption "enable blueman applet for tray"; + config = lib.mkIf config.swarselmodules.blueman-applet { + services.blueman-applet.enable = true; + }; + } +#+end_src + +***** network-manager-applet +:PROPERTIES: +:CUSTOM_ID: h:67907a83-40ed-49ad-9fa7-bcc0b9cf5936 +:END: + +#+begin_src nix-ts :tangle modules/home/common/network-manager-applet.nix + { lib, config, ... }: + { + options.swarselmodules.nm-applet = lib.mkEnableOption "enable network manager applet for tray"; + config = lib.mkIf config.swarselmodules.nm-applet { + services.network-manager-applet.enable = true; + xsession.preferStatusNotifierItems = true; # needed for indicator icon to show + }; + } +#+end_src + +***** obsidian service for tray +:PROPERTIES: +:CUSTOM_ID: h:7f943057-e0c8-4dbd-9875-67e55bc74a47 +:END: + +#+begin_src nix-ts :tangle modules/home/common/obsidian-tray.nix + { lib, config, ... }: + { + options.swarselmodules.obsidian-tray = lib.mkEnableOption "enable obsidian applet for tray"; + config = lib.mkIf config.swarselmodules.obsidian-tray { + + systemd.user.services.obsidian-applet = { + Unit = { + Description = "Obsidian applet"; + Requires = [ "tray.target" ]; + After = [ + "graphical-session.target" + "tray.target" + ]; + PartOf = [ "graphical-session.target" ]; + }; + + Install = { + WantedBy = [ "graphical-session.target" ]; + }; + + Service = { + ExecStart = "${lib.getExe config.programs.obsidian.package}"; + }; + }; + }; + + } +#+end_src + +***** anki service for tray +:PROPERTIES: +:CUSTOM_ID: h:872deae6-dc31-44ac-9c4a-95720fce0a53 +:END: + +Sets up a systemd user service for anki that does not stall the shutdown process. Note that the outcommented =ExecStart= does not work because the home-manager anki package builds a separate anki package that - I think - cannot be referenced as no such expression exists in the module. + +#+begin_src nix-ts :tangle modules/home/common/anki-tray.nix + { lib, config, ... }: + { + options.swarselmodules.anki-tray = lib.mkEnableOption "enable anki applet for tray"; + config = lib.mkIf config.swarselmodules.anki-tray { + + systemd.user.services.anki-applet = { + Unit = { + Description = "Anki applet"; + Requires = [ "tray.target" ]; + After = [ + "graphical-session.target" + "tray.target" + ]; + PartOf = [ "graphical-session.target" ]; + }; + + Install = { + WantedBy = [ "graphical-session.target" ]; + }; + + Service = { + # ExecStart = "${lib.getExe config.programs.anki.package}"; + Type = "simple"; + ExecStart = "/etc/profiles/per-user/${config.swarselsystems.mainUser}/bin/anki"; + Environment = [ + "QT_QPA_PLATFORM=xcb" + ]; + TimeoutStopSec = "2s"; + KillMode = "mixed"; + KillSignal = "SIGTERM"; + SendSIGKILL = "yes"; + }; + }; + + }; + } +#+end_src + +***** element service for tray +:PROPERTIES: +:CUSTOM_ID: h:2d0f1a35-cff5-4c24-b104-e431c05ae563 +:END: + +#+begin_src nix-ts :tangle modules/home/common/element-tray.nix + { lib, config, pkgs, ... }: + { + options.swarselmodules.element-tray = lib.mkEnableOption "enable element applet for tray"; + config = lib.mkIf config.swarselmodules.element-tray { + + systemd.user.services.element-applet = { + Unit = { + Description = "Element applet"; + Requires = [ "tray.target" ]; + After = [ + "graphical-session.target" + "tray.target" + ]; + PartOf = [ "graphical-session.target" ]; + }; + + Install = { + WantedBy = [ "graphical-session.target" ]; + }; + + Service = { + ExecStart = "${pkgs.element-desktop}/bin/element-desktop --hidden --enable-features=useozoneplatform --ozone-platform=wayland --disable-gpu-driver-bug-workarounds"; + }; + }; + }; + + } +#+end_src + +***** vesktop service for tray +:PROPERTIES: +:CUSTOM_ID: h:ea741a3c-982e-4e23-8ecf-b30193a5c326 +:END: + +#+begin_src nix-ts :tangle modules/home/common/vesktop-tray.nix + { lib, config, pkgs, ... }: + { + options.swarselmodules.vesktop-tray = lib.mkEnableOption "enable vesktop applet for tray"; + config = lib.mkIf config.swarselmodules.vesktop-tray { + + systemd.user.services.vesktop-applet = { + Unit = { + Description = "Vesktop applet"; + Requires = [ "tray.target" ]; + After = [ + "graphical-session.target" + "tray.target" + ]; + PartOf = [ "graphical-session.target" ]; + }; + + Install = { + WantedBy = [ "graphical-session.target" ]; + }; + + Service = { + ExecStart = "${pkgs.vesktop}/bin/vesktop --start-minimized --enable-speech-dispatcher --ozone-platform-hint=auto --enable-features=WaylandWindowDecorations --enable-wayland-ime"; + }; + }; + }; + + } +#+end_src + +***** syncthing service for tray +:PROPERTIES: +:CUSTOM_ID: h:5e7c606f-628a-4849-94e9-359d7b75f228 +:END: + +#+begin_src nix-ts :tangle modules/home/common/syncthing-tray.nix + { lib, config, pkgs, ... }: + { + options.swarselmodules.syncthing-tray = lib.mkEnableOption "enable syncthing applet for tray"; + config = lib.mkIf config.swarselmodules.syncthing-tray { + + home.activation.setupSyncthingIni = + let + syncthingApiEnvVarName = "SYNCTHING_API_KEY"; + syncthingIni = { + file = "${config.home.homeDirectory}/.config/syncthingtray.ini"; + content = '' + [General] + v=2.0.2 + + [qt] + customfont=false + customicontheme=false + customlocale=false + custompalette=false + customstylesheet=false + customwidgetstyle=false + font="Cantarell,11,-1,5,400,0,0,0,0,0,0,0,0,0,0,1" + icontheme=hicolor + iconthemepath= + locale=en_US + palette="@Variant(\0\0\0\x44\x1\x1\xff\xff\xa0\xa0\xb3\xb3\xc5\xc5\0\0\x1\x1\xff\xff jj\x86\x86\0\0\x1\x1\xff\xff\0\0::ff\0\0\x1\x1\xff\xff\0\0::ff\0\0\x1\x1\xff\xff\x1d\x1d%%,,\0\0\x1\x1\xff\xff\x1d\x1d%%,,\0\0\x1\x1\xff\xff\xa0\xa0\xb3\xb3\xc5\xc5\0\0\x1\x1\xff\xff\xff\xff\xff\xff\xff\xff\0\0\x1\x1\xff\xff\xa0\xa0\xb3\xb3\xc5\xc5\0\0\x1\x1\xff\xff\x1d\x1d%%,,\0\0\x1\x1\xff\xff\x17\x17\x1d\x1d##\0\0\x1\x1\xff\xff\0\0\0\0\0\0\0\0\x1\x1\xff\xff\0\0::ff\0\0\x1\x1\xff\xff\xa0\xa0\xb3\xb3\xc5\xc5\0\0\x1\x1\xff\xff^^\xc4\xc4\xff\xff\0\0\x1\x1\xff\xff\xc0\xc0nn\xce\xce\0\0\x1\x1\xff\xff\x17\x17\x1d\x1d##\0\0\x1\x1\xff\xff^^\xc4\xc4\xff\xff\0\0\x1\x1\xff\xff jj\x86\x86\0\0\x1\x1\xff\xff\0\0::ff\0\0\x1\x1\xff\xff\0\0::ff\0\0\x1\x1\xff\xff\x1d\x1d%%,,\0\0\x1\x1\xff\xff\x1d\x1d%%,,\0\0\x1\x1\xff\xff^^\xc4\xc4\xff\xff\0\0\x1\x1\xff\xff\xff\xff\xff\xff\xff\xff\0\0\x1\x1\xff\xff^^\xc4\xc4\xff\xff\0\0\x1\x1\xff\xff\x1d\x1d%%,,\0\0\x1\x1\xff\xff\x17\x17\x1d\x1d##\0\0\x1\x1\xff\xff\0\0\0\0\0\0\0\0\x1\x1\xff\xff\0\0::ff\0\0\x1\x1\x66\x66\xa0\xa0\xb3\xb3\xc5\xc5\0\0\x1\x1\xff\xff^^\xc4\xc4\xff\xff\0\0\x1\x1\xff\xff\xc0\xc0nn\xce\xce\0\0\x1\x1\xff\xff\x17\x17\x1d\x1d##\0\0\x1\x1\xff\xff\xa0\xa0\xb3\xb3\xc5\xc5\0\0\x1\x1\xff\xff jj\x86\x86\0\0\x1\x1\xff\xff\0\0::ff\0\0\x1\x1\xff\xff\0\0::ff\0\0\x1\x1\xff\xff\x1d\x1d%%,,\0\0\x1\x1\xff\xff\x1d\x1d%%,,\0\0\x1\x1\xff\xff\xa0\xa0\xb3\xb3\xc5\xc5\0\0\x1\x1\xff\xff\xff\xff\xff\xff\xff\xff\0\0\x1\x1\xff\xff\xa0\xa0\xb3\xb3\xc5\xc5\0\0\x1\x1\xff\xff\x1d\x1d%%,,\0\0\x1\x1\xff\xff\x17\x17\x1d\x1d##\0\0\x1\x1\xff\xff\0\0\0\0\0\0\0\0\x1\x2\xff\xffP\x14\xff\xff\x65\x65\0\0\x1\x1\xff\xff\xa0\xa0\xb3\xb3\xc5\xc5\0\0\x1\x1\xff\xff^^\xc4\xc4\xff\xff\0\0\x1\x1\xff\xff\xc0\xc0nn\xce\xce\0\0\x1\x1\xff\xff\x17\x17\x1d\x1d##\0\0)" + plugindir= + stylesheetpath= + trpath= + widgetstyle= + + [startup] + considerForReconnect=false + considerLauncherForReconnect=false + showButton=false + showLauncherButton=false + stopOnMetered=false + stopServiceOnMetered=false + syncthingArgs="serve --no-browser --logflags=3" + syncthingAutostart=false + syncthingPath=syncthing + syncthingUnit=syncthing.service + systemUnit=false + useLibSyncthing=false + + [tray] + connections\1\apiKey=@ByteArray(''$${syncthingApiEnvVarName}) + connections\1\authEnabled=falsex + connections\1\autoConnect=true + connections\1\devStatsPollInterval=60000 + connections\1\diskEventLimit=200 + connections\1\errorsPollInterval=30000 + connections\1\httpsCertPath=${config.home.homeDirectory}/.config/syncthing/https-cert.pem + connections\1\label=Primary instance + connections\1\localPath= + connections\1\longPollingTimeout=0 + connections\1\password= + connections\1\pauseOnMetered=false + connections\1\reconnectInterval=30000 + connections\1\requestTimeout=0 + connections\1\statusComputionFlags=123 + connections\1\syncthingUrl=http://${config.services.syncthing.guiAddress} + connections\1\trafficPollInterval=5000 + connections\1\userName= + connections\size=1 + dbusNotifications=true + distinguishTrayIcons=false + frameStyle=16 + ignoreInavailabilityAfterStart=15 + notifyOnDisconnect=true + notifyOnErrors=true + notifyOnLauncherErrors=true + notifyOnLocalSyncComplete=false + notifyOnNewDeviceConnects=false + notifyOnNewDirectoryShared=false + notifyOnRemoteSyncComplete=false + positioning\assumedIconPos=@Point(0 0) + positioning\useAssumedIconPosition=false + positioning\useCursorPos=true + preferIconsFromTheme=false + showDownloads=false + showSyncthingNotifications=true + showTabTexts=true + showTraffic=true + statusIcons="#ff26b6db,#ff0882c8,#ffffffff;#ffdb3c26,#ffc80828,#ffffffff;#ffc9ce3b,#ffebb83b,#ffffffff;#ff2d9d69,#ff2d9d69,#ffffffff;#ff26b6db,#ff0882c8,#ffffffff;#ff26b6db,#ff0882c8,#ffffffff;#ffa9a9a9,#ff58656c,#ffffffff;#ffa9a9a9,#ff58656c,#ffffffff;#ffa9a9a9,#ff58656c,#ffffffff" + statusIconsRenderSize=@Size(32 32) + statusIconsStrokeWidth=0 + tabPos=1 + trayIcons="#ff26b6db,#ff0882c8,#ffffffff;#ffdb3c26,#ffc80828,#ffffffff;#ffc9ce3b,#ffebb83b,#ffffffff;#ff2d9d69,#ff2d9d69,#ffffffff;#ff26b6db,#ff0882c8,#ffffffff;#ff26b6db,#ff0882c8,#ffffffff;#ffa9a9a9,#ff58656c,#ffffffff;#ffa9a9a9,#ff58656c,#ffffffff;#ffa9a9a9,#ff58656c,#ffffffff" + trayIconsRenderSize=@Size(32 32) + trayIconsStrokeWidth=0 + trayMenuSize=@Size(575 475) + usePaletteForStatusIcons=false + usePaletteForTrayIcons=false + windowType=0 + + [webview] + customCommand= + disabled=false + mode=0 + + ''; + }; + in + lib.hm.dag.entryAfter [ "writeBoundary" ] '' + set -eu + + if [ ! -f ${syncthingIni.file} ]; then + cat >${syncthingIni.file} <<'EOF' + ${syncthingIni.content} + EOF + export ${syncthingApiEnvVarName}=$(cat /run/syncthing-init/api_key) + ${lib.getExe pkgs.envsubst} -i ${syncthingIni.file} -o ${syncthingIni.file} + unset ${syncthingApiEnvVarName} + fi + ''; + + }; + + } +#+end_src + +**** Sway +:PROPERTIES: +:CUSTOM_ID: h:02df9dfc-d1af-4a37-a7a0-d8da0af96a20 +:END: + +I am currently using SwayFX, which adds some nice effects to sway, like rounded corners and hiding the separator between title and content of a window. + +Currently, I am too lazy to explain every option here, but most of it is very self-explaining in any case. + +#+begin_src nix-ts :tangle modules/home/common/sway.nix + { config, lib, vars, confLib, ... }: + let + eachOutput = _: monitor: { + inherit (monitor) name; + value = builtins.removeAttrs monitor [ "mode" "name" "scale" "transform" "position" ]; + }; + in + { + options.swarselmodules.sway = lib.mkEnableOption "sway settings"; + options.swarselsystems = { + inputs = lib.mkOption { + type = lib.types.attrsOf (lib.types.attrsOf lib.types.str); + default = { }; + }; + monitors = lib.mkOption { + type = lib.types.attrsOf (lib.types.attrsOf lib.types.str); + default = { }; + }; + keybindings = lib.mkOption { + type = lib.types.attrsOf lib.types.str; + default = { }; + }; + + startup = lib.mkOption { + type = lib.types.listOf (lib.types.attrsOf lib.types.str); + default = [ + # { command = "nextcloud --background"; } + # { command = "vesktop --start-minimized --enable-speech-dispatcher --ozone-platform-hint=auto --enable-features=WaylandWindowDecorations --enable-wayland-ime"; } + # { command = "element-desktop --hidden --enable-features=useozoneplatform --ozone-platform=wayland --disable-gpu-driver-bug-workarounds"; } + # { command = "anki"; } + # { command = "obsidian"; } + # { command = "nm-applet"; } + # { command = "feishin"; } + ]; + }; + kyria = lib.mkOption { + type = lib.types.attrsOf (lib.types.attrsOf lib.types.str); + default = { + "36125:53060:splitkb.com_splitkb.com_Kyria_rev3" = { + xkb_layout = "us"; + xkb_variant = "altgr-intl"; + }; + "7504:24926:Kyria_Keyboard" = { + xkb_layout = "us"; + xkb_variant = "altgr-intl"; + }; + }; + internal = true; + }; + standardinputs = lib.mkOption { + type = lib.types.attrsOf (lib.types.attrsOf lib.types.str); + default = lib.recursiveUpdate (lib.recursiveUpdate config.swarselsystems.touchpad config.swarselsystems.kyria) config.swarselsystems.inputs; + internal = true; + }; + touchpad = lib.mkOption { + type = lib.types.attrsOf (lib.types.attrsOf lib.types.str); + default = { }; + internal = true; + }; + swayfxConfig = lib.mkOption { + type = lib.types.str; + default = '' + blur enable + blur_xray disable + blur_passes 1 + blur_radius 1 + shadows enable + corner_radius 2 + titlebar_separator disable + default_dim_inactive 0.02 + ''; + internal = true; + }; + }; + config = lib.mkIf config.swarselmodules.sway { + swarselsystems = { + touchpad = lib.mkIf config.swarselsystems.isLaptop { + "type:touchpad" = { + dwt = "enabled"; + tap = "enabled"; + natural_scroll = "enabled"; + middle_emulation = "enabled"; + drag_lock = "disabled"; + }; + }; + swayfxConfig = lib.mkIf (!config.swarselsystems.isNixos) " "; + }; + + wayland.windowManager.sway = { + enable = true; + # checkConfig = false; # delete this line once SwayFX is fixed upstream + package = lib.mkIf config.swarselsystems.isNixos null; + systemd = { + enable = true; + xdgAutostart = true; + variables = [ + "DISPLAY" + "WAYLAND_DISPLAY" + "SWAYSOCK" + "XDG_CURRENT_DESKTOP" + "XDG_SESSION_TYPE" + "NIXOS_OZONE_WL" + "XCURSOR_THEME" + "XCURSOR_SIZE" + ]; + }; + wrapperFeatures = { + base = true; + gtk = true; + }; + config = rec { + modifier = "Mod4"; + # terminal = "kitty"; + menu = "fuzzel"; + bars = [{ + command = "waybar"; + mode = "hide"; + hiddenState = "hide"; + position = "top"; + extraConfig = "modifier Mod4"; + }]; + keybindings = + let + inherit (config.wayland.windowManager.sway.config) modifier; + in + lib.recursiveUpdate + { + "${modifier}+0" = "workspace 10:十"; + "${modifier}+1" = "workspace 1:一"; + "${modifier}+2" = "workspace 2:二"; + "${modifier}+3" = "workspace 3:三"; + "${modifier}+4" = "workspace 4:四"; + "${modifier}+5" = "workspace 5:五"; + "${modifier}+6" = "workspace 6:六"; + "${modifier}+7" = "workspace 7:七"; + "${modifier}+8" = "workspace 8:八"; + "${modifier}+9" = "workspace 9:九"; + "${modifier}+Ctrl+Shift+c" = "reload"; + "${modifier}+Ctrl+Shift+e" = "move container to workspace 13:E"; + "${modifier}+Ctrl+Shift+f" = "move container to workspace 16:F"; + "${modifier}+Ctrl+Shift+l" = "move container to workspace 15:L"; + "${modifier}+Ctrl+Shift+m" = "move container to workspace 11:M"; + "${modifier}+Ctrl+Shift+r" = "exec swarsel-displaypower"; + "${modifier}+Ctrl+Shift+s" = "move container to workspace 12:S"; + "${modifier}+Ctrl+Shift+t" = "move container to workspace 14:T"; + "${modifier}+Ctrl+e" = "workspace 13:E"; + "${modifier}+Ctrl+f" = "workspace 16:F"; + "${modifier}+Ctrl+l" = "workspace 15:L"; + "${modifier}+Ctrl+m" = "workspace 11:M"; + "${modifier}+Ctrl+p" = "exec 1password --quick-acces"; + "${modifier}+Ctrl+s" = "workspace 12:S"; + "${modifier}+Ctrl+t" = "workspace 14:T"; + "${modifier}+Down" = "focus down"; + "${modifier}+Escape" = "exec wlogout"; + "${modifier}+F12" = "scratchpad show"; + "${modifier}+Left" = "focus left"; + "${modifier}+Return" = "exec swarselzellij"; + "${modifier}+Right" = "focus right"; + "${modifier}+Shift+0" = "move container to workspace 10:十"; + "${modifier}+Shift+1" = "move container to workspace 1:一"; + "${modifier}+Shift+2" = "move container to workspace 2:二"; + "${modifier}+Shift+3" = "move container to workspace 3:三"; + "${modifier}+Shift+4" = "move container to workspace 4:四"; + "${modifier}+Shift+5" = "move container to workspace 5:五"; + "${modifier}+Shift+6" = "move container to workspace 6:六"; + "${modifier}+Shift+7" = "move container to workspace 7:七"; + "${modifier}+Shift+8" = "move container to workspace 8:八"; + "${modifier}+Shift+9" = "move container to workspace 9:九"; + "${modifier}+Shift+Down" = "move down 40px"; + "${modifier}+Shift+Escape" = "exec kitty -o confirm_os_window_close=0 btm"; + "${modifier}+Shift+F12" = "move scratchpad"; + "${modifier}+Shift+Left" = "move left 40px"; + "${modifier}+Shift+Right" = "move right 40px"; + "${modifier}+Shift+Space" = "floating toggle"; + "${modifier}+Shift+Up" = "move up 40px"; + "${modifier}+Shift+a" = "exec emacsclient -cF '((name . \"Emacs Popup Anchor\"))' -e '(prot-window-popup-swarsel/open-calendar)'"; + "${modifier}+Shift+c" = "exec qalculate-gtk"; + "${modifier}+Shift+e" = "exec swaynag -t warning -m 'You pressed the exit shortcut. Do you really want to exit sway? This will end your Wayland session.' -b 'Yes, exit sway' 'swaymsg exit'"; + "${modifier}+Shift+f" = "exec swaymsg fullscreen"; + "${modifier}+Shift+m" = "exec emacsclient -cF '((name . \"Emacs Popup Anchor\"))' -e '(prot-window-popup-mu4e)'"; + "${modifier}+Shift+o" = "exec pass-fuzzel --otp --type"; + "${modifier}+Shift+p" = "exec pass-fuzzel --type"; + "${modifier}+Shift+s" = "exec slurp | grim -g - Pictures/Screenshots/$(date +'screenshot_%Y-%m-%d-%H%M%S.png')"; + "${modifier}+Shift+t" = "exec opacitytoggle"; + "${modifier}+Shift+v" = "exec wf-recorder -g '$(slurp -f %o -or)' -f ~/Videos/screenrecord_$(date +%Y-%m-%d-%H%M%S).mkv"; + "${modifier}+Space" = "exec fuzzel"; + "${modifier}+Up" = "focus up"; + "${modifier}+a" = "exec swarselcheck -s"; + "${modifier}+c" = "exec emacsclient -cF '((name . \"Emacs Popup Anchor\"))' -e '(prot-window-popup-org-capture)'"; + "${modifier}+d" = "exec swarselcheck -d"; + "${modifier}+e" = "exec emacsclient -nquc -a emacs -e \"(dashboard-open)\""; + "${modifier}+f" = "exec firefox"; + "${modifier}+h" = "exec hyprpicker | wl-copy"; + "${modifier}+m" = "exec swaymsg workspace back_and_forth"; + "${modifier}+o" = "exec pass-fuzzel --otp"; + "${modifier}+p" = "exec pass-fuzzel"; + "${modifier}+q" = "kill"; + "${modifier}+r" = "mode resize"; + "${modifier}+s" = "exec grim -g \"$(slurp)\" -t png - | wl-copy -t image/png"; + "${modifier}+t" = "exec emacsclient -cF '((name . \"Emacs Popup Anchor\"))' -e '(prot-window-popup-org-agenda)'"; + "${modifier}+w" = "exec swarselcheck -e"; + "${modifier}+x" = "exec swarselcheck -k"; + # "${modifier}+Escape" = "mode $exit"; + # "${modifier}+Return" = "exec kitty"; + "XF86AudioRaiseVolume" = "exec swayosd-client --output-volume raise"; + "XF86AudioLowerVolume" = "exec swayosd-client --output-volume lower"; + "XF86AudioMute" = "exec swayosd-client --output-volume mute-toggle"; + "XF86MonBrightnessUp" = "exec swayosd-client --brightness raise"; + "XF86MonBrightnessDown" = "exec swayosd-client --brightness lower"; + "XF86Display" = "exec wl-mirror eDP-1"; + # "--no-repeat Super_L" = "exec killall -SIGUSR1 .waybar-wrapped"; + # "${modifier}+z" = "exec killall -SIGUSR1 .waybar-wrapped"; + } + config.swarselsystems.keybindings; + modes = { + resize = { + Down = "resize grow height 10 px or 10 ppt"; + Escape = "mode default"; + Left = "resize shrink width 10 px or 10 ppt"; + Return = "mode default"; + Right = "resize grow width 10 px or 10 ppt"; + Up = "resize shrink height 10 px or 10 ppt"; + Tab = "move position center, resize set width 50 ppt height 50 ppt"; + }; + }; + defaultWorkspace = "workspace 1:一"; + # output = { + # "${config.swarselsystems.sharescreen}" = { + # bg = "${self}/files/wallpaper/lenovowp.png ${config.stylix.imageScalingMode}"; + # }; + # "Philips Consumer Electronics Company PHL BDM3270 AU11806002320" = { + # bg = "${self}/files/wallpaper/standwp.png ${config.stylix.imageScalingMode}"; + # }; + # }; + input = config.swarselsystems.standardinputs; + workspaceOutputAssign = + let + workplaceSets = lib.mapAttrs' eachOutput config.swarselsystems.monitors; + workplaceOutputs = map (key: lib.getAttr key workplaceSets) (lib.attrNames workplaceSets); + in + workplaceOutputs; + startup = config.swarselsystems.startup ++ [ + { command = "kitty -T kittyterm -o confirm_os_window_close=0 zellij attach --create kittyterm"; } + { command = "sleep 60; kitty -T spotifytui -o confirm_os_window_close=0 spotify_player"; } + ]; + seat = { + "*" = { + hide_cursor = "when-typing enable"; + }; + }; + window = { + border = 1; + titlebar = false; + }; + assigns = { + "15:L" = [{ app_id = "teams-for-linux"; }]; + }; + floating = { + border = 1; + criteria = [ + { app_id = "qalculate-gtk"; } + { app_id = "blueman"; } + { app_id = "pavucontrol"; } + { app_id = "syncthingtray"; } + { app_id = "Element"; } + { app_id = "1Password"; } + { app_id = "com.nextcloud.desktopclient.nextcloud"; } + { title = "(?:Open|Save) (?:File|Folder|As)"; } + { title = "^Add$"; } + { title = "^Picture-in-Picture$"; } + { title = "Syncthing Tray"; } + { title = "^Emacs Popup Frame$"; } + { title = "^Emacs Popup Anchor$"; } + { title = "^spotifytui$"; } + { title = "^kittyterm$"; } + { app_id = "vesktop"; } + { window_role = "pop-up"; } + { window_role = "bubble"; } + { window_role = "dialog"; } + { window_role = "task_dialog"; } + { window_role = "menu"; } + { window_role = "Preferences"; } + ]; + titlebar = false; + }; + window = { + commands = [ + { + command = "opacity 0.95"; + criteria = { + class = ".*"; + }; + } + { + command = "opacity 1"; + criteria = { + app_id = "at.yrlf.wl_mirror"; + }; + } + { + command = "opacity 1"; + criteria = { + app_id = "Gimp-2.10"; + }; + } + { + command = "opacity 0.99"; + criteria = { + app_id = "firefox"; + }; + } + { + command = "opacity 0.99"; + criteria = { + app_id = "chromium-browser"; + }; + } + { + command = "sticky enable, shadows enable"; + criteria = { + title = "^Picture-in-Picture$"; + }; + } + { + command = "resize set width 60 ppt height 60 ppt, opacity 0.99, sticky enable"; + criteria = { + title = "^Emacs Popup Frame$"; + }; + } + { + command = "move container to scratchpad"; + criteria = { + title = "^Emacs Popup Anchor$"; + }; + } + { + command = "resize set width 60 ppt height 60 ppt, opacity 0.8, sticky enable, border normal, move container to scratchpad"; + criteria = { + title = "^kittyterm$"; + }; + } + { + command = "resize set width 60 ppt height 60 ppt, opacity 0.95, sticky enable, border normal, move container to scratchpad"; + criteria = { + title = "^spotifytui$"; + }; + } + { + + command = "resize set width 60 ppt height 60 ppt, sticky enable, move container to scratchpad"; + criteria = { + class = "Spotify"; + }; + } + { + command = "resize set width 60 ppt height 60 ppt, sticky enable"; + criteria = { + app_id = "vesktop"; + }; + } + { + command = "resize set width 60 ppt height 60 ppt, sticky enable"; + criteria = { + class = "Element"; + }; + } + # { + # command = "resize set width 60 ppt height 60 ppt, sticky enable, move container to scratchpad"; + # criteria = { + # app_id="^$"; + # class="^$"; + # }; + # } + ]; + }; + gaps = { + inner = 5; + }; + }; + extraSessionCommands = '' + export XDG_CURRENT_DESKTOP=sway; + export XDG_SESSION_DESKTOP=sway; + export _JAVA_AWT_WM_NONREPARENTING=1; + export GITHUB_NOTIFICATION_TOKEN_PATH=${confLib.getConfig.sops.secrets.github-notifications-token.path}; + '' + vars.waylandExports; + # extraConfigEarly = " + # exec systemctl --user import-environment DISPLAY WAYLAND_DISPLAY SWAYSOCK + # exec hash dbus-update-activation-environment 2>/dev/null && dbus-update-activation-environment --systemd DISPLAY WAYLAND_DISPLAY SWAYSOCK + # "; + extraConfig = + let + inherit (config.wayland.windowManager.sway.config) modifier; + swayfxSettings = config.swarselsystems.swayfxConfig; + in + " + # exec_always autotiling + # set $exit \"exit: [s]leep, [l]ock, [p]oweroff, [r]eboot, [u]ser logout\" + + # mode $exit { + # bindsym --to-code { + # s exec \"systemctl suspend\", mode \"default\" + # h exec \"systemctl hibernate\", mode \"default\" + # l exec \"swaylock --screenshots --clock --effect-blur 7x5 --effect-vignette 0.5:0.5 --fade-in 0.2 --daemonize\", mode \"default\ + # p exec \"systemctl poweroff\" + # r exec \"systemctl reboot\" + # u exec \"swaymsg exit\" + + # Return mode \"default\" + # Escape mode \"default\" + # ${modifier}+Escape mode \"default\" + # } + # } + + exec systemctl --user import-environment + # exec swayidle -w + + seat * hide_cursor 2000 + + exec_always kill -1 $(pidof kanshi) + + bindswitch --locked lid:on exec kanshictl switch lidclosed + bindswitch --locked lid:off exec kanshictl switch lidopen + + ${swayfxSettings} + "; + }; + }; + } +#+end_src + +**** Kanshi +:PROPERTIES: +:CUSTOM_ID: h:eb94df98-2bcd-4555-9f88-e252f93b924f +:END: + + +#+begin_src nix-ts :tangle modules/home/common/kanshi.nix + { self, lib, pkgs, config, ... }: + { + options.swarselmodules.kanshi = lib.mkEnableOption "kanshi settings"; + config = lib.mkIf config.swarselmodules.kanshi { + swarselsystems = { + monitors = { + homedesktop = rec { + name = "Philips Consumer Electronics Company PHL BDM3270 AU11806002320"; + mode = "2560x1440"; + scale = "1"; + position = "0,0"; + workspace = "11:M"; + output = name; + }; + }; + }; + services.kanshi = { + enable = true; + settings = [ + { + # laptop screen + output = { + criteria = config.swarselsystems.sharescreen; + mode = config.swarselsystems.highResolution; + scale = 1.0; + }; + } + { + # home main screen + output = { + criteria = "Philips Consumer Electronics Company PHL BDM3270 AU11806002320"; + scale = 1.0; + mode = "2560x1440"; + }; + } + { + profile = { + name = "lidopen"; + exec = [ "${pkgs.swaybg}/bin/swaybg --output '${config.swarselsystems.sharescreen}' --image ${config.swarselsystems.wallpaper} --mode ${config.stylix.imageScalingMode}" ]; + outputs = [ + { + criteria = config.swarselsystems.sharescreen; + status = "enable"; + scale = 1.0; + } + ]; + }; + } + { + profile = + let + monitor = "Philips Consumer Electronics Company PHL BDM3270 AU11806002320"; + in + { + name = "lidopen"; + exec = [ + "${pkgs.swaybg}/bin/swaybg --output '${config.swarselsystems.sharescreen}' --image ${config.swarselsystems.wallpaper} --mode ${config.stylix.imageScalingMode}" + "${pkgs.swaybg}/bin/swaybg --output '${monitor}' --image ${self}/files/wallpaper/standwp.png --mode ${config.stylix.imageScalingMode}" + ]; + outputs = [ + { + criteria = config.swarselsystems.sharescreen; + status = "enable"; + scale = 1.7; + position = "2560,0"; + } + { + criteria = monitor; + scale = 1.0; + mode = "2560x1440"; + position = "0,0"; + } + ]; + }; + } + { + profile = + let + monitor = "Philips Consumer Electronics Company PHL BDM3270 AU11806002320"; + in + { + name = "lidclosed"; + exec = [ "${pkgs.swaybg}/bin/swaybg --output '${monitor}' --image ${self}/files/wallpaper/standwp.png --mode ${config.stylix.imageScalingMode}" ]; + outputs = [ + { + criteria = config.swarselsystems.sharescreen; + status = "disable"; + position = "2560,0"; + } + { + criteria = monitor; + scale = 1.0; + mode = "2560x1440"; + position = "0,0"; + } + ]; + }; + } + ]; + }; + }; + } +#+end_src + +**** gpg-agent +:PROPERTIES: +:CUSTOM_ID: h:7d384e3b-1be7-4644-b304-ada4af0b692b +:END: + +Settings that are needed for the gpg-agent. Also we are enabling emacs support for unlocking my Yubikey here. + +When setting up a new machine: + +#+begin_src markdown :noweb-ref worksetup :exports both :results html + - setup gpgsm for signing of mails using S/MIME: + - `gpgsm --import ~/Certificates/.p12` + - `gpgsm --import ~/Certificates/harica-root.pem` + - `gpgsm --import ~/Certificates/harica-intermediate.pem` + - `gpgsm --list-keys --with-validation "HARICA Client RSA Root CA 2021"` + - trust the certificate and set passphrase +#+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" + ]; + }; + + programs.gpg = { + enable = true; + publicKeys = [ + { + source = "${self}/secrets/keys/gpg/gpg-public-key-0x76FD3810215AE097.asc"; + trust = 5; + } + ]; + }; + + # assure correct permissions + systemd.user.tmpfiles.settings."30-gpgagent".rules = { + "${homeDir}/.gnupg" = { + d = { + group = "users"; + user = mainUser; + mode = "0700"; + }; + }; + }; + }; + + } +#+end_src + +**** gammastep +:PROPERTIES: +:CUSTOM_ID: h:74e236be-a977-4d38-b8c5-0b9feef8af91 +:END: + +This service changes the screen hue at night. I am not sure if that really does something, but I like the color anyways. + +#+begin_src nix-ts :tangle modules/home/common/gammastep.nix + { lib, config, confLib, ... }: + let + inherit (confLib.getConfig.repo.secrets.common.location) latitude longitude; + in + { + options.swarselmodules.gammastep = lib.mkEnableOption "gammastep settings"; + config = lib.mkIf config.swarselmodules.gammastep { + services.gammastep = lib.mkIf (config.swarselsystems.isNixos && !config.swarselsystems.isPublic) { + enable = true; + provider = "manual"; + inherit longitude latitude; + }; + }; + } +#+end_src + +**** Spicetify +:PROPERTIES: +:CUSTOM_ID: h:d1fb3075-ad52-4c1b-ba45-5ddbd0d3b708 +:END: + + +#+begin_src nix-ts :tangle modules/home/common/spicetify.nix + { inputs, lib, config, pkgs, ... }: + let + moduleName = "spicetify"; + spicePkgs = inputs.spicetify-nix.legacyPackages.${pkgs.stdenv.system}; + in + { + options.swarselmodules.${moduleName} = lib.mkEnableOption "${moduleName} settings"; + config = lib.mkIf config.swarselmodules.${moduleName} { + programs.spicetify = { + enable = true; + # spotifyPackage = pkgs.stable24_11.spotify; + spotifyPackage = pkgs.spotify; + enabledExtensions = with spicePkgs.extensions; [ + fullAppDisplay + shuffle + hidePodcasts + fullAlbumDate + skipStats + history + ]; + }; + }; + } +#+end_src + +**** Obsidian +:PROPERTIES: +:CUSTOM_ID: h:ffd97152-63ce-41a0-a40e-c78ba3eb6722 +:END: + +#+begin_src nix-ts :tangle modules/home/common/obsidian.nix + { lib, config, pkgs, confLib, ... }: + let + moduleName = "obsidian"; + inherit (confLib.getConfig.repo.secrets.common.obsidian) userIgnoreFilters; + name = "Main"; + in + { + options.swarselmodules.${moduleName} = lib.mkEnableOption "enable ${moduleName} with settings"; + config = lib.mkIf config.swarselmodules.${moduleName} { + + home.file = { + "${config.programs.obsidian.vaults.${name}.target}/.obsidian/app.json".force = true; + "${config.programs.obsidian.vaults.${name}.target}/.obsidian/appearance.json".force = true; + "${config.programs.obsidian.vaults.${name}.target}/.obsidian/core-plugins.json".force = true; + }; + + programs.obsidian = let + pluginSource = pkgs.nur.repos.swarsel; + in { + enable = true; + package = pkgs.obsidian; + defaultSettings = { + app = { + attachmentFolderPath = "attachments"; + alwaysUpdateLinks = true; + spellcheck = false; + inherit userIgnoreFilters; + vimMode = false; + newFileLocation = "current"; + }; + hotkeys = { + "graph:open" = [ ]; + "omnisearch:show-modal" = [ + { + modifiers = [ + "Mod" + ]; + key = "S"; + } + ]; + "editor:save-file" = [ ]; + "editor:delete-paragraph" = [ ]; + }; + corePlugins = [ + "backlink" + "bookmarks" + "canvas" + "command-palette" + "daily-notes" + "editor-status" + "file-explorer" + "file-recovery" + "global-search" + "graph" + "note-composer" + "outgoing-link" + "outline" + "page-preview" + "properties" + "slides" + "switcher" + "tag-pane" + "templates" + "word-count" + ]; + # communityPlugins = with pkgs.swarsel-nix; [ + communityPlugins = with pluginSource; [ + advanced-tables + calendar + file-hider + linter + omnisearch + sort-and-permute-lines + tag-wrangler + tray + ]; + }; + vaults = { + ${name} = { + target = "./Obsidian/${name}"; + settings = { + appearance = { + baseFontSize = lib.mkForce 19; + }; + # communityPlugins = with pkgs.swarsel-nix; [ + communityPlugins = with pluginSource; [ + { + pkg = advanced-tables; + enable = true; + } + { + pkg = calendar; + enable = true; + } + { + pkg = sort-and-permute-lines; + enable = true; + } + { + pkg = tag-wrangler; + enable = true; + } + { + pkg = tray; + enable = true; + settings = { + launchOnStartup = false; + hideOnLaunch = true; + runInBackground = true; + hideTaskbarIcon = false; + createTrayIcon = true; + }; + } + { + pkg = file-hider; + enable = true; + settings = + { + hidden = true; + hiddenList = [ + "attachments" + "images" + "ltximg" + "logseq" + ]; + }; + } + { + pkg = linter; + enable = true; + settings = { + auto-correct-common-misspellings = { + skip-words-with-multiple-capitals = true; + }; + convert-bullet-list-markers = { + enabled = true; + }; + }; + } + { + pkg = omnisearch; + enable = true; + settings = { + hideExcluded = true; + }; + } + ]; + }; + }; + }; + }; + }; + } +#+end_src + +**** Anki +:PROPERTIES: +:CUSTOM_ID: h:6f2839dc-c681-4697-8e93-4ef191362434 +:END: + + +#+begin_src nix-ts :tangle modules/home/common/anki.nix + { lib, config, pkgs, globals, inputs, confLib, ... }: + let + moduleName = "anki"; + inherit (config.swarselsystems) isPublic isNixos; + in + { + options.swarselmodules.${moduleName} = lib.mkEnableOption "enable ${moduleName} and settings"; + config = lib.mkIf config.swarselmodules.${moduleName} + ({ + + programs.anki = { + enable = true; + # # package = pkgs.anki; + hideBottomBar = true; + hideBottomBarMode = "always"; + hideTopBar = true; + hideTopBarMode = "always"; + reduceMotion = true; + spacebarRatesCard = true; + # videoDriver = "opengl"; + sync = { + autoSync = false; # sync on profile close will delay system shutdown + syncMedia = true; + autoSyncMediaMinutes = 5; + url = "https://${globals.services.ankisync.domain}"; + usernameFile = confLib.getConfig.sops.secrets.anki-user.path; + # this is not the password but the syncKey + # get it by logging in or out, saving preferences and then + # show details on the "settings wont be saved" dialog + keyFile = confLib.getConfig.sops.secrets.anki-pw.path; + }; + addons = + let + minimize-to-tray = pkgs.anki-utils.buildAnkiAddon + (finalAttrs: { + pname = "minimize-to-tray"; + version = "2.0.1"; + src = pkgs.fetchFromGitHub { + owner = "simgunz"; + repo = "anki21-addons_minimize-to-tray"; + rev = finalAttrs.version; + sparseCheckout = [ "src" ]; + hash = "sha256-xmvbIOfi9K0yEUtUNKtuvv2Vmqrkaa4Jie6J1s+FuqY="; + }; + sourceRoot = "${finalAttrs.src.name}/src"; + }); + in + [ + (minimize-to-tray.withConfig + { + config = { + hide_on_startup = "true"; + }; + }) + ]; + }; + } // lib.optionalAttrs (inputs ? sops) { + sops = lib.mkIf (!isPublic && !isNixos) { + secrets = { + anki-user = { }; + anki-pw = { }; + }; + }; + }); + + } +#+end_src + +**** Element-desktop +:PROPERTIES: +:CUSTOM_ID: h:add71e84-43ff-40c7-9173-de43a13bbae6 +:END: + + +#+begin_src nix-ts :tangle modules/home/common/element.nix + { lib, config, globals, ... }: + let + moduleName = "element-desktop"; + in + { + options.swarselmodules.${moduleName} = lib.mkEnableOption "enable ${moduleName} and settings"; + config = lib.mkIf config.swarselmodules.${moduleName} { + programs.element-desktop = { + enable = true; + settings = { + default_server_config = { + "m.homeserver" = { + base_url = "https://${globals.services.matrix.domain}/"; + }; + }; + UIFeature = { + feedback = false; + voip = false; + widgets = false; + shareSocial = false; + registration = false; + passwordReset = false; + deactivate = false; + }; + }; + }; + }; + + } +#+end_src + +**** Hexchat +:PROPERTIES: +:CUSTOM_ID: h:812cedcd-520e-417e-8923-aaae5ff5e316 +:END: + + +#+begin_src nix-ts :tangle modules/home/common/hexchat.nix + { lib, config, confLib, ... }: + let + moduleName = "hexchat"; + inherit (confLib.getConfig.repo.secrets.common.irc) irc_nick1; + in + { + options.swarselmodules.${moduleName} = lib.mkEnableOption "enable ${moduleName} and settings"; + config = lib.mkIf config.swarselmodules.${moduleName} { + programs.${moduleName} = { + enable = true; + settings = { + inherit irc_nick1; + }; + }; + }; + + } +#+end_src + +**** obs-studio +:PROPERTIES: +:CUSTOM_ID: h:ef995044-6833-40d6-825b-64063c00a790 +:END: + + +#+begin_src nix-ts :tangle modules/home/common/obs-studio.nix + { lib, config, ... }: + let + moduleName = "obs-studio"; + in + { + options.swarselmodules.${moduleName} = lib.mkEnableOption "enable ${moduleName} and settings"; + config = lib.mkIf config.swarselmodules.${moduleName} { + programs.${moduleName} = { + enable = true; + }; + }; + + } +#+end_src + +**** spotify-player +:PROPERTIES: +:CUSTOM_ID: h:b99d62a1-4560-429f-81c1-29fc544a46fb +:END: + +#+begin_src nix-ts :tangle modules/home/common/spotify-player.nix + { lib, config, ... }: + let + moduleName = "spotify-player"; + in + { + options.swarselmodules.${moduleName} = lib.mkEnableOption "enable ${moduleName} and settings"; + config = lib.mkIf config.swarselmodules.${moduleName} { + programs.${moduleName} = { + enable = true; + }; + }; + + } +#+end_src + +**** vesktop +:PROPERTIES: +:CUSTOM_ID: h:f5e191c5-b8c0-4f66-aa38-9cbfb1619058 +:END: + +#+begin_src nix-ts :tangle modules/home/common/vesktop.nix + { lib, pkgs, config, ... }: + let + moduleName = "vesktop"; + in + { + options.swarselmodules.${moduleName} = lib.mkEnableOption "enable ${moduleName} and settings"; + config = lib.mkIf config.swarselmodules.${moduleName} { + programs.${moduleName} = { + enable = true; + package = pkgs.stable.vesktop; + settings = { + appBadge = false; + arRPC = false; + checkUpdates = false; + customTitleBar = false; + disableMinSize = true; + minimizeToTray = true; + tray = true; + staticTitle = true; + hardwareAcceleration = true; + discordBranch = "stable"; + }; + vencord = { + useSystem = true; + settings = { + autoUpdate = false; + autoUpdateNotification = false; + enableReactDevtools = false; + frameless = false; + transparent = false; + winCtrlQ = false; + notifyAboutUpdates = false; + useQuickCss = true; + disableMinSize = true; + winNativeTitleBar = false; + plugins = { + MessageLogger = { + enabled = true; + ignoreSelf = true; + }; + ChatInputButtonAPI = { + enabled = false; + }; + CommandsAPI = { + enabled = true; + }; + MemberListDecoratorsAPI = { + enabled = false; + }; + MessageAccessoriesAPI = { + enabled = true; + }; + MessageDecorationsAPI = { + enabled = false; + }; + MessageEventsAPI = { + enabled = false; + }; + MessagePopoverAPI = { + enabled = false; + }; + MessageUpdaterAPI = { + enabled = false; + }; + ServerListAPI = { + enabled = false; + }; + UserSettingsAPI = { + enabled = true; + }; + FakeNitro = { + enabled = true; + }; + }; + }; + }; + }; + }; + + } +#+end_src + +**** batsignal +:PROPERTIES: +:CUSTOM_ID: h:b30fcdf0-93d8-4600-a267-e210bec8e680 +:END: + +#+begin_src nix-ts :tangle modules/home/common/batsignal.nix + { lib, config, ... }: + let + moduleName = "batsignal"; + in + { + options.swarselmodules.${moduleName} = lib.mkEnableOption "enable ${moduleName} and settings"; + config = lib.mkIf config.swarselmodules.${moduleName} { + services.${moduleName} = { + enable = true; + extraArgs = [ + "-W" + " Consider charging the battery" + "-C" + " Battery is low; plug in charger now" + "-D" + " Device will lose power in a few seconds" + "-c" + "10" + "-d" + "5" + ]; + }; + }; + + } +#+end_src + +**** autotiling +:PROPERTIES: +:CUSTOM_ID: h:a7bac755-510c-424b-b964-18fb9e4a6667 +:END: + +#+begin_src nix-ts :tangle modules/home/common/autotiling.nix + { lib, config, ... }: + let + moduleName = "autotiling"; + in + { + options.swarselmodules.${moduleName} = lib.mkEnableOption "enable ${moduleName} and settings"; + config = lib.mkIf config.swarselmodules.${moduleName} { + services.${moduleName} = { + enable = true; + systemdTarget = config.wayland.systemd.target; + }; + }; + + } +#+end_src + +**** swayidle +:PROPERTIES: +:CUSTOM_ID: h:2e23f3d9-ab65-4f2f-912f-dc236189c457 +:END: + +#+begin_src nix-ts :tangle modules/home/common/swayidle.nix + { lib, config, pkgs, ... }: + let + moduleName = "swayidle"; + in + { + options.swarselmodules.${moduleName} = lib.mkEnableOption "enable ${moduleName} and settings"; + config = lib.mkIf config.swarselmodules.${moduleName} { + services.${moduleName} = + let + brightnessctl = "${lib.getExe pkgs.brightnessctl}"; + swaylock = "${lib.getExe pkgs.swaylock-effects}"; + suspend = "${pkgs.systemd}/bin/systemctl suspend"; + in + { + enable = true; + systemdTarget = config.wayland.systemd.target; + extraArgs = [ "-w" ]; + timeouts = [ + { timeout = 60; command = "${brightnessctl} -s; ${brightnessctl} set 80%-"; resumeCommand = "${brightnessctl} -r"; } + # { timeout = 300; command = "${lib.getExe pkgs.swaylock-effects} -f --screenshots --clock --effect-blur 7x5 --effect-vignette 0.5:0.5 --fade-in 0.2"; } + { timeout = 300; command = "${swaylock} -f"; } + # { timeout = 600; command = ''${pkgs.sway}/bin/swaymsg "output * dpms off"; resumeCommand = "${pkgs.sway}/bin/swaymsg output * dpms on''; } + { timeout = 600; command = "${suspend}"; } + ]; + events = [ + # { event = "before-sleep"; command = "${lib.getExe pkgs.swaylock-effects} -f --screenshots --clock --effect-blur 7x5 --effect-vignette 0.5:0.5 --fade-in 0.2"; } + # { event = "after-resume"; command = "${swaylock} -f "; } + { event = "before-sleep"; command = "${swaylock} -f "; } + { event = "lock"; command = "${swaylock} -f "; } + ]; + }; + }; + + } +#+end_src + +**** swaylock +:PROPERTIES: +:CUSTOM_ID: h:8e508f62-d3e4-48bc-8bce-641bf38a0106 +:END: + +#+begin_src nix-ts :tangle modules/home/common/swaylock.nix + { lib, config, pkgs, ... }: + let + moduleName = "swaylock"; + in + { + options.swarselmodules.${moduleName} = lib.mkEnableOption "enable ${moduleName} and settings"; + config = lib.mkIf config.swarselmodules.${moduleName} { + programs.${moduleName} = { + enable = true; + package = pkgs.swaylock-effects; + settings = { + screenshots = true; + clock = true; + effect-blur = "7x5"; + effect-vignette = "0.5:0.5"; + fade-in = "0.2"; + }; + }; + }; + + } +#+end_src + +**** opkssh +:PROPERTIES: +:CUSTOM_ID: h:99bde2b8-ab38-4082-b06b-4afde9d06228 +:END: + +#+begin_src nix-ts :tangle modules/home/common/opkssh.nix + { lib, config, globals, ... }: + let + moduleName = "opkssh"; + in + { + options.swarselmodules.${moduleName} = lib.mkEnableOption "enable ${moduleName} and settings"; + config = lib.mkIf config.swarselmodules.${moduleName} { + programs.${moduleName} = { + enable = true; + settings = { + default_provider = "kanidm"; + + providers = [ + { + alias = "kanidm"; + issuer = "https://${globals.services.kanidm.domain}/oauth2/openid/opkssh"; + client_id = "opkssh"; + scopes = "openid email profile"; + redirect_uris = [ + "http://localhost:3000/login-callback" + "http://localhost:10001/login-callback" + "http://localhost:11110/login-callback" + ]; + } + ]; + }; + }; + }; + + } +#+end_src + +*** Server +:PROPERTIES: +:CUSTOM_ID: h:b1a00339-6e9b-4ae4-b5dc-6fd5669a2ddb +:END: + +This is again configuration that is mostly needed on servers. Most things should be done using the NixOS config instead, consider carefully if a home-manager config must be used. + +**** Imports +:PROPERTIES: +:CUSTOM_ID: h:7b4ee01a-b505-47da-8fb9-0b41285d0eab +:END: + +This section sets up all the imports that are used in the home-manager section. + +#+begin_src nix-ts :tangle modules/home/server/default.nix + { self, lib, ... }: + let + importNames = lib.swarselsystems.readNix "modules/home/server"; + modulesPath = "${self}/modules"; + in + { + imports = lib.swarselsystems.mkImports importNames "modules/home/server" ++ [ + "${modulesPath}/home/common/settings.nix" + ]; + } +#+end_src + +**** Symlinking dotfiles +:PROPERTIES: +:CUSTOM_ID: h:9fac0904-b615-4d9d-9bae-54a6691999c3 +:END: + +This section should be used in order to symlink already existing configuration files using `home.file` and setting session variables using `home.sessionVariables`. + +As for the `home.sessionVariables`, it should be noted that environment variables that are needed at system start should NOT be loaded here, but instead in `programs.zsh.config.extraSessionCommands` (in the home-manager programs section). This is also where all the wayland related variables are stored. + +#+begin_src nix-ts :tangle modules/home/server/symlink.nix + { self, lib, config, ... }: + { + options.swarselmodules.server.dotfiles = lib.mkEnableOption "server dotfiles settings"; + config = lib.mkIf config.swarselmodules.server.dotfiles { + home.file = { + "init.el" = lib.mkForce { + source = self + /files/emacs/server.el; + target = ".emacs.d/init.el"; + }; + }; + }; + } +#+end_src + +*** Darwin +:PROPERTIES: +:CUSTOM_ID: h:e0536bff-2552-4ac4-a34a-a23937a2c30f +:END: + +Again, mostly a placeholder for future home-manager modules that run on darwin systems. + +**** Imports +:PROPERTIES: +:CUSTOM_ID: h:cff37bdf-4f22-419a-af4e-2665ede9add0 +:END: + +This section sets up all the imports that are used in the home-manager section. + +#+begin_src nix-ts :tangle modules/home/darwin/default.nix + { self, ... }: + { + home.stateVersion = "23.05"; + imports = [ + "${self}/modules/home/common/settings.nix" + "${self}/modules/shared/options.nix" + "${self}/modules/shared/vars.nix" + ]; + } +#+end_src + +*** Optional +:PROPERTIES: +:CUSTOM_ID: h:be623200-557e-4bb7-bb11-1ec5d76c6b8b +:END: + +Akin to the [[#h:f9aa9af0-9b8d-43ff-901d-9ffccdd70589][Optional]] NixOS modules. + +#+begin_src nix-ts :tangle modules/home/optional/default.nix + { lib, ... }: + let + importNames = lib.swarselsystems.readNix "modules/home/optional"; + in + { + imports = lib.swarselsystems.mkImports importNames "modules/home/optional"; + } +#+end_src + +**** Niri +:PROPERTIES: +:CUSTOM_ID: h:06e77ca4-28ff-4cfd-bc60-b7fd848bfedb +:END: + +#+begin_src nix-ts :tangle modules/home/optional/niri.nix + { inputs, config, pkgs, lib, vars, ... }: + { + imports = [ + inputs.niri-flake.homeModules.niri + ]; + options.swarselmodules.niri = lib.mkEnableOption "niri settings"; + config = lib.mkIf config.swarselmodules.niri + { + + programs.niri = { + package = pkgs.niri-unstable; # which package to use for niri validation + settings = { + xwayland-satellite = { + enable = true; + path = "${lib.getExe pkgs.xwayland-satellite-unstable}"; + }; + prefer-no-csd = true; + layer-rules = [ + { matches = [{ namespace = "^notifications$"; }]; block-out-from = "screencast"; } + { matches = [{ namespace = "^wallpaper$"; }]; place-within-backdrop = true; } + ]; + window-rules = [ + { + matches = [{ app-id = ".*"; }]; + opacity = 0.95; + default-column-width = { proportion = 0.5; }; + shadow = { + enable = true; + draw-behind-window = true; + }; + geometry-corner-radius = { top-left = 2.0; top-right = 2.0; bottom-left = 2.0; bottom-right = 2.0; }; + } + { matches = [{ app-id = "at.yrlf.wl_mirror"; }]; opacity = 1.0; } + { matches = [{ app-id = "Gimp"; }]; opacity = 1.0; } + { matches = [{ app-id = "firefox"; }]; opacity = 0.99; } + { matches = [{ app-id = "^special.*"; }]; default-column-width = { proportion = 0.9; }; open-on-workspace = "Scratchpad"; } + { matches = [{ app-id = "chromium-browser"; }]; opacity = 0.99; } + { matches = [{ app-id = "^qalculate-gtk$"; }]; open-floating = true; } + { matches = [{ app-id = "^blueman$"; }]; open-floating = true; } + { matches = [{ app-id = "^pavucontrol$"; }]; open-floating = true; } + { matches = [{ app-id = "^syncthingtray$"; }]; open-floating = true; } + { matches = [{ app-id = "^Element$"; }]; open-floating = true; default-column-width = { proportion = 0.5; }; block-out-from = "screencast"; } + # { matches = [{ app-id = "^Element$"; }]; default-column-width = { proportion = 0.9; }; open-on-workspace = "Scratchpad"; block-out-from = "screencast"; } + { matches = [{ app-id = "^vesktop$"; }]; open-floating = true; default-column-width = { proportion = 0.5; }; block-out-from = "screencast"; } + # { matches = [{ app-id = "^vesktop$"; }]; default-column-width = { proportion = 0.9; }; open-on-workspace = "Scratchpad"; block-out-from = "screencast"; } + { matches = [{ app-id = "^com.nextcloud.desktopclient.nextcloud$"; }]; open-floating = true; } + { matches = [{ title = ".*1Password.*"; }]; excludes = [{ app-id = "^firefox$"; } { app-id = "^emacs$"; } { app-id = "^kitty$"; }]; open-floating = true; block-out-from = "screencast"; } + { matches = [{ title = "(?:Open|Save) (?:File|Folder|As)"; }]; open-floating = true; } + { matches = [{ title = "^Add$"; }]; open-floating = true; } + { matches = [{ title = "^Picture-in-Picture$"; }]; open-floating = true; } + { matches = [{ title = "Syncthing Tray"; }]; open-floating = true; } + { matches = [{ title = "^Emacs Popup Frame$"; }]; open-floating = true; } + { matches = [{ title = "^Emacs Popup Anchor$"; }]; open-floating = true; } + { matches = [{ app-id = "^spotifytui$"; }]; open-floating = true; default-column-width = { proportion = 0.5; }; } + { matches = [{ app-id = "^kittyterm$"; }]; open-floating = true; default-column-width = { proportion = 0.5; }; } + ]; + environment = { + DISPLAY = ":0"; + } // vars.waylandSessionVariables; + screenshot-path = "~/Pictures/Screenshots/screenshot_%Y-%m-%d-%H%M%S.png"; + input = { + mod-key = "Super"; + keyboard = { + xkb = { + layout = "us"; + variant = "altgr-intl"; + }; + }; + mouse = { + natural-scroll = false; + }; + touchpad = { + enable = true; + tap = true; + tap-button-map = "left-right-middle"; + natural-scroll = true; + scroll-method = "two-finger"; + click-method = "clickfinger"; + disabled-on-external-mouse = true; + drag = true; + drag-lock = false; + dwt = true; + dwtp = true; + }; + }; + cursor = { + hide-after-inactive-ms = 2000; + hide-when-typing = true; + }; + layout = { + background-color = "transparent"; + border = { + enable = true; + width = 1; + }; + focus-ring = { + enable = false; + }; + gaps = 5; + }; + binds = with config.lib.niri.actions; let + sh = spawn "sh" "-c"; + in + { + + # "Mod+Super_L" = spawn "killall -SIGUSR1 .waybar-wrapped"; + "Mod+z".action = spawn "killall -SIGUSR1 .waybar-wrapped"; + "Mod+Shift+t".action = toggle-window-rule-opacity; + # "Mod+Escape".action = "mode $exit"; + "Mod+m".action = focus-workspace-previous; + "Mod+Shift+Space".action = toggle-window-floating; + "Mod+Shift+f".action = toggle-windowed-fullscreen; + "Mod+q".action = close-window; + "Mod+f".action = spawn "firefox"; + "Mod+Space".action = spawn "fuzzel"; + "Mod+Shift+c".action = spawn "qalculate-gtk"; + "Mod+Ctrl+p".action = spawn "1password" "--quick-acces"; + "Mod+Shift+Escape".action = spawn "kitty" "-o" "confirm_os_window_close=0" "btm"; + "Mod+h".action = sh ''hyprpicker | wl-copy''; + # "Mod+s".action = spawn "grim" "-g" "\"$(slurp)\"" "-t" "png" "-" "|" "wl-copy" "-t" "image/png"; + # "Mod+s".action = screenshot { show-pointer = false; }; + "Mod+s".action.screenshot = { show-pointer = false; }; + # "Mod+Shift+s".action = spawn "slurp" "|" "grim" "-g" "-" "Pictures/Screenshots/$(date +'screenshot_%Y-%m-%d-%H%M%S.png')"; + # "Mod+Shift+s".action = screenshot-window { write-to-disk = true; }; + "Mod+Shift+s".action.screenshot-window = { write-to-disk = true; }; + # "Mod+Shift+v".action = spawn "wf-recorder" "-g" "'$(slurp -f %o -or)'" "-f" "~/Videos/screenrecord_$(date +%Y-%m-%d-%H%M%S).mkv"; + + "Mod+e".action = sh "emacsclient -nquc -a emacs -e '(dashboard-open)'"; + "Mod+c".action = sh "emacsclient -ce '(org-capture)'"; + "Mod+t".action = sh "emacsclient -ce '(org-agenda)'"; + "Mod+Shift+m".action = sh "emacsclient -ce '(mu4e)'"; + "Mod+Shift+a".action = sh "emacsclient -ce '(swarsel/open-calendar)'"; + + "Mod+a".action = spawn "swarselcheck-niri" "-s"; + "Mod+x".action = spawn "swarselcheck-niri" "-k"; + "Mod+d".action = spawn "swarselcheck-niri" "-d"; + "Mod+w".action = spawn "swarselcheck-niri" "-e"; + + "Mod+p".action = spawn "pass-fuzzel"; + "Mod+o".action = spawn "pass-fuzzel" "--otp"; + "Mod+Shift+p".action = spawn "pass-fuzzel" "--type"; + "Mod+Shift+o".action = spawn "pass-fuzzel" "--otp" "--type"; + + "Mod+Left".action = focus-column-or-monitor-left; + "Mod+Right".action = focus-column-or-monitor-right; + "Mod+Down".action = focus-window-or-workspace-down; + "Mod+Up".action = focus-window-or-workspace-up; + "Mod+Shift+Left".action = move-column-left; + "Mod+Shift+Right".action = move-column-right; + "Mod+Shift+Down".action = move-window-down-or-to-workspace-down; + "Mod+Shift+Up".action = move-window-up-or-to-workspace-up; + # "Mod+Ctrl+Shift+c".action = "reload"; + # "Mod+Ctrl+Shift+r".action = "exec swarsel-displaypower"; + # "Mod+Shift+e".action = "exec swaynag -t warning -m 'You pressed the exit shortcut. Do you really want to exit sway? This will end your Wayland session.' -b 'Yes, exit sway' 'swaymsg exit'"; + # "Mod+r".action = "mode resize"; + # "Mod+Return".action = "exec kitty"; + "Mod+Return".action = spawn "swarselzellij"; + "XF86AudioRaiseVolume".action = spawn "swayosd-client" "--output-volume" "raise"; + "XF86AudioLowerVolume".action = spawn "swayosd-client" "--output-volume" "lower"; + "XF86AudioMute".action = spawn "swayosd-client" "--output-volume" "mute-toggle"; + "XF86MonBrightnessUp".action = spawn "swayosd-client" "--brightness raise"; + "XF86MonBrightnessDown".action = spawn "swayosd-client" "--brightness lower"; + "XF86Display".action = spawn "wl-mirror" "eDP-1"; + "Mod+Escape".action = spawn "wlogout"; + "Mod+Equal".action = set-column-width "+10%"; + "Mod+Minus".action = set-column-width "-10%"; + + "Mod+1".action = focus-workspace 1; + "Mod+2".action = focus-workspace 2; + "Mod+3".action = focus-workspace 3; + "Mod+4".action = focus-workspace 4; + "Mod+5".action = focus-workspace 5; + "Mod+6".action = focus-workspace 6; + "Mod+7".action = focus-workspace 7; + "Mod+8".action = focus-workspace 8; + "Mod+9".action = focus-workspace 9; + "Mod+0".action = focus-workspace 0; + + "Mod+Shift+1".action = move-column-to-index 1; + "Mod+Shift+2".action = move-column-to-index 2; + "Mod+Shift+3".action = move-column-to-index 3; + "Mod+Shift+4".action = move-column-to-index 4; + "Mod+Shift+5".action = move-column-to-index 5; + "Mod+Shift+6".action = move-column-to-index 6; + "Mod+Shift+7".action = move-column-to-index 7; + "Mod+Shift+8".action = move-column-to-index 8; + "Mod+Shift+9".action = move-column-to-index 9; + "Mod+Shift+0".action = move-column-to-index 0; + }; + spawn-at-startup = [ + # { command = [ "vesktop" "--start-minimized" "--enable-speech-dispatcher" "--ozone-platform-hint=auto" "--enable-features=WaylandWindowDecorations" "--enable-wayland-ime" ]; } + # { command = [ "element-desktop" "--hidden" "--enable-features=UseOzonePlatform" "--ozone-platform=wayland" "--disable-gpu-driver-bug-workarounds" ]; } + # { command = [ "anki" ]; } + # { command = [ "obsidian" ]; } + # { command = [ "nm-applet" ]; } + { command = [ "niri" "msg" "action" "focus-workspace" "2" ]; } + ]; + workspaces = { + # "01-Main" = { + # name = "Scratchpad"; + # }; + "99-Scratchpad" = { + name = ""; + }; + }; + }; + }; + + } // { + programs.niri = lib.mkIf (!config.swarselmodules.niri) { + package = null; + config = null; + settings = null; + }; + }; + } +#+end_src + +**** Gaming +:PROPERTIES: +:CUSTOM_ID: h:84fd7029-ecb6-4131-9333-289982f24ffa +:END: + +The rest of the settings is at [[#h:fb3f3e01-7df4-4b06-9e91-aa9cac61a431][gaming]]. + +#+begin_src nix-ts :tangle modules/home/optional/gaming.nix + { config, pkgs, confLib, ... }: + let + inherit (config.swarselsystems) isNixos; + in + { + config = { + # specialisation = { + # gaming.configuration = { + home.packages = with pkgs; [ + # lutris + wine + protonplus + winetricks + libudev-zero + dwarfs + fuse-overlayfs + # steam + steam-run + patchelf + gamescope + vulkan-tools + moonlight-qt + ns-usbloader + + quark-goldleaf + + # gog games installing + heroic + + # minecraft + prismlauncher # has overrides + temurin-bin-17 + + pokefinder + retroarch + flips + ]; + + programs.lutris = { + enable = true; + extraPackages = with pkgs; [ + winetricks + gamescope + umu-launcher + ]; + steamPackage = if isNixos then confLib.getConfig.programs.steam.package else pkgs.steam; + winePackages = with pkgs; [ + wineWow64Packages.waylandFull + ]; + protonPackages = with pkgs; [ + proton-ge-bin + ]; + }; + # }; + # }; + }; + } + +#+end_src + +**** Work (pizauth) +:PROPERTIES: +:CUSTOM_ID: h:f0b2ea93-94c8-48d8-8d47-6fe58f58e0e6 +:END: + +The rest of the settings is at [[#h:bbf2ecb6-c8ff-4462-b5d5-d45b28604ddf][work]]. Here, I am setting up the different firefox profiles that I need for the SSO sites that I need to access at work as well as a few ssh shorthands. + +When setting up a new machine: + +#+begin_src markdown :noweb-ref worksetup :exports both :results html + - setup pizauth for microsoft mail sync (account names are possibly `uni` and `work`): + - `pizauth auth ` + - `pizauth dump > ~/.pizauth.state` +#+end_src + +#+begin_src nix-ts :tangle modules/home/optional/work.nix :noweb yes + { self, inputs, config, pkgs, lib, vars, confLib, ... }: + let + inherit (config.swarselsystems) homeDir mainUser; + inherit (confLib.getConfig.repo.secrets.local.mail) allMailAddresses; + inherit (confLib.getConfig.repo.secrets.local.work) mailAddress; + + certsSopsFile = self + /secrets/certs/secrets.yaml; + in + { + options.swarselmodules.optional-work = lib.swarselsystems.mkTrueOption; + config = { + home = { + packages = with pkgs; [ + stable.teams-for-linux + shellcheck + dig + docker + postman + # rclone + libguestfs-with-appliance + prometheus.cli + tigervnc + # openstackclient + + vscode + dev.antigravity + + rustdesk-vbc + ]; + sessionVariables = { + AWS_CA_BUNDLE = confLib.getConfig.sops.secrets.harica-root-ca.path; + }; + }; + systemd.user.sessionVariables = { + DOCUMENT_DIR_WORK = lib.mkForce "${homeDir}/Documents/Work"; + } // lib.optionalAttrs (!config.swarselsystems.isPublic) { + SWARSEL_MAIL_ALL = lib.mkForce allMailAddresses; + SWARSEL_MAIL_WORK = lib.mkForce mailAddress; + }; + + accounts.email.accounts.work = + let + inherit (confLib.getConfig.repo.secrets.local.work) mailName; + in + { + primary = false; + address = mailAddress; + userName = mailAddress; + realName = mailName; + passwordCommand = "pizauth show work"; + imap = { + host = "outlook.office365.com"; + port = 993; + tls.enable = true; # SSL/TLS + }; + smtp = { + host = "outlook.office365.com"; + port = 587; + tls = { + enable = true; # SSL/TLS + useStartTls = true; + }; + }; + thunderbird = { + enable = true; + profiles = [ "default" ]; + settings = id: { + "mail.smtpserver.smtp_${id}.authMethod" = 10; # oauth + "mail.server.server_${id}.authMethod" = 10; # oauth + # "toolkit.telemetry.enabled" = false; + # "toolkit.telemetry.rejected" = true; + # "toolkit.telemetry.prompted" = 2; + }; + }; + msmtp = { + enable = true; + extraConfig = { + auth = "xoauth2"; + host = "outlook.office365.com"; + protocol = "smtp"; + port = "587"; + tls = "on"; + tls_starttls = "on"; + from = "${mailAddress}"; + user = "${mailAddress}"; + passwordeval = "pizauth show work"; + }; + }; + mu.enable = true; + mbsync = { + enable = true; + expunge = "both"; + patterns = [ "INBOX" ]; + extraConfig = { + account = { + AuthMechs = "XOAUTH2"; + }; + }; + }; + }; + + # wayland.windowManager.sway.config = { + # output = { + # "Applied Creative Technology Transmitter QUATTRO201811" = { + # bg = "${self}/files/wallpaper/navidrome.png ${config.stylix.imageScalingMode}"; + # }; + # "Hewlett Packard HP Z24i CN44250RDT" = { + # bg = "${self}/files/wallpaper/op6wp.png ${config.stylix.imageScalingMode}"; + # }; + # "HP Inc. HP 732pk CNC4080YL5" = { + # bg = "${self}/files/wallpaper/botanicswp.png ${config.stylix.imageScalingMode}"; + # }; + # }; + # }; + + wayland.windowManager.sway = + let + inherit (confLib.getConfig.repo.secrets.local.work) user1 user1Long domain1 mailAddress; + in + { + config = { + keybindings = + let + inherit (config.wayland.windowManager.sway.config) modifier; + in + { + "${modifier}+Shift+d" = "exec ${pkgs.quickpass}/bin/quickpass work/adm/${user1}/${user1Long}@${domain1}"; + "${modifier}+Shift+i" = "exec ${pkgs.quickpass}/bin/quickpass work/${mailAddress}"; + }; + }; + }; + + stylix = { + targets.firefox.profileNames = + let + inherit (confLib.getConfig.repo.secrets.local.work) user1 user2 user3; + in + [ + "${user1}" + "${user2}" + "${user3}" + "work" + ]; + }; + + programs = + let + inherit (confLib.getConfig.repo.secrets.local.work) user1 user1Long user2 user2Long user3 user3Long user4 path1 loc1 loc2 site1 site2 site3 site4 site5 site6 site7 lifecycle1 lifecycle2 domain1 domain2 gitMail clouds; + in + { + openstackclient = { + enable = true; + inherit clouds; + }; + awscli = { + enable = true; + package = pkgs.stable24_05.awscli2; + # settings = { + # "default" = { }; + # "profile s3-imagebuilder-prod" = { }; + # }; + # credentials = { + # "s3-imagebuilder-prod" = { + # aws_access_key_id = "5OYXY4879EJG9I91K1B6"; + # credential_process = "${pkgs.pass}/bin/pass show work/awscli/s3-imagebuilder-prod/secret-key"; + # }; + # }; + }; + git.settings.user.email = lib.mkForce gitMail; + + zsh = { + shellAliases = { + dssh = "ssh -l ${user1Long}"; + cssh = "ssh -l ${user2Long}"; + wssh = "ssh -l ${user3Long}"; + }; + cdpath = [ + "~/Documents/Work" + ]; + dirHashes = { + d = "$HOME/.dotfiles"; + w = "$HOME/Documents/Work"; + s = "$HOME/.dotfiles/secrets"; + pr = "$HOME/Documents/Private"; + ac = path1; + }; + + sessionVariables = { + VSPHERE_USER = "$(cat ${confLib.getConfig.sops.secrets.vcuser.path})"; + VSPHERE_PW = "$(cat ${confLib.getConfig.sops.secrets.vcpw.path})"; + GOVC_USERNAME = "$(cat ${confLib.getConfig.sops.secrets.govcuser.path})"; + GOVC_PASSWORD = "$(cat ${confLib.getConfig.sops.secrets.govcpw.path})"; + GOVC_URL = "$(cat ${confLib.getConfig.sops.secrets.govcurl.path})"; + GOVC_DATACENTER = "$(cat ${confLib.getConfig.sops.secrets.govcdc.path})"; + GOVC_DATASTORE = "$(cat ${confLib.getConfig.sops.secrets.govcds.path})"; + GOVC_HOST = "$(cat ${confLib.getConfig.sops.secrets.govchost.path})"; + GOVC_RESOURCE_POOL = "$(cat ${confLib.getConfig.sops.secrets.govcpool.path})"; + GOVC_NETWORK = "$(cat ${confLib.getConfig.sops.secrets.govcnetwork.path})"; + }; + }; + + ssh = { + matchBlocks = { + "${loc1}" = { + hostname = "${loc1}.${domain2}"; + user = user4; + }; + "${loc1}.stg" = { + hostname = "${loc1}.${lifecycle1}.${domain2}"; + user = user4; + }; + "${loc1}.staging" = { + hostname = "${loc1}.${lifecycle1}.${domain2}"; + user = user4; + }; + "${loc1}.dev" = { + hostname = "${loc1}.${lifecycle2}.${domain2}"; + user = user4; + }; + "${loc2}" = { + hostname = "${loc2}.${domain1}"; + user = user1Long; + }; + "${loc2}.stg" = { + hostname = "${loc2}.${lifecycle1}.${domain2}"; + user = user1Long; + }; + "${loc2}.staging" = { + hostname = "${loc2}.${lifecycle1}.${domain2}"; + user = user1Long; + }; + "*.${domain1}" = { + user = user1Long; + }; + }; + }; + + firefox = { + profiles = + let + isDefault = false; + in + { + "${user1}" = lib.recursiveUpdate + { + inherit isDefault; + id = 1; + settings = { + "browser.startup.homepage" = "${site1}|${site2}"; + }; + } + vars.firefox; + "${user2}" = lib.recursiveUpdate + { + inherit isDefault; + id = 2; + settings = { + "browser.startup.homepage" = "${site3}"; + }; + } + vars.firefox; + "${user3}" = lib.recursiveUpdate + { + inherit isDefault; + id = 3; + } + vars.firefox; + work = lib.recursiveUpdate + { + inherit isDefault; + id = 4; + settings = { + "browser.startup.homepage" = "${site4}|${site5}|${site6}|${site7}"; + }; + } + vars.firefox; + }; + }; + + chromium = { + enable = true; + package = pkgs.chromium; + + extensions = [ + # 1password + "gejiddohjgogedgjnonbofjigllpkmbf" + # dark reader + "eimadpbcbfnmbkopoojfekhnkhdbieeh" + # ublock origin + "cjpalhdlnbpafiamejdnhcphjbkeiagm" + # i still dont care about cookies + "edibdbjcniadpccecjdfdjjppcpchdlm" + # browserpass + "naepdomgkenhinolocfifgehidddafch" + ]; + }; + }; + + services = { + kanshi = { + settings = [ + { + # seminary room + output = { + criteria = "Applied Creative Technology Transmitter QUATTRO201811"; + scale = 1.0; + mode = "1280x720"; + }; + } + { + # work main screen + output = { + criteria = "HP Inc. HP 732pk CNC4080YL5"; + scale = 1.0; + mode = "3840x2160"; + }; + } + { + # work side screen + output = { + criteria = "Hewlett Packard HP Z24i CN44250RDT"; + scale = 1.0; + mode = "1920x1200"; + transform = "270"; + }; + } + { + profile = { + name = "lidopen"; + exec = [ + "${pkgs.swaybg}/bin/swaybg --output '${config.swarselsystems.sharescreen}' --image ${config.swarselsystems.wallpaper} --mode ${config.stylix.imageScalingMode}" + "${pkgs.swaybg}/bin/swaybg --output 'HP Inc. HP 732pk CNC4080YL5' --image ${self}/files/wallpaper/botanicswp.png --mode ${config.stylix.imageScalingMode}" + "${pkgs.swaybg}/bin/swaybg --output 'Hewlett Packard HP Z24i CN44250RDT' --image ${self}/files/wallpaper/op6wp.png --mode ${config.stylix.imageScalingMode}" + ]; + outputs = [ + { + criteria = config.swarselsystems.sharescreen; + status = "enable"; + scale = 1.5; + position = "1462,0"; + } + { + criteria = "HP Inc. HP 732pk CNC4080YL5"; + scale = 1.4; + mode = "3840x2160"; + position = "-1280,0"; + } + { + criteria = "Hewlett Packard HP Z24i CN44250RDT"; + scale = 1.0; + mode = "1920x1200"; + transform = "90"; + position = "-2480,0"; + } + ]; + }; + } + { + profile = + let + monitor = "Applied Creative Technology Transmitter QUATTRO201811"; + in + { + name = "lidopen"; + exec = [ + "${pkgs.swaybg}/bin/swaybg --output '${config.swarselsystems.sharescreen}' --image ${config.swarselsystems.wallpaper} --mode ${config.stylix.imageScalingMode}" + "${pkgs.swaybg}/bin/swaybg --output '${monitor}' --image ${self}/files/wallpaper/navidrome.png --mode ${config.stylix.imageScalingMode}" + "${pkgs.kanshare}/bin/kanshare ${config.swarselsystems.sharescreen} '${monitor}'" + ]; + outputs = [ + { + criteria = config.swarselsystems.sharescreen; + status = "enable"; + scale = 1.7; + position = "2560,0"; + } + { + criteria = "Applied Creative Technology Transmitter QUATTRO201811"; + scale = 1.0; + mode = "1280x720"; + position = "10000,10000"; + } + ]; + }; + } + { + profile = { + name = "lidclosed"; + exec = [ + "${pkgs.swaybg}/bin/swaybg --output 'HP Inc. HP 732pk CNC4080YL5' --image ${self}/files/wallpaper/botanicswp.png --mode ${config.stylix.imageScalingMode}" + "${pkgs.swaybg}/bin/swaybg --output 'Hewlett Packard HP Z24i CN44250RDT' --image ${self}/files/wallpaper/op6wp.png --mode ${config.stylix.imageScalingMode}" + ]; + outputs = [ + { + criteria = config.swarselsystems.sharescreen; + status = "disable"; + } + { + criteria = "HP Inc. HP 732pk CNC4080YL5"; + scale = 1.4; + mode = "3840x2160"; + position = "-1280,0"; + } + { + criteria = "Hewlett Packard HP Z24i CN44250RDT"; + scale = 1.0; + mode = "1920x1200"; + transform = "270"; + position = "-2480,0"; + } + ]; + }; + } + { + profile = + let + monitor = "Applied Creative Technology Transmitter QUATTRO201811"; + in + { + name = "lidclosed"; + exec = [ + "${pkgs.swaybg}/bin/swaybg --output '${monitor}' --image ${self}/files/wallpaper/navidrome.png --mode ${config.stylix.imageScalingMode}" + ]; + outputs = [ + { + criteria = config.swarselsystems.sharescreen; + status = "disable"; + } + { + criteria = "Applied Creative Technology Transmitter QUATTRO201811"; + scale = 1.0; + mode = "1280x720"; + position = "10000,10000"; + } + ]; + }; + } + ]; + }; + }; + + systemd.user.services = { + pizauth.Service = { + ExecStartPost = [ + "${pkgs.toybox}/bin/sleep 1" + "//bin/sh -c '${lib.getExe pkgs.pizauth} restore < ${homeDir}/.pizauth.state'" + ]; + }; + + teams-applet = { + Unit = { + Description = "teams applet"; + Requires = [ "tray.target" ]; + After = [ + "graphical-session.target" + "tray.target" + ]; + PartOf = [ "graphical-session.target" ]; + }; + + Install = { + WantedBy = [ "graphical-session.target" ]; + }; + + Service = { + ExecStart = "${pkgs.stable.teams-for-linux}/bin/teams-for-linux --disableGpu=true --minimized=true --trayIconEnabled=true"; + }; + }; + + onepassword-applet = { + Unit = { + Description = "1password applet"; + Requires = [ "tray.target" ]; + After = [ + "graphical-session.target" + "tray.target" + ]; + PartOf = [ "graphical-session.target" ]; + }; + + Install = { + WantedBy = [ "graphical-session.target" ]; + }; + + Service = { + ExecStart = "${pkgs._1password-gui}/bin/1password"; + }; + }; + + }; + + services.pizauth = { + enable = true; + extraConfig = '' + auth_notify_cmd = "if [[ \"$(notify-send -A \"Open $PIZAUTH_ACCOUNT\" -t 30000 'pizauth authorisation')\" == \"0\" ]]; then open \"$PIZAUTH_URL\"; fi"; + error_notify_cmd = "notify-send -t 90000 \"pizauth error for $PIZAUTH_ACCOUNT\" \"$PIZAUTH_MSG\""; + token_event_cmd = "pizauth dump > ${homeDir}/.pizauth.state"; + ''; + accounts = { + work = { + authUri = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize"; + tokenUri = "https://login.microsoftonline.com/common/oauth2/v2.0/token"; + clientId = "08162f7c-0fd2-4200-a84a-f25a4db0b584"; + clientSecret = "TxRBilcHdC6WGBee]fs?QR:SJ8nI[g82"; + scopes = [ + "https://outlook.office365.com/IMAP.AccessAsUser.All" + "https://outlook.office365.com/SMTP.Send" + "offline_access" + ]; + loginHint = "${confLib.getConfig.repo.secrets.local.work.mailAddress}"; + }; + }; + + }; + + xdg = + let + inherit (confLib.getConfig.repo.secrets.local.work) user1 user2 user3; + in + { + mimeApps = { + defaultApplications = { + "x-scheme-handler/msteams" = [ "teams-for-linux.desktop" ]; + }; + }; + desktopEntries = + let + terminal = false; + categories = [ "Application" ]; + icon = "firefox"; + in + { + firefox_work = { + name = "Firefox (work)"; + genericName = "Firefox work"; + exec = "firefox -p work"; + inherit terminal categories icon; + }; + "firefox_${user1}" = { + name = "Firefox (${user1})"; + genericName = "Firefox ${user1}"; + exec = "firefox -p ${user1}"; + inherit terminal categories icon; + }; + + "firefox_${user2}" = { + name = "Firefox (${user2})"; + genericName = "Firefox ${user2}"; + exec = "firefox -p ${user2}"; + inherit terminal categories icon; + }; + + "firefox_${user3}" = { + name = "Firefox (${user3})"; + genericName = "Firefox ${user3}"; + exec = "firefox -p ${user3}"; + inherit terminal categories icon; + }; + + + }; + }; + swarselsystems = { + startup = [ + # { command = "nextcloud --background"; } + # { command = "vesktop --start-minimized --enable-speech-dispatcher --ozone-platform-hint=auto --enable-features=WaylandWindowDecorations --enable-wayland-ime"; } + # { command = "element-desktop --hidden --enable-features=UseOzonePlatform --ozone-platform=wayland --disable-gpu-driver-bug-workarounds"; } + # { command = "anki"; } + # { command = "obsidian"; } + # { command = "nm-applet"; } + # { command = "feishin"; } + # { command = "teams-for-linux --disableGpu=true --minimized=true --trayIconEnabled=true"; } + # { command = "1password"; } + ]; + monitors = { + work_back_middle = rec { + name = "LG Electronics LG Ultra HD 0x000305A6"; + mode = "2560x1440"; + scale = "1"; + position = "5120,0"; + workspace = "1:一"; + # output = "DP-10"; + output = name; + }; + work_front_left = rec { + name = "LG Electronics LG Ultra HD 0x0007AB45"; + mode = "3840x2160"; + scale = "1"; + position = "5120,0"; + workspace = "1:一"; + # output = "DP-7"; + output = name; + }; + work_back_right = rec { + name = "HP Inc. HP Z32 CN41212T55"; + mode = "3840x2160"; + scale = "1"; + position = "5120,0"; + workspace = "1:一"; + # output = "DP-3"; + output = name; + }; + work_middle_middle_main = rec { + name = "HP Inc. HP 732pk CNC4080YL5"; + mode = "3840x2160"; + scale = "1"; + position = "-1280,0"; + workspace = "11:M"; + # output = "DP-8"; + output = name; + }; + work_middle_middle_side = rec { + name = "Hewlett Packard HP Z24i CN44250RDT"; + mode = "1920x1200"; + transform = "270"; + scale = "1"; + position = "-2480,0"; + workspace = "12:S"; + # output = "DP-9"; + output = name; + }; + work_seminary = rec { + name = "Applied Creative Technology Transmitter QUATTRO201811"; + mode = "1280x720"; + scale = "1"; + position = "10000,10000"; # i.e. this screen is inaccessible by moving the mouse + workspace = "14:T"; + # output = "DP-4"; + output = name; + }; + }; + inputs = { + "1133:45081:MX_Master_2S_Keyboard" = { + xkb_layout = "us"; + xkb_variant = "altgr-intl"; + }; + # "2362:628:PIXA3854:00_093A:0274_Touchpad" = { + # dwt = "enabled"; + # tap = "enabled"; + # natural_scroll = "enabled"; + # middle_emulation = "enabled"; + # drag_lock = "disabled"; + # }; + "1133:50504:Logitech_USB_Receiver" = { + xkb_layout = "us"; + xkb_variant = "altgr-intl"; + }; + "1133:45944:MX_KEYS_S" = { + xkb_layout = "us"; + xkb_variant = "altgr-intl"; + }; + }; + + }; + } // lib.optionalAttrs (inputs ? sops) { + sops.secrets = lib.mkIf (!config.swarselsystems.isPublic && !config.swarselsystems.isNixos) { + harica-root-ca = { + sopsFile = certsSopsFile; + path = "${homeDir}/.aws/certs/harica-root.pem"; + owner = mainUser; + }; + }; + + }; + + } + +#+end_src + +**** Uni +:PROPERTIES: +:CUSTOM_ID: h:52b41e73-46f3-4c2c-af64-eafb51e3b6b6 +:END: + +#+begin_src nix-ts :tangle modules/home/optional/uni.nix :noweb yes + { confLib, ... }: + { + config = { + services.pizauth = { + enable = true; + accounts = { + uni = { + authUri = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize"; + tokenUri = "https://login.microsoftonline.com/common/oauth2/v2.0/token"; + clientId = "08162f7c-0fd2-4200-a84a-f25a4db0b584"; + clientSecret = "TxRBilcHdC6WGBee]fs?QR:SJ8nI[g82"; + scopes = [ + "https://outlook.office365.com/IMAP.AccessAsUser.All" + "https://outlook.office365.com/SMTP.Send" + "offline_access" + ]; + loginHint = "${confLib.getConfig.repo.secrets.local.uni.mailAddress}"; + }; + }; + }; + }; + } + +#+end_src + +**** Framework +:PROPERTIES: +:CUSTOM_ID: h:8a7b1c26-3448-42d3-932a-5d05d54b5490 +:END: + +This holds configuration that is specific to framework laptops. + +#+begin_src nix-ts :tangle modules/home/optional/framework.nix + _: + { + config = { + swarselsystems = { + inputs = { + "12972:18:Framework_Laptop_16_Keyboard_Module_-_ANSI_Keyboard" = { + xkb_layout = "us"; + xkb_variant = "altgr-intl"; + }; + }; + }; + }; + } +#+end_src +** Shared +:PROPERTIES: +:CUSTOM_ID: h:3552f06f-07e0-4bb1-a50f-fd1efb2d7778 +:END: + +This section is for modules that are to be used on =NixOS= and =home-manager= scopes alike. This is for example needed in order to allow me to define and set my own custom functions only once in the =NixOS= config and then mirror them into the corresponding =home-manager= option. + +*** TODO Configuration options +:PROPERTIES: +:CUSTOM_ID: h:79f7150f-b162-4f57-abdf-07f40dffd932 +:END: + +These are my own configuration options that are used in multiple places throughout the configuration - for which reason I did not put them right where they are used for the first time. + +TODO: check which of these can be replaced but builtin functions. + +#+begin_src nix-ts :noweb yes :tangle modules/shared/options.nix + { self, config, lib, ... }: + { + options.swarselsystems = { + proxyHost = lib.mkOption { + type = lib.types.str; + default = config.node.name; + }; + isBastionTarget = lib.mkOption { + type = lib.types.bool; + default = false; + }; + isCloud = lib.mkOption { + type = lib.types.bool; + default = false; + }; + isServer = lib.mkOption { + type = lib.types.bool; + default = config.swarselsystems.isCloud; + }; + isClient = lib.mkOption { + type = lib.types.bool; + default = config.swarselsystems.isLaptop; + }; + withHomeManager = lib.mkOption { + type = lib.types.bool; + default = true; + }; + isSwap = lib.mkOption { + type = lib.types.bool; + default = true; + }; + swapSize = lib.mkOption { + type = lib.types.str; + default = "8G"; + }; + rootDisk = lib.mkOption { + type = lib.types.str; + default = ""; + }; + mainUser = lib.mkOption { + type = lib.types.str; + default = "swarsel"; + }; + isCrypted = lib.mkEnableOption "uses full disk encryption"; + withMicroVMs = lib.mkEnableOption "enable MicroVMs on this host"; + + isImpermanence = lib.mkEnableOption "use impermanence on this system"; + isSecureBoot = lib.mkEnableOption "use secure boot on this system"; + isLaptop = lib.mkEnableOption "laptop host"; + isNixos = lib.mkEnableOption "nixos host"; + isPublic = lib.mkEnableOption "is a public machine (no secrets)"; + isDarwin = lib.mkEnableOption "darwin host"; + isLinux = lib.mkEnableOption "whether this is a linux machine"; + isBtrfs = lib.mkEnableOption "use btrfs filesystem"; + sopsFile = lib.mkOption { + type = lib.types.str; + default = "${if config.swarselsystems.isImpermanence then "/persist" else ""}${config.swarselsystems.flakePath}/secrets/${config.node.name}/secrets.yaml"; + }; + homeDir = lib.mkOption { + type = lib.types.str; + default = "/home/swarsel"; + }; + xdgDir = lib.mkOption { + type = lib.types.str; + default = "/run/user/1000"; + }; + flakePath = lib.mkOption { + type = lib.types.str; + default = "/home/swarsel/.dotfiles"; + }; + wallpaper = lib.mkOption { + type = lib.types.path; + default = "${self}/files/wallpaper/lenovowp.png"; + }; + sharescreen = lib.mkOption { + type = lib.types.str; + default = ""; + }; + lowResolution = lib.mkOption { + type = lib.types.str; + default = ""; + }; + highResolution = lib.mkOption { + type = lib.types.str; + default = ""; + }; + }; + } +#+end_src + +*** Variables (vars; holds firefox & stylix config parts) +:PROPERTIES: +:CUSTOM_ID: h:ea362c55-97b4-45fd-bf41-ab461c444212 +:END: + +At work I am using several services that are using SSO login - however, as I am using four different accounts at work, this becomes a chore here. Hence, I have defined multiple profiles in [[#h:f0b2ea93-94c8-48d8-8d47-6fe58f58e0e6][Work]] that are all practically using the same configuration. To save screen space, I template that profile here. +Set in firefox =about:config > toolkit.legacyUserProfileCustomizations.stylesheets= to true. This should in principle be set automatically using the below config, but it seems not to be working reliably. + +For styling, I am using the [[https://github.com/danth/stylix][stylix]] NixOS module, loaded by flake. This package is really great, as it adds nix expressions for basically everything. Ever since switching to this, I did not have to play around with theming anywhere else. + +The full list of nerd-fonts can be found here: https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/data/fonts/nerd-fonts/manifests/fonts.json + +This is where the theme for the whole OS is defined. Originally, this noweb-ref section could not be copied to the general NixOS config since they are on different folder structure levels in the config, which would have made the flake impure. By now, I have found out that using the =${self}= method for referencing the flake root, I could circumvent this problem. Also, the noweb-ref block could in general be replaced by a custom attribute set (see for example [[#h:e7f98ad8-74a6-4860-a368-cce154285ff0][firefox]]). The difference here was, for a long time, that this block is used in a NixOS and a home-manager-only configuration, verbatim. If I were to use an attribute set, I would have to duplicate this block once each for NixOS and home-manager. Alas, this block stays (for now). However, I learned how to use an attribute set in a custom home-manager module and pass it to both NixOS and home-manager configurations, which also removed the need for that use of it. + +In short, the options defined here are passed to the modules systems using =_modules.args= - they can then be used by passing =vars= as an attribute in the input attribute set of a modules system file (=basically all files in this configuration) + +#+begin_src nix-ts :noweb yes :tangle modules/shared/vars.nix + { self, lib, pkgs, ... }: + { + _module.args = { + vars = rec { + waylandSessionVariables = { + SDL_VIDEODRIVER = "wayland"; + QT_WAYLAND_DISABLE_WINDOWDECORATION = "1"; + QT_QPA_PLATFORM = "wayland-egl"; + ANKI_WAYLAND = "1"; + OBSIDIAN_USE_WAYLAND = "1"; + MOZ_ENABLE_WAYLAND = "1"; + }; + + waylandExports = + let + renderedWaylandExports = map (key: "export ${key}=${waylandSessionVariables.${key}};") (builtins.attrNames waylandSessionVariables); + in + builtins.concatStringsSep "\n" renderedWaylandExports; + + stylix = { + polarity = "dark"; + opacity.popups = 0.5; + cursor = { + package = pkgs.banana-cursor; + # package = pkgs.capitaine-cursors; + name = "Banana"; + # name = "capitaine-cursors"; + size = 16; + }; + fonts = { + sizes = { + terminal = 10; + applications = 11; + }; + serif = { + # package = (pkgs.nerdfonts.override { fonts = [ "FiraMono" "FiraCode"]; }); + package = pkgs.cantarell-fonts; + # package = pkgs.montserrat; + name = "Cantarell"; + # name = "FiraCode Nerd Font Propo"; + # name = "Montserrat"; + }; + sansSerif = { + # package = (pkgs.nerdfonts.override { fonts = [ "FiraMono" "FiraCode"]; }); + package = pkgs.cantarell-fonts; + # package = pkgs.montserrat; + name = "Cantarell"; + # name = "FiraCode Nerd Font Propo"; + # name = "Montserrat"; + }; + monospace = { + package = pkgs.nerd-fonts.fira-mono; # has overrides + name = "FiraCode Nerd Font Mono"; + }; + emoji = { + package = pkgs.noto-fonts-color-emoji; + name = "Noto Color Emoji"; + }; + }; + }; + + stylixHomeTargets = { + emacs.enable = false; + waybar.enable = false; + sway.useWallpaper = false; + spicetify.enable = true; + firefox.profileNames = [ "default" ]; + }; + + firefox = { + userChrome = builtins.readFile "${self}/files/firefox/chrome/userChrome.css"; + extensions = { + packages = with pkgs.nur.repos.rycee.firefox-addons; [ + tridactyl + tampermonkey + sidebery + browserpass + clearurls + darkreader + # enhancer-for-youtube + istilldontcareaboutcookies + translate-web-pages + ublock-origin + reddit-enhancement-suite + sponsorblock + web-archives + onepassword-password-manager + single-file + widegithub + enhanced-github + unpaywall + don-t-fuck-with-paste + # plasma-integration + noscript + + # configure a shortcut 'ctrl+shift+c' with behaviour 'do nothing' in order to disable the dev console shortcut + (buildFirefoxXpiAddon { + pname = "shortkeys"; + version = "4.0.2"; + addonId = "Shortkeys@Shortkeys.com"; + url = "https://addons.mozilla.org/firefox/downloads/file/3673761/shortkeys-4.0.2.xpi"; + sha256 = "c6fe12efdd7a871787ac4526eea79ecc1acda8a99724aa2a2a55c88a9acf467c"; + meta = with lib; + { + description = "Easily customizable custom keyboard shortcuts for Firefox. To configure this addon go to Addons (ctrl+shift+a) ->Shortkeys ->Options. Report issues here (please specify that the issue is found in Firefox): https://github.com/mikecrittenden/shortkeys"; + mozPermissions = [ + "tabs" + "downloads" + "clipboardWrite" + "browsingData" + "storage" + "bookmarks" + "sessions" + "" + ]; + platforms = platforms.all; + }; + }) + ]; + }; + + settings = + { + "extensions.autoDisableScopes" = 0; + "browser.bookmarks.showMobileBookmarks" = true; + "browser.autofocus" = false; + "toolkit.legacyUserProfileCustomizations.stylesheets" = true; + "browser.search.suggest.enabled" = false; + "browser.search.suggest.enabled.private" = false; + "browser.urlbar.suggest.searches" = false; + "browser.urlbar.showSearchSuggestionsFirst" = false; + "browser.topsites.contile.enabled" = false; + "browser.newtabpage.activity-stream.feeds.section.topstories" = false; + "browser.newtabpage.activity-stream.feeds.snippets" = false; + "browser.newtabpage.activity-stream.section.highlights.includePocket" = false; + "browser.newtabpage.activity-stream.section.highlights.includeBookmarks" = false; + "browser.newtabpage.activity-stream.section.highlights.includeDownloads" = false; + "browser.newtabpage.activity-stream.section.highlights.includeVisited" = false; + "browser.newtabpage.activity-stream.showSponsored" = false; + "browser.newtabpage.activity-stream.system.showSponsored" = false; + "browser.newtabpage.activity-stream.showSponsoredTopSites" = false; + }; + + search = { + # default = "Kagi"; + default = "google"; + # privateDefault = "Kagi"; + privateDefault = "google"; + engines = { + "Kagi" = { + urls = [{ + template = "https://kagi.com/search"; + params = [ + { name = "q"; value = "{searchTerms}"; } + ]; + }]; + icon = "https://kagi.com/favicon.ico"; + updateInterval = 24 * 60 * 60 * 1000; # every day + definedAliases = [ "@k" ]; + }; + + "Nix Packages" = { + urls = [{ + template = "https://search.nixos.org/packages"; + params = [ + { name = "type"; value = "packages"; } + { name = "query"; value = "{searchTerms}"; } + ]; + }]; + icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg"; + definedAliases = [ "@np" ]; + }; + + "NixOS Wiki" = { + urls = [{ + template = "https://nixos.wiki/index.php?search={searchTerms}"; + }]; + icon = "https://nixos.wiki/favicon.png"; + updateInterval = 24 * 60 * 60 * 1000; # every day + definedAliases = [ "@nw" ]; + }; + + "NixOS Options" = { + urls = [{ + template = "https://search.nixos.org/options"; + params = [ + { name = "query"; value = "{searchTerms}"; } + ]; + }]; + + icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg"; + definedAliases = [ "@no" ]; + }; + + "Home Manager Options" = { + urls = [{ + template = "https://home-manager-options.extranix.com/"; + params = [ + { name = "query"; value = "{searchTerms}"; } + ]; + }]; + + icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg"; + definedAliases = [ "@hm" "@ho" "@hmo" ]; + }; + + "Confluence search" = { + urls = [{ + template = "https://vbc.atlassian.net/wiki/search"; + params = [ + { name = "text"; value = "{searchTerms}"; } + ]; + }]; + + definedAliases = [ "@c" "@cf" "@confluence" ]; + }; + + "Jira search" = { + urls = [{ + template = "https://vbc.atlassian.net/issues/"; + params = [ + { name = "jql"; value = "textfields ~ \"{searchTerms}*\"&wildcardFlag=true"; } + ]; + }]; + + definedAliases = [ "@j" "@jire" ]; + }; + + "google".metaData.alias = "@g"; + }; + force = true; # this is required because otherwise the search.json.mozlz4 symlink gets replaced on every firefox restart + }; + }; + }; + }; + } +#+end_src + +*** Config Library (confLib) +:PROPERTIES: +:CUSTOM_ID: h:a33322d5-014a-4072-a4a5-91bc71c343b8 +:END: +#+begin_src nix-ts :noweb yes :tangle modules/shared/config-lib.nix + { config, lib, globals, nixosConfig ? null, ... }: + { + _module.args = { + confLib = rec { + + addressDefault = if config.swarselsystems.proxyHost != config.node.name then globals.networks.${config.swarselsystems.server.netConfigName}.hosts.${config.node.name}.ipv4 else "localhost"; + + domainDefault = service: config.repo.secrets.common.services.domains.${service}; + proxyDefault = config.swarselsystems.proxyHost; + + getConfig = if nixosConfig == null then config else nixosConfig; + + gen = { name, user ? name, group ? name, dir ? null, port ? null, domain ? (domainDefault name), address ? addressDefault, proxy ? proxyDefault }: rec { + servicePort = port; + serviceName = name; + specificServiceName = "${name}-${config.node.name}"; + serviceUser = user; + serviceGroup = group; + serviceDomain = domain; + baseDomain = lib.swarselsystems.getBaseDomain domain; + subDomain = lib.swarselsystems.getSubDomain domain; + serviceDir = dir; + serviceAddress = address; + serviceProxy = proxy; + proxyAddress4 = globals.hosts.${proxy}.wanAddress4; + proxyAddress6 = globals.hosts.${proxy}.wanAddress6 or null; + }; + }; + }; + } +#+end_src *** Packages :PROPERTIES: @@ -2081,38 +21764,23 @@ This is the central station for self-defined packages. These are all referenced 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. -#+begin_src nix :tangle pkgs/default.nix - { pkgs, ... }: +*** Packages (flake) +:PROPERTIES: +:CUSTOM_ID: h:2803e3ab-b746-46c0-bcc4-051a23185bc3 +:END: + +#+begin_src nix-ts :tangle pkgs/flake/default.nix + { self, lib, pkgs, ... }: let - packageNames = [ - "pass-fuzzel" - "cura5" - "hm-specialisation" - "cdw" - "cdb" - "bak" - "timer" - "e" - "swarselcheck" - "waybarupdate" - "opacitytoggle" - "fs-diff" - "update-checker" - "github-notifications" - "screenshare" - "bootstrap" - "swarsel-install" - "t2ts" - "ts2t" - "vershell" - "eontimer" - ]; - mkPackages = names: builtins.listToAttrs (map (name: { - inherit name; - value = pkgs.callPackage ./${name} { }; - }) names); - in - mkPackages packageNames + mkPackages = names: pkgs: builtins.listToAttrs (map + (name: { + inherit name; + value = pkgs.callPackage "${self}/pkgs/flake/${name}" { inherit self name; }; + }) + names); + packageNames = lib.swarselsystems.readNix "pkgs/flake"; + in + mkPackages packageNames pkgs #+end_src @@ -2124,7 +21792,7 @@ 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 scripts/pass-fuzzel.sh +#+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 @@ -2178,13 +21846,41 @@ This app allows me, in conjunction with my Yubikey, to quickly enter passwords w notify-send -u critical -a pass -t 1000 "Copied/Typed Password" #+end_src -#+begin_src nix :tangle pkgs/pass-fuzzel/default.nix - { writeShellApplication, libnotify, pass, fuzzel, wtype }: - +#+begin_src nix-ts :tangle pkgs/flake/pass-fuzzel/default.nix + { self, name, writeShellApplication, libnotify, pass, fuzzel, wtype }: writeShellApplication { - name = "pass-fuzzel"; + inherit name; runtimeInputs = [ libnotify (pass.withExtensions (exts: [ exts.pass-otp ])) fuzzel wtype ]; - text = builtins.readFile ../../scripts/pass-fuzzel.sh; + text = builtins.readFile "${self}/files/scripts/${name}.sh"; + } + +#+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 + +#+begin_src nix-ts :tangle pkgs/flake/quickpass/default.nix + { self, name, writeShellApplication, libnotify, pass, wtype }: + writeShellApplication { + inherit name; + runtimeInputs = [ libnotify pass wtype ]; + text = builtins.readFile "${self}/files/scripts/${name}.sh"; } #+end_src @@ -2197,8 +21893,9 @@ This app allows me, in conjunction with my Yubikey, to quickly enter passwords w The version of =cura= used to be quite outdated in nixpkgs. I am fetching a newer AppImage here and use that instead. -#+begin_src nix :tangle pkgs/cura5/default.nix - { appimageTools, fetchurl, writeScriptBin, pkgs }: +#+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 @@ -2237,18 +21934,18 @@ The version of =cura= used to be quite outdated in nixpkgs. I am fetching a newe This script allows for quick git home-manager specialisation switching. -#+begin_src nix :tangle pkgs/hm-specialisation/default.nix - { writeShellApplication, fzf, findutils, home-manager }: +#+begin_src nix-ts :tangle pkgs/flake/hm-specialisation/default.nix + { name, writeShellApplication, fzf, findutils, home-manager, ... }: - writeShellApplication { - name = "hm-specialisation"; - runtimeInputs = [ fzf findutils home-manager ]; - text = '' - genpath=$(home-manager generations | head -1 | awk '{print $7}') - dirs=$(find "$genpath/specialisation" -type l 2>/dev/null; [ -d "$genpath" ] && echo "$genpath") - "$(echo "$dirs" | fzf --prompt="Choose home-manager specialisation to activate")"/activate - ''; - } + writeShellApplication { + inherit name; + runtimeInputs = [ fzf findutils home-manager ]; + text = '' + genpath=$(home-manager generations | head -1 | awk '{print $7}') + dirs=$(find "$genpath/specialisation" -type l 2>/dev/null; [ -d "$genpath" ] && echo "$genpath") + "$(echo "$dirs" | fzf --prompt="Choose home-manager specialisation to activate")"/activate + ''; + } #+end_src @@ -2261,11 +21958,11 @@ This script allows for quick git home-manager specialisation switching. This script allows for quick git worktree switching. -#+begin_src nix :tangle pkgs/cdw/default.nix - { writeShellApplication, fzf }: +#+begin_src nix-ts :tangle pkgs/flake/cdw/default.nix + { name, writeShellApplication, fzf, ... }: writeShellApplication { - name = "cdw"; + inherit name; runtimeInputs = [ fzf ]; text = '' cd "$(git worktree list | fzf | awk '{print $1}')" @@ -2282,11 +21979,11 @@ This script allows for quick git worktree switching. This script allows for quick git branch switching. -#+begin_src nix :tangle pkgs/cdb/default.nix - { writeShellApplication, fzf }: +#+begin_src nix-ts :tangle pkgs/flake/cdb/default.nix + { name, writeShellApplication, fzf, ... }: writeShellApplication { - name = "cdb"; + inherit name; runtimeInputs = [ fzf ]; text = '' git checkout "$(git branch --list | grep -v "^\*" | fzf | awk '{print $1}')" @@ -2303,13 +22000,13 @@ This script allows for quick git branch switching. This script lets me quickly backup files by appending =.bak= to the filename. -#+begin_src nix :tangle pkgs/bak/default.nix - { writeShellApplication }: +#+begin_src nix-ts :tangle pkgs/flake/bak/default.nix + { name, writeShellApplication, ... }: writeShellApplication { - name = "bak"; + inherit name; text = '' - cp "$1"{,.bak} + cp -r "$1"{,.bak} ''; } @@ -2324,11 +22021,11 @@ This script lets me quickly backup files by appending =.bak= to the filename. This app starts a configuratble timer and uses TTS to say something once the timer runs out. -#+begin_src nix :tangle pkgs/timer/default.nix - { writeShellApplication, speechd }: +#+begin_src nix-ts :tangle pkgs/flake/timer/default.nix + { name, writeShellApplication, speechd, ... }: writeShellApplication { - name = "timer"; + inherit name; runtimeInputs = [ speechd ]; text = '' sleep "$1"; while true; do spd-say "$2"; sleep 0.5; done; @@ -2344,7 +22041,7 @@ 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 scripts/e.sh +#+begin_src shell :tangle files/scripts/e.sh wait=0 while :; do case ${1:-} in @@ -2370,13 +22067,12 @@ This is a shorthand for calling emacsclient mostly. Also, it hides the kittyterm fi #+end_src -#+begin_src nix :tangle pkgs/e/default.nix - { writeShellApplication, emacs30-pgtk, sway, jq }: - +#+begin_src nix-ts :tangle pkgs/flake/e/default.nix + { self, name, writeShellApplication, emacs30-pgtk, sway, jq }: writeShellApplication { - name = "e"; + inherit name; runtimeInputs = [ emacs30-pgtk sway jq ]; - text = builtins.readFile ../../scripts/e.sh; + text = builtins.readFile "${self}/files/scripts/${name}.sh"; } #+end_src @@ -2389,7 +22085,7 @@ This is a shorthand for calling emacsclient mostly. Also, it hides the kittyterm 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 scripts/command-not-found.sh +#+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 @@ -2398,7 +22094,7 @@ The normal =command-not-found.sh= uses the outdated =nix-shell= commands as sugg fi echo -n "searching nix-index..." - ATTRS=$(@nix-locate@ --minimal --no-group --type x --type s --top-level --whole-name --at-root "/bin/$1") + ATTRS=$(@nix-locate@ --minimal --no-group --type x --type s --whole-name --at-root "/bin/$1") case $(echo -n "$ATTRS" | grep -c "^") in 0) @@ -2432,7 +22128,7 @@ 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 scripts/swarselcheck.sh +#+begin_src shell :tangle files/scripts/swarselcheck.sh kitty=0 element=0 vesktop=0 @@ -2460,7 +22156,7 @@ This app checks for different apps that I keep around in the scratchpad for quic 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 -T kittyterm & + exec kitty --app-id kittyterm -T kittyterm -o confirm_os_window_close=0 zellij attach --create kittyterm & sleep 1 fi if [ "$STR" == "" ]; then @@ -2486,7 +22182,7 @@ This app checks for different apps that I keep around in the scratchpad for quic 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 -T spotifytui -o confirm_os_window_close=0 spotify_player & + exec kitty --add-id spotifytui -T spotifytui -o confirm_os_window_close=0 spotify_player & sleep 1 fi if [ "$STR" == "" ]; then @@ -2497,13 +22193,92 @@ This app checks for different apps that I keep around in the scratchpad for quic fi #+end_src -#+begin_src nix :tangle pkgs/swarselcheck/default.nix - { writeShellApplication, kitty, element-desktop-wayland, vesktop, spotify-player, jq }: - +#+begin_src nix-ts :tangle pkgs/flake/swarselcheck/default.nix + { self, name, writeShellApplication, kitty, element-desktop, vesktop, spotify-player, jq }: writeShellApplication { - name = "swarselcheck"; - runtimeInputs = [ kitty element-desktop-wayland vesktop spotify-player jq ]; - text = builtins.readFile ../../scripts/swarselcheck.sh; + inherit name; + runtimeInputs = [ kitty element-desktop vesktop spotify-player jq ]; + text = builtins.readFile "${self}/files/scripts/${name}.sh"; + } + +#+end_src + +**** swarselcheck-niri +:PROPERTIES: +:CUSTOM_ID: h:96da8360-2d23-4e86-9602-415fbdb972af +:END: + +#+begin_src shell :tangle files/scripts/swarselcheck-niri.sh + while :; do + case ${1:-} in + -k | --kitty) + cmd=(sh -c 'kitty --app-id kittyterm -T kittyterm -o confirm_os_window_close=0 zellij attach --create kittyterm' '&') + searchapp="kittyterm" + ;; + -e | --element) + cmd=(element-desktop) + searchapp="Element" + ;; + -d | --vesktop) + cmd=(vesktop) + searchapp="vesktop" + ;; + -s | --spotifyplayer) + cmd=(sh -c 'kitty --add-id spotifytui -T spotifytui -o confirm_os_window_close=0 spotify_player' '&') + searchapp="spotifytui" + ;; + ,*) break ;; + esac + shift + done + + WIN_INFO=$(niri msg -j windows | jq --arg search "$searchapp" '.[] | select (.app_id | test($search)) | { id, is_focused, workspace_id }') + ID=$(echo "$WIN_INFO" | jq -r '.id // empty') + IS_FOCUSED=$(echo "$WIN_INFO" | jq -r '.is_focused // empty') + TARGET_MONITOR=$(niri msg -j workspaces | jq --arg search "" '.[] | select (.name != null and (.name | test($search))) | { output }' | jq -r '.output // empty') + CURRENT_WORKSPACE=$(niri msg -j workspaces | jq -r '.[] | select (.is_active == true) | .output // empty') + + if [ -z "$ID" ]; then + niri msg action spawn -- "${cmd[@]}" + elif [ "$IS_FOCUSED" ]; then + niri msg action move-window-to-workspace "" --window-id "$ID" --focus false + else + niri msg action focus-monitor "$TARGET_MONITOR" && niri msg action move-window-to-workspace "$CURRENT_WORKSPACE" --window-id "$ID" && niri msg action focus-floating + fi +#+end_src + +#+begin_src nix-ts :tangle pkgs/flake/swarselcheck-niri/default.nix + { self, 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"; + } + +#+end_src + +**** swarselzellij +:PROPERTIES: +: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 + +#+begin_src nix-ts :tangle pkgs/flake/swarselzellij/default.nix + { self, name, writeShellApplication, kitty }: + writeShellApplication { + inherit name; + runtimeInputs = [ kitty ]; + text = builtins.readFile "${self}/files/scripts/${name}.sh"; } #+end_src @@ -2515,7 +22290,7 @@ 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 scripts/waybarupdate.sh +#+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))) @@ -2542,13 +22317,12 @@ This scripts checks if there are uncommited changes in either my dotfile repo, m echo "$OUT" #+end_src -#+begin_src nix :tangle pkgs/waybarupdate/default.nix - { writeShellApplication, git }: - +#+begin_src nix-ts :tangle pkgs/flake/waybarupdate/default.nix + { self, name, writeShellApplication, git }: writeShellApplication { - name = "waybarupdate"; + inherit name; runtimeInputs = [ git ]; - text = builtins.readFile ../../scripts/waybarupdate.sh; + text = builtins.readFile "${self}/files/scripts/${name}.sh"; } #+end_src @@ -2560,7 +22334,7 @@ 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 scripts/opacitytoggle.sh +#+begin_src shell :tangle files/scripts/opacitytoggle.sh if swaymsg opacity plus 0.01 -q; then swaymsg opacity 1 else @@ -2568,13 +22342,12 @@ This app quickly toggles between 5% and 0% transparency. fi #+end_src -#+begin_src nix :tangle pkgs/opacitytoggle/default.nix - { writeShellApplication, sway }: - +#+begin_src nix-ts :tangle pkgs/flake/opacitytoggle/default.nix + { self, name, writeShellApplication, sway }: writeShellApplication { - name = "opacitytoggle"; + inherit name; runtimeInputs = [ sway ]; - text = builtins.readFile ../../scripts/opacitytoggle.sh; + text = builtins.readFile "${self}/files/scripts/${name}.sh"; } #+end_src @@ -2585,7 +22358,7 @@ 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 scripts/fs-diff.sh +#+begin_src shell :tangle files/scripts/fs-diff.sh set -euo pipefail OLD_TRANSID=$(sudo btrfs subvolume find-new /mnt/root-blank 9999999) @@ -2608,46 +22381,11 @@ This utility is used to compare the current state of the root directory with the done #+end_src -#+begin_src nix :tangle pkgs/fs-diff/default.nix - { writeShellApplication }: - +#+begin_src nix-ts :tangle pkgs/flake/fs-diff/default.nix + { self, name, writeShellApplication }: writeShellApplication { - name = "fs-diff"; - text = builtins.readFile ../../scripts/fs-diff.sh; - } -#+end_src - -**** update-checker -:PROPERTIES: -:CUSTOM_ID: h:4d864147-f9ef-46da-9b4f-4e7996a65157 -:END: - -This utility checks if there are updated packages in nixpkgs-unstable. It does so by fully building the most recent configuration, which I do not love, but it has its merits once I am willing to switch to the newer version. - -#+begin_src shell :tangle scripts/update-checker.sh - updates="$({ cd /home/swarsel/.dotfiles && nix flake lock --update-input nixpkgs && nix build .#nixosConfigurations."$(eval hostname)".config.system.build.toplevel && nvd diff /run/current-system ./result | grep -c '\[U'; } || true)" - - alt="has-updates" - if [[ $updates -eq 0 ]]; then - alt="updated" - fi - - tooltip="System updated" - if [[ $updates != 0 ]]; then - tooltip=$(cd ~/.dotfiles && nvd diff /run/current-system ./result | grep -e '\[U' | awk '{ for (i=3; i= 3) print $NF; }' ORS='\\n') - echo "{ \"text\":\"$updates\", \"alt\":\"$alt\", \"tooltip\":\"$tooltip\" }" - else - echo "{ \"text\":\"\", \"alt\":\"$alt\", \"tooltip\":\"\" }" - fi -#+end_src - -#+begin_src nix :tangle pkgs/update-checker/default.nix - { writeShellApplication, nvd }: - - writeShellApplication { - name = "update-checker"; - runtimeInputs = [ nvd ]; - text = builtins.readFile ../../scripts/update-checker.sh; + inherit name; + text = builtins.readFile "${self}/files/scripts/${name}.sh"; } #+end_src @@ -2659,14 +22397,14 @@ This utility checks if there are updated packages in nixpkgs-unstable. It does s This utility checks if there are updated packages in nixpkgs-unstable. It does so by fully building the most recent configuration, which I do not love, but it has its merits once I am willing to switch to the newer version. -#+begin_src nix :tangle pkgs/github-notifications/default.nix - { writeShellApplication, jq }: +#+begin_src nix-ts :tangle pkgs/flake/github-notifications/default.nix + { name, writeShellApplication, jq, ... }: writeShellApplication { - name = "github-notifications"; + inherit name; runtimeInputs = [ jq ]; text = '' - count=$(curl -u Swarsel:"$(cat /run/user/1000/secrets/github_notif)" https://api.github.com/notifications | jq '. | length') + count=$(curl -u Swarsel:"$(cat "$GITHUB_NOTIFICATION_TOKEN_PATH")" https://api.github.com/notifications | jq '. | length') if [[ "$count" != "0" ]]; then echo "{\"text\":\"$count\"}" @@ -2675,77 +22413,68 @@ This utility checks if there are updated packages in nixpkgs-unstable. It does s } #+end_src -**** screenshare +**** kanshare :PROPERTIES: -:CUSTOM_ID: h:960e539c-2a5a-4e21-b3d4-bcdfc8be8fda +:CUSTOM_ID: h:3981cd16-00c0-4ea8-95e2-c6d8c04ec4e5 :END: - -#+begin_src shell :tangle scripts/screenshare.sh - SHARESCREEN="$(nix eval --raw ~/.dotfiles#nixosConfigurations."$(hostname)".config.home-manager.users."$(whoami)".swarselsystems.sharescreen)" - - touch /tmp/screenshare.state - STATE=$(< /tmp/screenshare.state) - - if [[ $STATE != "1" ]]; then - wl-mirror "$SHARESCREEN" & - sleep 0.1 - swaymsg output "$SHARESCREEN" mode "$SWARSEL_LO_RES" - echo 1 > /tmp/screenshare.state - swaymsg '[app_id=at.yrlf.wl_mirror] move to workspace 12:S' - swaymsg '[app_id=at.yrlf.wl_mirror] fullscreen' - else - swaymsg output "$SHARESCREEN" mode "$SWARSEL_HI_RES" - echo 0 > /tmp/screenshare.state - swaymsg '[app_id=at.yrlf.wl_mirror] kill' - fi -#+end_src +This utility checks if there are updated packages in nixpkgs-unstable. It does so by fully building the most recent configuration, which I do not love, but it has its merits once I am willing to switch to the newer version. -#+begin_src nix :tangle pkgs/screenshare/default.nix - { writeShellApplication, sway }: +#+begin_src nix-ts :tangle pkgs/flake/kanshare/default.nix + { name, writeShellApplication, wlr-randr, busybox, wl-mirror, mako, ... }: writeShellApplication { - name = "screenshare"; - runtimeInputs = [ sway ]; - text = builtins.readFile ../../scripts/screenshare.sh; + inherit name; + runtimeInputs = [ wlr-randr busybox wl-mirror mako ]; + text = '' + makoctl mode -a do-not-disturb + wlr-randr | grep "$2" | cut -d" " -f1 | xargs -I{} wl-present mirror "$1" --fullscreen-output {} + makoctl mode -r do-not-disturb + ''; } #+end_src -**** bootstrap +**** swarsel-bootstrap :PROPERTIES: :CUSTOM_ID: h:74db57ae-0bb9-4257-84be-eddbc85130dd :END: -This program sets up a new NixOS host. +This program sets up a new NixOS host remotely. It also takes care of secret management on the new host. -#+begin_src shell :tangle scripts/bootstrap.sh - # highly inspired by https://github.com/EmergentMind/nix-config/blob/dev/scripts/bootstrap-nixos.sh +#+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 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 NixOS on a target machine using this nix-config." + 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 " --impermanence Use this flag if the target machine has impermanence enabled. WARNING: Assumes /persist path." 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 } @@ -2799,14 +22528,14 @@ This program sets up a new NixOS host. 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 + # 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 - } @@ -2821,6 +22550,10 @@ This program sets up a new NixOS host. shift target_destination=$1 ;; + -a) + shift + target_arch=$1 + ;; -u) shift target_user=$1 @@ -2829,9 +22562,8 @@ This program sets up a new NixOS host. shift ssh_port=$1 ;; - --temp-override) - shift - temp=$1 + --no-disko-deps) + no_disko_deps="true" ;; --debug) set -x @@ -2845,6 +22577,60 @@ This program sets up a new NixOS host. 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" + 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@} @@ -2861,6 +22647,8 @@ This program sets up a new NixOS host. fi cd "$FLAKE" + + rm install/flake.lock || true git_root=$(git rev-parse --show-toplevel) # ------------------------ green "Wiping known_hosts of $target_destination" @@ -2868,33 +22656,53 @@ This program sets up a new NixOS host. # ------------------------ 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/etc/ssh" + install -d -m755 "$temp/$persist_dir/etc/ssh" # Generate host ssh key pair without a passphrase - ssh-keygen -t ed25519 -f "$temp/etc/ssh/ssh_host_ed25519_key" -C root@"$target_hostname" -N "" + 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/etc/ssh/ssh_host_ed25519_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 - green "Preparing a temporary password for disko." - green "[Optional] Set disk encryption passphrase:" - read -rs luks_passphrase - if [ -n "$luks_passphrase" ]; then - $ssh_root_cmd "/bin/sh -c 'echo $luks_passphrase > /tmp/disko-password'" - else - $ssh_root_cmd "/bin/sh -c 'echo passphrase > /tmp/disko-password'" + 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 + $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_hostname" - $scp_cmd root@"$target_destination":/mnt/etc/nixos/hardware-configuration.nix "${git_root}"/hosts/nixos/"$target_hostname"/hardware-configuration.nix + + 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" - SHELL=/bin/sh nix run github:nix-community/nixos-anywhere -- --ssh-port "$ssh_port" --extra-files "$temp" --flake .#"$target_hostname" root@"$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 @@ -2909,6 +22717,22 @@ This program sets up a new NixOS host. 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=$( @@ -2939,16 +22763,19 @@ This program sets up a new NixOS host. fi green "Updating all secrets files to reflect updates .sops.yaml" sops updatekeys --yes --enable-local-keyservice "${git_root}"/secrets/*/secrets.yaml + sops updatekeys --yes --enable-local-keyservice "${git_root}"/hosts/nixos/"$target_arch"/"$target_hostname"/secrets/pii.nix.enc # -------------------------- 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/swarsel/.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 swagit.swarsel.win >> /home/$target_user/.ssh/known_hosts" - $ssh_root_cmd "mkdir -p /root/.ssh/; ssh-keyscan -t ssh-ed25519 gitlab.com github.com swagit.swarsel.win >> /root/.ssh/known_hosts" + $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 # -------------------------- @@ -2959,70 +22786,94 @@ This program sets up a new NixOS host. cd "${git_root}" just sync "$target_user" "$target_destination" - if yes_or_no "Do you want to rebuild immediately?"; then - green "Rebuilding nix-config on $target_hostname" - $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}}' > /root/.local/share/nix/trusted-settings.json" - $ssh_cmd -oForwardAgent=yes "cd .dotfiles && sudo nixos-rebuild --show-trace --flake .#$target_hostname switch" + 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 - 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 --show-trace --flake .#$target_hostname switch" - # echo "just rebuild" - echo 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_hostname"/hardware-configuration.nix -qe - nixpkgs-fmt hosts/nixos/"$target_hostname"/hardware-configuration.nix - (pre-commit run --all-files 2> /dev/null || true) && - git add "$git_root/hosts/nixos/$target_hostname/hardware-configuration.nix" && + 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 #+end_src +#+RESULTS: +| trap: | undefined | signal: | exit | | | | | +| [ | Babel | evaluation | exited | with | code | 1 | ] | -#+begin_src nix :tangle pkgs/bootstrap/default.nix - { writeShellApplication, openssh }: - +#+begin_src nix-ts :tangle pkgs/flake/swarsel-bootstrap/default.nix + { self, name, writeShellApplication, openssh }: writeShellApplication { - name = "bootstrap"; + inherit name; runtimeInputs = [ openssh ]; - text = builtins.readFile ../../scripts/bootstrap.sh; + text = builtins.readFile "${self}/files/scripts/${name}.sh"; } #+end_src **** swarsel-rebuild +:PROPERTIES: +:CUSTOM_ID: h:1eabdc59-8832-44ca-a22b-11f848ab150a +:END: -This program sets up a new NixOS host. - -#+begin_src shell :tangle scripts/swarsel-rebuild.sh +#+begin_src shell :tangle files/scripts/swarsel-rebuild.sh set -eo pipefail - target_flake="chaostheatre" + target_config="hotel" + target_arch="" target_user="swarsel" function help_and_exit() { echo - echo "Remotely installs NixOS on a target machine using this nix-config." + echo "Builds SwarselSystem configuration." echo echo "USAGE: $0 [OPTIONS]" echo echo "ARGS:" - echo " -f specify flake to deploy the nixos config of." - echo " Default: chaostheatre" + 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 } @@ -3048,9 +22899,13 @@ This program sets up a new NixOS host. while [[ $# -gt 0 ]]; do case "$1" in - -f) + -n) shift - target_flake=$1 + target_config=$1 + ;; + -a) + shift + target_arch=$1 ;; -u) shift @@ -3065,6 +22920,11 @@ This program sets up a new NixOS host. 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 @@ -3076,7 +22936,7 @@ This program sets up a new NixOS host. fi local_keys=$(ssh-add -L || true) - pub_key=$(cat /home/"$target_user"/.dotfiles/secrets/keys/ssh/nbl-imba-2.pub) + pub_key=$(cat /home/"$target_user"/.dotfiles/secrets/keys/ssh/yubikey.pub) read -ra pub_arr <<< "$pub_key" cd .dotfiles @@ -3084,60 +22944,83 @@ This program sets up a new NixOS host. 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 - git add 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_flake"/ - git add /home/"$target_user"/.dotfiles/hosts/nixos/"$target_flake"/hardware-configuration.nix + 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_flake" - sudo nixos-rebuild --show-trace --flake .#"$target_flake" boot + 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 -#+begin_src nix :tangle pkgs/swarsel-rebuild/default.nix - { writeShellApplication, git }: - +#+begin_src nix-ts :tangle pkgs/flake/swarsel-rebuild/default.nix + { self, name, writeShellApplication, git }: writeShellApplication { - name = "swarsel-rebuild"; + inherit name; runtimeInputs = [ git ]; - text = builtins.readFile ../../scripts/swarsel-rebuild.sh; + text = builtins.readFile "${self}/files/scripts/${name}.sh"; } #+end_src **** swarsel-install +:PROPERTIES: +:CUSTOM_ID: h:fbd8aaf2-9dca-4ca3-aca1-19d0d188a435 +:END: -This program sets up a new NixOS host. +Autoformatting always puts the =EOF= with indentation, which makes shfmt check fail. When editing this block, unindent them manually. -#+begin_src shell :tangle scripts/swarsel-install.sh +#+begin_src shell :tangle files/scripts/swarsel-install.sh set -eo pipefail - target_flake="chaostheatre" + target_config="hotel" + target_hostname="hotel" target_user="swarsel" - fs_type="ext4" - disk="" + target_arch="" + persist_dir="" + target_disk="/dev/vda" + disk_encryption=0 function help_and_exit() { echo - echo "Remotely installs NixOS on a target machine using this nix-config." + echo "Locally installs SwarselSystem on this machine." echo - echo "USAGE: $0 -d [OPTIONS]" + echo "USAGE: $0 -n -d [OPTIONS]" echo echo "ARGS:" - echo " -d specify disk to install on." - echo " -f specify flake to deploy the nixos config of." - echo " Default: chaostheatre" + 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 " -t specify file system type to deploy for." - echo " Default: ext4" + 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 @@ -3153,21 +23036,22 @@ This program sets up a new NixOS host. while [[ $# -gt 0 ]]; do case "$1" in - -f) + -n) shift - target_flake=$1 + target_config=$1 + target_hostname=$1 ;; -u) shift target_user=$1 ;; - -t) - shift - fs_type=$1 - ;; -d) shift - disk=$1 + target_disk=$1 + ;; + -a) + shift + target_arch=$1 ;; -h | --help) help_and_exit ;; ,*) @@ -3178,8 +23062,22 @@ This program sets up a new NixOS host. 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 @@ -3187,58 +23085,202 @@ This program sets up a new NixOS host. git clone https://github.com/Swarsel/.dotfiles.git local_keys=$(ssh-add -L || true) - pub_key=$(cat /home/"$target_user"/.dotfiles/secrets/keys/ssh/nbl-imba-2.pub) + pub_key=$(cat /home/"$target_user"/.dotfiles/secrets/keys/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 - git add flake.nix + 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 "Creating /boot partition" - sudo parted -a optimal --script "$disk" mklabel gpt - sudo parted -a optimal --script "$disk" mkpart "boot" fat32 1MiB 1025MiB - sudo parted -a optimal --script "$disk" set 1 esp on + 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 "Creating / partition" - sudo parted -a optimal --script "$disk" mkpart "root" "$fs_type" 1025MiB 100% - sudo parted -a optimal --script "$disk" type 2 4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709 + 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 - green "Ensuring proper file systems" - sudo mkfs.fat -F32 "$disk"1 - sudo mkfs."${fs_type}" -F "$disk"2 + 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 - green "Generating hardware configuration" - sudo mount "$disk"2 /mnt - sudo mkdir -p /mnt/boot - sudo mount "$disk"1 /mnt/boot - sudo nixos-generate-config --root /mnt --dir /home/"$target_user"/.dotfiles/hosts/nixos/"$target_flake"/ + SWAP="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isSwap)" + if [[ $SWAP == "true" ]]; then + green "Swap: ✓" + else + red "Swap: X" + fi - git add /home/"$target_user"/.dotfiles/hosts/nixos/"$target_flake"/hardware-configuration.nix - # sudo rm -rf /root/.nix-defexpr/channels - # sudo rm -rf /nix/var/nix/profiles/per-user/channels + 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_flake" - sudo nixos-install --flake .#"$target_flake" - yellow "Please keep in mind that this is only a demo of the configuration. Things might break unexpectedly." + 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"; + } +#+end_src + +**** swarsel-postinstall +:PROPERTIES: +: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 -#+begin_src nix :tangle pkgs/swarsel-install/default.nix - { writeShellApplication, git }: - +#+begin_src nix-ts :tangle pkgs/flake/swarsel-postinstall/default.nix + { self, name, writeShellApplication, git }: writeShellApplication { - name = "swarsel-install"; + inherit name; runtimeInputs = [ git ]; - text = builtins.readFile ../../scripts/swarsel-install.sh; + text = builtins.readFile "${self}/files/scripts/${name}.sh"; } #+end_src @@ -3247,18 +23289,16 @@ This program sets up a new NixOS host. :CUSTOM_ID: h:5ad99997-e54c-4f0b-9ab7-15f76b1e16e1 :END: -This script allows for quick git branch switching. +#+begin_src nix-ts :tangle pkgs/flake/t2ts/default.nix + { name, writeShellApplication, ... }: -#+begin_src nix :tangle pkgs/t2ts/default.nix - { writeShellApplication }: - - writeShellApplication { - name = "t2ts"; - runtimeInputs = [ ]; - text = '' - date -d"$1" +%s - ''; - } + writeShellApplication { + inherit name; + runtimeInputs = [ ]; + text = '' + date -d"$1" +%s + ''; + } #+end_src @@ -3267,13 +23307,11 @@ This script allows for quick git branch switching. :CUSTOM_ID: h:5ad99997-e54c-4f0b-9ab7-15f76b1e16e1 :END: -This script allows for quick git branch switching. - -#+begin_src nix :tangle pkgs/ts2t/default.nix - { writeShellApplication }: +#+begin_src nix-ts :tangle pkgs/flake/ts2t/default.nix + { name, writeShellApplication, ... }: writeShellApplication { - name = "ts2t"; + inherit name; runtimeInputs = [ ]; text = '' date -d @"$1" 2>/dev/null || date -r "$1" @@ -3283,14 +23321,15 @@ This script allows for quick git branch switching. #+end_src **** vershell +:PROPERTIES: +:CUSTOM_ID: h:7806b129-a4a5-4d10-af27-6cbeafbcb294 +:END: -This script allows for quick git branch switching. - -#+begin_src nix :tangle pkgs/vershell/default.nix - { writeShellApplication }: +#+begin_src nix-ts :tangle pkgs/flake/vershell/default.nix + { name, writeShellApplication, ... }: writeShellApplication { - name = "vershell"; + inherit name; runtimeInputs = [ ]; text = '' nix shell github:nixos/nixpkgs/"$1"#"$2"; @@ -3300,29 +23339,42 @@ This script allows for quick git branch switching. #+end_src **** eontimer +:PROPERTIES: +:CUSTOM_ID: h:9fda7829-09a4-4b8f-86f6-08b078ab2874 +:END: -This script allows for quick git branch switching. - -#+begin_src nix :tangle pkgs/eontimer/default.nix - { pkgs, python3Packages }: - - python3Packages.buildPythonApplication rec { +#+begin_src nix-ts :tangle pkgs/flake/eontimer/default.nix + { lib + , python3 + , fetchFromGitHub + , makeDesktopItem + , writeShellScript + , ... + }: + let + wrapper = writeShellScript "eontimer-wrapper" '' + export QT_QPA_PLATFORM=xcb + exec @out@/bin/EonTimer + ''; + in + python3.pkgs.buildPythonApplication rec { pname = "eontimer"; - version = "3.0.0"; + version = "3.0.0-rc.6"; pyproject = true; - src = pkgs.fetchFromGitHub { + src = fetchFromGitHub { owner = "DasAmpharos"; repo = "EonTimer"; - rev = "9449e6158f0aa6eaa24b3b1d0a427aa198b5c0e4"; + rev = version; hash = "sha256-+XN/VGGlEg2gVncRZrWDOZ2bfxt8xyIu22F2wHlG6YI="; }; - build-system = with python3Packages; [ - setuptools + build-system = [ + python3.pkgs.setuptools + python3.pkgs.wheel ]; - dependencies = with python3Packages; [ + dependencies = with python3.pkgs; [ altgraph certifi charset-normalizer @@ -3342,104 +23394,495 @@ This script allows for quick git branch switching. urllib3 ]; + nativeBuildInputs = [ + python3.pkgs.pyinstaller + ]; + buildPhase = '' - ${pkgs.python3Packages.pyinstaller}/bin/pyinstaller EonTimer.spec + runHook preBuild + + pyinstaller --clean --noconfirm EonTimer.spec + + runHook postBuild ''; installPhase = '' + runHook preInstall + mkdir -p $out/bin + mkdir -p $out/share/applications cp dist/EonTimer $out/bin/ + install -Dm755 -T ${wrapper} $out/bin/eontimer + substituteInPlace $out/bin/eontimer --subst-var out + + runHook postInstall + ''; + + postInstall = '' + install -Dm755 -t $out/share/applications ${ + makeDesktopItem { + name = "eontimer"; + desktopName = "EonTimer"; + comment = "Start EonTimer"; + exec = "eontimer"; + } + }/share/applications/eontimer.desktop ''; + + meta = { + description = "Pokémon RNG Timer"; + homepage = "https://github.com/DasAmpharos/EonTimer"; + license = lib.licenses.mit; + maintainers = with lib.maintainers; [ ]; + mainProgram = "eon-timer"; + }; } #+end_src -*** Overlays (additions, overrides, nixpkgs-stable) +**** project :PROPERTIES: -:CUSTOM_ID: h:5e3e21e0-57af-4dad-b32f-6400af9b7aab +:CUSTOM_ID: h:154b6df4-dd50-4f60-9794-05a140d02994 :END: -This file now holds all of the "nixpkgs-changes" that I am using across the configurations. Most notable here are the =modifications=, where I am editing derivations according to my needs. +#+begin_src shell :tangle files/scripts/project.sh + set -euo pipefail -When adding a new entry here, do not forget to add it in the default output of this file, otherwise it will not be exposed to the rest of the system. + if [ ! -d "$(pwd)/.git" ]; then + git init + fi + nix flake init --template "$FLAKE"#"$1" + direnv allow +#+end_src -#+begin_src nix :tangle overlays/default.nix - { inputs, ... }: +#+begin_src nix-ts :tangle pkgs/flake/project/default.nix + { self, name, writeShellApplication }: + writeShellApplication { + inherit name; + text = builtins.readFile "${self}/files/scripts/${name}.sh"; + } +#+end_src +**** fhs +:PROPERTIES: +:CUSTOM_ID: h:36d6c17c-6d91-4297-b76d-9d7feab6c1a0 +:END: + + +#+begin_src nix-ts :tangle pkgs/flake/fhs/default.nix + { name, pkgs, ... }: let - additions = final: _prev: import ../pkgs { pkgs = final; }; - modifications = _: _prev: { - vesktop = _prev.vesktop.override { - withSystemVencord = true; - }; - - firefox = _prev.firefox.override { - nativeMessagingHosts = [ - _prev.tridactyl-native - _prev.browserpass - _prev.plasma5Packages.plasma-browser-integration - ]; - }; - - 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 - ]); - - # prismlauncher = _prev.prismlauncher.override { - # glfw = _prev.glfw-wayland-minecraft; - # }; - - # #river = prev.river.overrideAttrs (oldAttrs: rec { - # pname = "river"; - # version = "git"; - # src = prev.fetchFromGitHub { - # owner = "riverwm"; - # repo = pname; - # rev = "c16628c7f57c51d50f2d10a96c265fb0afaddb02"; - # hash = "sha256-E3Xtv7JeCmafiNmpuS5VuLgh1TDAbibPtMo6A9Pz6EQ="; - # fetchSubmodules = true; - # }; - # }); - }; - - nixpkgs-stable = final: _prev: { - stable = import inputs.nixpkgs-stable { - inherit (final) system; - config.allowUnfree = true; - }; - }; - - zjstatus = _: _prev: { - zjstatus = inputs.zjstatus.packages.${_prev.system}.default; - }; - + base = pkgs.appimageTools.defaultFhsEnvArgs; in - { - default = - final: prev: + pkgs.buildFHSEnv (base // { + inherit name; + targetPkgs = pkgs: (base.targetPkgs pkgs) ++ [ pkgs.pkg-config ]; + profile = "export FHS=1"; + runScript = "zsh"; + extraOutputsToInstall = [ "dev" ]; + }) +#+end_src - (additions final prev) - // (modifications final prev) - // (nixpkgs-stable final prev) - // (zjstatus final prev) - // (inputs.nur.overlays.default final prev) - // (inputs.emacs-overlay.overlay final prev) - // (inputs.nixgl.overlay final prev); +**** swarsel-displaypower +:PROPERTIES: +:CUSTOM_ID: h:814d5e7f-4b95-412d-b246-33f888514ec6 +:END: + +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 }: + writeShellApplication { + inherit name; + runtimeInputs = [ sway ]; + text = builtins.readFile "${self}/files/scripts/${name}.sh"; + } + +#+end_src + +**** swarsel-mgba +:PROPERTIES: +:CUSTOM_ID: h:799579f3-ddd3-4f76-928a-a8c665980476 +:END: + +AppImage version of mgba in which the lua scripting works. + + +#+begin_src nix-ts :tangle pkgs/flake/swarsel-mgba/default.nix + { appimageTools, fetchurl, ... }: + let + pname = "mgba"; + version = "0.10.4"; + src = fetchurl { + url = "https://github.com/mgba-emu/mgba/releases/download/${version}/mGBA-${version}-appimage-x64.appimage"; + hash = "sha256-rDihDfuA8DqxvCe6UeavCzpjeU+fSqUbFnyTNC2dc1I="; + }; + appimageContents = appimageTools.extractType2 { inherit pname version src; }; + in + appimageTools.wrapType2 { + inherit pname version src; + extraInstallCommands = '' + install -Dm444 ${appimageContents}/io.mgba.mGBA.desktop -t $out/share/applications + substituteInPlace $out/share/applications/io.mgba.mGBA.desktop \ + --replace-fail 'Exec=mgba-qt %f' 'Exec=mgba' + cp -r ${appimageContents}/usr/share/icons $out/share + ''; } #+end_src -*** Modules +**** swarsel-deploy +:PROPERTIES: +:CUSTOM_ID: h:c3362d4e-d3a8-43e8-9ef7-272b6de0572e +:END: + +#+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, ... }: + writeShellApplication { + runtimeInputs = [ bc nix-output-monitor ]; + inherit name; + text = '' + set -euo pipefail + shopt -s lastpipe # allow cmd | readarray + + function die() { + echo "error: $*" >&2 + exit 1 + } + function show_help() { + echo 'Usage: deploy [OPTIONS] [ACTION]' + echo "Builds, pushes and activates nixosConfigurations on target systems." + echo "" + echo 'ACTION:' + echo ' switch [default] Switch immediately to the new configuration and make it the boot default' + echo ' boot Make the configuration the new boot default' + echo " test Activate the configuration but don't make it the boot default" + echo " dry-activate Don't activate, just show what would be done" + echo "" + echo 'OPTIONS: [passed to nix build]' + } + + function time_start() { + T_START=$(date +%s.%N) + } + + function time_next() { + T_END=$(date +%s.%N) + T_LAST=$(${bc}/bin/bc <<< "scale=1; ($T_END - $T_START)/1") + T_START="$T_END" + } + + USER_FLAKE_DIR=$(git rev-parse --show-toplevel 2> /dev/null || pwd) || + die "Could not determine current working directory. Something went very wrong." + [[ -e "$USER_FLAKE_DIR/flake.nix" ]] || + die "Could not determine location of your project's flake.nix. Please run this at or below your main directory containing the flake.nix." + cd "$USER_FLAKE_DIR" + + [[ $# -gt 0 ]] || { + show_help + exit 1 + } + + OPTIONS=() + POSITIONAL_ARGS=() + while [[ $# -gt 0 ]]; do + case "$1" in + "help" | "--help" | "-help" | "-h") + show_help + exit 1 + ;; + + -*) OPTIONS+=("$1") ;; + ,*) POSITIONAL_ARGS+=("$1") ;; + esac + shift + done + + [[ ''${#POSITIONAL_ARGS[@]} -ge 1 ]] || + die "Missing argument: " + [[ ''${#POSITIONAL_ARGS[@]} -le 2 ]] || + die "Too many arguments given." + + tr , '\n' <<< "''${POSITIONAL_ARGS[0]}" | sort -u | readarray -t HOSTS + ACTION="''${POSITIONAL_ARGS[1]-switch}" + + # Expand flake paths for hosts definitions + declare -A TOPLEVEL_FLAKE_PATHS + for host in "''${HOSTS[@]}"; do + TOPLEVEL_FLAKE_PATHS["$host"]=".#nixosConfigurations.$host.config.system.build.toplevel" + done + + time_start + + # Get outputs of all derivations (should be cached) + declare -A TOPLEVEL_STORE_PATHS + for host in "''${HOSTS[@]}"; do + toplevel="''${TOPLEVEL_FLAKE_PATHS["$host"]}" + # Make sudo call to get prompt out of the way + sudo echo " Building 📦 $host" + nix build --no-link "''${OPTIONS[@]}" --show-trace --log-format internal-json -v "$toplevel" |& ${nix-output-monitor}/bin/nom --json || + die "Failed to get derivation path for $host from ''${TOPLEVEL_FLAKE_PATHS["$host"]}" + TOPLEVEL_STORE_PATHS["$host"]=$(nix build --no-link --print-out-paths "''${OPTIONS[@]}" "$toplevel") + time_next + echo " Built ✅ $host ''${TOPLEVEL_STORE_PATHS["$host"]} in ''${T_LAST}s" + done + + current_host=$(hostname) + + for host in "''${HOSTS[@]}"; do + store_path="''${TOPLEVEL_STORE_PATHS["$host"]}" + + if [ "$host" = "$current_host" ]; then + echo -e "\033[1;36m Running locally for $host... \033[m" + ssh_prefix="sudo" + else + echo -e "\033[1;36m Copying \033[m➡️ \033[34m$host\033[m" + nix copy --to "ssh://$host" "$store_path" + time_next + echo -e "\033[1;32m Copied \033[m✅ \033[34m$host\033[m \033[90min ''${T_LAST}s\033[m" + ssh_prefix="ssh $host --" + fi + + echo -e "\033[1;36m Applying \033[m⚙️ \033[34m$host\033[m" + prev_system=$($ssh_prefix readlink -e /nix/var/nix/profiles/system) + $ssh_prefix /run/current-system/sw/bin/nix-env --profile /nix/var/nix/profiles/system --set "$store_path" || + die "Failed to set system profile" + $ssh_prefix "$store_path"/bin/switch-to-configuration "$ACTION" || + echo "Error while activating new system" >&2 + + if [[ -n $prev_system ]]; then + $ssh_prefix nvd --color always diff "$prev_system" "$store_path" || true + fi + + time_next + echo -e "\033[1;32m Applied \033[m✅ \033[34m$host\033[m \033[90min ''${T_LAST}s\033[m" + done + ''; + } + +#+end_src + +**** swarsel-build +:PROPERTIES: +:CUSTOM_ID: h:c3362d4e-d3a8-43e8-9ef7-272b6de0572e +:END: + +#+begin_src nix-ts :tangle pkgs/flake/swarsel-build/default.nix + { name, nix-output-monitor, writeShellApplication, ... }: + writeShellApplication { + runtimeInputs = [ nix-output-monitor ]; + inherit name; + text = '' + set -euo pipefail + [[ "$#" -ge 1 ]] \ + || { echo "usage: build ..." >&2; exit 1; } + HOSTS=() + for h in "$@"; do + HOSTS+=(".#nixosConfigurations.$h.config.system.build.toplevel") + done + nom build --no-link --print-out-paths --show-trace "''${HOSTS[@]}" + ''; + } + +#+end_src + +**** swarsel-instantiate +:PROPERTIES: +:CUSTOM_ID: h:95ebfd13-1f6b-427f-950d-e30c1ed6f9fa +:END: + +This is a convenience function that calls =nix-instantiate= with a number of flags that I need in order to evaluate nix expressions in org-src blocks. + +#+begin_src nix-ts :tangle pkgs/flake/swarsel-instantiate/default.nix + { name, writeShellApplication, ... }: + writeShellApplication { + inherit name; + text = '' + set -euo pipefail + nix-instantiate --strict --eval --expr "let lib = import ; in $*" + ''; + } + +#+end_src + +**** sshrm +:PROPERTIES: +:CUSTOM_ID: h:02842543-caca-4d4c-a4d2-7ac749b5c136 +:END: + +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 }: + writeShellApplication { + inherit name; + runtimeInputs = [ openssh ]; + text = builtins.readFile "${self}/files/scripts/${name}.sh"; + } +#+end_src +**** endme +:PROPERTIES: +:CUSTOM_ID: h:abbd18a2-73ae-4ee4-8487-06fef23638bb +:END: + +Sometimes my DE crashes after putting it to suspend - to be precise, it happens when I put it into suspend when I have multiple screens plugged in. I have never taken the time to debug the issue, but instead just switch to a different TTY and then use this script to kill the hanging session. + +#+begin_src nix-ts :tangle pkgs/flake/endme/default.nix + { name, writeShellApplication, ... }: + writeShellApplication { + inherit name; + text = '' + set -euo pipefail + systemctl --user stop graphical-session.target + systemctl --user stop graphical-session-pre.target + ''; + } + +#+end_src + +**** git-replace +:PROPERTIES: +:CUSTOM_ID: h:e1330feb-4a9b-4e6d-9d15-6d2adb5879d2 +:END: + +This script allows for quick git replace of a string. + + +#+begin_src nix-ts :tangle pkgs/flake/git-replace/default.nix + { name, writeShellApplication, git, gnugrep, findutils, ... }: + + writeShellApplication { + inherit name; + runtimeInputs = [ git gnugrep findutils ]; + text = '' + + function help_and_exit() { + echo + echo "Remotely installs SwarselSystem on a target machine including secret deployment." + echo + echo "USAGE: $0 [-f/-t} " + echo + echo "ARGS:" + echo " -f | --filenames Replace in filenames." + echo " -d | --directory Replace text in files within this directory." + echo " -r | --repo Replace text in files in the entire git repo." + echo " -h | --help Print this help." + exit 0 + } + + target_files=false + target_repo=false + target_dirs=false + while [[ $# -gt 0 ]]; do + case "$1" in + -f | --filenames) + shift + target_files=true + ;; + -r | --repo) + shift + target_repo=rue + ;; + -d | --directory) + shift + target_dirs=rue + ;; + -h | --help) help_and_exit ;; + ,*) + echo "Invalid option detected." + help_and_exit + ;; + esac + shift + done + + + if [[ $target_files == "true" ]]; then + for file in $(git ls-files | grep "$1" | sed -e "s/\($1[^/]*\).*/\1/" | uniq); do + git mv "$file" "''${file//$1/$2}" + done + fi + + if [[ $target_repo == "true" ]]; then + git grep -l "$1" | xargs sed -i "s/$1/$2/g" + fi + + if [[ $target_dirs == "true" ]]; then + grep -rl "$1" . | xargs sed -i "s/$1/$2/g" + fi + ''; + } + + +#+end_src + +*** Packages (config) +:PROPERTIES: +:CUSTOM_ID: h:c01a91b8-b751-4978-b987-733de63c8211 +:END: + +#+begin_src nix-ts :tangle pkgs/config/default.nix + { self, homeConfig, lib, pkgs, ... }: + let + mkPackages = names: pkgs: builtins.listToAttrs (map + (name: { + inherit name; + value = pkgs.callPackage "${self}/pkgs/config/${name}" { inherit self name homeConfig; }; + }) + names); + packageNames = lib.swarselsystems.readNix "pkgs/config"; + in + mkPackages packageNames pkgs +#+end_src + +**** cdr +:PROPERTIES: +:CUSTOM_ID: h:78d17941-68b3-4b36-b378-3282ae2178b8 +:END: + + +#+begin_src nix-ts :tangle pkgs/config/cdr/default.nix + { name, homeConfig, writeShellApplication, fzf, ... }: + + writeShellApplication { + inherit name; + runtimeInputs = [ fzf ]; + text = '' + DOCUMENT_DIR_WORK=${homeConfig.systemd.user.sessionVariables.DOCUMENT_DIR_WORK or ""} + DOCUMENT_DIR_PRIV=${homeConfig.systemd.user.sessionVariables.DOCUMENT_DIR_PRIV} + FLAKE=${homeConfig.home.sessionVariables.FLAKE} + + cd "$( (find "$DOCUMENT_DIR_WORK" "$DOCUMENT_DIR_PRIV" -maxdepth 1 && echo "$FLAKE") | fzf )" + ''; + } + + +#+end_src + +** Profiles :PROPERTIES: :CUSTOM_ID: h:f0f1c961-3e7a-47b8-99ab-1654bb45dffc :END: @@ -3448,7416 +23891,511 @@ In this section I define custom modules under the =swarsel= attribute. These are 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. -**** NixOS +*** NixOS :PROPERTIES: :CUSTOM_ID: h:14e68518-8ec7-48ec-b208-0e3d6d49954d :END: Modules that need to be loaded on the NixOS level. Note that these will not be available on systems that are not running NixOS. -#+begin_src nix :tangle modules/nixos/default.nix -let - moduleNames = [ - "wallpaper" - "hardware" - "setup" - "impermanence" - "filesystem" - "input" - ]; - - mkImports = names: builtins.listToAttrs (map (name: { - inherit name; - value = import ./${name}.nix; - }) names); - -in - mkImports moduleNames - -#+end_src - - -***** Wallpaper -:PROPERTIES: -:CUSTOM_ID: h:bd7517c6-0e0a-4063-bc81-e62cd24e7170 -:END: - -This lets me set the wallpaper that I want to use. Duplicated with home-manager options because mixing system and user level configuration is not a good idea. - -#+begin_src nix :tangle modules/nixos/wallpaper.nix - { lib, ... }: - - { - options.swarselsystems.wallpaper = lib.mkOption { - type = lib.types.path; - default = ""; - }; - } - -#+end_src - -***** Hardware -:PROPERTIES: -:CUSTOM_ID: h:c6a138ff-f07f-4cae-95b9-b6daa2b11463 -:END: - -This lets me set some basic flags about the hardware of the configured systems. - -#+begin_src nix :tangle modules/nixos/hardware.nix - { lib, ... }: - - { - options.swarselsystems.hasBluetooth = lib.mkEnableOption "bluetooth availability"; - options.swarselsystems.hasFingerprint = lib.mkEnableOption "fingerprint sensor availability"; - options.swarselsystems.trackpoint.isAvailable = lib.mkEnableOption "trackpoint availability"; - options.swarselsystems.trackpoint.device = lib.mkOption { - type = lib.types.str; - default = ""; - }; - } -#+end_src - -***** Setup -:PROPERTIES: -:CUSTOM_ID: h:f4f22166-e345-43e6-b15f-b7f5bb886554 -:END: - -I usually use =mutableUsers = false= in my NixOS configuration. However, on a new system where sops-keys have not been deployed, this would immediately lock me out of the system. Hence this flag can be used until sops-keys are created. - -#+begin_src nix :tangle modules/nixos/setup.nix +#+begin_src nix-ts :tangle profiles/nixos/default.nix { lib, ... }: let - inherit (lib) mkOption types; - in - - { - options.swarselsystems.flakePath = mkOption { - type = types.str; - default = ""; - }; - options.swarselsystems.withHomeManager = mkOption { - type = types.bool; - default = true; - }; - options.swarselsystems.isPublic = lib.mkEnableOption "is a public machine (no secrets)"; - options.swarselsystems.initialSetup = lib.mkEnableOption "initial setup (no sops keys available)"; - options.swarselsystems.server.enable = lib.mkEnableOption "is a server machine"; - options.swarselsystems.server.kavita = lib.mkEnableOption "enable kavita on server"; - options.swarselsystems.server.jellyfin = lib.mkEnableOption "enable jellyfin on server"; - options.swarselsystems.server.navidrome = lib.mkEnableOption "enable navidrome on server"; - options.swarselsystems.server.spotifyd = lib.mkEnableOption "enable spotifyd on server"; - options.swarselsystems.server.mpd = lib.mkEnableOption "enable mpd on server"; - options.swarselsystems.server.matrix = lib.mkEnableOption "enable matrix on server"; - options.swarselsystems.server.nextcloud = lib.mkEnableOption "enable nextcloud on server"; - options.swarselsystems.server.immich = lib.mkEnableOption "enable immich on server"; - options.swarselsystems.server.paperless = lib.mkEnableOption "enable paperless on server"; - options.swarselsystems.server.transmission = lib.mkEnableOption "enable transmission and friends on server"; - options.swarselsystems.server.syncthing = lib.mkEnableOption "enable syncthing on server"; - options.swarselsystems.server.restic = lib.mkEnableOption "enable restic backups on server"; - options.swarselsystems.server.monitoring = lib.mkEnableOption "enable monitoring on server"; - options.swarselsystems.server.jenkins = lib.mkEnableOption "enable jenkins on server"; - options.swarselsystems.server.emacs = lib.mkEnableOption "enable emacs server on server"; - options.swarselsystems.server.forgejo = lib.mkEnableOption "enable forgejo on server"; - options.swarselsystems.server.ankisync = lib.mkEnableOption "enable ankisync on server"; - options.swarselsystems.server.freshrss = lib.mkEnableOption "enable freshrss on server"; - } -#+end_src - -***** Input -:PROPERTIES: -:CUSTOM_ID: h:45188d3c-9910-480b-beec-d5fd713b05fb -:END: - -This section is for everything input-related on the NixOS side. At the moment, this is only used to define shell aliases for servers. - -#+begin_src nix :tangle modules/nixos/input.nix - { lib, ... }: - let - inherit (lib) mkOption types; + profileNames = lib.swarselsystems.readNix "profiles/nixos"; in { - options.swarselsystems.shellAliases = mkOption { - type = types.attrsOf types.str; - default = { }; + imports = lib.swarselsystems.mkImports profileNames "profiles/nixos"; + } +#+end_src +**** Personal +:PROPERTIES: +:CUSTOM_ID: h:32d654de-8db2-403a-9a27-4c46d7b9172d +:END: + +#+begin_src nix-ts :tangle profiles/nixos/personal/default.nix :mkdirp yes + { lib, config, ... }: + { + options.swarselprofiles.personal = lib.mkEnableOption "is this a personal host"; + config = lib.mkIf config.swarselprofiles.personal { + swarselmodules = { + # keyd = lib.mkDefault true; + appimage = lib.mkDefault true; + autologin = lib.mkDefault true; + blueman = lib.mkDefault true; + boot = lib.mkDefault true; + btrfs = lib.mkDefault true; + distrobox = lib.mkDefault true; + env = lib.mkDefault true; + general = lib.mkDefault true; + gnome-keyring = lib.mkDefault true; + gvfs = lib.mkDefault true; + hardware = lib.mkDefault true; + home-manager = lib.mkDefault true; + impermanence = lib.mkDefault true; + interceptionTools = lib.mkDefault true; + keyboards = lib.mkDefault true; + lanzaboote = lib.mkDefault true; + ledger = lib.mkDefault true; + lid = lib.mkDefault true; + login = lib.mkDefault true; + lowBattery = lib.mkDefault false; + network = lib.mkDefault true; + networkDevices = lib.mkDefault true; + nix-ld = lib.mkDefault true; + nvd = lib.mkDefault true; + packages = lib.mkDefault true; + pii = lib.mkDefault true; + pipewire = lib.mkDefault true; + ppd = lib.mkDefault true; + programs = lib.mkDefault true; + pulseaudio = lib.mkDefault true; + remotebuild = lib.mkDefault true; + security = lib.mkDefault true; + sops = lib.mkDefault true; + stylix = lib.mkDefault true; + sway = lib.mkDefault true; + swayosd = lib.mkDefault true; + syncthing = lib.mkDefault true; + systemdTimeout = lib.mkDefault true; + time = lib.mkDefault true; + users = lib.mkDefault true; + uwsm = lib.mkDefault true; + xdg-portal = lib.mkDefault true; + xserver = lib.mkDefault true; + yubikey = lib.mkDefault true; + zsh = lib.mkDefault true; + + }; + home-manager.users."${config.swarselsystems.mainUser}" = { + swarselprofiles = { + personal = lib.mkDefault true; + }; + }; + }; + } + #+end_src -***** Impermanence +**** Minimal :PROPERTIES: -:CUSTOM_ID: h:e591075d-4a77-4add-bbc8-b711998fa97f +:CUSTOM_ID: h:b926f0c8-7968-4079-924c-a5d0ae4d3a45 :END: -Option to enable impermanence configurations. This could also be done via optional imports, but impermanence is a "big enough" change to warrant a line in the machine =default.nix=. - -#+begin_src nix :tangle modules/nixos/impermanence.nix - { lib, ... }: - +#+begin_src nix-ts :tangle profiles/nixos/minimal/default.nix :mkdirp yes + { lib, config, ... }: { - options.swarselsystems.impermanence = lib.mkEnableOption "use impermanence on this system"; + options.swarselprofiles.minimal = lib.mkEnableOption "declare this a minimal host"; + config = lib.mkIf config.swarselprofiles.minimal { + swarselmodules = { + general = lib.mkDefault true; + home-manager = lib.mkDefault true; + xserver = lib.mkDefault true; + lanzaboote = lib.mkDefault true; + time = lib.mkDefault true; + users = lib.mkDefault true; + impermanence = lib.mkDefault true; + security = lib.mkDefault true; + sops = lib.mkDefault true; + pii = lib.mkDefault true; + zsh = lib.mkDefault true; + yubikey = lib.mkDefault true; + autologin = lib.mkDefault true; + boot = lib.mkDefault true; + btrfs = lib.mkDefault true; + + server = { + ssh = lib.mkDefault true; + diskEncryption = lib.mkDefault true; + }; + }; + + }; + } + #+end_src -***** Filesystem +**** Hotel :PROPERTIES: -:CUSTOM_ID: h:f77358ee-a80c-403a-be9d-04e7052bc556 +:CUSTOM_ID: h:b79fbb59-9cf2-48eb-b469-2589223dda95 :END: -This lets me quickly set flags for "special" file systems. These options mostly function in conjunction with other settings (for example, the =isBtrfs= function is mostly used for impermanence configuration). - -#+begin_src nix :tangle modules/nixos/filesystem.nix - { lib, ... }: - +#+begin_src nix-ts :tangle profiles/nixos/hotel/default.nix :mkdirp yes + { lib, config, ... }: { - options.swarselsystems.isBtrfs = lib.mkEnableOption "use btrfs filesystem"; + options.swarselprofiles.hotel = lib.mkEnableOption "is this a hotel host"; + config = lib.mkIf config.swarselprofiles.hotel { + swarselmodules = { + packages = lib.mkForce true; + general = lib.mkForce true; + home-manager = lib.mkForce true; + xserver = lib.mkForce true; + users = lib.mkForce true; + sops = lib.mkForce true; + env = lib.mkForce true; + security = lib.mkForce true; + systemdTimeout = lib.mkForce true; + hardware = lib.mkForce true; + pulseaudio = lib.mkForce true; + pipewire = lib.mkForce true; + network = lib.mkForce true; + time = lib.mkForce true; + stylix = lib.mkForce true; + programs = lib.mkForce true; + zsh = lib.mkForce true; + syncthing = lib.mkForce true; + blueman = lib.mkForce true; + networkDevices = lib.mkForce true; + gvfs = lib.mkForce true; + interceptionTools = lib.mkForce true; + swayosd = lib.mkForce true; + ppd = lib.mkForce true; + yubikey = lib.mkForce false; + ledger = lib.mkForce true; + keyboards = lib.mkForce true; + login = lib.mkForce true; + nix-ld = lib.mkForce true; + impermanence = lib.mkForce true; + nvd = lib.mkForce true; + gnome-keyring = lib.mkForce true; + sway = lib.mkForce true; + xdg-portal = lib.mkForce true; + distrobox = lib.mkForce true; + appimage = lib.mkForce true; + lid = lib.mkForce true; + lowBattery = lib.mkForce true; + lanzaboote = lib.mkForce true; + autologin = lib.mkForce true; + }; + + }; + } + #+end_src -**** home-manager +**** Server +:PROPERTIES: +:CUSTOM_ID: h:dfc076fd-ee74-4663-b164-653370c52b75 +:END: + +#+begin_src nix-ts :tangle profiles/nixos/localserver/default.nix :mkdirp yes + { lib, config, ... }: + { + 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; + server = { + general = lib.mkDefault true; + network = lib.mkDefault true; + diskEncryption = lib.mkDefault true; + packages = lib.mkDefault true; + ssh = lib.mkDefault true; + nginx = lib.mkDefault true; + }; + }; + }; + + } + +#+end_src +**** Router +:PROPERTIES: +:CUSTOM_ID: h:f3af356a-e732-471b-b8b3-37dcd70297d5 +:END: + +#+begin_src nix-ts :tangle profiles/nixos/router/default.nix :mkdirp yes + { lib, config, ... }: + { + options.swarselprofiles.router = lib.mkEnableOption "enable the router profile"; + config = lib.mkIf config.swarselprofiles.router { + swarselmodules = { + server = { + router = lib.mkDefault true; + }; + }; + }; + + } + +#+end_src +*** home-manager :PROPERTIES: :CUSTOM_ID: h:ced5841f-c088-4d88-b3a1-7d62aad8837b :END: This holds modules that are to be used on most hosts. These are also the most important options to configure, as these allow me easy access to monitor, keyboard, and other setups. -#+BEGIN_src nix :tangle modules/home/default.nix - let - moduleNames = [ - "laptop" - "hardware" - "monitors" - "input" - "nixos" - "darwin" - "waybar" - "startup" - "wallpaper" - "filesystem" - "firefox" - ]; - - mkImports = names: builtins.listToAttrs (map (name: { - inherit name; - value = import ./${name}.nix; - }) names); - - in - mkImports moduleNames -#+end_src - -***** Laptop -:PROPERTIES: -:CUSTOM_ID: h:ec08cd7e-4a9a-419f-a0a7-6cc4576302a1 -:END: - -Laptops are not always plugged in, so they should show a battery icon in Waybar. Also, most laptops have a touchpad which usually needs to be configured. - -#+begin_src nix :tangle modules/home/laptop.nix - { lib, config, ... }: - { - options.swarselsystems.isLaptop = lib.mkEnableOption "laptop host"; - config.swarselsystems.touchpad = lib.mkIf config.swarselsystems.isLaptop { - "type:touchpad" = { - dwt = "enabled"; - tap = "enabled"; - natural_scroll = "enabled"; - middle_emulation = "enabled"; - }; - }; - config.swarselsystems.waybarModules = lib.mkIf config.swarselsystems.isLaptop [ - "custom/outer-left-arrow-dark" - "mpris" - "custom/left-arrow-light" - "network" - "custom/vpn" - "custom/left-arrow-dark" - "pulseaudio" - "custom/left-arrow-light" - "battery" - "custom/left-arrow-dark" - "group/hardware" - "custom/left-arrow-light" - "clock#2" - "custom/left-arrow-dark" - "clock#1" - ]; - } -#+end_src - -***** Hardware -:PROPERTIES: -:CUSTOM_ID: h:5f0bf0e2-a096-4b07-affb-6beba7786fab -:END: - -This section is mostly used to deliver the correct information to Waybar. AMD systems have changing hwmon paths that can be specifically set here. Also the cpu count can be set here for Waybars cpu module, but 8 is usually a good setting to show - -#+begin_src nix :tangle modules/home/hardware.nix - { lib, ... }: - - { - options.swarselsystems.cpuCount = lib.mkOption { - type = lib.types.int; - default = 8; - }; - options.swarselsystems.temperatureHwmon.isAbsolutePath = lib.mkEnableOption "absolute temperature path"; - options.swarselsystems.temperatureHwmon.path = lib.mkOption { - type = lib.types.str; - default = ""; - }; - options.swarselsystems.temperatureHwmon.input-filename = lib.mkOption { - type = lib.types.str; - default = ""; - }; - } -#+end_src - -***** Waybar -:PROPERTIES: -:CUSTOM_ID: h:a9530c81-1976-442b-b597-0b4bed6baf25 -:END: - -These are explicit waybar options. Laptops do not need the battery module. However, this leads to a slight problem with theming: my waybar modules alternate their background-color between black and grey. The battery module is usually on grey background. If I were to simply delete that, I would now have two modules on black background. To avoid this, I define a pseudo-module =custom/pseudobat= that simply shows a static image and calls =wlogout= on right click. This wastes a little bit of screen space, but that is a price I am willing to pay for consistency. - -The most part of this configuration is done here: [[#h:0bf51f63-01c0-4053-a591-7f0c5697c690][Waybar]] - -#+begin_src nix :tangle modules/home/waybar.nix - { lib, config, ... }: - - let - generateIcons = n: lib.concatStringsSep " " (builtins.map (x: "{icon" + toString x + "}") (lib.range 0 (n - 1))); - in - { - options.swarselsystems.cpuString = lib.mkOption { - type = lib.types.str; - default = generateIcons config.swarselsystems.cpuCount; - description = "The generated icons string for use by Waybar."; - internal = true; - }; - options.swarselsystems.waybarModules = lib.mkOption { - type = lib.types.listOf lib.types.str; - default = [ - "custom/outer-left-arrow-dark" - "mpris" - "custom/left-arrow-light" - "network" - "custom/vpn" - "custom/left-arrow-dark" - "pulseaudio" - "custom/left-arrow-light" - "custom/pseudobat" - "battery" - "custom/left-arrow-dark" - "group/hardware" - "custom/left-arrow-light" - "clock#2" - "custom/left-arrow-dark" - "clock#1" - ]; - }; - } -#+end_src - -***** Monitors -:PROPERTIES: -:CUSTOM_ID: h:dfd5c190-f213-45e1-b17c-e650b7b94b38 -:END: - -This allows me to define my monitors in the machine's =default.nix=. - -#+begin_src nix :tangle modules/home/monitors.nix +#+BEGIN_src nix-ts :tangle profiles/home/default.nix { lib, ... }: let - inherit (lib) mkOption types; + profileNames = lib.swarselsystems.readNix "profiles/home"; in { - options.swarselsystems.monitors = mkOption { - type = types.attrsOf (types.attrsOf types.str); - default = { }; - }; - options.swarselsystems.sharescreen = mkOption { - type = types.str; - default = ""; - }; - options.swarselsystems.lowResolution = mkOption { - type = types.str; - default = ""; - }; - options.swarselsystems.highResolution = mkOption { - type = types.str; - default = ""; - }; + imports = lib.swarselsystems.mkImports profileNames "profiles/home"; } #+end_src -***** Input +**** Personal :PROPERTIES: -:CUSTOM_ID: h:880df388-4050-4955-9663-9c1c197f5ae9 +:CUSTOM_ID: h:26512487-8c29-4b92-835b-d67394c3f5ef :END: -This allows me to configure input options. Here, I am globally defining my split keyboards. Then, I am joining some attribute sets so that they can be easier used in the rest of the configurations. - -#+begin_src nix :tangle modules/home/input.nix - { lib, config, ... }: - let - inherit (lib) mkOption types; - in - { - options.swarselsystems.inputs = mkOption { - type = types.attrsOf (types.attrsOf types.str); - default = { }; - }; - options.swarselsystems.kyria = mkOption { - type = types.attrsOf (types.attrsOf types.str); - default = { - "36125:53060:splitkb.com_splitkb.com_Kyria_rev3" = { - xkb_layout = "us"; - xkb_variant = "altgr-intl"; - }; - "7504:24926:Kyria_Keyboard" = { - xkb_layout = "us"; - xkb_variant = "altgr-intl"; - }; - }; - }; - options.swarselsystems.touchpad = mkOption { - type = types.attrsOf (types.attrsOf types.str); - default = { }; - }; - options.swarselsystems.standardinputs = mkOption { - type = types.attrsOf (types.attrsOf types.str); - default = lib.recursiveUpdate (lib.recursiveUpdate config.swarselsystems.touchpad config.swarselsystems.kyria) config.swarselsystems.inputs; - internal = true; - }; - options.swarselsystems.keybindings = mkOption { - type = types.attrsOf types.str; - default = { }; - }; - options.swarselsystems.shellAliases = mkOption { - type = types.attrsOf types.str; - default = { }; - }; - } -#+end_src - -***** Nixos -:PROPERTIES: -:CUSTOM_ID: h:e4a9e96f-ff9f-4fc2-8fc0-9913e03bd568 -:END: - -These are some extra options that will be used if the machine also runs NixOS. For example, non-NixOS hosts need =nixGL= prepended to most graphic commands, and =swayfx= works less nicely on these machines. - -#+begin_src nix :noweb yes :tangle modules/home/nixos.nix +#+begin_src nix-ts :tangle profiles/home/personal/default.nix :mkdirp yes { lib, config, ... }: { - options.swarselsystems.flakePath = lib.mkOption { - type = lib.types.str; - default = ""; - }; - options.swarselsystems.isNixos = lib.mkEnableOption "nixos host"; - options.swarselsystems.isPublic = lib.mkEnableOption "is a public machine (no secrets)"; - config.swarselsystems.startup = lib.mkIf (!config.swarselsystems.isNixos) [ - { - command = "sleep 60 && nixGL nextcloud --background"; - } - { command = "sleep 60 && nixGL vesktop --start-minimized -enable-features=UseOzonePlatform -ozone-platform=wayland"; } - { command = "sleep 60 && nixGL syncthingtray --wait"; } - { command = "sleep 60 && ANKI_WAYLAND=1 nixGL anki"; } - { command = "nm-applet --indicator"; } - { command = "sleep 60 && OBSIDIAN_USE_WAYLAND=1 nixGL obsidian -enable-features=UseOzonePlatform -ozone-platform=wayland"; } - { command = "sleep 60 && element-desktop --hidden -enable-features=UseOzonePlatform -ozone-platform=wayland --disable-gpu-driver-bug-workarounds"; } - ]; - options.swarselsystems.swayfxConfig = lib.mkOption { - type = lib.types.str; - default = " - blur enable - blur_xray disable - blur_passes 1 - blur_radius 1 - shadows enable - corner_radius 2 - titlebar_separator disable - default_dim_inactive 0.02 - "; - internal = true; - }; - config.swarselsystems.swayfxConfig = lib.mkIf (!config.swarselsystems.isNixos) " "; - } -#+end_src - -***** darwin -:PROPERTIES: -:CUSTOM_ID: h:79f7150f-b162-4f57-abdf-07f40dffd932 -:END: - -Provides settings related to nix-darwin systems. At the moment, I am only making use of a =isDarwin= flag. - -#+begin_src nix :noweb yes :tangle modules/home/darwin.nix -{ lib, ... }: -{ - options.swarselsystems.isDarwin = lib.mkEnableOption "darwin host"; -} -#+end_src - -***** System startup -:PROPERTIES: -:CUSTOM_ID: h:0809445e-9a24-4700-8675-03fb8f4beab8 -:END: - -This defines programs I want to have starting when I start the system - -Part of the startup is also defined in [[#h:02df9dfc-d1af-4a37-a7a0-d8da0af96a20][Sway]]. The distinction is as follows. As this configuration also needs to work on systems that are running only home manager, I probably need to run nixGL or something similar on those systems to get these graphic apps to display properly. In this section we only define such graphical programs, in the other location we only put shell applications and such. - -These other apps currently include: -- spotifytui -- kitty - -Do not that =syncthingtray= is also not mentioned here. It is installed as a home manager package that automatically starts at system start. - -#+begin_src nix :tangle modules/home/startup.nix -{ lib, ... }: -let - inherit (lib) mkOption types; -in -{ - - options.swarselsystems.startup = mkOption { - type = types.listOf (types.attrsOf types.str); - default = [ - { command = "nextcloud --background"; } - { command = "vesktop --start-minimized --enable-speech-dispatcher --ozone-platform-hint=auto --enable-features=WaylandWindowDecorations --enable-wayland-ime"; } - { command = "element-desktop --hidden --enable-features=UseOzonePlatform --ozone-platform=wayland --disable-gpu-driver-bug-workarounds"; } - { command = "ANKI_WAYLAND=1 anki"; } - { command = "OBSIDIAN_USE_WAYLAND=1 obsidian"; } - { command = "nm-applet"; } - { command = "feishin"; } - ]; - }; -} -#+end_src - -***** Wallpaper -:PROPERTIES: -:CUSTOM_ID: h:21e344a8-8212-463f-9c01-7dbca28515b6 -:END: - -Again, I set the wallpaper here for =stylix=. - -#+begin_src nix :tangle modules/home/wallpaper.nix - { lib, ... }: - - { - options.swarselsystems.wallpaper = lib.mkOption { - type = lib.types.path; - default = ""; - }; - } - -#+end_src - -***** Filesystem -:PROPERTIES: -:CUSTOM_ID: h:c4982d06-1962-439c-9eed-cdec52491dee -:END: - -Another duplicated option for the filesystem. - -#+begin_src nix :tangle modules/home/filesystem.nix - { lib, ... }: - - { - options.swarselsystems.isBtrfs = lib.mkEnableOption "use btrfs filesystem"; - } -#+end_src - -***** firefox -:PROPERTIES: -:CUSTOM_ID: h:e7f98ad8-74a6-4860-a368-cce154285ff0 -:END: - - -At work I am using several services that are using SSO login - however, as I am using four different accounts at work, this becomes a chore here. Hence, I have defined multiple profiles in [[#h:f0b2ea93-94c8-48d8-8d47-6fe58f58e0e6][Work]] that are all practically using the same configuration. To save screen space, I template that profile here. -Set in firefox =about:config > toolkit.legacyUserProfileCustomizations.stylesheets= to true. This should in principle be set automatically using the below config, but it seems not to be working reliably - -#+begin_src nix :noweb yes :tangle modules/home/firefox.nix -{ lib, pkgs, ... }: - let - lock-false = { - Value = false; - Status = "locked"; - }; - lock-true = { - Value = true; - Status = "locked"; - }; - in -{ - options.swarselsystems.firefox = lib.mkOption { - type = lib.types.attrs; - default = { - isDefault = false; - userChrome = builtins.readFile ../../programs/firefox/chrome/userChrome.css; - extensions = with pkgs.nur.repos.rycee.firefox-addons; [ - tridactyl - tampermonkey - sidebery - browserpass - clearurls - darkreader - enhancer-for-youtube - istilldontcareaboutcookies - translate-web-pages - ublock-origin - reddit-enhancement-suite - sponsorblock - web-archives - onepassword-password-manager - single-file - widegithub - enhanced-github - unpaywall - don-t-fuck-with-paste - plasma-integration - (buildFirefoxXpiAddon { - pname = "shortkeys"; - version = "4.0.2"; - addonId = "Shortkeys@Shortkeys.com"; - url = "https://addons.mozilla.org/firefox/downloads/file/3673761/shortkeys-4.0.2.xpi"; - sha256 = "c6fe12efdd7a871787ac4526eea79ecc1acda8a99724aa2a2a55c88a9acf467c"; - meta = with lib; - { - description = "Easily customizable custom keyboard shortcuts for Firefox. To configure this addon go to Addons (ctrl+shift+a) ->Shortkeys ->Options. Report issues here (please specify that the issue is found in Firefox): https://github.com/mikecrittenden/shortkeys"; - mozPermissions = [ - "tabs" - "downloads" - "clipboardWrite" - "browsingData" - "storage" - "bookmarks" - "sessions" - "" - ]; - platforms = platforms.all; - }; - }) - ]; - - settings = - { - "extensions.autoDisableScopes" = 0; - "browser.bookmarks.showMobileBookmarks" = lock-true; - "toolkit.legacyUserProfileCustomizations.stylesheets" = lock-true; - "browser.search.suggest.enabled" = lock-false; - "browser.search.suggest.enabled.private" = lock-false; - "browser.urlbar.suggest.searches" = lock-false; - "browser.urlbar.showSearchSuggestionsFirst" = lock-false; - "browser.topsites.contile.enabled" = lock-false; - "browser.newtabpage.activity-stream.feeds.section.topstories" = lock-false; - "browser.newtabpage.activity-stream.feeds.snippets" = lock-false; - "browser.newtabpage.activity-stream.section.highlights.includePocket" = lock-false; - "browser.newtabpage.activity-stream.section.highlights.includeBookmarks" = lock-false; - "browser.newtabpage.activity-stream.section.highlights.includeDownloads" = lock-false; - "browser.newtabpage.activity-stream.section.highlights.includeVisited" = lock-false; - "browser.newtabpage.activity-stream.showSponsored" = lock-false; - "browser.newtabpage.activity-stream.system.showSponsored" = lock-false; - "browser.newtabpage.activity-stream.showSponsoredTopSites" = lock-false; - }; - - search = { - default = "Kagi"; - privateDefault = "Kagi"; - engines = { - "Kagi" = { - urls = [{ - template = "https://kagi.com/search"; - params = [ - { name = "q"; value = "{searchTerms}"; } - ]; - }]; - iconUpdateURL = "https://kagi.com/favicon.ico"; - updateInterval = 24 * 60 * 60 * 1000; # every day - definedAliases = [ "@k" ]; - }; - - "Nix Packages" = { - urls = [{ - template = "https://search.nixos.org/packages"; - params = [ - { name = "type"; value = "packages"; } - { name = "query"; value = "{searchTerms}"; } - ]; - }]; - icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg"; - definedAliases = [ "@np" ]; - }; - - "NixOS Wiki" = { - urls = [{ - template = "https://nixos.wiki/index.php?search={searchTerms}"; - }]; - iconUpdateURL = "https://nixos.wiki/favicon.png"; - updateInterval = 24 * 60 * 60 * 1000; # every day - definedAliases = [ "@nw" ]; - }; - - "NixOS Options" = { - urls = [{ - template = "https://search.nixos.org/options"; - params = [ - { name = "query"; value = "{searchTerms}"; } - ]; - }]; - - icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg"; - definedAliases = [ "@no" ]; - }; - - "Home Manager Options" = { - urls = [{ - template = "https://home-manager-options.extranix.com/"; - params = [ - { name = "query"; value = "{searchTerms}"; } - ]; - }]; - - icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg"; - definedAliases = [ "@hm" "@ho" "@hmo" ]; - }; - - "Google".metaData.alias = "@g"; - }; - force = true; # this is required because otherwise the search.json.mozlz4 symlink gets replaced on every firefox restart - }; - }; - }; - - -} -#+end_src - -** NixOS -:PROPERTIES: -:CUSTOM_ID: h:6da812f5-358c-49cb-aff2-0a94f20d70b3 -:END: - -Here we have NixOS options. All options are split into smaller files that are loaded by the general =default.nix=. Common files are used by all user hosts equally, optionals need to be added to the machine's =default.nix= on a case-by-case basis. -*** Common -:PROPERTIES: -:CUSTOM_ID: h:1c1250cd-e9b4-4715-8d9f-eb09e64bfc7f -:END: - -These are system-level settings specific to NixOS machines. All settings that are required on all machines go here. - -**** Imports, non-server settings -:PROPERTIES: -:CUSTOM_ID: h:4acbe063-188b-42e7-b75c-b6d2e232e784 -:END: - -This section is for setting things that should be used on hosts that are using the default NixOS configuration. This means that servers should NOT import this, as much of these imported modules are user-configured. - -#+begin_src nix :tangle profiles/common/nixos/default.nix - _: - { - imports = [ - ./settings.nix - ./home-manager.nix - ./xserver.nix - ./users.nix - ./env.nix - ./stylix.nix - ./polkit.nix - ./gc.nix - ./store.nix - ./systemd.nix - ./network.nix - ./time.nix - ./hardware.nix - ./pipewire.nix - ./sops.nix - ./packages.nix - ./programs.nix - ./zsh.nix - ./syncthing.nix - ./blueman.nix - ./networkdevices.nix - ./gvfs.nix - ./interceptiontools.nix - ./hardwarecompatibility.nix - ./login.nix - ./stylix.nix - ./power-profiles-daemon.nix - # ./impermanence.nix - ./nvd-rebuild.nix - ./nix-ld.nix - ./gnome-keyring.nix - ./sway.nix - ./xdg-portal.nix - # ./yubikey-touch-detector.nix - # ./safeeyes.nix - ./distrobox.nix - ./lid.nix - ./lowbattery.nix - ]; - - nixpkgs.config.permittedInsecurePackages = [ - "jitsi-meet-1.0.8043" - "electron-29.4.6" - ]; - - } - - #+end_src - -**** General NixOS settings (stateVersion) -:PROPERTIES: -:CUSTOM_ID: h:24c9146f-2147-4fd5-bafc-d5853e15cf12 -:END: - - -Also, we disable the warnings that trigger when rebuilding with a dirty flake. At this point, I am also disabling channels and pinning the flake registry - the latter lets me use the local version of nixpkgs for commands like =nix shell= (without it, we will always download the newest version of nixpkgs for these commands). - -Also, the system state version is set here. No need to touch it. - -#+begin_src nix :tangle profiles/common/nixos/settings.nix - { lib, inputs, ... }: - { - nix = - let - flakeInputs = lib.filterAttrs (_: lib.isType "flake") inputs; - in - { - settings = { - experimental-features = [ - "nix-command" - "flakes" - "ca-derivations" - "pipe-operators" - ]; - trusted-users = [ "swarsel" ]; - flake-registry = ""; - warn-dirty = false; - }; - channel.enable = false; - registry = lib.mapAttrs (_: flake: { inherit flake; }) flakeInputs; - nixPath = lib.mapAttrsToList (n: _: "${n}=flake:${n}") flakeInputs; - }; - - - system.stateVersion = lib.mkDefault "23.05"; - - } - #+end_src - -**** System Packages -:PROPERTIES: -:CUSTOM_ID: h:0e7e8bea-ec58-499c-9731-09dddfc39532 -:END: - -Mostly used to install some compilers and lsp's that I want to have available when not using a devShell flake. Most other packages should go in [[#h:893a7f33-7715-415b-a895-2687ded31c18][Installed packages]]. - -#+begin_src nix :tangle profiles/common/nixos/packages.nix - { pkgs, ... }: - { - environment.systemPackages = with pkgs; [ - # yubikey packages - gnupg - yubikey-personalization - yubikey-personalization-gui - yubico-pam - yubioath-flutter - yubikey-manager - yubikey-manager-qt - yubikey-touch-detector - yubico-piv-tool - cfssl - pcsctools - pcscliteWithPolkit.out - - # ledger packages - ledger-live-desktop - - # pinentry - dbus - swaylock-effects - syncthingtray-minimal - - # secure boot - sbctl - - libsForQt5.qt5.qtwayland - - # nix package database - nix-index - nixos-generators - - # commit hooks - pre-commit - - # proc info - acpi - - # better make for general tasks - just - - # keyboards - qmk - vial - via - - # theme related - adwaita-icon-theme - - # kde-connect - xdg-desktop-portal - xdg-desktop-portal-wlr - - # bluetooth - bluez - - # lsp-related ------------------------------- - # nix - # latex - texlab - ghostscript_headless - # wireguard - wireguard-tools - # rust - rust-analyzer - clippy - rustfmt - # go - go - gopls - # nix - nixd - # zig - zig - zls - # cpp - clang-tools - # + cuda - cudatoolkit - # ansible - ansible-lint - ansible-language-server - molecule - #lsp-bridge / python - gcc - gdb - (python3.withPackages (ps: with ps; [ jupyter ipython pyqt5 epc orjson sexpdata six setuptools paramiko numpy pandas scipy matplotlib requests debugpy flake8 gnureadline python-lsp-server ])) - # (python3.withPackages(ps: with ps; [ jupyter ipython pyqt5 numpy pandas scipy matplotlib requests debugpy flake8 gnureadline python-lsp-server])) - # -------------------------------------------- - - (stdenv.mkDerivation { - name = "oama"; - - src = pkgs.fetchurl { - name = "oama"; - url = "https://github.com/pdobsan/oama/releases/download/0.13.1/oama-0.13.1-Linux-x86_64-static.tgz"; - sha256 = "sha256-OTdCObVfnMPhgZxVtZqehgUXtKT1iyqozdkPIV+i3Gc="; - }; - - phases = [ - "unpackPhase" - ]; - - unpackPhase = '' - mkdir -p $out/bin - tar xvf $src -C $out/ - mv $out/oama-0.13.1-Linux-x86_64-static/oama $out/bin/ - ''; - - }) - - ]; - } -#+end_src - -**** Setup home-manager -:PROPERTIES: -:CUSTOM_ID: h:7f6d6908-4d02-4907-9c70-f802f4358520 -:END: - -We enable the use of =home-manager= as a NixoS module. A nice trick here is the =extraSpecialArgs = inputs= line, which enables the use of =seflf= in most parts of the configuration. This is useful to refer to the root of the flake (which is otherwise quite hard while maintaining flake purity). - -#+begin_src nix :tangle profiles/common/nixos/home-manager.nix - { inputs, config, lib, ... }: - { - home-manager = lib.mkIf config.swarselsystems.withHomeManager { - useGlobalPkgs = true; - useUserPackages = true; - extraSpecialArgs = inputs; # used mainly for inputs.self - }; - } - #+end_src - -**** Setup login keymap -:PROPERTIES: -:CUSTOM_ID: h:7248f338-8cad-4443-9060-deae7955b26f -:END: - -Next, we setup the keymap in case we are not in a graphical session. At this point, I always resort to us/altgr-intl, as it is comfortable to use and I do not write too much German anyways. - -#+begin_src nix :tangle profiles/common/nixos/xserver.nix - _: - { - services.xserver = { - xkb = { - layout = "us"; - variant = "altgr-intl"; - }; - }; - } - #+end_src - -**** User setup, Make users non-mutable -:PROPERTIES: -:CUSTOM_ID: h:48959890-fbc7-4d28-b33c-f33e028ab473 -:END: - -This ensures that all user-configuration happens here in the config file. -In case of using a fully setup system, this makes also sure that no further user level modifications can be made using CLI utilities (e.g. usermod etc.). Everything must be defined in the flake. - -For that reason, make sure that =sops-nix= is properly working before setting the =initialSetup= flag, otherwise you might lose user access. - -#+begin_src nix :tangle profiles/common/nixos/users.nix - { pkgs, config, lib, ... }: - { - sops.secrets.swarseluser = lib.mkIf (!config.swarselsystems.isPublic) { neededForUsers = true; }; - - users = { - mutableUsers = lib.mkIf (!config.swarselsystems.initialSetup) false; - users.swarsel = { - isNormalUser = true; - description = "Leon S"; - password = lib.mkIf config.swarselsystems.initialSetup "setup"; - hashedPasswordFile = lib.mkIf (!config.swarselsystems.initialSetup) config.sops.secrets.swarseluser.path; - extraGroups = [ "networkmanager" "syncthing" "docker" "wheel" "lp" "audio" "video" "vboxusers" "libvirtd" "scanner" ]; - packages = with pkgs; [ ]; - }; - }; - } -#+end_src - -**** Environment setup -:PROPERTIES: -:CUSTOM_ID: h:f4006367-0965-4b4f-a3b0-45f63b07d2b8 -:END: - -Next, we will setup some environment variables that need to be set on the system-side. We apply some compatibility options for chromium apps on wayland, enable the wordlist and make metadata reading possible for my file explorer (nautilus). - -#+begin_src nix :tangle profiles/common/nixos/env.nix - { lib, pkgs, ... }: - { - environment = { - wordlist.enable = true; - sessionVariables = { - NIXOS_OZONE_WL = "1"; - GST_PLUGIN_SYSTEM_PATH_1_0 = lib.makeSearchPathOutput "lib" "lib/gstreamer-1.0" (with pkgs.gst_all_1; [ - gst-plugins-good - gst-plugins-bad - gst-plugins-ugly - gst-libav - ]); - }; - }; - # gstreamer plugins for nautilus (used for file metadata) - } -#+end_src - -**** Security -:PROPERTIES: -:CUSTOM_ID: h:e2d40df9-0026-4caa-8476-9dc2353055a1 -:END: - -Needed for control over system-wide privileges etc. Also I make sure that the root user has access to =SSH_AUTH_SOCK= (without this, root will not be able to read my =nix-secrets= repository). - -#+begin_src nix :tangle profiles/common/nixos/polkit.nix - _: - { - - security.pam.services = { - login.u2fAuth = true; - sudo.u2fAuth = true; - swaylock.u2fAuth = true; - swaylock.fprintAuth = false; - }; - security.polkit.enable = true; - - security.sudo.extraConfig = '' - Defaults env_keep+=SSH_AUTH_SOCK - ''; - - } -#+end_src - -**** Enable automatic garbage collection -:PROPERTIES: -:CUSTOM_ID: h:9a3b7f1f-d0c3-417e-a262-c920fb25f3ee -:END: - -The nix store fills up over time, until =/boot/efi= is filled. This snippet cleans it automatically on a weekly basis. - -#+begin_src nix :tangle profiles/common/nixos/gc.nix - _: - { - nix.gc = { - automatic = true; - randomizedDelaySec = "14m"; - dates = "weekly"; - options = "--delete-older-than 10d"; - }; - } -#+end_src - -**** Enable automatic store optimisation -:PROPERTIES: -:CUSTOM_ID: h:97a2b9f7-c835-4db8-a0e9-e923bab69ee8 -:END: - -This enables hardlinking identical files in the nix store, to save on disk space. I have read this incurs a significant I/O overhead, I need to keep an eye on this. - -#+begin_src nix :tangle profiles/common/nixos/store.nix - _: - { - nix.optimise = { - automatic = true; - dates = [ "weekly" ]; - }; - } - -#+end_src - -**** Reduce systemd timeouts -:PROPERTIES: -:CUSTOM_ID: h:12858442-c129-4aa1-9c9c-a0916e36b302 -:END: - -There is a persistent bug over Linux kernels that makes the user wait 1m30s on system shutdown due to the reason =a stop job is running for session 1 of user ...=. I do not want to wait that long and am confident no important data is lost by doing this. - -#+begin_src nix :tangle profiles/common/nixos/systemd.nix - _: - { - # systemd - systemd.extraConfig = '' - DefaultTimeoutStartSec=60s - DefaultTimeoutStopSec=15s - ''; - } -#+end_src - -**** Hardware settings -:PROPERTIES: -:CUSTOM_ID: h:1fa7cf61-5c03-43a3-a7f0-3d6ee246b31b -:END: - -Enable OpenGL, Sound, Bluetooth and various drivers. - -#+begin_src nix :tangle profiles/common/nixos/hardware.nix - { pkgs, config, lib, ... }: - { - - hardware = { - # opengl.driSupport32Bit = true is replaced with graphics.enable32Bit and hence redundant - graphics = { - enable = true; - enable32Bit = true; - }; - - - trackpoint = lib.mkIf config.swarselsystems.trackpoint.isAvailable { - enable = true; - inherit (config.swarselsystems.trackpoint) device; - }; - - keyboard.qmk.enable = true; - - - pulseaudio = { - enable = lib.mkIf (!config.services.pipewire.enable) true; - package = pkgs.pulseaudioFull; - }; - - enableAllFirmware = true; - - bluetooth = lib.mkIf config.swarselsystems.hasBluetooth { - enable = true; - package = pkgs.stable.bluez; - powerOnBoot = true; - settings = { - General = { - Enable = "Source,Sink,Media,Socket"; - }; - }; + options.swarselprofiles.personal = lib.mkEnableOption "is this a personal host"; + config = lib.mkIf config.swarselprofiles.personal { + swarselmodules = { + anki = lib.mkDefault true; + anki-tray = lib.mkDefault true; + atuin = lib.mkDefault true; + autotiling = lib.mkDefault true; + batsignal = lib.mkDefault true; + blueman-applet = lib.mkDefault true; + desktop = lib.mkDefault true; + direnv = lib.mkDefault true; + element-desktop = lib.mkDefault true; + element-tray = lib.mkDefault true; + emacs = lib.mkDefault true; + env = lib.mkDefault true; + eza = lib.mkDefault true; + firefox = lib.mkDefault true; + fuzzel = lib.mkDefault true; + gammastep = lib.mkDefault true; + general = lib.mkDefault true; + git = lib.mkDefault true; + gnome-keyring = lib.mkDefault true; + gpgagent = lib.mkDefault true; + hexchat = lib.mkDefault true; + kanshi = lib.mkDefault true; + kdeconnect = lib.mkDefault true; + kitty = lib.mkDefault true; + mail = lib.mkDefault true; + mako = lib.mkDefault true; + nix-index = lib.mkDefault true; + nixgl = lib.mkDefault true; + nix-your-shell = lib.mkDefault true; + nm-applet = lib.mkDefault true; + obs-studio = lib.mkDefault true; + obsidian = lib.mkDefault true; + obsidian-tray = lib.mkDefault true; + opkssh = lib.mkDefault true; + ownpackages = lib.mkDefault true; + packages = lib.mkDefault true; + passwordstore = lib.mkDefault true; + programs = lib.mkDefault true; + sops = lib.mkDefault false; + spicetify = lib.mkDefault true; + spotify-player = lib.mkDefault true; + ssh = lib.mkDefault true; + starship = lib.mkDefault true; + stylix = lib.mkDefault true; + sway = lib.mkDefault true; + swayidle = lib.mkDefault true; + swaylock = lib.mkDefault true; + swayosd = lib.mkDefault true; + symlink = lib.mkDefault true; + tmux = lib.mkDefault true; + vesktop = lib.mkDefault true; + vesktop-tray = lib.mkDefault true; + syncthing-tray = lib.mkDefault true; + waybar = lib.mkDefault true; + yubikey = lib.mkDefault false; + yubikeytouch = lib.mkDefault true; + zellij = lib.mkDefault true; + zsh = lib.mkDefault true; }; }; - services.fprintd.enable = lib.mkIf config.swarselsystems.hasFingerprint true; } + #+end_src -**** Pipewire +**** DGX Spark :PROPERTIES: -:CUSTOM_ID: h:aa433f5e-a455-4414-b76b-0a2692fa06aa +:CUSTOM_ID: h:6d30ef28-ee26-4954-90f6-53c33dee9217 :END: -Pipewire handles communication on Wayland. This enables several sound tools as well as screen sharing in combinaton with =xdg-desktop-portal-wlr=. - -#+begin_src nix :tangle profiles/common/nixos/pipewire.nix - _: { - security.rtkit.enable = true; # this is required for pipewire real-time access - - services.pipewire = { - enable = true; - pulse.enable = true; - jack.enable = true; - audio.enable = true; - wireplumber.enable = true; - alsa = { - enable = true; - support32Bit = true; - }; - }; - } -#+end_src -**** Common network settings -:PROPERTIES: -:CUSTOM_ID: h:7d696b64-debe-4a95-80b5-1e510156a6c6 -:END: - -Here I only enable =networkmanager= and a few default networks. The rest of the network config is done separately in [[#h:88bf4b90-e94b-46fb-aaf1-a381a512860d][System specific configuration]]. - -#+begin_src nix :tangle profiles/common/nixos/network.nix +#+begin_src nix-ts :tangle profiles/home/dgxspark/default.nix :mkdirp yes { lib, config, ... }: { - networking = { - nftables.enable = lib.mkDefault true; - enableIPv6 = lib.mkDefault true; - firewall = { - checkReversePath = lib.mkDefault false; - enable = lib.mkDefault true; - allowedUDPPorts = [ 51820 ]; # 51820: wireguard - allowedTCPPortRanges = [ - { from = 1714; to = 1764; } # kde-connect - ]; - allowedUDPPortRanges = [ - { from = 1714; to = 1764; } # kde-connect - ]; - }; - - networkmanager = { - enable = true; - ensureProfiles = lib.mkIf (!config.swarselsystems.isPublic) { - environmentFiles = [ - "${config.sops.templates."network-manager.env".path}" - ]; - profiles = { - "Ernest Routerford" = { - connection = { - id = "Ernest Routerford"; - permissions = ""; - type = "wifi"; - }; - ipv4 = { - dns-search = ""; - method = "auto"; - }; - ipv6 = { - addr-gen-mode = "stable-privacy"; - dns-search = ""; - method = "auto"; - }; - wifi = { - mac-address-blacklist = ""; - mode = "infrastructure"; - ssid = "Ernest Routerford"; - }; - wifi-security = { - auth-alg = "open"; - key-mgmt = "wpa-psk"; - psk = "$ERNEST"; - }; - }; - - LAN-Party = { - connection = { - autoconnect = "false"; - id = "LAN-Party"; - type = "ethernet"; - }; - ethernet = { - auto-negotiate = "true"; - cloned-mac-address = "preserve"; - mac-address = "90:2E:16:D0:A1:87"; - }; - ipv4 = { method = "shared"; }; - ipv6 = { - addr-gen-mode = "stable-privacy"; - method = "auto"; - }; - proxy = { }; - }; - - eduroam = { - "802-1x" = { - eap = "ttls;"; - identity = "$EDUID"; - password = "$EDUPASS"; - phase2-auth = "mschapv2"; - }; - connection = { - id = "eduroam"; - type = "wifi"; - }; - ipv4 = { method = "auto"; }; - ipv6 = { - addr-gen-mode = "default"; - method = "auto"; - }; - proxy = { }; - wifi = { - mode = "infrastructure"; - ssid = "eduroam"; - }; - wifi-security = { - auth-alg = "open"; - key-mgmt = "wpa-eap"; - }; - }; - - local = { - connection = { - autoconnect = "false"; - id = "local"; - type = "ethernet"; - }; - ethernet = { }; - ipv4 = { - address1 = "10.42.1.1/24"; - method = "shared"; - }; - ipv6 = { - addr-gen-mode = "stable-privacy"; - method = "auto"; - }; - proxy = { }; - }; - - HH40V_39F5 = { - connection = { - id = "HH40V_39F5"; - type = "wifi"; - }; - ipv4 = { method = "auto"; }; - ipv6 = { - addr-gen-mode = "stable-privacy"; - method = "auto"; - }; - proxy = { }; - wifi = { - band = "bg"; - mode = "infrastructure"; - ssid = "HH40V_39F5"; - }; - wifi-security = { - key-mgmt = "wpa-psk"; - psk = "$FRAUNS"; - }; - }; - - magicant = { - connection = { - id = "magicant"; - type = "wifi"; - }; - ipv4 = { method = "auto"; }; - ipv6 = { - addr-gen-mode = "default"; - method = "auto"; - }; - proxy = { }; - wifi = { - mode = "infrastructure"; - ssid = "magicant"; - }; - wifi-security = { - auth-alg = "open"; - key-mgmt = "wpa-psk"; - psk = "$HANDYHOTSPOT"; - }; - }; - - wireguardvpn = { - connection = { - id = "HomeVPN"; - type = "wireguard"; - autoconnect = "false"; - interface-name = "wg1"; - }; - wireguard = { private-key = "$WIREGUARDPRIV"; }; - "wireguard-peer.$WIREGUARDPUB" = { - endpoint = "$WIREGUARDENDPOINT"; - allowed-ips = "0.0.0.0/0"; - }; - ipv4 = { - method = "ignore"; - address1 = "192.168.3.3/32"; - }; - ipv6 = { - addr-gen-mode = "stable-privacy"; - method = "ignore"; - }; - proxy = { }; - }; - - "sweden-aes-128-cbc-udp-dns" = { - connection = { - autoconnect = "false"; - id = "PIA Sweden"; - type = "vpn"; - }; - ipv4 = { method = "auto"; }; - ipv6 = { - addr-gen-mode = "stable-privacy"; - method = "auto"; - }; - proxy = { }; - vpn = { - auth = "sha1"; - ca = - "${config.users.users.swarsel.home}/.dotfiles/secrets/certs/sweden-aes-128-cbc-udp-dns-ca.pem"; - challenge-response-flags = "2"; - cipher = "aes-128-cbc"; - compress = "yes"; - connection-type = "password"; - crl-verify-file = "${config.users.users.swarsel.home}/.dotfiles/secrets/certs/sweden-aes-128-cbc-udp-dns-crl-verify.pem"; - dev = "tun"; - password-flags = "0"; - remote = "sweden.privacy.network:1198"; - remote-cert-tls = "server"; - reneg-seconds = "0"; - service-type = "org.freedesktop.NetworkManager.openvpn"; - username = "$VPNUSER"; - }; - vpn-secrets = { password = "$VPNPASS"; }; - }; - - Hotspot = { - connection = { - autoconnect = "false"; - id = "Hotspot"; - type = "wifi"; - }; - ipv4 = { method = "shared"; }; - ipv6 = { - addr-gen-mode = "default"; - method = "ignore"; - }; - proxy = { }; - wifi = { - mode = "ap"; - ssid = "Hotspot-swarsel"; - }; - wifi-security = { - group = "ccmp;"; - key-mgmt = "wpa-psk"; - pairwise = "ccmp;"; - proto = "rsn;"; - psk = "$HOTSPOT"; - }; - }; - - }; - }; - }; - }; - - systemd.services.NetworkManager-ensure-profiles.after = [ "NetworkManager.service" ]; - } -#+end_src - -**** Time, locale settings -:PROPERTIES: -:CUSTOM_ID: h:852d59ab-63c3-4831-993d-b5e23b877796 -:END: - -Setup timezone and locale. I want to use the US layout, but have the rest adapted to my country and timezone. Also, there is an issue with running Windows/Linux dualboot on the same machine where the hardware clock desyncs between the two OS'es. We fix that bug here as well. - -#+begin_src nix :tangle profiles/common/nixos/time.nix - _: - { - time = { - timeZone = "Europe/Vienna"; - # hardwareClockInLocalTime = true; - }; - - i18n = { - defaultLocale = "en_US.UTF-8"; - extraLocaleSettings = { - LC_ADDRESS = "de_AT.UTF-8"; - LC_IDENTIFICATION = "de_AT.UTF-8"; - LC_MEASUREMENT = "de_AT.UTF-8"; - LC_MONETARY = "de_AT.UTF-8"; - LC_NAME = "de_AT.UTF-8"; - LC_NUMERIC = "de_AT.UTF-8"; - LC_PAPER = "de_AT.UTF-8"; - LC_TELEPHONE = "de_AT.UTF-8"; - LC_TIME = "de_AT.UTF-8"; - }; - }; - } -#+end_src - -**** sops -:PROPERTIES: -:CUSTOM_ID: h:d87d80fd-2ac7-4f29-b338-0518d06b4deb -:END: - -I use sops-nix to handle secrets that I want to have available on my machines at all times. Procedure to add a new machine: -- `ssh-keygen -t ed25519 -C "NAME sops"` in .ssh directory (or wherever) - name e.g. "sops" -- cat ~/.ssh/sops.pub | ssh-to-age | wl-copy -- add the output to .sops.yaml -- cp ~/.ssh/sops.pub ~/.dotfiles/secrets/keys/NAME.pub -- update entry for sops.age.sshKeyPaths - -#+begin_src nix :tangle profiles/common/nixos/sops.nix - { config, lib, ... }: - let - mkIfElse = p: yes: no: lib.mkMerge [ - (lib.mkIf p yes) - (lib.mkIf (!p) no) - ]; - in - { - sops = lib.mkIf (!config.swarselsystems.isPublic) { - - age.sshKeyPaths = mkIfElse config.swarselsystems.isBtrfs [ "/persist/.ssh/sops" ] [ "${config.users.users.swarsel.home}/.ssh/sops" "/etc/ssh/ssh_host_ed25519_key" ]; - defaultSopsFile = mkIfElse config.swarselsystems.isBtrfs "/persist/.dotfiles/secrets/general/secrets.yaml" "${config.users.users.swarsel.home}/.dotfiles/secrets/general/secrets.yaml"; - - validateSopsFiles = false; - - secrets = { - ernest = { }; - frauns = { }; - hotspot = { }; - eduid = { }; - edupass = { }; - handyhotspot = { }; - vpnuser = { }; - vpnpass = { }; - wireguardpriv = { }; - wireguardpub = { }; - wireguardendpoint = { }; - stashuser = { }; - stashpass = { }; - githubforgeuser = { }; - githubforgepass = { }; - gitlabforgeuser = { }; - gitlabforgepass = { }; - }; - templates = { - "network-manager.env".content = '' - ERNEST=${config.sops.placeholder.ernest} - FRAUNS=${config.sops.placeholder.frauns} - HOTSPOT=${config.sops.placeholder.hotspot} - EDUID=${config.sops.placeholder.eduid} - EDUPASS=${config.sops.placeholder.edupass} - HANDYHOTSPOT=${config.sops.placeholder.handyhotspot} - VPNUSER=${config.sops.placeholder.vpnuser} - VPNPASS=${config.sops.placeholder.vpnpass} - WIREGUARDPRIV=${config.sops.placeholder.wireguardpriv} - WIREGUARDPUB=${config.sops.placeholder.wireguardpub} - WIREGUARDENDPOINT=${config.sops.placeholder.wireguardendpoint} - ''; - ".authinfo" = { - owner = "swarsel"; - path = "${config.users.users.swarsel.home}/.emacs.d/.authinfo"; - content = '' - machine stash.swarsel.win:443 port https login ${config.sops.placeholder.stashuser} password ${config.sops.placeholder.stashpass} - machine gitlab.com/api/v4 login ${config.sops.placeholder.githubforgeuser} password ${config.sops.placeholder.githubforgepass} - machine api.github.com login ${config.sops.placeholder.gitlabforgeuser} password ${config.sops.placeholder.gitlabforgepass} - ''; - }; - }; - }; - } - #+end_src - -**** Theme (stylix) -:PROPERTIES: -:CUSTOM_ID: h:e6e44705-94af-49fe-9ca0-0629d0f7d932 -:END: - -By default, [[https://github.com/danth/stylix][stylix]] wants to style GRUB as well. However, I think that looks horrible. -=theme= is defined in [[#h:5bc1b0c9-dc59-4c81-b5b5-e60699deda78][Theme (stylix)]]. - -#+begin_src nix :noweb yes :tangle profiles/common/nixos/stylix.nix - { self, pkgs, home-manager, config, ... }: - { - stylix = { - <> - targets.grub.enable = false; # the styling makes grub more ugly - image = config.swarselsystems.wallpaper; - }; - home-manager.users.swarsel = { - stylix = { - targets = { - emacs.enable = false; - waybar.enable = false; - }; - }; - }; - } -#+end_src - -**** Programs (including zsh setup) -:PROPERTIES: -:CUSTOM_ID: h:2bbf5f31-246d-4738-925f-eca40681f7b6 -:END: - -Some programs profit from being installed through dedicated NixOS settings on system-level; these go here. Notably the zsh setup goes here and cannot be deleted under any circumstances. - -#+begin_src nix :tangle profiles/common/nixos/programs.nix - _: - { - programs = { - dconf.enable = true; - evince.enable = true; - kdeconnect.enable = true; - }; - } -#+end_src - -***** zsh -:PROPERTIES: -:CUSTOM_ID: h:7daa06ff-d3b0-4491-97ce-770b749c52f9 -:END: -Do not touch this. - -#+begin_src nix :tangle profiles/common/nixos/zsh.nix - { pkgs, ... }: - { - programs.zsh.enable = true; - users.defaultUserShell = pkgs.zsh; - environment.shells = with pkgs; [ zsh ]; - environment.pathsToLink = [ "/share/zsh" ]; - } -#+end_src -***** syncthing -:PROPERTIES: -:CUSTOM_ID: h:1e6d3d56-e415-43a2-8e80-3bad8062ecf8 -:END: - -#+begin_src nix :tangle profiles/common/nixos/syncthing.nix - _: - { - services.syncthing = { - enable = true; - user = "swarsel"; - dataDir = "/home/swarsel"; - configDir = "/home/swarsel/.config/syncthing"; - openDefaultPorts = true; - settings = { - devices = { - "magicant" = { - id = "VMWGEE2-4HDS2QO-KNQOVGN-LXLX6LA-666E4EK-ZBRYRRO-XFEX6FB-6E3XLQO"; - }; - "sync (@oracle)" = { - id = "ETW6TST-NPK7MKZ-M4LXMHA-QUPQHDT-VTSHH5X-CR5EIN2-YU7E55F-MGT7DQB"; - }; - "winters" = { - id = "O7RWDMD-AEAHPP7-7TAVLKZ-BSWNBTU-2VA44MS-EYGUNBB-SLHKB3C-ZSLMOAA"; - }; - }; - folders = { - "Default Folder" = { - path = "/home/swarsel/Sync"; - devices = [ "sync (@oracle)" "magicant" "winters" ]; - id = "default"; - }; - "Obsidian" = { - path = "/home/swarsel/Nextcloud/Obsidian"; - devices = [ "sync (@oracle)" "magicant" "winters" ]; - id = "yjvni-9eaa7"; - }; - "Org" = { - path = "/home/swarsel/Nextcloud/Org"; - devices = [ "sync (@oracle)" "magicant" "winters" ]; - id = "a7xnl-zjj3d"; - }; - "Vpn" = { - path = "/home/swarsel/Vpn"; - devices = [ "sync (@oracle)" "magicant" "winters" ]; - id = "hgp9s-fyq3p"; - }; - ".elfeed" = { - path = "/home/swarsel/.elfeed"; - devices = [ "sync (@oracle)" "magicant" "winters" ]; - id = "h7xbs-fs9v1"; - }; - }; - }; - }; - } -#+end_src - -**** Services -:PROPERTIES: -:CUSTOM_ID: h:79f3258f-ed9d-434d-b50a-e58d57ade2a7 -:END: - -Setting up some hardware services as well as keyboard related settings. Here we make sure that we can use the CAPS key as a ESC/CTRL double key, which is a lifesaver. - -***** blueman -:PROPERTIES: -:CUSTOM_ID: h:b91df05b-113d-4d09-93d1-b271e5b76810 -:END: - -Enables the blueman service including the nice system tray icon. - -#+begin_src nix :tangle profiles/common/nixos/blueman.nix - _: - { - services.blueman.enable = true; - services.hardware.bolt.enable = true; - } -#+end_src - -***** Network devices -:PROPERTIES: -:CUSTOM_ID: h:73ed28cb-2f82-47b2-8bc5-208278b55788 -:END: - -In this section we enable compatibility with several network devices I have at home, mainly printers and scanners. -****** Scanners -:PROPERTIES: -:CUSTOM_ID: h:fae5939e-22ac-4532-a10e-0b86013d20ce -:END: - -This allows me to use my big scanner/printer's scanning function over the network. - -#+begin_src nix :tangle profiles/common/nixos/networkdevices.nix - { pkgs, ... }: - { - # enable scanners over network - hardware.sane = { - enable = true; - extraBackends = [ pkgs.sane-airscan ]; - }; - -#+end_src - -****** Printers -:PROPERTIES: -:CUSTOM_ID: h:8c13df62-c6d9-4a0a-83be-d77e71628f0b -:END: - -This allows me to use my big scanner/printer's printing function over the network. Most of the settings are driver related. - -#+begin_src nix :tangle profiles/common/nixos/networkdevices.nix - - # enable discovery and usage of network devices (esp. printers) - services.printing = { - enable = true; - drivers = [ - pkgs.gutenprint - pkgs.gutenprintBin - ]; - browsedConf = '' - BrowseDNSSDSubTypes _cups,_print - BrowseLocalProtocols all - BrowseRemoteProtocols all - CreateIPPPrinterQueues All - BrowseProtocols all - ''; - }; - -#+end_src - -****** Avahi (device discovery) -:PROPERTIES: -:CUSTOM_ID: h:80decee9-9151-4892-967e-73d103205770 -:END: - -Avahi is the service used for the network discovery. - -#+begin_src nix :tangle profiles/common/nixos/networkdevices.nix - - services.avahi = { - enable = true; - nssmdns4 = true; - openFirewall = true; - }; - } -#+end_src - -***** enable GVfs -:PROPERTIES: -:CUSTOM_ID: h:f101daa2-604d-4553-99e2-f64b9c207f51 -:END: - -This is being set to allow myself to use all functions of nautilus in NixOS - -#+begin_src nix :tangle profiles/common/nixos/gvfs.nix - _: - { - services.gvfs.enable = true; - } -#+end_src - -***** interception-tools: Make CAPS work as ESC/CTRL -:PROPERTIES: -:CUSTOM_ID: h:08d213d5-a9f4-4309-8635-ba557b01dc7d -:END: - -This is a super-convenient package that lets my remap my =CAPS= key to =ESC= if pressed shortly, and =CTRL= if being held. - -#+begin_src nix :tangle profiles/common/nixos/interceptiontools.nix - { pkgs, ... }: - { - # Make CAPS work as a dual function ESC/CTRL key - services.interception-tools = { - enable = true; - udevmonConfig = - let - dualFunctionKeysConfig = builtins.toFile "dual-function-keys.yaml" '' - TIMING: - TAP_MILLISEC: 200 - DOUBLE_TAP_MILLISEC: 0 - - MAPPINGS: - - KEY: KEY_CAPSLOCK - TAP: KEY_ESC - HOLD: KEY_LEFTCTRL - ''; - in - '' - - JOB: | - ${pkgs.interception-tools}/bin/intercept -g $DEVNODE \ - | ${pkgs.interception-tools-plugins.dual-function-keys}/bin/dual-function-keys -c ${dualFunctionKeysConfig} \ - | ${pkgs.interception-tools}/bin/uinput -d $DEVNODE - DEVICE: - EVENTS: - EV_KEY: [KEY_CAPSLOCK] - ''; - }; - } -#+end_src - -***** power-profiles-daemon -:PROPERTIES: -:CUSTOM_ID: h:82fbba41-3a46-4db7-aade-49e4c23fc475 -:END: - -This enables power profile management. The available modes are: - -- power-saver -- balanced -- performance - -Most of the time I am using =power-saver=, however, it is good to be able to choose. - -#+begin_src nix :tangle profiles/common/nixos/power-profiles-daemon.nix - _: - { - services.power-profiles-daemon.enable = true; - } -#+end_src - -**** Hardware compatibility settings (Yubikey, Ledger, Keyboards) - udev rules -:PROPERTIES: -:CUSTOM_ID: h:7a89b5e3-b700-4167-8b14-2b8172f33936 -:END: - -It makes sense to house these settings in their own section, since they are all needed really. Note that the starting of the gpg-agent is done in the sway settings, to also perform this step of the setup for non NixOS-machines at the same time. - -=pcscd= is needed to use the smartcard mode (CCID) of the Yubikey. - -The exception is the system packages, since that cannot be defined twice in the same file (common.nix). The comment is left in as a remider for that. - -Also, this is a good place to setup the udev rules. - -#+begin_src nix :tangle profiles/common/nixos/hardwarecompatibility.nix - { pkgs, ... }: - { - programs.ssh.startAgent = false; - - services.pcscd.enable = true; - - hardware.ledger.enable = true; - - services.udev.packages = with pkgs; [ - yubikey-personalization - ledger-udev-rules - qmk-udev-rules - vial - via - ]; - } -#+end_src - -**** System Login -:PROPERTIES: -:CUSTOM_ID: h:eae45839-223a-4027-bce3-e26e092c9096 -:END: - -This section houses the greetd related settings. I do not really want to use a display manager, but it is useful to have setup in some ways - in my case for starting sway on system startup. Notably the default user login setting that is commented out here goes into the *system specific* settings, make sure to update it there - -#+begin_src nix :tangle profiles/common/nixos/login.nix - { pkgs, ... }: - { - services.greetd = { - enable = true; - settings = { - initial_session.command = "sway"; - # initial_session.user ="swarsel"; - default_session.command = '' - ${pkgs.greetd.tuigreet}/bin/tuigreet \ - --time \ - --asterisks \ - --user-menu \ - --cmd sway - ''; - }; - }; - - environment.etc."greetd/environments".text = '' - sway - ''; - } -#+end_src - -**** nix-ld -:PROPERTIES: -:CUSTOM_ID: h:404cc18b-b5f8-48d9-a407-a0fd70d57f46 -:END: - -This provides libraries for binaries that are not patched for use on NixOS. This really makes the biggest gripe with NixOS go away, that being having to run a binary that is only found in a single spot. It is most of the times possible to patch such a file, but this makes such a situation take much less time to resolve. - -Only some binaries that touch system settings might still not work, apart from that, the list of libraries I have curated here should be quite exhaustive. - -When a program does not work, start with =nix-ldd =. This will tell you which library is missing. Afterwards, continue with =nix-locate = to find which packages provide that library. Add it to libraries below and rebuild. After a reboot, it will be visible using =nix-ldd=. It can also be useful to take a look at =ldd= to see which libraries are needed in general. - -#+begin_src nix :tangle profiles/common/nixos/nix-ld.nix - { pkgs, ... }: - { - programs.nix-ld = { - enable = true; - libraries = with pkgs; [ - SDL - SDL2 - SDL2_image - SDL2_mixer - SDL2_ttf - SDL_image - SDL_mixer - SDL_ttf - alsa-lib - at-spi2-atk - at-spi2-core - atk - bzip2 - cairo - cups - curl - dbus - dbus-glib - expat - ffmpeg - flac - fontconfig - freeglut - freetype - fuse3 - gdk-pixbuf - glew110 - glib - gnome2.GConf - gnome2.pango - gtk2 - gtk3 - icu - libGL - libappindicator-gtk2 - libappindicator-gtk3 - libcaca - libcanberra - libcap - libdbusmenu-gtk2 - libdrm - libelf - libgcrypt - libglvnd - libidn - libindicator-gtk2 - libjpeg - libmikmod - libnotify - libogg - libpng - libpng12 - libpulseaudio - librsvg - libsamplerate - libtheora - libtiff - libudev0-shim - libunwind - libusb1 - libuuid - libva - libvdpau - libvorbis - libvpx - libxkbcommon - libxml2 - libz - mesa - nspr - nss - openssl - pango - pipewire - pixman - speex - stdenv.cc.cc - steam-fhsenv-without-steam - systemd - tbb - vulkan-loader - xorg.libICE - xorg.libSM - xorg.libX11 - xorg.libXScrnSaver - xorg.libXcomposite - xorg.libXcursor - xorg.libXdamage - xorg.libXext - xorg.libXfixes - xorg.libXft - xorg.libXi - xorg.libXinerama - xorg.libXmu - xorg.libXrandr - xorg.libXrender - xorg.libXt - xorg.libXtst - xorg.libXxf86vm - xorg.libxcb - xorg.libxshmfence - zlib - ]; - }; - } -#+end_src - -**** Impermanence -:PROPERTIES: -:CUSTOM_ID: h:e7668594-fa8b-4d36-a695-a58222478988 -:END: - -This is where the impermanence magic happens. When this is enabled, the root directory is rolled back to a blanket state on each reboot. - -Normally, doing that also resets the lecture that happens on the first use of =sudo=, so we disable that at this point. Also, here we can set files to be persisted. Do note that you should still pay attention to files that need sudo access, as these need to be copied manually. - -#+begin_src nix :tangle profiles/common/nixos/impermanence.nix - { config, lib, ... }: - { - - security.sudo.extraConfig = lib.mkIf config.swarselsystems.impermanence '' - # rollback results in sudo lectures after each reboot - Defaults lecture = never - ''; - - # This script does the actual wipe of the system - # So if it doesn't run, the btrfs system effectively acts like a normal system - # Taken from https://github.com/NotAShelf/nyx/blob/2a8273ed3f11a4b4ca027a68405d9eb35eba567b/modules/core/common/system/impermanence/default.nix - - boot.initrd.systemd.enable = true; - - boot.initrd.systemd.services.rollback = lib.mkIf config.swarselsystems.impermanence { - description = "Rollback BTRFS root subvolume to a pristine state"; - wantedBy = [ "initrd.target" ]; - # make sure it's done after encryption - # i.e. LUKS/TPM process - after = [ "systemd-cryptsetup@enc.service" ]; - # mount the root fs before clearing - before = [ "sysroot.mount" ]; - unitConfig.DefaultDependencies = "no"; - serviceConfig.Type = "oneshot"; - script = '' - mkdir -p /mnt - - # We first mount the btrfs root to /mnt - # so we can manipulate btrfs subvolumes. - mount -o subvol=/ /dev/mapper/cryptroot /mnt - btrfs subvolume list -o /mnt/root - - # While we're tempted to just delete /root and create - # a new snapshot from /root-blank, /root is already - # populated at this point with a number of subvolumes, - # which makes `btrfs subvolume delete` fail. - # So, we remove them first. - # - # /root contains subvolumes: - # - /root/var/lib/portables - # - /root/var/lib/machines - - btrfs subvolume list -o /mnt/root | - cut -f9 -d' ' | - while read subvolume; do - echo "deleting /$subvolume subvolume..." - # btrfs subvolume delete "/mnt/$subvolume" - done && - echo "deleting /root subvolume..." && - # btrfs subvolume delete /mnt/root - - echo "restoring blank /root subvolume..." - # btrfs subvolume snapshot /mnt/root-blank /mnt/root - - # Once we're done rolling back to a blank snapshot, - # we can unmount /mnt and continue on the boot process. - umount /mnt - ''; - }; - - - environment.persistence."/persist" = lib.mkIf config.swarselsystems.impermanence { - hideMounts = true; - directories = - [ - "/.cache/nix" - "/srv" - "/etc/nixos" - "/etc/nix" - "/home/swarsel/.dotfiles" - "/etc/NetworkManager/system-connections" - "/etc/secureboot" - "/var/db/sudo" - "/var/cache" - "/var/lib" - ]; - - files = [ - # ssh stuff - /* - "/etc/ssh/ssh_host_ed25519_key" - "/etc/ssh/ssh_host_ed25519_key.pub" - "/etc/ssh/ssh_host_rsa_key" - "/etc/ssh/ssh_host_rsa_key.pub" - ,*/ - ]; - }; - - } -#+end_src - -**** Summary of nixos-rebuild diff -:PROPERTIES: -:CUSTOM_ID: h:b751d77d-246c-4bd6-b689-3467d82bf9c3 -:END: - -This snipped is added to the activation script that is run after every rebuild and shows what packages have been added and removed. This is actually not the optimal place to add that snipped, but the correct spot is in some perl file that I have not had the leisure to take a look at yet. - -#+begin_src nix :tangle profiles/common/nixos/nvd-rebuild.nix - { pkgs, ... }: - { - system.activationScripts.diff = { - supportsDryActivation = true; - text = '' - ${pkgs.nvd}/bin/nvd --color=always --nix-bin-dir=${pkgs.nix}/bin diff \ - /run/current-system "$systemConfig" - ''; - }; - } -#+end_src - -**** gnome-keyring -:PROPERTIES: -:CUSTOM_ID: h:ce50eb90-8bf4-4203-b502-c3165d2fbf1f -:END: - -Used for storing sessions in e.g. Nextcloud. Using this on a system level keeps the login information when logging out of the session as well. - -#+begin_src nix :tangle profiles/common/nixos/gnome-keyring.nix - _: - { - services.gnome.gnome-keyring = { - enable = true; - }; - - programs.seahorse.enable = true; - } -#+end_src - -**** Sway -:PROPERTIES: -:CUSTOM_ID: h:f78ffdd3-232b-4313-bd89-d6fb331fef22 -:END: - -This is used to better integrate Sway into the system on NixOS hosts. On the home-manager side, the =package= attribute will be =null= for such an host, using the systems derivation instead. - -#+begin_src nix :tangle profiles/common/nixos/sway.nix - { pkgs, ... }: - { - - programs.sway = { - enable = true; - package = pkgs.swayfx; - wrapperFeatures = { - base = true; - gtk = true; - }; - - extraSessionCommands = '' - export XDG_SESSION_DESKTOP=sway - export SDL_VIDEODRIVER=wayland - export QT_QPA_PLATFORM=wayland-egl - export QT_WAYLAND_DISABLE_WINDOWDECORATION=1 - export QT_QPA_PLATFORM_PLUGIN_PATH="${pkgs.libsForQt5.qt5.qtbase.bin}/lib/qt-${pkgs.libsForQt5.qt5.qtbase.version}/plugins"; - export MOZ_ENABLE_WAYLAND=1 - export MOZ_DISABLE_RDD_SANDBOX=1 - ''; - }; - - } -#+end_src - -**** xdg-portal -:PROPERTIES: -:CUSTOM_ID: h:872d5f46-2ffd-4076-9a2c-98783dd29434 -:END: - -This allows me to use screen sharing on Wayland. The implementation is a bit crude and only the whole screen can be shared. However, most of the time that is all I need to do anyways. - -#+begin_src nix :tangle profiles/common/nixos/xdg-portal.nix - { pkgs, ... }: - { - - xdg.portal = { - enable = true; - config = { - common = { - default = "wlr"; - }; - }; - wlr.enable = true; - wlr.settings.screencast = { - output_name = "eDP-1"; - chooser_type = "simple"; - chooser_cmd = "${pkgs.slurp}/bin/slurp -f %o -or"; + options.swarselprofiles.dgxspark = lib.mkEnableOption "is this a dgx spark host"; + config = lib.mkIf config.swarselprofiles.dgxspark { + swarselmodules = { + anki = lib.mkDefault false; + anki-tray = lib.mkDefault false; + atuin = lib.mkDefault true; + autotiling = lib.mkDefault false; + batsignal = lib.mkDefault false; + bash = lib.mkDefault true; + blueman-applet = lib.mkDefault true; + desktop = lib.mkDefault false; + direnv = lib.mkDefault true; + element-desktop = lib.mkDefault false; + element-tray = lib.mkDefault false; + emacs = lib.mkDefault false; + env = lib.mkDefault false; + eza = lib.mkDefault true; + firefox = lib.mkDefault true; + fuzzel = lib.mkDefault true; + gammastep = lib.mkDefault false; + general = lib.mkDefault true; + git = lib.mkDefault true; + gnome-keyring = lib.mkDefault false; + gpgagent = lib.mkDefault true; + hexchat = lib.mkDefault false; + kanshi = lib.mkDefault false; + kdeconnect = lib.mkDefault false; + kitty = lib.mkDefault true; + mail = lib.mkDefault false; + mako = lib.mkDefault false; + nix-index = lib.mkDefault true; + nixgl = lib.mkDefault true; + nix-your-shell = lib.mkDefault true; + nm-applet = lib.mkDefault true; + obs-studio = lib.mkDefault false; + obsidian = lib.mkDefault false; + obsidian-tray = lib.mkDefault false; + ownpackages = lib.mkDefault false; + packages = lib.mkDefault false; + passwordstore = lib.mkDefault false; + programs = lib.mkDefault false; + sops = lib.mkDefault true; + spicetify = lib.mkDefault false; + spotify-player = lib.mkDefault false; + ssh = lib.mkDefault false; + starship = lib.mkDefault true; + stylix = lib.mkDefault true; + sway = lib.mkDefault false; + swayidle = lib.mkDefault false; + swaylock = lib.mkDefault false; + swayosd = lib.mkDefault false; + symlink = lib.mkDefault false; + tmux = lib.mkDefault true; + vesktop = lib.mkDefault false; + vesktop-tray = lib.mkDefault false; + syncthing-tray = lib.mkDefault false; + waybar = lib.mkDefault false; + yubikey = lib.mkDefault false; + yubikeytouch = lib.mkDefault false; + zellij = lib.mkDefault true; + zsh = lib.mkDefault true; }; }; } + #+end_src -**** safeeyes +**** Minimal :PROPERTIES: -:CUSTOM_ID: h:d33c93f5-0ac8-44e5-8756-02dc0e6975e4 +:CUSTOM_ID: h:26512487-8c29-4b92-835b-d67394c3f5ef :END: -A friend of mine used this service and I used to make fun of him. But I have to admit this is actually a nice program. It forces you to look away from the screen from time to time, reducing eye strain. - -#+begin_src nix :tangle profiles/common/nixos/safeeyes.nix - _: - { - services.safeeyes.enable = true; - } -#+end_src - -**** Podmam (distrobox) -:PROPERTIES: -:CUSTOM_ID: h:1bef3914-a258-4585-b232-e0fbe9e7a9b5 -:END: - -I am using distrobox to quickly circumvent isses that I cannot immediately solve on NixOS. It is always the goal to quickly get things working on NixOS, but this prevents me from getting completely stuck. - -#+begin_src nix :tangle profiles/common/nixos/distrobox.nix - { pkgs, ... }: - { - environment.systemPackages = with pkgs; [ - distrobox - boxbuddy - ]; - - virtualisation.podman = { - enable = true; - }; - - } -#+end_src - -**** Handle lid switch correctly -:PROPERTIES: -:CUSTOM_ID: h:a5a0d84e-c7b3-4164-a4c7-2e2d8ada69cd -:END: - -This turns off the display when the lid is closed. - -#+begin_src nix :tangle profiles/common/nixos/lid.nix - _: - { - services.logind = { - lidSwitch = "suspend"; - lidSwitchDocked = "ignore"; - }; - services.acpid = { - enable = true; - lidEventCommands = - '' - export PATH=$PATH:/run/current-system/sw/bin - export WAYLAND_DISPLAY=wayland-1 - export XDG_RUNTIME_DIR=/run/user/1000 - export SWAYSOCK=$(ls /run/user/1000/sway-ipc.* | head -n 1) - - LID_STATE=$(cat /proc/acpi/button/lid/*/state | grep -q closed && echo "closed" || echo "open") - DOCKED=$(swaymsg -t get_outputs | grep -q 'HDMI\|DP' && echo "docked" || echo "undocked") - - if [ "$LID_STATE" == "closed" ] && [ "$DOCKED" == "docked" ]; then - swaymsg output eDP-2 disable - else - swaymsg output eDP-2 enable - fi - ''; - }; - } -#+end_src - -**** Low battery notification -:PROPERTIES: -:CUSTOM_ID: h:adf894d7-b3c6-4b8b-b13f-c28b3a5e1e17 -:END: - -Since I hide the waybar completely during normal operation, I run the risk of not noticing when my battery is about to run out. This module sends a notification when the battery level falls below 10%. Written by [[https://gist.github.com/cafkafk][cafkafk]]. - -#+begin_src nix :tangle profiles/common/nixos/lowbattery.nix - { pkgs, lib, ... }: - { - systemd.user.services."battery-low" = { - enable = true; - description = "Notify user if battery is below 10%"; - partOf = [ "graphical-session.target" ]; - wantedBy = [ "graphical-session.target" ]; - serviceConfig = { - Type = "simple"; - ExecStart = pkgs.writeShellScript "battery-low-notification" - '' - if (( 10 >= $(${lib.getExe pkgs.acpi} -b | head -n 1 | ${lib.getExe pkgs.ripgrep} -o "\d+%" | ${lib.getExe pkgs.ripgrep} -o "\d+"))); - then ${lib.getExe pkgs.libnotify} --urgency=critical "low battery" "$(${lib.getExe pkgs.acpi} -b | head -n 1 | ${lib.getExe pkgs.ripgrep} -o "\d+%")"; - fi; - ''; - }; - }; - systemd.user.timers."battery-low" = { - wantedBy = [ "timers.target" ]; - timerConfig = { - # Every Minute - OnCalendar = "*-*-* *:*:00"; - Unit = "battery-low.service"; - }; - }; - } -#+end_src - -*** Server -:PROPERTIES: -:CUSTOM_ID: h:e492c24a-83a0-4bcb-a084-706f49318651 -:END: -**** Imports -:PROPERTIES: -:CUSTOM_ID: h:4e64e564-b7cb-469f-bd79-cd3efb3caa62 -:END: - -First, we enable the use of =home-manager= as a NixoS module. - -Also, we disable the warnings that trigger when rebuilding with a dirty flake. At this point, I am also disabling channels and pinning the flake registry - the latter lets me use the local version of nixpkgs for commands like =nix shell= (without it, we will always download the newest version of nixpkgs for these commands). - -Also, the system state version is set here. No need to touch it. - -#+begin_src nix :tangle profiles/server/nixos/default.nix - { self, ... }: - let - profilesPath = "${self}/profiles"; - in - { - imports = [ - "${profilesPath}/common/nixos/settings.nix" - "${profilesPath}/common/nixos/home-manager.nix" - "${profilesPath}/common/nixos/xserver.nix" - "${profilesPath}/common/nixos/gc.nix" - "${profilesPath}/common/nixos/store.nix" - "${profilesPath}/common/nixos/time.nix" - "${profilesPath}/common/nixos/users.nix" - "${profilesPath}/common/nixos/nix-ld.nix" - ./settings.nix - ./packages.nix - ./sops.nix - ./ssh.nix - ./nfs.nix - ./nginx.nix - ./kavita.nix - ./jellyfin.nix - ./navidrome.nix - ./spotifyd.nix - ./mpd.nix - ./matrix.nix - ./pipewire.nix - ./nextcloud.nix - ./immich.nix - ./paperless.nix - ./transmission.nix - ./syncthing.nix - ./restic.nix - ./monitoring.nix - ./jenkins.nix - ./emacs.nix - ./forgejo.nix - ./ankisync.nix - ./freshrss.nix - ]; - } - #+end_src - -**** General NixOS Server settings -:PROPERTIES: -:CUSTOM_ID: h:dc365e83-f6c8-4d05-a390-b5f2d01649b4 -:END: - -Here we just define some aliases for rebuilding the system, and we allow some insecure packages that are needed by some server derivations. It would be more elegant to define these in the respective module, but nixpkgs needs to be defined before we can evaluate modules within it, so this must be a top-level configuration. - -#+begin_src nix :tangle profiles/server/nixos/settings.nix +#+begin_src nix-ts :tangle profiles/home/minimal/default.nix :mkdirp yes { lib, config, ... }: { - environment.shellAliases = lib.recursiveUpdate - { - npswitch = "cd ${config.swarselsystems.flakePath}; git pull; sudo nixos-rebuild --flake .#$(hostname) switch; cd -;"; - nswitch = "sudo nixos-rebuild --flake ${config.swarselsystems.flakePath}#$(hostname) switch;"; - npiswitch = "cd ${config.swarselsystems.flakePath}; git pull; sudo nixos-rebuild --flake .#$(hostname) switch --impure; cd -;"; - nipswitch = "cd ${config.swarselsystems.flakePath}; git pull; sudo nixos-rebuild --flake .#$(hostname) switch --impure; cd -;"; - niswitch = "sudo nixos-rebuild --flake ${config.swarselsystems.flakePath}#$(hostname) switch --impure;"; - } - config.swarselsystems.shellAliases; - - nixpkgs.config.permittedInsecurePackages = [ - # matrix - "olm-3.2.16" - # sonarr - "aspnetcore-runtime-wrapped-6.0.36" - "aspnetcore-runtime-6.0.36" - "dotnet-sdk-wrapped-6.0.428" - "dotnet-sdk-6.0.428" - ]; - - } -#+end_src - -**** System Packages -:PROPERTIES: -:CUSTOM_ID: h:6f2967d9-7e32-4605-bb5c-5e27770bec0f -:END: - -#+begin_src nix :tangle profiles/server/nixos/packages.nix - { pkgs, ... }: - { - environment.systemPackages = with pkgs; [ - gnupg - nix-index - ssh-to-age - git - emacs - vim - ]; - } -#+end_src - -**** sops -:PROPERTIES: -:CUSTOM_ID: h:313f7940-e8bb-4b5d-97cb-e2fea4e665e4 -:END: - -#+begin_src nix :tangle profiles/server/nixos/sops.nix - { config, lib, ... }: - { - sops = { - age.sshKeyPaths = lib.mkDefault [ "/etc/ssh/sops" ]; - defaultSopsFile = lib.mkDefault "${config.swarselsystems.flakePath}/secrets/winters/secrets.yaml"; - validateSopsFiles = false; + options.swarselprofiles.minimal = lib.mkEnableOption "is this a personal host"; + config = lib.mkIf config.swarselprofiles.minimal { + swarselmodules = { + general = lib.mkDefault true; + sops = lib.mkDefault true; + kitty = lib.mkDefault true; + zsh = lib.mkDefault true; + git = lib.mkDefault true; + }; }; } + #+end_src -**** nfs/samba (smb) +**** Hotel :PROPERTIES: -:CUSTOM_ID: h:d6840d31-110c-465f-93fa-0306f755de28 +:CUSTOM_ID: h:36a0209f-2c17-4808-a1d0-a9e1920c307a :END: -#+begin_src nix :tangle profiles/server/nixos/nfs.nix - { pkgs, ... }: - { - services = { - # add a user with sudo smbpasswd -a - samba = { - package = pkgs.samba4Full; - # extraConfig = '' - # workgroup = WORKGROUP - # server role = standalone server - # dns proxy = no - - # pam password change = yes - # map to guest = bad user - # create mask = 0664 - # force create mode = 0664 - # directory mask = 0775 - # force directory mode = 0775 - # follow symlinks = yes - # ''; - - enable = true; - openFirewall = true; - settings.Eternor = { - browseable = "yes"; - "read only" = "no"; - "guest ok" = "no"; - path = "/Vault/Eternor"; - writable = "true"; - comment = "Eternor"; - "valid users" = "Swarsel"; - }; - }; - - - avahi = { - publish.enable = true; - publish.userServices = true; # Needed to allow samba to automatically register mDNS records without the need for an `extraServiceFile` - nssmdns4 = true; - enable = true; - openFirewall = true; - }; - - # This enables autodiscovery on windows since SMB1 (and thus netbios) support was discontinued - samba-wsdd = { - enable = true; - openFirewall = true; - }; - }; - } -#+end_src - -**** NGINX -:PROPERTIES: -:CUSTOM_ID: h:302468d2-106a-41c8-b2bc-9fdc40064a9c -:END: - -#+begin_src nix :tangle profiles/server/nixos/nginx.nix - { pkgs, config, ... }: - { - environment.systemPackages = with pkgs; [ - lego - ]; - - # users.users.acme = {}; - - sops = { - # secrets.dnstokenfull = { owner = "acme"; }; - secrets.dnstokenfull = { }; - templates."certs.secret".content = '' - CF_DNS_API_TOKEN=${config.sops.placeholder.dnstokenfull} - ''; - }; - - security.acme = { - acceptTerms = true; - preliminarySelfsigned = false; - defaults.email = "mrswarsel@gmail.com"; - defaults.dnsProvider = "cloudflare"; - defaults.environmentFile = "${config.sops.templates."certs.secret".path}"; - }; - - services.nginx = { - enable = true; - statusPage = true; - recommendedProxySettings = true; - recommendedTlsSettings = true; - recommendedOptimisation = true; - recommendedGzipSettings = true; - # virtualHosts are defined in the respective sections - }; - - } -#+end_src - -**** ssh -:PROPERTIES: -:CUSTOM_ID: h:f3db197d-1d03-4bf8-b59f-f9891b358f0b -:END: - -#+begin_src nix :tangle profiles/server/nixos/ssh.nix - { self, ... }: - { - services.openssh = { - enable = true; - }; - users.users.swarsel.openssh.authorizedKeys.keyFiles = [ - (self + /secrets/keys/ssh/nbl-imba-2.pub) - (self + /secrets/keys/ssh/magicant.pub) - ]; - users.users.root.openssh.authorizedKeys.keyFiles = [ - (self + /secrets/keys/ssh/nbl-imba-2.pub) - (self + /secrets/keys/ssh/magicant.pub) - ]; - security.sudo.extraConfig = '' - Defaults env_keep+=SSH_AUTH_SOCK - ''; - - } -#+end_src - -**** kavita -:PROPERTIES: -:CUSTOM_ID: h:d33f5982-dfe6-42d0-9cf2-2cd8c7b04295 -:END: - -#+begin_src nix :tangle profiles/server/nixos/kavita.nix - { pkgs, lib, config, ... }: - { - config = lib.mkIf config.swarselsystems.server.kavita { - environment.systemPackages = with pkgs; [ - calibre - ]; - - - users.users.jellyfin = { - extraGroups = [ "users" ]; - }; - - sops.secrets.kavita = { owner = "kavita"; }; - - networking.firewall.allowedTCPPorts = [ 8080 ]; - - services.kavita = { - enable = true; - user = "kavita"; - settings.Port = 8080; - tokenKeyFile = config.sops.secrets.kavita.path; - }; - - services.nginx = { - virtualHosts = { - "scroll.swarsel.win" = { - enableACME = true; - forceSSL = true; - acmeRoot = null; - locations = { - "/" = { - proxyPass = "http://localhost:8080"; - extraConfig = '' - client_max_body_size 0; - ''; - }; - }; - }; - }; - }; - }; - } -#+end_src - -**** jellyfin -:PROPERTIES: -:CUSTOM_ID: h:e0d4c16e-ab64-48ac-9734-1ab62953ad4b -:END: - -#+begin_src nix :tangle profiles/server/nixos/jellyfin.nix -{ pkgs, lib, config, ... }: -{ - config = lib.mkIf config.swarselsystems.server.jellyfin { - users.users.jellyfin = { - extraGroups = [ "video" "render" "users" ]; - }; - nixpkgs.config.packageOverrides = pkgs: { - vaapiIntel = pkgs.vaapiIntel.override { enableHybridCodec = true; }; - }; - hardware.graphics = { - enable = true; - extraPackages = with pkgs; [ - intel-media-driver # LIBVA_DRIVER_NAME=iHD - vaapiIntel # LIBVA_DRIVER_NAME=i965 (older but works better for Firefox/Chromium) - vaapiVdpau - libvdpau-va-gl - ]; - }; - services.jellyfin = { - enable = true; - user = "jellyfin"; - openFirewall = true; # this works only for the default ports - }; - - services.nginx = { - virtualHosts = { - "screen.swarsel.win" = { - enableACME = true; - forceSSL = true; - acmeRoot = null; - locations = { - "/" = { - proxyPass = "http://localhost:8096"; - extraConfig = '' - client_max_body_size 0; - ''; - }; - }; - }; - }; - }; - }; - -} -#+end_src - -**** navidrome -:PROPERTIES: -:CUSTOM_ID: h:f347f3ad-5100-4c4f-8616-cfd7f8e14a72 -:END: - -#+begin_src nix :tangle profiles/server/nixos/navidrome.nix - { pkgs, lib, inputs, config, ... }: - let - secretsDirectory = builtins.toString inputs.nix-secrets; - in - { - config = lib.mkIf config.swarselsystems.server.navidrome { - environment.systemPackages = with pkgs; [ - pciutils - alsa-utils - mpv - ]; - - users = { - groups = { - navidrome = { - gid = 61593; - }; - }; - - users = { - navidrome = { - isSystemUser = true; - uid = 61593; - group = "navidrome"; - extraGroups = [ "audio" "utmp" "users" "pipewire" ]; - }; - }; - }; - - - hardware = { - # opengl.enable = true; - enableAllFirmware = true; - }; - - networking.firewall.allowedTCPPorts = [ 4040 ]; - - services.navidrome = { - enable = true; - openFirewall = true; - settings = { - LogLevel = "error"; - Address = "127.0.0.1"; - Port = 4040; - MusicFolder = "/Vault/Eternor/Musik"; - EnableSharing = true; - EnableTranscodingConfig = true; - Scanner.GroupAlbumReleases = true; - ScanSchedule = "@every 24h"; - MPVPath = "${pkgs.mpv}/bin/mpv"; - MPVCommandTemplate = "mpv --audio-device=%d --no-audio-display --pause %f"; - Jukebox = { - Enabled = true; - Default = "pch"; - Devices = [ - [ "pch" "alsa/sysdefault:CARD=PCH" ] - ]; - }; - # Switch using --impure as these credential files are not stored within the flake - # sops-nix is not supported for these which is why we need to resort to these - LastFM.ApiKey = builtins.readFile "${secretsDirectory}/navidrome/lastfm-secret"; - LastFM.Secret = builtins.readFile "${secretsDirectory}/navidrome/lastfm-key"; - Spotify.ID = builtins.readFile "${secretsDirectory}/navidrome/spotify-id"; - Spotify.Secret = builtins.readFile "${secretsDirectory}/navidrome/spotify-secret"; - UILoginBackgroundUrl = "https://i.imgur.com/OMLxi7l.png"; - UIWelcomeMessage = "~SwarselSound~"; - }; - }; - - services.nginx = { - virtualHosts = { - "sound.swarsel.win" = { - enableACME = true; - forceSSL = true; - acmeRoot = null; - locations = { - "/" = { - proxyPass = "http://localhost:4040"; - proxyWebsockets = true; - extraConfig = '' - proxy_redirect http:// https://; - proxy_read_timeout 600s; - proxy_send_timeout 600s; - proxy_buffering off; - proxy_request_buffering off; - client_max_body_size 0; - ''; - }; - }; - }; - }; - }; - }; - - - } -#+end_src - -**** spotifyd -:PROPERTIES: -:CUSTOM_ID: h:ec9c5a7d-ea8b-46d5-809c-163c917f5c41 -:END: - -#+begin_src nix :tangle profiles/server/nixos/spotifyd.nix +#+begin_src nix-ts :tangle profiles/home/hotel/default.nix :mkdirp yes { lib, config, ... }: { - config = lib.mkIf config.swarselsystems.server.spotifyd { - users.groups.spotifyd = { - gid = 65136; - }; - - users.users.spotifyd = { - isSystemUser = true; - uid = 65136; - group = "spotifyd"; - extraGroups = [ "audio" "utmp" "pipewire" ]; - }; - - networking.firewall.allowedTCPPorts = [ 1025 ]; - - services.pipewire.systemWide = true; - - services.spotifyd = { - enable = true; - settings = { - global = { - dbus_type = "session"; - use_mpris = false; - device = "sysdefault:CARD=PCH"; - device_name = "SwarselSpot"; - mixer = "alsa"; - zeroconf_port = 1025; - }; - }; + options.swarselprofiles.hotel = lib.mkEnableOption "is this a hotel host"; + config = lib.mkIf config.swarselprofiles.hotel { + swarselmodules = { + packages = lib.mkForce true; + ownpackages = lib.mkForce true; + general = lib.mkForce true; + nixgl = lib.mkForce true; + sops = lib.mkForce true; + yubikey = lib.mkForce false; + ssh = lib.mkForce true; + stylix = lib.mkForce true; + desktop = lib.mkForce true; + symlink = lib.mkForce true; + env = lib.mkForce false; + programs = lib.mkForce true; + nix-index = lib.mkForce true; + direnv = lib.mkForce true; + eza = lib.mkForce true; + git = lib.mkForce false; + fuzzel = lib.mkForce true; + starship = lib.mkForce true; + kitty = lib.mkForce true; + zsh = lib.mkForce true; + zellij = lib.mkForce true; + tmux = lib.mkForce true; + mail = lib.mkForce false; + emacs = lib.mkForce true; + waybar = lib.mkForce true; + firefox = lib.mkForce true; + gnome-keyring = lib.mkForce true; + kdeconnect = lib.mkForce true; + mako = lib.mkForce true; + swayosd = lib.mkForce true; + yubikeytouch = lib.mkForce true; + sway = lib.mkForce true; + kanshi = lib.mkForce true; + gpgagent = lib.mkForce true; + gammastep = lib.mkForce false; }; }; } + #+end_src -**** mpd +**** Local Server :PROPERTIES: -:CUSTOM_ID: h:baa4149b-3788-4b05-87ec-0ee9d0726117 +:CUSTOM_ID: h:8027b858-369e-4f12-bbaf-f15eeee3d904 :END: -#+begin_src nix :tangle profiles/server/nixos/mpd.nix -{ pkgs, lib, config, ... }: -{ - config = lib.mkIf config.swarselsystems.server.mpd { - users = { - groups = { - mpd = { }; - }; - - users = { - mpd = { - isSystemUser = true; - group = "mpd"; - extraGroups = [ "audio" "utmp" ]; - }; - }; - }; - - sops = { - secrets.mpdpass = { owner = "mpd"; }; - }; - - environment.systemPackages = with pkgs; [ - pciutils - alsa-utils - mpv - ]; - - services.mpd = { - enable = true; - musicDirectory = "/media"; - user = "mpd"; - group = "mpd"; - network = { - port = 3254; - listenAddress = "any"; - }; - credentials = [ - { - passwordFile = config.sops.secrets.mpdpass.path; - permissions = [ - "read" - "add" - "control" - "admin" - ]; - } - ]; - }; - }; - -} -#+end_src - -**** pipewire -:PROPERTIES: -:CUSTOM_ID: h:ce6a4371-e44f-419a-be9e-e17c7abdaf3a -:END: - -#+begin_src nix :tangle profiles/server/nixos/pipewire.nix +#+begin_src nix-ts :tangle profiles/home/localserver/default.nix :mkdirp yes { lib, config, ... }: { - config = lib.mkIf (config.swarselsystems.server.mpd || config.swarselsystems.server.navidrome) { - - security.rtkit.enable = true; # this is required for pipewire real-time access - - services.pipewire = { - enable = true; - pulse.enable = true; - jack.enable = true; - audio.enable = true; - wireplumber.enable = true; - alsa = { - enable = true; - support32Bit = true; + options.swarselprofiles.server.local = lib.mkEnableOption "is this a local server"; + config = lib.mkIf config.swarselprofiles.server.local { + swarselmodules = { + general = lib.mkDefault true; + server = { + dotfiles = lib.mkDefault true; }; }; }; } -#+end_src - -**** matrix -:PROPERTIES: -:CUSTOM_ID: h:1e68d84a-8f99-422f-89ac-78f664ac0013 -:END: - -#+begin_src nix :tangle profiles/server/nixos/matrix.nix - { config, lib, pkgs, sops, ... }: - let - matrixDomain = "swatrix.swarsel.win"; - baseUrl = "https://${matrixDomain}"; - clientConfig."m.homeserver".base_url = baseUrl; - serverConfig."m.server" = "${matrixDomain}:443"; - mkWellKnown = data: '' - default_type application/json; - add_header Access-Control-Allow-Origin *; - return 200 '${builtins.toJSON data}'; - ''; - in - { - - config = lib.mkIf config.swarselsystems.server.matrix { - environment.systemPackages = with pkgs; [ - matrix-synapse - lottieconverter - ffmpeg - ]; - - sops = { - secrets = { - matrixsharedsecret = { owner = "matrix-synapse"; }; - mautrixtelegram_as = { owner = "matrix-synapse"; }; - mautrixtelegram_hs = { owner = "matrix-synapse"; }; - mautrixtelegram_api_id = { owner = "matrix-synapse"; }; - mautrixtelegram_api_hash = { owner = "matrix-synapse"; }; - }; - templates = { - "matrix_user_register.sh".content = '' - register_new_matrix_user -k ${config.sops.placeholder.matrixsharedsecret} http://localhost:8008 - ''; - matrixshared = { - owner = "matrix-synapse"; - content = '' - registration_shared_secret: ${config.sops.placeholder.matrixsharedsecret} - ''; - }; - mautrixtelegram = { - owner = "matrix-synapse"; - content = '' - MAUTRIX_TELEGRAM_APPSERVICE_AS_TOKEN=${config.sops.placeholder.mautrixtelegram_as} - MAUTRIX_TELEGRAM_APPSERVICE_HS_TOKEN=${config.sops.placeholder.mautrixtelegram_hs} - MAUTRIX_TELEGRAM_TELEGRAM_API_ID=${config.sops.placeholder.mautrixtelegram_api_id} - MAUTRIX_TELEGRAM_TELEGRAM_API_HASH=${config.sops.placeholder.mautrixtelegram_api_hash} - ''; - }; - }; - }; - - services.postgresql = { - enable = true; - initialScript = pkgs.writeText "synapse-init.sql" '' - CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD 'synapse'; - CREATE DATABASE "matrix-synapse" WITH OWNER "matrix-synapse" - TEMPLATE template0 - LC_COLLATE = "C" - LC_CTYPE = "C"; - CREATE ROLE "mautrix-telegram" WITH LOGIN PASSWORD 'telegram'; - CREATE DATABASE "mautrix-telegram" WITH OWNER "mautrix-telegram" - TEMPLATE template0 - LC_COLLATE = "C" - LC_CTYPE = "C"; - CREATE ROLE "mautrix-whatsapp" WITH LOGIN PASSWORD 'whatsapp'; - CREATE DATABASE "mautrix-whatsapp" WITH OWNER "mautrix-whatsapp" - TEMPLATE template0 - LC_COLLATE = "C" - LC_CTYPE = "C"; - CREATE ROLE "mautrix-signal" WITH LOGIN PASSWORD 'signal'; - CREATE DATABASE "mautrix-signal" WITH OWNER "mautrix-signal" - TEMPLATE template0 - LC_COLLATE = "C" - LC_CTYPE = "C"; - ''; - }; - - services.matrix-synapse = { - enable = true; - settings = { - app_service_config_files = [ - "/var/lib/matrix-synapse/telegram-registration.yaml" - "/var/lib/matrix-synapse/whatsapp-registration.yaml" - "/var/lib/matrix-synapse/signal-registration.yaml" - "/var/lib/matrix-synapse/doublepuppet.yaml" - ]; - server_name = matrixDomain; - public_baseurl = "https://${matrixDomain}"; - listeners = [ - { - port = 8008; - bind_addresses = [ - "127.0.0.1" - # "::1" - ]; - type = "http"; - tls = false; - x_forwarded = true; - resources = [ - { - names = [ "client" "federation" ]; - compress = true; - } - ]; - } - ]; - }; - extraConfigFiles = [ - config.sops.templates.matrixshared.path - ]; - }; - - services.mautrix-telegram = { - enable = true; - environmentFile = config.sops.templates.mautrixtelegram.path; - settings = { - homeserver = { - address = "http://localhost:8008"; - domain = matrixDomain; - }; - appservice = { - address = "http://localhost:29317"; - hostname = "localhost"; - port = "29317"; - provisioning.enabled = true; - id = "telegram"; - # ephemeral_events = true; # not needed due to double puppeting - public = { - enabled = false; - }; - database = "postgresql:///mautrix-telegram?host=/run/postgresql"; - }; - bridge = { - relaybot.authless_portals = true; - allow_avatar_remove = true; - allow_contact_info = true; - sync_channel_members = true; - startup_sync = true; - sync_create_limit = 0; - sync_direct_chats = true; - telegram_link_preview = true; - permissions = { - "*" = "relaybot"; - "@swarsel:${matrixDomain}" = "admin"; - }; - animated_sticker = { - target = "gif"; - args = { - width = 256; - height = 256; - fps = 30; # only for webm - background = "020202"; # only for gif, transparency not supported - }; - }; - }; - }; - }; - systemd.services.mautrix-telegram.path = with pkgs; [ - lottieconverter # for animated stickers conversion, unfree package - ffmpeg # if converting animated stickers to webm (very slow!) - ]; - - services.mautrix-whatsapp = { - enable = true; - registerToSynapse = false; - settings = { - homeserver = { - address = "http://localhost:8008"; - domain = matrixDomain; - }; - appservice = { - address = "http://localhost:29318"; - hostname = "127.0.0.1"; - port = 29318; - database = { - type = "postgres"; - uri = "postgresql:///mautrix-whatsapp?host=/run/postgresql"; - }; - }; - bridge = { - displayname_template = "{{or .FullName .PushName .JID}} (WA)"; - history_sync = { - backfill = true; - max_initial_conversations = -1; - message_count = -1; - request_full_sync = true; - full_sync_config = { - days_limit = 900; - size_mb_limit = 5000; - storage_quota_mb = 5000; - }; - }; - login_shared_secret_map = { - matrixDomain = "as_token:doublepuppet"; - }; - sync_manual_marked_unread = true; - send_presence_on_typing = true; - parallel_member_sync = true; - url_previews = true; - caption_in_message = true; - extev_polls = true; - permissions = { - "*" = "relay"; - "@swarsel:${matrixDomain}" = "admin"; - }; - }; - }; - }; - - services.mautrix-signal = { - enable = true; - registerToSynapse = false; - settings = { - homeserver = { - address = "http://localhost:8008"; - domain = matrixDomain; - }; - appservice = { - - address = "http://localhost:29328"; - hostname = "127.0.0.1"; - port = 29328; - database = { - type = "postgres"; - uri = "postgresql:///mautrix-signal?host=/run/postgresql"; - }; - }; - bridge = { - displayname_template = "{{or .ContactName .ProfileName .PhoneNumber}} (Signal)"; - login_shared_secret_map = { - matrixDomain = "as_token:doublepuppet"; - }; - caption_in_message = true; - permissions = { - "*" = "relay"; - "@swarsel:${matrixDomain}" = "admin"; - }; - }; - }; - }; - - # restart the bridges daily. this is done for the signal bridge mainly which stops carrying - # messages out after a while. - - systemd.timers."restart-bridges" = { - wantedBy = [ "timers.target" ]; - timerConfig = { - OnBootSec = "1d"; - OnUnitActiveSec = "1d"; - Unit = "restart-bridges.service"; - }; - }; - - systemd.services."restart-bridges" = { - script = '' - systemctl restart mautrix-whatsapp.service - systemctl restart mautrix-signal.service - systemctl restart mautrix-telegram.service - ''; - serviceConfig = { - Type = "oneshot"; - User = "root"; - }; - }; - - services.nginx = { - virtualHosts = { - "swatrix.swarsel.win" = { - enableACME = true; - forceSSL = true; - acmeRoot = null; - listen = [ - { - addr = "0.0.0.0"; - port = 8448; - ssl = true; - extraParameters = [ - "default_server" - ]; - } - { - addr = "[::0]"; - port = 8448; - ssl = true; - extraParameters = [ - "default_server" - ]; - } - { - addr = "0.0.0.0"; - port = 443; - ssl = true; - } - { - addr = "[::0]"; - port = 443; - ssl = true; - } - ]; - locations = { - "~ ^(/_matrix|/_synapse/client)" = { - # proxyPass = "http://localhost:8008"; - proxyPass = "http://localhost:8008"; - extraConfig = '' - client_max_body_size 0; - ''; - }; - "= /.well-known/matrix/server".extraConfig = mkWellKnown serverConfig; - "= /.well-known/matrix/client".extraConfig = mkWellKnown clientConfig; - }; - }; - }; - }; - }; - - - } - -#+end_src - -**** nextcloud -:PROPERTIES: -:CUSTOM_ID: h:d11ad8d5-25d7-4691-b319-61c16ccef715 -:END: - -#+begin_src nix :tangle profiles/server/nixos/nextcloud.nix - { pkgs, lib, config, ... }: - { - config = lib.mkIf config.swarselsystems.server.nextcloud { - - sops.secrets.nextcloudadminpass = { - owner = "nextcloud"; - group = "nextcloud"; - mode = "0440"; - }; - - services.nextcloud = { - enable = true; - package = pkgs.nextcloud30; - hostName = "stash.swarsel.win"; - home = "/Vault/apps/nextcloud"; - datadir = "/Vault/data/nextcloud"; - https = true; - configureRedis = true; - maxUploadSize = "4G"; - extraApps = { - inherit (pkgs.nextcloud30Packages.apps) mail calendar contacts cospend phonetrack polls tasks; - }; - config = { - adminuser = "admin"; - adminpassFile = config.sops.secrets.nextcloudadminpass.path; - }; - }; - - - services.nginx = { - virtualHosts = { - "stash.swarsel.win" = { - enableACME = true; - forceSSL = true; - acmeRoot = null; - # config is automatically added by nixos nextcloud config. - # hence, only provide certificate - }; - }; - }; - }; - - } -#+end_src - -**** immich -:PROPERTIES: -:CUSTOM_ID: h:33bad8ad-b362-4bf1-8a49-b9df92329aed -:END: - -#+begin_src nix :tangle profiles/server/nixos/immich.nix - { lib, config, ... }: - { - config = lib.mkIf config.swarselsystems.server.immich { - - users.users.immich = { - extraGroups = [ "video" "render" "users" ]; - }; - - # sops.secrets.nextcloudadminpass = { owner = "nextcloud"; }; - - services.immich = { - enable = true; - port = 3001; - openFirewall = true; - mediaLocation = "/Vault/Eternor/Immich"; - environment.IMMICH_MACHINE_LEARNING_URL = lib.mkForce "http://localhost:3003"; - }; - - - services.nginx = { - virtualHosts = { - "shots.swarsel.win" = { - enableACME = true; - forceSSL = true; - acmeRoot = null; - locations = { - "/" = { - proxyPass = "http://localhost:3001"; - extraConfig = '' - client_max_body_size 0; - - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - proxy_redirect off; - - proxy_read_timeout 600s; - proxy_send_timeout 600s; - send_timeout 600s; - ''; - }; - }; - }; - }; - }; - - }; - - } -#+end_src - -**** paperless -:PROPERTIES: -:CUSTOM_ID: h:89638fb5-0593-4420-9567-f85f0223e341 -:END: - -#+begin_src nix :tangle profiles/server/nixos/paperless.nix - { lib, config, ... }: - { - config = lib.mkIf config.swarselsystems.server.paperless { - - users.users.paperless = { - extraGroups = [ "users" ]; - }; - - - sops.secrets.paperless_admin = { owner = "paperless"; }; - - services.paperless = { - enable = true; - mediaDir = "/Vault/Eternor/Paperless"; - dataDir = "/Vault/data/paperless"; - user = "paperless"; - port = 28981; - passwordFile = config.sops.secrets.paperless_admin.path; - address = "127.0.0.1"; - settings = { - PAPERLESS_OCR_LANGUAGE = "deu+eng"; - PAPERLESS_URL = "https://scan.swarsel.win"; - PAPERLESS_OCR_USER_ARGS = builtins.toJSON { - optimize = 1; - invalidate_digital_signatures = true; - pdfa_image_compression = "lossless"; - }; - }; - }; - - services.nginx = { - virtualHosts = { - "scan.swarsel.win" = { - enableACME = true; - forceSSL = true; - acmeRoot = null; - locations = { - "/" = { - proxyPass = "http://localhost:28981"; - extraConfig = '' - client_max_body_size 0; - ''; - }; - }; - }; - }; - }; - }; - - } -#+end_src - -**** transmission -:PROPERTIES: -:CUSTOM_ID: h:5afeb311-ab86-4029-be53-2160f6d836c3 -:END: - -#+begin_src nix :tangle profiles/server/nixos/transmission.nix - { pkgs, lib, config, ... }: - { - config = lib.mkIf config.swarselsystems.server.transmission { - - # this user/group section is probably unneeded - users = { - groups = { - dockeruser = { - gid = 1155; - }; - radarr = { }; - readarr = { }; - sonarr = { }; - lidarr = { }; - prowlarr = { }; - }; - users = { - dockeruser = { - isSystemUser = true; - uid = 1155; - group = "docker"; - extraGroups = [ "users" ]; - }; - radarr = { - isSystemUser = true; - group = "radarr"; - extraGroups = [ "users" ]; - }; - readarr = { - isSystemUser = true; - group = "readarr"; - extraGroups = [ "users" ]; - }; - sonarr = { - isSystemUser = true; - group = "sonarr"; - extraGroups = [ "users" ]; - }; - lidarr = { - isSystemUser = true; - group = "lidarr"; - extraGroups = [ "users" ]; - }; - prowlarr = { - isSystemUser = true; - group = "prowlarr"; - extraGroups = [ "users" ]; - }; - }; - }; - - virtualisation.docker.enable = true; - environment.systemPackages = with pkgs; [ - docker - ]; - - services = { - radarr = { - enable = true; - openFirewall = true; - dataDir = "/Vault/apps/radarr"; - }; - readarr = { - enable = true; - openFirewall = true; - dataDir = "/Vault/apps/readarr"; - }; - sonarr = { - enable = true; - openFirewall = true; - dataDir = "/Vault/apps/sonarr"; - }; - lidarr = { - enable = true; - openFirewall = true; - dataDir = "/Vault/apps/lidarr"; - }; - prowlarr = { - enable = true; - openFirewall = true; - }; - - nginx = { - virtualHosts = { - "store.swarsel.win" = { - enableACME = false; - forceSSL = false; - acmeRoot = null; - locations = { - "/" = { - proxyPass = "http://localhost:9091"; - extraConfig = '' - client_max_body_size 0; - ''; - }; - "/radarr" = { - proxyPass = "http://localhost:7878"; - extraConfig = '' - client_max_body_size 0; - ''; - }; - "/readarr" = { - proxyPass = "http://localhost:8787"; - extraConfig = '' - client_max_body_size 0; - ''; - }; - "/sonarr" = { - proxyPass = "http://localhost:8989"; - extraConfig = '' - client_max_body_size 0; - ''; - }; - "/lidarr" = { - proxyPass = "http://localhost:8686"; - extraConfig = '' - client_max_body_size 0; - ''; - }; - "/prowlarr" = { - proxyPass = "http://localhost:9696"; - extraConfig = '' - client_max_body_size 0; - ''; - }; - }; - }; - }; - }; - }; - }; - } - -#+end_src - -**** syncthing -:PROPERTIES: -:CUSTOM_ID: h:ad2787a2-7b1c-4326-aeff-9d8d6c3f591d -:END: - -#+begin_src nix :tangle profiles/server/nixos/syncthing.nix - { lib, config, ... }: - { - config = lib.mkIf config.swarselsystems.server.syncthing { - - users.users.syncthing = { - extraGroups = [ "users" ]; - group = "syncthing"; - isSystemUser = true; - }; - - users.groups.syncthing = {}; - - services.syncthing = { - enable = true; - user = "swarsel"; - dataDir = "/Vault/data/syncthing"; - configDir = "/Vault/apps/syncthing"; - guiAddress = "0.0.0.0:8384"; - openDefaultPorts = true; - relay.enable = false; - settings = { - urAccepted = -1; - devices = { - "magicant" = { - id = "VMWGEE2-4HDS2QO-KNQOVGN-LXLX6LA-666E4EK-ZBRYRRO-XFEX6FB-6E3XLQO"; - }; - "sync (@oracle)" = { - id = "ETW6TST-NPK7MKZ-M4LXMHA-QUPQHDT-VTSHH5X-CR5EIN2-YU7E55F-MGT7DQB"; - }; - "nbl-imba-2" = { - id = "YAPV4BV-I26WPTN-SIP32MV-SQP5TBZ-3CHMTCI-Z3D6EP2-MNDQGLP-53FT3AB"; - }; - }; - folders = { - "Default Folder" = { - path = "/Vault/data/syncthing/Sync"; - type = "receiveonly"; - versioning = null; - devices = [ "sync (@oracle)" "magicant" "nbl-imba-2" ]; - id = "default"; - }; - "Obsidian" = { - path = "/Vault/data/syncthing/Obsidian"; - type = "receiveonly"; - versioning = { - type = "simple"; - params.keep = "5"; - }; - devices = [ "sync (@oracle)" "magicant" "nbl-imba-2" ]; - id = "yjvni-9eaa7"; - }; - "Org" = { - path = "/Vault/data/syncthing/Org"; - type = "receiveonly"; - versioning = { - type = "simple"; - params.keep = "5"; - }; - devices = [ "sync (@oracle)" "magicant" "nbl-imba-2" ]; - id = "a7xnl-zjj3d"; - }; - "Vpn" = { - path = "/Vault/data/syncthing/Vpn"; - type = "receiveonly"; - versioning = { - type = "simple"; - params.keep = "5"; - }; - devices = [ "sync (@oracle)" "magicant" "nbl-imba-2" ]; - id = "hgp9s-fyq3p"; - }; - "Documents" = { - path = "/Vault/data/syncthing/Documents"; - type = "receiveonly"; - versioning = { - type = "simple"; - params.keep = "5"; - }; - devices = [ "magicant" "nbl-imba-2" ]; - id = "hgr3d-pfu3w"; - }; - # ".elfeed" = { - # path = "/Vault/data/syncthing/.elfeed"; - # devices = [ "sync (@oracle)" "magicant" "nbl-imba-2" ]; - # id = "h7xbs-fs9v1"; - # }; - }; - }; - }; - - services.nginx = { - virtualHosts = { - "storync.swarsel.win" = { - enableACME = true; - forceSSL = true; - acmeRoot = null; - locations = { - "/" = { - proxyPass = "http://localhost:8384"; - extraConfig = '' - client_max_body_size 0; - ''; - }; - }; - }; - }; - }; - }; - - } -#+end_src - -**** restic -:PROPERTIES: -:CUSTOM_ID: h:b73ac8bf-b721-4563-9eff-973925c99a39 -:END: - -Once this is finished, it will house a restic client that manages automatic backups of my image library. Before I get to this however, I first need to organice my pictures in the first place. - -#+begin_src nix :tangle profiles/server/nixos/restic.nix - { lib, config, ... }: - { - config = lib.mkIf config.swarselsystems.server.restic { - - # TODO - - }; - } -#+end_src - -**** monitoring -:PROPERTIES: -:CUSTOM_ID: h:a31c7192-e11d-4a26-915d-1bbc38e373d3 -:END: - -This section exposes several metrics that I use to check the health of my server. I need to expand on the exporters section at some point, but for now I have everything I need. - -#+begin_src nix :tangle profiles/server/nixos/monitoring.nix - { self, lib, config, ... }: - { - config = lib.mkIf config.swarselsystems.server.monitoring { - - sops.secrets = { - grafanaadminpass = { - owner = "grafana"; - }; - prometheusadminpass = { - owner = "grafana"; - }; - }; - - users.users.nextcloud-exporter = { - extraGroups = [ "nextcloud" ]; - }; - - users.users.grafana = { - extraGroups = [ "users" ]; - }; - - services.grafana = { - enable = true; - dataDir = "/Vault/data/grafana"; - provision = { - enable = true; - datasources.settings = { - datasources = [ - { - name = "prometheus"; - type = "prometheus"; - url = "https://status.swarsel.win/prometheus"; - editable = false; - access = "proxy"; - basicAuth = true; - basicAuthUser = "admin"; - jsonData = { - httpMethod = "POST"; - manageAlerts = true; - prometheusType = "Prometheus"; - prometheusVersion = "> 2.50.x"; - cacheLevel = "High"; - disableRecordingRules = false; - incrementalQueryOverlapWindow = "10m"; - }; - secureJsonData = { - basicAuthPassword = "$__file{/run/secrets/prometheusadminpass}"; - }; - } - ]; - }; - }; - - settings = { - security.admin_password = "$__file{/run/secrets/grafanaadminpass}"; - server = { - http_port = 3000; - http_addr = "127.0.0.1"; - protocol = "http"; - domain = "status.swarsel.win"; - }; - }; - }; - - services.prometheus = { - enable = true; - webExternalUrl = "https://status.swarsel.win/prometheus"; - port = 9090; - listenAddress = "127.0.0.1"; - globalConfig = { - scrape_interval = "10s"; - }; - webConfigFile = self + /programs/server/prometheus/web.config; - scrapeConfigs = [ - { - job_name = "node"; - static_configs = [{ - targets = [ "localhost:${toString config.services.prometheus.exporters.node.port}" ]; - }]; - } - { - job_name = "zfs"; - static_configs = [{ - targets = [ "localhost:${toString config.services.prometheus.exporters.zfs.port}" ]; - }]; - } - { - job_name = "nginx"; - static_configs = [{ - targets = [ "localhost:${toString config.services.prometheus.exporters.nginx.port}" ]; - }]; - } - { - job_name = "nextcloud"; - static_configs = [{ - targets = [ "localhost:${toString config.services.prometheus.exporters.nextcloud.port}" ]; - }]; - } - ]; - exporters = { - node = { - enable = true; - port = 9000; - enabledCollectors = [ "systemd" ]; - extraFlags = [ "--collector.ethtool" "--collector.softirqs" "--collector.tcpstat" "--collector.wifi" ]; - }; - zfs = { - enable = true; - port = 9134; - pools = [ - "Vault" - ]; - }; - restic = { - enable = false; - port = 9753; - }; - nginx = { - enable = true; - port = 9113; - sslVerify = false; - scrapeUri = "http://localhost/nginx_status"; - }; - nextcloud = lib.mkIf config.swarselsystems.server.nextcloud { - enable = true; - port = 9205; - url = "https://stash.swarsel.win/ocs/v2.php/apps/serverinfo/api/v1/info"; - username = "admin"; - passwordFile = config.sops.secrets.nextcloudadminpass.path; - }; - }; - }; - - - services.nginx = { - virtualHosts = { - "status.swarsel.win" = { - enableACME = true; - forceSSL = true; - acmeRoot = null; - locations = { - "/" = { - proxyPass = "http://localhost:3000"; - extraConfig = '' - client_max_body_size 0; - ''; - }; - "/prometheus" = { - proxyPass = "http://localhost:9090"; - extraConfig = '' - client_max_body_size 0; - ''; - }; - }; - }; - }; - }; - }; - - } -#+end_src - -**** Jenkins -:PROPERTIES: -:CUSTOM_ID: h:23452a18-a0a1-4515-8612-ceb19bb5fc22 -:END: - -This is a WIP Jenkins instance. It is used to automatically build a new system when pushes to the main repository are detected. I have turned this service off for now however, as I actually prefer to start my builds manually. - -#+begin_src nix :tangle profiles/server/nixos/jenkins.nix - { pkgs, lib, config, ... }: - { - config = lib.mkIf config.swarselsystems.server.jenkins { - - services.jenkins = { - enable = true; - withCLI = true; - port = 8088; - packages = [ pkgs.stdenv pkgs.git pkgs.jdk17 config.programs.ssh.package pkgs.nix ]; - listenAddress = "127.0.0.1"; - home = "/Vault/apps/jenkins"; - }; - - - - services.nginx = { - virtualHosts = { - "servant.swarsel.win" = { - enableACME = true; - forceSSL = true; - acmeRoot = null; - locations = { - "/" = { - proxyPass = "http://localhost:8088"; - extraConfig = '' - client_max_body_size 0; - ''; - }; - }; - }; - }; - }; - }; - - } -#+end_src - -**** Emacs elfeed (RSS Server) -:PROPERTIES: -:CUSTOM_ID: h:4e6824bc-c3db-485d-b543-4072e6283b62 -:END: - -This was an approach of hosting an RSS server from within emacs. That would have been useful as it would have allowed me to allow my feeds from any device. However, it proved impossible to do bidirectional syncing, so I abandoned this configuration in favor of [[#h:9da3df74-6fc5-4ee1-a345-23ab4e8a613d][FreshRSS]]. - -#+begin_src nix :tangle profiles/server/nixos/emacs.nix - { lib, config, ... }: - { - config = lib.mkIf config.swarselsystems.server.emacs { - - networking.firewall.allowedTCPPorts = [ 9812 ]; - - services.emacs = { - enable = true; - install = true; - startWithGraphical = false; - }; - - }; - - } -#+end_src - -**** FreshRSS -:PROPERTIES: -:CUSTOM_ID: h:9da3df74-6fc5-4ee1-a345-23ab4e8a613d -:END: - -FreshRSS is a more 'classical' RSS aggregator that I can just host as a distinct service. This also has its upsides because I jave more control over the state this way. - -It serves both a Greader API at https://signpost.swarsel.win/api/greader.php, as well as a Fever API at https://signpost.swarsel.win/api/fever.php. - -#+begin_src nix :tangle profiles/server/nixos/freshrss.nix - { lib, config, ... }: - { - config = lib.mkIf config.swarselsystems.server.freshrss { - - users.users.freshrss = { - extraGroups = [ "users" ]; - group = "freshrss"; - isSystemUser = true; - }; - - users.groups.freshrss = {}; - - sops.secrets.fresh = { owner = "freshrss"; }; - - services.freshrss = { - enable = true; - virtualHost = "signpost.swarsel.win"; - baseUrl = "https://signpost.swarsel.win"; - # authType = "none"; - dataDir = "/Vault/data/tt-rss"; - defaultUser = "Swarsel"; - passwordFile = config.sops.secrets.fresh.path; - }; - - services.nginx = { - virtualHosts = { - "signpost.swarsel.win" = { - enableACME = true; - forceSSL = true; - acmeRoot = null; - }; - }; - }; - }; - - } -#+end_src - -**** forgejo (git server) -:PROPERTIES: -:CUSTOM_ID: h:a9965660-4358-4b9a-8c46-d55f28598344 -:END: - -#+begin_src nix :tangle profiles/server/nixos/forgejo.nix - { lib, config, ... }: - { - config = lib.mkIf config.swarselsystems.server.forgejo { - - networking.firewall.allowedTCPPorts = [ 3000 ]; - - services.forgejo = { - enable = true; - settings = { - DEFAULT = { - APP_NAME = "~SwaGit~"; - }; - server = { - PROTOCOL = "http"; - HTTP_PORT = 3000; - HTTP_ADDR = "0.0.0.0"; - DOMAIN = "swagit.swarsel.win"; - ROOT_URL = "https://swagit.swarsel.win"; - }; - service = { - DISABLE_REGISTRATION = true; - SHOW_REGISTRATION_BUTTON = false; - }; - }; - }; - - services.nginx = { - virtualHosts = { - "swagit.swarsel.win" = { - enableACME = true; - forceSSL = true; - acmeRoot = null; - locations = { - "/" = { - proxyPass = "http://localhost:3000"; - extraConfig = '' - client_max_body_size 0; - ''; - }; - }; - }; - }; - }; - }; - - } -#+end_src - -**** Anki Sync Server -:PROPERTIES: -:CUSTOM_ID: h:cb3f6552-7751-4f9a-b4c7-8d8ba5b255c4 -:END: - -#+begin_src nix :tangle profiles/server/nixos/ankisync.nix -{ lib, config, ... }: -{ - config = lib.mkIf config.swarselsystems.server.ankisync { - - networking.firewall.allowedTCPPorts = [ 22701 ]; - - sops.secrets.swarsel = { owner = "root"; }; - - services.anki-sync-server = { - enable = true; - port = 27701; - address = "0.0.0.0"; - openFirewall = true; - users = [ - { - username = "Swarsel"; - passwordFile = config.sops.secrets.swarsel.path; - } - ]; - }; - - services.nginx = { - virtualHosts = { - "synki.swarsel.win" = { - enableACME = true; - forceSSL = true; - acmeRoot = null; - locations = { - "/" = { - proxyPass = "http://localhost:27701"; - extraConfig = '' - client_max_body_size 0; - ''; - }; - }; - }; - }; - }; - }; - -} -#+end_src - -*** Darwin -:PROPERTIES: -:CUSTOM_ID: h:ac0cd8b3-06cf-4dca-ba73-6100c8fedb47 -:END: -**** Imports -:PROPERTIES: -:CUSTOM_ID: h:25a95a30-8e4f-4fe3-9b8e-508a82e0a1b4 -:END: - -This section sets up all the imports that are used in the home-manager section. - -#+begin_src nix :tangle profiles/darwin/nixos/default.nix - { self, ... }: - let - profilesPath = "${self}/profiles"; - in - { - imports = [ - "${profilesPath}/nixos/home-manager.nix" - ]; - - nix.settings.experimental-features = "nix-command flakes"; - nixpkgs = { - hostPlatform = "x86_64-darwin"; - overlays = [ outputs.overlays.default ]; - config = { - allowUnfree = true; - }; - }; - - system.stateVersion = 4; - } -#+end_src - -*** Optional -:PROPERTIES: -:CUSTOM_ID: h:f9aa9af0-9b8d-43ff-901d-9ffccdd70589 -:END: - -These sets of configuration do not need to be deployed on every host, for a multitude of reasons. - -- The gaming set is not needed on weak machines, and also not on my work machine. -- The VirtualBox package takes forever to build, and I do not need virtual machines on every host. -- There are some hosts that I do not want to autologin to. -- =nswitch-rcm= is a tool I wrote for easy payload flashing of a Nintendo Switch in RCM mode. However, that is not needed on every machine. -- The work profile is only used on my work laptop. - -**** gaming -:PROPERTIES: -:CUSTOM_ID: h:fb3f3e01-7df4-4b06-9e91-aa9cac61a431 -:END: - -This opens a few gaming ports and installs the steam configuration suite for gaming. There are more options in [[#h:84fd7029-ecb6-4131-9333-289982f24ffa][Gaming]] (home-manager side). - -#+begin_src nix :tangle profiles/optional/nixos/gaming.nix -{ pkgs, ... }: -{ - specialisation = { - gaming.configuration = { - networking = { - firewall = { - allowedUDPPorts = [ 4380 27036 14242 34197 ]; # 34197: factorio; 4380 27036 14242: barotrauma; - allowedTCPPorts = [ ]; # 34197: factorio; 4380 27036 14242: barotrauma; 51820: wireguard - allowedTCPPortRanges = [ - { from = 27015; to = 27030; } # barotrauma - { from = 27036; to = 27037; } # barotrauma - ]; - allowedUDPPortRanges = [ - { from = 27000; to = 27031; } # barotrauma - { from = 58962; to = 58964; } # barotrauma - ]; - }; - }; - - programs.steam = { - enable = true; - extraCompatPackages = [ - pkgs.proton-ge-bin - ]; - }; - - hardware.xone.enable = true; - - environment.systemPackages = [ - pkgs.linuxKernel.packages.linux_6_12.xone - ]; - }; - }; - -} - - -#+end_src - -**** VirtualBox -:PROPERTIES: -:CUSTOM_ID: h:b3523246-14e9-4284-ba22-cebc5ca36732 -:END: - -This sets the VirtualBox configuration. Guest should not be enabled if not direly needed, it will make rebuilds unbearably slow. I only use this privately to run an old editor that does not run well under wine, so I put it into it's own specialisation. - -#+begin_src nix :tangle profiles/optional/nixos/virtualbox.nix - { lib, pkgs, ... }: - { - - specialisation = { - VBox.configuration = { - virtualisation.virtualbox = { - host = { - enable = true; - enableExtensionPack = true; - }; - # leaving this here for future notice. setting guest.enable = true will make 'restarting sysinit-reactivation.target' take till timeout on nixos-rebuild switch - guest = { - enable = false; - }; - }; - # run an older kernel to provide compatibility with windows vm - boot.kernelPackages = lib.mkForce pkgs.linuxPackages; - }; - }; - - } -#+end_src - -**** VmWare -:PROPERTIES: -:CUSTOM_ID: h:34db28fb-62f7-4597-a9ff-0de2991a8415 -:END: - - -This sets the VirtualBox configuration. Guest should not be enabled if not direly needed, it will make rebuilds unbearably slow. - -#+begin_src nix :tangle profiles/optional/nixos/vmware.nix - _: - { - - virtualisation.vmware.host.enable = true; - virtualisation.vmware.guest.enable = true; - } -#+end_src - -**** Auto-login -:PROPERTIES: -:CUSTOM_ID: h:fa8d9ec4-3e22-458a-9239-859cffe7f55c -:END: - -Auto login for the initial session. - -#+begin_src nix :tangle profiles/optional/nixos/autologin.nix - _: - { - services = { - getty.autologinUser = "swarsel"; - greetd.settings.initial_session.user = "swarsel"; - }; - } -#+end_src - -**** nswitch-rcm -:PROPERTIES: -:CUSTOM_ID: h:5c41c4ee-22ca-405b-9e4f-cc4051634edd -:END: - -This smashes Atmosphere 1.3.2 on the switch, which is what I am currenty using. - -#+begin_src nix :tangle profiles/optional/nixos/nswitch-rcm.nix - { pkgs, ... }: - { - services.nswitch-rcm = { - enable = true; - package = pkgs.fetchurl { - url = "https://github.com/Atmosphere-NX/Atmosphere/releases/download/1.3.2/fusee.bin"; - hash = "sha256-5AXzNsny45SPLIrvWJA9/JlOCal5l6Y++Cm+RtlJppI="; - }; - }; - } -#+end_src - -**** work -:PROPERTIES: -:CUSTOM_ID: h:bbf2ecb6-c8ff-4462-b5d5-d45b28604ddf -:END: - -Options that I need specifically at work. There are more options at [[#h:f0b2ea93-94c8-48d8-8d47-6fe58f58e0e6][Work]] (home-manager side). - -#+begin_src nix :tangle profiles/optional/nixos/work.nix - { self, pkgs, config, ... }: - let - owner = "swarsel"; - sopsFile = self + /secrets/work/secrets.yaml; - in - { - sops = { - secrets = { - clad = { - inherit owner sopsFile; - }; - dcad = { - inherit owner sopsFile; - }; - wsad = { - inherit owner sopsFile; - }; - imbad = { - inherit owner sopsFile; - }; - }; - }; - - # boot.initrd.luks.yubikeySupport = true; - programs = { - zsh.shellInit = '' - export CLAD="$(cat ${config.sops.secrets.clad.path})" - export DCAD="$(cat ${config.sops.secrets.dcad.path})" - export GOVC_PASSWORD="$(cat ${config.sops.secrets.dcad.path})" - export WSAD="$(cat ${config.sops.secrets.wsad.path})" - export IMBAD="$(cat ${config.sops.secrets.imbad.path})" - export DCUSER="dc_adm_schwarzaeugl@IMP.UNIVIE.AC.AT" - export GOVC_USERNAME="dc_adm_schwarzaeugl@IMP.UNIVIE.AC.AT" - export PACKER_SSH_EXTRA_ARGS='"--scp-extra-args","'-O'"' - ''; - - browserpass.enable = true; - _1password.enable = true; - _1password-gui = { - enable = true; - polkitPolicyOwners = [ "swarsel" ]; - }; - }; - - networking.firewall.trustedInterfaces = [ "virbr0" ]; - - virtualisation = { - docker.enable = true; - spiceUSBRedirection.enable = true; - libvirtd = { - enable = true; - qemu = { - package = pkgs.qemu_kvm; - runAsRoot = true; - swtpm.enable = true; - vhostUserPackages = with pkgs; [ virtiofsd ]; - ovmf = { - enable = true; - packages = [(pkgs.OVMFFull.override { - secureBoot = true; - tpmSupport = true; - }).fd]; - }; - }; - }; - }; - - environment.systemPackages = with pkgs; [ - # (python39.withPackages (ps: with ps; [ - # cryptography - # ])) - # docker - python39 - qemu - packer - gnumake - libisoburn - govc - terraform - - # vm - virt-manager - virt-viewer - virtiofsd - spice - spice-gtk - spice-protocol - win-virtio - win-spice - ]; - - - services = { - spice-vdagentd.enable = true; - openssh = { - enable = true; - extraConfig = '' - ''; - }; - - syncthing = { - settings = { - "winters" = { - id = "O7RWDMD-AEAHPP7-7TAVLKZ-BSWNBTU-2VA44MS-EYGUNBB-SLHKB3C-ZSLMOAA"; - }; - folders = { - "Documents" = { - path = "/home/swarsel/Documents"; - devices = [ "magicant" "winters" ]; - id = "hgr3d-pfu3w"; - }; - }; - }; - }; - }; - - # cgroups v1 is required for centos7 dockers - specialisation = { - cgroup_v1.configuration = { - boot.kernelParams = [ - "SYSTEMD_CGROUP_ENABLE_LEGACY_FORCE=1" - "systemd.unified_cgroup_hierarchy=0" - ]; - }; - }; - - } -#+end_src - -**** Minimal Install -:PROPERTIES: -:CUSTOM_ID: h:3fc1d301-7bae-4678-9085-d12c23eed8ac -:END: - - These options are really only to be used on the iso image in order to run nixos-anywhere. - -#+begin_src nix :tangle profiles/iso/minimal.nix - { lib, pkgs, ... }: - { - - nix.settings = { - experimental-features = [ "nix-command" "flakes" ]; - warn-dirty = false; - }; - - boot = { - # initrd.systemd.enable = true; - kernelPackages = pkgs.linuxPackages_latest; - supportedFilesystems = lib.mkForce [ "brtfs" "vfat" ]; - loader = { - efi.canTouchEfiVariables = true; - systemd-boot = { - enable = true; - configurationLimit = lib.mkDefault 5; - consoleMode = lib.mkDefault "max"; - }; - }; - }; - - services = { - qemuGuest.enable = true; - openssh = { - enable = true; - ports = lib.mkDefault [ 22 ]; - settings.PermitRootLogin = "yes"; - authorizedKeysFiles = lib.mkForce [ - "/etc/ssh/authorized_keys.d/%u" - ]; - }; - }; - - security.sudo.extraConfig = '' - Defaults env_keep+=SSH_AUTH_SOCK - Defaults lecture = never - ''; - - security.pam = { - sshAgentAuth.enable = true; - services = { - sudo.u2fAuth = true; - }; - }; - - environment.systemPackages = with pkgs; [ - curl - git - gnupg - rsync - ssh-to-age - sops - vim - just - ]; - - programs = { - git.enable = true; - }; - - fileSystems."/boot".options = [ "umask=0077" ]; - - networking.networkmanager.enable = true; - - - } -#+end_src - -** Home-manager -:PROPERTIES: -:CUSTOM_ID: h:08ded95b-9c43-475d-a0b2-fc088a512287 -:END: - -The general structure is the same as in the [[#h:6da812f5-358c-49cb-aff2-0a94f20d70b3][NixOS]] section. - -*** Common -:PROPERTIES: -:CUSTOM_ID: h:f0a6b5e0-2157-4522-b5e1-3f0abd91c05e -:END: -**** Imports -:PROPERTIES: -:CUSTOM_ID: h:16fd2e85-fdd4-440a-81f0-65b9b098a43a -:END: - -This section sets up all the imports that are used in the home-manager section. - -#+begin_src nix :tangle profiles/common/home/default.nix - _: - { - imports = [ - ./settings.nix - ./packages.nix - ./custom-packages.nix - ./sops.nix - ./ssh.nix - ./stylix.nix - ./desktop.nix - ./symlink.nix - ./env.nix - ./programs.nix - ./nix-index.nix - ./password-store.nix - ./direnv.nix - ./eza.nix - ./git.nix - ./fuzzel.nix - ./starship.nix - ./kitty.nix - ./zsh.nix - ./mail.nix - ./emacs.nix - ./waybar.nix - ./firefox.nix - ./gnome-keyring.nix - ./kdeconnect.nix - ./mako.nix - ./sway.nix - ./gpg-agent.nix - ./gammastep.nix - # ./safeeyes.nix - ./yubikey-touch-detector.nix - ./zellij.nix - ./tmux.nix - ]; - } -#+end_src - -**** General home-manager-settings -:PROPERTIES: -:CUSTOM_ID: h:4af4f67f-7c48-4754-b4bd-6800e3a66664 -:END: - - Again, we adapt =nix= to our needs, enable the home-manager command for non-NixOS machines (NixOS machines are using it as a module) and setting user information that I always keep the same. - -#+begin_src nix :tangle profiles/common/home/settings.nix - { lib, config, pkgs, ... }: - { - nix = { - package = lib.mkDefault pkgs.nix; - settings = { - experimental-features = [ - "nix-command" - "flakes" - "ca-derivations" - "pipe-operators" - ]; - }; - }; - - programs.home-manager.enable = lib.mkIf (!config.swarselsystems.isNixos) true; - - home = { - username = lib.mkDefault "swarsel"; - homeDirectory = lib.mkDefault "/home/${config.home.username}"; - stateVersion = lib.mkDefault "23.05"; - keyboard.layout = "us"; - sessionVariables = { - FLAKE = "${config.home.homeDirectory}/.dotfiles"; - }; - }; - } -#+end_src - -**** Installed packages -:PROPERTIES: -:CUSTOM_ID: h:893a7f33-7715-415b-a895-2687ded31c18 -:END: - -Here are defined some packages that I would like to use across all my machines. Most of these should not require further setup. Notably the cura package is severely outdated on nixpkgs, so I just fetch a more recent AppImage and run that instead. - -Also, I define some useful shell scripts here. - -Programming languages and default lsp's are defined here: [[#h:0e7e8bea-ec58-499c-9731-09dddfc39532][System Packages]] - -***** Packaged -:PROPERTIES: -:CUSTOM_ID: h:6ef9bb5f-c5ee-496e-86e2-d8d271a34d75 -:END: - -This holds packages that I can use as provided, or with small modifications (as in the =texlive= package that needs special configuration). - -#+begin_src nix :tangle profiles/common/home/packages.nix - { pkgs, ... }: - - { - home.packages = with pkgs; [ - - # audio stuff - spek # spectrum analyzer - losslessaudiochecker - ffmpeg_7-full - flac - mediainfo - picard-tools - audacity - sox - feishin - - # printing - cups - simple-scan - - # dict - (aspellWithDicts (dicts: with dicts; [ de en en-computers en-science ])) - - # utilities - util-linux - nmap - lsof - nvd - nix-output-monitor - hyprpicker # color picker - findutils - units - vim - - # nix - alejandra - nixpkgs-fmt - deadnix - statix - nix-tree - - # shellscripts - shfmt - - # local file sharing - wormhole-rs - - # b2 backup @backblaze - restic - - # "big" programs - gimp - inkscape - zoom-us - # nomacs - libreoffice-qt - xournalpp - obsidian - spotify - vesktop # discord client - nextcloud-client - spotify-player - element-desktop-wayland - nicotine-plus - stable.transmission - mktorrent - hexchat - hugo - - # kyria - qmk - qmk-udev-rules - - # firefox related - tridactyl-native - - # mako related - mako - libnotify - - # general utilities - unrar - samba - cifs-utils - zbar # qr codes - readline - autotiling - brightnessctl - libappindicator-gtk3 - sqlite - speechd - networkmanagerapplet - psmisc # kill etc - lm_sensors - # jq # used for searching the i3 tree in check.sh files - - # specifically needed for anki - # mpv - anki-bin - - # dirvish file previews - fd - imagemagick - poppler - ffmpegthumbnailer - mediainfo - gnutar - unzip - - #nautilus - nautilus - xfce.tumbler - libgsf - - # wayland stuff - wtype - wl-clipboard - wl-mirror - - # screenshotting tools - grim - slurp - - # the following packages are used (in some way) by waybar - playerctl - pavucontrol - pamixer - # gnome.gnome-clocks - # wlogout - # jdiskreport - # monitor - - #keychain - qalculate-gtk - gcr # needed for gnome-secrets to work - seahorse - - # sops-related - sops - ssh-to-age - - # mail related packages - mu - - # latex and related packages - (texlive.combine { - inherit (pkgs.texlive) scheme-full - dvisvgm dvipng# for preview and export as html - wrapfig amsmath ulem hyperref capt-of; - }) - - # font stuff - nerd-fonts.fira-mono - nerd-fonts.fira-code - nerd-fonts.symbols-only - noto-fonts-emoji - font-awesome_5 - noto-fonts - noto-fonts-cjk-sans - ]; - } -#+end_src - -***** Self-defined -:PROPERTIES: -:CUSTOM_ID: h:96cbea91-ff13-4120-b8a9-496b2fa96e70 -:END: - -This is just a separate container for derivations defined in [[#h:64a5cc16-6b16-4802-b421-c67ccef853e1][Packages]]. This is a good idea so that I do not lose track of package names I have defined myself, as this was once a problem in the past already. - -#+begin_src nix :tangle profiles/common/home/custom-packages.nix - { pkgs, ... }: - - { - home.packages = with pkgs; [ - pass-fuzzel - cura5 - cdw - cdb - bak - timer - e - swarselcheck - waybarupdate - opacitytoggle - fs-diff - update-checker - github-notifications - screenshare - hm-specialisation - t2ts - ts2t - vershell - eontimer - - bootstrap - - (pkgs.writeScriptBin "project" '' - #! ${pkgs.bash}/bin/bash - if [ "$1" == "rust" ]; then - cp ~/.dotfiles/templates/rust_flake.nix ./flake.nix - cp ~/.dotfiles/templates/toolchain.toml . - elif [ "$1" == "cpp" ]; then - cp ~/.dotfiles/templates/cpp_flake.nix ./flake.nix - elif [ "$1" == "python" ]; then - cp ~/.dotfiles/templates/py_flake.nix ./flake.nix - elif [ "$1" == "cuda" ]; then - cp ~/.dotfiles/templates/cu_flake.nix ./flake.nix - elif [ "$1" == "other" ]; then - cp ~/.dotfiles/templates/other_flake.nix ./flake.nix - elif [ "$1" == "latex" ]; then - if [ "$2" == "" ]; then - echo "No filename specified, usage: 'project latex '" - exit 0 - fi - cp ~/.dotfiles/templates/tex_standard.tex ./"$2".tex - exit 0 - else - echo "No valid argument given. Valid arguments are rust cpp python, cuda" - exit 0 - fi - echo "use flake" >> .envrc - direnv allow - '') - - - - - - - ]; - } -#+end_src - -**** sops -:PROPERTIES: -:CUSTOM_ID: h:d87d80fd-2ac7-4f29-b338-0518d06b4deb -:END: - -I use sops-nix to handle secrets that I want to have available on my machines at all times. Procedure to add a new machine: -- `ssh-keygen -t ed25519 -C "NAME sops"` in .ssh directory (or wherever) - name e.g. "sops" -- cat ~/.ssh/sops.pub | ssh-to-age | wl-copy -- add the output to .sops.yaml -- cp ~/.ssh/sops.pub ~/.dotfiles/secrets/keys/NAME.pub -- update entry for sops.age.sshKeyPaths - - Since we are using the home-manager implementation here, we need to specify the runtime path. - -#+begin_src nix :tangle profiles/common/home/sops.nix - { config, lib, ... }: - let - mkIfElse = p: yes: no: lib.mkMerge [ - (lib.mkIf p yes) - (lib.mkIf (!p) no) - ]; - in - { - sops = lib.mkIf (!config.swarselsystems.isPublic) { - age.sshKeyPaths = [ "${config.home.homeDirectory}/.ssh/sops" "${config.home.homeDirectory}/.ssh/ssh_host_ed25519_key" ]; - defaultSopsFile = mkIfElse config.swarselsystems.isBtrfs "/persist/.dotfiles/secrets/general/secrets.yaml" "${config.home.homeDirectory}/.dotfiles/secrets/general/secrets.yaml"; - - validateSopsFiles = false; - secrets = { - mrswarsel = { path = "/run/user/1000/secrets/mrswarsel"; }; - nautilus = { path = "/run/user/1000/secrets/nautilus"; }; - leon = { path = "/run/user/1000/secrets/leon"; }; - swarselmail = { path = "/run/user/1000/secrets/swarselmail"; }; - github_notif = { path = "/run/user/1000/secrets/github_notif"; }; - u2f_keys = { path = "${config.home.homeDirectory}/.config/Yubico/u2f_keys"; }; - }; - }; - } -#+end_src - -**** SSH Machines -:PROPERTIES: -:CUSTOM_ID: h:edd6720e-1f90-40bf-b6f9-30a19d4cae08 -:END: - -It is very convenient to have SSH aliases in place for machines that I use. This is mainly used for some server machines and some university clusters. We also enable agent forwarding to have our Yubikey SSH key accessible on the remote host. - -#+begin_src nix :tangle profiles/common/home/ssh.nix - _: - { - programs.ssh = { - enable = true; - forwardAgent = true; - extraConfig = '' - SetEnv TERM=xterm-256color - ''; - matchBlocks = { - # Local machines - "pfsense" = { - hostname = "192.168.1.1"; - user = "root"; - }; - "winters" = { - hostname = "192.168.1.2"; - user = "swarsel"; - }; - "minecraft" = { - hostname = "130.61.119.129"; - user = "opc"; - }; - "sync" = { - hostname = "193.122.53.173"; - user = "root"; #this is a oracle vm server but needs root due to nixos-infect - }; - "songdiver" = { - hostname = "89.168.100.65"; - user = "ubuntu"; - }; - "pkv" = { - hostname = "46.232.248.161"; - user = "root"; - }; - "efficient" = { - hostname = "g0.complang.tuwien.ac.at"; - user = "ep01427399"; - }; - }; - }; - } -#+end_src - -**** Theme (stylix) -:PROPERTIES: -:CUSTOM_ID: h:a92318cd-413e-4e78-a478-e63b09df019c -:END: - -These section allows home-manager to allow theme settings, and handles some other appearance-related settings like cursor styles. Interestingly, system icons (adwaita) still need to be setup on system-level, and will break if defined here. - -This section has been notably empty ever since switching to stylix. Only Emacs is not allowed to be styled by it, because it becomes more ugly compared to my handcrafted setup. - -=theme= is defined in [[#h:5bc1b0c9-dc59-4c81-b5b5-e60699deda78][Theme (stylix)]]. - -#+begin_src nix :noweb yes :tangle profiles/common/home/stylix.nix - { self, lib, config, pkgs, ... }: - { - stylix = lib.mkIf (!config.swarselsystems.isNixos) { - <> - image = config.swarselsystems.wallpaper; - targets = { - emacs.enable = false; - waybar.enable = false; - }; - }; - } -#+end_src - -**** Desktop Entries, MIME types (xdg) -:PROPERTIES: -:CUSTOM_ID: h:867556e6-5a24-4c43-9d47-3edca2f16488 -:END: - -Some programs lack a dmenu launcher - I define them myself here. - -TODO: Non-NixOS machines (=sp3) should not use these by default, but instead the programs prefixed with "nixGL". I need to figure out how to automate this process, as it is not feasible to write desktop entries for all programs installed on that machine. - -#+begin_src nix :tangle profiles/common/home/desktop.nix - - _: - { - xdg.desktopEntries = { - - cura = { - name = "Ultimaker Cura"; - genericName = "Cura"; - exec = "cura"; - terminal = false; - categories = [ "Application" ]; - }; - - anki = { - name = "Anki Flashcards"; - genericName = "Anki"; - exec = "anki"; - terminal = false; - categories = [ "Application" ]; - }; - - element = { - name = "Element Matrix Client"; - genericName = "Element"; - exec = "element-desktop -enable-features=UseOzonePlatform -ozone-platform=wayland --disable-gpu-driver-bug-workarounds"; - terminal = false; - categories = [ "Application" ]; - }; - - emacsclient-newframe = { - name = "Emacs (Client, New Frame)"; - genericName = "Emacs (Client, New Frame)"; - exec = "emacsclient -r %u"; - icon = "emacs"; - terminal = false; - categories = [ "Development" "TextEditor" ]; - }; - - }; - - xdg.mimeApps = { - - enable = true; - defaultApplications = { - "x-scheme-handler/http" = [ "firefox.desktop" ]; - "x-scheme-handler/https" = [ "firefox.desktop" ]; - "x-scheme-handler/chrome" = [ "firefox.desktop" ]; - "text/plain" = [ "emacsclient.desktop" ]; - "text/csv" = [ "emacsclient.desktop" ]; - "text/html" = [ "firefox.desktop" ]; - "application/x-extension-htm" = [ "firefox.desktop" ]; - "application/x-extension-html" = [ "firefox.desktop" ]; - "application/x-extension-shtml" = [ "firefox.desktop" ]; - "application/xhtml+xml" = [ "firefox.desktop" ]; - "application/x-extension-xhtml" = [ "firefox.desktop" ]; - "application/x-extension-xht" = [ "firefox.desktop" ]; - "image/png" = [ "imv.desktop" ]; - "image/jpeg" = [ "imv.desktop" ]; - "image/gif" = [ "imv.desktop" ]; - "image/svg" = [ "imv.desktop" ]; - "image/webp" = [ "firefox.desktop" ]; - "image/vnd.adobe.photoshop" = [ "gimp.desktop" ]; - "image/vnd.dxf" = [ "org.inkscape.Inkscape.desktop" ]; - "audio/flac" = [ "mpv.desktop" ]; - "audio/mp3" = [ "mpv.desktop" ]; - "audio/ogg" = [ "mpv.desktop" ]; - "audio/wav" = [ "mpv.desktop" ]; - "video/mp4" = [ "umpv.desktop" ]; - "video/mkv" = [ "umpv.desktop" ]; - "video/flv" = [ "umpv.desktop" ]; - "video/3gp" = [ "umpv.desktop" ]; - "application/pdf" = [ "org.gnome.Evince.desktop" ]; - "application/metalink+xml" = [ "emacsclient.desktop" ]; - "application/sql" = [ "emacsclient.desktop" ]; - "application/vnd.ms-powerpoint" = [ "impress.desktop" ]; - "application/msword" = [ "writer.desktop" ]; - "application/vnd.ms-excel" = [ "calc.desktop" ]; - }; - associations = { - added = { - "application/x-zerosize" = [ "emacsclient.desktop" ]; - }; - }; - }; - } -#+end_src - -**** Linking dotfiles -:PROPERTIES: -:CUSTOM_ID: h:5ef03803-e150-41bc-b603-e80d60d96efc -:END: - -This section should be used in order to symlink already existing configuration files using `home.file` and setting session variables using `home.sessionVariables`. - -As for the `home.sessionVariables`, it should be noted that environment variables that are needed at system start should NOT be loaded here, but instead in `programs.zsh.config.extraSessionCommands` (in the home-manager programs section). This is also where all the wayland related variables are stored. - -#+begin_src nix :tangle profiles/common/home/symlink.nix - { self, ... }: - { - home.file = { - "init.el" = { - source = self + /programs/emacs/init.el; - target = ".emacs.d/init.el"; - }; - "early-init.el" = { - source = self + /programs/emacs/early-init.el; - target = ".emacs.d/early-init.el"; - }; - # on NixOS, Emacs does not find the aspell dicts easily. Write the configuration manually - ".aspell.conf" = { - source = self + /programs/config/.aspell.conf; - target = ".aspell.conf"; - }; - ".gitmessage" = { - source = self + /programs/git/.gitmessage; - target = ".gitmessage"; - }; - "swayidle/config" = { - source = self + /programs/swayidle/config; - target = ".config/swayidle/config"; - }; - }; - -#+end_src - -Also, we link some files to the users XDG configuration home: -Also in firefox `about:config > toolkit.legacyUserProfileCustomizations.stylesheets` to true. - -#+begin_src nix :tangle profiles/common/home/symlink.nix - xdg.configFile = { - "tridactyl/tridactylrc".source = self + /programs/firefox/tridactyl/tridactylrc; - "tridactyl/themes/base16-codeschool.css".source = self + /programs/firefox/tridactyl/themes/base16-codeschool.css; - }; - } -#+end_src - -**** Sourcing environment variables -:PROPERTIES: -:CUSTOM_ID: h:4486b02f-4fb8-432b-bfa2-2e786206341d -:END: - -Sets environment variables. Here I am only setting the EDITOR variable, most variables are set in the [[#h:02df9dfc-d1af-4a37-a7a0-d8da0af96a20][Sway]] section. - -#+begin_src nix :tangle profiles/common/home/env.nix - { config, ... }: - { - home.sessionVariables = { - EDITOR = "e -w"; - SWARSEL_LO_RES = config.swarselsystems.lowResolution; - SWARSEL_HI_RES = config.swarselsystems.highResolution; - }; - } -#+end_src - -**** General Programs: bottom, imv, sioyek, bat, carapace, wlogout, swayr, yt-dlp, mpv, jq, nix-index, ripgrep, pandoc, fzf -:PROPERTIES: -:CUSTOM_ID: h:f0e0b580-2e1c-4ca6-a983-f05d3ebbbcde -:END: - -This section is for programs that require no further configuration. zsh Integration is enabled by default for these. - -#+begin_src nix :tangle profiles/common/home/programs.nix - { pkgs, ... }: - { - programs = { - bottom.enable = true; - imv.enable = true; - sioyek.enable = true; - bat = { - enable = true; - extraPackages = with pkgs.bat-extras; [ batdiff batman batgrep batwatch ]; - }; - carapace.enable = true; - wlogout.enable = true; - swayr.enable = true; - yt-dlp.enable = true; - mpv.enable = true; - jq.enable = true; - ripgrep.enable = true; - pandoc.enable = true; - fzf.enable = true; - zoxide.enable = true; - }; - } -#+end_src - -**** nix-index -:PROPERTIES: -:CUSTOM_ID: h:64dbbb9e-8097-4c1b-813c-8c10cf9b9748 -:END: - -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. - -#+begin_src nix :tangle profiles/common/home/nix-index.nix - { self, pkgs, ... }: - { - programs.nix-index = - let - commandNotFound = pkgs.runCommandLocal "command-not-found.sh" { } '' - mkdir -p $out/etc/profile.d - substitute ${self + /scripts/command-not-found.sh} \ - $out/etc/profile.d/command-not-found.sh \ - --replace @nix-locate@ ${pkgs.nix-index}/bin/nix-locate \ - --replace @tput@ ${pkgs.ncurses}/bin/tput - ''; - in - - { - enable = true; - package = pkgs.symlinkJoin { - name = "nix-index"; - paths = [ commandNotFound ]; - }; - }; - } -#+end_src - -**** password-store -:PROPERTIES: -:CUSTOM_ID: h:ac0e5e62-0dbf-4782-9a96-9e558eae86ae -:END: - -Enables password store with the =pass-otp= extension which allows me to store and generate one-time-passwords. - -#+begin_src nix :tangle profiles/common/home/password-store.nix - { pkgs, ... }: - { - programs.password-store = { - enable = true; - settings = { - PASSWORD_STORE_DIR = "$HOME/.local/share/password-store"; - }; - package = pkgs.pass.withExtensions (exts: [ exts.pass-otp ]); - }; - } -#+end_src - -**** direnv -:PROPERTIES: -:CUSTOM_ID: h:1ab84307-b3fb-4c32-9def-4b89a53a8547 -:END: - -Enables direnv, which I use for nearly all of my nix dev flakes. - -#+begin_src nix :tangle profiles/common/home/direnv.nix - _: - { - programs.direnv = { - enable = true; - nix-direnv.enable = true; - }; - } -#+end_src - -**** eza -:PROPERTIES: -:CUSTOM_ID: h:1bd6b0c7-f201-43e2-9624-6c50de00a1f6 -:END: - -Eza provides me with a better =ls= command and some other useful aliases. - -#+begin_src nix :tangle profiles/common/home/eza.nix - _: - { - programs.eza = { - enable = true; - icons = "auto"; - git = true; - extraOptions = [ - "-l" - "--group-directories-first" - ]; - }; - } -#+end_src - -**** git -:PROPERTIES: -:CUSTOM_ID: h:419675ec-3310-438e-80ae-9eaa798a319d -:END: - -Here I set up my git config, automatic signing of commits, useful aliases for my ost used commands (for when I am not using [[#h:d2c7323d-f8c6-4f23-b70a-930e3e4ecce5][Magit]]) as well as a git template defined in [[#h:5ef03803-e150-41bc-b603-e80d60d96efc][Linking dotfiles]]. - -#+begin_src nix :tangle profiles/common/home/git.nix - { lib, ... }: - { - programs.git = { - enable = true; - aliases = { - a = "add"; - c = "commit"; - cl = "clone"; - co = "checkout"; - b = "branch"; - i = "init"; - m = "merge"; - s = "status"; - r = "restore"; - p = "pull"; - pp = "push"; - }; - signing = { - key = "0x76FD3810215AE097"; - signByDefault = true; - }; - userEmail = lib.mkDefault "leon.schwarzaeugl@gmail.com"; - userName = "Leon Schwarzäugl"; - difftastic.enable = true; - lfs.enable = true; - includes = [ - { - contents = { - github = { - user = "Swarsel"; - }; - commit = { - template = "~/.gitmessage"; - }; - }; - } - ]; - }; - } -#+end_src - -**** Fuzzel -:PROPERTIES: -:CUSTOM_ID: h:069cabf3-df14-49ba-8d17-75f2bcf34fbf -:END: - -Here I only need to set basic layout options - the rest is being managed by stylix. - -#+begin_src nix :tangle profiles/common/home/fuzzel.nix - _: - { - programs.fuzzel = { - enable = true; - settings = { - main = { - layer = "overlay"; - lines = "10"; - width = "40"; - }; - border.radius = "0"; - }; - }; - } -#+end_src - -**** Starship -:PROPERTIES: -:CUSTOM_ID: h:55212502-c8f6-43af-ae99-55c8377ef34e -:END: - -Starship makes my =zsh= look cooler! I have symbols for most programming languages and toolchains, also I build my own powerline. - -#+begin_src nix :tangle profiles/common/home/starship.nix - _: - { - programs.starship = { - enable = true; - enableZshIntegration = true; - settings = { - add_newline = false; - format = "$character"; - right_format = "$all"; - command_timeout = 3000; - - directory.substitutions = { - "Documents" = "󰈙 "; - "Downloads" = " "; - "Music" = " "; - "Pictures" = " "; - }; - - git_status = { - style = "bg:#394260"; - format = "[[($all_status$ahead_behind )](fg:#769ff0 bg:#394260)]($style)"; - }; - - character = { - success_symbol = "[λ](bold green)"; - error_symbol = "[λ](bold red)"; - }; - - aws.symbol = " "; - buf.symbol = " "; - c.symbol = " "; - conda.symbol = " "; - dart.symbol = " "; - directory.read_only = " 󰌾"; - docker_context.symbol = " "; - elixir.symbol = " "; - elm.symbol = " "; - fossil_branch.symbol = " "; - git_branch.symbol = " "; - golang.symbol = " "; - guix_shell.symbol = " "; - haskell.symbol = " "; - haxe.symbol = " "; - hg_branch.symbol = " "; - hostname.ssh_symbol = " "; - java.symbol = " "; - julia.symbol = " "; - lua.symbol = " "; - memory_usage.symbol = "󰍛 "; - meson.symbol = "󰔷 "; - nim.symbol = "󰆥 "; - nix_shell.symbol = " "; - nodejs.symbol = " "; - - os.symbols = { - Alpaquita = " "; - Alpine = " "; - Amazon = " "; - Android = " "; - Arch = " "; - Artix = " "; - CentOS = " "; - Debian = " "; - DragonFly = " "; - Emscripten = " "; - EndeavourOS = " "; - Fedora = " "; - FreeBSD = " "; - Garuda = "󰛓 "; - Gentoo = " "; - HardenedBSD = "󰞌 "; - Illumos = "󰈸 "; - Linux = " "; - Mabox = " "; - Macos = " "; - Manjaro = " "; - Mariner = " "; - MidnightBSD = " "; - Mint = " "; - NetBSD = " "; - NixOS = " "; - OpenBSD = "󰈺 "; - openSUSE = " "; - OracleLinux = "󰌷 "; - Pop = " "; - Raspbian = " "; - Redhat = " "; - RedHatEnterprise = " "; - Redox = "󰀘 "; - Solus = "󰠳 "; - SUSE = " "; - Ubuntu = " "; - Unknown = " "; - Windows = "󰍲 "; - }; - - package.symbol = "󰏗 "; - pijul_channel.symbol = " "; - python.symbol = " "; - rlang.symbol = "󰟔 "; - ruby.symbol = " "; - rust.symbol = " "; - scala.symbol = " "; - }; - }; - } -#+end_src - -**** Kitty -:PROPERTIES: -:CUSTOM_ID: h:5f1287db-d2e8-49aa-8c58-730129c7795c -:END: - -Kitty is the terminal emulator of choice for me, it is nice to configure using nix, fast, and has a nice style. - -The theme is handled by stylix. - -#+begin_src nix :tangle profiles/common/home/kitty.nix - _: - { - programs.kitty = { - enable = true; - keybindings = { }; - settings = { - scrollback_lines = 10000; - enable_audio_bell = false; - notify_on_cmd_finish = "always 20"; - }; - }; - } -#+end_src - -**** zsh -:PROPERTIES: -:CUSTOM_ID: h:91dd4cc4-aada-4e74-be23-0cc69ed85af5 -:END: - -zsh is the most convenient shell for me and it happens to be super neat to configure within home manager. - -Here we set some aliases (some of them should be shellApplications instead) as well as some zsh plugins like =fzf-tab=. - -#+begin_src nix :tangle profiles/common/home/zsh.nix - { config, pkgs, lib, ... }: - { - programs.zsh = { - enable = true; - shellAliases = lib.recursiveUpdate - { - hg = "history | grep"; - hmswitch = "home-manager --flake ${config.swarselsystems.flakePath}#$(whoami)@$(hostname) switch |& nom"; - nswitch = "sudo nixos-rebuild --flake ${config.swarselsystems.flakePath}#$(hostname) --show-trace --log-format internal-json -v switch |& nom --json"; - nboot = "sudo nixos-rebuild --flake ${config.swarselsystems.flakePath}#$(hostname) --show-trace --log-format internal-json -v boot |& nom --json"; - magit = "emacsclient -nc -e \"(magit-status)\""; - config = "git --git-dir=$HOME/.cfg/ --work-tree=$HOME"; - g = "git"; - c = "git --git-dir=$FLAKE/.git --work-tree=$FLAKE/"; - passpush = "cd ~/.local/share/password-store; git add .; git commit -m 'pass file changes'; git push; cd -;"; - passpull = "cd ~/.local/share/password-store; git pull; cd -;"; - hotspot = "nmcli connection up local; nmcli device wifi hotspot;"; - cd = "z"; - cd-orig = "cd"; - cat-orig = "cat"; - cdr = "cd \"$( (find $DOCUMENT_DIR_WORK $DOCUMENT_DIR_PRIV -maxdepth 1 && echo $FLAKE) | fzf )\""; - nix-ldd = "LD_LIBRARY_PATH=$NIX_LD_LIBRARY_PATH ldd"; - fs-diff = "sudo mount -o subvol=/ /dev/mapper/cryptroot /mnt ; fs-diff"; - lt = "eza -las modified --total-size"; - boot-diff = "nix store diff-closures /run/*-system"; - gen-diff = "nix profile diff-closures --profile /nix/var/nix/profiles/system"; - } - config.swarselsystems.shellAliases; - autosuggestion.enable = true; - enableCompletion = true; - syntaxHighlighting.enable = true; - autocd = false; - cdpath = [ - "~/.dotfiles" - # "~/Documents/GitHub" - ]; - defaultKeymap = "emacs"; - dirHashes = { - dl = "$HOME/Downloads"; - gh = "$HOME/Documents/GitHub"; - }; - history = { - expireDuplicatesFirst = true; - path = "$HOME/.histfile"; - save = 10000; - size = 10000; - }; - historySubstringSearch = { - enable = true; - searchDownKey = "^[OB"; - searchUpKey = "^[OA"; - }; - plugins = [ - { - name = "fzf-tab"; - src = pkgs.zsh-fzf-tab; - } - ]; - initExtra = '' - bindkey "^[[1;5D" backward-word - bindkey "^[[1;5C" forward-word - - my-backward-delete-word() { - # Copy the global WORDCHARS variable to a local variable. That way any - # modifications are scoped to this function only - local WORDCHARS=$WORDCHARS - # Use bash string manipulation to remove `:` so our delete will stop at it - WORDCHARS="''${WORDCHARS//:}" - # Use bash string manipulation to remove `/` so our delete will stop at it - WORDCHARS="''${WORDCHARS//\/}" - # Use bash string manipulation to remove `.` so our delete will stop at it - WORDCHARS="''${WORDCHARS//.}" - # zle will run an existing widget. - zle backward-delete-word - } - zle -N my-backward-delete-word - bindkey '^H' my-backward-delete-word - - # This will be our `ctrl+alt+w` command - my-backward-delete-whole-word() { - # Copy the global WORDCHARS variable to a local variable. That way any - # modifications are scoped to this function only - local WORDCHARS=$WORDCHARS - # Use bash string manipulation to add `:` to WORDCHARS if it's not present - # already. - [[ ! $WORDCHARS == *":"* ]] && WORDCHARS="$WORDCHARS"":" - # zle will run that widget. - zle backward-delete-word - } - # `zle -N` will create a new widget that we can use on the command line - zle -N my-backward-delete-whole-word - # bind this new widget to `ctrl+alt+w` - bindkey '^W' my-backward-delete-whole-word - - vterm_printf() { - if [ -n "$TMUX" ] && ([ "''${TERM%%-*}" = "tmux" ] || [ "''${TERM%%-*}" = "screen" ]); then - # Tell tmux to pass the escape sequences through - printf "\ePtmux;\e\e]%s\007\e\\" "$1" - elif [ "''${TERM%%-*}" = "screen" ]; then - # GNU screen (screen, screen-256color, screen-256color-bce) - printf "\eP\e]%s\007\e\\" "$1" - else - printf "\e]%s\e\\" "$1" - fi - } - vterm_prompt_end() { - vterm_printf "51;A$(whoami)@$(hostname):$(pwd)" - } - setopt PROMPT_SUBST - PROMPT=$PROMPT'%{$(vterm_prompt_end)%}' - - vterm_cmd() { - local vterm_elisp - vterm_elisp="" - while [ $# -gt 0 ]; do - vterm_elisp="$vterm_elisp""$(printf '"%s" ' "$(printf "%s" "$1" | sed -e 's|\\|\\\\|g' -e 's|"|\\"|g')")" - shift - done - vterm_printf "51;E$vterm_elisp" - } - - ''; - }; - } -#+end_src - -**** zellij -:PROPERTIES: -:CUSTOM_ID: h:00de4901-631c-4b4c-86ce-d9d6e62ed8c7 -:END: -#+begin_src nix :tangle profiles/common/home/zellij.nix - _: - # { pkgs, config, ... }: - # let - # inherit (config.lib.stylix) colors; - # sesh = pkgs.writeScriptBin "sesh" '' - # #! /usr/bin/env sh - - # # Taken from https://github.com/zellij-org/zellij/issues/884#issuecomment-1851136980 - # # select a directory using zoxide - # ZOXIDE_RESULT=$(zoxide query --interactive) - # # checks whether a directory has been selected - # if [[ -z "$ZOXIDE_RESULT" ]]; then - # # if there was no directory, select returns without executing - # exit 0 - # fi - # # extracts the directory name from the absolute path - # SESSION_TITLE=$(echo "$ZOXIDE_RESULT" | sed 's#.*/##') - - # # get the list of sessions - # SESSION_LIST=$(zellij list-sessions -n | awk '{print $1}') - - # # checks if SESSION_TITLE is in the session list - # if echo "$SESSION_LIST" | grep -q "^$SESSION_TITLE$"; then - # # if so, attach to existing session - # zellij attach "$SESSION_TITLE" - # else - # # if not, create a new session - # echo "Creating new session $SESSION_TITLE and CD $ZOXIDE_RESULT" - # cd $ZOXIDE_RESULT - # zellij attach -c "$SESSION_TITLE" - # fi - # ''; - - # in - { - programs.zellij = { - enable = true; - }; - home.packages = [ - # pkgs.tmate - # sesh - ]; - # xdg.configFile."zellij/config.kdl".source = ../../../programs/zellij/config.kdl; - # xdg.configFile."zellij/layouts/default.kdl".text = '' - # layout { - # swap_tiled_layout name="vertical" { - # tab max_panes=5 { - # pane split_direction="vertical" { - # pane - # pane { children; } - # } - # } - # tab max_panes=8 { - # pane split_direction="vertical" { - # pane { children; } - # pane { pane; pane; pane; pane; } - # } - # } - # tab max_panes=12 { - # pane split_direction="vertical" { - # pane { children; } - # pane { pane; pane; pane; pane; } - # pane { pane; pane; pane; pane; } - # } - # } - # } - - # swap_tiled_layout name="horizontal" { - # tab max_panes=5 { - # pane - # pane - # } - # tab max_panes=8 { - # pane { - # pane split_direction="vertical" { children; } - # pane split_direction="vertical" { pane; pane; pane; pane; } - # } - # } - # tab max_panes=12 { - # pane { - # pane split_direction="vertical" { children; } - # pane split_direction="vertical" { pane; pane; pane; pane; } - # pane split_direction="vertical" { pane; pane; pane; pane; } - # } - # } - # } - - # swap_tiled_layout name="stacked" { - # tab min_panes=5 { - # pane split_direction="vertical" { - # pane - # pane stacked=true { children; } - # } - # } - # } - - # swap_floating_layout name="staggered" { - # floating_panes - # } - - # swap_floating_layout name="enlarged" { - # floating_panes max_panes=10 { - # pane { x "5%"; y 1; width "90%"; height "90%"; } - # pane { x "5%"; y 2; width "90%"; height "90%"; } - # pane { x "5%"; y 3; width "90%"; height "90%"; } - # pane { x "5%"; y 4; width "90%"; height "90%"; } - # pane { x "5%"; y 5; width "90%"; height "90%"; } - # pane { x "5%"; y 6; width "90%"; height "90%"; } - # pane { x "5%"; y 7; width "90%"; height "90%"; } - # pane { x "5%"; y 8; width "90%"; height "90%"; } - # pane { x "5%"; y 9; width "90%"; height "90%"; } - # pane focus=true { x 10; y 10; width "90%"; height "90%"; } - # } - # } - - # swap_floating_layout name="spread" { - # floating_panes max_panes=1 { - # pane {y "50%"; x "50%"; } - # } - # floating_panes max_panes=2 { - # pane { x "1%"; y "25%"; width "45%"; } - # pane { x "50%"; y "25%"; width "45%"; } - # } - # floating_panes max_panes=3 { - # pane focus=true { y "55%"; width "45%"; height "45%"; } - # pane { x "1%"; y "1%"; width "45%"; } - # pane { x "50%"; y "1%"; width "45%"; } - # } - # floating_panes max_panes=4 { - # pane { x "1%"; y "55%"; width "45%"; height "45%"; } - # pane focus=true { x "50%"; y "55%"; width "45%"; height "45%"; } - # pane { x "1%"; y "1%"; width "45%"; height "45%"; } - # pane { x "50%"; y "1%"; width "45%"; height "45%"; } - # } - # } - - # default_tab_template { - # pane size=2 borderless=true { - # plugin location="file://${pkgs.zjstatus}/bin/zjstatus.wasm" { - # format_left "{mode}#[bg=#${colors.base00}] {tabs}" - # format_center "" - # format_right "#[bg=#${colors.base00},fg=#${colors.base0D}]#[bg=#${colors.base0D},fg=#${colors.base01},bold] #[bg=#${colors.base02},fg=#${colors.base05},bold] {session} #[bg=#${colors.base03},fg=#${colors.base05},bold]" - # format_space "" - # format_hide_on_overlength "true" - # format_precedence "crl" - - # border_enabled "false" - # border_char "─" - # border_format "#[fg=#6C7086]{char}" - # border_position "top" - - # mode_normal "#[bg=#${colors.base0B},fg=#${colors.base02},bold] NORMAL#[bg=#${colors.base03},fg=#${colors.base0B}]█" - # mode_locked "#[bg=#${colors.base04},fg=#${colors.base02},bold] LOCKED #[bg=#${colors.base03},fg=#${colors.base04}]█" - # mode_resize "#[bg=#${colors.base08},fg=#${colors.base02},bold] RESIZE#[bg=#${colors.base03},fg=#${colors.base08}]█" - # mode_pane "#[bg=#${colors.base0D},fg=#${colors.base02},bold] PANE#[bg=#${colors.base03},fg=#${colors.base0D}]█" - # mode_tab "#[bg=#${colors.base07},fg=#${colors.base02},bold] TAB#[bg=#${colors.base03},fg=#${colors.base07}]█" - # mode_scroll "#[bg=#${colors.base0A},fg=#${colors.base02},bold] SCROLL#[bg=#${colors.base03},fg=#${colors.base0A}]█" - # mode_enter_search "#[bg=#${colors.base0D},fg=#${colors.base02},bold] ENT-SEARCH#[bg=#${colors.base03},fg=#${colors.base0D}]█" - # mode_search "#[bg=#${colors.base0D},fg=#${colors.base02},bold] SEARCHARCH#[bg=#${colors.base03},fg=#${colors.base0D}]█" - # mode_rename_tab "#[bg=#${colors.base07},fg=#${colors.base02},bold] RENAME-TAB#[bg=#${colors.base03},fg=#${colors.base07}]█" - # mode_rename_pane "#[bg=#${colors.base0D},fg=#${colors.base02},bold] RENAME-PANE#[bg=#${colors.base03},fg=#${colors.base0D}]█" - # mode_session "#[bg=#${colors.base0E},fg=#${colors.base02},bold] SESSION#[bg=#${colors.base03},fg=#${colors.base0E}]█" - # mode_move "#[bg=#${colors.base0F},fg=#${colors.base02},bold] MOVE#[bg=#${colors.base03},fg=#${colors.base0F}]█" - # mode_prompt "#[bg=#${colors.base0D},fg=#${colors.base02},bold] PROMPT#[bg=#${colors.base03},fg=#${colors.base0D}]█" - # mode_tmux "#[bg=#${colors.base09},fg=#${colors.base02},bold] TMUX#[bg=#${colors.base03},fg=#${colors.base09}]█" - - # // formatting for inactive tabs - # tab_normal "#[bg=#${colors.base03},fg=#${colors.base0D}]█#[bg=#${colors.base0D},fg=#${colors.base02},bold]{index} #[bg=#${colors.base02},fg=#${colors.base05},bold] {name}{floating_indicator}#[bg=#${colors.base03},fg=#${colors.base02},bold]█" - # tab_normal_fullscreen "#[bg=#${colors.base03},fg=#${colors.base0D}]█#[bg=#${colors.base0D},fg=#${colors.base02},bold]{index} #[bg=#${colors.base02},fg=#${colors.base05},bold] {name}{fullscreen_indicator}#[bg=#${colors.base03},fg=#${colors.base02},bold]█" - # tab_normal_sync "#[bg=#${colors.base03},fg=#${colors.base0D}]█#[bg=#${colors.base0D},fg=#${colors.base02},bold]{index} #[bg=#${colors.base02},fg=#${colors.base05},bold] {name}{sync_indicator}#[bg=#${colors.base03},fg=#${colors.base02},bold]█" - - # // formatting for the current active tab - # tab_active "#[bg=#${colors.base03},fg=#${colors.base09}]█#[bg=#${colors.base09},fg=#${colors.base02},bold]{index} #[bg=#${colors.base02},fg=#${colors.base05},bold] {name}{floating_indicator}#[bg=#${colors.base03},fg=#${colors.base02},bold]█" - # tab_active_fullscreen "#[bg=#${colors.base03},fg=#${colors.base09}]█#[bg=#${colors.base09},fg=#${colors.base02},bold]{index} #[bg=#${colors.base02},fg=#${colors.base05},bold] {name}{fullscreen_indicator}#[bg=#${colors.base03},fg=#${colors.base02},bold]█" - # tab_active_sync "#[bg=#${colors.base03},fg=#${colors.base09}]█#[bg=#${colors.base09},fg=#${colors.base02},bold]{index} #[bg=#${colors.base02},fg=#${colors.base05},bold] {name}{sync_indicator}#[bg=#${colors.base03},fg=#${colors.base02},bold]█" - - # // separator between the tabs - # tab_separator "#[bg=#${colors.base00}] " - - # // indicators - # tab_sync_indicator " " - # tab_fullscreen_indicator " 󰊓" - # tab_floating_indicator " 󰹙" - - # command_git_branch_command "git rev-parse --abbrev-ref HEAD" - # command_git_branch_format "#[fg=blue] {stdout} " - # command_git_branch_interval "10" - # command_git_branch_rendermode "static" - - # datetime "#[fg=#6C7086,bold] {format} " - # datetime_format "%A, %d %b %Y %H:%M" - # datetime_timezone "Europe/London" - # } - # } - # children - # } - # } - # ''; - - - } -#+end_src -**** tmux -:PROPERTIES: -:CUSTOM_ID: h:45de9430-f925-4df6-9db6-bffb5b8f1604 -:END: -#+begin_src nix :tangle profiles/common/home/tmux.nix - - { pkgs, ... }: - let - tmux-super-fingers = pkgs.tmuxPlugins.mkTmuxPlugin - { - pluginName = "tmux-super-fingers"; - version = "unstable-2023-01-06"; - src = pkgs.fetchFromGitHub { - owner = "artemave"; - repo = "tmux_super_fingers"; - rev = "2c12044984124e74e21a5a87d00f844083e4bdf7"; - sha256 = "sha256-cPZCV8xk9QpU49/7H8iGhQYK6JwWjviL29eWabuqruc="; - }; - }; - in - { - - home.packages = with pkgs; [ - lsof - sesh - ]; - - programs.tmux = { - enable = true; - shell = "${pkgs.zsh}/bin/zsh"; - terminal = "tmux-256color"; - historyLimit = 100000; - plugins = with pkgs; - [ - tmuxPlugins.tmux-thumbs - { - plugin = tmux-super-fingers; - extraConfig = "set -g @super-fingers-key f"; - } - - tmuxPlugins.sensible - # must be before continuum edits right status bar - { - plugin = tmuxPlugins.catppuccin; - extraConfig = '' - set -g @catppuccin_flavour 'frappe' - set -g @catppuccin_window_tabs_enabled on - set -g @catppuccin_date_time "%H:%M" - ''; - } - { - plugin = tmuxPlugins.resurrect; - extraConfig = '' - set -g @resurrect-strategy-vim 'session' - set -g @resurrect-strategy-nvim 'session' - set -g @resurrect-capture-pane-contents 'on' - ''; - } - { - plugin = tmuxPlugins.continuum; - extraConfig = '' - set -g @continuum-restore 'on' - set -g @continuum-boot 'on' - set -g @continuum-save-interval '10' - ''; - } - tmuxPlugins.better-mouse-mode - tmuxPlugins.yank - ]; - extraConfig = '' - set -g default-terminal "tmux-256color" - set -ag terminal-overrides ",xterm-256color:RGB" - - set-option -g prefix C-a - unbind-key C-b - bind-key C-a send-prefix - - set -g mouse on - - # Open new split at cwd of current split - bind | split-window -h -c "#{pane_current_path}" - bind - split-window -v -c "#{pane_current_path}" - - # Use vim keybindings in copy mode - set-window-option -g mode-keys vi - - # v in copy mode starts making selection - bind-key -T copy-mode-vi v send-keys -X begin-selection - bind-key -T copy-mode-vi C-v send-keys -X rectangle-toggle - bind-key -T copy-mode-vi y send-keys -X copy-selection-and-cancel - - # Escape turns on copy mode - bind Escape copy-mode - - set-option -g status-position top - - # make Prefix p paste the buffer. - unbind p - bind p paste-buffer - - ''; - }; - } - - -#+end_src -**** Mail -:PROPERTIES: -:CUSTOM_ID: h:506d01fc-c20b-473a-ac78-bce4b53fe0e3 -:END: - -Normally I use 4 mail accounts - here I set them all up. Three of them are Google accounts (sadly), which are a chore to setup. The last is just a sender account that I setup SMTP for here. - -#+begin_src nix :tangle profiles/common/home/mail.nix - { lib, config, ... }: - { - programs.mbsync = lib.mkIf (!config.swarselsystems.isPublic) { - enable = true; - }; - services.mbsync = lib.mkIf (!config.swarselsystems.isPublic) { - enable = true; - }; - # this is needed so that mbsync can use the passwords from sops - systemd.user.services.mbsync.Unit.After = lib.mkIf (!config.swarselsystems.isPublic) [ "sops-nix.service" ]; - - programs.msmtp = lib.mkIf (!config.swarselsystems.isPublic) { - enable = true; - }; - - programs.mu = lib.mkIf (!config.swarselsystems.isPublic) { - enable = true; - }; - - accounts.email = lib.mkIf (!config.swarselsystems.isPublic) { - maildirBasePath = "Mail"; - accounts.leon = { - primary = true; - address = "leon.schwarzaeugl@gmail.com"; - userName = "leon.schwarzaeugl@gmail.com"; - realName = "Leon Schwarzäugl"; - passwordCommand = "cat ${config.sops.secrets.leon.path}"; - gpg = { - key = "0x76FD3810215AE097"; - signByDefault = true; - }; - imap.host = "imap.gmail.com"; - smtp.host = "smtp.gmail.com"; - mu.enable = true; - msmtp = { - enable = true; - }; - mbsync = { - enable = true; - create = "maildir"; - expunge = "both"; - patterns = [ "*" "![Gmail]*" "[Gmail]/Sent Mail" "[Gmail]/Starred" "[Gmail]/All Mail" ]; - extraConfig = { - channel = { - Sync = "All"; - }; - account = { - Timeout = 120; - PipelineDepth = 1; - }; - }; - }; - }; - - accounts.swarsel = lib.mkIf (!config.swarselsystems.isPublic) { - address = "leon@swarsel.win"; - userName = "8227dc594dd515ce232eda1471cb9a19"; - realName = "Leon Schwarzäugl"; - passwordCommand = "cat ${config.sops.secrets.swarselmail.path}"; - smtp = { - host = "in-v3.mailjet.com"; - port = 587; - tls = { - enable = true; - useStartTls = true; - }; - }; - mu.enable = false; - msmtp = { - enable = true; - }; - mbsync = { - enable = false; - }; - }; - - accounts.nautilus = lib.mkIf (!config.swarselsystems.isPublic) { - primary = false; - address = "nautilus.dw@gmail.com"; - userName = "nautilus.dw@gmail.com"; - realName = "Nautilus"; - passwordCommand = "cat ${config.sops.secrets.nautilus.path}"; - imap.host = "imap.gmail.com"; - smtp.host = "smtp.gmail.com"; - msmtp.enable = true; - mu.enable = true; - mbsync = { - enable = true; - create = "maildir"; - expunge = "both"; - patterns = [ "*" "![Gmail]*" "[Gmail]/Sent Mail" "[Gmail]/Starred" "[Gmail]/All Mail" ]; - extraConfig = { - channel = { - Sync = "All"; - }; - account = { - Timeout = 120; - PipelineDepth = 1; - }; - }; - }; - }; - accounts.mrswarsel = lib.mkIf (!config.swarselsystems.isPublic) { - primary = false; - address = "mrswarsel@gmail.com"; - userName = "mrswarsel@gmail.com"; - realName = "Swarsel"; - passwordCommand = "cat ${config.sops.secrets.mrswarsel.path}"; - imap.host = "imap.gmail.com"; - smtp.host = "smtp.gmail.com"; - msmtp.enable = true; - mu.enable = true; - mbsync = { - enable = true; - create = "maildir"; - expunge = "both"; - patterns = [ "*" "![Gmail]*" "[Gmail]/Sent Mail" "[Gmail]/Starred" "[Gmail]/All Mail" ]; - extraConfig = { - channel = { - Sync = "All"; - }; - account = { - Timeout = 120; - PipelineDepth = 1; - }; - }; - }; - }; - }; - } -#+end_src - -**** Home-manager: Emacs -:PROPERTIES: -:CUSTOM_ID: h:c05d1b64-7110-4151-b436-46bc447113b4 -:END: - -By using the emacs-overlay NixOS module, I can install all Emacs packages that I want to use right through NixOS. This is done by passing my =init.el= file to the configuration which will then be parsed upon system rebuild, looking for =use-package= sections in the Elisp code. Also I define here the style of Emacs that I want to run - I am going with native Wayland Emacs here (=emacs-pgtk=). All of the nice options such as =tree-sitter= support are enabled by default, so I do not need to adjust the build process. - -Lastly, I am defining some more packages here that the parser has problems finding. Also there are some packages that are not in ELPA or MELPA that I still want to use, like =calfw= and =fast-scroll=, so I build them here. - -#+begin_src nix :tangle profiles/common/home/emacs.nix - { self, lib, config, pkgs, ... }: - { - - # needed for elfeed - sops.secrets.fever = lib.mkIf (!config.swarselsystems.isPublic) { path = "${config.home.homeDirectory}/.emacs.d/.fever"; }; - - # enable emacs overlay for bleeding edge features - # also read init.el file and install use-package packages - programs.emacs = { - enable = true; - package = pkgs.emacsWithPackagesFromUsePackage { - config = self + /programs/emacs/init.el; - package = pkgs.emacs-pgtk; - alwaysEnsure = true; - alwaysTangle = true; - extraEmacsPackages = epkgs: [ - epkgs.mu4e - epkgs.use-package - # epkgs.lsp-bridge - epkgs.doom-themes - epkgs.vterm - epkgs.treesit-grammars.with-all-grammars - - # build the rest of the packages myself - # org-calfw is severely outdated on MELPA and throws many warnings on emacs startup - # build the package from the haji-ali fork, which is well-maintained - - (epkgs.trivialBuild rec { - pname = "eglot-booster"; - version = "main-29-10-2024"; - - src = pkgs.fetchFromGitHub { - owner = "jdtsmith"; - repo = "eglot-booster"; - rev = "e6daa6bcaf4aceee29c8a5a949b43eb1b89900ed"; - hash = "sha256-PLfaXELkdX5NZcSmR1s/kgmU16ODF8bn56nfTh9g6bs="; - }; - - packageRequires = [ epkgs.jsonrpc epkgs.eglot ]; - }) - (epkgs.trivialBuild rec { - pname = "calfw"; - version = "1.0.0-20231002"; - src = pkgs.fetchFromGitHub { - owner = "haji-ali"; - repo = "emacs-calfw"; - rev = "bc99afee611690f85f0cd0bd33300f3385ddd3d3"; - hash = "sha256-0xMII1KJhTBgQ57tXJks0ZFYMXIanrOl9XyqVmu7a7Y="; - }; - packageRequires = [ epkgs.howm ]; - }) - - (epkgs.trivialBuild rec { - pname = "fast-scroll"; - version = "1.0.0-20191016"; - src = pkgs.fetchFromGitHub { - owner = "ahungry"; - repo = "fast-scroll"; - rev = "3f6ca0d5556fe9795b74714304564f2295dcfa24"; - hash = "sha256-w1wmJW7YwXyjvXJOWdN2+k+QmhXr4IflES/c2bCX3CI="; - }; - packageRequires = [ ]; - }) - - ]; - }; - }; - - services.emacs = { - enable = true; - # socketActivation.enable = false; - # startWithUserSession = "graphical"; - }; - } -#+end_src - -**** Waybar -:PROPERTIES: -:CUSTOM_ID: h:0bf51f63-01c0-4053-a591-7f0c5697c690 -:END: - -Again I am just using the first bar option here that I was able to find good understandable documentation for. Of note is that the `cpu` section's `format` is not defined here, but in section 1 (since not every machine has the same number of cores) - -The rest of the related configuration is found here: -- [[#h:a9530c81-1976-442b-b597-0b4bed6baf25][Waybar]] -- [[#h:f93f66f9-6b8b-478e-b139-b2f382c1f25e][waybarupdate]] - -#+begin_src nix :tangle profiles/common/home/waybar.nix - { self, config, lib, ... }: - { - programs.waybar = { - - enable = true; - systemd = { - enable = true; - target = "sway-sessions.target"; - }; - settings = { - mainBar = { - ipc = true; - id = "bar-0"; - layer = "top"; - position = "top"; - modules-left = [ "sway/workspaces" "custom/outer-right-arrow-dark" "sway/window" ]; - modules-center = [ "sway/mode" "privacy" "custom/github" "custom/configwarn" "custom/nix-updates" ]; - "sway/mode" = { - format = "{}"; - }; - - modules-right = config.swarselsystems.waybarModules; - - "custom/pseudobat" = lib.mkIf (!config.swarselsystems.isLaptop) { - format = ""; - on-click-right = "wlogout -p layer-shell"; - }; - - "custom/configwarn" = { - exec = "waybarupdate"; - interval = 60; - }; - - "custom/scratchpad-indicator" = { - interval = 3; - exec = "swaymsg -t get_tree | jq 'recurse(.nodes[]) | first(select(.name==\"__i3_scratch\")) | .floating_nodes | length | select(. >= 1)'"; - format = "{} "; - on-click = "swaymsg 'scratchpad show'"; - on-click-right = "swaymsg 'move scratchpad'"; - }; - - "custom/github" = { - format = "{}  "; - return-type = "json"; - interval = 60; - exec = "github-notifications"; - on-click = "xdg-open https://github.com/notifications"; - }; - - # "custom/nix-updates" = { - # exec = "update-checker"; - # on-click = "update-checker && notify-send 'The system has been updated'"; - # interval = "once"; - # tooltip = true; - # return-type = "json"; - # format = "{} {icon}"; - # format-icon = { - # "has-updates" = ""; - # "updated" = " "; - # }; - # }; - - idle_inhibitor = { - format = "{icon}"; - format-icons = { - activated = ""; - deactivated = ""; - }; - }; - - "group/hardware" = { - orientation = "inherit"; - drawer = { - "transition-left-to-right" = false; - }; - modules = [ - "tray" - "temperature" - "power-profiles-daemon" - "custom/left-arrow-light" - "custom/left-arrow-dark" - "custom/scratchpad-indicator" - "custom/left-arrow-light" - "disk" - "custom/left-arrow-dark" - "memory" - "custom/left-arrow-light" - "cpu" - "custom/left-arrow-dark" - "backlight/slider" - "idle_inhibitor" - ]; - }; - - "backlight/slider" = { - min = 0; - max = 100; - orientation = "horizontal"; - device = "intel_backlight"; - }; - - power-profiles-daemon = { - format = "{icon}"; - tooltip-format = "Power profile: {profile}\nDriver: {driver}"; - tooltip = true; - format-icons = { - "default" = ""; - "performance" = ""; - "balanced" = ""; - "power-saver" = ""; - }; - }; - - temperature = { - hwmon-path = lib.mkIf (!config.swarselsystems.temperatureHwmon.isAbsolutePath) config.swarselsystems.temperatureHwmon.path; - hwmon-path-abs = lib.mkIf config.swarselsystems.temperatureHwmon.isAbsolutePath config.swarselsystems.temperatureHwmon.path; - input-filename = lib.mkIf config.swarselsystems.temperatureHwmon.isAbsolutePath config.swarselsystems.temperatureHwmon.input-filename; - critical-threshold = 80; - format-critical = " {temperatureC}°C"; - format = " {temperatureC}°C"; - - }; - - mpris = { - format = "{player_icon} {title} [{position}/{length}]"; - format-paused = "{player_icon} {title} [{position}/{length}]"; - player-icons = { - "default" = "▶ "; - "mpv" = "🎵 "; - "spotify" = " "; - }; - status-icons = { - "paused" = " "; - }; - interval = 1; - title-len = 20; - artist-len = 20; - album-len = 10; - }; - "custom/left-arrow-dark" = { - format = ""; - tooltip = false; - }; - "custom/outer-left-arrow-dark" = { - format = ""; - tooltip = false; - }; - "custom/left-arrow-light" = { - format = ""; - tooltip = false; - }; - "custom/right-arrow-dark" = { - format = ""; - tooltip = false; - }; - "custom/outer-right-arrow-dark" = { - format = ""; - tooltip = false; - }; - "custom/right-arrow-light" = { - format = ""; - tooltip = false; - }; - "sway/workspaces" = { - disable-scroll = true; - format = "{name}"; - }; - - "clock#1" = { - min-length = 8; - interval = 1; - format = "{:%H:%M:%S}"; - # on-click-right= "gnome-clocks"; - tooltip-format = "{:%Y %B}\n{calendar}"; - }; - - "clock#2" = { - format = "{:%d. %B %Y}"; - # on-click-right= "gnome-clocks"; - tooltip-format = "{:%Y %B}\n{calendar}"; - }; - - pulseaudio = { - format = "{icon} {volume:2}%"; - format-bluetooth = "{icon} {volume}%"; - format-muted = "MUTE"; - format-icons = { - headphones = ""; - default = [ - "" - "" - ]; - }; - scroll-step = 1; - on-click = "pamixer -t"; - on-click-right = "pavucontrol"; - }; - - memory = { - interval = 5; - format = " {}%"; - tooltip-format = "Memory: {used:0.1f}G/{total:0.1f}G\nSwap: {swapUsed}G/{swapTotal}G"; - }; - cpu = { - format = config.swarselsystems.cpuString; - min-length = 6; - interval = 5; - format-icons = [ "▁" "▂" "▃" "▄" "▅" "▆" "▇" "█" ]; - # on-click-right= "com.github.stsdc.monitor"; - on-click-right = "kitty -o confirm_os_window_close=0 btm"; - - }; - "custom/vpn" = { - format = "()"; - exec = "echo '{\"class\": \"connected\"}'"; - exec-if = "test -d /proc/sys/net/ipv4/conf/tun0"; - return-type = "json"; - interval = 5; - }; - battery = { - states = { - "warning" = 60; - "error" = 30; - "critical" = 15; - }; - interval = 5; - format = "{icon} {capacity}%"; - format-charging = "{capacity}% "; - format-plugged = "{capacity}% "; - format-icons = [ - "" - "" - "" - "" - "" - ]; - on-click-right = "wlogout -p layer-shell"; - }; - disk = { - interval = 30; - format = "Disk {percentage_used:2}%"; - path = "/"; - states = { - "warning" = 80; - "critical" = 90; - }; - tooltip-format = "{used} used out of {total} on {path} ({percentage_used}%)\n{free} free on {path} ({percentage_free}%)"; - }; - tray = { - icon-size = 20; - }; - network = { - interval = 5; - format-wifi = "{signalStrength}% "; - format-ethernet = ""; - format-linked = "{ifname} (No IP) "; - format-disconnected = "Disconnected ⚠"; - format-alt = "{ifname}: {ipaddr}/{cidr}"; - tooltip-format-ethernet = "{ifname} via {gwaddr}: {essid} {ipaddr}/{cidr}\n\n⇡{bandwidthUpBytes} ⇣{bandwidthDownBytes}"; - tooltip-format-wifi = "{ifname} via {gwaddr}: {essid} {ipaddr}/{cidr} \n{signaldBm}dBm @ {frequency}MHz\n\n⇡{bandwidthUpBytes} ⇣{bandwidthDownBytes}"; - }; - }; - }; - style = builtins.readFile (self + /programs/waybar/style.css); - }; - } -#+end_src - -**** Firefox -:PROPERTIES: -:CUSTOM_ID: h:fbec0bd4-690b-4f79-8b2b-a40263760a96 -:END: - -Setting up firefox along with some policies that are important to me (mostly disabling telemetry related stuff as well as Pocket). I also enable some integrations that enable super useful packages, namely =tridactyl= and =browserpass=. - -Also, using NUR with rycee's firefox addons, it is very convenient for me to add firefox addons here that will be automatically installed. - -Also, I setup some search aliases for functions I often use, such as NixOS options search (=@no=) - -I used to build the firefox addon =bypass-paywalls-clean= myself here, but the maintainer always deletes old packages, and it became a chore for me to maintain here, so I no longer do that. - -#+begin_src nix :tangle profiles/common/home/firefox.nix - { self, pkgs, lib, ... }: - let - lock-false = { - Value = false; - Status = "locked"; - }; - lock-true = { - Value = true; - Status = "locked"; - }; - in - { - programs.firefox = { - enable = true; - package = pkgs.firefox; # uses overrides - policies = { - # CaptivePortal = false; - AppAutoUpdate = false; - BackgroundAppUpdate = false; - DisableBuiltinPDFViewer = true; - DisableFirefoxStudies = true; - DisablePocket = true; - DisableFirefoxScreenshots = true; - DisableTelemetry = true; - DisableFirefoxAccounts = false; - DisableProfileImport = true; - DisableProfileRefresh = true; - DisplayBookmarksToolbar = "always"; - DontCheckDefaultBrowser = true; - NoDefaultBookmarks = true; - OfferToSaveLogins = false; - OfferToSaveLoginsDefault = false; - PasswordManagerEnabled = false; - DisableMasterPasswordCreation = true; - ExtensionUpdate = false; - EnableTrackingProtection = { - Value = true; - Locked = true; - Cryptomining = true; - Fingerprinting = true; - EmailTracking = true; - # Exceptions = ["https://example.com"] - }; - PDFjs = { - Enabled = false; - EnablePermissions = false; - }; - Handlers = { - mimeTypes."application/pdf".action = "saveToDisk"; - }; - extensions = { - pdf = { - action = "useHelperApp"; - ask = true; - handlers = [ - { - name = "GNOME Document Viewer"; - path = "${pkgs.evince}/bin/evince"; - } - ]; - }; - }; - FirefoxHome = { - Search = true; - TopSites = true; - SponsoredTopSites = false; - Highlights = true; - Pocket = false; - SponsoredPocket = false; - Snippets = false; - Locked = true; - }; - FirefoxSuggest = { - WebSuggestions = false; - SponsoredSuggestions = false; - ImproveSuggest = false; - Locked = true; - }; - SanitizeOnShutdown = { - Cache = true; - Cookies = false; - Downloads = true; - FormData = true; - History = false; - Sessions = false; - SiteSettings = false; - OfflineApps = true; - Locked = true; - }; - SearchEngines = { - PreventInstalls = true; - Remove = [ - "Bing" # Fuck you - ]; - }; - UserMessaging = { - ExtensionRecommendations = false; # Don’t recommend extensions while the user is visiting web pages - FeatureRecommendations = false; # Don’t recommend browser features - Locked = true; # Prevent the user from changing user messaging preferences - MoreFromMozilla = false; # Don’t show the “More from Mozilla” section in Preferences - SkipOnboarding = true; # Don’t show onboarding messages on the new tab page - UrlbarInterventions = false; # Don’t offer suggestions in the URL bar - WhatsNew = false; # Remove the “What’s New” icon and menuitem - }; - ExtensionSettings = { - "3rdparty".Extensions = { - # https://github.com/gorhill/uBlock/blob/master/platform/common/managed_storage.json - "uBlock0@raymondhill.net".adminSettings = { - userSettings = rec { - uiTheme = "dark"; - uiAccentCustom = true; - uiAccentCustom0 = "#0C8084"; - cloudStorageEnabled = lib.mkForce false; - importedLists = [ - "https://filters.adtidy.org/extension/ublock/filters/3.txt" - "https://github.com/DandelionSprout/adfilt/raw/master/LegitimateURLShortener.txt" - ]; - externalLists = lib.concatStringsSep "\n" importedLists; - }; - selectedFilterLists = [ - "CZE-0" - "adguard-generic" - "adguard-annoyance" - "adguard-social" - "adguard-spyware-url" - "easylist" - "easyprivacy" - "https://github.com/DandelionSprout/adfilt/raw/master/LegitimateURLShortener.txt" - "plowe-0" - "ublock-abuse" - "ublock-badware" - "ublock-filters" - "ublock-privacy" - "ublock-quick-fixes" - "ublock-unbreak" - "urlhaus-1" - ]; - }; - }; - - }; - - }; - - profiles.default = { - id = 0; - isDefault = true; - userChrome = builtins.readFile (self + /programs/firefox/chrome/userChrome.css); - extensions = with pkgs.nur.repos.rycee.firefox-addons; [ - tridactyl - tampermonkey - sidebery - browserpass - clearurls - darkreader - enhancer-for-youtube - istilldontcareaboutcookies - translate-web-pages - ublock-origin - reddit-enhancement-suite - sponsorblock - web-archives - single-file - widegithub - enhanced-github - unpaywall - don-t-fuck-with-paste - plasma-integration - (buildFirefoxXpiAddon { - pname = "shortkeys"; - version = "4.0.2"; - addonId = "Shortkeys@Shortkeys.com"; - url = "https://addons.mozilla.org/firefox/downloads/file/3673761/shortkeys-4.0.2.xpi"; - sha256 = "c6fe12efdd7a871787ac4526eea79ecc1acda8a99724aa2a2a55c88a9acf467c"; - meta = with lib; - { - description = "Easily customizable custom keyboard shortcuts for Firefox. To configure this addon go to Addons (ctrl+shift+a) ->Shortkeys ->Options. Report issues here (please specify that the issue is found in Firefox): https://github.com/mikecrittenden/shortkeys"; - mozPermissions = [ - "tabs" - "downloads" - "clipboardWrite" - "browsingData" - "storage" - "bookmarks" - "sessions" - "" - ]; - platforms = platforms.all; - }; - }) - ]; - - settings = { - "extensions.autoDisableScopes" = 0; - "browser.bookmarks.showMobileBookmarks" = lock-true; - "toolkit.legacyUserProfileCustomizations.stylesheets" = lock-true; - "browser.search.suggest.enabled" = lock-false; - "browser.search.suggest.enabled.private" = lock-false; - "browser.urlbar.suggest.searches" = lock-false; - "browser.urlbar.showSearchSuggestionsFirst" = lock-false; - "browser.topsites.contile.enabled" = lock-false; - "browser.newtabpage.activity-stream.feeds.section.topstories" = lock-false; - "browser.newtabpage.activity-stream.feeds.snippets" = lock-false; - "browser.newtabpage.activity-stream.section.highlights.includePocket" = lock-false; - "browser.newtabpage.activity-stream.section.highlights.includeBookmarks" = lock-false; - "browser.newtabpage.activity-stream.section.highlights.includeDownloads" = lock-false; - "browser.newtabpage.activity-stream.section.highlights.includeVisited" = lock-false; - "browser.newtabpage.activity-stream.showSponsored" = lock-false; - "browser.newtabpage.activity-stream.system.showSponsored" = lock-false; - "browser.newtabpage.activity-stream.showSponsoredTopSites" = lock-false; - }; - - search = { - default = "Kagi"; - privateDefault = "Kagi"; - engines = { - "Kagi" = { - urls = [{ - template = "https://kagi.com/search"; - params = [ - { name = "q"; value = "{searchTerms}"; } - ]; - }]; - iconUpdateURL = "https://kagi.com/favicon.ico"; - updateInterval = 24 * 60 * 60 * 1000; # every day - definedAliases = [ "@k" ]; - }; - - "Nix Packages" = { - urls = [{ - template = "https://search.nixos.org/packages"; - params = [ - { name = "type"; value = "packages"; } - { name = "query"; value = "{searchTerms}"; } - ]; - }]; - icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg"; - definedAliases = [ "@np" ]; - }; - - "NixOS Wiki" = { - urls = [{ - template = "https://nixos.wiki/index.php?search={searchTerms}"; - }]; - iconUpdateURL = "https://nixos.wiki/favicon.png"; - updateInterval = 24 * 60 * 60 * 1000; # every day - definedAliases = [ "@nw" ]; - }; - - "NixOS Options" = { - urls = [{ - template = "https://search.nixos.org/options"; - params = [ - { name = "query"; value = "{searchTerms}"; } - ]; - }]; - - icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg"; - definedAliases = [ "@no" ]; - }; - - "Home Manager Options" = { - urls = [{ - template = "https://home-manager-options.extranix.com/"; - params = [ - { name = "query"; value = "{searchTerms}"; } - ]; - }]; - - icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg"; - definedAliases = [ "@hm" "@ho" "@hmo" ]; - }; - - "Google".metaData.alias = "@g"; - }; - force = true; # this is required because otherwise the search.json.mozlz4 symlink gets replaced on every firefox restart - }; - }; - }; - } -#+end_src - -**** Services -:PROPERTIES: -:CUSTOM_ID: h:387c3a82-1fb1-4c0f-8051-874e2acb8804 -:END: - -Services that can be defined through home-manager should be defined here. - -***** gnome-keyring -:PROPERTIES: -:CUSTOM_ID: h:cb812c8a-247c-4ce5-a00c-59332c2f5fb9 -:END: - -Used for storing sessions in e.g. Nextcloud - -#+begin_src nix :tangle profiles/common/home/gnome-keyring.nix - { lib, config, ... }: - { - services.gnome-keyring = lib.mkIf (!config.swarselsystems.isNixos) { - enable = true; - }; - } -#+end_src - -***** KDE Connect -:PROPERTIES: -:CUSTOM_ID: h:be6afd89-9e1e-40b6-8542-5c07a0ab780d -:END: - -This enables phone/computer communication, including sending clipboard, files etc. Sadly on Wayland many of the features are broken (like remote control). - -#+begin_src nix :tangle profiles/common/home/kdeconnect.nix - _: - { - services.kdeconnect = { - enable = true; - indicator = true; - }; - - } -#+end_src - -***** Mako -:PROPERTIES: -:CUSTOM_ID: h:99d05729-df35-4958-9940-3319d6a41359 -:END: - -Desktop notifications! - -The `extraConfig` section here CANNOT be reindented. This has something to do with how nix handles multiline strings, when indented Mako will fail to start. This might be a mako bug as well. - -#+begin_src nix :tangle profiles/common/home/mako.nix - _: - { - services.mako = { - enable = true; - # backgroundColor = "#2e3440"; - # borderColor = "#88c0d0"; - borderRadius = 15; - borderSize = 1; - defaultTimeout = 5000; - height = 150; - icons = true; - ignoreTimeout = true; - layer = "overlay"; - maxIconSize = 64; - sort = "-time"; - width = 300; - # font = "monospace 10"; - extraConfig = '' - [urgency=low] - border-color=#cccccc - [urgency=normal] - border-color=#d08770 - [urgency=high] - border-color=#bf616a - default-timeout=3000 - [category=mpd] - default-timeout=2000 - group-by=category - ''; - }; - } -#+end_src - -***** yubikey-touch-detector -:PROPERTIES: -:CUSTOM_ID: h:1598c90b-f195-41a0-9132-94612edf3586 -:END: - -#+begin_src nix :tangle profiles/common/home/yubikey-touch-detector.nix - { pkgs, ... }: - { - systemd.user.services.yubikey-touch-detector = { - Unit = { - Description = "Detects when your YubiKey is waiting for a touch"; - Requires = [ "yubikey-touch-detector.socket" ]; - }; - Service = { - ExecStart = "${pkgs.yubikey-touch-detector}/bin/yubikey-touch-detector --libnotify"; - EnvironmentFile = "-%E/yubikey-touch-detector/service.conf"; - }; - Install = { - Also = [ "yubikey-touch-detector.socket" ]; - WantedBy = [ "default.target" ]; - }; - }; - systemd.user.sockets.yubikey-touch-detector = { - Unit = { - Description = "Unix socket activation for YubiKey touch detector service"; - }; - Socket = { - ListenStream = "%t/yubikey-touch-detector.socket"; - RemoveOnStop = true; - }; - Install = { - WantedBy = [ "sockets.target" ]; - }; - }; - } -#+end_src - -**** Sway -:PROPERTIES: -:CUSTOM_ID: h:02df9dfc-d1af-4a37-a7a0-d8da0af96a20 -:END: - -I am currently using SwayFX, which adds some nice effects to sway, like rounded corners and hiding the separator between title and content of a window. - -Currently, I am too lazy to explain every option here, but most of it is very self-explaining in any case. - -#+begin_src nix :tangle profiles/common/home/sway.nix - { config, lib, ... }: - let - inherit (config.swarselsystems) monitors; - eachMonitor = _name: monitor: { - inherit (monitor) name; - value = builtins.removeAttrs monitor [ "workspace" "name" "output" ]; - }; - eachOutput = _name: monitor: { - inherit (monitor) name; - value = builtins.removeAttrs monitor [ "mode" "name" "scale" "transform" "position" ]; - }; - workplaceSets = lib.mapAttrs' eachOutput monitors; - workplaceOutputs = map (key: lib.getAttr key workplaceSets) (lib.attrNames workplaceSets); - in - { - wayland.windowManager.sway = { - enable = true; - checkConfig = false; # delete this line once SwayFX is fixed upstream - package = lib.mkIf config.swarselsystems.isNixos null; - systemd = { - enable = true; - xdgAutostart = true; - }; - wrapperFeatures.gtk = true; - config = rec { - modifier = "Mod4"; - terminal = "kitty"; - menu = "fuzzel"; - bars = [{ - command = "waybar"; - mode = "hide"; - hiddenState = "hide"; - position = "top"; - extraConfig = "modifier Mod4"; - }]; - keybindings = - let - inherit (config.wayland.windowManager.sway.config) modifier; - in - lib.recursiveUpdate - { - "${modifier}+q" = "kill"; - "${modifier}+f" = "exec firefox"; - "${modifier}+Shift+f" = "exec swaymsg fullscreen"; - "${modifier}+Space" = "exec fuzzel"; - "${modifier}+Shift+Space" = "floating toggle"; - "${modifier}+e" = "exec emacsclient -nquc -a emacs -e \"(dashboard-open)\""; - "${modifier}+Shift+m" = "exec emacsclient -nquc -a emacs -e \"(mu4e)\""; - "${modifier}+Shift+c" = "exec emacsclient -nquc -a emacs -e \"(swarsel/open-calendar)\""; - "${modifier}+m" = "exec swarselcheck -s"; - "${modifier}+x" = "exec swarselcheck -k"; - "${modifier}+d" = "exec swarselcheck -d"; - "${modifier}+w" = "exec swarselcheck -e"; - "${modifier}+Shift+t" = "exec opacitytoggle"; - "${modifier}+Shift+F12" = "move scratchpad"; - "${modifier}+F12" = "scratchpad show"; - "${modifier}+c" = "exec qalculate-gtk"; - "${modifier}+p" = "exec pass-fuzzel"; - "${modifier}+o" = "exec pass-fuzzel --otp"; - "${modifier}+Shift+p" = "exec pass-fuzzel --type"; - "${modifier}+Shift+o" = "exec pass-fuzzel --otp --type"; - "${modifier}+Ctrl+p" = "exec 1password --quick-acces"; - "${modifier}+Escape" = "mode $exit"; - "${modifier}+Shift+Escape" = "exec kitty -o confirm_os_window_close=0 btm"; - "${modifier}+h" = "exec hyprpicker | wl-copy"; - "${modifier}+s" = "exec grim -g \"$(slurp)\" -t png - | wl-copy -t image/png"; - "${modifier}+Shift+s" = "exec slurp | grim -g - Pictures/Screenshots/$(date +'screenshot_%Y-%m-%d-%H%M%S.png')"; - "${modifier}+1" = "workspace 1:一"; - "${modifier}+Shift+1" = "move container to workspace 1:一"; - "${modifier}+2" = "workspace 2:二"; - "${modifier}+Shift+2" = "move container to workspace 2:二"; - "${modifier}+3" = "workspace 3:三"; - "${modifier}+Shift+3" = "move container to workspace 3:三"; - "${modifier}+4" = "workspace 4:四"; - "${modifier}+Shift+4" = "move container to workspace 4:四"; - "${modifier}+5" = "workspace 5:五"; - "${modifier}+Shift+5" = "move container to workspace 5:五"; - "${modifier}+6" = "workspace 6:六"; - "${modifier}+Shift+6" = "move container to workspace 6:六"; - "${modifier}+7" = "workspace 7:七"; - "${modifier}+Shift+7" = "move container to workspace 7:七"; - "${modifier}+8" = "workspace 8:八"; - "${modifier}+Shift+8" = "move container to workspace 8:八"; - "${modifier}+9" = "workspace 9:九"; - "${modifier}+Shift+9" = "move container to workspace 9:九"; - "${modifier}+0" = "workspace 10:十"; - "${modifier}+Shift+0" = "move container to workspace 10:十"; - "${modifier}+Ctrl+m" = "workspace 11:M"; - "${modifier}+Ctrl+Shift+m" = "move container to workspace 11:M"; - "${modifier}+Ctrl+s" = "workspace 12:S"; - "${modifier}+Ctrl+Shift+s" = "move container to workspace 12:S"; - "${modifier}+Ctrl+e" = "workspace 13:E"; - "${modifier}+Ctrl+Shift+e" = "move container to workspace 13:E"; - "${modifier}+Ctrl+t" = "workspace 14:T"; - "${modifier}+Ctrl+Shift+t" = "move container to workspace 14:T"; - "${modifier}+Ctrl+l" = "workspace 15:L"; - "${modifier}+Ctrl+Shift+l" = "move container to workspace 15:L"; - "${modifier}+Ctrl+f" = "workspace 16:F"; - "${modifier}+Ctrl+Shift+f" = "move container to workspace 16:F"; - "${modifier}+Left" = "focus left"; - "${modifier}+Right" = "focus right"; - "${modifier}+Down" = "focus down"; - "${modifier}+Up" = "focus up"; - "${modifier}+Shift+Left" = "move left 40px"; - "${modifier}+Shift+Right" = "move right 40px"; - "${modifier}+Shift+Down" = "move down 40px"; - "${modifier}+Shift+Up" = "move up 40px"; - "${modifier}+Ctrl+Shift+c" = "reload"; - "${modifier}+Shift+e" = "exec swaynag -t warning -m 'You pressed the exit shortcut. Do you really want to exit sway? This will end your Wayland session.' -b 'Yes, exit sway' 'swaymsg exit'"; - "${modifier}+r" = "mode resize"; - "${modifier}+Return" = "exec kitty"; - "${modifier}+Print" = "exec screenshare"; - # "XF86AudioRaiseVolume" = "exec pa 5%"; - "XF86AudioRaiseVolume" = "exec pamixer -i 5"; - # "XF86AudioLowerVolume" = "exec pactl set-sink-volume @DEFAULT_SINK@ -5%"; - "XF86AudioLowerVolume" = "exec pamixer -d 5"; - # "XF86AudioMute" = "exec pactl set-sink-mute @DEFAULT_SINK@ toggle"; - "XF86AudioMute" = "exec pamixer -t"; - "XF86MonBrightnessUp" = "exec brightnessctl set +5%"; - "XF86MonBrightnessDown" = "exec brightnessctl set 5%-"; - "XF86Display" = "exec wl-mirror eDP-1"; - } - config.swarselsystems.keybindings; - modes = { - resize = { - Down = "resize grow height 10 px or 10 ppt"; - Escape = "mode default"; - Left = "resize shrink width 10 px or 10 ppt"; - Return = "mode default"; - Right = "resize grow width 10 px or 10 ppt"; - Up = "resize shrink height 10 px or 10 ppt"; - Tab = "move position center, resize set width 50 ppt height 50 ppt"; - }; - }; - defaultWorkspace = "workspace 1:一"; - output = lib.mapAttrs' eachMonitor monitors; - input = config.swarselsystems.standardinputs; - workspaceOutputAssign = workplaceOutputs; - startup = config.swarselsystems.startup ++ [ - { command = "kitty -T kittyterm"; } - { command = "sleep 60; kitty -T spotifytui -o confirm_os_window_close=0 spotify_player"; } - ]; - window = { - border = 1; - titlebar = false; - }; - assigns = { - "15:L" = [{ app_id = "teams-for-linux"; }]; - }; - floating = { - border = 1; - criteria = [ - { app_id = "qalculate-gtk"; } - { app_id = "blueman"; } - { app_id = "pavucontrol"; } - { app_id = "syncthingtray"; } - { app_id = "Element"; } - { class = "1Password"; } - { app_id = "com.nextcloud.desktopclient.nextcloud"; } - { title = "(?:Open|Save) (?:File|Folder|As)"; } - { title = "^Add$"; } - { title = "^Picture-in-Picture$"; } - { title = "Syncthing Tray"; } - { app_id = "vesktop"; } - { window_role = "pop-up"; } - { window_role = "bubble"; } - { window_role = "dialog"; } - { window_role = "task_dialog"; } - { window_role = "menu"; } - { window_role = "Preferences"; } - ]; - titlebar = false; - }; - window = { - commands = [ - { - command = "opacity 0.95"; - criteria = { - class = ".*"; - }; - } - { - command = "opacity 1"; - criteria = { - app_id = "Gimp-2.10"; - }; - } - { - command = "opacity 0.99"; - criteria = { - app_id = "firefox"; - }; - } - { - command = "opacity 0.99"; - criteria = { - app_id = "chromium-browser"; - }; - } - { - command = "sticky enable, shadows enable"; - criteria = { - title = "^Picture-in-Picture$"; - }; - } - { - command = "resize set width 60 ppt height 60 ppt, opacity 0.8, sticky enable, border normal, move container to scratchpad"; - criteria = { - title = "^kittyterm$"; - }; - } - { - command = "resize set width 60 ppt height 60 ppt, opacity 0.95, sticky enable, border normal, move container to scratchpad"; - criteria = { - title = "^spotifytui$"; - }; - } - { - - command = "resize set width 60 ppt height 60 ppt, sticky enable, move container to scratchpad"; - criteria = { - class = "Spotify"; - }; - } - { - command = "resize set width 60 ppt height 60 ppt, sticky enable"; - criteria = { - app_id = "vesktop"; - }; - } - { - command = "resize set width 60 ppt height 60 ppt, sticky enable"; - criteria = { - class = "Element"; - }; - } - # { - # command = "resize set width 60 ppt height 60 ppt, sticky enable, move container to scratchpad"; - # criteria = { - # app_id="^$"; - # class="^$"; - # }; - # } - ]; - }; - gaps = { - inner = 5; - }; - }; - extraSessionCommands = '' - export SDL_VIDEODRIVER=wayland - export QT_QPA_PLATFORM=wayland - export QT_WAYLAND_DISABLE_WINDOWDECORATION="1" - export _JAVA_AWT_WM_NONREPARENTING=1 - export XDG_CURRENT_DESKTOP=sway - export XDG_SESSION_DESKTOP=sway - export QTWEBENGINE_CHROMIUM_FLAGS="--no-sandbox"; - export ANKI_WAYLAND=1; - export OBSIDIAN_USE_WAYLAND=1; - ''; - # extraConfigEarly = " - # exec systemctl --user import-environment DISPLAY WAYLAND_DISPLAY SWAYSOCK - # exec hash dbus-update-activation-environment 2>/dev/null && dbus-update-activation-environment --systemd DISPLAY WAYLAND_DISPLAY SWAYSOCK - # "; - extraConfig = - let - inherit (config.wayland.windowManager.sway.config) modifier; - swayfxSettings = config.swarselsystems.swayfxConfig; - in - " - exec_always autotiling - set $exit \"exit: [s]leep, [l]ock, [p]oweroff, [r]eboot, [u]ser logout\" - mode $exit { - - bindsym --to-code { - s exec \"systemctl suspend\", mode \"default\" - l exec \"swaylock --screenshots --clock --effect-blur 7x5 --effect-vignette 0.5:0.5 --fade-in 0.2 --daemonize && systemctl suspend \", mode \"default \" - p exec \"systemctl poweroff\" - r exec \"systemctl reboot\" - u exec \"swaymsg exit\" - - Return mode \"default\" - Escape mode \"default\" - ${modifier}+Escape mode \"default\" - } - } - - exec systemctl --user import-environment - exec swayidle -w - - - ${swayfxSettings} - - "; - }; - } -#+end_src - -**** gpg-agent -:PROPERTIES: -:CUSTOM_ID: h:7d384e3b-1be7-4644-b304-ada4af0b692b -:END: - -Settinfs that are needed for the gpg-agent. Also we are enabling emacs support for unlocking my Yubikey here. - -#+begin_src nix :tangle profiles/common/home/gpg-agent.nix - { self, pkgs, ... }: - { - services.gpg-agent = { - enable = true; - enableSshSupport = true; - enableExtraSocket = true; - pinentryPackage = pkgs.pinentry.gtk2; - defaultCacheTtl = 600; - maxCacheTtl = 7200; - extraConfig = '' - allow-loopback-pinentry - allow-emacs-pinentry - ''; - sshKeys = [ - "4BE7925262289B476DBBC17B76FD3810215AE097" - ]; - }; - - programs.gpg = { - enable = true; - publicKeys = [ - { - source = "${self}/secrets/keys/gpg/gpg-public-key-0x76FD3810215AE097.asc"; - trust = 5; - } - ]; - }; - - # assure correct permissions - systemd.user.tmpfiles.rules = [ - "d /home/swarsel/.gnupg 700 swarsel users" - ]; - - } -#+end_src - -**** gammastep -:PROPERTIES: -:CUSTOM_ID: h:74e236be-a977-4d38-b8c5-0b9feef8af91 -:END: - -This service changes the screen hue at night. I am not sure if that really does something, but I like the color anyways. - -#+begin_src nix :tangle profiles/common/home/gammastep.nix - _: - { - services.gammastep = { - enable = true; - provider = "manual"; - latitude = 48.210033; - longitude = 16.363449; - }; - } -#+end_src - -*** Server -:PROPERTIES: -:CUSTOM_ID: h:b1a00339-6e9b-4ae4-b5dc-6fd5669a2ddb -:END: - -**** Imports -:PROPERTIES: -:CUSTOM_ID: h:7b4ee01a-b505-47da-8fb9-0b41285d0eab -:END: - -This section sets up all the imports that are used in the home-manager section. - -#+begin_src nix :tangle profiles/server/home/default.nix - { self, ... }: - let - profilesPath = "${self}/profiles"; - in - { - imports = [ - "${profilesPath}/common/home/settings.nix" - ./symlink.nix - ]; - } -#+end_src - -**** Linking dotfiles -:PROPERTIES: -:CUSTOM_ID: h:9fac0904-b615-4d9d-9bae-54a6691999c3 -:END: - -This section should be used in order to symlink already existing configuration files using `home.file` and setting session variables using `home.sessionVariables`. - -As for the `home.sessionVariables`, it should be noted that environment variables that are needed at system start should NOT be loaded here, but instead in `programs.zsh.config.extraSessionCommands` (in the home-manager programs section). This is also where all the wayland related variables are stored. - -#+begin_src nix :tangle profiles/server/home/symlink.nix - { self, ... }: - { - home.file = { - "init.el" = { - source = self + /programs/emacs/server.el; - target = ".emacs.d/init.el"; - }; - }; - } -#+end_src - -*** Darwin -:PROPERTIES: -:CUSTOM_ID: h:e0536bff-2552-4ac4-a34a-a23937a2c30f -:END: - -**** Imports -:PROPERTIES: -:CUSTOM_ID: h:cff37bdf-4f22-419a-af4e-2665ede9add0 -:END: - -This section sets up all the imports that are used in the home-manager section. - -#+begin_src nix :tangle profiles/darwin/home/default.nix - { self, ... }: - let - profilesPath = "${self}/profiles"; - in - { - imports = [ - "${profilesPath}/common/home/settings.nix" - ]; - } -#+end_src - -*** Optional -:PROPERTIES: -:CUSTOM_ID: h:be623200-557e-4bb7-bb11-1ec5d76c6b8b -:END: - -Akin to the optional NixOS modules. - -**** Gaming -:PROPERTIES: -:CUSTOM_ID: h:84fd7029-ecb6-4131-9333-289982f24ffa -:END: - -The rest of the settings is at [[#h:fb3f3e01-7df4-4b06-9e91-aa9cac61a431][gaming]]. - -#+begin_src nix :tangle profiles/optional/home/gaming.nix - { pkgs, ... }: - { - # specialisation = { - # gaming.configuration = { - home.packages = with pkgs; [ - stable.lutris - wine - libudev-zero - dwarfs - fuse-overlayfs - # steam - # steam-run - patchelf - gamescope - vulkan-tools - moonlight-qt - ns-usbloader - - quark-goldleaf - # gog games installing - heroic - - # minecraft - prismlauncher # has overrides - temurin-bin-17 - - pokefinder - retroarch - ]; - # }; - # }; - } - -#+end_src - -**** Work -:PROPERTIES: -:CUSTOM_ID: h:f0b2ea93-94c8-48d8-8d47-6fe58f58e0e6 -:END: - -The rest of the settings is at [[#h:bbf2ecb6-c8ff-4462-b5d5-d45b28604ddf][work]]. Here, I am setting up the different firefox profiles that I need for the SSO sites that I need to access at work as well as a few ssh shorthands. - -#+begin_src nix :tangle profiles/optional/home/work.nix :noweb yes - { config, pkgs, lib, ... }: - { - home.packages = with pkgs; [ - stable.teams-for-linux - shellcheck - dig - docker - postman - rclone - awscli2 - libguestfs-with-appliance - ]; - - home.sessionVariables = { - DOCUMENT_DIR_PRIV = lib.mkForce "${config.home.homeDirectory}/Documents/Private"; - DOCUMENT_DIR_WORK = lib.mkForce "${config.home.homeDirectory}/Documents/Work"; - }; - programs = { - git.userEmail = "leon.schwarzaeugl@imba.oeaw.ac.at"; - - zsh = { - cdpath = [ - "~/Documents/Work" - ]; - dirHashes = { - d = "$HOME/.dotfiles"; - w = "$HOME/Documents/Work"; - s = "$HOME/.dotfiles/secrets"; - pr = "$HOME/Documents/Private"; - ac = "$HOME/.ansible/collections/ansible_collections/vbc/linux/roles"; - }; - }; - - - ssh = { - matchBlocks = { - "uc" = { - hostname = "uc.clip.vbc.ac.at"; - user = "stack"; - }; - "uc-stg" = { - hostname = "uc.staging.clip.vbc.ac.at"; - user = "stack"; - }; - "cbe" = { - hostname = "cbe.vbc.ac.at"; - user = "dc_adm_schwarzaeugl"; - }; - "cbe-stg" = { - hostname = "cbe.staging.vbc.ac.at"; - user = "dc_adm_schwarzaeugl"; - }; - "*.vbc.ac.at" = { - user = "dc_adm_schwarzaeugl"; - }; - }; - }; - - firefox = { - profiles = { - dc_adm = lib.recursiveUpdate { id = 1; } config.swarselsystems.firefox; - cl_adm = lib.recursiveUpdate { id = 2; } config.swarselsystems.firefox; - ws_adm = lib.recursiveUpdate { id = 3; } config.swarselsystems.firefox; - }; - }; - - chromium = { - enable = true; - package = pkgs.chromium; - - extensions = [ - # 1password - "gejiddohjgogedgjnonbofjigllpkmbf" - # dark reader - "eimadpbcbfnmbkopoojfekhnkhdbieeh" - # ublock origin - "cjpalhdlnbpafiamejdnhcphjbkeiagm" - # i still dont care about cookies - "edibdbjcniadpccecjdfdjjppcpchdlm" - # browserpass - "naepdomgkenhinolocfifgehidddafch" - ]; - }; - }; - - xdg = { - mimeApps = { - defaultApplications = { - "x-scheme-handler/msteams" = [ "teams-for-linux.desktop"] ; - }; - }; - desktopEntries = - let - terminal = false; - categories = [ "Application" ]; - icon = "firefox"; - in - { - firefox_dc = { - name = "Firefox (dc_adm)"; - genericName = "Firefox dc"; - exec = "firefox -p dc_adm"; - inherit terminal categories icon; - }; - - firefox_ws = { - name = "Firefox (ws_adm)"; - genericName = "Firefox ws"; - exec = "firefox -p ws_adm"; - inherit terminal categories icon; - }; - - firefox_cl = { - name = "Firefox (cl_adm)"; - genericName = "Firefox cl"; - exec = "firefox -p cl_adm"; - inherit terminal categories icon; - }; - - }; - }; - - } #+end_src @@ -10885,7 +24423,8 @@ In the end, we need to restore those values to values that will work during norm Also packed into the hook function is the line =(fset 'epg-wait-for-status 'ignore)=. This line is needed at the end of the configuration in order to allow for my Yubikey to be used to encrypt and decrypt =.gpg= files. Without it, Emacs will just hang forever and basically crash. -#+begin_src emacs-lisp :tangle programs/emacs/early-init.el :mkdirp yes +#+begin_src emacs-lisp :tangle files/emacs/early-init.el :mkdirp yes +;; -*- lexical-binding: t; -*- (defvar swarsel-file-name-handler-alist file-name-handler-alist) (defvar swarsel-vc-handled-backends vc-handled-backends) @@ -10897,9 +24436,7 @@ Also packed into the hook function is the line =(fset 'epg-wait-for-status 'igno (add-hook 'emacs-startup-hook (lambda () (progn - ;; (setq gc-cons-threshold (* 1000 1000 8) - ;; (setq gc-cons-threshold #x40000000 - (setq gc-cons-threshold (* 32 1024 1024) + (setq gc-cons-threshold (* 32 1024 1024) gc-cons-percentage 0.1 jit-lock-defer-time 0.05 read-process-output-max (* 1024 1024) @@ -10920,7 +24457,7 @@ We also make require immediate compilation of native code. For the =default-frame-alist=, I used to also set ='(right-divider-width . 4)= and ='(bottom-divider-width . 4)=, but I did not like the look of the divider bar and usually know my splits anyways, so this is no longer set. -#+begin_src emacs-lisp :tangle programs/emacs/early-init.el :mkdirp yes +#+begin_src emacs-lisp :tangle files/emacs/early-init.el :mkdirp yes (tool-bar-mode 0) (menu-bar-mode 0) (scroll-bar-mode 0) @@ -10969,7 +24506,7 @@ These keybinds exist to make Emacs work well in terminal mode. However, most of NOTE: To use these keybinds, you need to enclose the binding in angled brackets (=<>=). Then they can be used normally -#+begin_src emacs-lisp :tangle programs/emacs/early-init.el :mkdirp yes +#+begin_src emacs-lisp :tangle files/emacs/early-init.el :mkdirp yes (add-hook 'after-make-frame-functions @@ -11006,7 +24543,11 @@ In this section I define extra functions that I need. Some of these functions I Since I am rebinding the =C-z= hotkey for emacs-evil-state toggling, I want to have a function that still lets me perform this action quickly. +We set a keybinding to this in [[#h:2b827c27-0de7-45ed-9d9e-6c511e2c6bb5][Custom Keybindings]]. + + #+begin_src emacs-lisp +;; -*- lexical-binding: t; -*- (defun swarsel/toggle-evil-state () (interactive) @@ -11021,7 +24562,9 @@ Since I am rebinding the =C-z= hotkey for emacs-evil-state toggling, I want to h :CUSTOM_ID: h:1e0ee570-e509-4ecb-a3af-b75543731bb0 :END: -I often find myself bouncing between two buffers when I do not want to use a window split. This funnction simply jumps to the last used buffer. +I often find myself bouncing between two buffers when I do not want to use a window split. This function simply jumps to the last used buffer. + +We set a keybinding to this in [[#h:2b827c27-0de7-45ed-9d9e-6c511e2c6bb5][Custom Keybindings]]. #+begin_src emacs-lisp @@ -11063,14 +24606,18 @@ Used here: [[#h:b92a18cf-eec3-4605-a8c2-37133ade3574][mu4e]] (when-let ((dest (swarsel/mu4e-rfs--matching-address))) (cl-destructuring-bind (from-user from-addr) dest (setq user-mail-address from-addr) + (when (and (boundp 'user-mail-address) + (stringp user-mail-address) + (string-equal user-mail-address (getenv "SWARSEL_MAIL_WORK"))) + (mml-secure-message-sign-smime)) (message-position-on-field "From") (message-beginning-of-line) (delete-region (point) (line-end-position)) (insert (format "%s <%s>" (or from-user user-full-name) from-addr))))))) (defun swarsel/mu4e-restore-default () - (setq user-mail-address "leon@swarsel.win" - user-full-name "Leon Schwarzäugl")) + (setq user-mail-address (getenv "SWARSEL_MAIL4") + user-full-name (getenv "SWARSEL_FULLNAME"))) #+end_src @@ -11106,6 +24653,8 @@ The below function avoids these problems. Originally I used the function =duplic However, this function does not work on regions. Later, I found a solution implemented by [[https://github.com/bbatsov/crux][crux]]. I do not need the whole package, so I just extracted the three functions I needed from it. +We set a keybinding to this in [[#h:2b827c27-0de7-45ed-9d9e-6c511e2c6bb5][Custom Keybindings]]. + #+begin_src emacs-lisp (defun crux-get-positions-of-line-or-region () @@ -11271,6 +24820,29 @@ This function was found here: [[https://www.reddit.com/r/emacs/comments/re31i6/h (define-key minibuffer-local-filename-completion-map [C-backspace] #'up-directory) +#+end_src +**** Magit: List directories using vertico/consult +:PROPERTIES: +:CUSTOM_ID: h:1f8bfddf-a12a-49c8-beaa-97baa47abb9f +:END: + +At work and when working on private projects, I often have to jump between several git repositories. This function fires up a picker that gets me to the magit overview page of that repository. + +We set a keybinding to this in [[#h:2b827c27-0de7-45ed-9d9e-6c511e2c6bb5][Custom Keybindings]]. + +#+begin_src emacs-lisp + + (defun swarsel/consult-magit-repos () + (interactive) + (require 'magit) + (let* ((repos (magit-list-repos)) + (repo (consult--read repos + :prompt "Magit repo: " + :require-match t + :history 'my/consult-magit-repos-history + :sort t))) + (magit-status repo))) + #+end_src **** org-mode: General setup :PROPERTIES: @@ -11283,17 +24855,10 @@ Used here: [[#h:877c9401-a354-4e44-a235-db1a90d19e00][General org-mode]] #+begin_src emacs-lisp - (defun swarsel/org-mode-setup () - ;; (org-indent-mode) - (variable-pitch-mode 1) - ;;(auto-fill-mode 0) - ;; (setq display-line-numbers-type 'relative - ;; display-line-numbers-current-absolute 1 - ;; display-line-numbers-width-start nil - ;; display-line-numbers-width 6 - ;; display-line-numbers-grow-only 1) - (add-hook 'org-tab-first-hook 'org-end-of-line) - (visual-line-mode 1)) + (defun swarsel/org-mode-setup () + (variable-pitch-mode 1) + (add-hook 'org-tab-first-hook 'org-end-of-line) + (visual-line-mode 1)) #+end_src **** org-mode: Visual-fill column @@ -11328,25 +24893,25 @@ This section handles everything that shoudld happen when I save =SwarselSystems. We set a hook that runs everytime we save the file. It would be a bit more efficient to only export and format when we enter a magit window for instance (since especially the html export takes times), however, since I cannot be sure to only ever commit from magit (I do indeed sometimes use git from the command line), I prefer this approach. #+begin_src emacs-lisp - (defun swarsel/run-formatting () - (interactive) - (let ((default-directory (expand-file-name "~/.dotfiles"))) - (shell-command "nixpkgs-fmt . > /dev/null"))) + (defun swarsel/run-formatting () + (interactive) + (let ((default-directory (expand-file-name "~/.dotfiles"))) + (shell-command "nixpkgs-fmt . > /dev/null"))) - (defun swarsel/org-babel-tangle-config () - (interactive) - (when (string-equal (buffer-file-name) - swarsel-swarsel-org-filepath) - ;; Dynamic scoping to the rescue - (let ((org-confirm-babel-evaluate nil)) - ;; (org-html-export-to-html) - (org-babel-tangle) - (swarsel/run-formatting) - ))) + (defun swarsel/org-babel-tangle-config () + (interactive) + (when (string-equal (buffer-file-name) + swarsel-swarsel-org-filepath) + ;; Dynamic scoping to the rescue + (let ((org-confirm-babel-evaluate nil)) + ;; (org-html-export-to-html) + (org-babel-tangle) + (swarsel/run-formatting) + ))) - (setq org-html-htmlize-output-type nil) + (setq org-html-htmlize-output-type nil) - ;; (add-hook 'org-mode-hook (lambda () (add-hook 'after-save-hook #'swarsel/org-babel-tangle-config))) + ;; (add-hook 'org-mode-hook (lambda () (add-hook 'after-save-hook #'swarsel/org-babel-tangle-config))) #+end_src @@ -11363,6 +24928,8 @@ Normally emacs cycles between three states: However, I want to be able to fold a single heading consistently. +We set a keybinding to this in [[#h:2b827c27-0de7-45ed-9d9e-6c511e2c6bb5][Custom Keybindings]]. + #+begin_src emacs-lisp (defun org-fold-outer () @@ -11404,114 +24971,7 @@ These functions are used here: [[#h:5653d693-ecca-4c95-9633-66b9e3241070][Corfu] #+end_src -**** python shell reloading -:PROPERTIES: -:CUSTOM_ID: h:291e43d9-eae2-4e23-8e38-160e223bf314 -:END: - -The standard Emacs behaviour for the Python process shell is a bit annoying. This is my attempt at making it show automatically on opening a python buffer and making it refresh on its own as well. This does not nicely work yet. - -#+begin_src emacs-lisp - - ;; run the python inferior shell immediately upon entering a python buffer - ;; (add-hook 'python-mode-hook 'swarsel/run-python) - - ;; (defun swarsel/run-python () - ;; (save-selected-window - ;; (switch-to-buffer-other-window (process-buffer (python-shell-get-or-create-process (python-shell-parse-command)))))) - - ;; reload python shell automatically - (defun my-python-shell-run () - (interactive) - (when (get-buffer-process "*Python*") - (set-process-query-on-exit-flag (get-buffer-process "*Python*") nil) - (kill-process (get-buffer-process "*Python*")) - ;; Uncomment If you want to clean the buffer too. - ;;(kill-buffer "*Python*") - ;; Not so fast! - (sleep-for 0.5)) - (run-python (python-shell-parse-command) nil nil) - (python-shell-send-buffer) - ;; Pop new window only if shell isnt visible - ;; in any frame. - (unless (get-buffer-window "*Python*" t) - (python-shell-switch-to-shell))) - - (defun my-python-shell-run-region () - (interactive) - (python-shell-send-region (region-beginning) (region-end)) - (python-shell-switch-to-shell)) - -#+end_src - -**** Nix common prefix bracketer -:PROPERTIES: -:CUSTOM_ID: h:79288251-3b8d-4bc4-ae2c-448fce709fbd -:END: - -This function searches for common delimiters in region and removes them, summarizing all captured lines by it. - -#+begin_src emacs-lisp - -(defun swarsel/prefix-block (start end) - (interactive "r") - (save-excursion - (goto-char start) - (setq start (line-beginning-position)) - (goto-char end) - (setq end (line-end-position)) - (let ((common-prefix (save-excursion - (goto-char start) - (if (re-search-forward "^\\([^.\n]+\\)\\." end t) - (match-string 1) - (error "No common prefix found"))))) - (save-excursion - (goto-char start) - (insert common-prefix " = {\n") - (goto-char (+ end (length common-prefix) 6)) - (insert "};\n") - (goto-char start) - (while (re-search-forward (concat "^" (regexp-quote common-prefix) "\\.") end t) - (replace-match "")))))) - -#+end_src - -**** Nix formatters -:PROPERTIES: -:CUSTOM_ID: h:a6b9dd66-571b-4916-8793-65b6a17afd76 -:END: - -This formats the org code block at =point= in accordance to the =nixpkgs-fmt= formatter - -#+begin_src emacs-lisp - - (defun swarsel/org-nixpkgs-fmt-block-lite () - (interactive) - (org-babel-mark-block) - (call-interactively 'nixpkgs-fmt-region)) - - - (defun swarsel/org-nixpkgs-fmt-block () - (interactive) - (save-excursion - (let* ((element (org-element-at-point)) - (begin (org-element-property :begin element)) - (end (org-element-property :end element)) - (lang (org-element-property :language element))) - (when lang - (goto-char begin) - (forward-line) - (insert "{") - (goto-char end) - (forward-line -1) - (beginning-of-line) - (forward-char -1) - (insert "}") - (org-babel-mark-block) - (call-interactively 'nixpkgs-fmt-region))))) -#+end_src - -**** Disable garbace collection while minibuffer is active +**** Disable garbage collection while minibuffer is active :PROPERTIES: :CUSTOM_ID: h:3c436647-71e6-441c-b452-d817ad2f8331 :END: @@ -11519,18 +24979,75 @@ This formats the org code block at =point= in accordance to the =nixpkgs-fmt= fo #+begin_src emacs-lisp - (defun swarsel/minibuffer-setup-hook () - (setq gc-cons-threshold most-positive-fixnum)) + (defun swarsel/minibuffer-setup-hook () + (setq gc-cons-threshold most-positive-fixnum)) - (defun swarsel/minibuffer-exit-hook () - (setq gc-cons-threshold (* 32 1024 1024))) + (defun swarsel/minibuffer-exit-hook () + (setq gc-cons-threshold (* 32 1024 1024))) - (add-hook 'minibuffer-setup-hook #'swarsel/minibuffer-setup-hook) - (add-hook 'minibuffer-exit-hook #'swarsel/minibuffer-exit-hook) + (add-hook 'minibuffer-setup-hook #'swarsel/minibuffer-setup-hook) + (add-hook 'minibuffer-exit-hook #'swarsel/minibuffer-exit-hook) #+end_src +**** Insert link to another header in org file +:PROPERTIES: +:CUSTOM_ID: h:06e70e44-502b-4a49-8b48-63c511f1c377 +:END: + +When writing this file, I often want to refer to a different section of the file. One way to do this is to =C-x O= (consult-org-heading) to get to said heading, then =C=c s= (org-store-link), finally =C-o= (evil-jump-backward) to get back to the origin and insert the link using =C-c C-l= (org-insert-link). + +These two scripts just let me do all of this in one step. I have styled the picker in a way that is similar to consult-org-heading. + +We set a keybinding to this in [[#h:2b827c27-0de7-45ed-9d9e-6c511e2c6bb5][Custom Keybindings]]. + +#+begin_src emacs-lisp + + (defun swarsel/org-colorize-outline (parents raw) + (let* ((palette ["#58B6ED" "#8BD49C" "#33CED8" "#4B9CCC" + "yellow" "orange" "salmon" "red"]) + (n (length parents)) + (colored-parents + (cl-mapcar + (lambda (p i) + (propertize p 'face `(:foreground ,(aref palette (mod i (length palette))) :weight bold))) + parents + (number-sequence 0 (1- n))))) + (concat + (when parents + (string-join colored-parents "/")) + (when parents "/") + (propertize raw 'face `(:foreground ,(aref palette (mod n (length palette))) + :weight bold))))) + + (defun swarsel/org-insert-link-to-heading () + (interactive) + (let ((candidates '())) + (org-map-entries + (lambda () + (let* ((raw (org-get-heading t t t t)) + (parents (org-get-outline-path t)) + (m (copy-marker (point))) + (colored (swarsel/org-colorize-outline parents raw))) + (push (cons colored m) candidates)))) + + (let* ((choice (completing-read "Heading: " (mapcar #'car candidates))) + (marker (cdr (assoc choice candidates))) + id raw-heading) + (unless marker + (user-error "No marker for heading??")) + + (save-excursion + (goto-char marker) + (setq id (prot-org--id-get)) + (setq raw-heading (org-get-heading t t t t))) + + (insert (org-link-make-string (format "#%s" id) + raw-heading))))) + +#+end_src + *** Custom Keybindings :PROPERTIES: :CUSTOM_ID: h:2b827c27-0de7-45ed-9d9e-6c511e2c6bb5 @@ -11542,127 +25059,115 @@ I also define some keybinds to some combinations directly. Those are used mostly #+begin_src emacs-lisp - ;; Make ESC quit prompts - (global-set-key (kbd "") 'keyboard-escape-quit) + ;; Make ESC quit prompts + (global-set-key (kbd "") 'keyboard-escape-quit) - ;; Set up general keybindings - (use-package general - :config - (general-create-definer swarsel/leader-keys - :keymaps '(normal insert visual emacs) - :prefix "SPC" - :global-prefix "C-SPC") + ;; Set up general keybindings + (use-package general + :config + (general-create-definer swarsel/leader-keys + :keymaps '(normal insert visual emacs) + :prefix "SPC" + :global-prefix "C-SPC") - (swarsel/leader-keys - "e" '(:ignore e :which-key "evil") - "eo" '(evil-jump-backward :which-key "cursor jump backwards") - "eO" '(evil-jump-forward :which-key "cursor jump forwards") - "t" '(:ignore t :which-key "toggles") - "ts" '(hydra-text-scale/body :which-key "scale text") - "te" '(swarsel/toggle-evil-state :which-key "emacs/evil") - "tl" '(display-line-numbers-mode :which-key "line numbers") - "tp" '(evil-cleverparens-mode :wk "cleverparens") - "to" '(olivetti-mode :wk "olivetti") - "td" '(darkroom-tentative-mode :wk "darkroom") - "tw" '((lambda () (interactive) (toggle-truncate-lines)) :which-key "line wrapping") - "m" '(:ignore m :which-key "modes/programs") - "mm" '((lambda () (interactive) (mu4e)) :which-key "mu4e") - "mg" '((lambda () (interactive) (magit-list-repositories)) :which-key "magit-list-repos") - "mc" '((lambda () (interactive) (swarsel/open-calendar)) :which-key "calendar") - "mp" '(popper-toggle :which-key "popper") - "md" '(dirvish :which-key "dirvish") - "mr" '(bjm/elfeed-load-db-and-open :which-key "elfeed") - "o" '(:ignore o :which-key "org") - "op" '((lambda () (interactive) (org-present)) :which-key "org-present") - "oa" '((lambda () (interactive) (org-agenda)) :which-key "org-agenda") - "oa" '((lambda () (interactive) (org-refile)) :which-key "org-refile") - "ob" '((lambda () (interactive) (org-babel-mark-block)) :which-key "Mark whole src-block") - "ol" '((lambda () (interactive) (org-insert-link)) :which-key "insert link") - "oc" '((lambda () (interactive) (org-store-link)) :which-key "copy (=store) link") - "os" '(shfmt-region :which-key "format sh-block") - "od" '((lambda () (interactive) (org-babel-demarcate-block)) :which-key "demarcate (split) src-block") - "on" '(nixpkgs-fmt-region :which-key "format nix-block") - "ot" '(swarsel/org-babel-tangle-config :which-key "tangle file") - "oe" '(org-html-export-to-html :which-key "export to html") - "c" '(:ignore c :which-key "capture") - "ct" '((lambda () (interactive) (org-capture nil "tt")) :which-key "task") - ;; "cj" '((lambda () (interactive) (org-capture nil "jj")) :which-key "journal") - ;; "cs" '(markdown-download-screenshot :which-key "screenshot") - "l" '(:ignore l :which-key "links") - "lc" '((lambda () (interactive) (progn (find-file swarsel-swarsel-org-filepath) (org-overview) )) :which-key "SwarselSystems.org") - "le" '((lambda () (interactive) (progn (find-file swarsel-swarsel-org-filepath) (goto-char (org-find-exact-headline-in-buffer "Emacs") ) (org-overview) (org-cycle) )) :which-key "Emacs.org") - "ln" '((lambda () (interactive) (progn (find-file swarsel-swarsel-org-filepath) (goto-char (org-find-exact-headline-in-buffer "System") ) (org-overview) (org-cycle))) :which-key "Nixos.org") - "ls" '((lambda () (interactive) (find-file "/smb:Swarsel@winters:")) :which-key "Server") - "lo" '(dired swarsel-obsidian-vault-directory :which-key "obsidian") - ;; "la" '((lambda () (interactive) (find-file swarsel-org-anki-filepath)) :which-key "anki") - ;; "ln" '((lambda () (interactive) (find-file swarsel-nix-org-filepath)) :which-key "Nix.org") - "lp" '((lambda () (interactive) (projectile-switch-project)) :which-key "switch project") - "lg" '((lambda () (interactive) (magit-list-repositories)) :which-key "list git repos") - ;; "a" '(:ignore a :which-key "anki") - ;; "ap" '(anki-editor-push-tree :which-key "push new cards") - ;; "an" '((lambda () (interactive) (org-capture nil "a")) :which-key "new card") - ;; "as" '(swarsel-anki-set-deck-and-notetype :which-key "change deck and notetype") - "h" '(:ignore h :which-key "help") - "hy" '(yas-describe-tables :which-key "yas tables") - "hb" '(embark-bindings :which-key "current key bindings") - "h" '(:ignore t :which-key "describe") - "he" 'view-echo-area-messages - "hf" 'describe-function - "hF" 'describe-face - "hl" '(view-lossage :which-key "show command keypresses") - "hL" 'find-library - "hm" 'describe-mode - "ho" 'describe-symbol - "hk" 'describe-key - "hK" 'describe-keymap - "hp" 'describe-package - "hv" 'describe-variable - "hd" 'devdocs-lookup - "w" '(:ignore t :which-key "window") - "wl" 'windmove-right - "w " 'windmove-right - "wh" 'windmove-left - "w " 'windmove-left - "wk" 'windmove-up - "w " 'windmove-up - "wj" 'windmove-down - "w " 'windmove-down - "wr" 'winner-redo - "wd" 'delete-window - "w=" 'balance-windows-area - "wD" 'kill-buffer-and-window - "wu" 'winner-undo - "wr" 'winner-redo - "w/" 'evil-window-vsplit - "w\\" 'evil-window-vsplit - "w-" 'evil-window-split - "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-M-d" 'swarsel-obsidian-daily ; open daily obsidian file and create if not exist - ;; "C-M-S" 'swarsel-anki-set-deck-and-notetype ; switch deck and notetype for new anki cards - ;; "C-M-s" 'markdown-download-screenshot ; wrapper for org-download-screenshot - "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 - "C-" 'my-python-shell-run - "" '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 - ) + (swarsel/leader-keys + "e" '(:ignore e :which-key "evil") + "eo" '(evil-jump-backward :which-key "cursor jump backwards") + "eO" '(evil-jump-forward :which-key "cursor jump forwards") + "t" '(:ignore t :which-key "toggles") + "ts" '(hydra-text-scale/body :which-key "scale text") + "te" '(swarsel/toggle-evil-state :which-key "emacs/evil") + "tl" '(display-line-numbers-mode :which-key "line numbers") + "tp" '(evil-cleverparens-mode :wk "cleverparens") + "to" '(olivetti-mode :wk "olivetti") + "td" '(darkroom-tentative-mode :wk "darkroom") + "tw" '((lambda () (interactive) (toggle-truncate-lines)) :which-key "line wrapping") + "m" '(:ignore m :which-key "modes/programs") + "mm" '((lambda () (interactive) (mu4e)) :which-key "mu4e") + "mg" '((lambda () (interactive) (magit-list-repositories)) :which-key "magit-list-repos") + "mc" '((lambda () (interactive) (swarsel/open-calendar)) :which-key "calendar") + "mp" '(popper-toggle :which-key "popper") + "md" '(dirvish :which-key "dirvish") + "mr" '(bjm/elfeed-load-db-and-open :which-key "elfeed") + "o" '(:ignore o :which-key "org") + "op" '((lambda () (interactive) (org-present)) :which-key "org-present") + "oa" '((lambda () (interactive) (org-agenda)) :which-key "org-agenda") + "oa" '((lambda () (interactive) (org-refile)) :which-key "org-refile") + "ob" '((lambda () (interactive) (org-babel-mark-block)) :which-key "Mark whole src-block") + "ol" '((lambda () (interactive) (org-insert-link)) :which-key "insert link") + "oc" '((lambda () (interactive) (org-store-link)) :which-key "copy (=store) link") + "os" '(shfmt-region :which-key "format sh-block") + "od" '((lambda () (interactive) (org-babel-demarcate-block)) :which-key "demarcate (split) src-block") + "on" '(nixpkgs-fmt-region :which-key "format nix-block") + "ot" '(swarsel/org-babel-tangle-config :which-key "tangle file") + "oe" '(org-html-export-to-html :which-key "export to html") + "c" '(:ignore c :which-key "capture") + "ct" '((lambda () (interactive) (org-capture nil "tt")) :which-key "task") + "l" '(:ignore l :which-key "links") + "lc" '((lambda () (interactive) (progn (find-file swarsel-swarsel-org-filepath) (org-overview) )) :which-key "SwarselSystems.org") + "le" '((lambda () (interactive) (progn (find-file swarsel-swarsel-org-filepath) (goto-char (org-find-exact-headline-in-buffer "Emacs") ) (org-overview) (org-cycle) )) :which-key "Emacs.org") + "lr" '(swarsel/consult-magit-repos :which-key "List repos") + "ln" '((lambda () (interactive) (progn (find-file swarsel-swarsel-org-filepath) (goto-char (org-find-exact-headline-in-buffer "System") ) (org-overview) (org-cycle))) :which-key "Nixos.org") + "lp" '((lambda () (interactive) (projectile-switch-project)) :which-key "switch project") + "lg" '((lambda () (interactive) (magit-list-repositories)) :which-key "list git repos") + "h" '(:ignore h :which-key "help") + "hy" '(yas-describe-tables :which-key "yas tables") + "hb" '(embark-bindings :which-key "current key bindings") + "h" '(:ignore t :which-key "describe") + "he" 'view-echo-area-messages + "hf" 'describe-function + "hF" 'describe-face + "hl" '(view-lossage :which-key "show command keypresses") + "hL" 'find-library + "hm" 'describe-mode + "ho" 'describe-symbol + "hk" 'describe-key + "hK" 'describe-keymap + "hp" 'describe-package + "hv" 'describe-variable + "hd" 'devdocs-lookup + "w" '(:ignore t :which-key "window") + "wl" 'windmove-right + "w " 'windmove-right + "wh" 'windmove-left + "w " 'windmove-left + "wk" 'windmove-up + "w " 'windmove-up + "wj" 'windmove-down + "w " 'windmove-down + "wr" 'winner-redo + "wd" 'delete-window + "w=" 'balance-windows-area + "wD" 'kill-buffer-and-window + "wu" 'winner-undo + "wr" 'winner-redo + "w/" 'evil-window-vsplit + "w\\" 'evil-window-vsplit + "w-" 'evil-window-split + "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 + ) #+end_src *** Directory setup / File structure @@ -11670,46 +25175,20 @@ I also define some keybinds to some combinations directly. Those are used mostly :CUSTOM_ID: h:07951589-54ba-4e3e-bd7b-4106cd22ff6a :END: -In this section I setup some aliases that I use for various directories on my system. Some of these are actually used for magit repository finding etc., but many of them serve no real use and I need to clean this up someday. +In this section I setup some aliases that I use for various directories on my system. This is just to prevent setting the same stuff too often. #+begin_src emacs-lisp ;; set Nextcloud directory for journals etc. - (setq swarsel-sync-directory "~/Nextcloud" - swarsel-emacs-directory "~/.emacs.d" - swarsel-dotfiles-directory "~/.dotfiles" - swarsel-projects-directory "~/Documents/GitHub") - - (setq swarsel-emacs-org-filepath (expand-file-name "Emacs.org" swarsel-dotfiles-directory) - swarsel-nix-org-filepath (expand-file-name "Nix.org" swarsel-dotfiles-directory) - swarsel-swarsel-org-filepath (expand-file-name "SwarselSystems.org" swarsel-dotfiles-directory) - ) - - - ;; set Emacs main configuration .org names - (setq swarsel-emacs-org-file "Emacs.org" - swarsel-anki-org-file "Anki.org" - swarsel-tasks-org-file "Tasks.org" - swarsel-archive-org-file "Archive.org" - swarsel-org-folder-name "Org" - swarsel-obsidian-daily-folder-name "⭐ Personal/Journal" - swarsel-obsidian-folder-name "Obsidian" - swarsel-obsidian-vault-name "Main") - - - ;; set directory paths - (setq swarsel-org-directory (expand-file-name swarsel-org-folder-name swarsel-sync-directory)) ; path to org folder - (setq swarsel-obsidian-directory (expand-file-name swarsel-obsidian-folder-name swarsel-sync-directory)) ; path to obsidian - (setq swarsel-obsidian-vault-directory (expand-file-name swarsel-obsidian-vault-name swarsel-obsidian-directory)) ; path to obsidian vault - (setq swarsel-obsidian-daily-directory (expand-file-name swarsel-obsidian-daily-folder-name swarsel-obsidian-vault-directory)) ; path to obsidian daily folder - - ;; filepaths to certain documents - (setq swarsel-org-anki-filepath (expand-file-name swarsel-anki-org-file swarsel-org-directory) ; path to anki export file - swarsel-org-tasks-filepath (expand-file-name swarsel-tasks-org-file swarsel-org-directory) - swarsel-org-archive-filepath (expand-file-name swarsel-archive-org-file swarsel-org-directory)) - - - + (setq + swarsel-emacs-directory "~/.emacs.d" + swarsel-dotfiles-directory (getenv "FLAKE") + swarsel-swarsel-org-filepath (expand-file-name "SwarselSystems.org" swarsel-dotfiles-directory) + swarsel-tasks-org-file "Tasks.org" + swarsel-archive-org-file "Archive.org" + swarsel-work-projects-directory (getenv "DOCUMENT_DIR_WORK") + swarsel-private-projects-directory (getenv "DOCUMENT_DIR_PRIV") + ) #+end_src *** Unclutter .emacs.d @@ -11766,7 +25245,7 @@ Many people dislike the Emacs backup files; I do enjoy them, but have to admit t :CUSTOM_ID: h:786b447d-03ad-4c1d-b114-c37caa2d591c :END: -In this general section I have settings that I either consider to be integral to my experience when using emacs or have no other section that I feel they belong to. +In this general section I have settings that I either consider to be integral to my experience when using Emacs or have no other section that I feel they belong to. *** General setup :PROPERTIES: @@ -11782,56 +25261,57 @@ Here I set up some things that are too minor to put under other categories. #+begin_src emacs-lisp - ;; 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") + ;; 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 - (global-subword-mode 1) ; Iterate through CamelCase words - (setq blink-matching-paren nil) ;; this makes the cursor jump around annoyingly - (delete-selection-mode 1) - (setq vc-follow-symlinks t) - (setq require-final-newline t) - (winner-mode 1) - (setq load-prefer-newer t) - (setq-default bidi-paragraph-direction 'left-to-right - 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) - (setq idle-update-delay 1.0 - which-func-update-delay 1.0) - (setq undo-limit 80000000 - evil-want-fine-undo t - auto-save-default t - password-cache-expiry nil - ) - (setq browse-url-browser-function 'browse-url-firefox) - ;; disable a keybind that does more harm than good - (global-set-key [remap suspend-frame] - (lambda () - (interactive) - (message "This keybinding is disabled (was 'suspend-frame')"))) + ;; (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 + (global-subword-mode 1) ; Iterate through CamelCase words + (setq blink-matching-paren nil) ;; this makes the cursor jump around annoyingly + (delete-selection-mode 1) + (setq vc-follow-symlinks t) + (setq require-final-newline t) + (winner-mode 1) + (setq load-prefer-newer t) + (setq-default bidi-paragraph-direction 'left-to-right + 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) + (setq idle-update-delay 1.0 + which-func-update-delay 1.0) + (setq undo-limit 80000000 + evil-want-fine-undo t + auto-save-default t + password-cache-expiry nil + ) + (setq browse-url-browser-function 'browse-url-firefox) + ;; (setenv "DISPLAY" ":0") ;; needed for firefox + ;; disable a keybind that does more harm than good + (global-set-key [remap suspend-frame] + (lambda () + (interactive) + (message "This keybinding is disabled (was 'suspend-frame')"))) - (setq visible-bell nil) - (setq initial-major-mode 'fundamental-mode - initial-scratch-message nil) + (setq visible-bell nil) + (setq initial-major-mode 'fundamental-mode + initial-scratch-message nil) - (add-hook 'prog-mode-hook 'display-line-numbers-mode) - ;; (add-hook 'text-mode-hook 'display-line-numbers-mode) - ;; (global-visual-line-mode 1) + (add-hook 'prog-mode-hook 'display-line-numbers-mode) + ;; (add-hook 'text-mode-hook 'display-line-numbers-mode) + ;; (global-visual-line-mode 1) #+end_src @@ -11854,6 +25334,8 @@ Normally when switching themes in emacs, the user will be warned that themes can When Emacs compiles stuff, it often shows a bunch of warnings that I do not need to deal with. Here we silence those. Some will be disabled completely, and some only when we have native compilation available (which should be most of the time, however). +This is really not needed anymore ever since I started managing my emacs packages with nix, but I still keep this around in case I ever move away from it. + #+begin_src emacs-lisp (setq byte-compile-warnings '(not free-vars unresolved noruntime lexical make-local)) @@ -11868,7 +25350,7 @@ When Emacs compiles stuff, it often shows a bunch of warnings that I do not need :CUSTOM_ID: h:1667913c-2272-4010-bf3a-356455b97c83 :END: -This sets up automatic garbage collection when the frame is unused. +This sets up automatic garbage collection when the frame is unused. There is a lot of discussion on whether it is smart to tamper with garbage collection - in my eyes it is worth running this, because I often times switch away from Emacs for a while when researching. That times can be then used to run GC. #+begin_src emacs-lisp (setq garbage-collection-messages nil) @@ -11884,8 +25366,8 @@ This sets up automatic garbage collection when the frame is unused. (run-with-idle-timer 15 t (lambda () ;; (message "Garbage Collector has run for %.06fsec" - (k-time (garbage-collect))))) - ;; ) + (k-time (garbage-collect))))) + ;; ) #+end_src *** Indentation @@ -11920,8 +25402,8 @@ Lastly, I load the =highlight-indent-guides= package. This adds a neat visual in (set-face-attribute 'highlight-indent-guides-stack-even-face nil :background "gray40") (set-face-attribute 'highlight-indent-guides-stack-odd-face nil :background "gray50")) - (use-package aggressive-indent) - (global-aggressive-indent-mode 1) + ;; (use-package aggressive-indent) + ;; (global-aggressive-indent-mode 1) #+end_src @@ -11969,46 +25451,46 @@ Also, I setup initial modes for several major-modes depending on what I deem fit #+begin_src emacs-lisp - ;; Emulate vim in emacs - (use-package evil - :init - (setq evil-want-integration t) ; loads evil - (setq evil-want-keybinding nil) ; loads "helpful bindings" for other modes - (setq evil-want-C-u-scroll t) ; scrolling using C-u - (setq evil-want-C-i-jump nil) ; jumping with C-i - (setq evil-want-Y-yank-to-eol t) ; give Y some utility - (setq evil-shift-width 2) ; uniform indent - (setq evil-respect-visual-line-mode nil) ; i am torn on this one - (setq evil-split-window-below t) - (setq evil-vsplit-window-right t) - :config - (evil-mode 1) + ;; Emulate vim in emacs + (use-package evil + :init + (setq evil-want-integration t) ; loads evil + (setq evil-want-keybinding nil) ; loads "helpful bindings" for other modes + (setq evil-want-C-u-scroll t) ; scrolling using C-u + (setq evil-want-C-i-jump nil) ; jumping with C-i + (setq evil-want-Y-yank-to-eol t) ; give Y some utility + (setq evil-shift-width 2) ; uniform indent + (setq evil-respect-visual-line-mode nil) ; i am torn on this one + (setq evil-split-window-below t) + (setq evil-vsplit-window-right t) + :config + (evil-mode 1) - ;; make normal mode respect wrapped lines - (define-key evil-normal-state-map (kbd "j") 'evil-next-visual-line) - (define-key evil-normal-state-map (kbd "") 'evil-next-visual-line) - (define-key evil-normal-state-map (kbd "k") 'evil-previous-visual-line) - (define-key evil-normal-state-map (kbd "") 'evil-previous-visual-line) + ;; make normal mode respect wrapped lines + (define-key evil-normal-state-map (kbd "j") 'evil-next-visual-line) + (define-key evil-normal-state-map (kbd "") 'evil-next-visual-line) + (define-key evil-normal-state-map (kbd "k") 'evil-previous-visual-line) + (define-key evil-normal-state-map (kbd "") 'evil-previous-visual-line) - (define-key evil-normal-state-map (kbd "C-z") nil) - (define-key evil-insert-state-map (kbd "C-z") nil) - (define-key evil-visual-state-map (kbd "C-z") nil) - (define-key evil-motion-state-map (kbd "C-z") nil) - (define-key evil-operator-state-map (kbd "C-z") nil) - (define-key evil-replace-state-map (kbd "C-z") nil) - (define-key global-map (kbd "C-z") nil) - (evil-set-undo-system 'undo-tree) + (define-key evil-normal-state-map (kbd "C-z") nil) + (define-key evil-insert-state-map (kbd "C-z") nil) + (define-key evil-visual-state-map (kbd "C-z") nil) + (define-key evil-motion-state-map (kbd "C-z") nil) + (define-key evil-operator-state-map (kbd "C-z") nil) + (define-key evil-replace-state-map (kbd "C-z") nil) + (define-key global-map (kbd "C-z") nil) + (evil-set-undo-system 'undo-tree) - ;; Don't use evil-mode in these contexts, or use it in a specific mode - (evil-set-initial-state 'messages-buffer-mode 'emacs) - (evil-set-initial-state 'dashboard-mode 'emacs) - (evil-set-initial-state 'dired-mode 'emacs) - (evil-set-initial-state 'cfw:details-mode 'emacs) - (evil-set-initial-state 'Custom-mode 'emacs) ; god knows why this mode is in uppercase - (evil-set-initial-state 'mu4e-headers-mode 'normal) - (evil-set-initial-state 'python-inferior-mode 'normal) - (add-hook 'org-capture-mode-hook 'evil-insert-state) - (add-to-list 'evil-buffer-regexps '("COMMIT_EDITMSG" . insert))) + ;; Don't use evil-mode in these contexts, or use it in a specific mode + (evil-set-initial-state 'messages-buffer-mode 'emacs) + (evil-set-initial-state 'dashboard-mode 'emacs) + (evil-set-initial-state 'dired-mode 'emacs) + (evil-set-initial-state 'cfw:details-mode 'emacs) + (evil-set-initial-state 'Custom-mode 'emacs) ; god knows why this mode is in uppercase + (evil-set-initial-state 'mu4e-headers-mode 'normal) + (evil-set-initial-state 'python-inferior-mode 'normal) + (add-hook 'org-capture-mode-hook 'evil-insert-state) + (add-to-list 'evil-buffer-regexps '("COMMIT_EDITMSG" . insert))) #+end_src **** evil-collection @@ -12073,12 +25555,58 @@ This minor-mode adds functionality for doing better surround-commands; for examp #+end_src +**** evil-visual-mark-mode +:PROPERTIES: +:CUSTOM_ID: h:df6729b6-2135-4070-bcab-a6a26f0fb2c4 +:END: + +This makes it so that when setting a mark in evil mode (using =m =), it creates a visual marker at that place that reminds me what the key for that marker position is (the marker is of course not part of the text of the document, and is hence not saved). + +#+begin_src emacs-lisp + + (use-package evil-visual-mark-mode + :config (evil-visual-mark-mode)) + +#+end_src +**** evil-textobj-tree-sitter +:PROPERTIES: +:CUSTOM_ID: h:cd9a0fb6-e287-4c3c-8013-6aad64ef89cb +:END: + +This adds support for tree-sitter objects. This allows for the following chords: + - "...af" around function + - "...if" inside function + +#+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))))) + +#+end_src +**** evil-numbers +:PROPERTIES: +:CUSTOM_ID: h:06002ad2-686a-42c5-82d7-61f1340e262d +:END: + +A very simple package that brings back the vim possibility of incrementing/decrementing numbers. I do not need it often, but it is nice to have. + +#+begin_src emacs-lisp + + (use-package evil-numbers) + +#+end_src *** ispell :PROPERTIES: :CUSTOM_ID: h:e888d7a7-1755-4109-af11-5358b8cf140e :END: -This should setup a wordlist that can be used as a dictionary. However, for some reason this does not work, and I will need to further investigate this issue. +This sets up a wordlist that is, for example, used in completions. When coding, I do not really need this, but it is sometimes useful when writing prose. #+begin_src emacs-lisp @@ -12109,7 +25637,6 @@ Here I define my fonts to be used. Honestly I do not understand the face-attribu :weight 'regular :height 1.06) - ;; these settings used to be in custom.el #+end_src @@ -12146,7 +25673,7 @@ This section loads the base icons used in my configuration. I am using =nerd-ico Used in: - [[#h:b190d512-bfb5-42ec-adec-8d86bab726ce][Vertico and friends]] -- [[#h:5653d693-ecca-4c95-9633-66b9e3241070][IN USE Corfu]] +- [[#h:5653d693-ecca-4c95-9633-66b9e3241070][Corfu]] #+begin_src emacs-lisp @@ -12170,7 +25697,6 @@ This minor mode allows mixing fixed and variable pitch fonts within the same buf :hook (text-mode . mixed-pitch-mode)) - #+end_src *** Modeline @@ -12178,9 +25704,9 @@ This minor mode allows mixing fixed and variable pitch fonts within the same buf :CUSTOM_ID: h:ed585848-875a-4673-910c-d2e1901dd95b :END: -Here I set up the modeline with some information that I find useful. Specficially I am using the doom modeline. Most informations I disable for it, except for the cursor information (row + column) as well as a widget for =mu4e= and git information. +Here I set up the modeline with some information that I find useful. I was using the doom modeline for a while. Most informations I disabled for it, except for the cursor information (row + column) as well as a widget for =mu4e= and git information. -I have currently disabled this in favor of [[#h:80ed2431-9c9a-4bfc-a3c0-08a2a058d208][mini-modeline]]. +I have currently disabled this in favor of [[#h:80ed2431-9c9a-4bfc-a3c0-08a2a058d208][mini-modeline]], which saves more screen space and holds only the information I really need. #+begin_src emacs-lisp @@ -12193,7 +25719,6 @@ I have currently disabled this in favor of [[#h:80ed2431-9c9a-4bfc-a3c0-08a2a058 (doom-modeline-indent-info nil) (doom-modeline-buffer-encoding nil))) - #+end_src *** mini-modeline @@ -12201,35 +25726,44 @@ I have currently disabled this in favor of [[#h:80ed2431-9c9a-4bfc-a3c0-08a2a058 :CUSTOM_ID: h:80ed2431-9c9a-4bfc-a3c0-08a2a058d208 :END: -I have found that the doom-modeline, while very useful, consumes too much screen space for my liking. This modeline takes a more minimalistic approach. +I have found that the doom-modeline, while very useful, consumes too much screen space for my liking. This modeline takes a more minimalistic approach. The only information that is shown is: + +- the line number +- state of the file (whether it is saved etc.) +- the name of the file +- the percentage of the cursor in the file +- the major mode of the file +- the current evil mode + +This is really the perfect solution for me, but it might not be for everyone. #+begin_src emacs-lisp - (use-package mini-modeline - :after smart-mode-line - :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 )) - ) + (use-package mini-modeline + :after smart-mode-line + :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 )) + ) - (use-package smart-mode-line - :config - (sml/setup) - (add-to-list 'sml/replacer-regexp-list '("^~/Documents/Work/" ":WK:")) - (add-to-list 'sml/replacer-regexp-list '("^~/Documents/Private/" ":PR:")) - (add-to-list 'sml/replacer-regexp-list '("^~/.dotfiles/" ":D:") t) - ) + (use-package smart-mode-line + :config + (sml/setup) + (add-to-list 'sml/replacer-regexp-list '("^~/Documents/Work/" ":WK:")) + (add-to-list 'sml/replacer-regexp-list '("^~/Documents/Private/" ":PR:")) + (add-to-list 'sml/replacer-regexp-list '("^~/.dotfiles/" ":D:") t) + ) #+end_src @@ -12243,21 +25777,16 @@ I have found that the doom-modeline, while very useful, consumes too much screen :CUSTOM_ID: h:b190d512-bfb5-42ec-adec-8d86bab726ce :END: -This set of packages uses the default emacs completion framework and works together to provide a very nice user experience: +This set of packages uses the default emacs completion framework and works together to provide a very nice user experience. -- Vertico simply provides a vertically stacking completion -- Marginalia adds more information to completion results -- Orderless allows for fuzzy matching -- Consult provides better implementations for several user functions, e.g. =consult-line= or =consult-outline= -- Embark allows acting on the results in the minibuffer while the completion is still ongoing - this is extremely useful since it allows to, for example, read the documentation for several functions without closing the help search. It can also collect the results of a grep operation into a seperate buffer that edits the result in their original location. - -Nerd icons is originally enabled here: [[#h:eb0ea526-a83a-4664-b3a1-2b40d3a31493][Icons]] ***** vertico :PROPERTIES: :CUSTOM_ID: h:d7c7f597-f870-4e01-8f7e-27dd31dd245d :END: +Vertico simply provides a vertically stacking completion framework. + #+begin_src emacs-lisp (setq read-buffer-completion-ignore-case t @@ -12300,6 +25829,8 @@ This package allows for =Ido=-like directory navigation. :CUSTOM_ID: h:211fc0bd-0d64-4577-97d8-6abc94435f04 :END: +Orderless allows for fuzzy matching. + When first installing orderless, I often times faced the problem, that when editing long files and calling =consult-line=, Emacs would hang when changing a search term in the middle (e.g. from =servicse.xserver= to =servic.xserver= in order to fix the typo). The below orderless rules have a more strict matching that has a positive impact on performance. #+begin_src emacs-lisp @@ -12327,6 +25858,7 @@ When first installing orderless, I often times faced the problem, that when edit :PROPERTIES: :CUSTOM_ID: h:49ab82bf-812d-4fbe-a5b6-d3ad703fe32c :END: +Consult provides better implementations for several user functions, e.g. =consult-line= or =consult-outline=. The big winner here are the convenient keybinds being setup here for general use. Also, I setup vim-navigation for minibuffer completions. =consult-buffer= is set twice because I am still used to that weird =C-M-j= command that I chose for =ivy-switch-buffer= when I first started using Emacs. I want to move to the other command but for now it is not feasible to delete the other one. @@ -12354,6 +25886,7 @@ The big winner here are the convenient keybinds being setup here for general use :PROPERTIES: :CUSTOM_ID: h:1c564ee5-ccd7-48be-b69a-d963400c4704 :END: +Embark allows acting on the results in the minibuffer while the completion is still ongoing - this is extremely useful since it allows to, for example, read the documentation for several functions without closing the help search. It can also collect the results of a grep operation into a seperate buffer that edits the result in their original location. I have stripped down the embark keybinds heavily. It is very useful to me even in it's current state, but it quickly becomes overwhelming. =embark-dwim= acts on a candidate without closing the minibuffer, which is very useful. =embark-act= lets the user choose from all actions, but has an overwhelming interface. @@ -12396,15 +25929,19 @@ Provides previews for embark. :PROPERTIES: :CUSTOM_ID: h:f32040a4-882f-4e6b-97f1-a0105c44c034 :END: +Marginalia adds more information to completion results. I set the annotation-mode of marginalia to =heavy=. This gives even more information on the stuff that you are looking at. One thing I am missing from ivy is the highlighting on =mode=-commands based on the current state of the mode. Also, I do not understand all the shorthands used by marginalia yet. #+begin_src emacs-lisp - (use-package marginalia - :after vertico - :init - (marginalia-mode) - (setq marginalia-annotators '(marginalia-annotators-heavy marginalia-annotators-light nil))) + (use-package marginalia + :after vertico + :bind (:map minibuffer-local-map + ("M-A" . marginalia-cycle)) + :init + (marginalia-mode) + ;; (setq marginalia-annotators '(marginalia-annotators-heavy marginalia-annotators-light nil)) + ) #+end_src ***** nerd-icons-completion @@ -12413,6 +25950,7 @@ I set the annotation-mode of marginalia to =heavy=. This gives even more informa :END: As stated above, this simply provides nerd-icons to the completion framework. +It is originally enabled here: [[#h:eb0ea526-a83a-4664-b3a1-2b40d3a31493][Icons]] #+begin_src emacs-lisp @@ -12422,7 +25960,6 @@ As stated above, this simply provides nerd-icons to the completion framework. :init (nerd-icons-completion-mode)) - #+end_src **** Helpful + which-key: Better help defaults @@ -12547,10 +26084,12 @@ This places little angled indicators on the fringe of a window which indicate bu This defines the authentication sources used by =org-calfw= ([[#h:c760f04e-622f-4b3e-8916-53ca8cce6edc][Calendar]]) and [[#h:1a8585ed-d9f2-478f-a132-440ada1cde2c][Forge]]. +This file is written using home-manager [[#h:d87d80fd-2ac7-4f29-b338-0518d06b4deb][sops]] in [[#h:c05d1b64-7110-4151-b436-46bc447113b4][Home-manager: Emacs]] + #+begin_src emacs-lisp ;; (setq auth-sources '( "~/.emacs.d/.caldav" "~/.emacs.d/.authinfo.gpg") - ;; auth-source-cache-expiry nil) ; default is 2h + ;; auth-source-cache-expiry nil) ; default is 2h (setq auth-sources '( "~/.emacs.d/.authinfo") auth-source-cache-expiry nil) @@ -12584,9 +26123,26 @@ This part of the configuration mostly makes some aesthetic changes, enables neat #+begin_src emacs-lisp + (defun swarsel/org-agenda-done-and-archive () + "Mark TODO at point as DONE, archive it, and save all agenda files." + (interactive) + (let ((org-archive-location "~/Org/Archive.org::Archive")) + (org-agenda-todo "DONE") + (org-agenda-archive) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (when (and buffer-file-name + (string-prefix-p (expand-file-name "~/Org/") (file-truename buffer-file-name)) + (derived-mode-p 'org-mode)) + (save-buffer)))))) + + (with-eval-after-load 'org-agenda + (define-key org-agenda-mode-map (kbd "C-a") #'swarsel/org-agenda-done-and-archive)) + (use-package org ;;:diminish (org-indent-mode) :hook (org-mode . swarsel/org-mode-setup) + ;; :mode "\\.nix\\'" :bind (("C-" . org-fold-outer) ("C-c s" . org-store-link)) @@ -12597,145 +26153,31 @@ This part of the configuration mostly makes some aesthetic changes, enables neat (setq org-startup-folded t) (setq org-support-shift-select t) - ;; (setq org-agenda-start-with-log-mode t) - ;; (setq org-log-done 'time) - ;; (setq org-log-into-drawer t) + (setq org-agenda-start-with-log-mode t) + (setq org-log-done 'time) + (setq org-log-into-drawer t) (setq org-startup-with-inline-images t) (setq org-export-headline-levels 6) (setq org-image-actual-width nil) (setq org-format-latex-options '(:foreground "White" :background default :scale 2.0 :html-foreground "Black" :html-background "Transparent" :html-scale 1.0 :matchers ("begin" "$1" "$" "$$" "\\(" "\\["))) -#+end_src -**** org-agenda -:PROPERTIES: -:CUSTOM_ID: h:2b3b4eb6-68a1-476d-b5d1-940a21484f1d -:END: + (setq org-agenda-files '("/home/swarsel/Org/Tasks.org" + "/home/swarsel/Org/Archive.org" + )) -Here I setup a plethora of keywords, keybinds and paths to give my org-agenda more power. + (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") + "* %?\nEntered on %U\n %i\n %a"))) -#+begin_src emacs-lisp - - (setq org-agenda-files '("/home/swarsel/Nextcloud/Org/Tasks.org" - "/home/swarsel/Nextcloud/Org/Archive.org" - "/home/swarsel/Nextcloud/Org/Anki.org" - "/home/swarsel/Calendars/leon_cal.org")) - - (setq org-refile-targets - '((swarsel-archive-org-file :maxlevel . 1) - (swarsel-anki-org-file :maxlevel . 1) - (swarsel-tasks-org-file :maxlevel . 1))) - - (setq org-todo-keywords - '((sequence "TODO(t)" "NEXT(n)" "|" "DONE(d!)") - (sequence "BACKLOG(b)" "PLAN(p)" "READY(r)" "ACTIVE(a)" "REVIEW(v)" "WAIT(w@/!)" "HOLD(h)" "|" "COMPLETED(c)" "CANC(k@)"))) - - - ;; Configure custom agenda views - (setq org-agenda-custom-commands - '(("d" "Dashboard" - ((agenda "" ((org-deadline-warning-days 7))) - (todo "NEXT" - ((org-agenda-overriding-header "Next Tasks"))) - (tags-todo "agenda/ACTIVE" ((org-agenda-overriding-header "Active Projects"))))) - - ("n" "Next Tasks" - ((todo "NEXT" - ((org-agenda-overriding-header "Next Tasks"))))) - - ("W" "Work Tasks" tags-todo "+work-email") - - - ("w" "Workflow Status" - ((todo "WAIT" - ((org-agenda-overriding-header "Waiting on External") - (org-agenda-files org-agenda-files))) - (todo "REVIEW" - ((org-agenda-overriding-header "In Review") - (org-agenda-files org-agenda-files))) - (todo "PLAN" - ((org-agenda-overriding-header "In Planning") - (org-agenda-todo-list-sublevels nil) - (org-agenda-files org-agenda-files))) - (todo "BACKLOG" - ((org-agenda-overriding-header "Project Backlog") - (org-agenda-todo-list-sublevels nil) - (org-agenda-files org-agenda-files))) - (todo "READY" - ((org-agenda-overriding-header "Ready for Work") - (org-agenda-files org-agenda-files))) - (todo "ACTIVE" - ((org-agenda-overriding-header "Active Projects") - (org-agenda-files org-agenda-files))) - (todo "COMPLETED" - ((org-agenda-overriding-header "Completed Projects") - (org-agenda-files org-agenda-files))) - (todo "CANC" - ((org-agenda-overriding-header "Cancelled Projects") - (org-agenda-files org-agenda-files))))))) + (setq org-refile-targets + '((swarsel-archive-org-file :maxlevel . 1) + (swarsel-tasks-org-file :maxlevel . 1))) + ) #+end_src -**** org capture templates -:PROPERTIES: -:CUSTOM_ID: h:23183635-3d46-4d7d-8eda-e0a085b335ef -:END: - -I wrote these capture templates to allow myself to quickly create Anki cards from within Emacs. I nearly never use this feature, but it cannot hurt to have. - -#+begin_src emacs-lisp - - (setq org-capture-templates - `( - ("a" "Anki basic" - entry - (file+headline swarsel-org-anki-filepath "Dispatch") - (function swarsel-anki-make-template-string)) - - ("A" "Anki cloze" - entry - (file+headline org-swarsel-anki-file "Dispatch") - "* %<%H:%M>\n:PROPERTIES:\n:ANKI_NOTE_TYPE: Cloze\n:ANKI_DECK: 🦁 All::01 ❤️ Various::00 ✨ Allgemein\n:END:\n** Text\n%?\n** Extra\n") - ("t" "Tasks / Projects") - ("tt" "Task" entry (file+olp swarsel-org-tasks-filepath "Inbox") - "* TODO %?\n %U\n %a\n %i" :empty-lines 1) - )) - ) -#+end_src - -**** Font Faces -:PROPERTIES: -:CUSTOM_ID: h:40528f5a-c8cd-471b-b862-4088e8e61860 -:END: - -Again, my understanding of the font-faces in Emacs is limited. This is mostly just tuned so that my org-files look acceptable. - -#+begin_src emacs-lisp - - - - ;; Set faces for heading levels - (with-eval-after-load 'org-faces (dolist (face '((org-level-1 . 1.1) - (org-level-2 . 0.9) - (org-level-3 . 0.9) - (org-level-4 . 0.9) - (org-level-5 . 0.9) - (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))) - - ;; Ensure that anything that should be fixed-pitch in Org files appears that way - (set-face-attribute 'org-block 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-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)) - -#+end_src - **** org-appear :PROPERTIES: :CUSTOM_ID: h:62829574-a069-44b8-afb3-401a268d2747 @@ -12803,39 +26245,54 @@ It also offers a very useful utility of exporting org-mode buffers to different #+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) - )) + (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) + (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))))) - (setq org-export-with-broken-links 'mark) - (setq org-confirm-babel-evaluate nil) #+end_src -***** old easy structure templates +***** 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 =RET=. The corresponding source block should appear. + Usage: Type =<=, followed by one of the below keywords and press =TAB=. The corresponding source block should appear. - #+begin_src emacs-lisp + #+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 :tangle")) + (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 + #+end_src **** aucTex :PROPERTIES: @@ -12846,20 +26303,21 @@ 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-master nil) + (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) + (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 @@ -12872,20 +26330,6 @@ This package allows to download and copy images into org-mode buffers. Sadly it #+begin_src emacs-lisp - (use-package org-download - :after org - :defer nil - :custom - (org-download-method 'directory) - (org-download-image-dir "./images") - (org-download-heading-lvl 0) - (org-download-timestamp "org_%Y%m%d-%H%M%S_") - ;;(org-image-actual-width 500) - (org-download-screenshot-method "grim -g \"$(slurp)\" %s") - :bind - ("C-M-y" . org-download-screenshot) - :config - (require 'org-download)) #+end_src @@ -12926,7 +26370,9 @@ This just makes org-mode a little bit more beautiful, mostly by making the =begi :CUSTOM_ID: h:4e11a845-a7bb-4eb5-b4ce-5b2f52e07425 :END: -Recently I have grown fond of holding presentations using Emacs :) +Recently I have grown fond of holding presentations using Emacs. + +When holding presentations, I think it is important to not have too many distractions on your slides. org-present just shows a plain background, is very responsive, and it is still an org buffer (so you can e.g. run source block codes while in the presentation). #+begin_src emacs-lisp @@ -13033,26 +26479,75 @@ Recently I have grown fond of holding presentations using Emacs :) (add-hook 'org-present-after-navigate-functions 'swarsel/org-present-slide) #+end_src + +**** Render markdown blocks as body to expand noweb blocks +:PROPERTIES: +:CUSTOM_ID: h:d4137200-7f91-43d9-9550-e0b6bfda1683 +:END: + +I have written this function to allow me to get a preview of the information that is gathered throughout the file and aggregated in [[#h:ed34ee4d-31f9-4d27-bc6e-ba37ee502d5a][Manual steps when setting up a new machine]]. Normally, running a markdown source block does nothing in Emacs. Hence, I just let it return the output, which inserts the noweb-ref blocks. + +#+begin_src emacs-lisp +(defun org-babel-execute:markdown (body params) + "Just return BODY unchanged, allowing noweb expansion." + body) +#+end_src *** Nix Mode :PROPERTIES: :CUSTOM_ID: h:406c2ecc-0e3e-4d9f-9ae3-3eb1f8b87d1b :END: -This adds a rudimentary nix-mode to Emacs. I have not really tried this out, as I am mostly editing nix-files in org-mode anyways. +This adds a nix mode to Emacs. This has become increasingly useful since I have added [[#h:cd552ba1-4db1-4605-8ead-4fcb6a466826][lsp-mode in org-src blocks]], because since that time, I am now able to actually make use of major modes while I theoretically stay in org-mode. + +It supports all functions that I normally need. Note that getting completions for flake inputs is a bit finnicky and I am not quite fond of it yet. #+begin_src emacs-lisp - (use-package nix-mode) + (use-package nix-mode + :after lsp-mode + :ensure t + :hook + (nix-mode . lsp-deferred) ;; So that envrc mode will work + :custom + (lsp-disabled-clients '((nix-mode . nix-nil))) ;; Disable nil so that nixd will be used as lsp-server + :config + (setq lsp-nix-nixd-server-path "nixd" + lsp-nix-nixd-formatting-command [ "nixpkgs-fmt" ] + lsp-nix-nixd-nixpkgs-expr "import (builtins.getFlake \"/home/swarsel/.dotfiles\").inputs.nixpkgs { }" + lsp-nix-nixd-nixos-options-expr "(builtins.getFlake \"/home/swarsel/.dotfiles\").nixosConfigurations.pyramid.options" + lsp-nix-nixd-home-manager-options-expr "(builtins.getFlake \"/home/swarsel/.dotfiles\").nixosConfigurations.pyramid.options.home-manager.users.type.getSubOptions []" + )) - (use-package nix-ts-mode - :mode "\\.nix\\'") + (use-package nix-ts-mode + :after lsp-mode + :mode "\\.nix\\'" + :ensure t + :hook + (nix-ts-mode . lsp-deferred) ;; So that envrc mode will work + :custom + (lsp-disabled-clients '((nix-ts-mode . nix-nil))) ;; Disable nil so that nixd will be used as lsp-server + :config + (setq lsp-nix-nixd-server-path "nixd" + lsp-nix-nixd-formatting-command [ "nixpkgs-fmt" ] + lsp-nix-nixd-nixpkgs-expr "import (builtins.getFlake \"/home/swarsel/.dotfiles\").inputs.nixpkgs { }" + lsp-nix-nixd-nixos-options-expr "(builtins.getFlake \"/home/swarsel/.dotfiles\").nixosConfigurations.pyramid.options" + lsp-nix-nixd-home-manager-options-expr "(builtins.getFlake \"/home/swarsel/.dotfiles\").nixosConfigurations.pyramid.options.home-manager.users.type.getSubOptions []" + )) + + + (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: :CUSTOM_ID: h:e8074881-3441-4abd-b25b-358a87e7984f :END: -This adds support for Hashicorp Configuration Language. I need this at work. +This adds support for Hashicorp Configuration Language. Used at work, it is mostly a [[#h:7834adb0-fbd3-4136-bdb7-6dbc9a083296][Terraform Mode]] that does not support autoformatting upon save. It still is nice :) #+begin_src emacs-lisp @@ -13067,7 +26562,7 @@ This adds support for Hashicorp Configuration Language. I need this at work. :CUSTOM_ID: h:c9e3ffd7-4fb1-4a04-8563-92ceec4b4410 :END: -This adds support for Groovy, which I specifically need to work with Jenkinsfiles. I need this at work. +This adds support for Groovy, which I specifically need to work with Jenkinsfiles. Similar to [[id:7aa9803f-b419-40fa-aafc-4bb934c8f687][HCL Mode]], it just provides some nice functions. #+begin_src emacs-lisp @@ -13076,13 +26571,26 @@ This adds support for Groovy, which I specifically need to work with Jenkinsfile (use-package jenkinsfile-mode :mode "Jenkinsfile") +#+end_src +*** Ansible +:PROPERTIES: +:CUSTOM_ID: h:77fa79d8-81d5-46f2-82f9-8e2922538d44 +:END: + +This is supposed to provide auto-completion when turned on. Of course I cannot globally turn this on since it would run in any =.yaml= file then, but even when manually started, it seems to do nothing. This would be nice at work. + + +#+begin_src emacs-lisp + +(use-package ansible) + #+end_src *** Dockerfile :PROPERTIES: :CUSTOM_ID: h:534d8729-4422-4f0c-9ae6-d3737d4a6dd3 :END: -This adds support for Dockerfiles. I need this at work. +This adds support for Dockerfiles in a similar way to [[id:ebd53be9-c38a-4a0f-a7b4-eee30a0074fc][Jenkinsfile/Groovy]]. #+begin_src emacs-lisp @@ -13095,7 +26603,7 @@ This adds support for Dockerfiles. I need this at work. :CUSTOM_ID: h:7834adb0-fbd3-4136-bdb7-6dbc9a083296 :END: -This adds support for Terraform configuration files. I need this at work. +This adds support for Terraform configuration files. This is basically the same as the [[id:7aa9803f-b419-40fa-aafc-4bb934c8f687][HCL Mode]] mode as the languages are very similar. #+begin_src emacs-lisp @@ -13108,12 +26616,14 @@ This adds support for Terraform configuration files. I need this at work. (add-hook 'terraform-mode-hook #'outline-minor-mode) #+end_src -*** nixpkgs-fmt +*** nix formatting :PROPERTIES: :CUSTOM_ID: h:5ca7484b-b9d6-4023-88d1-a1e37d5df249 :END: -Adds functions for formatting nix code. +Adds functions for formatting nix code. I make huge use of this using the chords =C- o b= (org-babel-mark-block) and then =C- o n= (nixpkgs-fmt-region). This is what I use to keep my nix org-src-blocks formatted. However, using [[id:a67adf2f-20ce-49d6-ba6b-0341ca3d9972][org-mode: Upon-save actions (Auto-tangle, export to html, formatting)]], the resulting tangled files will be formatted in any case. + +Note that for files that are not managed using this file (which there should normally not be many of), we can still use =nix fmt= for running treefmt for formatting and checks. #+begin_src emacs-lisp @@ -13126,7 +26636,7 @@ Adds functions for formatting nix code. :CUSTOM_ID: h:489a71c4-38af-44a3-a9ef-8b1ed1ee4ac4 :END: -Adds functions for formatting shellscripts. +Adds functions for formatting shellscripts. Similarly to [[id:460a47fd-cddc-4080-9eba-6724fc63606e][nix formatting]]m I use this using the chords =C- o b= (org-babel-mark-block) and then =C- o s= (shfmt-region). This is what I use to keep shell script blocks formatted in this file. This is also handled by treefmt, but still, I want this file to stay organized as well. #+begin_src emacs-lisp @@ -13146,6 +26656,8 @@ Adds functions for formatting shellscripts. :CUSTOM_ID: h:734dc40a-a2c4-4839-b884-cb99b81aa6fe :END: +Adds a mode for markdown, specifically MultiMarkdown, which allows me to render LaTeX and other nice things. + #+begin_src emacs-lisp (setq markdown-command "pandoc") @@ -13164,6 +26676,8 @@ Adds functions for formatting shellscripts. :CUSTOM_ID: h:8d90fe51-0b32-423a-a159-4f853bc29b68 :END: +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 (add-hook 'markdown-mode-hook @@ -13174,29 +26688,13 @@ Adds functions for formatting shellscripts. #+end_src -*** Olivetti -:PROPERTIES: -:CUSTOM_ID: h:65e69741-9860-4ed0-bbed-7b7be9a2a9d6 -:END: - -Olivetti is a mode specialized for writing prose in Emacs. I went for a very simple setup with little distractions. - -This mode is not automatically activated anywhere because I only rarely need it. - -#+begin_src emacs-lisp - - (use-package olivetti - :init - (setq olivetti-body-width 100) - (setq olivetti-recall-visual-line-mode-entry-state t)) - -#+end_src - *** elfeed :PROPERTIES: :CUSTOM_ID: h:a83c5820-2016-44ae-90a0-4756bb471c01 :END: +This adds elfeed, a neat RSS reader for Emacs. I use this as a client for [[#h:9da3df74-6fc5-4ee1-a345-23ab4e8a613d][FreshRSS]]. While I read most of my feeds on my phone (using Capy Reader), it is still good to have an Emacs-native reader as well. Some time ago I was still running a separate Emacs instance on my server: [[id:0e07e2fb-adc4-4fd8-9b54-0a59338a471e][Emacs elfeed (RSS Server)]]. This instance would then sync the read feeds to other instances. This was very brittle however and is only left as a historical note. + #+begin_src emacs-lisp (use-package elfeed) @@ -13216,9 +26714,13 @@ This mode is not automatically activated anywhere because I only rarely need it. (setq elfeed-protocol-enabled-protocols '(fever)) (setq elfeed-protocol-fever-update-unread-only t) (setq elfeed-protocol-fever-fetch-category-as-tag t) - (setq elfeed-protocol-feeds '(("fever+https://Swarsel@signpost.swarsel.win" - :api-url "https://signpost.swarsel.win/api/fever.php" - :password-file "~/.emacs.d/.fever"))) + + (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) @@ -13229,29 +26731,12 @@ This mode is not automatically activated anywhere because I only rarely need it. #+end_src - -*** darkroom -:PROPERTIES: -:CUSTOM_ID: h:94d4a0dc-b0d7-4702-b760-beeaa6da2b8f -:END: - -Darkroom is package that reduces all forms of distraction to a minimum - this can be useful when simply reading a file for example. For this mode I have increased the text scale by a large margin to make for comfortable reading -This mode is not automatically activated anywhere because I only rarely need it. - -#+begin_src emacs-lisp - - (use-package darkroom - :init - (setq darkroom-text-scale-increase 3)) - -#+end_src - *** Ripgrep :PROPERTIES: :CUSTOM_ID: h:87453f1c-8ea5-4d0a-862d-8973d5bc5405 :END: -This is the ripgrep command for Emacs. +This is the ripgrep package for Emacs. #+begin_src emacs-lisp @@ -13265,7 +26750,7 @@ This is the ripgrep command for Emacs. Tree-sitter is a parsing library integrated into Emacs to provide better syntax highlighting and code analysis. It generates concrete syntax trees for source code, enabling more accurate and efficient text processing. Emacs' tree-sitter integration enhances language support, offering features like incremental parsing and precise syntax-aware editing. This improves the development experience by providing robust and dynamic syntax features, making it easier for me to navigate and manipulate code. -In order to update the language grammars, run the next command below. +In order to update the language grammars, run the next command below. NOTE: since we now load =epkgs.treesit-grammars.with-all-grammars= in [[#h:c05d1b64-7110-4151-b436-46bc447113b4][Home-manager: Emacs]], we actually never run this anymore. I leave it here however for a potential future reader. For safety, I still instruct treesit to install missing grammars on the fly. #+begin_src emacs-lisp :tangle no :export both @@ -13278,53 +26763,63 @@ In order to update the language grammars, run the next command below. #+begin_src emacs-lisp - (use-package emacs - :ensure nil - :init - (setq treesit-language-source-alist - '((bash . ("https://github.com/tree-sitter/tree-sitter-bash")) - (c . ("https://github.com/tree-sitter/tree-sitter-c")) - (cmake . ("https://github.com/uyha/tree-sitter-cmake")) - (cpp . ("https://github.com/tree-sitter/tree-sitter-cpp")) - (css . ("https://github.com/tree-sitter/tree-sitter-css")) - (elisp . ("https://github.com/Wilfred/tree-sitter-elisp")) - (go . ("https://github.com/tree-sitter/tree-sitter-go")) - (html . ("https://github.com/tree-sitter/tree-sitter-html")) - (javascript . ("https://github.com/tree-sitter/tree-sitter-javascript")) - (json . ("https://github.com/tree-sitter/tree-sitter-json")) - (julia . ("https://github.com/tree-sitter/tree-sitter-julia")) - (latex . ("https://github.com/latex-lsp/tree-sitter-latex")) - (make . ("https://github.com/alemuller/tree-sitter-make")) - (markdown . ("https://github.com/ikatyang/tree-sitter-markdown")) - (nix . ("https://github.com/nix-community/tree-sitter-nix")) - (R . ("https://github.com/r-lib/tree-sitter-r")) - (python . ("https://github.com/tree-sitter/tree-sitter-python")) - (typescript . ("https://github.com/tree-sitter/tree-sitter-typescript" "typescript/src" "typescript")) - (rust . ("https://github.com/tree-sitter/tree-sitter-rust")) - (sql . ("https://github.com/m-novikov/tree-sitter-sql")) - (toml . ("https://github.com/tree-sitter/tree-sitter-toml")) - (tsx . ("https://github.com/tree-sitter/tree-sitter-typescript" "master" "typescript/src")) - (yaml . ("https://github.com/ikatyang/tree-sitter-yaml")))) - ) + ;; (use-package emacs + ;; :ensure nil + ;; :init + ;; (setq treesit-language-source-alist + ;; '((bash . ("https://github.com/tree-sitter/tree-sitter-bash")) + ;; (c . ("https://github.com/tree-sitter/tree-sitter-c")) + ;; (cmake . ("https://github.com/uyha/tree-sitter-cmake")) + ;; (cpp . ("https://github.com/tree-sitter/tree-sitter-cpp")) + ;; (css . ("https://github.com/tree-sitter/tree-sitter-css")) + ;; (elisp . ("https://github.com/Wilfred/tree-sitter-elisp")) + ;; (go . ("https://github.com/tree-sitter/tree-sitter-go")) + ;; (html . ("https://github.com/tree-sitter/tree-sitter-html")) + ;; (javascript . ("https://github.com/tree-sitter/tree-sitter-javascript")) + ;; (json . ("https://github.com/tree-sitter/tree-sitter-json")) + ;; (julia . ("https://github.com/tree-sitter/tree-sitter-julia")) + ;; (latex . ("https://github.com/latex-lsp/tree-sitter-latex")) + ;; (make . ("https://github.com/alemuller/tree-sitter-make")) + ;; (markdown . ("https://github.com/ikatyang/tree-sitter-markdown")) + ;; (nix . ("https://github.com/nix-community/tree-sitter-nix")) + ;; (R . ("https://github.com/r-lib/tree-sitter-r")) + ;; (python . ("https://github.com/tree-sitter/tree-sitter-python")) + ;; (typescript . ("https://github.com/tree-sitter/tree-sitter-typescript" "typescript/src" "typescript")) + ;; (rust . ("https://github.com/tree-sitter/tree-sitter-rust")) + ;; (sql . ("https://github.com/m-novikov/tree-sitter-sql")) + ;; (toml . ("https://github.com/tree-sitter/tree-sitter-toml")) + ;; (tsx . ("https://github.com/tree-sitter/tree-sitter-typescript" "master" "typescript/src")) + ;; (yaml . ("https://github.com/ikatyang/tree-sitter-yaml")))) + ;; ) (use-package treesit-auto + :custom + (setq treesit-auto-install t) :config - (global-treesit-auto-mode) - (setq treesit-auto-install 'prompt)) + (treesit-auto-add-to-auto-mode-alist 'all) + (global-treesit-auto-mode)) #+end_src +#+RESULTS: +: t + *** direnv (envrc) :PROPERTIES: :CUSTOM_ID: h:82ddeef2-99f8-465b-ba36-07c3eaad717b :END: +In emacs, there are two packages for managing dev environments - emacs-direnv (direnv) and envrc. Direnv uses the global Emacs environment whereas envrc is buffer-local. I do not really care about this difference. What is more important to me is that emacs should not block upon handling a bigger flake.nix while setting up the dev environment. This seems to be better handled by envrc. + #+begin_src emacs-lisp - (use-package direnv - :custom (direnv-always-show-summary nil) - :config (direnv-mode)) + ;; (use-package direnv + ;; :custom (direnv-always-show-summary nil) + ;; :config (direnv-mode)) + + (use-package envrc + :hook (after-init . envrc-global-mode)) #+end_src @@ -13345,19 +26840,6 @@ In order to update the language grammars, run the next command below. #+end_src -*** crdt (Collaborative Editing) -:PROPERTIES: -:CUSTOM_ID: h:1c1821c6-98de-4079-a4f3-6ba6e6dcb668 -:END: - -With this it is possible to work on the same file collaboratively. I have never tried it out, but it sounds cool. - -#+begin_src emacs-lisp - - (use-package crdt) - -#+end_src - *** devdocs :PROPERTIES: :CUSTOM_ID: h:d9a6cb44-736e-4608-951f-e928e1b757c0 @@ -13407,8 +26889,9 @@ projectile is useful for keeping track of your git projects within Emacs. I most ("C-c p" . projectile-command-map) ; all projectile commands under this :init ;; NOTE: Set this to the folder where you keep your Git repos! - (when (file-directory-p swarsel-projects-directory) - (setq projectile-project-search-path (list swarsel-projects-directory))) + (when (file-directory-p swarsel-work-projects-directory) + (when (file-directory-p swarsel-private-projects-directory) + (setq projectile-project-search-path (list swarsel-work-projects-directory swarsel-private-projects-directory)))) (setq projectile-switch-project-action #'magit-status)) #+end_src @@ -13420,15 +26903,14 @@ projectile is useful for keeping track of your git projects within Emacs. I most magit is the best git utility I have ever used - it has a beautiful interface and is very verbose. Here I mostly just setup the list of repositories that I want to expost to magit. -Also, Emacs needs a little extra love to accept my Yubikey for git commits etc. We also set that here. +Also, Emacs needs a little extra love to accept my Yubikey for git commits etc. We set that here: [[id:59df9a4c-2a1f-466b-abe2-fbb8524cd0ed][Yubikey support]]. #+begin_src emacs-lisp (use-package magit :config - (setq magit-repository-directories `((,swarsel-projects-directory . 1) - (,swarsel-emacs-directory . 0) - (,swarsel-obsidian-directory . 0) + (setq magit-repository-directories `((,swarsel-work-projects-directory . 3) + (,swarsel-private-projects-directory . 3) ("~/.dotfiles/" . 0))) :custom (magit-display-buffer-function #'magit-display-buffer-same-window-except-diff-v1)) ; stay in the same window @@ -13439,7 +26921,7 @@ Also, Emacs needs a little extra love to accept my Yubikey for git commits etc. :CUSTOM_ID: h:d78709dd-4f79-441c-9166-76f61f90359a :END: -The following settings are needed to make sure emacs works for magit commits and pushes. It is not a beautiful solution since commiting uses pinentry-emacs and pushing uses pinentry-gtk2, but it works for now at least. +The following settings are needed to make sure emacs works for magit commits and pushes. It is not a beautiful solution since commiting uses pinentry-emacs and pushing uses pinentry-gtk2, but it works for now at least. This works especially well since I have switched from =pinentry-gtk3= to =pinentry-waypromt=. #+begin_src emacs-lisp @@ -13465,21 +26947,15 @@ NOTE: Make sure to configure a GitHub token before using this package! (1) in practice: github -<> settings -<> developer option -<> create classic token with repo; user; read:org permissions - (2) install GnuGP (and add to PATH) - (3) create ~/.authinfo.gpg with the following info scheme: - machine api.github.com login USERNAME^forge password 012345abcdef... + (2)machine api.github.com login USERNAME^forge password 012345abcdef... + + The above is handled by [[id:ebb558ed-883a-486f-a6f5-8b283eb735a3][Home-manager: Emacs]] and only here as a historical note. Forge lets me interact with non-core git objects like issues and pull requests from within emacs. #+begin_src emacs-lisp (use-package forge :after magit) - (with-eval-after-load 'forge - (add-to-list 'forge-alist - '("sgit.iue.tuwien.ac.at" - "sgit.iue.tuwien.ac.at/api/v1" - "sgit.iue.tuwien.ac.at" - forge-gitea-repository))) #+end_src *** git-timemachine @@ -13563,12 +27039,6 @@ Navigation functions defined here: [[#h:a1802f9b-bb71-4fd5-86fa-945da18e8b81][co #+begin_src emacs-lisp - ;; (use-package corfu - ;; :custom - ;; (corfu-cycle t) - ;; :init - ;; (global-corfu-mode)) - (use-package corfu :init (global-corfu-mode) @@ -13577,7 +27047,7 @@ Navigation functions defined here: [[#h:a1802f9b-bb71-4fd5-86fa-945da18e8b81][co :custom (corfu-auto t) (corfu-auto-prefix 3) - (corfu-auto-delay 0.3) + (corfu-auto-delay 1) (corfu-cycle t) (corfu-quit-no-match 'separator) (corfu-separator ?\s) @@ -13642,22 +27112,6 @@ I leave the commented out alist extensions here in case I want to try them out a ("C-z ^" . cape-tex) ("C-z &" . cape-sgml) ("C-z r" . cape-rfc1345) - ;; Add to the global default value of `completion-at-point-functions' which is - ;; used by `completion-at-point'. The order of the functions matters, the - ;; first function returning a result wins. Note that the list of buffer-local - ;; completion functions takes precedence over the global list. - ;; (add-to-list 'completion-at-point-functions #'cape-dabbrev) - ;; (add-to-list 'completion-at-point-functions #'cape-file) - ;; (add-to-list 'completion-at-point-functions #'cape-elisp-block) - ;; (add-to-list 'completion-at-point-functions #'cape-history) - ;; (add-to-list 'completion-at-point-functions #'cape-keyword) - ;; (add-to-list 'completion-at-point-functions #'cape-tex) - ;; (add-to-list 'completion-at-point-functions #'cape-sgml) - ;; (add-to-list 'completion-at-point-functions #'cape-rfc1345) - ;; (add-to-list 'completion-at-point-functions #'cape-abbrev) - ;; (add-to-list 'completion-at-point-functions #'cape-dict) - ;; (add-to-list 'completion-at-point-functions #'cape-elisp-symbol) - ;; (add-to-list 'completion-at-point-functions #'cape-line) ) #+end_src @@ -13671,18 +27125,18 @@ This sets up rustic-mode with tree-sitter support - there is still one issue to #+begin_src emacs-lisp - (use-package rustic - :init - (setq rust-mode-treesitter-derive t) - :config - (define-key rust-ts-mode-map (kbd "C-c C-c C-r") 'rustic-cargo-run) - (define-key rust-ts-mode-map (kbd "C-c C-c C-b") 'rustic-cargo-build) - (define-key rust-ts-mode-map (kbd "C-c C-c C-k") 'rustic-cargo-check) - (define-key rust-ts-mode-map (kbd "C-c C-c d") 'rustic-cargo-doc) - (define-key rust-ts-mode-map (kbd "C-c C-c a") 'rustic-cargo-add) - (setq rustic-format-on-save t) - (setq rustic-lsp-client 'eglot) - :mode ("\\.rs" . rustic-mode)) + ;;(use-package rustic + ;; :init + ;; (setq rust-mode-treesitter-derive t) + ;; :config + ;; (define-key rust-ts-mode-map (kbd "C-c C-c C-r") 'rustic-cargo-run) + ;; (define-key rust-ts-mode-map (kbd "C-c C-c C-b") 'rustic-cargo-build) + ;; (define-key rust-ts-mode-map (kbd "C-c C-c C-k") 'rustic-cargo-check) + ;; (define-key rust-ts-mode-map (kbd "C-c C-c d") 'rustic-cargo-doc) + ;; (define-key rust-ts-mode-map (kbd "C-c C-c a") 'rustic-cargo-add) + ;; (setq rustic-format-on-save t) + ;; (setq rustic-lsp-client 'eglot) + ;; :mode ("\\.rs" . rustic-mode)) #+end_src @@ -13699,6 +27153,7 @@ Tramp allows for SSH access of files over Emacs. I have no ideas what the option (use-package tramp + ;; :ensure nil :init (setq vc-ignore-dir-regexp (format "\\(%s\\)\\|\\(%s\\)" @@ -13760,100 +27215,31 @@ Still, this is avery convenient package. #+end_src -*** yasnippet -:PROPERTIES: -:CUSTOM_ID: h:9ec11ee4-2250-414a-87b5-73ee680a3a4a -:END: - -yasnippet allows to define snippets that can be quickly expanded by hitting the =TAB= key after inputting a keyword. - -I used to run this together with the =yasnippet-snippets= package, but the snippets in there I did not find all too useful for myself. I need to create some custom snippets here one day. - -#+begin_src emacs-lisp - - (use-package yasnippet - :init (yas-global-mode 1) - :config - (yas-reload-all)) - -#+end_src - -***** yasnippet math-snippets -:PROPERTIES: -:CUSTOM_ID: h:af0a78a5-17c2-4e13-b64a-772c27c4dee2 -:END: - -The following block is mostly inspired from [[https://code.kulupu.party/thesuess/WTFmacs/]] and sets up a few prefixes that make LaTeX-math-mode nicer to use even with auctex and cape enabled. - -#+begin_src emacs-lisp - - - (setq wtf/latex-mathbb-prefix "''") - (setq swarsel/latex-mathcal-prefix "``") - - (use-package yasnippet - :config - - (setq wtf/english-alphabet - '("a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z")) - - (dolist (elem wtf/english-alphabet) - (when (string-equal elem (downcase elem)) - (add-to-list 'wtf/english-alphabet (upcase elem)))) - - - (yas-define-snippets - 'latex-mode - (mapcar - (lambda (elem) - (list (concat wtf/latex-mathbb-prefix elem) (concat "\\mathbb{" elem "}") (concat "Mathbb letter " elem))) - wtf/english-alphabet)) - - (yas-define-snippets - 'latex-mode - (mapcar - (lambda (elem) - (list (concat swarsel/latex-mathcal-prefix elem) (concat "\\mathcal{" elem "}") (concat "Mathcal letter " elem))) - wtf/english-alphabet)) - - (setq swtf/latex-math-symbols - '(("x" . "\\times") - ("*" . "\\cdot") - ("." . "\\ldots") - ("op" . "\\operatorname{$1}$0") - ("o" . "\\circ") - ("V" . "\\forall") - ("v" . "\\vee") - ("w" . "\\wedge") - ("q" . "\\quad") - ("f" . "\\frac{$1}{$2}$0") - ("s" . "\\sum_{$1}^{$2}$0") - ("p" . "\\prod_{$1}^{$2}$0") - ("e" . "\\exists") - ("i" . "\\int_{$1}^{$2}$0") - ("c" . "\\cap") - ("u" . "\\cup") - ("0" . "\\emptyset"))) - - ) - - -#+end_src - *** eglot :PROPERTIES: :CUSTOM_ID: h:6cf0310b-2fdf-45f0-9845-4704649777eb :END: -After having tried out =lsp-mode= and =lsp-bridge= for a while each, I must say that =eglot= feels the most clean and fast to me. +Up comes the section of lsp clients for Emacs. For a longer time, I thought that I had to choose one only, and after having started with =lsp-mode= I had tried out =lsp-booster= and then went to =eglot=. My requirements are as follow: + +Must have: + - mostly unintrusive, non-blocking + - fast (configurable) completion + - xref (or similar) + +Nice to have: + - Debugger + - Multi-lsp support (running two lsp's on a single project) + - Native Emacs support + +=eglot= fills most items on the first list except for the non-blocking issue initially. It blocks sometimes on bigger projects as well as when entering directories using (nix-)direnv and the lsp is not yet loaded. The first issue is solved by using =eglot-booster=, which increases the parsing speed by what feels like a huge margin (but I never ran any actual tests). The second issue is solved with =eglot-sync-connect=, which avoids blocking the interface while the server is starting. + +A blocking issue can still occur while entering a direnv that has a longer evaluation/build time. That issue can only be fixed by using Mic92's [[https://github.com/Mic92/emacs-direnv][emacs-direnv fork]], which calls direnv asynchronously, which in turn avoids the blocking. I am not using this on a daily basis however, since my environments are normally cached anyways and most of them (except for the LaTeX one) are not blocking for long enough for this to be worth it. However, I am considering spinning up my own fork of this at some point. #+begin_src emacs-lisp (use-package eglot - :config - (add-to-list 'eglot-server-programs - '(yaml-ts-mode . ("ansible-language-server" "--stdio"))) :hook ((python-mode python-ts-mode @@ -13861,11 +27247,12 @@ After having tried out =lsp-mode= and =lsp-bridge= for a while each, I must say c-ts-mode c++-mode c++-ts-mode - rust-ts-mode - rustic-mode + go-mode + go-ts-mode + ;;rust-ts-mode + ;;rustic-mode tex-mode LaTeX-mode - yaml-ts-mode ) . (lambda () (progn (eglot-ensure) (add-hook 'before-save-hook 'eglot-format nil 'local)))) @@ -13892,6 +27279,78 @@ After having tried out =lsp-mode= and =lsp-bridge= for a while each, I must say (defalias 'start-lsp-server #'eglot) #+end_src +*** lsp-mode & company +:PROPERTIES: +:CUSTOM_ID: h:7b9044cf-0fab-4dfa-87fc-f8c18e433e75 +:END: + +company is now disabled since it seems that corfu runs just fine with lsp-mode and I prefer it. Also I set the auto-guess-root option to true in order to stop excessive nag when editing within org-src blocks. + +#+begin_src emacs-lisp + + (use-package lsp-mode + :init + ;; 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) + + ;; (use-package company) + +#+end_src + +*** lsp-mode in org-src blocks +:PROPERTIES: +:CUSTOM_ID: h:cd552ba1-4db1-4605-8ead-4fcb6a466826 +:END: + +This incredible function allows to start a sub-pane in a org-file while in a source-block that spins up a lsp-server. In practise that allows me to use a nix lsp when editing complex blocks in my config. The only bother is that we have to add the modes where it should run manually to =org-babel-lang-list=, but that is a small price to pay for the usefulness that it brings. + +#+begin_src emacs-lisp + ;; thanks to https://tecosaur.github.io/emacs-config/config.html#lsp-support-src + (cl-defmacro lsp-org-babel-enable (lang) + "Support LANG in org source code block." + (setq centaur-lsp 'lsp-mode) + (cl-check-type lang string) + (let* ((edit-pre (intern (format "org-babel-edit-prep:%s" lang))) + (intern-pre (intern (format "lsp--%s" (symbol-name edit-pre))))) + `(progn + (defun ,intern-pre (info) + (let ((file-name (->> info caddr (alist-get :file)))) + (unless file-name + (setq file-name (make-temp-file "babel-lsp-"))) + (setq buffer-file-name file-name) + (lsp-deferred))) + (put ',intern-pre 'function-documentation + (format "Enable lsp-mode in the buffer of org source block (%s)." + (upcase ,lang))) + (if (fboundp ',edit-pre) + (advice-add ',edit-pre :after ',intern-pre) + (progn + (defun ,edit-pre (info) + (,intern-pre info)) + (put ',edit-pre 'function-documentation + (format "Prepare local buffer environment for org source block (%s)." + (upcase ,lang)))))))) + (defvar org-babel-lang-list + '( "nix" "nix-ts" "go" "python" "ipython" "bash" "sh" )) + (dolist (lang org-babel-lang-list) + (eval `(lsp-org-babel-enable ,lang))) + +#+end_src +*** lsp-bridge +:PROPERTIES: +:CUSTOM_ID: h:f7bc590b-9f91-4f6a-8ffe-93e1dea90a61 +:END: + +This is another lsp-implementation for Emacs using multi-threading, so this should be the least blocking one. Still, in general I prefer [[#h:6cf0310b-2fdf-45f0-9845-4704649777eb][eglot]]. + + +#+begin_src emacs-lisp + + (use-package lsp-bridge + :ensure nil) +#+end_src *** sideline-flymake :PROPERTIES: @@ -13906,26 +27365,11 @@ This brings back warnings and errors on the sideline for eglot; a feature that I :hook (flymake-mode . sideline-mode) :init (setq sideline-flymake-display-mode 'point) ; 'point to show errors only on point - ; 'line to show errors on the current line + ; 'line to show errors on the current line (setq sideline-backends-right '(sideline-flymake))) #+end_src -*** Breadcrumb -:PROPERTIES: -:CUSTOM_ID: h:1de35f27-335d-4cbd-beb6-f85cf5496173 -:END: - -This simple shows the path to the current file on the top of the buffer - I just think it looks kind of neat, even though it is not extremely useful :) - -#+begin_src emacs-lisp - - (use-package breadcrumb - ;; :config (breadcrumb-mode) - ) - -#+end_src - *** Prevent breaking of hardlinks :PROPERTIES: :CUSTOM_ID: h:e9a30d0f-423f-4e85-af4b-f8560f1c1b53 @@ -13954,12 +27398,12 @@ Dirvish is an improvement upon the dired-framework and has more features like fi :config (dirvish-peek-mode) (dirvish-side-follow-mode) - (setq dirvish-open-with-programs - (append dirvish-open-with-programs '( - (("xlsx" "docx" "doc" "odt" "ods") "libreoffice" "%f") - (("jpg" "jpeg" "png") "imv" "%f") - (("pdf") "sioyek" "%f") - (("xopp") "xournalpp" "%f")))) + ;; (setq dirvish-open-with-programs + ;; (append dirvish-open-with-programs '( + ;; (("xlsx" "docx" "doc" "odt" "ods") "libreoffice" "%f") + ;; (("jpg" "jpeg" "png") "imv" "%f") + ;; (("pdf") "sioyek" "%f") + ;; (("xopp") "xournalpp" "%f")))) :custom (delete-by-moving-to-trash t) (dired-listing-switches @@ -14000,36 +27444,6 @@ Dirvish is an improvement upon the dired-framework and has more features like fi ("M-j" . dirvish-fd-jump))) #+end_src -*** pdf-tools: pdf-viewer and support for dirvish -:PROPERTIES: -:CUSTOM_ID: h:b108dd3e-f34d-4ed3-98df-0bf9de055889 -:END: - -This enables pdf-previewing in dirvish and gives a much better pdf-viewer than is shipped normally by emacs. - -#+begin_src emacs-lisp - - ;; (use-package pdf-tools - ;; :init - ;; (if (not (boundp 'pdf-tools-directory)) - ;; (pdf-tools-install)) - ;; :mode ("\\.pdf" . pdf-view-mode)) - -#+end_src - -*** Jupyter -:PROPERTIES: -:CUSTOM_ID: h:c15efae7-b884-4c97-8367-ccc7e7ed9ba8 -:END: - -This is a jupyter client. Using it is a bit cumbersome though, so I have not fully explored all features. - -#+begin_src emacs-lisp - - (use-package ein) - -#+end_src - *** undo-tree :PROPERTIES: :CUSTOM_ID: h:1fc538d1-8c53-48b2-8652-66046f4bbbf8 @@ -14055,10 +27469,6 @@ While we are at it, we are also setting up a persistent undo-file for every file :config (setq undo-tree-history-directory-alist '(("." . "~/.emacs.d/undo")))) - ;; (add-hook 'prog-mode-hook 'undo-tree-mode) - ;; (add-hook 'text-mode-hook 'undo-tree-mode) - ;; (add-hook 'org-mode-hook 'undo-tree-mode) - ;; (add-hook 'latex-mode-hook 'undo-tree-mode) #+end_src *** Hydra :PROPERTIES: @@ -14091,167 +27501,10 @@ I only wrote this in order to try out hydra; rarely do I really need this. Howev ("f" nil "finished" :exit t)) #+end_src -*** External Applications -:PROPERTIES: -:CUSTOM_ID: h:fff816a0-6d70-4bda-abab-833345e51100 -:END: -**** Obsidian -:PROPERTIES: -:CUSTOM_ID: h:9335d32d-bf08-4601-820d-f3d1f33f876f -:END: - -This provides an interface to Obsidian for Emacs - as much as I want to like it, I actually enjoy using the official Obsidian app more - even though that cannot be used by Emacs directly. - -My workflow for Obsidian is now as follows: - -1) create notes either in Emacs or Obsidian -2) look at them in the official client - - I hope that this package will improve, then I will come back to it one day. - -#+begin_src emacs-lisp - - ;; (use-package obsidian - ;; :ensure t - ;; :demand t - ;; :config - ;; (obsidian-specify-path swarsel-obsidian-vault-directory) - ;; (global-obsidian-mode t) - ;; :custom - ;; ;; This directory will be used for `obsidian-capture' if set. - ;; (obsidian-inbox-directory "Inbox") - ;; (bind-key (kbd "C-c M-o") 'obsidian-hydra/body 'obsidian-mode-map) - ;; :bind (:map obsidian-mode-map - ;; ;; Replace C-c C-o with Obsidian.el's implementation. It's ok to use another key binding. - ;; ("C-c C-o" . obsidian-follow-link-at-point) - ;; ;; Jump to backlinks - ;; ("C-c C-b" . obsidian-backlink-jump) - ;; ;; If you prefer you can use `obsidian-insert-link' - ;; ("C-c C-l" . obsidian-insert-wikilink))) - -#+end_src - -**** Anki -:PROPERTIES: -:CUSTOM_ID: h:5854c9a6-1319-4961-a112-75b1bf2e1f69 -:END: - -This section is here to make Anki usable from within Emacs - an endeavour that I have mostly given up on. - -***** Basic Anki setup -:PROPERTIES: -:CUSTOM_ID: h:d20559ed-7ada-4fea-a964-33bfd64b4549 -:END: - -#+begin_src emacs-lisp - - ;; (use-package anki-editor - ;; :after org - ;; :bind (:map org-mode-map - ;; ("" . anki-editor-cloze-region-auto-incr) - ;; ("" . anki-editor-cloze-region-dont-incr) - ;; ("" . anki-editor-reset-cloze-number) - ;; ("" . anki-editor-push-tree)) - ;; :hook (org-capture-after-finalize . anki-editor-reset-cloze-number) ; Reset cloze-number after each capture. - ;; :config - ;; (setq anki-editor-create-decks t ;; Allow anki-editor to create a new deck if it doesn't exist - ;; anki-editor-org-tags-as-anki-tags t) - - ;; (defun anki-editor-cloze-region-auto-incr (&optional arg) - ;; "Cloze region without hint and increase card number." - ;; (interactive) - ;; (anki-editor-cloze-region swarsel-anki-editor-cloze-number "") - ;; (setq swarsel-anki-editor-cloze-number (1+ swarsel-anki-editor-cloze-number)) - ;; (forward-sexp)) - ;; (defun anki-editor-cloze-region-dont-incr (&optional arg) - ;; "Cloze region without hint using the previous card number." - ;; (interactive) - ;; (anki-editor-cloze-region (1- swarsel-anki-editor-cloze-number) "") - ;; (forward-sexp)) - ;; (defun anki-editor-reset-cloze-number (&optional arg) - ;; "Reset cloze number to ARG or 1" - ;; (interactive) - ;; (setq swarsel-anki-editor-cloze-number (or arg 1))) - ;; (defun anki-editor-push-tree () - ;; "Push all notes under a tree." - ;; (interactive) - ;; (anki-editor-push-notes '(4)) - ;; (anki-editor-reset-cloze-number)) - ;; ;; Initialize - ;; (anki-editor-reset-cloze-number) - ;; ) - - ;; (require 'anki-editor) - -#+end_src - -***** Own Anki functions -:PROPERTIES: -:CUSTOM_ID: h:64242e95-6454-4330-bcb9-15353083bade -:END: - -- These functions enable you to quickly set the destination note type and deck - -#+begin_src emacs-lisp - - ;; (defvar swarsel-anki-deck nil) - ;; (defvar swarsel-anki-notetype nil) - ;; (defvar swarsel-anki-fields nil) - - ;; (defun swarsel-anki-set-deck-and-notetype () - ;; (interactive) - ;; (setq swarsel-anki-deck (completing-read "Choose a deck: " - ;; (sort (anki-editor-deck-names) #'string-lessp))) - ;; (setq swarsel-anki-notetype (completing-read "Choose a note type: " - ;; (sort (anki-editor-note-types) #'string-lessp))) - ;; (setq swarsel-anki-fields (progn - ;; (anki-editor--anki-connect-invoke-result "modelFieldNames" `((modelName . ,swarsel-anki-notetype))))) - ;; ) - - ;; (defun swarsel-anki-make-template-string () - ;; (if (not swarsel-anki-deck) - ;; (call-interactively 'swarsel-anki-set-deck-and-notetype)) - ;; (setq swarsel-temp swarsel-anki-fields) - ;; (concat (concat "* %<%H:%M>\n:PROPERTIES:\n:ANKI_NOTE_TYPE: " swarsel-anki-notetype "\n:ANKI_DECK: " swarsel-anki-deck "\n:END:\n** ")(pop swarsel-temp) "\n%?\n** " (mapconcat 'identity swarsel-temp "\n\n** ") "\n\n")) - - ;; (defun swarsel-today() - ;; (format-time-string "%Y-%m-%d")) - - ;; (defun swarsel-obsidian-daily () - ;; (interactive) - ;; (if (not (file-exists-p (expand-file-name (concat (swarsel-today) ".md") swarsel-obsidian-daily-directory))) - ;; (write-region "" nil (expand-file-name (concat (swarsel-today) ".md") swarsel-obsidian-daily-directory)) - ;; ) - ;; (find-file (expand-file-name (concat (swarsel-today) ".md") swarsel-obsidian-daily-directory))) - -#+end_src - *** Email :PROPERTIES: :CUSTOM_ID: h:2f333330-b19d-4f64-85ea-146ff28667e8 :END: -**** make sure mu4e is found -:PROPERTIES: -:CUSTOM_ID: h:48fde614-7cd0-4764-a7ac-0dae60d8b65a -:END: - -This seems not to be needed - I do not yet dare to delete it though. - -#+begin_src emacs-lisp - - ;; (let ((mu4epath - ;; (concat - ;; (f-dirname - ;; (file-truename - ;; (executable-find "mu"))) - ;; "/../share/emacs/site-lisp/mu4e"))) - ;; (when (and - ;; (string-prefix-p "/nix/store/" mu4epath) - ;; (file-directory-p mu4epath)) - ;; (add-to-list 'load-path mu4epath))) - -#+end_src - **** mu4e :PROPERTIES: :CUSTOM_ID: h:b92a18cf-eec3-4605-a8c2-37133ade3574 @@ -14275,7 +27528,11 @@ The hook functions are defined here: [[#h:34506761-06b9-43b5-a818-506d9b3faf28][ (setq mu4e-mu-binary (executable-find "mu")) (setq mu4e-hide-index-messages t) - (setq mu4e-update-interval 180) + ;; this is so that messages that target multiple addresses still are individually shown in the unreads + ;; this is needed because otherwise after closing the view there will still be an unread message + (setq mu4e-search-skip-duplicates nil) + + (setq mu4e-update-interval 60) (setq mu4e-get-mail-command "mbsync -a") (setq mu4e-maildir "~/Mail") @@ -14294,16 +27551,19 @@ The hook functions are defined here: [[#h:34506761-06b9-43b5-a818-506d9b3faf28][ '((:maildir "/leon/Inbox" :key ?1) (:maildir "/nautilus/Inbox" :key ?2) (:maildir "/mrswarsel/Inbox" :key ?3) + (:maildir "/work/Inbox" :key ?4) (:maildir "/Sent Mail" :key ?s) (:maildir "/Trash" :key ?t) (:maildir "/Drafts" :key ?d) (:maildir "/All Mail" :key ?a))) - (setq user-mail-address "leon@swarsel.win" - user-full-name "Leon Schwarzäugl") + (setq user-mail-address (getenv "SWARSEL_MAIL4") + user-full-name (getenv "SWARSEL_FULLNAME")) - - (setq mu4e-user-mail-address-list '(leon.schwarzaeugl@gmail.com leon@swarsel.win nautilus.dw@gmail.com mrswarsel@gmail.com))) + ;; 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))) + ) (add-hook 'mu4e-compose-mode-hook #'swarsel/mu4e-send-from-correct-address) @@ -14321,13 +27581,56 @@ This adds the simple utility of sending desktop notifications whenever a new mai (use-package mu4e-alert :config - (setq mu4e-alert-set-default-style 'libnotify)) + (mu4e-alert-enable-notifications) + (mu4e-alert-set-default-style 'libnotify) + (setq mu4e-alert-interesting-mail-query + (concat "(maildir:/leon/Inbox AND date:today..now" + " OR maildir:/work/Inbox AND date:today..now)" + " AND flag:unread")) + (alert-add-rule + :category "mu4e-alert" + :predicate (lambda (_) (string-match-p "^mu4e-" (symbol-name major-mode))) + :continue t) - (add-hook 'after-init-hook #'mu4e-alert-enable-notifications) + + (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: :CUSTOM_ID: h:c760f04e-622f-4b3e-8916-53ca8cce6edc @@ -14335,7 +27638,6 @@ This adds the simple utility of sending desktop notifications whenever a new mai This provides a beautiful calender to emacs. -Yes, I am aware that I am exposing my university-calendar to the public here. I can imagine worse things ;) if you however know how to obscure this, let me know! #+begin_src emacs-lisp @@ -14343,11 +27645,11 @@ Yes, I am aware that I am exposing my university-calendar to the public here. I :init ;; set org-caldav-sync-initalization (setq swarsel-caldav-synced 0) - (setq org-caldav-url "https://stash.swarsel.win/remote.php/dav/calendars/Swarsel") - (setq org-caldav-calendars - '((:calendar-id "personal" - :inbox "~/Calendars/leon_cal.org"))) - (setq org-caldav-files '("~/Calendars/leon_cal.org")) + ;; (setq org-caldav-url "https://cal.example.org/swarsel/calendar") + ;; (setq org-caldav-calendars + ;; '((:calendar-id "personal" + ;; :inbox "~/Calendars/leon_cal.org"))) + ;; (setq org-caldav-files '("~/Calendars/leon_cal.org")) ;; (setq org-caldav-backup-file "~/org-caldav/org-caldav-backup.org") ;; (setq org-caldav-save-directory "~/org-caldav/") @@ -14374,6 +27676,14 @@ Yes, I am aware that I am exposing my university-calendar to the public here. I :config (bind-key "g" 'cfw:refresh-calendar-buffer cfw:calendar-mode-map) (bind-key "q" 'evil-quit cfw:details-mode-map) + ;; dont change the order of days in this one, as it will break weekend markings + (setq calendar-day-name-array + ["Sunday" "Monday" "Tuesday" "Wednesday" "Thursday" "Friday" "Saturday"]) + + ;; First day of the week + (setq calendar-week-start-day 1) ; 0:Sunday, 1:Monday + + ;; (custom-set-faces ;; '(cfw:face-title ((t (:foreground "#f0dfaf" :weight bold :height 65)))) ;; ) @@ -14381,14 +27691,17 @@ Yes, I am aware that I am exposing my university-calendar to the public here. I (defun swarsel/open-calendar () (interactive) - (unless (eq swarsel-caldav-synced 1) (org-caldav-sync) (setq swarsel-caldav-synced 1)) + ;; (unless (eq swarsel-caldav-synced 1) (org-caldav-sync) (setq swarsel-caldav-synced 1)) ;; (select-frame (make-frame '((name . "calendar")))) ; makes a new frame and selects it ;; (set-face-attribute 'default (selected-frame) :height 65) ; reduces the font size of the new frame (cfw:open-calendar-buffer :contents-sources (list - (cfw:org-create-source "Purple") ; orgmode source - (cfw:ical-create-source "TISS" "https://tiss.tuwien.ac.at/events/rest/calendar/personal?locale=de&token=4463bf7a-87a3-490a-b54c-99b4a65192f3" "Cyan")))) + (cfw:org-create-source "Blue") ; orgmode source + (cfw:ical-create-source (getenv "SWARSEL_CAL1NAME") (getenv "SWARSEL_CAL1") "Cyan") + (cfw:ical-create-source (getenv "SWARSEL_CAL2NAME") (getenv "SWARSEL_CAL2") "Green") + (cfw:ical-create-source (getenv "SWARSEL_CAL3NAME") (getenv "SWARSEL_CAL3") "Magenta") + ))) #+end_src @@ -14406,59 +27719,66 @@ This sets up the =dashboard=, which is really quite useless. But, it looks cool :config (dashboard-setup-startup-hook) ;; (setq initial-buffer-choice (lambda () (get-buffer-create "*dashboard*"))) - (setq dashboard-display-icons-p t ;; display icons on both GUI and terminal - dashboard-icon-type 'nerd-icons ;; use `nerd-icons' package - dashboard-set-file-icons t - dashboard-items '((recents . 5) - (projects . 5) - (agenda . 5)) - dashboard-set-footer nil - dashboard-banner-logo-title "Welcome to SwarsEmacs!" - dashboard-image-banner-max-height 300 - dashboard-startup-banner "~/.dotfiles/wallpaper/swarsel.png" - dashboard-projects-backend 'projectile - dashboard-projects-switch-function 'magit-status - dashboard-set-navigator t - dashboard-startupify-list '(dashboard-insert-banner - dashboard-insert-newline - dashboard-insert-banner-title - dashboard-insert-newline - dashboard-insert-navigator - dashboard-insert-newline - dashboard-insert-init-info - dashboard-insert-items - ) - dashboard-navigator-buttons - `(;; line1 - ((,"" - "SwarselSocial" - "Browse Swarsele" - (lambda (&rest _) (browse-url "instagram.com/Swarsele"))) - (,"" - "SwarselSound" - "Browse SwarselSound" - (lambda (&rest _) (browse-url "sound.swarsel.win")) ) - (,"" - "SwarselSwarsel" - "Browse Swarsel" - (lambda (&rest _) (browse-url "github.com/Swarsel")) ) - (,"" - "SwarselStash" - "Browse SwarselStash" - (lambda (&rest _) (browse-url "stash.swarsel.win")) ) - (,"󰫑" - "SwarselSport" - "Browse SwarselSports" - (lambda (&rest _) (browse-url "social.parkour.wien/@Lenno"))) - ) - ( - (,"󱄅" - "swarsel.win" - "Browse swarsel.win" - (lambda (&rest _) (browse-url "swarsel.win"))) - ) - ))) + (let ((files-domain (getenv "SWARSEL_FILES_DOMAIN")) + (music-domain (getenv "SWARSEL_MUSIC_DOMAIN")) + (insta-domain (getenv "SWARSEL_INSTA_DOMAIN")) + (sport-domain (getenv "SWARSEL_SPORT_DOMAIN")) + (swarsel-domain (getenv "SWARSEL_DOMAIN")) + ) + (setq dashboard-display-icons-p t ;; display icons on both GUI and terminal + dashboard-icon-type 'nerd-icons ;; use `nerd-icons' package + dashboard-set-file-icons t + dashboard-items '((recents . 5) + (projects . 5) + (agenda . 5)) + dashboard-set-footer nil + dashboard-banner-logo-title "Welcome to SwarsEmacs!" + dashboard-image-banner-max-height 300 + dashboard-startup-banner "~/.dotfiles/files/wallpaper/swarsel.png" + dashboard-projects-backend 'projectile + dashboard-projects-switch-function 'magit-status + dashboard-set-navigator t + dashboard-startupify-list '(dashboard-insert-banner + dashboard-insert-newline + dashboard-insert-banner-title + dashboard-insert-newline + dashboard-insert-navigator + dashboard-insert-newline + dashboard-insert-init-info + dashboard-insert-items + ) + dashboard-navigator-buttons + `(;; line1 + ((,"" + "SwarselSocial" + "Browse Swarsele" + (lambda (&rest _) (browse-url ,insta-domain))) + + (,"" + "SwarselSound" + "Browse SwarselSound" + (lambda (&rest _) (browse-url ,(concat "https://" music-domain))) ) + (,"" + "SwarselSwarsel" + "Browse Swarsel" + (lambda (&rest _) (browse-url "https://github.com/Swarsel")) ) + (,"" + "SwarselStash" + "Browse SwarselStash" + (lambda (&rest _) (browse-url ,(concat "https://" files-domain))) ) + (,"󰫑" + "SwarselSport" + "Browse SwarselSports" + (lambda (&rest _) (browse-url ,sport-domain))) + ) + ( + (,"󱄅" + ,swarsel-domain + ,(concat "Browse " main-domain) + (lambda (&rest _) (browse-url ,(concat "https://" swarsel-domain)))) + ) + )))) #+end_src @@ -14471,115 +27791,8 @@ 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) - (defun sudo-find-file (file-name) - "Like find file, but opens the file as root." - (interactive "FSudo Find File: ") - (let ((tramp-file-name (concat "/sudo::" (expand-file-name file-name)))) - (find-file tramp-file-name))) - ;;; vterm/config.el -*- lexical-binding: t; -*- - - ;; Original functions overwrites tramp path with a guessed path. - ;; However it breaks if remote fqdn/hostname is not resolvale by local machine - ;; could also break on port forwarding, multihops, - ;; custom protocol such as: docker, vagrant, ... - ;; *if* you try to shell-side configure them. - ;; Easily testable with vagrant ssh port on localhost. - ;; My workflow is to open a tramp dired on / of the remote to get a - ;; "foothold" then open vterms from there. - (defun vterm--get-directory (path) - "[OVERLOADED] Get normalized directory to PATH." - (when path - (let (directory) - (if (string-match "^\\(.*?\\)@\\(.*?\\):\\(.*?\\)$" path) - (progn - (let ((user (match-string 1 path)) - (host (match-string 2 path)) - (dir (match-string 3 path))) - (if (and (string-equal user user-login-name) - (string-equal host (system-name))) - (progn - (when (file-directory-p dir) - (setq directory (file-name-as-directory dir)))) - (setq directory - ;; Bellow is what i altered - (file-name-as-directory (concat (file-remote-p default-directory) dir)))))) - (when (file-directory-p path) - (setq directory (file-name-as-directory path)))) - directory))) - ;; Injects the payload to the vterm buffer. - (defun me/vterm-load-config () - "Pass local configuration files to vterm. - - Allows remote vterm to be shell-side configured, - without altering remote config. - Also adds my personal configuration that does not rely - too much on external packages. - Prints a reasuring message to proove good faith." - (interactive) - (let (;; Bellow messages to reassure other users that look at history - (reasuring-message (format "Configuring shell of user %s to be emacs comptible" - user-full-name)) - (reasuring-notice "This action is shell local, it will not affect other shells") - ;; Bellow lies my configuration - (basic-func-script (f-read-text (concat (getenv "HOME") - "/.emacs.d/shells/sources/functions.sh"))) - ;; Bellow lies the vterm shell-side configuration - ;; Must be sourced last - (vterm-func-script (f-read-text (concat - (file-name-directory (find-library-name "vterm")) - "/etc/emacs-vterm-bash.sh")))) - (vterm-insert (format "# START: %s\n" reasuring-message)) - (vterm-insert (format "# %s\n" reasuring-notice)) - ;; Create one single block in history - (vterm-insert "{\n") - (vterm-insert basic-func-script) - (vterm-insert vterm-func-script) - (vterm-insert "}\n") - ;; End the single block in history - (vterm-insert (format "# %s\n" reasuring-notice)) - (vterm-insert (format "# STOP: %s\n" reasuring-message)) - ) - ) - - ;; find-file-other-window does not works great on remote: - ;; if given an absolute path on a remote host, - ;; the path will be understood as a local file since no - ;; tramp prefix is present, and bash does not care - ;; about tramp prefixes. - ;; Bellow we solve context before sending it to - ;; ffow - (defun me/vterm--find-file-other-window-wrapper (file) - "Help vterm find a FILE." - (find-file-other-window (me/vterm--ffow-resolver file))) - (defun me/vterm--ffow-resolver (file) - "Help vterm resolve FILE." - (cond - ;; "/sudo::" - ;; doom--sudo-file-path do the trick for us - ((s-starts-with-p "/sudo::" file) - (sudo-find-file - (concat (file-remote-p default-directory) - (substring-no-properties file 7)))) - ;; "/" means we want the "Relative root" - ;; try appending the remote prefix if relevent - ((s-starts-with-p "/" file) - (concat (file-remote-p default-directory) file)) - ;; we got a relative path - ;; we don't need to help ffow to find it - (t - file))) - - ;; The variable vterm-eval-cmds is a SERIOUSLY SENSIBLE variable ! - ;; Do not be the guy that adds RCE into their config ! - - ;; Allow customed ffow to be called from vterm - ;; ffow should be as safe as find-file which is already trusted - ;; we append our resolver that only manipulate strings, - ;; Proove me wrong but i think it's safe. - (add-to-list 'vterm-eval-cmds '("find-file-other-window" - me/vterm--find-file-other-window-wrapper)) #+end_src *** multiple cursors @@ -14589,6 +27802,2895 @@ This sets up the =dashboard=, which is really quite useless. But, it looks cool #+begin_src emacs-lisp -(use-package multiple-cursors) + (use-package multiple-cursors) #+end_src +*** Less logging +:PROPERTIES: +:CUSTOM_ID: h:438d928f-77a8-477a-ac8b-ca54ec673f91 +:END: + +#+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) + +#+end_src + +*** Popup frames +:PROPERTIES: +:CUSTOM_ID: h:5322b631-a108-49a0-b95a-b61a70070dd9 +:END: + +#+begin_src emacs-lisp + (defun prot-window-delete-popup-frame (&rest _) + "Kill selected selected frame if it has parameter `prot-window-popup-frame'. + Use this function via a hook." + (when (frame-parameter nil 'prot-window-popup-frame) + (delete-frame))) + + (defmacro prot-window-define-with-popup-frame (command) + "Define interactive function which calls COMMAND in a new frame. + Make the new frame have the `prot-window-popup-frame' parameter." + `(defun ,(intern (format "prot-window-popup-%s" command)) () + ,(format "Run `%s' in a popup frame with `prot-window-popup-frame' parameter. + Also see `prot-window-delete-popup-frame'." command) + (interactive) + (let ((frame (make-frame '((prot-window-popup-frame . t) + (title . "Emacs Popup Frame"))))) + (unwind-protect + (progn + (select-frame frame) + (switch-to-buffer " prot-window-hidden-buffer-for-popup-frame") + (condition-case nil + (call-interactively ',command) + ((quit error user-error) + (delete-frame frame)))) + (dolist (fr (frame-list)) + (when (string= (frame-parameter fr 'name) "Emacs Popup Anchor") + (delete-frame fr))))))) + + (declare-function org-capture "org-capture" (&optional goto keys)) + (defvar org-capture-after-finalize-hook) + ;;;###autoload (autoload 'prot-window-popup-org-capture "prot-window") + (prot-window-define-with-popup-frame org-capture) + (add-hook 'org-capture-after-finalize-hook #'prot-window-delete-popup-frame) + + (declare-function mu4e "mu4e" (&optional goto keys)) + ;;;###autoload (autoload 'prot-window-popup-mu4e "prot-window") + (prot-window-define-with-popup-frame mu4e) + (advice-add 'mu4e-quit :after #'prot-window-delete-popup-frame) + + (declare-function swarsel/open-calendar "swarsel/open-calendar" (&optional goto keys)) + ;;;###autoload (autoload 'prot-window-popup-swarsel/open-calendar "prot-window") + (prot-window-define-with-popup-frame swarsel/open-calendar) + (advice-add 'bury-buffer :after #'prot-window-delete-popup-frame) + + (declare-function org-agenda "org-agenda" (&optional goto keys)) + ;;;###autoload (autoload 'prot-window-popup-org-agenda "prot-window") + (prot-window-define-with-popup-frame org-agenda) + +#+end_src + +* Appendix A: Noweb-Ref blocks +:PROPERTIES: +:CUSTOM_ID: h:dae0c5bb-edb7-4fe4-ae31-9f8f064cc53c +:END: + +This sections is no longer used really. An introduction can be found in [[#h:bcc3ebbe-df8a-46bd-b42d-73aad6fc66e5][Structure of this file]] under the historical note. The little noweb-ref blocks that I still use are found in [[#h:48e0cb2c-e412-4ae3-a244-80a8c09dbb02][Hosts]] and [[#h:3bb92528-c61c-4b8d-8214-bf2a40baaa32][Services]]. +** General steps when setting up a new machine +:PROPERTIES: +:CUSTOM_ID: h:cc04139d-e9b7-48fe-8e21-fb43aac35b88 +:END: + +These general steps are needed when setting up a new machine and do not fit into another block well: + +#+begin_src markdown :noweb-ref setup :exports both :results html + - setup yubikey (automatic yubikey enrollment is not yet supported by `disko`): + - `systemd-cryptenroll --fido2-device=auto /dev/` +#+end_src + +** Current patches and fixes +:PROPERTIES: +:CUSTOM_ID: h:e1798163-5d88-4776-aa44-57ed2df92e45 +:END: + +These are current deviations from the standard settings that I take while some things are broken upstream + +#+begin_src markdown :noweb-ref fixes :exports both :results html +- 202501102: + - flake: + - emacs-overlay: + - : version pinned because emacsclient is currently broken on latest + - niri-flake: + - currently not using the sugared version of screenshot-[,window], as it is currently broken + - home-manager: + - emacs-tramp: + - using stable version in extraPackages (broken in unstable) + - :ensure nil in emacs tramp settings to use package in extraPackages + - emacs-calfwL + - pinned to version not in nixpkgs (is in latest emacs-overlay, but that is broken) + - vesktop: + - running stable version (broken in unstable) + - batgrep: + - running stable version (broken in unstable) + - swayosd: + - pinned to version not in nixpkgs (fixes https://github.com/ErikReider/SwayOSD/issues/175) +#+end_src + +* Appendix B: Supplementary Files +:PROPERTIES: +:CUSTOM_ID: h:8fc9f66a-7412-4091-8dee-a06f897baf67 +:END: + +This section now holds some of the configuration files that cannot be defined directly within NixOS configuration. These files are usually symlinked using =home.file=. + +** Server Emacs config +:PROPERTIES: +:CUSTOM_ID: h:c1e53aed-fb47-4aff-930c-dc52f3c5dcb8 +:END: + +On my server, I use a reduced, self-contained emacs configuration that only serves as an elfeed sync server. This is currently unused, however, I am keeping this in here for now as a reference. The big problem here was the bidirectional syncing using =bjm/elfeed-updater=. As I am using this both on a laptop client (using elfeed) as well as on a mobile phone (using elfeed-cljsrn over elfeed-web), I set up a Syncthing service to take care of the feeds as well as the db state. However, I could only either achieve changes propagating properly from the laptop to the server or from the phone to the server. Both would not work. This current state represents the state where from-laptop changes would propagate. To allow from-phone changes, change =(elfeed-db-load)= in =bjm/elfeed-updater= to =(elfeed-db-save)=. + + +#+begin_src emacs-lisp :tangle files/emacs/server.el + (require 'package) + + (package-initialize nil) + (setq package-enable-at-startup nil) + + (add-to-list 'package-archives '("org" . "http://orgmode.org/elpa/") t) + + (add-to-list 'package-archives + '("melpa" . "https://melpa.org/packages/") t) + + + (package-initialize) + + (let ((default-directory "~/.emacs.d/elpa/")) + (normal-top-level-add-subdirs-to-load-path)) + + (unless (package-installed-p 'use-package) + (package-refresh-contents) + (package-install 'use-package)) + + (require 'use-package) + + (use-package elfeed + :ensure t + :bind (:map elfeed-search-mode-map + ("q" . bjm/elfeed-save-db-and-bury))) + + (require 'elfeed) + + (use-package elfeed-org + :ensure t + :config + (elfeed-org) + (setq rmh-elfeed-org-files (list "/var/lib/syncthing/.elfeed/elfeed.org"))) + + (use-package elfeed-goodies + :ensure t) + + (elfeed-goodies/setup) + + (use-package elfeed-web + :ensure t) + + (global-set-key (kbd "C-x w") 'bjm/elfeed-load-db-and-open) + + (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) + + + (defun bjm/elfeed-save-db-and-bury () + "Wrapper to save the elfeed db to disk before burying buffer" + (interactive) + (elfeed-db-save) + (quit-window)) + + (defun bjm/elfeed-load-db-and-open () + "Wrapper to load the elfeed db from disk before opening" + (interactive) + (elfeed-db-load) + (elfeed) + (elfeed-search-update--force) + (elfeed-update)) + + (defun bjm/elfeed-updater () + "Wrapper to load the elfeed db from disk before opening" + (interactive) + (elfeed-db-load)) + + (run-with-timer 0 (* 1 60) 'bjm/elfeed-updater) + + (setq httpd-port 9812) + (setq httpd-host "0.0.0.0") + (setq httpd-root "/root/.emacs.d/elpa/elfeed-web-20240729.1741/") + (setq elfeed-db-directory "/var/lib/syncthing/.elfeed/db/") + + (httpd-start) + (elfeed-web-start) + +#+end_src +** tridactylrc +:PROPERTIES: +:CUSTOM_ID: h:fc64f42f-e7cf-4829-89f6-2d0d58e04f51 +:END: + +This is the configuration file for tridactyl, which provides keyboard-driven navigation in firefox. Pay attention to the warnings in this file; depending on your browsing behaviour, you might expose yourself to some vulnerabilities by copying this configuration. + +The =command= command can be supplied with a =-p= flag that will take a single argmuent which is exposed as =JS_ARG=. I use this in a function that switches to an open tab if it exists and otherwise creates it. + +#+begin_src config :tangle files/firefox/tridactyl/tridactylrc :mkdirp yes + +sanitise tridactyllocal tridactylsync + +colourscheme swarsel + +" General Settings +set update.lastchecktime 1720629386560 +set update.lastnaggedversion 1.24.1 +set update.nag true +set update.nagwait 7 +set update.checkintervalsecs 86400 +set configversion 2.0 +set searchurls.no https://search.nixos.org/options?query= +set searchurls.np https://search.nixos.org/packages?query= +set searchurls.hm https://home-manager-options.extranix.com/?query= +set searchurls.@c https://vbc.atlassian.net/wiki/search?text= +set searchurls.@j https://vbc.atlassian.net/issues/?jql=textfields%20~%20%22%s*%22&wildcardFlag=true +set completions.Tab.statusstylepretty true +set hintfiltermode vimperator-reflow +set hintnames numeric +unbind --mode=hint + +" Binds +bind buffer # +bind gd tabdetach +bind gD composite tabduplicate; tabdetach +bind d composite tabprev; tabclose # +bind D tabclose +bind c hint -J +bindurl ^http(s)?://www\.google\.com c hint -Jc [class="LC20lb MBeuO DKV0Md"],[class="YmvwI"],[class="YyVfkd"],[class="fl"] +bindurl ^http(s)?://news\.ycombinator\.com c hint -Jc [class="titleline"],[class="age"] +bindurl ^http(s)?://lobste\.rs c hint -Jc [class="u-url"],[class="comments_label"] +bindurl ^http(s)?://reddit\.com c hint -Jc [class="title may-blank loggedin"],[class="bylink comments may-blank"] +bindurl ^http(s)?://github\.com c hint -Jc [class="Link--primary"],[class="AppHeader-button Button--secondary Button--medium Button p-0 color-fg-muted"],[class="UnderlineNav-item no-wrap js-responsive-underlinenav-item js-selected-navigation-item"],[class="prc-ActionList-ItemLabel-TmBhn"],[class="PRIVATE_TreeView-item-content-text prc-TreeView-TreeViewItemContentText-smZM-"] +bindurl ^http(s)?://vbc\.atlassian\.net\/wiki c hint -Jc [class="_1reo15vq _18m915vq _1bto1l2s _kqswh2mm _o5721q9c _syaz1fxt"],[class="_11c81ixg _1reo15vq _18m915vq _18s81b66 _kqswh2mm _k48p1wq8 _o5721q9c _1bto1l2s _u5f31b66"],[class="_1r04ze3t _kqswstnw"],[class="css-a61etj"],[class="jira-macro-table-underline-pdfexport"] +bindurl ^http(s)?://www\.google\.com gi composite focusinput -l ; text.end_of_line + +" Work +command tab_or_tabopen jsb -p (async () => {let tabs = await browser.tabs.query({}); let tab = tabs.find(t => t.url.includes(JS_ARG)); if (tab) {browser.tabs.update(tab.id, { active: true });} else {tri.excmds.tabopen(JS_ARG);}})() + +command tab_or_tabopen_local jsb -p (async () => {const currentWindow = await browser.windows.getCurrent(); const tabs = await browser.tabs.query({ windowId: currentWindow.id }); const tab = tabs.find(t => t.url.includes(JS_ARG)); if (tab) {browser.tabs.update(tab.id, { active: true });} else {tri.excmds.tabopen(JS_ARG);}})() + +bind gwa tab_or_tabopen_local apic-impimba-1.m.imp.ac.at +bind gwA tab_or_tabopen_local artifactory.imp.ac.at +bind gwb tab_or_tabopen_local bitbucket.vbc.ac.at +bind gwc tab_or_tabopen_local vbc.atlassian.net/wiki +bind gwd tab_or_tabopen_local datadomain-impimba-2.imp.ac.at +bind gwe tab_or_tabopen_local exivity.vbc.ac.at +bind gwg tab_or_tabopen_local github.com +bind gwG tab_or_tabopen_local goc.egi.eu +bind gwh tab_or_tabopen_local jupyterhub.vbc.ac.at +bind gwj tab_or_tabopen_local jenkins.vbc.ac.at +bind gwJ tab_or_tabopen_local test-jenkins.vbc.ac.at +bind gwl tab_or_tabopen_local lucid.app +bind gwm tab_or_tabopen_local monitoring.vbc.ac.at/grafana +bind gwM tab_or_tabopen_local monitoring.vbc.ac.at/prometheus +bind gwn tab_or_tabopen_local netbox.vbc.ac.at +bind gwN tab_or_tabopen_local nap.imp.ac.at +bind gwo tab_or_tabopen_local outlook.office.com +bind gws tab_or_tabopen_local satellite.vbc.ac.at +bind gwt tab_or_tabopen_local tower.vbc.ac.at +bind gwv tab_or_tabopen_local vc-impimba-1.m.imp.ac.at/ui +bind gwx tab_or_tabopen_local xclarity.vbc.ac.at + +unbind --mode=normal gh +bind ghp tab_or_tabopen_local https://github.com/pulls +bind ghi tab_or_tabopen_local https://github.com/issues/assigned?q=is%3Aissue%20state%3Aopen%20archived%3Afalse%20(assignee%3A%40me%20OR%20author%3A%40me)%20sort%3Aupdated-desc +bind ghv tab_or_tabopen_local github.com/orgs/vbc-it/repositories +bind ghc tab_or_tabopen_local github.com/orgs/CLIP-HPC/repositories +bind ghd tab_or_tabopen_local github.com/Swarsel/.dotfiles +bind ghni tab_or_tabopen_local github.com/NixOS/nixpkgs/issues +bind ghnp tab_or_tabopen_local github.com/NixOS/nixpkgs/pulls + +unbind --mode=normal gp +bind gprn tab_or_tabopen_local www.reddit.com/r/NixOS/ +bind gpd tab_or_tabopen_local discourse.nixos.org/ +bind gpp tab_or_tabopen_local parkour.wien/categories + +" Search in page +set findcase smart +bind / fillcmdline find +bind ? fillcmdline find -? +bind n findnext 1 +bind N findnext -1 + +bind j scrollline 4 +bind k scrollline -4 + + +" WARNING: This file defines and runs a command called fixamo_quiet. If you +" also have a malicious addon that operates on `` installed this +" will allow it to steal your firefox account credentials! +" +" With those credentials, an attacker can read anything in your sync account, +" publish addons to the AMO, etc, etc. +" +" Without this command a malicious addon can steal credentials from any site +" that you visit that is not in the restrictedDomains list. +" +" You should comment out the fixamo lines unless you are entirely sure that +" they are what you want. +command fixamo_quiet jsb tri.excmds.setpref("privacy.resistFingerprinting.block_mozAddonManager", "true").then(tri.excmds.setpref("extensions.webextensions.restrictedDomains", '""')) +command fixamo js tri.excmds.setpref("privacy.resistFingerprinting.block_mozAddonManager", "true").then(tri.excmds.setpref("extensions.webextensions.restrictedDomains", '""').then(tri.excmds.fillcmdline_tmp(3000, "Permissions added to user.js. Please restart Firefox to make them take affect."))) + +fixamo_quiet +set allowautofocus false + +" The following modification allows Tridactyl to function on more pages, e.g. raw GitHub pages. +" You may not wish to run this. Mozilla strongly feels that you shouldn't. +" Read https://wiki.mozilla.org/Security/CSP#Goals for more information. +" +" Equivalent to `set csp clobber` before it was removed. +" This weakens your defences against cross-site-scripting attacks +" and other types of code-injection by reducing the strictness +" of Content Security Policy on all sites in a couple of ways. +" +" We remove the sandbox directive +" https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/sandbox +" which allows our iframe (and anyone else's) to run on any website. +" +" We weaken the style-src directive +" https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/style-src +" to allow us to theme our elements. +" This exposes you to 'cross site styling' attacks +jsb browser.webRequest.onHeadersReceived.addListener(tri.request.clobberCSP,{urls:[""],types:["main_frame"]},["blocking","responseHeaders"]) + +" default is 300ms +set hintdelay 500 + +" Some pages like github break on the tridactyl quick search. have this as a fallback +unbind + +" Do not let websites steal sitefocus +set allowautofocus false + +" whitelist sites +" :seturl [URL regex for sites with text editors you use] allowautofocus true + +" stronger blacklist for specific sites +seturl vbc.atlassian.net preventautofocusjackhammer true + +" Subconfig Settings +seturl www.google.com followpagepatterns.next Next +seturl www.google.com followpagepatterns.prev Previous + +" Autocmds +autocmd DocStart undefined mode ignore +autocmd DocStart pokerogue.net mode ignore +autocmd DocStart typelit.io mode ignore +autocmd DocStart vc-impimba-1.m.imp.ac.at/ui/webconsole mode ignore + +" For syntax highlighting see https://github.com/tridactyl/vim-tridactyl +" vim: set filetype=tridactyl + +#+end_src +** tridactyl theme +:PROPERTIES: +:CUSTOM_ID: h:86f1fd9b-56ee-4fd2-8b35-9ea104d83df0 +:END: +#+begin_src config :tangle files/firefox/tridactyl/themes/swarsel.css :mkdirp yes + +:root { + + --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; + + --tridactyl-def-fg: var(--base02); + --tridactyl-cmdl-bg: var(--base00); + --tridactyl-cmdl-fg: var(--base0C); + + --tridactyl-font-family: "San Francisco", sans-serif; + + --tridactyl-cmdl-font-size: 1.5rem; + --tridactyl-cmdl-line-height: 1.5; + + --tridactyl-cmplt-option-height: 1.4em; + --tridactyl-cmplt-font-size: var(--tridactyl-small-font-size); + --tridactyl-cmplt-border-top: unset; + + --tridactyl-status-font-size: 9px; + --tridactyl-status-font-family: "Fira Code", monospace; + --tridactyl-status-border: 1px var(--tridactyl-fg) solid; + + --tridactyl-header-font-size: var(--tridactyl-small-font-size); + --tridactyl-header-font-weight: 200; + --tridactyl-header-border-bottom: unset; + + --tridactyl-hintspan-font-size: var(--tridactyl-font-size); + --tridactyl-hint-active-fg: none; + +} + +:root #command-line-holder { + order: 1; + border: 2px solid var(--tridactyl-cmdl-fg); + color: var(--tridactyl-cmdl-bg); +} + +:root #tridactyl-input { + width: 90%; + padding: 1rem; + color: var(--tridactyl-def-fg); +} + +:root #completions table { + font-size: 0.8rem; + font-weight: 200; + border-spacing: 0; + table-layout: fixed; + padding: 1rem; + padding-top: 0; +} + +:root #completions > div { + max-height: calc(20 * var(--tridactyl-cmplt-option-height)); + min-height: calc(10 * var(--tridactyl-cmplt-option-height)); +} + +/* COMPLETIONS */ + +:root #completions { + font-weight: 200; + order: 2; + color: var(--tridactyl-def-fg); + background: var(--tridactyl-cmdl-bg); + +} + +/* Olie doesn't know how CSS inheritance works */ +:root #completions .HistoryCompletionSource { + max-height: unset; + min-height: unset; +} + +:root #completions .HistoryCompletionSource table { + width: 100%; + font-size: 9pt; + border-spacing: 0; + table-layout: fixed; +} + +/* redundancy 2: redundancy 2: more redundancy */ +:root #completions .BmarkCompletionSource { + max-height: unset; + min-height: unset; +} + +:root #completions table tr { white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +:root #completions .url { + background: var(--tridactyl-cmdl-bg); +} + +:root #completions .focused { + background: #44391F; +} +:root #completions .focused .url { + background: #44391F; +} + +:root #completions .BufferCompletionSource table { + width: unset; + font-size: unset; + border-spacing: unset; + table-layout: unset; +} + +:root #completions table tr { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +:root #completions .sectionHeader { + background: unset; + padding: 1rem !important; + padding-left: unset; + padding-bottom: 0.2rem; +} + +:root #cmdline_iframe { + position: fixed !important; + bottom: unset; + top: 25% !important; + left: 10% !important; + z-index: 2147483647 !important; + width: 80% !important; + box-shadow: rgba(0, 0, 0, 0.5) 0px 0px 15px !important; +} + +:root .TridactylStatusIndicator { + position: fixed !important; + bottom: 0 !important; + font-weight: 200 !important; + padding: 0.8ex !important; +} + +/* #Shydactyl-normal { */ +/* border-color: green !important; */ +/* } */ + +/* #Shydactyl-insert { */ +/* border-color: yellow !important; */ +/* } */ + + +#+end_src + +** Waybar style.css +:PROPERTIES: +:CUSTOM_ID: h:77b1c523-5074-4610-b320-90af95e6134d +:END: + +This is the stylesheet used by waybar. + +#+begin_src css :tangle files/waybar/style.css :mkdirp yes + @define-color foreground #fdf6e3; + @define-color background #1a1a1a; + @define-color background-alt #292b2e; + @define-color foreground-warning #268bd2; + @define-color background-warning @background; + @define-color foreground-error red; + @define-color background-error @background; + @define-color foreground-critical gold; + @define-color background-critical blue; + + + ,* { + border: none; + border-radius: 0; + font-family: "FiraCode Nerd Font Propo", "Font Awesome 5 Free"; + font-size: 14px; + min-height: 0; + margin: -1px 0px; + } + + window#waybar { + background: transparent; + color: @foreground; + transition-duration: .5s; + } + + window#waybar.hidden { + opacity: 0.2; + } + + + #mpris { + padding: 0 10px; + background-color: transparent; + color: #1DB954; + font-family: Monospace; + font-size: 12px; + } + + #custom-right-arrow-dark, + #custom-left-arrow-dark { + color: @background; + background: @background-alt; + font-size: 24px; + } + + #window { + font-size: 12px; + padding: 0 20px; + } + + #mode { + background: @background-critical; + color: @foreground-critical; + padding: 0 3px; + } + + #privacy, + #custom-configwarn { + color: black; + padding: 0 3px; + animation-name: configblink; + animation-duration: 0.5s; + animation-timing-function: linear; + animation-iteration-count: infinite; + animation-direction: alternate; + } + + #custom-nix-updates { + color: white; + padding: 0 3px; + } + + #custom-outer-right-arrow-dark, + #custom-outer-left-arrow-dark { + color: @background; + font-size: 24px; + } + + #custom-outer-left-arrow-dark, + #custom-left-arrow-dark, + #custom-left-arrow-light { + margin: 0 -1px; + } + + #custom-right-arrow-light, + #custom-left-arrow-light { + color: @background-alt; + background: @background; + font-size: 24px; + } + + #workspaces, + #clock.1, + #clock.2, + #clock.3, + #pulseaudio, + #memory, + #cpu, + #temperature, + #custom-scratchpad-indicator, + #power-profiles-daemon, + #idle_inhibitor, + #backlight-slider, + #mpris, + #tray { + background: @background; + } + + #network, + #custom-vpn, + #clock.2, + #battery, + #cpu, + #custom-pseudobat, + #disk { + background: @background-alt; + } + + + #workspaces button { + padding: 0 2px; + color: #fdf6e3; + } + #workspaces button.focused { + color: @foreground-warning; + } + + #workspaces button:hover { + background: @foreground; + color: @background; + border: @foreground; + padding: 0 2px; + box-shadow: inherit; + text-shadow: inherit; + } + + #workspaces button.urgent { + color: @background-critical; + background: @foreground-critical; + } + + #custom-vpn, + #network { + color: #cc99c9; + } + + #temperature, + #power-profiles-daemon { + color: #9ec1cf; + } + + #disk { + /*color: #b58900;*/ + color: #9ee09e; + } + + #custom-scratchpad-indicator { + color: #ffffff; + } + + #disk.warning { + color: @foreground-error; + background-color: @background-error; + } + #disk.critical, + #temperature.critical { + color: @foreground-critical; + background-color: @background-critical; + animation-name: blink; + animation-duration: 0.5s; + animation-timing-function: linear; + animation-iteration-count: infinite; + animation-direction: alternate; + } + #pulseaudio.muted { + color: @foreground-error; + } + #memory { + /*color: #2aa198;*/ + color: #fdfd97; + } + #cpu { + /*color: #6c71c4;*/ + color: #feb144; + } + + #pulseaudio { + /*color: #268bd2;*/ + color: #ff6663; + } + + #battery, + #custom-pseudobat { + color: cyan; + } + #battery.discharging { + color: #859900; + } + + @keyframes blink { + to { + color: @foreground-error; + background-color: @background-error; + } + } + @keyframes configblink { + to { + color: @foreground-error; + background-color: transparent; + } + } + + #battery.critical:not(.charging) { + color: @foreground-critical; + background-color: @background-critical; + animation-name: blink; + animation-duration: 0.5s; + animation-timing-function: linear; + animation-iteration-count: infinite; + animation-direction: alternate; + } + + #backlight-slider slider { + min-height: 0px; + min-width: 0px; + opacity: 0; + background-image: none; + border: none; + box-shadow: none; + } + #backlight-slider trough { + min-height: 5px; + min-width: 80px; + border-radius: 5px; + background-color: black; + } + #backlight-slider highlight { + min-width: 0px; + border-radius: 5px; + background-color: grey; + } + + #clock.1, + #clock.2, + #clock.3 { + font-family: Monospace; + } + + #clock, + #pulseaudio, + #memory, + #cpu, + #tray, + #temperature, + #power-profiles-daemon, + #network, + #custom-vpn, + #mpris, + #battery, + #custom-scratchpad-indicator, + #custom-pseudobat, + #disk { + padding: 0 3px; + } + +#+end_src +** justfile +:PROPERTIES: +:CUSTOM_ID: h:788937cf-8816-466b-8e57-1b695cb50f52 +:END: +This file defines a few workflows that I often need to run when working on my configuration. This works similar to =make=, but is geared towards general tasks and as such requires no extra handling (as long as there are no dependencies involved) or =.PHONY= recipes. + +(In the org-src block I still call it a Makefile in order to get syntax highlighting) + +#+begin_src makefile :tangle justfile + + default: + @just --list + + check: + nix flake check --keep-going + + check-trace: + nix flake check --show-trace + + update: + nix flake update + + iso CONFIG="live-iso": + rm -rf result + nix build --print-out-paths .#live-iso + + iso-install DRIVE: iso + sudo dd if=$(eza --sort changed result/iso/*.iso | tail -n1) of={{DRIVE}} bs=4M status=progress oflag=sync + + dd DRIVE ISO: + sudo dd if=$(eza --sort changed {{ISO}} | tail -n1) of={{DRIVE}} bs=4M status=progress oflag=sync + + sync USER HOST: + rsync -rltv --filter=':- .gitignore' -e "ssh -l {{USER}}" . {{USER}}@{{HOST}}:.dotfiles/ + + secrets USER HOST: + rsync -rltv -e "ssh -l {{USER}}" /var/tmp/nix-import-encrypted/1000/ {{USER}}@{{HOST}}:/var/tmp/nix-import-encrypted/0 + + bootstrap DEST CONFIG ARCH="x86_64-linux" NODISKODEPS="": + nix develop .#deploy --command zsh -c "swarsel-bootstrap {{NODISKODEPS}} -n {{CONFIG}} -d {{DEST}} -a {{ARCH}}" + +#+end_src +** aspell.conf +:PROPERTIES: +:CUSTOM_ID: h:038feb42-6e1e-4b65-abe9-e26746b72b78 +:END: + +#+begin_src shell :tangle files/config/.aspell.conf +dict-dir /run/current-system/sw/lib/aspell +#+end_src +** nix-plugins.patch +:PROPERTIES: +:CUSTOM_ID: h:931ff2fd-61f0-4f8f-b221-d879780f38d7 +:END: + +#+begin_src diff :tangle nix/nix-plugins.patch +diff --git a/extra-builtins.cc b/extra-builtins.cc +index 3a0f90e..bb10f8b 100644 +--- a/extra-builtins.cc ++++ b/extra-builtins.cc +@@ -1,9 +1,9 @@ +-#include +-#include +-#include +-#include +-#include +-#include +-#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + + #include "nix-plugins-config.h" +#+end_src +** Zellij layout swarsel.kdl.nix +:PROPERTIES: +:CUSTOM_ID: h:bed316c9-47ed-494f-8375-998ef1315d7b +:END: + +#+begin_src shell :tangle files/zellij/layouts/swarsel.kdl.nix +{ config, pkgs }: +let + inherit (config.lib.stylix) colors; +in +'' + layout { + swap_tiled_layout name="vertical" { + tab max_panes=5 { + pane split_direction="vertical" { + pane + pane { children; } + } + } + tab max_panes=8 { + pane split_direction="vertical" { + pane { children; } + pane { pane; pane; pane; pane; } + } + } + tab max_panes=12 { + pane split_direction="vertical" { + pane { children; } + pane { pane; pane; pane; pane; } + pane { pane; pane; pane; pane; } + } + } + } + + swap_tiled_layout name="horizontal" { + tab max_panes=5 { + pane + pane + } + tab max_panes=8 { + pane { + pane split_direction="vertical" { children; } + pane split_direction="vertical" { pane; pane; pane; pane; } + } + } + tab max_panes=12 { + pane { + pane split_direction="vertical" { children; } + pane split_direction="vertical" { pane; pane; pane; pane; } + pane split_direction="vertical" { pane; pane; pane; pane; } + } + } + } + + swap_tiled_layout name="stacked" { + tab min_panes=5 { + pane split_direction="vertical" { + pane + pane stacked=true { children; } + } + } + } + + swap_floating_layout name="staggered" { + floating_panes + } + + swap_floating_layout name="enlarged" { + floating_panes max_panes=10 { + pane { x "5%"; y 1; width "90%"; height "90%"; } + pane { x "5%"; y 2; width "90%"; height "90%"; } + pane { x "5%"; y 3; width "90%"; height "90%"; } + pane { x "5%"; y 4; width "90%"; height "90%"; } + pane { x "5%"; y 5; width "90%"; height "90%"; } + pane { x "5%"; y 6; width "90%"; height "90%"; } + pane { x "5%"; y 7; width "90%"; height "90%"; } + pane { x "5%"; y 8; width "90%"; height "90%"; } + pane { x "5%"; y 9; width "90%"; height "90%"; } + pane focus=true { x 10; y 10; width "90%"; height "90%"; } + } + } + + swap_floating_layout name="spread" { + floating_panes max_panes=1 { + pane {y "50%"; x "50%"; } + } + floating_panes max_panes=2 { + pane { x "1%"; y "25%"; width "45%"; } + pane { x "50%"; y "25%"; width "45%"; } + } + floating_panes max_panes=3 { + pane focus=true { y "55%"; width "45%"; height "45%"; } + pane { x "1%"; y "1%"; width "45%"; } + pane { x "50%"; y "1%"; width "45%"; } + } + floating_panes max_panes=4 { + pane { x "1%"; y "55%"; width "45%"; height "45%"; } + pane focus=true { x "50%"; y "55%"; width "45%"; height "45%"; } + pane { x "1%"; y "1%"; width "45%"; height "45%"; } + pane { x "50%"; y "1%"; width "45%"; height "45%"; } + } + } + + default_tab_template { + children + pane size=1 borderless=true { + plugin location="file://${pkgs.zjstatus}/bin/zjstatus.wasm" { + format_left "{mode}#[bg=#${colors.base00}] {tabs}" + format_center "" + format_right "#[bg=#${colors.base00},fg=#${colors.base02}]#[bg=#${colors.base02},fg=#${colors.base01},bold] #[bg=#${colors.base02},fg=#${colors.base01},bold] {session} #[bg=#${colors.base02},fg=#${colors.base01},bold]" + format_space "" + format_hide_on_overlength "false" + format_precedence "lcr" + + border_enabled "false" + border_char "─" + border_format "#[fg=#6C7086]{char}" + border_position "top" + + mode_normal "#[bg=#${colors.base0B},fg=#${colors.base01},bold] NORMAL#[bg=#${colors.base01},fg=#${colors.base0B}]█" + mode_locked "#[bg=#${colors.base04},fg=#${colors.base01},bold] LOCKED #[bg=#${colors.base01},fg=#${colors.base04}]█" + mode_resize "#[bg=#${colors.base08},fg=#${colors.base01},bold] RESIZE#[bg=#${colors.base01},fg=#${colors.base08}]█" + mode_pane "#[bg=#${colors.base0D},fg=#${colors.base01},bold] PANE#[bg=#${colors.base01},fg=#${colors.base0D}]█" + mode_tab "#[bg=#${colors.base07},fg=#${colors.base01},bold] TAB#[bg=#${colors.base01},fg=#${colors.base07}]█" + mode_scroll "#[bg=#${colors.base0A},fg=#${colors.base01},bold] SCROLL#[bg=#${colors.base01},fg=#${colors.base0A}]█" + mode_enter_search "#[bg=#${colors.base0D},fg=#${colors.base01},bold] ENT-SEARCH#[bg=#${colors.base01},fg=#${colors.base0D}]█" + mode_search "#[bg=#${colors.base0D},fg=#${colors.base01},bold] SEARCHARCH#[bg=#${colors.base01},fg=#${colors.base0D}]█" + mode_rename_tab "#[bg=#${colors.base07},fg=#${colors.base01},bold] RENAME-TAB#[bg=#${colors.base01},fg=#${colors.base07}]█" + mode_rename_pane "#[bg=#${colors.base0D},fg=#${colors.base01},bold] RENAME-PANE#[bg=#${colors.base01},fg=#${colors.base0D}]█" + mode_session "#[bg=#${colors.base0E},fg=#${colors.base01},bold] SESSION#[bg=#${colors.base01},fg=#${colors.base0E}]█" + mode_move "#[bg=#${colors.base0F},fg=#${colors.base01},bold] MOVE#[bg=#${colors.base01},fg=#${colors.base0F}]█" + mode_prompt "#[bg=#${colors.base0D},fg=#${colors.base01},bold] PROMPT#[bg=#${colors.base01},fg=#${colors.base0D}]█" + mode_tmux "#[bg=#${colors.base09},fg=#${colors.base01},bold] TMUX#[bg=#${colors.base01},fg=#${colors.base09}]█" + + // formatting for inactive tabs + tab_normal "#[bg=#${colors.base01},fg=#${colors.base0C}]█#[bg=#${colors.base0C},fg=#${colors.base01},bold]{index} #[bg=#${colors.base01},fg=#${colors.base0C},bold] {name}{floating_indicator}#[bg=#${colors.base01},fg=#${colors.base01},bold]█" + tab_normal_fullscreen "#[bg=#${colors.base01},fg=#${colors.base0C}]█#[bg=#${colors.base0C},fg=#${colors.base01},bold]{index} #[bg=#${colors.base01},fg=#${colors.base0C},bold] {name}{fullscreen_indicator}#[bg=#${colors.base01},fg=#${colors.base01},bold]█" + tab_normal_sync "#[bg=#${colors.base01},fg=#${colors.base0C}]█#[bg=#${colors.base0C},fg=#${colors.base01},bold]{index} #[bg=#${colors.base01},fg=#${colors.base0C},bold] {name}{sync_indicator}#[bg=#${colors.base01},fg=#${colors.base01},bold]█" + + // formatting for the current active tab + tab_active "#[bg=#${colors.base01},fg=#${colors.base09}]█#[bg=#${colors.base09},fg=#${colors.base01},bold]{index} #[bg=#${colors.base01},fg=#${colors.base09},bold] {name}{floating_indicator}#[bg=#${colors.base01},fg=#${colors.base01},bold]█" + tab_active_fullscreen "#[bg=#${colors.base01},fg=#${colors.base09}]█#[bg=#${colors.base09},fg=#${colors.base01},bold]{index} #[bg=#${colors.base01},fg=#${colors.base09},bold] {name}{fullscreen_indicator}#[bg=#${colors.base01},fg=#${colors.base01},bold]█" + tab_active_sync "#[bg=#${colors.base01},fg=#${colors.base09}]█#[bg=#${colors.base09},fg=#${colors.base01},bold]{index} #[bg=#${colors.base01},fg=#${colors.base09},bold] {name}{sync_indicator}#[bg=#${colors.base01},fg=#${colors.base01},bold]█" + + // separator between the tabs + tab_separator "#[bg=#${colors.base00}] " + + // indicators + tab_sync_indicator " " + tab_fullscreen_indicator " 󰊓" + tab_floating_indicator " 󰹙" + + command_git_branch_command "git rev-parse --abbrev-ref HEAD" + command_git_branch_format "#[fg=blue] {stdout} " + command_git_branch_interval "10" + command_git_branch_rendermode "static" + + datetime "#[fg=#6C7086,bold] {format} " + datetime_format "%A, %d %b %Y %H:%M" + datetime_timezone "Europe/Vienna" + } + } + } + } +'' + +#+end_src +** Zellij config.kdl.nix +:PROPERTIES: +:CUSTOM_ID: h:ae07e867-fc17-4dd7-bd21-5886265308ee +:END: + +#+begin_src nix-ts :tangle files/zellij/config.kdl.nix + { config }: + '' + pane_frames false + simplified_ui false + default_shell "zsh" + copy_on_select true + on_force_close "detach" + show_startup_tips false + + default_layout "default" + layout_dir "${config.home.homeDirectory}/.config/zellij/layouts" + theme_dir "${config.home.homeDirectory}/.config/zellij/themes" + + keybinds clear-defaults=true { + locked { + bind "Ctrl g" { SwitchToMode "normal"; } + } + pane { + bind "left" { MoveFocus "left"; } + bind "down" { MoveFocus "down"; } + bind "up" { MoveFocus "up"; } + bind "right" { MoveFocus "right"; } + bind "c" { SwitchToMode "renamepane"; PaneNameInput 0; } + bind "d" { NewPane "down"; SwitchToMode "normal"; } + bind "e" { TogglePaneEmbedOrFloating; SwitchToMode "normal"; } + bind "f" { ToggleFocusFullscreen; SwitchToMode "normal"; } + bind "h" { MoveFocus "left"; } + bind "j" { MoveFocus "down"; } + bind "k" { MoveFocus "up"; } + bind "l" { MoveFocus "right"; } + bind "n" { NewPane; SwitchToMode "normal"; } + bind "p" { SwitchFocus; } + bind "Ctrl p" { SwitchToMode "normal"; } + bind "r" { NewPane "right"; SwitchToMode "normal"; } + bind "w" { ToggleFloatingPanes; SwitchToMode "normal"; } + bind "z" { TogglePaneFrames; SwitchToMode "normal"; } + } + tab { + bind "left" { GoToPreviousTab; } + bind "down" { GoToNextTab; } + bind "up" { GoToPreviousTab; } + bind "right" { GoToNextTab; } + bind "1" { GoToTab 1; SwitchToMode "normal"; } + bind "2" { GoToTab 2; SwitchToMode "normal"; } + bind "3" { GoToTab 3; SwitchToMode "normal"; } + bind "4" { GoToTab 4; SwitchToMode "normal"; } + bind "5" { GoToTab 5; SwitchToMode "normal"; } + bind "6" { GoToTab 6; SwitchToMode "normal"; } + bind "7" { GoToTab 7; SwitchToMode "normal"; } + bind "8" { GoToTab 8; SwitchToMode "normal"; } + bind "9" { GoToTab 9; SwitchToMode "normal"; } + bind "[" { BreakPaneLeft; SwitchToMode "normal"; } + bind "]" { BreakPaneRight; SwitchToMode "normal"; } + bind "b" { BreakPane; SwitchToMode "normal"; } + bind "h" { GoToPreviousTab; } + bind "j" { GoToNextTab; } + bind "k" { GoToPreviousTab; } + bind "l" { GoToNextTab; } + bind "n" { NewTab; SwitchToMode "normal"; } + bind "r" { SwitchToMode "renametab"; TabNameInput 0; } + bind "s" { ToggleActiveSyncTab; SwitchToMode "normal"; } + bind "Ctrl t" { SwitchToMode "normal"; } + bind "x" { CloseTab; SwitchToMode "normal"; } + bind "tab" { ToggleTab; } + } + resize { + bind "left" { Resize "Increase left"; } + bind "down" { Resize "Increase down"; } + bind "up" { Resize "Increase up"; } + bind "right" { Resize "Increase right"; } + bind "+" { Resize "Increase"; } + bind "-" { Resize "Decrease"; } + bind "=" { Resize "Increase"; } + bind "H" { Resize "Decrease left"; } + bind "J" { Resize "Decrease down"; } + bind "K" { Resize "Decrease up"; } + bind "L" { Resize "Decrease right"; } + bind "h" { Resize "Increase left"; } + bind "j" { Resize "Increase down"; } + bind "k" { Resize "Increase up"; } + bind "l" { Resize "Increase right"; } + bind "Ctrl n" { SwitchToMode "normal"; } + } + move { + bind "left" { MovePane "left"; } + bind "down" { MovePane "down"; } + bind "up" { MovePane "up"; } + bind "right" { MovePane "right"; } + bind "h" { MovePane "left"; } + bind "Ctrl h" { SwitchToMode "normal"; } + bind "j" { MovePane "down"; } + bind "k" { MovePane "up"; } + bind "l" { MovePane "right"; } + bind "n" { MovePane; } + bind "p" { MovePaneBackwards; } + bind "tab" { MovePane; } + } + scroll { + bind "e" { EditScrollback; SwitchToMode "normal"; } + bind "s" { SwitchToMode "entersearch"; SearchInput 0; } + } + search { + bind "c" { SearchToggleOption "CaseSensitivity"; } + bind "n" { Search "down"; } + bind "o" { SearchToggleOption "WholeWord"; } + bind "p" { Search "up"; } + bind "w" { SearchToggleOption "Wrap"; } + } + session { + bind "c" { + LaunchOrFocusPlugin "configuration" { + floating true + move_to_focused_tab true + } + SwitchToMode "normal" + } + bind "Ctrl o" { SwitchToMode "normal"; } + bind "p" { + LaunchOrFocusPlugin "plugin-manager" { + floating true + move_to_focused_tab true + } + SwitchToMode "normal" + } + bind "w" { + LaunchOrFocusPlugin "session-manager" { + floating true + move_to_focused_tab true + } + SwitchToMode "normal" + } + } + shared_except "locked" { + bind "Alt left" { MoveFocusOrTab "left"; } + bind "Alt down" { MoveFocus "down"; } + bind "Alt up" { MoveFocus "up"; } + bind "Alt right" { MoveFocusOrTab "right"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt [" { PreviousSwapLayout; } + bind "Alt ]" { NextSwapLayout; } + bind "Alt f" { ToggleFloatingPanes; } + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Alt h" { MoveFocusOrTab "left"; } + bind "Alt i" { MoveTab "left"; } + bind "Alt j" { MoveFocus "down"; } + bind "Alt k" { MoveFocus "up"; } + bind "Alt l" { MoveFocusOrTab "right"; } + bind "Alt n" { NewPane; } + bind "Alt o" { MoveTab "right"; } + bind "Ctrl q" { Quit; } + } + shared_except "locked" "move" { + bind "Ctrl h" { SwitchToMode "move"; } + } + shared_except "locked" "session" { + bind "Ctrl o" { SwitchToMode "session"; } + } + shared_except "locked" "scroll" "search" "tmux" { + bind "Ctrl b" { SwitchToMode "tmux"; } + } + shared_except "locked" "scroll" "search" { + bind "Ctrl s" { SwitchToMode "scroll"; } + } + shared_except "locked" "tab" { + bind "Ctrl t" { SwitchToMode "tab"; } + } + shared_except "locked" "pane" { + bind "Ctrl p" { SwitchToMode "pane"; } + } + shared_except "locked" "resize" { + bind "Ctrl n" { SwitchToMode "resize"; } + } + shared_except "normal" "locked" "entersearch" { + bind "enter" { SwitchToMode "normal"; } + } + shared_except "normal" "locked" "entersearch" "renametab" "renamepane" { + bind "esc" { SwitchToMode "normal"; } + } + shared_among "pane" "tmux" { + bind "x" { CloseFocus; SwitchToMode "normal"; } + } + shared_among "scroll" "search" { + bind "PageDown" { PageScrollDown; } + bind "PageUp" { PageScrollUp; } + bind "left" { PageScrollUp; } + bind "down" { ScrollDown; } + bind "up" { ScrollUp; } + bind "right" { PageScrollDown; } + bind "Ctrl b" { PageScrollUp; } + bind "Ctrl c" { ScrollToBottom; SwitchToMode "normal"; } + bind "d" { HalfPageScrollDown; } + bind "Ctrl f" { PageScrollDown; } + bind "h" { PageScrollUp; } + bind "j" { ScrollDown; } + bind "k" { ScrollUp; } + bind "l" { PageScrollDown; } + bind "Ctrl s" { SwitchToMode "normal"; } + bind "u" { HalfPageScrollUp; } + } + entersearch { + bind "Ctrl c" { SwitchToMode "scroll"; } + bind "esc" { SwitchToMode "scroll"; } + bind "enter" { SwitchToMode "search"; } + } + renametab { + bind "esc" { UndoRenameTab; SwitchToMode "tab"; } + } + shared_among "renametab" "renamepane" { + bind "Ctrl c" { SwitchToMode "normal"; } + } + renamepane { + bind "esc" { UndoRenamePane; SwitchToMode "pane"; } + } + shared_among "session" "tmux" { + bind "d" { Detach; } + } + tmux { + bind "left" { MoveFocus "left"; SwitchToMode "normal"; } + bind "down" { MoveFocus "down"; SwitchToMode "normal"; } + bind "up" { MoveFocus "up"; SwitchToMode "normal"; } + bind "right" { MoveFocus "right"; SwitchToMode "normal"; } + bind "space" { NextSwapLayout; } + bind "\"" { NewPane "down"; SwitchToMode "normal"; } + bind "%" { NewPane "right"; SwitchToMode "normal"; } + bind "," { SwitchToMode "renametab"; } + bind "[" { SwitchToMode "scroll"; } + bind "Ctrl b" { Write 2; SwitchToMode "normal"; } + bind "c" { NewTab; SwitchToMode "normal"; } + bind "h" { MoveFocus "left"; SwitchToMode "normal"; } + bind "j" { MoveFocus "down"; SwitchToMode "normal"; } + bind "k" { MoveFocus "up"; SwitchToMode "normal"; } + bind "l" { MoveFocus "right"; SwitchToMode "normal"; } + bind "n" { GoToNextTab; SwitchToMode "normal"; } + bind "o" { FocusNextPane; } + bind "p" { GoToPreviousTab; SwitchToMode "normal"; } + bind "z" { ToggleFocusFullscreen; SwitchToMode "normal"; } + } + } + + // Plugin aliases - can be used to change the implementation of Zellij + // changing these requires a restart to take effect + plugins { + compact-bar location="zellij:compact-bar" + configuration location="zellij:configuration" + filepicker location="zellij:strider" { + cwd "/" + } + plugin-manager location="zellij:plugin-manager" + session-manager location="zellij:session-manager" + status-bar location="zellij:status-bar" + strider location="zellij:strider" + tab-bar location="zellij:tab-bar" + welcome-screen location="zellij:session-manager" { + welcome_screen true + } + } + + // Plugins to load in the background when a new session starts + // eg. "file:/path/to/my-plugin.wasm" + // eg. "https://example.com/my-plugin.wasm" + load_plugins { + } + + // Provide a command to execute when copying text. The text will be piped to + // the stdin of the program to perform the copy. This can be used with + // terminal emulators which do not support the OSC 52 ANSI control sequence + // that will be used by default if this option is not set. + // Examples: + // + // copy_command "xclip -selection clipboard" // x11 + // copy_command "wl-copy" // wayland + // copy_command "pbcopy" // osx + // + // copy_command "pbcopy" + + // Choose the destination for copied text + // Allows using the primary selection buffer (on x11/wayland) instead of the system clipboard. + // Does not apply when using copy_command. + // Options: + // - system (default) + // - primary + // + // copy_clipboard "primary" + + // Path to the default editor to use to edit pane scrollbuffer + // Default: $EDITOR or $VISUAL + // scrollback_editor "/usr/bin/vim" + + // Toggle between having Zellij lay out panes according to a predefined set of layouts whenever possible + // Options: + // - true (default) + // - false + // + // auto_layout false + + // Whether sessions should be serialized to the cache folder (including their tabs/panes, cwds and running commands) so that they can later be resurrected + // Options: + // - true (default) + // - false + // + // session_serialization false + + // Whether pane viewports are serialized along with the session, default is false + // Options: + // - true + // - false (default) + // + // serialize_pane_viewport false + + // Scrollback lines to serialize along with the pane viewport when serializing sessions, 0 + // defaults to the scrollback size. If this number is higher than the scrollback size, it will + // also default to the scrollback size. This does nothing if `serialize_pane_viewport` is not true. + // + // scrollback_lines_to_serialize 10000 + + // Enable or disable the rendering of styled and colored underlines (undercurl). + // May need to be disabled for certain unsupported terminals + // (Requires restart) + // Default: true + // + // styled_underlines false + + // How often in seconds sessions are serialized + // + // serialization_interval 10000 + + // Enable or disable writing of session metadata to disk (if disabled, other sessions might not know + // metadata info on this session) + // (Requires restart) + // Default: false + // + // disable_session_metadata false + + // Enable or disable support for the enhanced Kitty Keyboard Protocol (the host terminal must also support it) + // (Requires restart) + // Default: true (if the host terminal supports it) + // + // support_kitty_keyboard_protocol false + '' + +#+end_src +** Vieb config +:PROPERTIES: +:CUSTOM_ID: h:0124a4eb-4ea3-455c-939d-ba4584c703af +:END: + +#+begin_src shell :tangle files/vieb/viebrc +" Options +set adblocker=update +set adblockernotifications=all +set cache=clearonquit +set noclearcookiesonquit +set nocleardownloadsoncompleted +set nocleardownloadsonquit +set clearhistoryinterval=none +set noclearlocalstorageonquit +set noclosablepinnedtabs +set commandhist=persistuseronly +set containerkeeponreopen +set containernewtab=s:usecurrent +set containershowname=automatic +set containersplitpage=s:usecurrent +set containerstartuppage=main +set countlimit=100 +" set nodarkreader +set darkreaderbg=#181a1b +set darkreaderbrightness=100 +set darkreadercontrast=100 +set darkreaderfg=#e8e6e3 +set darkreadergrayscale=0 +set darkreadermode=dark +set darkreadersepia=0 +set darkreadertextstroke=0 +set devtoolsposition=split +set dialogalert=notifyblock +set dialogconfirm=notifyallow +set dialogprompt=notifyblock +set downloadmethod=automatic +set downloadpath= +set encodeurlcopy=nospaces +set encodeurlext=nospaces +set explorehist=persist +set externalcommand= +set favicons=session +set followchars=numbers +set followfallbackaction=filter +set followlabelposition=outsiderighttop +set follownewtabswitch +set guifontsize=14 +set guifullscreennavbar=oninput +set guifullscreentabbar=onupdate +set guihidetimeout=5000 +set guinavbar=oninput +set guiscrollbar=onscroll +set guitabbar=onupdate +set historyperpage=100 +set ignorecase +set incsearch +set inputfocusalignment=rememberend +set keeprecentlyclosed +set lang=en +set loadingindicator=line +set mapsuggest=9000000000000000 +set mapsuggestposition=topright +set markposition=newtab +set markpositionshifted=default +set maxmapdepth=10 +set menupage=elementasneeded +set menusuggest=both +set menuvieb=both +set mintabwidth=28 +set mouse=all +set mousedisabledbehavior=nothing +set nomousefocus +set mousenewtabswitch +set mousevisualmode=onswitch +set nativenotification=never +set nativetheme=dark +set newtaburl= +set notificationduration=6000 +set notificationforpermissions=silent +set notificationforsystemcommands=errors +set notificationlimitsmall=3 +set notificationposition=bottomright +set pdfbehavior=download +set permissioncamera=ask +set permissioncertificateerror=allow +set permissionclipboardread=allow +set permissionclipboardwrite=allow +set permissionclosepage=allow +set permissiondisplaycapture=ask +set permissionfullscreen=allow +set permissiongeolocation=block +set permissionhid=block +set permissionidledetection=block +set permissionmediadevices=allowfull +set permissionmicrophone=ask +set permissionmidi=ask +set permissionmidisysex=ask +set permissionnotifications=ask +set permissionopenexternal=ask +set permissionpersistentstorage=ask +set permissionpointerlock=block +set permissionscreenwakelock=block +set permissionsensors=block +set permissionserial=block +set permissionunknown=ask +set permissionusb=allow +set permissionwindowmanagement=ask +set pointerposlocalid=domain +set pointerpostype=casing +set noquitonlasttabclose +set redirecttohttp +set noreloadtaboncrash +set replacespecial=special +set replacestartup=never +set requesttimeout=20000 +set restoretabs=all +set scrollposlocalid=domain +set scrollpostype=casing +set searchemptyscope=global +set searchpointeralignment=left +set searchscope=global +set shell= +set showcmd +set smartcase +set spell +set nosplitbelow +set nosplitright +set nosponsorblock +set suggestbouncedelay=100 +set suggestcommands=9000000000000000 +set suggesttopsites=10 +set suspendbackgroundtab +set suspendonrestore=regular +set suspendtimeout=0 +set tabclosefocus=left +set tabcycle +set tabnewposition=right +set tabopenmuted=never +set taboverflow=scroll +set tabreopenmuted=remember +set tabreopenposition=right +set timeout +set timeoutlen=2000 +set translateapi=auto +set translatekey= +set translatelang=en-us +set translateurl=https://api-free.deepl.com/v2/ +" set nouserscript +" set nouserstyle +set useragent=%firefox +set vimcommand=gvim +set windowfullscreen=restore +set windowmaximize=restore +set windowposition=restore +set windowsize=restore +set windowtitle="%app - %title" + +" Commands +colorscheme default + + +" Mappings +nmap o +nmap t <:tabnew> +nmap b buffer +nmap g0 <:buffer 0> +nmap g^ <:buffer 0> +nmap g$ <:buffer -1> +nmap <:buffer #> +nmap J +nmap K +nmap >> +nmap +nmap O +nmap gx0 <:lclose> +nmap gx$ <:rclose> +nmap x +nunmap [ +nunmap ] +nmap [[ +nmap ]] +nmap [c +nmap ]c +nmap zz +nmap zi +nmap zo +nmap zm 5 +nmap zr 5 +nmap zM 5 +nmap zR 5 +nmap zI 7 +nmap zO 7 + +" Search +set searchengine=https://kagi.com/search?q=%s +set searchwords+=no~https://search.nixos.org/options?query=%s +set searchwords+=np~https://search.nixos.org/packages?query=%s +set searchwords+=hm~https://home-manager-options.extranix.com/?query=%s + +" Viebrc generated by Vieb +" vim: ft=vim + +#+end_src +** swayidle +:PROPERTIES: +:CUSTOM_ID: h:69ea5818-4ebb-436a-a31a-6a2348cf215c +:END: + +#+begin_src shell :tangle files/swayidle/config +timeout 300 'swaylock -f --screenshots --clock --effect-blur 7x5 --effect-vignette 0.5:0.5 --fade-in 0.2' +timeout 600 'swaymsg "output * dpms off"' resume 'swaymsg "output * dpms on"' +before-sleep 'swaylock -f --screenshots --clock --effect-blur 7x5 --effect-vignette 0.5:0.5 --fade-in 0.2' +#+end_src +** stylix color scheme +:PROPERTIES: +:CUSTOM_ID: h:2e9b84d7-cb18-4e74-83f8-65ada11a8911 +:END: + +#+begin_src bash :tangle files/stylix/swarsel.yaml :mkdirp yes + # scheme: "better-contrast" + author: "Swarsel" + author: "Swarsel" + base00: "1d252c" #1d252c" + base01: "171d23" #171d23" + base02: "206a86" #206a86" + base03: "003a66" #003a66" + base04: "5ec4ff" #5ec4ff" + base05: "a0b3c5" #a0b3c5" + base06: "7ed4ff" #7ed4ff" + base07: "8ef4ff" #8ef4ff" + base08: "d95468" #d95468" + base09: "ffa880" #ffa880" + base0A: "6ed4ff" #6ed4ff" + base0B: "8bd49c" #8bd49c" + base0C: "008b94" #008b94" + base0D: "5ec4ff" #5ec4ff" + base0E: "c06ece" #c06ece" + base0F: "3c0044" #3c0044" + + # base00: "1D252C" # #1d252c passt + # base01: "171D23" # #171d23 + # base02: "5EC4FF" # #5EC4FF + # base03: "566C7D" # #566C7D passt + # base04: "5EC4FF" # #5EC4FF passt + # base05: "A0B3C5" # #A0B3C5 passt + # base06: "C06ECE" # #C06ECE passt + # base07: "A0B3C5" # #A0B3C5 passt + # base08: "D95468" # #D95468 passt + # base09: "FFA880" # #ffA880 passt + # base0A: "5EC4FF" # #5EC4FF + # base0B: "8BD49C" # #8BD49C + # base0C: "008B94" # #008B94 passt + # base0D: "5EC4FF" # #5EC4FF passt + # base0E: "C06ECE" # #C06ECE passt + # base0F: "5EC4FF" # #5EC4FF passt + + # base00 - Default Background + # base01 - Lighter Background (Used for status bars) + # base02 - Selection Background + # base03 - Comments, Invisibles, Line Highlighting + # base04 - Dark Foreground (Used for status bars) + # base05 - Default Foreground, Caret, Delimiters, Operators + # base06 - Light Foreground (Not often used) + # base07 - Light Background (Not often used) + # base08 - Variables, XML Tags, Markup Link Text, Markup Lists, Diff Deleted + # base09 - Integers, Boolean, Constants, XML Attributes, Markup Link Url + # base0A - Classes, Markup Bold, Search Text Background + # base0B - Strings, Inherited Class, Markup Code, Diff Inserted + # base0C - Support, Regular Expressions, Escape Characters, Markup Quotes + # base0D - Functions, Methods, Attribute IDs, Headings + # base0E - Keywords, Storage, Selector, Markup Italic, Diff Changed + # base0F - Deprecated, Opening/Closing Embedded Language Tags, e.g. +#+end_src +** .gitmessage +:PROPERTIES: +:CUSTOM_ID: h:8bfaf6d3-a0ab-4199-a07b-8bd9991bc128 +:END: + +The double source block is intended here to circumvent a org-babel convenience where the first n empty lines of each source block are not taken into the final file. For the .gitmessage I want an empty newline to type into, so this is what I use to achieve that. + +#+begin_src shell :tangle files/git/.gitmessage + +#+end_src + +#+begin_src shell :tangle files/git/.gitmessage + # max. 50 chars is here: # + # [optional scope]: + # types: feat, fix, build, chore, ci, docs, style, refactor, perf, test + # ! indicates a breaking change. + + + # Body: wrap at 72 chars is here: # + # Include at least one empty line before co-authored. Format: + # Co-authored-by: name +#+end_src +** userChrome.css +:PROPERTIES: +:CUSTOM_ID: h:a2990def-9a2a-491b-9fee-3057dc324c3c +:END: + +#+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. */ + + /* 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 */ + + --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; + } + + @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; } + + #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 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; + } + } + } + + #navigator-toolbox > *{ line-height: normal; pointer-events: auto } + + /* Don't apply transform before window has been fully created */ + :root:not([sessionrestored]) #navigator-toolbox{ transform:none !important } + + :root[customizing] #navigator-toolbox{ + position: relative !important; + transform: none !important; + opacity: 1 !important; + } + + #navigator-toolbox[inFullscreen] > #PersonalToolbar, + #PersonalToolbar:is([collapsed=""],[collapsed="true"]){ display: none } + + /* 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 +:PROPERTIES: +:CUSTOM_ID: h:fefc38d9-b3fb-42c5-8a73-ca363e898bb9 +:END: + +#+begin_src nix-ts :tangle files/templates/default/flake.nix +{ + description = "General purpose Flake"; + + inputs = { + nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; + systems.url = "github:nix-systems/default"; + }; + + outputs = + { nixpkgs + , systems + , ... + }: + let + forEachSystem = nixpkgs.lib.genAttrs (import systems); + pkgsFor = forEachSystem (system: import nixpkgs { inherit system; }); + in + { + formatter = forEachSystem (system: pkgsFor.${system}.nixpkgs-fmt); + + devShells = forEachSystem (system: { + default = pkgsFor.${system}.mkShell { + packages = with pkgsFor.${system}; [ + + ]; + }; + }); + + }; +} +#+end_src +** C++ Flake Template +:PROPERTIES: +:CUSTOM_ID: h:c54fc65b-91ef-4f8f-b0d5-cc0c3cb92b53 +:END: + +#+begin_src nix-ts :tangle files/templates/cpp/flake.nix + # heavily inspired by https://github.com/nulladmin1/nix-flake-templates/blob/main/cpp-cmake/flake.nix + { + description = "C++ Flake"; + + inputs = { + nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; + systems.url = "github:nix-systems/default"; + }; + + outputs = + { self + , nixpkgs + , systems + , ... + }: + let + forEachSystem = nixpkgs.lib.genAttrs (import systems); + pkgsFor = forEachSystem (system: import nixpkgs { inherit system; }); + + pname = "name"; + in + { + formatter = forEachSystem (system: pkgsFor.${system}.nixpgks-fmt); + + devShells = forEachSystem (system: { + default = pkgsFor.${system}.mkShell { + packages = with pkgsFor.${system}; [ + libllvm + cmake + gtest + cppcheck + valgrind + doxygen + clang-tools + # cudatoolkit + ]; + }; + }); + + packages = forEachSystem (system: { + default = pkgsFor.${system}.stdenv.mkDerivation { + inherit pname; + version = "0.1.0"; + src = ./.; + + nativeBuildInputs = with pkgsFor.${system}; [ + cmake + ]; + buildInputs = with pkgsFor.${system}; [ + gtest + ]; + }; + }); + + apps = forEachSystem (system: { + default = { + type = "app"; + program = "${self.packages.${system}.default}/bin/${pname}"; + }; + }); + }; + } +#+end_src +** Go Flake Template +:PROPERTIES: +:CUSTOM_ID: h:def2d654-e8da-4d8a-8958-b59a60d019f5 +:END: + +#+begin_src nix-ts :tangle files/templates/go/flake.nix + # heavily inspired by https://github.com/nulladmin1/nix-flake-templates/blob/main/go-nix/flake.nix + { + description = "Go Flake"; + + inputs = { + nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; + systems.url = "github:nix-systems/default"; + }; + + outputs = + { self + , nixpkgs + , systems + , ... + }: + let + forEachSystem = nixpkgs.lib.genAttrs (import systems); + pkgsFor = forEachSystem (system: import nixpkgs { inherit system; }); + + pname = "name"; + in + { + formatter = forEachSystem (system: pkgsFor.${system}.nixpkgs-fmt); + + devShells = forEachSystem (system: { + default = pkgsFor.${system}.mkShell { + packages = with pkgsFor.${system}; [ + go + gopls + go-tools + gotools + ]; + }; + }); + + packages = forEachSystem (system: { + default = pkgsFor.${system}.buildGoModule { + inherit pname; + version = "0.1.0"; + src = ./.; + vendorHash = null; + }; + }); + + apps = forEachSystem (system: { + default = { + type = "app"; + program = "${self.packages.${system}.default}/bin/${pname}"; + }; + }); + }; + } +#+end_src +** LaTeX Flake Template +:PROPERTIES: +:CUSTOM_ID: h:adccea10-6c72-46aa-8c67-5e06b7606c71 +:END: + +#+begin_src nix-ts :tangle files/templates/latex/flake.nix + # This template is based on https://github.com/Leixb/latex-template/tree/master + { + description = "LaTeX Flake"; + + inputs.flake-utils.url = "github:numtide/flake-utils"; + + outputs = { self, nixpkgs, flake-utils }: + { + + lib.latexmk = import ./build-document.nix; + + } // flake-utils.lib.eachDefaultSystem (system: + let + pname = "document"; + + pkgs = import nixpkgs { inherit system; }; + + latex-packages = with pkgs; [ + (texlive.combine { + inherit (texlive) + scheme-medium + framed + titlesec + cleveref + multirow + wrapfig + tabu + threeparttable + threeparttablex + makecell + environ + biblatex + biber + fvextra + upquote + catchfile + xstring + csquotes + minted + dejavu + comment + footmisc + xltabular + ltablex + ; + }) + which + python39Packages.pygments + ]; + + dev-packages = with pkgs; [ + texlab + zathura + wmctrl + ]; + in + rec { + devShell = pkgs.mkShell { + buildInputs = [ latex-packages dev-packages ]; + }; + + formatter = pkgs.nixpkgs-fmt; + + packages = flake-utils.lib.flattenTree { + default = import ./build-document.nix { + inherit pkgs; + name = pname; + texlive = latex-packages; + shellEscape = true; + minted = true; + SOURCE_DATE_EPOCH = toString self.lastModified; + }; + }; + + apps.default = flake-utils.lib.mkApp { drv = "${pkgs.texlivePackages.latexmk}"; exePath = "/bin/latexmk"; }; + } + ); + } +#+end_src +** Python Flake Template +:PROPERTIES: +:CUSTOM_ID: h:1a918c8d-08b4-4474-8d34-3da502081a16 +:END: + +#+begin_src nix-ts :tangle files/templates/python/flake.nix + # based on https://github.com/pyproject-nix/uv2nix/tree/master/templates/hello-world + { + description = "Python flake using uv2nix"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + + pyproject-nix = { + url = "github:pyproject-nix/pyproject.nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + uv2nix = { + url = "github:pyproject-nix/uv2nix"; + inputs = { + pyproject-nix.follows = "pyproject-nix"; + nixpkgs.follows = "nixpkgs"; + }; + }; + + pyproject-build-systems = { + url = "github:pyproject-nix/build-system-pkgs"; + inputs = { + pyproject-nix.follows = "pyproject-nix"; + uv2nix.follows = "uv2nix"; + nixpkgs.follows = "nixpkgs"; + }; + }; + }; + + outputs = + { nixpkgs + , uv2nix + , pyproject-nix + , pyproject-build-systems + , ... + }: + let + inherit (nixpkgs) lib; + pname = "name"; + forAllSystems = lib.genAttrs lib.systems.flakeExposed; + + # Load a uv workspace from a workspace root. + # Uv2nix treats all uv projects as workspace projects. + workspace = uv2nix.lib.workspace.loadWorkspace { workspaceRoot = ./.; }; + + overlay = workspace.mkPyprojectOverlay { + # Prefer prebuilt binary wheels as a package source. + # Sdists are less likely to "just work" because of the metadata missing from uv.lock. + # Binary wheels are more likely to, but may still require overrides for library dependencies. + sourcePreference = "wheel"; # or sourcePreference = "sdist"; + # Optionally customise PEP 508 environment + # environ = { + # platform_release = "5.10.65"; + # }; + }; + + + pythonSets = forAllSystems + (system: + let + inherit (pkgs) stdenv; + pkgs = nixpkgs.legacyPackages.${system}; + pyprojectOverrides = final: prev: { + # Implement build fixups here. + ${pname} = prev.${pname}.overrideAttrs (old: { + + passthru = old.passthru // { + # Put all tests in the passthru.tests attribute set. + # Nixpkgs also uses the passthru.tests mechanism for ofborg test discovery. + # + # For usage with Flakes we will refer to the passthru.tests attributes to construct the flake checks attribute set. + tests = + let + + virtualenv = final.mkVirtualEnv "${pname}-pytest-env" { + ${pname} = [ "test" ]; + }; + + in + (old.tests or { }) + // { + pytest = stdenv.mkDerivation { + name = "${final.${pname}.name}-pytest"; + inherit (final.${pname}) src; + nativeBuildInputs = [ + virtualenv + ]; + dontConfigure = true; + + # Because this package is running tests, and not actually building the main package + # the build phase is running the tests. + # + # We also output a HTML coverage report, which is used as the build output. + buildPhase = '' + runHook preBuild + pytest --cov tests --cov-report html + runHook postBuild + ''; + + # Install the HTML coverage report into the build output. + # + # If you wanted to install multiple test output formats such as TAP outputs + # you could make this derivation a multiple-output derivation. + # + # See https://nixos.org/manual/nixpkgs/stable/#chap-multiple-output for more information on multiple outputs. + installPhase = '' + runHook preInstall + mv htmlcov $out + runHook postInstall + ''; + }; + + }; + }; + }); + }; + + baseSet = pkgs.callPackage pyproject-nix.build.packages { + python = pkgs.python312; + }; + in + baseSet.overrideScope + ( + lib.composeManyExtensions [ + pyproject-build-systems.overlays.default + overlay + pyprojectOverrides + ] + )); + + in + { + packages = forAllSystems (system: + let + pythonSet = pythonSets.${system}; + in + { default = pythonSet.mkVirtualEnv "${pname}-env" workspace.deps.default; }); + + devShells = forAllSystems + (system: + let + pythonSet = pythonSets.${system}; + pkgs = nixpkgs.legacyPackages.${system}; + in + { + default = + let + # Create an overlay enabling editable mode for all local dependencies. + editableOverlay = workspace.mkEditablePyprojectOverlay { + # Use environment variable + root = "$REPO_ROOT"; + # Optional: Only enable editable for these packages + # members = [ "hello-world" ]; + }; + + # Override previous set with our overrideable overlay. + editablePythonSet = pythonSet.overrideScope editableOverlay; + + virtualenv = editablePythonSet.mkVirtualEnv "${pname}-dev-env" { + ${pname} = [ "dev" ]; + }; + + in + pkgs.mkShell { + packages = [ + virtualenv + pkgs.uv + ]; + shellHook = '' + # Undo dependency propagation by nixpkgs. + unset PYTHONPATH + + # Don't create venv using uv + export UV_NO_SYNC=1 + + # Prevent uv from downloading managed Python's + export UV_PYTHON_DOWNLOADS=never + + # Get repository root using git. This is expanded at runtime by the editable `.pth` machinery. + export REPO_ROOT=$(git rev-parse --show-toplevel) + ''; + }; + }); + + checks = forAllSystems ( + system: + let + pythonSet = pythonSets.${system}; + in + { + inherit (pythonSet.${pname}.passthru.tests) pytest; + } + ); + + formatter = forAllSystems (system: nixpkgs.legacyPackages.${system}.nixpkgs-fmt); + + }; + } +#+end_src +** Rust Flake Template +:PROPERTIES: +:CUSTOM_ID: h:c03663fd-f7bd-4054-9075-5dacaf2abf76 +:END: + +#+begin_src nix-ts :tangle files/templates/rust/flake.nix + # heavily inspired by https://github.com/nulladmin1/nix-flake-templates/blob/main/rust-fenix-naersk/flake.nix + { + description = "Rust Flake using Fenix and Naersk"; + + inputs = { + nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; + systems.url = "github:nix-systems/default"; + naersk.url = "github:nix-community/naersk"; + fenix = { + url = "github:nix-community/fenix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + + outputs = + { self + , nixpkgs + , naersk + , fenix + , systems + , ... + }: + let + forEachSystem = nixpkgs.lib.genAttrs (import systems); + pkgsFor = forEachSystem (system: + + import nixpkgs { + inherit system; + overlays = [ + fenix.overlays.default + ]; + }); + rust-toolchain = forEachSystem (system: pkgsFor.${system}.fenix.stable); + in + { + formatter = forEachSystem (system: pkgsFor.${system}.nixpkgs-fmt); + + devShells = forEachSystem (system: { + default = pkgsFor.${system}.mkShell { + packages = with rust-toolchain.${system}; [ + cargo + rustc + clippy + rustfmt + rust-analyzer + ]; + env = { + RUST_BACKTRACE = "full"; + }; + RUST_SRC_PATH = "${rust-toolchain.${system}.rust-src}/lib/rustlib/src/rust/library"; + }; + }); + + packages = forEachSystem (system: { + default = + (pkgsFor.${system}.callPackage naersk { + inherit (rust-toolchain.${system}) cargo rustc; + }).buildPackage { + src = ./.; + }; + }); + + apps = forEachSystem (system: { + default = { + type = "app"; + program = "${self.packages.${system}.default}/bin/rust"; + }; + }); + }; + } +#+end_src +** GitHub Readme +:PROPERTIES: +:CUSTOM_ID: h:bf3e6fc0-a95a-46d0-9305-0d1068b2f1ec +:END: + +Here lies defined the readme for GitHub and Forgejo: + +#+begin_src markdown :tangle .github/README.md :noweb yes :mkdirp yes + [![Build Status](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Factions-badge.atrox.dev%2FSwarsel%2F.dotfiles%2Fbadge%3Fref%3Dmain&style=flat&labelColor=11111b)](https://actions-badge.atrox.dev/Swarsel/.dotfiles/goto?ref=main) + + ###### Disclaimer + + You probably do not want to use this setup verbatim. This is made to fit my specific use cases, and I do not guarantee best practises everywhere. Changes are made on a daily basis. + + That being said, there is a lot of general configuration that you *probably* can use without changes; if you only want to use this repository as a starting point for your own configuration, you should be fine. See below for more information. Also, if you see something that can be done more efficiently or better in general, please let me know! :) + + # \~SwarselSystems\~ + +

+ swarselsystems_preview1 + swarselsystems_preview2 +

+ + ## Overview + + - [Literate configuration](https://swarsel.github.io/.dotfiles/) defining my entire infrastructure, including Emacs + - Configuration based on flakes for personal hosts as well as servers on: + - [NixOS](https://github.com/NixOS/nixpkgs) + - [home-manager](https://github.com/nix-community/home-manager) only (no full NixOS) with support from [nixGL](https://github.com/nix-community/nixGL) + - [nix-darwin](https://github.com/LnL7/nix-darwin) + - [nix-on-droid](https://github.com/nix-community/nix-on-droid) + - Streamlined configuration and deployment pipeline: + - Framework for [packages](https://github.com/Swarsel/.dotfiles/blob/main/pkgs/default.nix), [overlays](https://github.com/Swarsel/.dotfiles/blob/main/overlays/default.nix), [modules](https://github.com/Swarsel/.dotfiles/tree/main/modules), and [library functions](https://github.com/Swarsel/.dotfiles/tree/main/lib/default.nix) + - Dynamically generated host configurations + - Limited local installer (no secrets handling) with a supported demo build + - Fully autonomous remote deployment using [nixos-anywhere](https://github.com/nix-community/nixos-anywhere) and [disko](https://github.com/nix-community/disko) (with secrets handling) + - Improved nix tooling + - Support for advanced features: + - Secrets handling using [sops-nix](https://github.com/Mic92/sops-nix) (pls no pwn ❤️) + - Management of personally identifiable information using [nix-plugins](https://github.com/shlevy/nix-plugins) + - Full Yubikey support + - LUKS-encryption + - Secure boot using [Lanzaboote](https://github.com/nix-community/lanzaboote) + - BTRFS-based [Impermanence](https://github.com/nix-community/impermanence) + - Configuration shared between configurations (configuration for one nixosConfiguration can be defined in another nixosConfiguration) + - Global attributes shared between all configurations to reduce attribute redeclaration + + ## Documentation + + If you are mainly interested in how I configured this system, check out this page: + + [SwarselSystems literate configuration](https://swarsel.github.io/.dotfiles/) + + This file will take you through my design process, in varying amounts of detail. + + Otherwise, the files that are possibly of biggest interest are found here: + + - [SwarselSystems.org](../SwarselSystems.org) + - [flake.nix](../flake.nix) + - [early-init.el](../files/emacs/early-init.el) + - [init.el](../files/emacs/init.el) + + + ### Getting started + + #### Demo configuration + +
+ Click here for instructions on how to install the demo system + + If you just want to see if this configuration is for you, run this command on any system that has `nix` installed: + + ``` shell + nix run --experimental-features 'nix-command flakes' github:Swarsel/.dotfiles#swarsel-rebuild -- -u + ``` + + This will activate the `hotel` configuration on your system, which is a de-facto mirror of my main configuration with secret-based settings removed. + Please keep in mind that this limited installer will make local changes to the cloned repository in order to be able to install it (otherwise the builder would fail at fetching my private secrets repository). As such, this should only be used to evaluate the system - if you want to use it longterm, you will need to create a fork and make some changes. +
+ + ### Deployment + +
+ Click here for deployment instructions + + The deployment process for this configuration is mostly automated, there are only a few steps that are needed to be done manually. You can choose between a remote deployment strategy that is also able to deploy new age keys for sops for you and a local installer that will only install the system without any secret handling. + + #### Remote deployment (recommended if you have at least one running system) + + 0) Fork this repo, and write your own host config at `hosts/nixos///default.nix` (you can use one of the other configurations as a template. Also see https://github.com/Swarsel/.dotfiles/tree/main/modules for a list of all additional options). At the very least, you should replace the `secrets/` directory with your own secrets and replace the SSH public keys with your own ones (otherwise I will come visit you!🔓❤️). I personally recommend to use the literate configuration and `org-babel-tangle-file` in Emacs, but you can also simply edit the separate `.nix` files. + 1) Have a system with `nix` available booted (this does not need to be installed, i.e. you can use a NixOS installer image; a custom minimal installer ISO can be built by running `just iso` in the root of this repo) + 2) Make sure that your Yubikey is plugged in or that you have your SSH key available (and configured) + 3) Run `swarsel-bootstrap -n -d ` on your existing system. + - Alternatively (if you run this on a system that is not yet running this configuration), you can also run `nix run --experimental-features 'nix-command flakes' github:Swarsel/.dotfiles -- -n -d ` (this runs the same program as the command above). + 4) Follow the installers instructions: + - you will have to choose a disk encryption password (if you want that feature) + - you will have to confirm once that the target system has rebooted + - you will have to enter the root password once during the final system install + 5) That should be it! The installer will take care of setting up disks, secrets, and the rest of the hardware configuration! You will still have to sign in manually to some webservices etc. + + #### Local deployment (recommended for setting up the first system) + + 1) Boot the latest install ISO from this repository on an UEFI system. + 2) Run `swarsel-install -n ` + 3) Reboot + + Alternatively, to install this from any NixOS live ISO, run `nix run --experimental-features 'nix-command flakes' github:Swarsel/.dotfiles#install -- -n ` at step 2. +
+ + ## Infrastructure + +
+ Click here for a summary of my infrastructure + + topology + + ### Programs + + <> + + ### Services + + <> + + ### Hosts + + <> +
+ + ## General Nix tips & useful links + +
+ Click here for a summary of nix tips & links + + - Below is a small list of tips that should be helpful if you are new to the nix ecosystem: + + - Temporarily install any package using `nix shell nixpkgs#` - this can be e.g. useful if you accidentally removed home-manager from your packages on a non-NixOS machine. + - if you need multiple packages, you can do `nix shell nixpkgs#{,,}`. + - you can set `nix.registry` to add more flakes to your registry. I use this to add a `n` shorthand to `nixpkgs`, which allows me to do `nix shell n#{,,}`. + - Alternatively, use [comma](https://github.com/nix-community/comma) + - More info on `nix [...]` commands: https://nixos.org/manual/nix/stable/command-ref/new-cli/nix + - some examples: + - `nix flake update ` lets you update a specific input only. + - `nix repl ` gives quick insight into your written configuration. + - `nix eval #` quickly returns an attribute in your written configuration + - `nix fmt` formats your flake using the formatter specified under `formatter` in your `flake.nix` + - When you are trying to setup a new configuration part, [GitHub code search](https://github.com/search?q=language%3ANix&type=code) can really help you to find a working configuration. Just filter for `.nix` files and the options you are trying to set up. + - getting packages at a different version than your target (or not packaged at all) can be done in most cases easily with fetchFromGithub (https://ryantm.github.io/nixpkgs/builders/fetchers/) + - you can easily install old revisions of packages using https://lazamar.co.uk/nix-versions/. You can conveniently spawn a shell with a chosen package available using `vershell `. Just make sure to pick a revision that has flakes enabled, otherwise you will need the legacy way of spawning the shell (see the link for more info) + - when developing modules in a dev branch of another flake, you can use `--override-input` to temporarily use the local directory as the flake source. + - including `nixosConfig ? config` in your module arguments is a smart way of enabling a module to pull in config from NixOS or home-manager config, no matter if it is a NixOS system or not. + - you can have a quick cli evaluation for nix commands with e.g. `nixpgks.lib` available using `nix-instantiate --strict --eval --expr "let lib = import ; in "`. + - if you are looking for a specific library, `nix-locate` makes it easy to look for them. + - to look at the dependencies pulled in by a tool, use `nix-tree` + - to find out which derivation uses another derivation, use `nix store --query --referrers ` + - to get a neat overview of your config changes in recent generations, use `nix profile diff-closures --profile /nix/var/nix/profiles/system` + - to get instead the changes since the last boot, use `nix profile diff-closures /run/*-system` + - if you just need the generation numbers, use `sudo nix-env --list-generations --profile /nix/var/nix/profiles/system` + - to then switch to another generation, you can use `sudo nix-env --switch-generation -p /nix/var/nix/profiles/system` followed by `sudo /nix/var/nix/profiles/system/bin/switch-to-configuration switch` + + - These links are your best friends: + - The nix documentation: https://nix.dev/ + - The nixpkgs reference manual: https://nixos.org/manual/nixpkgs/unstable/#buildpythonapplication-function + - the [nixpkgs repository](https://github.com/NixOS/nixpkgs) - especially useful to look at the various READMEs that are in various places in the repository (find using GitHub code search) as well as the [issues](https://github.com/Swarsel/.dotfiles/issues) and [PRs](https://github.com/Swarsel/.dotfiles/pulls) pages + - and the [nixpkgs Pull Request Tracker](https://nixpk.gs/pr-tracker.html) + - The NixOS manual: https://nixos.org/manual/nixos/stable/ + - The NixOS package search: https://search.nixos.org/packages + - and the nix package version search: https://lazamar.co.uk/nix-versions/ + - The NixOS option search https://search.nixos.org/options + - [mipmip](https://github.com/mipmip)'s home-manager option search: https://mipmip.github.io/home-manager-option-search/ + - [Alan Pearce](https://alanpearce.eu/)'s nix-darwin search: https://searchix.alanpearce.eu/options/darwin/search (which supports all of the other versions as well :o) + - For the above, you can use the CLI tool [manix](https://github.com/mlvzk/manix) + - Nix function search: https://noogle.dev/ + - Search for nix-community options: https://search.nüschtos.de/ + - But that is not all: + - Some nix resources + - A tour of Nix: https://nixcloud.io/tour/ + - The Nix One Pager: https://github.com/tazjin/nix-1p + - another one page introduction: https://learnxinyminutes.com/nix/ + - a very short introduction to Nix features: https://zaynetro.com/explainix + - introductory nix article: https://medium.com/@MrJamesFisher/nix-by-example-a0063a1a4c55 + - and another one: https://web.archive.org/web/20210121042658/https://ebzzry.io/en/nix/#nix + - How to learn nix: https://ianthehenry.com/posts/how-to-learn-nix/ + - the Nix Cookbook: https://github.com/functionalops/nix-cookbook?tab=readme-ov-file + - and the Nix Pills: https://nixos.org/guides/nix-pills/ + - Some resources on flakes + - Why to use flakes and introduction to flakes: https://www.tweag.io/blog/2020-05-25-flakes/ + - The [NixOS & Flakes Book](https://nixos-and-flakes.thiscute.world/) + - and [Wombat's book](https://mhwombat.codeberg.page/nix-book/) + - or the [Zero to Nix series](https://zero-to-nix.com/) + - Practical nix flakes article: https://serokell.io/blog/practical-nix-flakes + - A bit on Overlays: + - Overview on overlays: [Mastering Nixpkgs overlays article](https://nixcademy.com/posts/mastering-nixpkgs-overlays-techniques-and-best-practice/) + - Some examples on best practises: [Do's and Don'ts of overlays](https://flyingcircus.io/news/detailsansicht/nixos-the-dos-and-donts-of-nixpkgs-overlays) + - Blog article about overrides: https://bobvanderlinden.me/customizing-packages-in-nix/#using-modified-packages + - Also useful is the [official NixOS Wiki](https://wiki.nixos.org/wiki/NixOS_Wiki) + - there is also the [unofficial NixOS Wiki](https://nixos.wiki/) that tends to be a bit outdated, use with care + - Some resources for specific nix tools: + - Flake output reference: https://nixos-and-flakes.thiscute.world/other-usage-of-flakes/outputs + - You can find public repositories with modules at https://nur.nix-community.org/ (you should check what you are installing however): + - I like to use this for rycee's firefox extensions: https://nur.nix-community.org/repos/rycee/ + - List of nerdfonts: https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/data/fonts/nerd-fonts/manifests/fonts.json + - Stylix configuration options: https://danth.github.io/stylix/ + - nix-on-droid options: https://nix-community.github.io/nix-on-droid/nix-on-droid-options.html#sec-options + - Very useful tools that are mostly not directly used in configuration but instead called on need: + - Convert non-NixOS machines to NixOS using [nixos-infect](https://github.com/elitak/nixos-infect) + - Create various installation media with [nixos-generators](https://github.com/nix-community/nixos-generators) + - Remotely deploy NixOS using [nixos-anywhere](https://github.com/nix-community/nixos-anywhere) + - And a few links that are not directly nix-related, but may still serve you well: + - List of pre-commit-hooks: https://devenv.sh/reference/options/#pre-commithooks + - Waybar configuration: https://github.com/Alexays/Waybar/wiki +
+ + ## Attributions, Acknowledgements, Inspirations, etc. + + These are in random order (also known as 'the order in which I discovered them'). I would like to express my gratitude to: + + - All the great people who have contributed code for the nix-community, with special mentions for (this list is unfairly incomplete): +
+ Click here to expand... + + - [guibou](https://github.com/guibou/) + - [rycee](https://github.com/rycee) + - [adisbladis](https://github.com/adisbladis) + - [Mic92](https://github.com/Mic92/sops-nix) + - [lassulus](https://github.com/lassulus) + - [danth](https://github.com/danth/) + - [LnL7](https://github.com/LnL7) + - [t184256](https://github.com/t184256) + - [bennofs](https://github.com/bennofs) + - [Pandapip1](https://github.com/Pandapip1) + - [zowoq](https://github.com/zowoq) + - [numtide](https://github.com/numtide) + - [hsjobeki](https://github.com/hsjobeki) + - [blitz](https://github.com/blitz) + - [RaitoBezarius](https://github.com/RaitoBezarius) + - [nikstur](https://github.com/nikstur) + - [talyz](https://github.com/talyz) + - [infinisil](https://github.com/infinisil) + - [zhaofengli](https://github.com/zhaofengli) + - [Artturin](https://github.com/Artturin) + - [oddlama](https://github.com/oddlama) +
+ + - All the people who have inspired me with their configurations (sadly also highly incomplete): +
+ Click here to expand... + + - [theSuess](https://github.com/theSuess) with their [home-manager](https://code.kulupu.party/thesuess/home-manager) + - [hlissner](https://github.com/hlissner) with their [dotfiles](https://github.com/hlissner/dotfiles) + - [drduh](https://github.com/drduh/YubiKey-Guide) with their [YubiKey-Guide](https://github.com/drduh/YubiKey-Guide) + - [AntonHakansson](https://github.com/AntonHakansson) with their [nixos-config](https://github.com/AntonHakansson/nixos-config?tab=readme-ov-file) + - [Guekka](https://github.com/Guekka/) with their [blog](https://guekka.github.io/) + - [NotAShelf](https://github.com/NotAShelf) with their [nyx](https://github.com/NotAShelf/nyx) + - [Misterio77](https://github.com/Misterio77) with their [nix-config](https://github.com/Misterio77/nix-config) + - [0xdade](https://github.com/0xdade) with their [blog](https://0xda.de/blog/) + - [EmergentMind](https://github.com/EmergentMind) with their [nix-config](https://github.com/EmergentMind/nix-config) + - [librephoenix](https://github.com/librephoenix) with their [nixos-config](https://github.com/librephoenix/nixos-config) + - [Xe](https://github.com/Xe) with their [blog](https://xeiaso.net/blog/) + - [oddlama](https://github.com/oddlama) with their absolutely incredible [nix-config](https:/github.com/oddlama/nix-config) +
+ + If you feel that I forgot to pay you tribute for code that I used in this repository, please shoot me a message and I will fix it :) + + +#+end_src + +* Appendix C: Explanations to nix functions and operators +:PROPERTIES: +:CUSTOM_ID: h:8ea35dcc-ef94-4c10-9112-8be8efd6f424 +:END: + +This sections explains commonly used functions in nix (both builtins as well as in the nixpkgs library). +** The '//' operator +:PROPERTIES: +:CUSTOM_ID: h:b1fe7a9a-661b-4446-aefa-98373108f8fd +:END: + +The =//= operator in nix is used to merge attribute sets; if an attribute exists in both sets, then the latter set takes precedence: + +#+begin_src bash :exports both + swarsel-instantiate '{ a = 1; b = 2; } // { b = 3; c = 4; }' +#+end_src + +#+RESULTS: +: { a = 1; b = 3; c = 4; } + +Also, this will not merge nested sets: + +#+begin_src bash :exports both + swarsel-instantiate '{ a = { a1 = 1; a2 = 2; }; b = { b1 = 1; b2 = 2; }; } // { b = { b1 = 3; b3 = 4;}; c = 4; }' +#+end_src + +#+RESULTS: +: { a = { a1 = 1; a2 = 2; }; b = { b1 = 3; b3 = 4; }; c = 4; } + + It only took the latter =b= set, even though the =b2= value was not contested. This functionality is provided by [[#h:2227ba24-e3a1-40ba-8fb8-4cab5210692a][nixpkgs.lib.recursiveUpdate]]. + +** builtins.listToAttrs +:PROPERTIES: +:CUSTOM_ID: h:c63cd469-7724-4a05-b932-8843722a00f0 +:END: + +builtins.listToAttrs converts a list of name-value pairs into an attribute set. + +#+begin_src bash :exports both + swarsel-instantiate 'builtins.listToAttrs [{ name = "foo"; value = 1; } { name = "bar"; value = 2; }]' +#+end_src + +#+RESULTS: +: { bar = 2; foo = 1; } + +** builtins.readDir +:PROPERTIES: +:CUSTOM_ID: h:1fb6ff92-7cc1-4447-8a63-460f24633053 +:END: + +=builtins.readDir= reads the name of items of a directory as attributes and their type as values. + +#+begin_src bash :exports both + swarsel-instantiate 'builtins.readDir ./hosts/nixos' +#+end_src + +#+RESULTS: +: { bakery = "directory"; hotel= "directory"; milkywell = "directory"; moonside = "directory"; pyramid = "directory"; toto = "directory"; winters = "directory"; } +** nixpkgs.lib.recursiveUpdate +:PROPERTIES: +:CUSTOM_ID: h:2227ba24-e3a1-40ba-8fb8-4cab5210692a +:END: + +If you want to merge nested attribute sets, use =nixpkgs.lib.recursiveUpdate= instead of [[#h:b1fe7a9a-661b-4446-aefa-98373108f8fd][The '//' operator]]: + +#+begin_src bash :exports both + swarsel-instantiate 'lib.recursiveUpdate { a = { a1 = 1; a2 = 2; }; b = { b1 = 1; b2 = 2; }; } { b = { b1 = 3; b3 = 4;}; c = 4; }' +#+end_src + +#+RESULTS: +: { a = { a1 = 1; a2 = 2; }; b = { b1 = 3; b2 = 2; b3 = 4; }; c = 4; } + +** nixpkgs.lib.genAttrs +:PROPERTIES: +:CUSTOM_ID: h:94690fcb-e039-49da-9bd3-610fa80fa08b +:END: + +=nixpkgs.lib.genAttrs= is used to generate an attribute set (a dictionary-like structure) from a list of keys and a function that computes the values for those keys. + +#+begin_src bash :exports both + swarsel-instantiate 'lib.genAttrs ["a" "b" "c"] (x: "${x}-value")' +#+end_src + +#+RESULTS: +: { a = "a-value"; b = "b-value"; c = "c-value"; } + +** nixpkgs.lib.attrNames +:PROPERTIES: +:CUSTOM_ID: h:0fded8e7-6160-4fcd-a491-42f0debfec52 +:END: + +=nixpkgs.lib.attrNames= returns the list of attribute names from an attribute set. + +#+begin_src bash :exports both + swarsel-instantiate 'lib.attrNames { a = 1; b = 2; c = 3; }' +#+end_src + +#+RESULTS: +: [ "a" "b" "c" ] + +** nixpkgs.lib.map +:PROPERTIES: +:CUSTOM_ID: h:a4f9752a-33a6-4dd4-97ea-ef6bf340bd8e +:END: + +=nixpkgs.lib.map= takes a function and applies the elements of a list upon them. + +#+begin_src bash :exports both + swarsel-instantiate 'lib.map (x: x + 1) [1 2 3]' +#+end_src + +#+RESULTS: +: [ 2 3 4 ] + +** nixpkgs.lib.mkOverride +:PROPERTIES: +:CUSTOM_ID: h:9e81b727-1436-4228-82b1-1edec5c50e06 +:END: +=nixpkgs.lib.mkOverride= sets the priority of an expression. + +If two expression are defined twice accross the configuration, the evaluator does not know which one should take precedence; this will lead to an error. By default, all option definitions are given priority 100. Lower values take precedence over lower values. For reference, here are some commonly used values: + +- [[#h:16599d68-0ca5-40fa-810e-76b5c739b2b1][nixpkgs.lib.mkForce]] sets the priority to 50, which is a very low value, meaning it will be prioritised in nearly all cases +- [[#h:41180e6c-2a13-4b46-89b2-791562b4b816][nixpkgs.lib.mkDefault]] sets the priority to 1000, which is a quite high value that will almost never be used if the same attribute is defined elswheer. +** nixpkgs.lib.mkForce +:PROPERTIES: +:CUSTOM_ID: h:16599d68-0ca5-40fa-810e-76b5c739b2b1 +:END: + +An alias for ([[#h:9e81b727-1436-4228-82b1-1edec5c50e06][nixpkgs.lib.mkOverride]] 50). +** nixpkgs.lib.mkDefault +:PROPERTIES: +:CUSTOM_ID: h:41180e6c-2a13-4b46-89b2-791562b4b816 +:END: + +An alias for ([[#h:9e81b727-1436-4228-82b1-1edec5c50e06][nixpkgs.lib.mkOverride]] 1000). +** nixpkgs.lib.filter +:PROPERTIES: +:CUSTOM_ID: h:38d8aecf-d997-4b50-80a2-c86314b5e67e +:END: + +=nixpkgs.lib.filter= takes a list as input and only keeps elements that fulfill a given function: + +#+begin_src bash :exports both + swarsel-instantiate 'lib.filter (x: x != "a") (lib.attrNames { a = 1; b = 2; c = 3; })' +#+end_src + +#+RESULTS: +: [ "b" "c" ] + +** nixpkgs.lib.mapAttrsToList +:PROPERTIES: +:CUSTOM_ID: h:b9663237-2232-4554-bc81-843be28a707c +:END: + +=nixpkgs.lib.mapAttrsToList= converts an attribute set into a list by applying a given function to each name-value pair: + +#+begin_src bash :exports both + swarsel-instantiate 'lib.mapAttrsToList (name: value: "${name} = ${value}") { a = "1"; b = "2"; }' +#+end_src + +#+RESULTS: +: [ "a = 1" "b = 2" ] + +** nixpkgs.lib.flip +:PROPERTIES: +:CUSTOM_ID: h:21389cc9-fd89-45ca-9836-592f84a45bb4 +:END: + + + - =nixpkgs.lib.flip= reverses the argument order passed to an expression (in semantics, that is lib.flip f a b == f b a). This is useful when an expression has one big argument and one small one; in that case it is convenient to have the shorter expression at the start of the function. Take this example of a function that simply prints its attributes as a list: + + #+begin_src bash :exports both + swarsel-instantiate 'lib.mapAttrsToList (name: value: "${name} = ${value}") {a = "1"; b = "2";}' +#+end_src + +#+RESULTS: +: [ "a = 1" "b = 2" ] + +It prints the attributs unchanged, as is to be expected. If, however, we call the function using =nixpkgs.lib.flip=: + + #+begin_src bash :exports both + swarsel-instantiate 'lib.mapAttrsToList (lib.flip (name: value: "${name} = ${value}")) {a = "1"; b = "2";}' +#+end_src + +#+RESULTS: +: [ "1 = a" "2 = b" ] + +** nixpkgs.lib.concatLists +:PROPERTIES: +:CUSTOM_ID: h:22264e49-b6d0-4c1f-8d05-2ef1f3da3d54 +:END: + +=nixpkgs.lib.concatLists=, as the name suggests, concatenates lists, while keeping the original order of items: + +#+begin_src bash :exports both + swarsel-instantiate 'lib.concatLists [ [ 1 2 ] [ 3 4 ] [ 5 ] ]' +#+end_src + +#+RESULTS: +: [ 1 2 3 4 5 ] + +** nixpkgs.lib.mkMerge +:PROPERTIES: +:CUSTOM_ID: h:82c26445-2af4-4a6c-ae91-c804325fdf11 +:END: + + + - =nixpgks.lib.mkMerge= is used to deeply merge values. + +#+begin_src bash :exports both + swarsel-instantiate ' + lib.mkMerge [ + { + a = [ 1 ]; + } + { + a = [ 3 ]; + } + ] + ' +#+end_src + +#+RESULTS: +: { _type = "merge"; contents = [ { a = [ 1 ]; } { a = [ 3 ]; } ]; } + +** nixpkgs.lib.foldl +:PROPERTIES: +:CUSTOM_ID: h:e21d17fb-0c98-42d5-b08f-1c7584afa07f +:END: + +=nixpkgs.lib.foldl= reduces an attribute set by repeatedly calling a function on an attribute set from the left. + +#+begin_src bash :exports both + swarsel-instantiate 'lib.foldl (acc: x: "(" + acc + " + " + x + ")") "0" ["1" "2" "3"]' +#+end_src + +#+RESULTS: +: (((0 + 1) + 2) + 3) + +similarly, there exists an version that starts from the right. + +#+begin_src bash :exports both + swarsel-instantiate 'lib.foldr (acc: x: "(" + acc + " + " + x + ")") "0" ["1" "2" "3"]' +#+end_src + +#+RESULTS: +: (1 + (2 + (3 + 0))) diff --git a/checks/default.nix b/checks/default.nix deleted file mode 100644 index 4830423..0000000 --- a/checks/default.nix +++ /dev/null @@ -1,39 +0,0 @@ -{ self, inputs, pkgs, system, ... }: -{ - pre-commit-check = inputs.pre-commit-hooks.lib.${system}.run { - src = "${self}"; - hooks = { - check-added-large-files.enable = true; - check-case-conflicts.enable = true; - check-executables-have-shebangs.enable = true; - check-shebang-scripts-are-executable.enable = false; - check-merge-conflicts.enable = true; - deadnix.enable = true; - detect-private-keys.enable = true; - end-of-file-fixer.enable = true; - fix-byte-order-marker.enable = true; - flake-checker.enable = true; - forbid-new-submodules.enable = true; - mixed-line-endings.enable = true; - nixpkgs-fmt.enable = true; - statix.enable = true; - trim-trailing-whitespace.enable = true; - - destroyed-symlinks = { - enable = true; - entry = "${inputs.pre-commit-hooks.checks.${system}.pre-commit-hooks}/bin/destroyed-symlinks"; - }; - - shellcheck = { - enable = true; - entry = "${pkgs.shellcheck}/bin/shellcheck --shell=bash"; - }; - - shfmt = { - enable = true; - entry = "${pkgs.shfmt}/bin/shfmt -i 4 -sr -d -s -l"; - }; - - }; - }; -} diff --git a/programs/config/.aspell.conf b/files/config/.aspell.conf similarity index 100% rename from programs/config/.aspell.conf rename to files/config/.aspell.conf diff --git a/programs/emacs/early-init.el b/files/emacs/early-init.el similarity index 63% rename from programs/emacs/early-init.el rename to files/emacs/early-init.el index b7045d0..b86d1c1 100644 --- a/programs/emacs/early-init.el +++ b/files/emacs/early-init.el @@ -1,24 +1,23 @@ -(defvar swarsel-file-name-handler-alist file-name-handler-alist) -(defvar swarsel-vc-handled-backends vc-handled-backends) +;; -*- lexical-binding: t; -*- + (defvar swarsel-file-name-handler-alist file-name-handler-alist) + (defvar swarsel-vc-handled-backends vc-handled-backends) -(setq gc-cons-threshold most-positive-fixnum - gc-cons-percentage 0.6 - file-name-handler-alist nil - vc-handled-backends nil) + (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 (* 1000 1000 8) - ;; (setq gc-cons-threshold #x40000000 - (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 + (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) + ))) (tool-bar-mode 0) (menu-bar-mode 0) diff --git a/programs/emacs/init.el b/files/emacs/init.el similarity index 53% rename from programs/emacs/init.el rename to files/emacs/init.el index de87fe2..26d3439 100644 --- a/programs/emacs/init.el +++ b/files/emacs/init.el @@ -1,8 +1,10 @@ -(defun swarsel/toggle-evil-state () - (interactive) - (if (or (evil-emacs-state-p) (evil-insert-state-p)) - (evil-normal-state) - (evil-emacs-state))) +;; -*- lexical-binding: t; -*- + + (defun swarsel/toggle-evil-state () + (interactive) + (if (or (evil-emacs-state-p) (evil-insert-state-p)) + (evil-normal-state) + (evil-emacs-state))) (defun swarsel/last-buffer () (interactive) (switch-to-buffer nil)) @@ -28,14 +30,18 @@ (when-let ((dest (swarsel/mu4e-rfs--matching-address))) (cl-destructuring-bind (from-user from-addr) dest (setq user-mail-address from-addr) + (when (and (boundp 'user-mail-address) + (stringp user-mail-address) + (string-equal user-mail-address (getenv "SWARSEL_MAIL_WORK"))) + (mml-secure-message-sign-smime)) (message-position-on-field "From") (message-beginning-of-line) (delete-region (point) (line-end-position)) (insert (format "%s <%s>" (or from-user user-full-name) from-addr))))))) (defun swarsel/mu4e-restore-default () - (setq user-mail-address "leon@swarsel.win" - user-full-name "Leon Schwarzäugl")) + (setq user-mail-address (getenv "SWARSEL_MAIL4") + user-full-name (getenv "SWARSEL_FULLNAME"))) (defun swarsel/with-buffer-name-prompt-and-make-subdirs () (let ((parent-directory (file-name-directory buffer-file-name))) @@ -156,15 +162,19 @@ create a new one." (define-key minibuffer-local-filename-completion-map [C-backspace] #'up-directory) +(defun swarsel/consult-magit-repos () + (interactive) + (require 'magit) + (let* ((repos (magit-list-repos)) + (repo (consult--read repos + :prompt "Magit repo: " + :require-match t + :history 'my/consult-magit-repos-history + :sort t))) + (magit-status repo))) + (defun swarsel/org-mode-setup () - ;; (org-indent-mode) (variable-pitch-mode 1) - ;;(auto-fill-mode 0) - ;; (setq display-line-numbers-type 'relative - ;; display-line-numbers-current-absolute 1 - ;; display-line-numbers-width-start nil - ;; display-line-numbers-width 6 - ;; display-line-numbers-grow-only 1) (add-hook 'org-tab-first-hook 'org-end-of-line) (visual-line-mode 1)) @@ -178,20 +188,20 @@ create a new one." (let ((default-directory (expand-file-name "~/.dotfiles"))) (shell-command "nixpkgs-fmt . > /dev/null"))) - (defun swarsel/org-babel-tangle-config () +(defun swarsel/org-babel-tangle-config () (interactive) - (when (string-equal (buffer-file-name) - swarsel-swarsel-org-filepath) - ;; Dynamic scoping to the rescue - (let ((org-confirm-babel-evaluate nil)) - ;; (org-html-export-to-html) - (org-babel-tangle) - (swarsel/run-formatting) - ))) + (when (string-equal (buffer-file-name) + swarsel-swarsel-org-filepath) + ;; Dynamic scoping to the rescue + (let ((org-confirm-babel-evaluate nil)) + ;; (org-html-export-to-html) + (org-babel-tangle) + (swarsel/run-formatting) + ))) - (setq org-html-htmlize-output-type nil) +(setq org-html-htmlize-output-type nil) - ;; (add-hook 'org-mode-hook (lambda () (add-hook 'after-save-hook #'swarsel/org-babel-tangle-config))) +;; (add-hook 'org-mode-hook (lambda () (add-hook 'after-save-hook #'swarsel/org-babel-tangle-config))) (defun org-fold-outer () (interactive) @@ -217,81 +227,6 @@ create a new one." (corfu-quit) (evil-next-visual-line)) -;; run the python inferior shell immediately upon entering a python buffer -;; (add-hook 'python-mode-hook 'swarsel/run-python) - -;; (defun swarsel/run-python () -;; (save-selected-window -;; (switch-to-buffer-other-window (process-buffer (python-shell-get-or-create-process (python-shell-parse-command)))))) - -;; reload python shell automatically -(defun my-python-shell-run () - (interactive) - (when (get-buffer-process "*Python*") - (set-process-query-on-exit-flag (get-buffer-process "*Python*") nil) - (kill-process (get-buffer-process "*Python*")) - ;; Uncomment If you want to clean the buffer too. - ;;(kill-buffer "*Python*") - ;; Not so fast! - (sleep-for 0.5)) - (run-python (python-shell-parse-command) nil nil) - (python-shell-send-buffer) - ;; Pop new window only if shell isnt visible - ;; in any frame. - (unless (get-buffer-window "*Python*" t) - (python-shell-switch-to-shell))) - -(defun my-python-shell-run-region () - (interactive) - (python-shell-send-region (region-beginning) (region-end)) - (python-shell-switch-to-shell)) - -(defun swarsel/prefix-block (start end) - (interactive "r") - (save-excursion - (goto-char start) - (setq start (line-beginning-position)) - (goto-char end) - (setq end (line-end-position)) - (let ((common-prefix (save-excursion - (goto-char start) - (if (re-search-forward "^\\([^.\n]+\\)\\." end t) - (match-string 1) - (error "No common prefix found"))))) - (save-excursion - (goto-char start) - (insert common-prefix " = {\n") - (goto-char (+ end (length common-prefix) 6)) - (insert "};\n") - (goto-char start) - (while (re-search-forward (concat "^" (regexp-quote common-prefix) "\\.") end t) - (replace-match "")))))) - -(defun swarsel/org-nixpkgs-fmt-block-lite () - (interactive) - (org-babel-mark-block) - (call-interactively 'nixpkgs-fmt-region)) - - - (defun swarsel/org-nixpkgs-fmt-block () - (interactive) - (save-excursion - (let* ((element (org-element-at-point)) - (begin (org-element-property :begin element)) - (end (org-element-property :end element)) - (lang (org-element-property :language element))) - (when lang - (goto-char begin) - (forward-line) - (insert "{") - (goto-char end) - (forward-line -1) - (beginning-of-line) - (forward-char -1) - (insert "}") - (org-babel-mark-block) - (call-interactively 'nixpkgs-fmt-region))))) - (defun swarsel/minibuffer-setup-hook () (setq gc-cons-threshold most-positive-fixnum)) @@ -301,160 +236,168 @@ create a new one." (add-hook 'minibuffer-setup-hook #'swarsel/minibuffer-setup-hook) (add-hook 'minibuffer-exit-hook #'swarsel/minibuffer-exit-hook) +(defun swarsel/org-colorize-outline (parents raw) + (let* ((palette ["#58B6ED" "#8BD49C" "#33CED8" "#4B9CCC" + "yellow" "orange" "salmon" "red"]) + (n (length parents)) + (colored-parents + (cl-mapcar + (lambda (p i) + (propertize p 'face `(:foreground ,(aref palette (mod i (length palette))) :weight bold))) + parents + (number-sequence 0 (1- n))))) + (concat + (when parents + (string-join colored-parents "/")) + (when parents "/") + (propertize raw 'face `(:foreground ,(aref palette (mod n (length palette))) + :weight bold))))) + +(defun swarsel/org-insert-link-to-heading () + (interactive) + (let ((candidates '())) + (org-map-entries + (lambda () + (let* ((raw (org-get-heading t t t t)) + (parents (org-get-outline-path t)) + (m (copy-marker (point))) + (colored (swarsel/org-colorize-outline parents raw))) + (push (cons colored m) candidates)))) + + (let* ((choice (completing-read "Heading: " (mapcar #'car candidates))) + (marker (cdr (assoc choice candidates))) + id raw-heading) + (unless marker + (user-error "No marker for heading??")) + + (save-excursion + (goto-char marker) + (setq id (prot-org--id-get)) + (setq raw-heading (org-get-heading t t t t))) + + (insert (org-link-make-string (format "#%s" id) + raw-heading))))) + ;; Make ESC quit prompts - (global-set-key (kbd "") 'keyboard-escape-quit) +(global-set-key (kbd "") 'keyboard-escape-quit) - ;; Set up general keybindings - (use-package general - :config - (general-create-definer swarsel/leader-keys - :keymaps '(normal insert visual emacs) - :prefix "SPC" - :global-prefix "C-SPC") +;; Set up general keybindings +(use-package general + :config + (general-create-definer swarsel/leader-keys + :keymaps '(normal insert visual emacs) + :prefix "SPC" + :global-prefix "C-SPC") - (swarsel/leader-keys - "e" '(:ignore e :which-key "evil") - "eo" '(evil-jump-backward :which-key "cursor jump backwards") - "eO" '(evil-jump-forward :which-key "cursor jump forwards") - "t" '(:ignore t :which-key "toggles") - "ts" '(hydra-text-scale/body :which-key "scale text") - "te" '(swarsel/toggle-evil-state :which-key "emacs/evil") - "tl" '(display-line-numbers-mode :which-key "line numbers") - "tp" '(evil-cleverparens-mode :wk "cleverparens") - "to" '(olivetti-mode :wk "olivetti") - "td" '(darkroom-tentative-mode :wk "darkroom") - "tw" '((lambda () (interactive) (toggle-truncate-lines)) :which-key "line wrapping") - "m" '(:ignore m :which-key "modes/programs") - "mm" '((lambda () (interactive) (mu4e)) :which-key "mu4e") - "mg" '((lambda () (interactive) (magit-list-repositories)) :which-key "magit-list-repos") - "mc" '((lambda () (interactive) (swarsel/open-calendar)) :which-key "calendar") - "mp" '(popper-toggle :which-key "popper") - "md" '(dirvish :which-key "dirvish") - "mr" '(bjm/elfeed-load-db-and-open :which-key "elfeed") - "o" '(:ignore o :which-key "org") - "op" '((lambda () (interactive) (org-present)) :which-key "org-present") - "oa" '((lambda () (interactive) (org-agenda)) :which-key "org-agenda") - "oa" '((lambda () (interactive) (org-refile)) :which-key "org-refile") - "ob" '((lambda () (interactive) (org-babel-mark-block)) :which-key "Mark whole src-block") - "ol" '((lambda () (interactive) (org-insert-link)) :which-key "insert link") - "oc" '((lambda () (interactive) (org-store-link)) :which-key "copy (=store) link") - "os" '(shfmt-region :which-key "format sh-block") - "od" '((lambda () (interactive) (org-babel-demarcate-block)) :which-key "demarcate (split) src-block") - "on" '(nixpkgs-fmt-region :which-key "format nix-block") - "ot" '(swarsel/org-babel-tangle-config :which-key "tangle file") - "oe" '(org-html-export-to-html :which-key "export to html") - "c" '(:ignore c :which-key "capture") - "ct" '((lambda () (interactive) (org-capture nil "tt")) :which-key "task") - ;; "cj" '((lambda () (interactive) (org-capture nil "jj")) :which-key "journal") - ;; "cs" '(markdown-download-screenshot :which-key "screenshot") - "l" '(:ignore l :which-key "links") - "lc" '((lambda () (interactive) (progn (find-file swarsel-swarsel-org-filepath) (org-overview) )) :which-key "SwarselSystems.org") - "le" '((lambda () (interactive) (progn (find-file swarsel-swarsel-org-filepath) (goto-char (org-find-exact-headline-in-buffer "Emacs") ) (org-overview) (org-cycle) )) :which-key "Emacs.org") - "ln" '((lambda () (interactive) (progn (find-file swarsel-swarsel-org-filepath) (goto-char (org-find-exact-headline-in-buffer "System") ) (org-overview) (org-cycle))) :which-key "Nixos.org") - "ls" '((lambda () (interactive) (find-file "/smb:Swarsel@winters:")) :which-key "Server") - "lo" '(dired swarsel-obsidian-vault-directory :which-key "obsidian") - ;; "la" '((lambda () (interactive) (find-file swarsel-org-anki-filepath)) :which-key "anki") - ;; "ln" '((lambda () (interactive) (find-file swarsel-nix-org-filepath)) :which-key "Nix.org") - "lp" '((lambda () (interactive) (projectile-switch-project)) :which-key "switch project") - "lg" '((lambda () (interactive) (magit-list-repositories)) :which-key "list git repos") - ;; "a" '(:ignore a :which-key "anki") - ;; "ap" '(anki-editor-push-tree :which-key "push new cards") - ;; "an" '((lambda () (interactive) (org-capture nil "a")) :which-key "new card") - ;; "as" '(swarsel-anki-set-deck-and-notetype :which-key "change deck and notetype") - "h" '(:ignore h :which-key "help") - "hy" '(yas-describe-tables :which-key "yas tables") - "hb" '(embark-bindings :which-key "current key bindings") - "h" '(:ignore t :which-key "describe") - "he" 'view-echo-area-messages - "hf" 'describe-function - "hF" 'describe-face - "hl" '(view-lossage :which-key "show command keypresses") - "hL" 'find-library - "hm" 'describe-mode - "ho" 'describe-symbol - "hk" 'describe-key - "hK" 'describe-keymap - "hp" 'describe-package - "hv" 'describe-variable - "hd" 'devdocs-lookup - "w" '(:ignore t :which-key "window") - "wl" 'windmove-right - "w " 'windmove-right - "wh" 'windmove-left - "w " 'windmove-left - "wk" 'windmove-up - "w " 'windmove-up - "wj" 'windmove-down - "w " 'windmove-down - "wr" 'winner-redo - "wd" 'delete-window - "w=" 'balance-windows-area - "wD" 'kill-buffer-and-window - "wu" 'winner-undo - "wr" 'winner-redo - "w/" 'evil-window-vsplit -"w\\" 'evil-window-vsplit - "w-" 'evil-window-split - "wm" '(delete-other-windows :wk "maximize") - "" 'up-list - "" 'down-list - )) + (swarsel/leader-keys + "e" '(:ignore e :which-key "evil") + "eo" '(evil-jump-backward :which-key "cursor jump backwards") + "eO" '(evil-jump-forward :which-key "cursor jump forwards") + "t" '(:ignore t :which-key "toggles") + "ts" '(hydra-text-scale/body :which-key "scale text") + "te" '(swarsel/toggle-evil-state :which-key "emacs/evil") + "tl" '(display-line-numbers-mode :which-key "line numbers") + "tp" '(evil-cleverparens-mode :wk "cleverparens") + "to" '(olivetti-mode :wk "olivetti") + "td" '(darkroom-tentative-mode :wk "darkroom") + "tw" '((lambda () (interactive) (toggle-truncate-lines)) :which-key "line wrapping") + "m" '(:ignore m :which-key "modes/programs") + "mm" '((lambda () (interactive) (mu4e)) :which-key "mu4e") + "mg" '((lambda () (interactive) (magit-list-repositories)) :which-key "magit-list-repos") + "mc" '((lambda () (interactive) (swarsel/open-calendar)) :which-key "calendar") + "mp" '(popper-toggle :which-key "popper") + "md" '(dirvish :which-key "dirvish") + "mr" '(bjm/elfeed-load-db-and-open :which-key "elfeed") + "o" '(:ignore o :which-key "org") + "op" '((lambda () (interactive) (org-present)) :which-key "org-present") + "oa" '((lambda () (interactive) (org-agenda)) :which-key "org-agenda") + "oa" '((lambda () (interactive) (org-refile)) :which-key "org-refile") + "ob" '((lambda () (interactive) (org-babel-mark-block)) :which-key "Mark whole src-block") + "ol" '((lambda () (interactive) (org-insert-link)) :which-key "insert link") + "oc" '((lambda () (interactive) (org-store-link)) :which-key "copy (=store) link") + "os" '(shfmt-region :which-key "format sh-block") + "od" '((lambda () (interactive) (org-babel-demarcate-block)) :which-key "demarcate (split) src-block") + "on" '(nixpkgs-fmt-region :which-key "format nix-block") + "ot" '(swarsel/org-babel-tangle-config :which-key "tangle file") + "oe" '(org-html-export-to-html :which-key "export to html") + "c" '(:ignore c :which-key "capture") + "ct" '((lambda () (interactive) (org-capture nil "tt")) :which-key "task") + "l" '(:ignore l :which-key "links") + "lc" '((lambda () (interactive) (progn (find-file swarsel-swarsel-org-filepath) (org-overview) )) :which-key "SwarselSystems.org") + "le" '((lambda () (interactive) (progn (find-file swarsel-swarsel-org-filepath) (goto-char (org-find-exact-headline-in-buffer "Emacs") ) (org-overview) (org-cycle) )) :which-key "Emacs.org") + "lr" '(swarsel/consult-magit-repos :which-key "List repos") + "ln" '((lambda () (interactive) (progn (find-file swarsel-swarsel-org-filepath) (goto-char (org-find-exact-headline-in-buffer "System") ) (org-overview) (org-cycle))) :which-key "Nixos.org") + "lp" '((lambda () (interactive) (projectile-switch-project)) :which-key "switch project") + "lg" '((lambda () (interactive) (magit-list-repositories)) :which-key "list git repos") + "h" '(:ignore h :which-key "help") + "hy" '(yas-describe-tables :which-key "yas tables") + "hb" '(embark-bindings :which-key "current key bindings") + "h" '(:ignore t :which-key "describe") + "he" 'view-echo-area-messages + "hf" 'describe-function + "hF" 'describe-face + "hl" '(view-lossage :which-key "show command keypresses") + "hL" 'find-library + "hm" 'describe-mode + "ho" 'describe-symbol + "hk" 'describe-key + "hK" 'describe-keymap + "hp" 'describe-package + "hv" 'describe-variable + "hd" 'devdocs-lookup + "w" '(:ignore t :which-key "window") + "wl" 'windmove-right + "w " 'windmove-right + "wh" 'windmove-left + "w " 'windmove-left + "wk" 'windmove-up + "w " 'windmove-up + "wj" 'windmove-down + "w " 'windmove-down + "wr" 'winner-redo + "wd" 'delete-window + "w=" 'balance-windows-area + "wD" 'kill-buffer-and-window + "wu" 'winner-undo + "wr" 'winner-redo + "w/" 'evil-window-vsplit + "w\\" 'evil-window-vsplit + "w-" 'evil-window-split + "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-M-d" 'swarsel-obsidian-daily ; open daily obsidian file and create if not exist - ;; "C-M-S" 'swarsel-anki-set-deck-and-notetype ; switch deck and notetype for new anki cards - ;; "C-M-s" 'markdown-download-screenshot ; wrapper for org-download-screenshot - "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 - "C-" 'my-python-shell-run - "" '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 swarsel-sync-directory "~/Nextcloud" - swarsel-emacs-directory "~/.emacs.d" - swarsel-dotfiles-directory "~/.dotfiles" - swarsel-projects-directory "~/Documents/GitHub") - -(setq swarsel-emacs-org-filepath (expand-file-name "Emacs.org" swarsel-dotfiles-directory) - swarsel-nix-org-filepath (expand-file-name "Nix.org" swarsel-dotfiles-directory) - swarsel-swarsel-org-filepath (expand-file-name "SwarselSystems.org" swarsel-dotfiles-directory) - ) - - -;; set Emacs main configuration .org names -(setq swarsel-emacs-org-file "Emacs.org" - swarsel-anki-org-file "Anki.org" - swarsel-tasks-org-file "Tasks.org" - swarsel-archive-org-file "Archive.org" - swarsel-org-folder-name "Org" - swarsel-obsidian-daily-folder-name "⭐ Personal/Journal" - swarsel-obsidian-folder-name "Obsidian" - swarsel-obsidian-vault-name "Main") - - -;; set directory paths -(setq swarsel-org-directory (expand-file-name swarsel-org-folder-name swarsel-sync-directory)) ; path to org folder -(setq swarsel-obsidian-directory (expand-file-name swarsel-obsidian-folder-name swarsel-sync-directory)) ; path to obsidian -(setq swarsel-obsidian-vault-directory (expand-file-name swarsel-obsidian-vault-name swarsel-obsidian-directory)) ; path to obsidian vault -(setq swarsel-obsidian-daily-directory (expand-file-name swarsel-obsidian-daily-folder-name swarsel-obsidian-vault-directory)) ; path to obsidian daily folder - -;; filepaths to certain documents -(setq swarsel-org-anki-filepath (expand-file-name swarsel-anki-org-file swarsel-org-directory) ; path to anki export file - swarsel-org-tasks-filepath (expand-file-name swarsel-tasks-org-file swarsel-org-directory) - swarsel-org-archive-filepath (expand-file-name swarsel-archive-org-file swarsel-org-directory)) +(setq + swarsel-emacs-directory "~/.emacs.d" + swarsel-dotfiles-directory (getenv "FLAKE") + swarsel-swarsel-org-filepath (expand-file-name "SwarselSystems.org" swarsel-dotfiles-directory) + swarsel-tasks-org-file "Tasks.org" + swarsel-archive-org-file "Archive.org" + swarsel-work-projects-directory (getenv "DOCUMENT_DIR_WORK") + swarsel-private-projects-directory (getenv "DOCUMENT_DIR_PRIV") + ) ;; Change the user-emacs-directory to keep unwanted things out of ~/.emacs.d (setq user-emacs-directory (expand-file-name "~/.cache/emacs/") @@ -484,7 +427,7 @@ create a new one." ;; use UTF-8 everywhere (set-language-environment "UTF-8") -(profiler-start 'cpu) +;; (profiler-start 'cpu) ;; set default font size (defvar swarsel/default-font-size 130) (setq swarsel-standard-font "FiraCode Nerd Font Mono" @@ -519,6 +462,7 @@ create a new one." password-cache-expiry nil ) (setq browse-url-browser-function 'browse-url-firefox) +;; (setenv "DISPLAY" ":0") ;; needed for firefox ;; disable a keybind that does more harm than good (global-set-key [remap suspend-frame] (lambda () @@ -554,8 +498,8 @@ create a new one." (run-with-idle-timer 15 t (lambda () ;; (message "Garbage Collector has run for %.06fsec" - (k-time (garbage-collect))))) - ;; ) + (k-time (garbage-collect))))) +;; ) (setq-default indent-tabs-mode nil tab-width 2) @@ -576,8 +520,8 @@ create a new one." (set-face-attribute 'highlight-indent-guides-stack-even-face nil :background "gray40") (set-face-attribute 'highlight-indent-guides-stack-odd-face nil :background "gray50")) -(use-package aggressive-indent) -(global-aggressive-indent-mode 1) +;; (use-package aggressive-indent) +;; (global-aggressive-indent-mode 1) (setq mouse-wheel-scroll-amount '(1 @@ -660,6 +604,20 @@ create a new one." :config (global-evil-surround-mode 1)) +(use-package evil-visual-mark-mode + :config (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-numbers) + ;; set the NixOS wordlist by hand (setq ispell-alternate-dictionary (getenv "WORDLIST")) @@ -676,8 +634,6 @@ create a new one." :weight 'regular :height 1.06) -;; these settings used to be in custom.el - (use-package solaire-mode :custom (solaire-global-mode +1)) @@ -817,9 +773,12 @@ create a new one." (use-package marginalia :after vertico + :bind (:map minibuffer-local-map + ("M-A" . marginalia-cycle)) :init (marginalia-mode) - (setq marginalia-annotators '(marginalia-annotators-heavy marginalia-annotators-light nil))) + ;; (setq marginalia-annotators '(marginalia-annotators-heavy marginalia-annotators-light nil)) + ) (use-package nerd-icons-completion :after (marginalia nerd-icons) @@ -900,14 +859,31 @@ create a new one." (setq-default indicate-buffer-boundaries t) ;; (setq auth-sources '( "~/.emacs.d/.caldav" "~/.emacs.d/.authinfo.gpg") - ;; auth-source-cache-expiry nil) ; default is 2h +;; auth-source-cache-expiry nil) ; default is 2h (setq auth-sources '( "~/.emacs.d/.authinfo") auth-source-cache-expiry nil) +(defun swarsel/org-agenda-done-and-archive () + "Mark TODO at point as DONE, archive it, and save all agenda files." + (interactive) + (let ((org-archive-location "~/Org/Archive.org::Archive")) + (org-agenda-todo "DONE") + (org-agenda-archive) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (when (and buffer-file-name + (string-prefix-p (expand-file-name "~/Org/") (file-truename buffer-file-name)) + (derived-mode-p 'org-mode)) + (save-buffer)))))) + +(with-eval-after-load 'org-agenda + (define-key org-agenda-mode-map (kbd "C-a") #'swarsel/org-agenda-done-and-archive)) + (use-package org ;;:diminish (org-indent-mode) :hook (org-mode . swarsel/org-mode-setup) + ;; :mode "\\.nix\\'" :bind (("C-" . org-fold-outer) ("C-c s" . org-store-link)) @@ -918,109 +894,29 @@ create a new one." (setq org-startup-folded t) (setq org-support-shift-select t) - ;; (setq org-agenda-start-with-log-mode t) - ;; (setq org-log-done 'time) - ;; (setq org-log-into-drawer t) + (setq org-agenda-start-with-log-mode t) + (setq org-log-done 'time) + (setq org-log-into-drawer t) (setq org-startup-with-inline-images t) (setq org-export-headline-levels 6) (setq org-image-actual-width nil) (setq org-format-latex-options '(:foreground "White" :background default :scale 2.0 :html-foreground "Black" :html-background "Transparent" :html-scale 1.0 :matchers ("begin" "$1" "$" "$$" "\\(" "\\["))) -(setq org-agenda-files '("/home/swarsel/Nextcloud/Org/Tasks.org" - "/home/swarsel/Nextcloud/Org/Archive.org" - "/home/swarsel/Nextcloud/Org/Anki.org" - "/home/swarsel/Calendars/leon_cal.org")) + (setq org-agenda-files '("/home/swarsel/Org/Tasks.org" + "/home/swarsel/Org/Archive.org" + )) -(setq org-refile-targets - '((swarsel-archive-org-file :maxlevel . 1) - (swarsel-anki-org-file :maxlevel . 1) - (swarsel-tasks-org-file :maxlevel . 1))) + (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") + "* %?\nEntered on %U\n %i\n %a"))) -(setq org-todo-keywords - '((sequence "TODO(t)" "NEXT(n)" "|" "DONE(d!)") - (sequence "BACKLOG(b)" "PLAN(p)" "READY(r)" "ACTIVE(a)" "REVIEW(v)" "WAIT(w@/!)" "HOLD(h)" "|" "COMPLETED(c)" "CANC(k@)"))) + (setq org-refile-targets + '((swarsel-archive-org-file :maxlevel . 1) + (swarsel-tasks-org-file :maxlevel . 1))) - -;; Configure custom agenda views -(setq org-agenda-custom-commands - '(("d" "Dashboard" - ((agenda "" ((org-deadline-warning-days 7))) - (todo "NEXT" - ((org-agenda-overriding-header "Next Tasks"))) - (tags-todo "agenda/ACTIVE" ((org-agenda-overriding-header "Active Projects"))))) - - ("n" "Next Tasks" - ((todo "NEXT" - ((org-agenda-overriding-header "Next Tasks"))))) - - ("W" "Work Tasks" tags-todo "+work-email") - - - ("w" "Workflow Status" - ((todo "WAIT" - ((org-agenda-overriding-header "Waiting on External") - (org-agenda-files org-agenda-files))) - (todo "REVIEW" - ((org-agenda-overriding-header "In Review") - (org-agenda-files org-agenda-files))) - (todo "PLAN" - ((org-agenda-overriding-header "In Planning") - (org-agenda-todo-list-sublevels nil) - (org-agenda-files org-agenda-files))) - (todo "BACKLOG" - ((org-agenda-overriding-header "Project Backlog") - (org-agenda-todo-list-sublevels nil) - (org-agenda-files org-agenda-files))) - (todo "READY" - ((org-agenda-overriding-header "Ready for Work") - (org-agenda-files org-agenda-files))) - (todo "ACTIVE" - ((org-agenda-overriding-header "Active Projects") - (org-agenda-files org-agenda-files))) - (todo "COMPLETED" - ((org-agenda-overriding-header "Completed Projects") - (org-agenda-files org-agenda-files))) - (todo "CANC" - ((org-agenda-overriding-header "Cancelled Projects") - (org-agenda-files org-agenda-files))))))) - -(setq org-capture-templates - `( - ("a" "Anki basic" - entry - (file+headline swarsel-org-anki-filepath "Dispatch") - (function swarsel-anki-make-template-string)) - - ("A" "Anki cloze" - entry - (file+headline org-swarsel-anki-file "Dispatch") - "* %<%H:%M>\n:PROPERTIES:\n:ANKI_NOTE_TYPE: Cloze\n:ANKI_DECK: 🦁 All::01 ❤️ Various::00 ✨ Allgemein\n:END:\n** Text\n%?\n** Extra\n") - ("t" "Tasks / Projects") - ("tt" "Task" entry (file+olp swarsel-org-tasks-filepath "Inbox") - "* TODO %?\n %U\n %a\n %i" :empty-lines 1) - )) -) - -;; Set faces for heading levels -(with-eval-after-load 'org-faces (dolist (face '((org-level-1 . 1.1) - (org-level-2 . 0.9) - (org-level-3 . 0.9) - (org-level-4 . 0.9) - (org-level-5 . 0.9) - (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))) - - ;; Ensure that anything that should be fixed-pitch in Org files appears that way - (set-face-attribute 'org-block 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-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)) + ) (use-package org-appear :hook (org-mode . org-appear-mode) @@ -1037,29 +933,44 @@ create a new one." (setq org-src-preserve-indentation nil) - (org-babel-do-load-languages - 'org-babel-load-languages - '((emacs-lisp . t) - (python . t) - (js . t) - (shell . t) - )) +(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) +(push '("conf-unix" . conf-unix) org-src-lang-modes) - (setq org-export-with-broken-links 'mark) - (setq org-confirm-babel-evaluate nil) +(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 :tangle")) +(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) @@ -1071,20 +982,7 @@ create a new one." (setq TeX-electric-sub-and-superscript t) ;; (setq reftex-plug-into-AUCTeX t) -(use-package org-download - :after org - :defer nil - :custom - (org-download-method 'directory) - (org-download-image-dir "./images") - (org-download-heading-lvl 0) - (org-download-timestamp "org_%Y%m%d-%H%M%S_") - ;;(org-image-actual-width 500) - (org-download-screenshot-method "grim -g \"$(slurp)\" %s") - :bind - ("C-M-y" . org-download-screenshot) - :config - (require 'org-download)) + (use-package org-fragtog) (add-hook 'org-mode-hook 'org-fragtog-mode) @@ -1198,10 +1096,48 @@ create a new one." (add-hook 'org-present-mode-quit-hook 'swarsel/org-present-end) (add-hook 'org-present-after-navigate-functions 'swarsel/org-present-slide) -(use-package nix-mode) +(defun org-babel-execute:markdown (body params) + "Just return BODY unchanged, allowing noweb expansion." + body) + +(use-package nix-mode + :after lsp-mode + :ensure t + :hook + (nix-mode . lsp-deferred) ;; So that envrc mode will work + :custom + (lsp-disabled-clients '((nix-mode . nix-nil))) ;; Disable nil so that nixd will be used as lsp-server + :config + (setq lsp-nix-nixd-server-path "nixd" + lsp-nix-nixd-formatting-command [ "nixpkgs-fmt" ] + lsp-nix-nixd-nixpkgs-expr "import (builtins.getFlake \"/home/swarsel/.dotfiles\").inputs.nixpkgs { }" + lsp-nix-nixd-nixos-options-expr "(builtins.getFlake \"/home/swarsel/.dotfiles\").nixosConfigurations.pyramid.options" + lsp-nix-nixd-home-manager-options-expr "(builtins.getFlake \"/home/swarsel/.dotfiles\").nixosConfigurations.pyramid.options.home-manager.users.type.getSubOptions []" + )) (use-package nix-ts-mode - :mode "\\.nix\\'") + :after lsp-mode + :mode "\\.nix\\'" + :ensure t + :hook + (nix-ts-mode . lsp-deferred) ;; So that envrc mode will work + :custom + (lsp-disabled-clients '((nix-ts-mode . nix-nil))) ;; Disable nil so that nixd will be used as lsp-server + :config + (setq lsp-nix-nixd-server-path "nixd" + lsp-nix-nixd-formatting-command [ "nixpkgs-fmt" ] + lsp-nix-nixd-nixpkgs-expr "import (builtins.getFlake \"/home/swarsel/.dotfiles\").inputs.nixpkgs { }" + lsp-nix-nixd-nixos-options-expr "(builtins.getFlake \"/home/swarsel/.dotfiles\").nixosConfigurations.pyramid.options" + lsp-nix-nixd-home-manager-options-expr "(builtins.getFlake \"/home/swarsel/.dotfiles\").nixosConfigurations.pyramid.options.home-manager.users.type.getSubOptions []" + )) + + +(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\\'" @@ -1213,6 +1149,8 @@ create a new one." (use-package jenkinsfile-mode :mode "Jenkinsfile") +(use-package ansible) + (use-package dockerfile-mode :mode "Dockerfile") @@ -1246,11 +1184,6 @@ create a new one." (local-set-key (kbd "C-c C-x C-u") 'markdown-toggle-url-hiding) )) -(use-package olivetti - :init - (setq olivetti-body-width 100) - (setq olivetti-recall-visual-line-mode-entry-state t)) - (use-package elfeed) (use-package elfeed-goodies) @@ -1268,9 +1201,13 @@ create a new one." (setq elfeed-protocol-enabled-protocols '(fever)) (setq elfeed-protocol-fever-update-unread-only t) (setq elfeed-protocol-fever-fetch-category-as-tag t) -(setq elfeed-protocol-feeds '(("fever+https://Swarsel@signpost.swarsel.win" - :api-url "https://signpost.swarsel.win/api/fever.php" - :password-file "~/.emacs.d/.fever"))) + +(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) @@ -1279,49 +1216,50 @@ create a new one." (define-key elfeed-search-mode-map (kbd "k") 'previous-line) (define-key elfeed-show-mode-map (kbd "S-SPC") 'scroll-down-command) -(use-package darkroom - :init - (setq darkroom-text-scale-increase 3)) - (use-package rg) -(use-package emacs - :ensure nil - :init - (setq treesit-language-source-alist - '((bash . ("https://github.com/tree-sitter/tree-sitter-bash")) - (c . ("https://github.com/tree-sitter/tree-sitter-c")) - (cmake . ("https://github.com/uyha/tree-sitter-cmake")) - (cpp . ("https://github.com/tree-sitter/tree-sitter-cpp")) - (css . ("https://github.com/tree-sitter/tree-sitter-css")) - (elisp . ("https://github.com/Wilfred/tree-sitter-elisp")) - (go . ("https://github.com/tree-sitter/tree-sitter-go")) - (html . ("https://github.com/tree-sitter/tree-sitter-html")) - (javascript . ("https://github.com/tree-sitter/tree-sitter-javascript")) - (json . ("https://github.com/tree-sitter/tree-sitter-json")) - (julia . ("https://github.com/tree-sitter/tree-sitter-julia")) - (latex . ("https://github.com/latex-lsp/tree-sitter-latex")) - (make . ("https://github.com/alemuller/tree-sitter-make")) - (markdown . ("https://github.com/ikatyang/tree-sitter-markdown")) - (nix . ("https://github.com/nix-community/tree-sitter-nix")) - (R . ("https://github.com/r-lib/tree-sitter-r")) - (python . ("https://github.com/tree-sitter/tree-sitter-python")) - (typescript . ("https://github.com/tree-sitter/tree-sitter-typescript" "typescript/src" "typescript")) - (rust . ("https://github.com/tree-sitter/tree-sitter-rust")) - (sql . ("https://github.com/m-novikov/tree-sitter-sql")) - (toml . ("https://github.com/tree-sitter/tree-sitter-toml")) - (tsx . ("https://github.com/tree-sitter/tree-sitter-typescript" "master" "typescript/src")) - (yaml . ("https://github.com/ikatyang/tree-sitter-yaml")))) - ) +;; (use-package emacs +;; :ensure nil +;; :init +;; (setq treesit-language-source-alist +;; '((bash . ("https://github.com/tree-sitter/tree-sitter-bash")) +;; (c . ("https://github.com/tree-sitter/tree-sitter-c")) +;; (cmake . ("https://github.com/uyha/tree-sitter-cmake")) +;; (cpp . ("https://github.com/tree-sitter/tree-sitter-cpp")) +;; (css . ("https://github.com/tree-sitter/tree-sitter-css")) +;; (elisp . ("https://github.com/Wilfred/tree-sitter-elisp")) +;; (go . ("https://github.com/tree-sitter/tree-sitter-go")) +;; (html . ("https://github.com/tree-sitter/tree-sitter-html")) +;; (javascript . ("https://github.com/tree-sitter/tree-sitter-javascript")) +;; (json . ("https://github.com/tree-sitter/tree-sitter-json")) +;; (julia . ("https://github.com/tree-sitter/tree-sitter-julia")) +;; (latex . ("https://github.com/latex-lsp/tree-sitter-latex")) +;; (make . ("https://github.com/alemuller/tree-sitter-make")) +;; (markdown . ("https://github.com/ikatyang/tree-sitter-markdown")) +;; (nix . ("https://github.com/nix-community/tree-sitter-nix")) +;; (R . ("https://github.com/r-lib/tree-sitter-r")) +;; (python . ("https://github.com/tree-sitter/tree-sitter-python")) +;; (typescript . ("https://github.com/tree-sitter/tree-sitter-typescript" "typescript/src" "typescript")) +;; (rust . ("https://github.com/tree-sitter/tree-sitter-rust")) +;; (sql . ("https://github.com/m-novikov/tree-sitter-sql")) +;; (toml . ("https://github.com/tree-sitter/tree-sitter-toml")) +;; (tsx . ("https://github.com/tree-sitter/tree-sitter-typescript" "master" "typescript/src")) +;; (yaml . ("https://github.com/ikatyang/tree-sitter-yaml")))) +;; ) (use-package treesit-auto + :custom + (setq treesit-auto-install t) :config - (global-treesit-auto-mode) - (setq treesit-auto-install 'prompt)) + (treesit-auto-add-to-auto-mode-alist 'all) + (global-treesit-auto-mode)) -(use-package direnv - :custom (direnv-always-show-summary nil) - :config (direnv-mode)) +;; (use-package direnv +;; :custom (direnv-always-show-summary nil) +;; :config (direnv-mode)) + +(use-package envrc + :hook (after-init . envrc-global-mode)) (use-package avy :bind @@ -1329,8 +1267,6 @@ create a new one." :config (setq avy-all-windows 'all-frames)) -(use-package crdt) - (use-package devdocs) (add-hook 'python-mode-hook @@ -1358,15 +1294,15 @@ create a new one." ("C-c p" . projectile-command-map) ; all projectile commands under this :init ;; NOTE: Set this to the folder where you keep your Git repos! - (when (file-directory-p swarsel-projects-directory) - (setq projectile-project-search-path (list swarsel-projects-directory))) + (when (file-directory-p swarsel-work-projects-directory) + (when (file-directory-p swarsel-private-projects-directory) + (setq projectile-project-search-path (list swarsel-work-projects-directory swarsel-private-projects-directory)))) (setq projectile-switch-project-action #'magit-status)) (use-package magit :config - (setq magit-repository-directories `((,swarsel-projects-directory . 1) - (,swarsel-emacs-directory . 0) - (,swarsel-obsidian-directory . 0) + (setq magit-repository-directories `((,swarsel-work-projects-directory . 3) + (,swarsel-private-projects-directory . 3) ("~/.dotfiles/" . 0))) :custom (magit-display-buffer-function #'magit-display-buffer-same-window-except-diff-v1)) ; stay in the same window @@ -1381,13 +1317,6 @@ create a new one." (use-package forge :after magit) -(with-eval-after-load 'forge - (add-to-list 'forge-alist - '("sgit.iue.tuwien.ac.at" - "sgit.iue.tuwien.ac.at/api/v1" - "sgit.iue.tuwien.ac.at" - forge-gitea-repository))) - (use-package git-timemachine :hook (git-time-machine-mode . evil-normalize-keymaps) :init (setq git-timemachine-show-minibuffer-details t)) @@ -1417,12 +1346,6 @@ create a new one." (use-package rainbow-mode :config (rainbow-mode)) -;; (use-package corfu -;; :custom -;; (corfu-cycle t) -;; :init -;; (global-corfu-mode)) - (use-package corfu :init (global-corfu-mode) @@ -1431,7 +1354,7 @@ create a new one." :custom (corfu-auto t) (corfu-auto-prefix 3) - (corfu-auto-delay 0.3) + (corfu-auto-delay 1) (corfu-cycle t) (corfu-quit-no-match 'separator) (corfu-separator ?\s) @@ -1483,38 +1406,23 @@ create a new one." ("C-z ^" . cape-tex) ("C-z &" . cape-sgml) ("C-z r" . cape-rfc1345) - ;; Add to the global default value of `completion-at-point-functions' which is - ;; used by `completion-at-point'. The order of the functions matters, the - ;; first function returning a result wins. Note that the list of buffer-local - ;; completion functions takes precedence over the global list. - ;; (add-to-list 'completion-at-point-functions #'cape-dabbrev) - ;; (add-to-list 'completion-at-point-functions #'cape-file) - ;; (add-to-list 'completion-at-point-functions #'cape-elisp-block) - ;; (add-to-list 'completion-at-point-functions #'cape-history) - ;; (add-to-list 'completion-at-point-functions #'cape-keyword) - ;; (add-to-list 'completion-at-point-functions #'cape-tex) - ;; (add-to-list 'completion-at-point-functions #'cape-sgml) - ;; (add-to-list 'completion-at-point-functions #'cape-rfc1345) - ;; (add-to-list 'completion-at-point-functions #'cape-abbrev) - ;; (add-to-list 'completion-at-point-functions #'cape-dict) - ;; (add-to-list 'completion-at-point-functions #'cape-elisp-symbol) - ;; (add-to-list 'completion-at-point-functions #'cape-line) ) -(use-package rustic - :init - (setq rust-mode-treesitter-derive t) - :config - (define-key rust-ts-mode-map (kbd "C-c C-c C-r") 'rustic-cargo-run) - (define-key rust-ts-mode-map (kbd "C-c C-c C-b") 'rustic-cargo-build) - (define-key rust-ts-mode-map (kbd "C-c C-c C-k") 'rustic-cargo-check) - (define-key rust-ts-mode-map (kbd "C-c C-c d") 'rustic-cargo-doc) - (define-key rust-ts-mode-map (kbd "C-c C-c a") 'rustic-cargo-add) - (setq rustic-format-on-save t) - (setq rustic-lsp-client 'eglot) - :mode ("\\.rs" . rustic-mode)) +;;(use-package rustic +;; :init +;; (setq rust-mode-treesitter-derive t) +;; :config +;; (define-key rust-ts-mode-map (kbd "C-c C-c C-r") 'rustic-cargo-run) +;; (define-key rust-ts-mode-map (kbd "C-c C-c C-b") 'rustic-cargo-build) +;; (define-key rust-ts-mode-map (kbd "C-c C-c C-k") 'rustic-cargo-check) +;; (define-key rust-ts-mode-map (kbd "C-c C-c d") 'rustic-cargo-doc) +;; (define-key rust-ts-mode-map (kbd "C-c C-c a") 'rustic-cargo-add) +;; (setq rustic-format-on-save t) +;; (setq rustic-lsp-client 'eglot) +;; :mode ("\\.rs" . rustic-mode)) (use-package tramp + ;; :ensure nil :init (setq vc-ignore-dir-regexp (format "\\(%s\\)\\|\\(%s\\)" @@ -1549,64 +1457,7 @@ create a new one." (use-package evil-nerd-commenter :bind ("M-/" . evilnc-comment-or-uncomment-lines)) -(use-package yasnippet - :init (yas-global-mode 1) - :config - (yas-reload-all)) - -(setq wtf/latex-mathbb-prefix "''") -(setq swarsel/latex-mathcal-prefix "``") - -(use-package yasnippet - :config - - (setq wtf/english-alphabet - '("a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z")) - - (dolist (elem wtf/english-alphabet) - (when (string-equal elem (downcase elem)) - (add-to-list 'wtf/english-alphabet (upcase elem)))) - - - (yas-define-snippets - 'latex-mode - (mapcar - (lambda (elem) - (list (concat wtf/latex-mathbb-prefix elem) (concat "\\mathbb{" elem "}") (concat "Mathbb letter " elem))) - wtf/english-alphabet)) - - (yas-define-snippets - 'latex-mode - (mapcar - (lambda (elem) - (list (concat swarsel/latex-mathcal-prefix elem) (concat "\\mathcal{" elem "}") (concat "Mathcal letter " elem))) - wtf/english-alphabet)) - - (setq swtf/latex-math-symbols - '(("x" . "\\times") - ("*" . "\\cdot") - ("." . "\\ldots") - ("op" . "\\operatorname{$1}$0") - ("o" . "\\circ") - ("V" . "\\forall") - ("v" . "\\vee") - ("w" . "\\wedge") - ("q" . "\\quad") - ("f" . "\\frac{$1}{$2}$0") - ("s" . "\\sum_{$1}^{$2}$0") - ("p" . "\\prod_{$1}^{$2}$0") - ("e" . "\\exists") - ("i" . "\\int_{$1}^{$2}$0") - ("c" . "\\cap") - ("u" . "\\cup") - ("0" . "\\emptyset"))) - - ) - (use-package eglot - :config - (add-to-list 'eglot-server-programs - '(yaml-ts-mode . ("ansible-language-server" "--stdio"))) :hook ((python-mode python-ts-mode @@ -1614,11 +1465,12 @@ create a new one." c-ts-mode c++-mode c++-ts-mode - rust-ts-mode - rustic-mode + go-mode + go-ts-mode + ;;rust-ts-mode + ;;rustic-mode tex-mode LaTeX-mode - yaml-ts-mode ) . (lambda () (progn (eglot-ensure) (add-hook 'before-save-hook 'eglot-format nil 'local)))) @@ -1644,17 +1496,55 @@ create a new one." (defalias 'start-lsp-server #'eglot) +(use-package lsp-mode + :init + ;; 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) + +;; (use-package company) + +;; thanks to https://tecosaur.github.io/emacs-config/config.html#lsp-support-src +(cl-defmacro lsp-org-babel-enable (lang) + "Support LANG in org source code block." + (setq centaur-lsp 'lsp-mode) + (cl-check-type lang string) + (let* ((edit-pre (intern (format "org-babel-edit-prep:%s" lang))) + (intern-pre (intern (format "lsp--%s" (symbol-name edit-pre))))) + `(progn + (defun ,intern-pre (info) + (let ((file-name (->> info caddr (alist-get :file)))) + (unless file-name + (setq file-name (make-temp-file "babel-lsp-"))) + (setq buffer-file-name file-name) + (lsp-deferred))) + (put ',intern-pre 'function-documentation + (format "Enable lsp-mode in the buffer of org source block (%s)." + (upcase ,lang))) + (if (fboundp ',edit-pre) + (advice-add ',edit-pre :after ',intern-pre) + (progn + (defun ,edit-pre (info) + (,intern-pre info)) + (put ',edit-pre 'function-documentation + (format "Prepare local buffer environment for org source block (%s)." + (upcase ,lang)))))))) +(defvar org-babel-lang-list + '( "nix" "nix-ts" "go" "python" "ipython" "bash" "sh" )) +(dolist (lang org-babel-lang-list) + (eval `(lsp-org-babel-enable ,lang))) + +(use-package lsp-bridge + :ensure nil) + (use-package sideline-flymake :hook (flymake-mode . sideline-mode) :init (setq sideline-flymake-display-mode 'point) ; 'point to show errors only on point - ; 'line to show errors on the current line + ; 'line to show errors on the current line (setq sideline-backends-right '(sideline-flymake))) -(use-package breadcrumb - ;; :config (breadcrumb-mode) - ) - (setq backup-by-copying-when-linked t) (use-package dirvish @@ -1663,12 +1553,12 @@ create a new one." :config (dirvish-peek-mode) (dirvish-side-follow-mode) - (setq dirvish-open-with-programs - (append dirvish-open-with-programs '( - (("xlsx" "docx" "doc" "odt" "ods") "libreoffice" "%f") - (("jpg" "jpeg" "png") "imv" "%f") - (("pdf") "sioyek" "%f") - (("xopp") "xournalpp" "%f")))) + ;; (setq dirvish-open-with-programs + ;; (append dirvish-open-with-programs '( + ;; (("xlsx" "docx" "doc" "odt" "ods") "libreoffice" "%f") + ;; (("jpg" "jpeg" "png") "imv" "%f") + ;; (("pdf") "sioyek" "%f") + ;; (("xopp") "xournalpp" "%f")))) :custom (delete-by-moving-to-trash t) (dired-listing-switches @@ -1708,14 +1598,6 @@ create a new one." ("M-e" . dirvish-emerge-menu) ("M-j" . dirvish-fd-jump))) -;; (use-package pdf-tools -;; :init -;; (if (not (boundp 'pdf-tools-directory)) -;; (pdf-tools-install)) -;; :mode ("\\.pdf" . pdf-view-mode)) - -(use-package ein) - (use-package undo-tree :init (global-undo-tree-mode) :bind (:map undo-tree-visualizer-mode-map @@ -1726,11 +1608,6 @@ create a new one." :config (setq undo-tree-history-directory-alist '(("." . "~/.emacs.d/undo")))) -;; (add-hook 'prog-mode-hook 'undo-tree-mode) -;; (add-hook 'text-mode-hook 'undo-tree-mode) -;; (add-hook 'org-mode-hook 'undo-tree-mode) -;; (add-hook 'latex-mode-hook 'undo-tree-mode) - (use-package hydra) ;; change the text size of the current buffer @@ -1740,103 +1617,6 @@ create a new one." ("k" text-scale-decrease "out") ("f" nil "finished" :exit t)) -;; (use-package obsidian -;; :ensure t -;; :demand t -;; :config -;; (obsidian-specify-path swarsel-obsidian-vault-directory) -;; (global-obsidian-mode t) -;; :custom -;; ;; This directory will be used for `obsidian-capture' if set. -;; (obsidian-inbox-directory "Inbox") -;; (bind-key (kbd "C-c M-o") 'obsidian-hydra/body 'obsidian-mode-map) -;; :bind (:map obsidian-mode-map -;; ;; Replace C-c C-o with Obsidian.el's implementation. It's ok to use another key binding. -;; ("C-c C-o" . obsidian-follow-link-at-point) -;; ;; Jump to backlinks -;; ("C-c C-b" . obsidian-backlink-jump) -;; ;; If you prefer you can use `obsidian-insert-link' -;; ("C-c C-l" . obsidian-insert-wikilink))) - -;; (use-package anki-editor -;; :after org -;; :bind (:map org-mode-map -;; ("" . anki-editor-cloze-region-auto-incr) -;; ("" . anki-editor-cloze-region-dont-incr) -;; ("" . anki-editor-reset-cloze-number) -;; ("" . anki-editor-push-tree)) -;; :hook (org-capture-after-finalize . anki-editor-reset-cloze-number) ; Reset cloze-number after each capture. -;; :config -;; (setq anki-editor-create-decks t ;; Allow anki-editor to create a new deck if it doesn't exist -;; anki-editor-org-tags-as-anki-tags t) - -;; (defun anki-editor-cloze-region-auto-incr (&optional arg) -;; "Cloze region without hint and increase card number." -;; (interactive) -;; (anki-editor-cloze-region swarsel-anki-editor-cloze-number "") -;; (setq swarsel-anki-editor-cloze-number (1+ swarsel-anki-editor-cloze-number)) -;; (forward-sexp)) -;; (defun anki-editor-cloze-region-dont-incr (&optional arg) -;; "Cloze region without hint using the previous card number." -;; (interactive) -;; (anki-editor-cloze-region (1- swarsel-anki-editor-cloze-number) "") -;; (forward-sexp)) -;; (defun anki-editor-reset-cloze-number (&optional arg) -;; "Reset cloze number to ARG or 1" -;; (interactive) -;; (setq swarsel-anki-editor-cloze-number (or arg 1))) -;; (defun anki-editor-push-tree () -;; "Push all notes under a tree." -;; (interactive) -;; (anki-editor-push-notes '(4)) -;; (anki-editor-reset-cloze-number)) -;; ;; Initialize -;; (anki-editor-reset-cloze-number) -;; ) - -;; (require 'anki-editor) - -;; (defvar swarsel-anki-deck nil) -;; (defvar swarsel-anki-notetype nil) -;; (defvar swarsel-anki-fields nil) - -;; (defun swarsel-anki-set-deck-and-notetype () -;; (interactive) -;; (setq swarsel-anki-deck (completing-read "Choose a deck: " -;; (sort (anki-editor-deck-names) #'string-lessp))) -;; (setq swarsel-anki-notetype (completing-read "Choose a note type: " -;; (sort (anki-editor-note-types) #'string-lessp))) -;; (setq swarsel-anki-fields (progn -;; (anki-editor--anki-connect-invoke-result "modelFieldNames" `((modelName . ,swarsel-anki-notetype))))) -;; ) - -;; (defun swarsel-anki-make-template-string () -;; (if (not swarsel-anki-deck) -;; (call-interactively 'swarsel-anki-set-deck-and-notetype)) -;; (setq swarsel-temp swarsel-anki-fields) -;; (concat (concat "* %<%H:%M>\n:PROPERTIES:\n:ANKI_NOTE_TYPE: " swarsel-anki-notetype "\n:ANKI_DECK: " swarsel-anki-deck "\n:END:\n** ")(pop swarsel-temp) "\n%?\n** " (mapconcat 'identity swarsel-temp "\n\n** ") "\n\n")) - -;; (defun swarsel-today() -;; (format-time-string "%Y-%m-%d")) - -;; (defun swarsel-obsidian-daily () -;; (interactive) -;; (if (not (file-exists-p (expand-file-name (concat (swarsel-today) ".md") swarsel-obsidian-daily-directory))) -;; (write-region "" nil (expand-file-name (concat (swarsel-today) ".md") swarsel-obsidian-daily-directory)) -;; ) -;; (find-file (expand-file-name (concat (swarsel-today) ".md") swarsel-obsidian-daily-directory))) - -;; (let ((mu4epath -;; (concat -;; (f-dirname -;; (file-truename -;; (executable-find "mu"))) -;; "/../share/emacs/site-lisp/mu4e"))) -;; (when (and -;; (string-prefix-p "/nix/store/" mu4epath) -;; (file-directory-p mu4epath)) -;; (add-to-list 'load-path mu4epath))) - (use-package mu4e :ensure nil ;; :load-path "/usr/share/emacs/site-lisp/mu4e/" @@ -1849,7 +1629,11 @@ create a new one." (setq mu4e-mu-binary (executable-find "mu")) (setq mu4e-hide-index-messages t) - (setq mu4e-update-interval 180) + ;; this is so that messages that target multiple addresses still are individually shown in the unreads + ;; this is needed because otherwise after closing the view there will still be an unread message + (setq mu4e-search-skip-duplicates nil) + + (setq mu4e-update-interval 60) (setq mu4e-get-mail-command "mbsync -a") (setq mu4e-maildir "~/Mail") @@ -1868,16 +1652,19 @@ create a new one." '((:maildir "/leon/Inbox" :key ?1) (:maildir "/nautilus/Inbox" :key ?2) (:maildir "/mrswarsel/Inbox" :key ?3) + (:maildir "/work/Inbox" :key ?4) (:maildir "/Sent Mail" :key ?s) (:maildir "/Trash" :key ?t) (:maildir "/Drafts" :key ?d) (:maildir "/All Mail" :key ?a))) - (setq user-mail-address "leon@swarsel.win" - user-full-name "Leon Schwarzäugl") + (setq user-mail-address (getenv "SWARSEL_MAIL4") + user-full-name (getenv "SWARSEL_FULLNAME")) - - (setq mu4e-user-mail-address-list '(leon.schwarzaeugl@gmail.com leon@swarsel.win nautilus.dw@gmail.com mrswarsel@gmail.com))) + ;; 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))) + ) (add-hook 'mu4e-compose-mode-hook #'swarsel/mu4e-send-from-correct-address) @@ -1885,21 +1672,54 @@ create a new one." (use-package mu4e-alert :config - (setq mu4e-alert-set-default-style 'libnotify)) + (mu4e-alert-enable-notifications) + (mu4e-alert-set-default-style 'libnotify) + (setq mu4e-alert-interesting-mail-query + (concat "(maildir:/leon/Inbox AND date:today..now" + " OR maildir:/work/Inbox AND date:today..now)" + " AND flag:unread")) + (alert-add-rule + :category "mu4e-alert" + :predicate (lambda (_) (string-match-p "^mu4e-" (symbol-name major-mode))) + :continue t) -(add-hook 'after-init-hook #'mu4e-alert-enable-notifications) + + (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 (setq swarsel-caldav-synced 0) - (setq org-caldav-url "https://stash.swarsel.win/remote.php/dav/calendars/Swarsel") - (setq org-caldav-calendars - '((:calendar-id "personal" - :inbox "~/Calendars/leon_cal.org"))) - (setq org-caldav-files '("~/Calendars/leon_cal.org")) + ;; (setq org-caldav-url "https://cal.example.org/swarsel/calendar") + ;; (setq org-caldav-calendars + ;; '((:calendar-id "personal" + ;; :inbox "~/Calendars/leon_cal.org"))) + ;; (setq org-caldav-files '("~/Calendars/leon_cal.org")) ;; (setq org-caldav-backup-file "~/org-caldav/org-caldav-backup.org") ;; (setq org-caldav-save-directory "~/org-caldav/") @@ -1926,6 +1746,14 @@ create a new one." :config (bind-key "g" 'cfw:refresh-calendar-buffer cfw:calendar-mode-map) (bind-key "q" 'evil-quit cfw:details-mode-map) + ;; dont change the order of days in this one, as it will break weekend markings + (setq calendar-day-name-array + ["Sunday" "Monday" "Tuesday" "Wednesday" "Thursday" "Friday" "Saturday"]) + + ;; First day of the week + (setq calendar-week-start-day 1) ; 0:Sunday, 1:Monday + + ;; (custom-set-faces ;; '(cfw:face-title ((t (:foreground "#f0dfaf" :weight bold :height 65)))) ;; ) @@ -1933,183 +1761,137 @@ create a new one." (defun swarsel/open-calendar () (interactive) - (unless (eq swarsel-caldav-synced 1) (org-caldav-sync) (setq swarsel-caldav-synced 1)) + ;; (unless (eq swarsel-caldav-synced 1) (org-caldav-sync) (setq swarsel-caldav-synced 1)) ;; (select-frame (make-frame '((name . "calendar")))) ; makes a new frame and selects it ;; (set-face-attribute 'default (selected-frame) :height 65) ; reduces the font size of the new frame (cfw:open-calendar-buffer :contents-sources (list - (cfw:org-create-source "Purple") ; orgmode source - (cfw:ical-create-source "TISS" "https://tiss.tuwien.ac.at/events/rest/calendar/personal?locale=de&token=4463bf7a-87a3-490a-b54c-99b4a65192f3" "Cyan")))) + (cfw:org-create-source "Blue") ; orgmode source + (cfw:ical-create-source (getenv "SWARSEL_CAL1NAME") (getenv "SWARSEL_CAL1") "Cyan") + (cfw:ical-create-source (getenv "SWARSEL_CAL2NAME") (getenv "SWARSEL_CAL2") "Green") + (cfw:ical-create-source (getenv "SWARSEL_CAL3NAME") (getenv "SWARSEL_CAL3") "Magenta") + ))) (use-package dashboard :ensure t :config (dashboard-setup-startup-hook) ;; (setq initial-buffer-choice (lambda () (get-buffer-create "*dashboard*"))) - (setq dashboard-display-icons-p t ;; display icons on both GUI and terminal - dashboard-icon-type 'nerd-icons ;; use `nerd-icons' package - dashboard-set-file-icons t - dashboard-items '((recents . 5) - (projects . 5) - (agenda . 5)) - dashboard-set-footer nil - dashboard-banner-logo-title "Welcome to SwarsEmacs!" - dashboard-image-banner-max-height 300 - dashboard-startup-banner "~/.dotfiles/wallpaper/swarsel.png" - dashboard-projects-backend 'projectile - dashboard-projects-switch-function 'magit-status - dashboard-set-navigator t - dashboard-startupify-list '(dashboard-insert-banner - dashboard-insert-newline - dashboard-insert-banner-title - dashboard-insert-newline - dashboard-insert-navigator - dashboard-insert-newline - dashboard-insert-init-info - dashboard-insert-items - ) - dashboard-navigator-buttons - `(;; line1 - ((,"" - "SwarselSocial" - "Browse Swarsele" - (lambda (&rest _) (browse-url "instagram.com/Swarsele"))) - (,"" - "SwarselSound" - "Browse SwarselSound" - (lambda (&rest _) (browse-url "sound.swarsel.win")) ) - (,"" - "SwarselSwarsel" - "Browse Swarsel" - (lambda (&rest _) (browse-url "github.com/Swarsel")) ) - (,"" - "SwarselStash" - "Browse SwarselStash" - (lambda (&rest _) (browse-url "stash.swarsel.win")) ) - (,"󰫑" - "SwarselSport" - "Browse SwarselSports" - (lambda (&rest _) (browse-url "social.parkour.wien/@Lenno"))) - ) - ( - (,"󱄅" - "swarsel.win" - "Browse swarsel.win" - (lambda (&rest _) (browse-url "swarsel.win"))) - ) - ))) + (let ((files-domain (getenv "SWARSEL_FILES_DOMAIN")) + (music-domain (getenv "SWARSEL_MUSIC_DOMAIN")) + (insta-domain (getenv "SWARSEL_INSTA_DOMAIN")) + (sport-domain (getenv "SWARSEL_SPORT_DOMAIN")) + (swarsel-domain (getenv "SWARSEL_DOMAIN")) + ) + (setq dashboard-display-icons-p t ;; display icons on both GUI and terminal + dashboard-icon-type 'nerd-icons ;; use `nerd-icons' package + dashboard-set-file-icons t + dashboard-items '((recents . 5) + (projects . 5) + (agenda . 5)) + dashboard-set-footer nil + dashboard-banner-logo-title "Welcome to SwarsEmacs!" + dashboard-image-banner-max-height 300 + dashboard-startup-banner "~/.dotfiles/files/wallpaper/swarsel.png" + dashboard-projects-backend 'projectile + dashboard-projects-switch-function 'magit-status + dashboard-set-navigator t + dashboard-startupify-list '(dashboard-insert-banner + dashboard-insert-newline + dashboard-insert-banner-title + dashboard-insert-newline + dashboard-insert-navigator + dashboard-insert-newline + dashboard-insert-init-info + dashboard-insert-items + ) + dashboard-navigator-buttons + `(;; line1 + ((,"" + "SwarselSocial" + "Browse Swarsele" + (lambda (&rest _) (browse-url ,insta-domain))) + + (,"" + "SwarselSound" + "Browse SwarselSound" + (lambda (&rest _) (browse-url ,(concat "https://" music-domain))) ) + (,"" + "SwarselSwarsel" + "Browse Swarsel" + (lambda (&rest _) (browse-url "https://github.com/Swarsel")) ) + (,"" + "SwarselStash" + "Browse SwarselStash" + (lambda (&rest _) (browse-url ,(concat "https://" files-domain))) ) + (,"󰫑" + "SwarselSport" + "Browse SwarselSports" + (lambda (&rest _) (browse-url ,sport-domain))) + ) + ( + (,"󱄅" + ,swarsel-domain + ,(concat "Browse " main-domain) + (lambda (&rest _) (browse-url ,(concat "https://" swarsel-domain)))) + ) + )))) (use-package vterm - :ensure t) - -(defun sudo-find-file (file-name) -"Like find file, but opens the file as root." -(interactive "FSudo Find File: ") -(let ((tramp-file-name (concat "/sudo::" (expand-file-name file-name)))) - (find-file tramp-file-name))) -;;; vterm/config.el -*- lexical-binding: t; -*- - - ;; Original functions overwrites tramp path with a guessed path. - ;; However it breaks if remote fqdn/hostname is not resolvale by local machine - ;; could also break on port forwarding, multihops, - ;; custom protocol such as: docker, vagrant, ... - ;; *if* you try to shell-side configure them. - ;; Easily testable with vagrant ssh port on localhost. - ;; My workflow is to open a tramp dired on / of the remote to get a - ;; "foothold" then open vterms from there. - (defun vterm--get-directory (path) - "[OVERLOADED] Get normalized directory to PATH." - (when path - (let (directory) - (if (string-match "^\\(.*?\\)@\\(.*?\\):\\(.*?\\)$" path) - (progn - (let ((user (match-string 1 path)) - (host (match-string 2 path)) - (dir (match-string 3 path))) - (if (and (string-equal user user-login-name) - (string-equal host (system-name))) - (progn - (when (file-directory-p dir) - (setq directory (file-name-as-directory dir)))) - (setq directory - ;; Bellow is what i altered - (file-name-as-directory (concat (file-remote-p default-directory) dir)))))) - (when (file-directory-p path) - (setq directory (file-name-as-directory path)))) - directory))) - ;; Injects the payload to the vterm buffer. - (defun me/vterm-load-config () - "Pass local configuration files to vterm. - -Allows remote vterm to be shell-side configured, -without altering remote config. -Also adds my personal configuration that does not rely -too much on external packages. -Prints a reasuring message to proove good faith." - (interactive) - (let (;; Bellow messages to reassure other users that look at history - (reasuring-message (format "Configuring shell of user %s to be emacs comptible" - user-full-name)) - (reasuring-notice "This action is shell local, it will not affect other shells") - ;; Bellow lies my configuration - (basic-func-script (f-read-text (concat (getenv "HOME") - "/.emacs.d/shells/sources/functions.sh"))) - ;; Bellow lies the vterm shell-side configuration - ;; Must be sourced last - (vterm-func-script (f-read-text (concat - (file-name-directory (find-library-name "vterm")) - "/etc/emacs-vterm-bash.sh")))) - (vterm-insert (format "# START: %s\n" reasuring-message)) - (vterm-insert (format "# %s\n" reasuring-notice)) - ;; Create one single block in history - (vterm-insert "{\n") - (vterm-insert basic-func-script) - (vterm-insert vterm-func-script) - (vterm-insert "}\n") - ;; End the single block in history - (vterm-insert (format "# %s\n" reasuring-notice)) - (vterm-insert (format "# STOP: %s\n" reasuring-message)) - ) - ) - - ;; find-file-other-window does not works great on remote: - ;; if given an absolute path on a remote host, - ;; the path will be understood as a local file since no - ;; tramp prefix is present, and bash does not care - ;; about tramp prefixes. - ;; Bellow we solve context before sending it to - ;; ffow - (defun me/vterm--find-file-other-window-wrapper (file) - "Help vterm find a FILE." - (find-file-other-window (me/vterm--ffow-resolver file))) - (defun me/vterm--ffow-resolver (file) - "Help vterm resolve FILE." - (cond - ;; "/sudo::" - ;; doom--sudo-file-path do the trick for us - ((s-starts-with-p "/sudo::" file) - (sudo-find-file - (concat (file-remote-p default-directory) - (substring-no-properties file 7)))) - ;; "/" means we want the "Relative root" - ;; try appending the remote prefix if relevent - ((s-starts-with-p "/" file) - (concat (file-remote-p default-directory) file)) - ;; we got a relative path - ;; we don't need to help ffow to find it - (t - file))) - - ;; The variable vterm-eval-cmds is a SERIOUSLY SENSIBLE variable ! - ;; Do not be the guy that adds RCE into their config ! - - ;; Allow customed ffow to be called from vterm - ;; ffow should be as safe as find-file which is already trusted - ;; we append our resolver that only manipulate strings, - ;; Proove me wrong but i think it's safe. - (add-to-list 'vterm-eval-cmds '("find-file-other-window" - me/vterm--find-file-other-window-wrapper)) + :ensure t) (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) + +(defun prot-window-delete-popup-frame (&rest _) + "Kill selected selected frame if it has parameter `prot-window-popup-frame'. + Use this function via a hook." + (when (frame-parameter nil 'prot-window-popup-frame) + (delete-frame))) + +(defmacro prot-window-define-with-popup-frame (command) + "Define interactive function which calls COMMAND in a new frame. +Make the new frame have the `prot-window-popup-frame' parameter." + `(defun ,(intern (format "prot-window-popup-%s" command)) () + ,(format "Run `%s' in a popup frame with `prot-window-popup-frame' parameter. +Also see `prot-window-delete-popup-frame'." command) + (interactive) + (let ((frame (make-frame '((prot-window-popup-frame . t) + (title . "Emacs Popup Frame"))))) + (unwind-protect + (progn + (select-frame frame) + (switch-to-buffer " prot-window-hidden-buffer-for-popup-frame") + (condition-case nil + (call-interactively ',command) + ((quit error user-error) + (delete-frame frame)))) + (dolist (fr (frame-list)) + (when (string= (frame-parameter fr 'name) "Emacs Popup Anchor") + (delete-frame fr))))))) + +(declare-function org-capture "org-capture" (&optional goto keys)) +(defvar org-capture-after-finalize-hook) + ;;;###autoload (autoload 'prot-window-popup-org-capture "prot-window") +(prot-window-define-with-popup-frame org-capture) +(add-hook 'org-capture-after-finalize-hook #'prot-window-delete-popup-frame) + +(declare-function mu4e "mu4e" (&optional goto keys)) + ;;;###autoload (autoload 'prot-window-popup-mu4e "prot-window") +(prot-window-define-with-popup-frame mu4e) +(advice-add 'mu4e-quit :after #'prot-window-delete-popup-frame) + +(declare-function swarsel/open-calendar "swarsel/open-calendar" (&optional goto keys)) + ;;;###autoload (autoload 'prot-window-popup-swarsel/open-calendar "prot-window") +(prot-window-define-with-popup-frame swarsel/open-calendar) +(advice-add 'bury-buffer :after #'prot-window-delete-popup-frame) + +(declare-function org-agenda "org-agenda" (&optional goto keys)) + ;;;###autoload (autoload 'prot-window-popup-org-agenda "prot-window") +(prot-window-define-with-popup-frame org-agenda) diff --git a/programs/emacs/server.el b/files/emacs/server.el similarity index 100% rename from programs/emacs/server.el rename to files/emacs/server.el diff --git a/files/firefox/chrome/userChrome.css b/files/firefox/chrome/userChrome.css new file mode 100644 index 0000000..c616488 --- /dev/null +++ b/files/firefox/chrome/userChrome.css @@ -0,0 +1,120 @@ +/* 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. */ + +/* 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 */ + + --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; +} + +@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; } + +#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 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; + } + } +} + +#navigator-toolbox > *{ line-height: normal; pointer-events: auto } + +/* Don't apply transform before window has been fully created */ +:root:not([sessionrestored]) #navigator-toolbox{ transform:none !important } + +:root[customizing] #navigator-toolbox{ + position: relative !important; + transform: none !important; + opacity: 1 !important; +} + +#navigator-toolbox[inFullscreen] > #PersonalToolbar, +#PersonalToolbar:is([collapsed=""],[collapsed="true"]){ display: none } + +/* 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; } +*/ diff --git a/files/firefox/tridactyl/themes/swarsel.css b/files/firefox/tridactyl/themes/swarsel.css new file mode 100644 index 0000000..2c20123 --- /dev/null +++ b/files/firefox/tridactyl/themes/swarsel.css @@ -0,0 +1,160 @@ +:root { + + --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; + + --tridactyl-def-fg: var(--base02); + --tridactyl-cmdl-bg: var(--base00); + --tridactyl-cmdl-fg: var(--base0C); + + --tridactyl-font-family: "San Francisco", sans-serif; + + --tridactyl-cmdl-font-size: 1.5rem; + --tridactyl-cmdl-line-height: 1.5; + + --tridactyl-cmplt-option-height: 1.4em; + --tridactyl-cmplt-font-size: var(--tridactyl-small-font-size); + --tridactyl-cmplt-border-top: unset; + + --tridactyl-status-font-size: 9px; + --tridactyl-status-font-family: "Fira Code", monospace; + --tridactyl-status-border: 1px var(--tridactyl-fg) solid; + + --tridactyl-header-font-size: var(--tridactyl-small-font-size); + --tridactyl-header-font-weight: 200; + --tridactyl-header-border-bottom: unset; + + --tridactyl-hintspan-font-size: var(--tridactyl-font-size); + --tridactyl-hint-active-fg: none; + +} + +:root #command-line-holder { + order: 1; + border: 2px solid var(--tridactyl-cmdl-fg); + color: var(--tridactyl-cmdl-bg); +} + +:root #tridactyl-input { + width: 90%; + padding: 1rem; + color: var(--tridactyl-def-fg); +} + +:root #completions table { + font-size: 0.8rem; + font-weight: 200; + border-spacing: 0; + table-layout: fixed; + padding: 1rem; + padding-top: 0; +} + +:root #completions > div { + max-height: calc(20 * var(--tridactyl-cmplt-option-height)); + min-height: calc(10 * var(--tridactyl-cmplt-option-height)); +} + +/* COMPLETIONS */ + +:root #completions { + font-weight: 200; + order: 2; + color: var(--tridactyl-def-fg); + background: var(--tridactyl-cmdl-bg); + +} + +/* Olie doesn't know how CSS inheritance works */ +:root #completions .HistoryCompletionSource { + max-height: unset; + min-height: unset; +} + +:root #completions .HistoryCompletionSource table { + width: 100%; + font-size: 9pt; + border-spacing: 0; + table-layout: fixed; +} + +/* redundancy 2: redundancy 2: more redundancy */ +:root #completions .BmarkCompletionSource { + max-height: unset; + min-height: unset; +} + +:root #completions table tr { white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +:root #completions .url { + background: var(--tridactyl-cmdl-bg); +} + +:root #completions .focused { + background: #44391F; +} +:root #completions .focused .url { + background: #44391F; +} + +:root #completions .BufferCompletionSource table { + width: unset; + font-size: unset; + border-spacing: unset; + table-layout: unset; +} + +:root #completions table tr { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +:root #completions .sectionHeader { + background: unset; + padding: 1rem !important; + padding-left: unset; + padding-bottom: 0.2rem; +} + +:root #cmdline_iframe { + position: fixed !important; + bottom: unset; + top: 25% !important; + left: 10% !important; + z-index: 2147483647 !important; + width: 80% !important; + box-shadow: rgba(0, 0, 0, 0.5) 0px 0px 15px !important; +} + +:root .TridactylStatusIndicator { + position: fixed !important; + bottom: 0 !important; + font-weight: 200 !important; + padding: 0.8ex !important; +} + +/* #Shydactyl-normal { */ +/* border-color: green !important; */ +/* } */ + +/* #Shydactyl-insert { */ +/* border-color: yellow !important; */ +/* } */ diff --git a/programs/firefox/tridactyl/tridactylrc b/files/firefox/tridactyl/tridactylrc similarity index 51% rename from programs/firefox/tridactyl/tridactylrc rename to files/firefox/tridactyl/tridactylrc index 2eccdca..9e4928f 100644 --- a/programs/firefox/tridactyl/tridactylrc +++ b/files/firefox/tridactyl/tridactylrc @@ -1,6 +1,6 @@ sanitise tridactyllocal tridactylsync -colourscheme base16-codeschool +colourscheme swarsel " General Settings set update.lastchecktime 1720629386560 @@ -12,9 +12,12 @@ set configversion 2.0 set searchurls.no https://search.nixos.org/options?query= set searchurls.np https://search.nixos.org/packages?query= set searchurls.hm https://home-manager-options.extranix.com/?query= +set searchurls.@c https://vbc.atlassian.net/wiki/search?text= +set searchurls.@j https://vbc.atlassian.net/issues/?jql=textfields%20~%20%22%s*%22&wildcardFlag=true set completions.Tab.statusstylepretty true set hintfiltermode vimperator-reflow set hintnames numeric +unbind --mode=hint " Binds bind buffer # @@ -22,12 +25,56 @@ bind gd tabdetach bind gD composite tabduplicate; tabdetach bind d composite tabprev; tabclose # bind D tabclose -bind c hint +bind c hint -J bindurl ^http(s)?://www\.google\.com c hint -Jc [class="LC20lb MBeuO DKV0Md"],[class="YmvwI"],[class="YyVfkd"],[class="fl"] bindurl ^http(s)?://news\.ycombinator\.com c hint -Jc [class="titleline"],[class="age"] bindurl ^http(s)?://lobste\.rs c hint -Jc [class="u-url"],[class="comments_label"] +bindurl ^http(s)?://reddit\.com c hint -Jc [class="title may-blank loggedin"],[class="bylink comments may-blank"] +bindurl ^http(s)?://github\.com c hint -Jc [class="Link--primary"],[class="AppHeader-button Button--secondary Button--medium Button p-0 color-fg-muted"],[class="UnderlineNav-item no-wrap js-responsive-underlinenav-item js-selected-navigation-item"],[class="prc-ActionList-ItemLabel-TmBhn"],[class="PRIVATE_TreeView-item-content-text prc-TreeView-TreeViewItemContentText-smZM-"] +bindurl ^http(s)?://vbc\.atlassian\.net\/wiki c hint -Jc [class="_1reo15vq _18m915vq _1bto1l2s _kqswh2mm _o5721q9c _syaz1fxt"],[class="_11c81ixg _1reo15vq _18m915vq _18s81b66 _kqswh2mm _k48p1wq8 _o5721q9c _1bto1l2s _u5f31b66"],[class="_1r04ze3t _kqswstnw"],[class="css-a61etj"],[class="jira-macro-table-underline-pdfexport"] bindurl ^http(s)?://www\.google\.com gi composite focusinput -l ; text.end_of_line +" Work +command tab_or_tabopen jsb -p (async () => {let tabs = await browser.tabs.query({}); let tab = tabs.find(t => t.url.includes(JS_ARG)); if (tab) {browser.tabs.update(tab.id, { active: true });} else {tri.excmds.tabopen(JS_ARG);}})() + +command tab_or_tabopen_local jsb -p (async () => {const currentWindow = await browser.windows.getCurrent(); const tabs = await browser.tabs.query({ windowId: currentWindow.id }); const tab = tabs.find(t => t.url.includes(JS_ARG)); if (tab) {browser.tabs.update(tab.id, { active: true });} else {tri.excmds.tabopen(JS_ARG);}})() + +bind gwa tab_or_tabopen_local apic-impimba-1.m.imp.ac.at +bind gwA tab_or_tabopen_local artifactory.imp.ac.at +bind gwb tab_or_tabopen_local bitbucket.vbc.ac.at +bind gwc tab_or_tabopen_local vbc.atlassian.net/wiki +bind gwd tab_or_tabopen_local datadomain-impimba-2.imp.ac.at +bind gwe tab_or_tabopen_local exivity.vbc.ac.at +bind gwg tab_or_tabopen_local github.com +bind gwG tab_or_tabopen_local goc.egi.eu +bind gwh tab_or_tabopen_local jupyterhub.vbc.ac.at +bind gwj tab_or_tabopen_local jenkins.vbc.ac.at +bind gwJ tab_or_tabopen_local test-jenkins.vbc.ac.at +bind gwl tab_or_tabopen_local lucid.app +bind gwm tab_or_tabopen_local monitoring.vbc.ac.at/grafana +bind gwM tab_or_tabopen_local monitoring.vbc.ac.at/prometheus +bind gwn tab_or_tabopen_local netbox.vbc.ac.at +bind gwN tab_or_tabopen_local nap.imp.ac.at +bind gwo tab_or_tabopen_local outlook.office.com +bind gws tab_or_tabopen_local satellite.vbc.ac.at +bind gwt tab_or_tabopen_local tower.vbc.ac.at +bind gwv tab_or_tabopen_local vc-impimba-1.m.imp.ac.at/ui +bind gwx tab_or_tabopen_local xclarity.vbc.ac.at + +unbind --mode=normal gh +bind ghp tab_or_tabopen_local https://github.com/pulls +bind ghi tab_or_tabopen_local https://github.com/issues/assigned?q=is%3Aissue%20state%3Aopen%20archived%3Afalse%20(assignee%3A%40me%20OR%20author%3A%40me)%20sort%3Aupdated-desc +bind ghv tab_or_tabopen_local github.com/orgs/vbc-it/repositories +bind ghc tab_or_tabopen_local github.com/orgs/CLIP-HPC/repositories +bind ghd tab_or_tabopen_local github.com/Swarsel/.dotfiles +bind ghni tab_or_tabopen_local github.com/NixOS/nixpkgs/issues +bind ghnp tab_or_tabopen_local github.com/NixOS/nixpkgs/pulls + +unbind --mode=normal gp +bind gprn tab_or_tabopen_local www.reddit.com/r/NixOS/ +bind gpd tab_or_tabopen_local discourse.nixos.org/ +bind gpp tab_or_tabopen_local parkour.wien/categories + " Search in page set findcase smart bind / fillcmdline find @@ -77,11 +124,20 @@ set allowautofocus false jsb browser.webRequest.onHeadersReceived.addListener(tri.request.clobberCSP,{urls:[""],types:["main_frame"]},["blocking","responseHeaders"]) " default is 300ms -set hintdelay 100 +set hintdelay 500 " Some pages like github break on the tridactyl quick search. have this as a fallback unbind +" Do not let websites steal sitefocus +set allowautofocus false + +" whitelist sites +" :seturl [URL regex for sites with text editors you use] allowautofocus true + +" stronger blacklist for specific sites +seturl vbc.atlassian.net preventautofocusjackhammer true + " Subconfig Settings seturl www.google.com followpagepatterns.next Next seturl www.google.com followpagepatterns.prev Previous diff --git a/programs/git/.gitmessage b/files/git/.gitmessage similarity index 99% rename from programs/git/.gitmessage rename to files/git/.gitmessage index 5043ffe..4dfc212 100644 --- a/programs/git/.gitmessage +++ b/files/git/.gitmessage @@ -1,4 +1,5 @@ + # max. 50 chars is here: # # [optional scope]: # types: feat, fix, build, chore, ci, docs, style, refactor, perf, test diff --git a/scripts/command-not-found.sh b/files/scripts/command-not-found.sh similarity index 95% rename from scripts/command-not-found.sh rename to files/scripts/command-not-found.sh index 4cd0b87..c81cb7a 100644 --- a/scripts/command-not-found.sh +++ b/files/scripts/command-not-found.sh @@ -6,7 +6,7 @@ command_not_found_handle() { fi echo -n "searching nix-index..." - ATTRS=$(@nix-locate@ --minimal --no-group --type x --type s --top-level --whole-name --at-root "/bin/$1") + ATTRS=$(@nix-locate@ --minimal --no-group --type x --type s --whole-name --at-root "/bin/$1") case $(echo -n "$ATTRS" | grep -c "^") in 0) diff --git a/scripts/devShell/benchmark b/files/scripts/devShell/benchmark similarity index 100% rename from scripts/devShell/benchmark rename to files/scripts/devShell/benchmark diff --git a/scripts/devShell/compile b/files/scripts/devShell/compile similarity index 100% rename from scripts/devShell/compile rename to files/scripts/devShell/compile diff --git a/scripts/e.sh b/files/scripts/e.sh similarity index 100% rename from scripts/e.sh rename to files/scripts/e.sh diff --git a/scripts/fs-diff.sh b/files/scripts/fs-diff.sh similarity index 100% rename from scripts/fs-diff.sh rename to files/scripts/fs-diff.sh diff --git a/scripts/opacitytoggle.sh b/files/scripts/opacitytoggle.sh similarity index 100% rename from scripts/opacitytoggle.sh rename to files/scripts/opacitytoggle.sh diff --git a/scripts/pass-fuzzel.sh b/files/scripts/pass-fuzzel.sh similarity index 100% rename from scripts/pass-fuzzel.sh rename to files/scripts/pass-fuzzel.sh diff --git a/files/scripts/project.sh b/files/scripts/project.sh new file mode 100644 index 0000000..10bff03 --- /dev/null +++ b/files/scripts/project.sh @@ -0,0 +1,7 @@ +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 new file mode 100644 index 0000000..3f95abf --- /dev/null +++ b/files/scripts/quickpass.sh @@ -0,0 +1,12 @@ +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 new file mode 100644 index 0000000..4e616c0 --- /dev/null +++ b/files/scripts/sshrm.sh @@ -0,0 +1,11 @@ +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/scripts/bootstrap.sh b/files/scripts/swarsel-bootstrap.sh similarity index 50% rename from scripts/bootstrap.sh rename to files/scripts/swarsel-bootstrap.sh index b2e01b4..4c4fef3 100644 --- a/scripts/bootstrap.sh +++ b/files/scripts/swarsel-bootstrap.sh @@ -1,29 +1,35 @@ -# highly inspired by https://github.com/EmergentMind/nix-config/blob/dev/scripts/bootstrap-nixos.sh +# 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 NixOS on a target machine using this nix-config." + 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 " --impermanence Use this flag if the target machine has impermanence enabled. WARNING: Assumes /persist path." 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 } @@ -77,14 +83,14 @@ function update_sops_file() { 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 + # 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 - } @@ -99,6 +105,10 @@ while [[ $# -gt 0 ]]; do shift target_destination=$1 ;; + -a) + shift + target_arch=$1 + ;; -u) shift target_user=$1 @@ -107,9 +117,8 @@ while [[ $# -gt 0 ]]; do shift ssh_port=$1 ;; - --temp-override) - shift - temp=$1 + --no-disko-deps) + no_disko_deps="true" ;; --debug) set -x @@ -123,6 +132,60 @@ while [[ $# -gt 0 ]]; do 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" + 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@} @@ -139,6 +202,8 @@ if [ ! -d "$FLAKE" ]; then fi cd "$FLAKE" + +rm install/flake.lock || true git_root=$(git rev-parse --show-toplevel) # ------------------------ green "Wiping known_hosts of $target_destination" @@ -146,33 +211,53 @@ 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/etc/ssh" +install -d -m755 "$temp/$persist_dir/etc/ssh" # Generate host ssh key pair without a passphrase -ssh-keygen -t ed25519 -f "$temp/etc/ssh/ssh_host_ed25519_key" -C root@"$target_hostname" -N "" +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/etc/ssh/ssh_host_ed25519_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 -green "Preparing a temporary password for disko." -green "[Optional] Set disk encryption passphrase:" -read -rs luks_passphrase -if [ -n "$luks_passphrase" ]; then - $ssh_root_cmd "/bin/sh -c 'echo $luks_passphrase > /tmp/disko-password'" -else - $ssh_root_cmd "/bin/sh -c 'echo passphrase > /tmp/disko-password'" +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 + $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_hostname" -$scp_cmd root@"$target_destination":/mnt/etc/nixos/hardware-configuration.nix "${git_root}"/hosts/nixos/"$target_hostname"/hardware-configuration.nix + +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" -SHELL=/bin/sh nix run github:nix-community/nixos-anywhere -- --ssh-port "$ssh_port" --extra-files "$temp" --flake .#"$target_hostname" root@"$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 @@ -187,6 +272,22 @@ while true; do 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=$( @@ -217,16 +318,19 @@ if yes_or_no "Do you want to manually edit .sops.yaml now?"; then fi green "Updating all secrets files to reflect updates .sops.yaml" sops updatekeys --yes --enable-local-keyservice "${git_root}"/secrets/*/secrets.yaml +sops updatekeys --yes --enable-local-keyservice "${git_root}"/hosts/nixos/"$target_arch"/"$target_hostname"/secrets/pii.nix.enc # -------------------------- 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/swarsel/.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 swagit.swarsel.win >> /home/$target_user/.ssh/known_hosts" - $ssh_root_cmd "mkdir -p /root/.ssh/; ssh-keyscan -t ssh-ed25519 gitlab.com github.com swagit.swarsel.win >> /root/.ssh/known_hosts" + $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 # -------------------------- @@ -237,32 +341,51 @@ if yes_or_no "Do you want to copy your full nix-config and nix-secrets to $targe cd "${git_root}" just sync "$target_user" "$target_destination" - if yes_or_no "Do you want to rebuild immediately?"; then - green "Rebuilding nix-config on $target_hostname" - $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}}' > /root/.local/share/nix/trusted-settings.json" - $ssh_cmd -oForwardAgent=yes "cd .dotfiles && sudo nixos-rebuild --show-trace --flake .#$target_hostname switch" + 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 -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 --show-trace --flake .#$target_hostname switch" - # echo "just rebuild" - echo 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_hostname"/hardware-configuration.nix -qe - nixpkgs-fmt hosts/nixos/"$target_hostname"/hardware-configuration.nix - (pre-commit run --all-files 2> /dev/null || true) && - git add "$git_root/hosts/nixos/$target_hostname/hardware-configuration.nix" && + 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 diff --git a/files/scripts/swarsel-displaypower.sh b/files/scripts/swarsel-displaypower.sh new file mode 100644 index 0000000..332f784 --- /dev/null +++ b/files/scripts/swarsel-displaypower.sh @@ -0,0 +1,2 @@ +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 new file mode 100644 index 0000000..537145f --- /dev/null +++ b/files/scripts/swarsel-install.sh @@ -0,0 +1,188 @@ +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/keys/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 new file mode 100644 index 0000000..448d3d8 --- /dev/null +++ b/files/scripts/swarsel-postinstall.sh @@ -0,0 +1,72 @@ +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/scripts/swarsel-rebuild.sh b/files/scripts/swarsel-rebuild.sh similarity index 58% rename from scripts/swarsel-rebuild.sh rename to files/scripts/swarsel-rebuild.sh index 601297c..0a725a1 100644 --- a/scripts/swarsel-rebuild.sh +++ b/files/scripts/swarsel-rebuild.sh @@ -1,19 +1,21 @@ set -eo pipefail -target_flake="chaostheatre" +target_config="hotel" +target_arch="" target_user="swarsel" function help_and_exit() { echo - echo "Remotely installs NixOS on a target machine using this nix-config." + echo "Builds SwarselSystem configuration." echo echo "USAGE: $0 [OPTIONS]" echo echo "ARGS:" - echo " -f specify flake to deploy the nixos config of." - echo " Default: chaostheatre" + 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 } @@ -39,9 +41,13 @@ function yellow() { while [[ $# -gt 0 ]]; do case "$1" in - -f) + -n) shift - target_flake=$1 + target_config=$1 + ;; + -a) + shift + target_arch=$1 ;; -u) shift @@ -56,6 +62,11 @@ while [[ $# -gt 0 ]]; do 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 @@ -67,7 +78,7 @@ else fi local_keys=$(ssh-add -L || true) -pub_key=$(cat /home/"$target_user"/.dotfiles/secrets/keys/ssh/nbl-imba-2.pub) +pub_key=$(cat /home/"$target_user"/.dotfiles/secrets/keys/ssh/yubikey.pub) read -ra pub_arr <<< "$pub_key" cd .dotfiles @@ -75,13 +86,25 @@ 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 - git add 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_flake"/ -git add /home/"$target_user"/.dotfiles/hosts/nixos/"$target_flake"/hardware-configuration.nix +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_flake" -sudo nixos-rebuild --show-trace --flake .#"$target_flake" boot +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-niri.sh b/files/scripts/swarselcheck-niri.sh new file mode 100644 index 0000000..6bfb966 --- /dev/null +++ b/files/scripts/swarselcheck-niri.sh @@ -0,0 +1,36 @@ +while :; do + case ${1:-} in + -k | --kitty) + cmd=(sh -c 'kitty --app-id kittyterm -T kittyterm -o confirm_os_window_close=0 zellij attach --create kittyterm' '&') + searchapp="kittyterm" + ;; + -e | --element) + cmd=(element-desktop) + searchapp="Element" + ;; + -d | --vesktop) + cmd=(vesktop) + searchapp="vesktop" + ;; + -s | --spotifyplayer) + cmd=(sh -c 'kitty --add-id spotifytui -T spotifytui -o confirm_os_window_close=0 spotify_player' '&') + searchapp="spotifytui" + ;; + *) break ;; + esac + shift +done + +WIN_INFO=$(niri msg -j windows | jq --arg search "$searchapp" '.[] | select (.app_id | test($search)) | { id, is_focused, workspace_id }') +ID=$(echo "$WIN_INFO" | jq -r '.id // empty') +IS_FOCUSED=$(echo "$WIN_INFO" | jq -r '.is_focused // empty') +TARGET_MONITOR=$(niri msg -j workspaces | jq --arg search "" '.[] | select (.name != null and (.name | test($search))) | { output }' | jq -r '.output // empty') +CURRENT_WORKSPACE=$(niri msg -j workspaces | jq -r '.[] | select (.is_active == true) | .output // empty') + +if [ -z "$ID" ]; then + niri msg action spawn -- "${cmd[@]}" +elif [ "$IS_FOCUSED" ]; then + niri msg action move-window-to-workspace "" --window-id "$ID" --focus false +else + niri msg action focus-monitor "$TARGET_MONITOR" && niri msg action move-window-to-workspace "$CURRENT_WORKSPACE" --window-id "$ID" && niri msg action focus-floating +fi diff --git a/scripts/swarselcheck.sh b/files/scripts/swarselcheck.sh similarity index 88% rename from scripts/swarselcheck.sh rename to files/scripts/swarselcheck.sh index 4b54418..b581068 100644 --- a/scripts/swarselcheck.sh +++ b/files/scripts/swarselcheck.sh @@ -25,7 +25,7 @@ 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 -T kittyterm & + exec kitty --app-id kittyterm -T kittyterm -o confirm_os_window_close=0 zellij attach --create kittyterm & sleep 1 fi if [ "$STR" == "" ]; then @@ -51,7 +51,7 @@ 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 -T spotifytui -o confirm_os_window_close=0 spotify_player & + exec kitty --add-id spotifytui -T spotifytui -o confirm_os_window_close=0 spotify_player & sleep 1 fi if [ "$STR" == "" ]; then diff --git a/files/scripts/swarselzellij.sh b/files/scripts/swarselzellij.sh new file mode 100644 index 0000000..24a1ac6 --- /dev/null +++ b/files/scripts/swarselzellij.sh @@ -0,0 +1,8 @@ +# 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/scripts/waybarupdate.sh b/files/scripts/waybarupdate.sh similarity index 100% rename from scripts/waybarupdate.sh rename to files/scripts/waybarupdate.sh diff --git a/files/stylix/swarsel.yaml b/files/stylix/swarsel.yaml new file mode 100644 index 0000000..155b93e --- /dev/null +++ b/files/stylix/swarsel.yaml @@ -0,0 +1,53 @@ +# scheme: "better-contrast" +author: "Swarsel" +author: "Swarsel" +base00: "1d252c" #1d252c" +base01: "171d23" #171d23" +base02: "206a86" #206a86" +base03: "003a66" #003a66" +base04: "5ec4ff" #5ec4ff" +base05: "a0b3c5" #a0b3c5" +base06: "7ed4ff" #7ed4ff" +base07: "8ef4ff" #8ef4ff" +base08: "d95468" #d95468" +base09: "ffa880" #ffa880" +base0A: "6ed4ff" #6ed4ff" +base0B: "8bd49c" #8bd49c" +base0C: "008b94" #008b94" +base0D: "5ec4ff" #5ec4ff" +base0E: "c06ece" #c06ece" +base0F: "3c0044" #3c0044" + +# base00: "1D252C" # #1d252c passt +# base01: "171D23" # #171d23 +# base02: "5EC4FF" # #5EC4FF +# base03: "566C7D" # #566C7D passt +# base04: "5EC4FF" # #5EC4FF passt +# base05: "A0B3C5" # #A0B3C5 passt +# base06: "C06ECE" # #C06ECE passt +# base07: "A0B3C5" # #A0B3C5 passt +# base08: "D95468" # #D95468 passt +# base09: "FFA880" # #ffA880 passt +# base0A: "5EC4FF" # #5EC4FF +# base0B: "8BD49C" # #8BD49C +# base0C: "008B94" # #008B94 passt +# base0D: "5EC4FF" # #5EC4FF passt +# base0E: "C06ECE" # #C06ECE passt +# base0F: "5EC4FF" # #5EC4FF passt + +# base00 - Default Background +# base01 - Lighter Background (Used for status bars) +# base02 - Selection Background +# base03 - Comments, Invisibles, Line Highlighting +# base04 - Dark Foreground (Used for status bars) +# base05 - Default Foreground, Caret, Delimiters, Operators +# base06 - Light Foreground (Not often used) +# base07 - Light Background (Not often used) +# base08 - Variables, XML Tags, Markup Link Text, Markup Lists, Diff Deleted +# base09 - Integers, Boolean, Constants, XML Attributes, Markup Link Url +# base0A - Classes, Markup Bold, Search Text Background +# base0B - Strings, Inherited Class, Markup Code, Diff Inserted +# base0C - Support, Regular Expressions, Escape Characters, Markup Quotes +# base0D - Functions, Methods, Attribute IDs, Headings +# base0E - Keywords, Storage, Selector, Markup Italic, Diff Changed +# base0F - Deprecated, Opening/Closing Embedded Language Tags, e.g. diff --git a/files/swayidle/config b/files/swayidle/config new file mode 100644 index 0000000..186eaf2 --- /dev/null +++ b/files/swayidle/config @@ -0,0 +1,3 @@ +timeout 300 'swaylock -f --screenshots --clock --effect-blur 7x5 --effect-vignette 0.5:0.5 --fade-in 0.2' +timeout 600 'swaymsg "output * dpms off"' resume 'swaymsg "output * dpms on"' +before-sleep 'swaylock -f --screenshots --clock --effect-blur 7x5 --effect-vignette 0.5:0.5 --fade-in 0.2' diff --git a/files/templates/cpp/.envrc b/files/templates/cpp/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/files/templates/cpp/.envrc @@ -0,0 +1 @@ +use flake diff --git a/files/templates/cpp/.gitignore b/files/templates/cpp/.gitignore new file mode 100644 index 0000000..11c7643 --- /dev/null +++ b/files/templates/cpp/.gitignore @@ -0,0 +1,12 @@ +CMakeLists.txt.user +CMakeCache.txt +CMakeFiles +CMakeScripts +Testing +Makefile +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake +_deps +CMakeUserPresets.json diff --git a/files/templates/cpp/CMakeLists.txt b/files/templates/cpp/CMakeLists.txt new file mode 100644 index 0000000..538be9a --- /dev/null +++ b/files/templates/cpp/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 3.20) + +project(name) + +set(CMAKE_CXX_STANDARD 23) + +add_subdirectory(src) + +install(TARGETS name DESTINATION bin) diff --git a/files/templates/cpp/flake.nix b/files/templates/cpp/flake.nix new file mode 100644 index 0000000..8a662ab --- /dev/null +++ b/files/templates/cpp/flake.nix @@ -0,0 +1,62 @@ +# heavily inspired by https://github.com/nulladmin1/nix-flake-templates/blob/main/cpp-cmake/flake.nix +{ + description = "C++ Flake"; + + inputs = { + nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; + systems.url = "github:nix-systems/default"; + }; + + outputs = + { self + , nixpkgs + , systems + , ... + }: + let + forEachSystem = nixpkgs.lib.genAttrs (import systems); + pkgsFor = forEachSystem (system: import nixpkgs { inherit system; }); + + pname = "name"; + in + { + formatter = forEachSystem (system: pkgsFor.${system}.nixpgks-fmt); + + devShells = forEachSystem (system: { + default = pkgsFor.${system}.mkShell { + packages = with pkgsFor.${system}; [ + libllvm + cmake + gtest + cppcheck + valgrind + doxygen + clang-tools + # cudatoolkit + ]; + }; + }); + + packages = forEachSystem (system: { + default = pkgsFor.${system}.stdenv.mkDerivation { + inherit pname; + version = "0.1.0"; + src = ./.; + + nativeBuildInputs = with pkgsFor.${system}; [ + cmake + ]; + buildInputs = with pkgsFor.${system}; [ + gtest + ]; + }; + }); + + apps = forEachSystem (system: { + default = { + type = "app"; + program = "${self.packages.${system}.default}/bin/${pname}"; + }; + }); + }; +} diff --git a/files/templates/cpp/src/CMakeLists.txt b/files/templates/cpp/src/CMakeLists.txt new file mode 100644 index 0000000..841969c --- /dev/null +++ b/files/templates/cpp/src/CMakeLists.txt @@ -0,0 +1 @@ +add_executable(name name.cpp name.cpp) diff --git a/files/templates/cpp/src/name.cpp b/files/templates/cpp/src/name.cpp new file mode 100644 index 0000000..3fa18c5 --- /dev/null +++ b/files/templates/cpp/src/name.cpp @@ -0,0 +1,7 @@ +#include +using namespace std; + +int main() { + cout << "Hello, world!" << endl; + return 0; +} diff --git a/files/templates/default/.envrc b/files/templates/default/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/files/templates/default/.envrc @@ -0,0 +1 @@ +use flake diff --git a/files/templates/default/flake.nix b/files/templates/default/flake.nix new file mode 100644 index 0000000..a37b7b5 --- /dev/null +++ b/files/templates/default/flake.nix @@ -0,0 +1,30 @@ +{ + description = "General purpose Flake"; + + inputs = { + nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; + systems.url = "github:nix-systems/default"; + }; + + outputs = + { nixpkgs + , systems + , ... + }: + let + forEachSystem = nixpkgs.lib.genAttrs (import systems); + pkgsFor = forEachSystem (system: import nixpkgs { inherit system; }); + in + { + formatter = forEachSystem (system: pkgsFor.${system}.nixpkgs-fmt); + + devShells = forEachSystem (system: { + default = pkgsFor.${system}.mkShell { + packages = with pkgsFor.${system}; [ + + ]; + }; + }); + + }; +} diff --git a/files/templates/go/.envrc b/files/templates/go/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/files/templates/go/.envrc @@ -0,0 +1 @@ +use flake diff --git a/files/templates/go/flake.nix b/files/templates/go/flake.nix new file mode 100644 index 0000000..c1b2888 --- /dev/null +++ b/files/templates/go/flake.nix @@ -0,0 +1,52 @@ +# heavily inspired by https://github.com/nulladmin1/nix-flake-templates/blob/main/go-nix/flake.nix +{ + description = "Go Flake"; + + inputs = { + nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; + systems.url = "github:nix-systems/default"; + }; + + outputs = + { self + , nixpkgs + , systems + , ... + }: + let + forEachSystem = nixpkgs.lib.genAttrs (import systems); + pkgsFor = forEachSystem (system: import nixpkgs { inherit system; }); + + pname = "name"; + in + { + formatter = forEachSystem (system: pkgsFor.${system}.nixpkgs-fmt); + + devShells = forEachSystem (system: { + default = pkgsFor.${system}.mkShell { + packages = with pkgsFor.${system}; [ + go + gopls + go-tools + gotools + ]; + }; + }); + + packages = forEachSystem (system: { + default = pkgsFor.${system}.buildGoModule { + inherit pname; + version = "0.1.0"; + src = ./.; + vendorHash = null; + }; + }); + + apps = forEachSystem (system: { + default = { + type = "app"; + program = "${self.packages.${system}.default}/bin/${pname}"; + }; + }); + }; +} diff --git a/files/templates/go/go.mod b/files/templates/go/go.mod new file mode 100644 index 0000000..5840ae0 --- /dev/null +++ b/files/templates/go/go.mod @@ -0,0 +1,3 @@ +module name + +go 1.22.7 diff --git a/files/templates/go/name/name.go b/files/templates/go/name/name.go new file mode 100644 index 0000000..2ca0d5e --- /dev/null +++ b/files/templates/go/name/name.go @@ -0,0 +1,9 @@ +package main + +import ( + "fmt" +) + +func main() { + fmt.Println("Hello, World!") +} diff --git a/files/templates/hosts/nixos/default.nix b/files/templates/hosts/nixos/default.nix new file mode 100644 index 0000000..cc96eeb --- /dev/null +++ b/files/templates/hosts/nixos/default.nix @@ -0,0 +1,61 @@ +{ self, config, inputs, pkgs, lib, ... }: +let + primaryUser = config.swarselsystems.mainUser; + modulesPath = "${self}/modules"; + sharedOptions = { + isBtrfs = true; + }; +in +{ + + imports = [ + # ---- nixos-hardware here ---- + + ./hardware-configuration.nix + ./disk-config.nix + + "${modulesPath}/nixos/optional/virtualbox.nix" + # "${modulesPath}/nixos/optional/vmware.nix" + "${modulesPath}/nixos/optional/autologin.nix" + "${modulesPath}/nixos/optional/nswitch-rcm.nix" + "${modulesPath}/nixos/optional/gaming.nix" + + inputs.home-manager.nixosModules.home-manager + { + home-manager.users."${primaryUser}".imports = [ + "${modulesPath}/home/optional/gaming.nix" + ]; + } + ]; + + boot = { + kernelPackages = lib.mkDefault pkgs.linuxPackages_latest; + }; + + networking = { + hostName = "TEMPLATE"; + firewall.enable = true; + }; + + swarselsystems = lib.recursiveUpdate + { + wallpaper = self + /files/wallpaper/lenovowp.png; + hasBluetooth = true; + hasFingerprint = true; + isImpermanence = true; + isSecureBoot = true; + isCrypted = true; + isSwap = true; + swapSize = "32G"; + rootDisk = "TEMPLATE"; + } + sharedOptions; + + home-manager.users."${primaryUser}".swarselsystems = lib.recursiveUpdate + { + isLaptop = true; + isNixos = true; + cpuCount = 16; + } + sharedOptions; +} diff --git a/files/templates/hosts/nixos/disk-config.nix b/files/templates/hosts/nixos/disk-config.nix new file mode 100644 index 0000000..3dbabf8 --- /dev/null +++ b/files/templates/hosts/nixos/disk-config.nix @@ -0,0 +1,122 @@ +{ lib, pkgs, config, ... }: +let + type = "btrfs"; + extraArgs = [ "-L" "nixos" "-f" ]; # force overwrite + subvolumes = { + "/root" = { + mountpoint = "/"; + mountOptions = [ + "subvol=root" + "compress=zstd" + "noatime" + ]; + }; + "/home" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/home"; + mountOptions = [ + "subvol=home" + "compress=zstd" + "noatime" + ]; + }; + "/persist" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/persist"; + mountOptions = [ + "subvol=persist" + "compress=zstd" + "noatime" + ]; + }; + "/log" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/var/log"; + mountOptions = [ + "subvol=log" + "compress=zstd" + "noatime" + ]; + }; + "/nix" = { + mountpoint = "/nix"; + mountOptions = [ + "subvol=nix" + "compress=zstd" + "noatime" + ]; + }; + "/swap" = lib.mkIf config.swarselsystems.isSwap { + mountpoint = "/.swapvol"; + swap.swapfile.size = config.swarselsystems.swapSize; + }; + }; +in +{ + disko.devices = { + disk = { + disk0 = { + type = "disk"; + device = config.swarselsystems.rootDisk; + content = { + type = "gpt"; + partitions = { + ESP = { + priority = 1; + name = "ESP"; + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "defaults" ]; + }; + }; + root = lib.mkIf (!config.swarselsystems.isCrypted) { + size = "100%"; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/disk/by-label/nixos" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + luks = lib.mkIf config.swarselsystems.isCrypted { + size = "100%"; + content = { + type = "luks"; + name = "cryptroot"; + passwordFile = "/tmp/disko-password"; # this is populated by bootstrap.sh + settings = { + allowDiscards = true; + # https://github.com/hmajid2301/dotfiles/blob/a0b511c79b11d9b4afe2a5e2b7eedb2af23e288f/systems/x86_64-linux/framework/disks.nix#L36 + crypttabExtraOpts = [ + "fido2-device=auto" + "token-timeout=10" + ]; + }; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/mapper/cryptroot" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + }; + }; + }; + }; + }; + }; + + fileSystems."/persist".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + fileSystems."/home".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + + environment.systemPackages = [ + pkgs.yubikey-manager + ]; +} diff --git a/files/templates/latex/.envrc b/files/templates/latex/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/files/templates/latex/.envrc @@ -0,0 +1 @@ +use flake diff --git a/files/templates/latex/.gitignore b/files/templates/latex/.gitignore new file mode 100644 index 0000000..953a4ca --- /dev/null +++ b/files/templates/latex/.gitignore @@ -0,0 +1,292 @@ +# nix build output +result + +## PDF output (but not in figures/) +*.pdf +!figures/*.pdf +!figures/**/*.pdf + +## Core latex/pdflatex auxiliary files: +*.aux +*.lof +*.log +*.lot +*.fls +*.out +*.toc +*.fmt +*.fot +*.cb +*.cb2 +.*.lb + +## Intermediate documents: +*.dvi +*.xdv +*-converted-to.* +# these rules might exclude image files for figures etc. +# *.ps +# *.eps +# *.pdf + +## Generated if empty string is given at "Please type another file name for output:" +.pdf + +## Bibliography auxiliary files (bibtex/biblatex/biber): +*.bbl +*.bcf +*.blg +*-blx.aux +*-blx.bib +*.run.xml + +## Build tool auxiliary files: +*.fdb_latexmk +*.synctex +*.synctex(busy) +*.synctex.gz +*.synctex.gz(busy) +*.pdfsync + +## Build tool directories for auxiliary files +# latexrun +latex.out/ + +## Auxiliary and intermediate files from other packages: +# algorithms +*.alg +*.loa + +# achemso +acs-*.bib + +# amsthm +*.thm + +# beamer +*.nav +*.pre +*.snm +*.vrb + +# changes +*.soc + +# comment +*.cut + +# cprotect +*.cpt + +# elsarticle (documentclass of Elsevier journals) +*.spl + +# endnotes +*.ent + +# fixme +*.lox + +# feynmf/feynmp +*.mf +*.mp +*.t[1-9] +*.t[1-9][0-9] +*.tfm + +#(r)(e)ledmac/(r)(e)ledpar +*.end +*.?end +*.[1-9] +*.[1-9][0-9] +*.[1-9][0-9][0-9] +*.[1-9]R +*.[1-9][0-9]R +*.[1-9][0-9][0-9]R +*.eledsec[1-9] +*.eledsec[1-9]R +*.eledsec[1-9][0-9] +*.eledsec[1-9][0-9]R +*.eledsec[1-9][0-9][0-9] +*.eledsec[1-9][0-9][0-9]R + +# glossaries +*.acn +*.acr +*.glg +*.glo +*.gls +*.glsdefs +*.lzo +*.lzs + +# uncomment this for glossaries-extra (will ignore makeindex's style files!) +# *.ist + +# gnuplottex +*-gnuplottex-* + +# gregoriotex +*.gaux +*.gtex + +# htlatex +*.4ct +*.4tc +*.idv +*.lg +*.trc +*.xref + +# hyperref +*.brf + +# knitr +*-concordance.tex +# TODO Uncomment the next line if you use knitr and want to ignore its generated tikz files +# *.tikz +*-tikzDictionary + +# listings +*.lol + +# luatexja-ruby +*.ltjruby + +# makeidx +*.idx +*.ilg +*.ind + +# minitoc +*.maf +*.mlf +*.mlt +*.mtc[0-9]* +*.slf[0-9]* +*.slt[0-9]* +*.stc[0-9]* + +# minted +_minted* +*.pyg + +# morewrites +*.mw + +# nomencl +*.nlg +*.nlo +*.nls + +# pax +*.pax + +# pdfpcnotes +*.pdfpc + +# sagetex +*.sagetex.sage +*.sagetex.py +*.sagetex.scmd + +# scrwfile +*.wrt + +# sympy +*.sout +*.sympy +sympy-plots-for-*.tex/ + +# pdfcomment +*.upa +*.upb + +# pythontex +*.pytxcode +pythontex-files-*/ + +# tcolorbox +*.listing + +# thmtools +*.loe + +# TikZ & PGF +*.dpth +*.md5 +*.auxlock + +# todonotes +*.tdo + +# vhistory +*.hst +*.ver + +# easy-todo +*.lod + +# xcolor +*.xcp + +# xmpincl +*.xmpi + +# xindy +*.xdy + +# xypic precompiled matrices and outlines +*.xyc +*.xyd + +# endfloat +*.ttt +*.fff + +# Latexian +TSWLatexianTemp* + +## Editors: +# WinEdt +*.bak +*.sav + +# Texpad +.texpadtmp + +# LyX +*.lyx~ + +# Kile +*.backup + +# gummi +.*.swp + +# KBibTeX +*~[0-9]* + +# TeXnicCenter +*.tps + +# auto folder when using emacs and auctex +./auto/* +*.el + +# expex forward references with \gathertags +*-tags.tex + +# standalone packages +*.sta + +# Makeindex log files +*.lpz + +# xwatermark package +*.xwm + +# REVTeX puts footnotes in the bibliography by default, unless the nofootinbib +# option is specified. Footnotes are the stored in a file with suffix Notes.bib. +# Uncomment the next line to have this generated file ignored. +#*Notes.bib diff --git a/files/templates/latex/.latexmkrc b/files/templates/latex/.latexmkrc new file mode 100644 index 0000000..5f227c1 --- /dev/null +++ b/files/templates/latex/.latexmkrc @@ -0,0 +1,3 @@ +$pdf_mode = 4; +@default_files = ('000-main.tex'); +$lualatex = "lualatex %O -shell-escape %S"; diff --git a/files/templates/latex/000-main.tex b/files/templates/latex/000-main.tex new file mode 100644 index 0000000..5f4d7f3 --- /dev/null +++ b/files/templates/latex/000-main.tex @@ -0,0 +1,75 @@ +%! TEX root = **/000-main.tex +% vim: spell spelllang=en: + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% PREAMBLE +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\input{001-preamble} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% EXTRA PACKAGES / CONFIG +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% METADATA +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% remove when using \maketitle: +\renewcommand\and{\\[\baselineskip]} + +\title{My title \\ \Large \normalfont My Subtitle} +\author{First Author \and Second Author} +\date{\today} + +\begin{document} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% TITLE +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + % Default title or use titlepage.tex + + %\maketitle + \include{005-titlepage} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% TOC & lists +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + \pagenumbering{Roman} + + %\setcounter{tocdepth}{2} + \tableofcontents \pagebreak + + \listoffigures \pagebreak + \listoftables \clearpage + + \pagenumbering{arabic} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SECTIONS +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + % Paragraph spacing (placed after ToC) + \setlength{\parskip}{1em plus 0.5em minus 0.2em} + %\setlength{\parindent}{0pt} + + \include{010-introduction} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% BIBLIO +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + \printbibliography[heading=bibintoc] + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% APPENDIX +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + % uncomment to add appendix section prefix to numbering + %\appendixpagenumbering + + \appendix + + \include{990-appendix} + +\end{document} diff --git a/files/templates/latex/001-preamble.tex b/files/templates/latex/001-preamble.tex new file mode 100644 index 0000000..4f72f3f --- /dev/null +++ b/files/templates/latex/001-preamble.tex @@ -0,0 +1,204 @@ +%! TEX root = **/000-main.tex +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LaTeX preamble, load in main.tex with: \input{preamble} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\documentclass[12pt, oneside]{article} +\usepackage[a4paper, left=2.5cm, right=2.5cm, top=2.5cm, bottom=2.5cm]{geometry} + +% for debugging overfulls +%\documentclass[draft, 12pt, oneside]{article} +%\usepackage[showframe, a4paper, left=2.5cm, right=2.5cm, top=2.5cm, bottom=2.5cm]{geometry} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% FONTS +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\usepackage[T1]{fontenc} +\usepackage{fontspec} +\usepackage{microtype} + +\setmonofont[Scale=MatchLowercase]{DejaVu Sans Mono} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LANGUAGE +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\usepackage{polyglossia} +\setdefaultlanguage{english} +\setotherlanguages{spanish,catalan} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% BIBLIOGRAPHY +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\usepackage[ + backend=biber, + style=numeric, +]{biblatex} +\DeclareNameAlias{default}{family-given} + +\addbibresource{biblio.bib} + +\usepackage{fvextra} % Req by minted (must load before csquotes) +\usepackage{csquotes} % For bibliography quotations +\DeclareQuoteAlias{spanish}{catalan} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% COMMON +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\usepackage{color, xcolor} % more colors + +\usepackage{graphicx} % graphics +\graphicspath{{./figures/}} + +\usepackage{comment} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% MATHS +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\usepackage{mathtools} % amsmath + more +\usepackage{amsthm} % Theorem enviroment +\usepackage{amssymb} % More symbols +\usepackage{amstext} % Text inside mathenv + +%\usepackage{relsize} % Bigger math with mathlarger{___} +%\usepackage{nicefrac} % nice fractions in one line + +%\usepackage{IEEEtrantools} % Complex equation arrays + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% REFERENCES (load order is important) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\usepackage{varioref} % reference far away (1) +\usepackage[colorlinks = true]{hyperref} % links in references (2) +\usepackage{cleveref} % smart references (3) +%hyperref configuration so that it doesn't contrast so much colorlinks, +\hypersetup{ + linkcolor={black}, + citecolor={black}, + %linkcolor={red!50!black}, + %citecolor={blue!50!black}, + urlcolor={blue!80!black} +} + +\usepackage[bottom]{footmisc} % Footnotes at bottom of page + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% FIGURES +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%\usepackage[export]{adjustbox} % Adjust table size +\usepackage{float} % Force tables and images position (H and H!) +%\usepackage{wrapfig} % Wrap images like in HTML + +\usepackage[justification=centering]{caption} +%\usepackage{subcaption} % Subfigures +%\usepackage[framemethod=tikz]{mdframed} % Custom frames + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TABLES +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%\usepackage{colortbl, booktabs} % Better tables +%\usepackage{tabularx} +%\usepackage{longtable} % Multiple page table (does not work with tabularx) +\usepackage{xltabular, colortbl, booktabs} % longtable + tabularx (has bug with booktabs: fix below) + +% Split cell in lines and more formating options inside table +\usepackage{array, multirow, multicol, makecell} + +%%% +% bug fix for booktabs + xltabular incompatibility +\makeatletter +\def\@BTrule[#1]{% + \ifx\longtable\undefined + \let\@BTswitch\@BTnormal + \else\ifx\hline\LT@hline + \nobreak + \let\@BTswitch\@BLTrule + \else + \let\@BTswitch\@BTnormal + \fi\fi + \global\@thisrulewidth=#1\relax + \ifnum\@thisruleclass=\tw@\vskip\@aboverulesep\else + \ifnum\@lastruleclass=\z@\vskip\@aboverulesep\else + \ifnum\@lastruleclass=\@ne\vskip\doublerulesep\fi\fi\fi + \@BTswitch} +\makeatother +%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% SIUNITX +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%\usepackage[alsoload=hep]{siunitx} % SI units and uncertainties +%\sisetup{locale = FR} % Commas and so on for spanish +%\sisetup{separate-uncertainty=true} +%\sisetup{ + %per-mode=fraction, + %fraction-function=\nicefrac +%} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TIKZ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%\usepackage{tikz} +%\usetikzlibrary{arrows} +%\usetikzlibrary{scopes} +%\usetikzlibrary{babel} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% MINTED +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\usepackage{minted} +\definecolor{codeBg}{HTML}{FFFDE7} +\setminted{ + %style=pastie, + frame=lines, + framesep=3mm, + linenos, + breaklines=true, + encoding=utf8, + fontsize=\footnotesize, + bgcolor=codeBg +} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% CUSTOM COMMANDS +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% empty whitepage without numbering +\newcommand{\whitepage}{ + \clearpage\thispagestyle{empty}\addtocounter{page}{-1} \newpage \clearpage +} + +% Add command before appendix section for page numbering: A-1 +\newcommand{\appendixpagenumbering}{ + \break + \pagenumbering{arabic} + \renewcommand{\thepage}{\thesection-\arabic{page}} +} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% CUSTOM MATH OPERATORS (functions not in italic in math mode) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%\DeclareMathOperator{\arcsec}{arcsec} +%\DeclareMathOperator{\arccot}{arccot} +%\DeclareMathOperator{\arccsc}{arccsc} +%\DeclareMathOperator{\cis}{cis} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% MISC +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%\usepackage{datetime} % Customize date +%% \monthyeardate\today gives the date without the day +%\newdateformat{monthyeardate}{% + %\monthname[\THEMONTH], \THEYEAR} diff --git a/files/templates/latex/005-titlepage.tex b/files/templates/latex/005-titlepage.tex new file mode 100644 index 0000000..f9022a7 --- /dev/null +++ b/files/templates/latex/005-titlepage.tex @@ -0,0 +1,28 @@ +%! TEX root = **/000-main.tex +% vim: spell spelllang=en: + +\thispagestyle{empty} +\clearpage +\setcounter{page}{-1} + +\makeatletter +\begin{titlepage} +{ + \centering + \includegraphics[width=0.9\textwidth]{institution-logo} + \null% + \vspace{3em} + {\Huge \bfseries \@title \par} + \vspace{2em} + {\large \scshape \@date \par} + \vfill +\begin{center} + % Supplementary image +\end{center} + \vspace{5em} + + \vfill + {\raggedleft \large \@author \par} +} +\end{titlepage} +\makeatother diff --git a/files/templates/latex/010-introduction.tex b/files/templates/latex/010-introduction.tex new file mode 100644 index 0000000..6e4fd4e --- /dev/null +++ b/files/templates/latex/010-introduction.tex @@ -0,0 +1,39 @@ +%! TEX root = **/000-main.tex +% vim: spell spelllang=en: + +\section{Introduction}% +\label{sec:introduction} + +\(E = mc^2\) \cite{einstein} + +\begin{figure}[H] + \centering + \includegraphics[width=0.3\linewidth]{Professortocat_v2} + \caption{Professor OctoCat}% + \label{fig:profocto} +\end{figure} + +As we can see in \cref{fig:profocto}, the professor is holding an apple. + +\begin{table}[H] + \begin{center} + \caption{Table captions go on top of the tables}% + \label{tab:example} + \begin{tabular}{ccc} + \toprule + a & b & c \\ + \midrule + 0 & 2 & 4 \\ + \bottomrule + \end{tabular} + \end{center} +\end{table} + +\subsection{Lorem ipsum}% +\label{sub:lorem_ipsum} + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ultricies est sit amet interdum ornare. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut nulla lectus, bibendum ultrices dui quis, sodales suscipit quam. Donec eu finibus lectus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Etiam eu metus mattis, bibendum massa quis, eleifend libero. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nunc lacinia ipsum at dolor tristique convallis. Sed dignissim malesuada nunc, nec malesuada risus sagittis eu. Nulla et erat et mi elementum scelerisque vitae at neque. Suspendisse scelerisque laoreet tellus, sit amet accumsan mauris placerat nec. Vestibulum mollis augue a odio posuere, ut gravida est lacinia. Etiam turpis ligula, molestie nec porta in, malesuada id magna. Donec elementum nulla ac tincidunt fringilla. Suspendisse porta laoreet nisl, non aliquam orci dictum egestas. + +Proin euismod consequat felis ut pharetra. Maecenas auctor, nunc ac gravida pretium, metus mi fringilla lectus, auctor scelerisque nunc velit id magna. Etiam sit amet mi sit amet nunc congue ornare non hendrerit diam. Nullam consectetur lectus quis urna vehicula, nec lacinia tortor rhoncus. Vestibulum at enim aliquam, ultricies urna sit amet, porta tellus. Curabitur posuere elit orci, et rutrum nibh cursus eget. Donec ac venenatis purus. Fusce vehicula nisi erat, at tempor turpis congue vitae. Nunc auctor pellentesque malesuada. Nunc sodales, dolor ac sagittis mollis, enim ipsum mollis sem, non porttitor arcu nulla at velit. Ut non velit nec lacus sollicitudin maximus id id tortor. Sed ac aliquam lorem. + +Nunc non ante ex. Curabitur lacinia euismod velit, non posuere leo bibendum non. Mauris ac orci non risus feugiat rutrum eu ac velit. Phasellus facilisis lacinia condimentum. Pellentesque vulputate nibh urna, vel varius mauris cursus quis. Aliquam vitae sem ac orci fermentum semper. Praesent est tellus, luctus sed venenatis at, bibendum id purus. Cras at mi sed lorem aliquet congue at sit amet turpis. Aliquam vestibulum tempor mauris, id aliquam ipsum scelerisque ut. In arcu turpis, dapibus ut nisi vel, luctus pellentesque felis. Aenean nisi erat, porttitor eu felis ut, imperdiet aliquam velit. Mauris vitae vehicula leo. Curabitur ut ante et ante pulvinar gravida. Donec tincidunt fringilla erat. Vivamus cursus augue et odio pharetra hendrerit. diff --git a/files/templates/latex/990-appendix.tex b/files/templates/latex/990-appendix.tex new file mode 100644 index 0000000..1e90572 --- /dev/null +++ b/files/templates/latex/990-appendix.tex @@ -0,0 +1,8 @@ +%! TEX root = **/000-main.tex +% vim: spell spelllang=en: + +\section{Appendix} + +Appendix contents + +\inputminted{cpp}{./code/P15601_en_Harrichu_y_and_the_maze.cc} diff --git a/files/templates/latex/biblio.bib b/files/templates/latex/biblio.bib new file mode 100644 index 0000000..053da58 --- /dev/null +++ b/files/templates/latex/biblio.bib @@ -0,0 +1,41 @@ +% vim: spell spelllang=en: + +@article{einstein, + author = "Albert Einstein", + title = "{Zur Elektrodynamik bewegter K{\"o}rper}. ({German}) + [{On} the electrodynamics of moving bodies]", + journal = "Annalen der Physik", + volume = "322", + number = "10", + pages = "891--921", + year = "1905", + DOI = "http://dx.doi.org/10.1002/andp.19053221004", + keywords = "physics" +} + +@book{dirac, + title = {The Principles of Quantum Mechanics}, + author = {Paul Adrien Maurice Dirac}, + isbn = {9780198520115}, + series = {International series of monographs on physics}, + year = {1981}, + publisher = {Clarendon Press}, + keywords = {physics} +} + +@online{knuthwebsite, + author = "Donald Knuth", + title = "Knuth: Computers and Typesetting", + url = "http://www-cs-faculty.stanford.edu/~uno/abcde.html", + addendum = "(accessed: 01.09.2016)", + keywords = "latex,knuth" +} + +@inbook{knuth-fa, + author = "Donald E. Knuth", + title = "Fundamental Algorithms", + publisher = "Addison-Wesley", + year = "1973", + chapter = "1.2", + keywords = "knuth,programming" +} diff --git a/files/templates/latex/build-document.nix b/files/templates/latex/build-document.nix new file mode 100644 index 0000000..b59432f --- /dev/null +++ b/files/templates/latex/build-document.nix @@ -0,0 +1,87 @@ +# Build a reproducible latex document with latexmk, based on: +# https://flyx.org/nix-flakes-latex/ + +{ pkgs + # Document source +, src ? ./. + + # Name of the final pdf file +, name ? "document.pdf" + + # Use -shell-escape +, shellEscape ? false + + # Use minted (requires shellEscape) +, minted ? false + + # Additional flags for latexmk +, extraFlags ? [ ] + + # Do not use the default latexmk flags. Usefull if you have a .latexmkrc or you + # don't want to use lualatex +, dontUseDefaultFlags ? false + + # texlive packages needed to build the document + # you can also include other packages as a list. +, texlive ? pkgs.texlive.combined.scheme-full + + # Pygments package to use (needed for minted) +, pygments ? pkgs.python39Packages.pygments + + # Add system fonts + # you can specify one font directly with: pkgs.fira-code + # of join multiple fonts using symlinJoin: + # pkgs.symlinkJoin { name = "fonts"; paths = with pkgs; [ fira-code souce-code-pro ]; } +, fonts ? null + + # Date for the document in unix time. You can change it + # to "$(date -r . +%s)" , "$(date -d "2022/02/22" +%s)", toString + # self.lastModified +, SOURCE_DATE_EPOCH ? "$(git log -1 --pretty=%ct)" +}: + +let + inherit (pkgs) lib; + defaultFlags = [ + "-interaction=nonstopmode" + "-pdf" + "-lualatex" + "-pretex='\\pdfvariable suppressoptionalinfo 512\\relax'" + "-usepretex" + ]; + flags = lib.concatLists [ + (lib.optional (!dontUseDefaultFlags) defaultFlags) + extraFlags + (lib.optional shellEscape [ "-shell-escape" ]) + ]; +in + +assert minted -> shellEscape; + +pkgs.stdenvNoCC.mkDerivation rec { + inherit src name; + + buildInputs = [ texlive pkgs.git ] ++ + lib.optional minted [ pkgs.which pygments ]; + + TEXMFHOME = "./cache"; + TEXMFVAR = "./cache/var"; + + OSFONTDIR = lib.optionalString (fonts != null) "${fonts}/share/fonts"; + + buildPhase = '' + runHook preBuild + + SOURCE_DATE_EPOCH="${SOURCE_DATE_EPOCH}" latexmk ${toString flags} + + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + + install -m644 -D *.pdf $out/${name} + + runHook postInstall + ''; +} diff --git a/files/templates/latex/code/P15601_en_Harrichu_y_and_the_maze.cc b/files/templates/latex/code/P15601_en_Harrichu_y_and_the_maze.cc new file mode 100644 index 0000000..d1eb718 --- /dev/null +++ b/files/templates/latex/code/P15601_en_Harrichu_y_and_the_maze.cc @@ -0,0 +1,51 @@ +#include +#include +#include +using namespace std; + +struct coord { + int x,y; + coord (int xx=0, int yy=0) : x(xx), y(yy) {} + bool operator== (const coord& p) {return x==p.x and y==p.y;} +} beg, goal; + +int main () { + int n; + cin >> n; + while (n--) { + int r,c; + cin >> r >> c; + vector > v (r, vector (c, 0)); + for (int i = 0; i < r; ++i) + for (int j = 0; j < c; ++j) { + char cc; + cin >> cc; + if (cc=='.') v[i][j]=true; + else if (cc=='b') beg = coord(i,j); + else if (cc=='g') goal = coord(i,j); + } + + v[goal.x][goal.y] = v[beg.x][beg.y]=true; + vector > f (v.size(),vector (v[0].size(),0)); + + queue q; + q.push(beg); + + while (!q.empty()) { + coord p = q.front(); q.pop(); + if (p.x>=v.size() or p.x<0 or p.y >= v[0].size() or p.y<0) continue; + if (!v[p.x][p.y]) continue; + if (f[p.x][p.y]) continue; + + f[p.x][p.y] = true; + if (p==goal) break; + + q.push(coord(p.x+1,p.y)); + q.push(coord(p.x-1,p.y)); + q.push(coord(p.x,p.y+1)); + q.push(coord(p.x,p.y-1)); + } + + cout << (f[goal.x][goal.y]? "Good" : "Bad") << endl; + } +} diff --git a/files/templates/latex/figures/Professortocat_v2.png b/files/templates/latex/figures/Professortocat_v2.png new file mode 100644 index 0000000..1cd01c3 Binary files /dev/null and b/files/templates/latex/figures/Professortocat_v2.png differ diff --git a/files/templates/latex/figures/institution-logo.pdf b/files/templates/latex/figures/institution-logo.pdf new file mode 100644 index 0000000..28fd319 Binary files /dev/null and b/files/templates/latex/figures/institution-logo.pdf differ diff --git a/files/templates/latex/flake.nix b/files/templates/latex/flake.nix new file mode 100644 index 0000000..a83a792 --- /dev/null +++ b/files/templates/latex/flake.nix @@ -0,0 +1,78 @@ +# This template is based on https://github.com/Leixb/latex-template/tree/master +{ + description = "LaTeX Flake"; + + inputs.flake-utils.url = "github:numtide/flake-utils"; + + outputs = { self, nixpkgs, flake-utils }: + { + + lib.latexmk = import ./build-document.nix; + + } // flake-utils.lib.eachDefaultSystem (system: + let + pname = "document"; + + pkgs = import nixpkgs { inherit system; }; + + latex-packages = with pkgs; [ + (texlive.combine { + inherit (texlive) + scheme-medium + framed + titlesec + cleveref + multirow + wrapfig + tabu + threeparttable + threeparttablex + makecell + environ + biblatex + biber + fvextra + upquote + catchfile + xstring + csquotes + minted + dejavu + comment + footmisc + xltabular + ltablex + ; + }) + which + python39Packages.pygments + ]; + + dev-packages = with pkgs; [ + texlab + zathura + wmctrl + ]; + in + rec { + devShell = pkgs.mkShell { + buildInputs = [ latex-packages dev-packages ]; + }; + + formatter = pkgs.nixpkgs-fmt; + + packages = flake-utils.lib.flattenTree { + default = import ./build-document.nix { + inherit pkgs; + name = pname; + texlive = latex-packages; + shellEscape = true; + minted = true; + SOURCE_DATE_EPOCH = toString self.lastModified; + }; + }; + + apps.default = flake-utils.lib.mkApp { drv = "${pkgs.texlivePackages.latexmk}"; exePath = "/bin/latexmk"; }; + } + ); +} diff --git a/files/templates/python/.envrc b/files/templates/python/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/files/templates/python/.envrc @@ -0,0 +1 @@ +use flake diff --git a/files/templates/python/.gitignore b/files/templates/python/.gitignore new file mode 100644 index 0000000..bee8a64 --- /dev/null +++ b/files/templates/python/.gitignore @@ -0,0 +1 @@ +__pycache__ diff --git a/files/templates/python/README.md b/files/templates/python/README.md new file mode 100644 index 0000000..baba212 --- /dev/null +++ b/files/templates/python/README.md @@ -0,0 +1,26 @@ +# Python template using uv2nix + +This template flake provides a python environment that is being managed by `uv` while still keeping the store managed by `nix`. + +## Setup + +1) Enter project directory +2) `project python` +3) Edit Python version in `flake.nix` and Python version + dependencies in `pyproject.toml` +4) `uv lock` +5) `direnv reload` + +## Usage + + + +### Testing + +- run `nix flake check` + +###### Note for Emacs users + +It can happen that Emacs will not immediately pick up on the new environment after you have made your changes. In that case, perform the following steps in Emacs (this is for a setup using `envrc.el` and `eglot`): + +1) `(envrc-reload)` +2) `(eglot)` diff --git a/files/templates/python/flake.nix b/files/templates/python/flake.nix new file mode 100644 index 0000000..6a2bd12 --- /dev/null +++ b/files/templates/python/flake.nix @@ -0,0 +1,199 @@ +# based on https://github.com/pyproject-nix/uv2nix/tree/master/templates/hello-world +{ + description = "Python flake using uv2nix"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + + pyproject-nix = { + url = "github:pyproject-nix/pyproject.nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + uv2nix = { + url = "github:pyproject-nix/uv2nix"; + inputs = { + pyproject-nix.follows = "pyproject-nix"; + nixpkgs.follows = "nixpkgs"; + }; + }; + + pyproject-build-systems = { + url = "github:pyproject-nix/build-system-pkgs"; + inputs = { + pyproject-nix.follows = "pyproject-nix"; + uv2nix.follows = "uv2nix"; + nixpkgs.follows = "nixpkgs"; + }; + }; + }; + + outputs = + { nixpkgs + , uv2nix + , pyproject-nix + , pyproject-build-systems + , ... + }: + let + inherit (nixpkgs) lib; + pname = "name"; + forAllSystems = lib.genAttrs lib.systems.flakeExposed; + + # Load a uv workspace from a workspace root. + # Uv2nix treats all uv projects as workspace projects. + workspace = uv2nix.lib.workspace.loadWorkspace { workspaceRoot = ./.; }; + + overlay = workspace.mkPyprojectOverlay { + # Prefer prebuilt binary wheels as a package source. + # Sdists are less likely to "just work" because of the metadata missing from uv.lock. + # Binary wheels are more likely to, but may still require overrides for library dependencies. + sourcePreference = "wheel"; # or sourcePreference = "sdist"; + # Optionally customise PEP 508 environment + # environ = { + # platform_release = "5.10.65"; + # }; + }; + + + pythonSets = forAllSystems + (system: + let + inherit (pkgs) stdenv; + pkgs = nixpkgs.legacyPackages.${system}; + pyprojectOverrides = final: prev: { + # Implement build fixups here. + ${pname} = prev.${pname}.overrideAttrs (old: { + + passthru = old.passthru // { + # Put all tests in the passthru.tests attribute set. + # Nixpkgs also uses the passthru.tests mechanism for ofborg test discovery. + # + # For usage with Flakes we will refer to the passthru.tests attributes to construct the flake checks attribute set. + tests = + let + + virtualenv = final.mkVirtualEnv "${pname}-pytest-env" { + ${pname} = [ "test" ]; + }; + + in + (old.tests or { }) + // { + pytest = stdenv.mkDerivation { + name = "${final.${pname}.name}-pytest"; + inherit (final.${pname}) src; + nativeBuildInputs = [ + virtualenv + ]; + dontConfigure = true; + + # Because this package is running tests, and not actually building the main package + # the build phase is running the tests. + # + # We also output a HTML coverage report, which is used as the build output. + buildPhase = '' + runHook preBuild + pytest --cov tests --cov-report html + runHook postBuild + ''; + + # Install the HTML coverage report into the build output. + # + # If you wanted to install multiple test output formats such as TAP outputs + # you could make this derivation a multiple-output derivation. + # + # See https://nixos.org/manual/nixpkgs/stable/#chap-multiple-output for more information on multiple outputs. + installPhase = '' + runHook preInstall + mv htmlcov $out + runHook postInstall + ''; + }; + + }; + }; + }); + }; + + baseSet = pkgs.callPackage pyproject-nix.build.packages { + python = pkgs.python312; + }; + in + baseSet.overrideScope + ( + lib.composeManyExtensions [ + pyproject-build-systems.overlays.default + overlay + pyprojectOverrides + ] + )); + + in + { + packages = forAllSystems (system: + let + pythonSet = pythonSets.${system}; + in + { default = pythonSet.mkVirtualEnv "${pname}-env" workspace.deps.default; }); + + devShells = forAllSystems + (system: + let + pythonSet = pythonSets.${system}; + pkgs = nixpkgs.legacyPackages.${system}; + in + { + default = + let + # Create an overlay enabling editable mode for all local dependencies. + editableOverlay = workspace.mkEditablePyprojectOverlay { + # Use environment variable + root = "$REPO_ROOT"; + # Optional: Only enable editable for these packages + # members = [ "hello-world" ]; + }; + + # Override previous set with our overrideable overlay. + editablePythonSet = pythonSet.overrideScope editableOverlay; + + virtualenv = editablePythonSet.mkVirtualEnv "${pname}-dev-env" { + ${pname} = [ "dev" ]; + }; + + in + pkgs.mkShell { + packages = [ + virtualenv + pkgs.uv + ]; + shellHook = '' + # Undo dependency propagation by nixpkgs. + unset PYTHONPATH + + # Don't create venv using uv + export UV_NO_SYNC=1 + + # Prevent uv from downloading managed Python's + export UV_PYTHON_DOWNLOADS=never + + # Get repository root using git. This is expanded at runtime by the editable `.pth` machinery. + export REPO_ROOT=$(git rev-parse --show-toplevel) + ''; + }; + }); + + checks = forAllSystems ( + system: + let + pythonSet = pythonSets.${system}; + in + { + inherit (pythonSet.${pname}.passthru.tests) pytest; + } + ); + + formatter = forAllSystems (system: nixpkgs.legacyPackages.${system}.nixpkgs-fmt); + + }; +} diff --git a/files/templates/python/pyproject.toml b/files/templates/python/pyproject.toml new file mode 100644 index 0000000..907bb71 --- /dev/null +++ b/files/templates/python/pyproject.toml @@ -0,0 +1,32 @@ +[project] +name = "name" +version = "0.1.0" +description = "Add your description here" +readme = "README.md" +requires-python = ">=3.12" +dependencies = [ +] + +[project.scripts] +hello = "name:hello" + +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[dependency-groups] +dev = [ + {include-group = "test"}, + {include-group = "lint"}, + {include-group = "lsp"}, +] +lsp = [ + "python-lsp-server", +] +lint = [ + "ruff>=0.6.7", +] +test = [ + "pytest-cov>=6.0.0", + "pytest>=8.3.3", +] diff --git a/files/templates/python/src/name/__init__.py b/files/templates/python/src/name/__init__.py new file mode 100644 index 0000000..be3f53f --- /dev/null +++ b/files/templates/python/src/name/__init__.py @@ -0,0 +1,2 @@ +def hello() -> None: + print("Hello from testing!") diff --git a/files/templates/python/tests/test_hello.py b/files/templates/python/tests/test_hello.py new file mode 100644 index 0000000..a86c661 --- /dev/null +++ b/files/templates/python/tests/test_hello.py @@ -0,0 +1,8 @@ +import name + + +def test_hello(capsys): + name.hello() + captured = capsys.readouterr() + assert captured.out == "Hello from testing!\n" + assert captured.err == "" diff --git a/files/templates/python/uv.lock b/files/templates/python/uv.lock new file mode 100644 index 0000000..c9fb7f2 --- /dev/null +++ b/files/templates/python/uv.lock @@ -0,0 +1,254 @@ +version = 1 +requires-python = ">=3.12" + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, +] + +[[package]] +name = "coverage" +version = "7.6.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/84/ba/ac14d281f80aab516275012e8875991bb06203957aa1e19950139238d658/coverage-7.6.10.tar.gz", hash = "sha256:7fb105327c8f8f0682e29843e2ff96af9dcbe5bab8eeb4b398c6a33a16d80a23", size = 803868 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/86/77/19d09ea06f92fdf0487499283b1b7af06bc422ea94534c8fe3a4cd023641/coverage-7.6.10-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:27c6e64726b307782fa5cbe531e7647aee385a29b2107cd87ba7c0105a5d3853", size = 208281 }, + { url = "https://files.pythonhosted.org/packages/b6/67/5479b9f2f99fcfb49c0d5cf61912a5255ef80b6e80a3cddba39c38146cf4/coverage-7.6.10-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c56e097019e72c373bae32d946ecf9858fda841e48d82df7e81c63ac25554078", size = 208514 }, + { url = "https://files.pythonhosted.org/packages/15/d1/febf59030ce1c83b7331c3546d7317e5120c5966471727aa7ac157729c4b/coverage-7.6.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7827a5bc7bdb197b9e066cdf650b2887597ad124dd99777332776f7b7c7d0d0", size = 241537 }, + { url = "https://files.pythonhosted.org/packages/4b/7e/5ac4c90192130e7cf8b63153fe620c8bfd9068f89a6d9b5f26f1550f7a26/coverage-7.6.10-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:204a8238afe787323a8b47d8be4df89772d5c1e4651b9ffa808552bdf20e1d50", size = 238572 }, + { url = "https://files.pythonhosted.org/packages/dc/03/0334a79b26ecf59958f2fe9dd1f5ab3e2f88db876f5071933de39af09647/coverage-7.6.10-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e67926f51821b8e9deb6426ff3164870976fe414d033ad90ea75e7ed0c2e5022", size = 240639 }, + { url = "https://files.pythonhosted.org/packages/d7/45/8a707f23c202208d7b286d78ad6233f50dcf929319b664b6cc18a03c1aae/coverage-7.6.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e78b270eadb5702938c3dbe9367f878249b5ef9a2fcc5360ac7bff694310d17b", size = 240072 }, + { url = "https://files.pythonhosted.org/packages/66/02/603ce0ac2d02bc7b393279ef618940b4a0535b0868ee791140bda9ecfa40/coverage-7.6.10-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:714f942b9c15c3a7a5fe6876ce30af831c2ad4ce902410b7466b662358c852c0", size = 238386 }, + { url = "https://files.pythonhosted.org/packages/04/62/4e6887e9be060f5d18f1dd58c2838b2d9646faf353232dec4e2d4b1c8644/coverage-7.6.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:abb02e2f5a3187b2ac4cd46b8ced85a0858230b577ccb2c62c81482ca7d18852", size = 240054 }, + { url = "https://files.pythonhosted.org/packages/5c/74/83ae4151c170d8bd071924f212add22a0e62a7fe2b149edf016aeecad17c/coverage-7.6.10-cp312-cp312-win32.whl", hash = "sha256:55b201b97286cf61f5e76063f9e2a1d8d2972fc2fcfd2c1272530172fd28c359", size = 210904 }, + { url = "https://files.pythonhosted.org/packages/c3/54/de0893186a221478f5880283119fc40483bc460b27c4c71d1b8bba3474b9/coverage-7.6.10-cp312-cp312-win_amd64.whl", hash = "sha256:e4ae5ac5e0d1e4edfc9b4b57b4cbecd5bc266a6915c500f358817a8496739247", size = 211692 }, + { url = "https://files.pythonhosted.org/packages/25/6d/31883d78865529257bf847df5789e2ae80e99de8a460c3453dbfbe0db069/coverage-7.6.10-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:05fca8ba6a87aabdd2d30d0b6c838b50510b56cdcfc604d40760dae7153b73d9", size = 208308 }, + { url = "https://files.pythonhosted.org/packages/70/22/3f2b129cc08de00c83b0ad6252e034320946abfc3e4235c009e57cfeee05/coverage-7.6.10-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9e80eba8801c386f72e0712a0453431259c45c3249f0009aff537a517b52942b", size = 208565 }, + { url = "https://files.pythonhosted.org/packages/97/0a/d89bc2d1cc61d3a8dfe9e9d75217b2be85f6c73ebf1b9e3c2f4e797f4531/coverage-7.6.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a372c89c939d57abe09e08c0578c1d212e7a678135d53aa16eec4430adc5e690", size = 241083 }, + { url = "https://files.pythonhosted.org/packages/4c/81/6d64b88a00c7a7aaed3a657b8eaa0931f37a6395fcef61e53ff742b49c97/coverage-7.6.10-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ec22b5e7fe7a0fa8509181c4aac1db48f3dd4d3a566131b313d1efc102892c18", size = 238235 }, + { url = "https://files.pythonhosted.org/packages/9a/0b/7797d4193f5adb4b837207ed87fecf5fc38f7cc612b369a8e8e12d9fa114/coverage-7.6.10-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26bcf5c4df41cad1b19c84af71c22cbc9ea9a547fc973f1f2cc9a290002c8b3c", size = 240220 }, + { url = "https://files.pythonhosted.org/packages/65/4d/6f83ca1bddcf8e51bf8ff71572f39a1c73c34cf50e752a952c34f24d0a60/coverage-7.6.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4e4630c26b6084c9b3cb53b15bd488f30ceb50b73c35c5ad7871b869cb7365fd", size = 239847 }, + { url = "https://files.pythonhosted.org/packages/30/9d/2470df6aa146aff4c65fee0f87f58d2164a67533c771c9cc12ffcdb865d5/coverage-7.6.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2396e8116db77789f819d2bc8a7e200232b7a282c66e0ae2d2cd84581a89757e", size = 237922 }, + { url = "https://files.pythonhosted.org/packages/08/dd/723fef5d901e6a89f2507094db66c091449c8ba03272861eaefa773ad95c/coverage-7.6.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:79109c70cc0882e4d2d002fe69a24aa504dec0cc17169b3c7f41a1d341a73694", size = 239783 }, + { url = "https://files.pythonhosted.org/packages/3d/f7/64d3298b2baf261cb35466000628706ce20a82d42faf9b771af447cd2b76/coverage-7.6.10-cp313-cp313-win32.whl", hash = "sha256:9e1747bab246d6ff2c4f28b4d186b205adced9f7bd9dc362051cc37c4a0c7bd6", size = 210965 }, + { url = "https://files.pythonhosted.org/packages/d5/58/ec43499a7fc681212fe7742fe90b2bc361cdb72e3181ace1604247a5b24d/coverage-7.6.10-cp313-cp313-win_amd64.whl", hash = "sha256:254f1a3b1eef5f7ed23ef265eaa89c65c8c5b6b257327c149db1ca9d4a35f25e", size = 211719 }, + { url = "https://files.pythonhosted.org/packages/ab/c9/f2857a135bcff4330c1e90e7d03446b036b2363d4ad37eb5e3a47bbac8a6/coverage-7.6.10-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2ccf240eb719789cedbb9fd1338055de2761088202a9a0b73032857e53f612fe", size = 209050 }, + { url = "https://files.pythonhosted.org/packages/aa/b3/f840e5bd777d8433caa9e4a1eb20503495709f697341ac1a8ee6a3c906ad/coverage-7.6.10-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:0c807ca74d5a5e64427c8805de15b9ca140bba13572d6d74e262f46f50b13273", size = 209321 }, + { url = "https://files.pythonhosted.org/packages/85/7d/125a5362180fcc1c03d91850fc020f3831d5cda09319522bcfa6b2b70be7/coverage-7.6.10-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2bcfa46d7709b5a7ffe089075799b902020b62e7ee56ebaed2f4bdac04c508d8", size = 252039 }, + { url = "https://files.pythonhosted.org/packages/a9/9c/4358bf3c74baf1f9bddd2baf3756b54c07f2cfd2535f0a47f1e7757e54b3/coverage-7.6.10-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4e0de1e902669dccbf80b0415fb6b43d27edca2fbd48c74da378923b05316098", size = 247758 }, + { url = "https://files.pythonhosted.org/packages/cf/c7/de3eb6fc5263b26fab5cda3de7a0f80e317597a4bad4781859f72885f300/coverage-7.6.10-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f7b444c42bbc533aaae6b5a2166fd1a797cdb5eb58ee51a92bee1eb94a1e1cb", size = 250119 }, + { url = "https://files.pythonhosted.org/packages/3e/e6/43de91f8ba2ec9140c6a4af1102141712949903dc732cf739167cfa7a3bc/coverage-7.6.10-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b330368cb99ef72fcd2dc3ed260adf67b31499584dc8a20225e85bfe6f6cfed0", size = 249597 }, + { url = "https://files.pythonhosted.org/packages/08/40/61158b5499aa2adf9e37bc6d0117e8f6788625b283d51e7e0c53cf340530/coverage-7.6.10-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:9a7cfb50515f87f7ed30bc882f68812fd98bc2852957df69f3003d22a2aa0abf", size = 247473 }, + { url = "https://files.pythonhosted.org/packages/50/69/b3f2416725621e9f112e74e8470793d5b5995f146f596f133678a633b77e/coverage-7.6.10-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f93531882a5f68c28090f901b1d135de61b56331bba82028489bc51bdd818d2", size = 248737 }, + { url = "https://files.pythonhosted.org/packages/3c/6e/fe899fb937657db6df31cc3e61c6968cb56d36d7326361847440a430152e/coverage-7.6.10-cp313-cp313t-win32.whl", hash = "sha256:89d76815a26197c858f53c7f6a656686ec392b25991f9e409bcef020cd532312", size = 211611 }, + { url = "https://files.pythonhosted.org/packages/1c/55/52f5e66142a9d7bc93a15192eba7a78513d2abf6b3558d77b4ca32f5f424/coverage-7.6.10-cp313-cp313t-win_amd64.whl", hash = "sha256:54a5f0f43950a36312155dae55c505a76cd7f2b12d26abeebbe7a0b36dbc868d", size = 212781 }, +] + +[[package]] +name = "docstring-to-markdown" +version = "0.15" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7a/ad/6a66abd14676619bd56f6b924c96321a2e2d7d86558841d94a30023eec53/docstring-to-markdown-0.15.tar.gz", hash = "sha256:e146114d9c50c181b1d25505054a8d0f7a476837f0da2c19f07e06eaed52b73d", size = 29246 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/cf/4eee59f6c4111b3e80cc32cf6bac483a90646f5c8693e84496c9855e8e38/docstring_to_markdown-0.15-py3-none-any.whl", hash = "sha256:27afb3faedba81e34c33521c32bbd258d7fbb79eedf7d29bc4e81080e854aec0", size = 21640 }, +] + +[[package]] +name = "iniconfig" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", size = 4646 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 }, +] + +[[package]] +name = "jedi" +version = "0.19.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "parso" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278 }, +] + +[[package]] +name = "name" +version = "0.1.0" +source = { editable = "." } + +[package.dev-dependencies] +dev = [ + { name = "pytest" }, + { name = "pytest-cov" }, + { name = "python-lsp-server" }, + { name = "ruff" }, +] +lint = [ + { name = "ruff" }, +] +lsp = [ + { name = "python-lsp-server" }, +] +test = [ + { name = "pytest" }, + { name = "pytest-cov" }, +] + +[package.metadata] + +[package.metadata.requires-dev] +dev = [ + { name = "pytest", specifier = ">=8.3.3" }, + { name = "pytest-cov", specifier = ">=6.0.0" }, + { name = "python-lsp-server" }, + { name = "ruff", specifier = ">=0.6.7" }, +] +lint = [{ name = "ruff", specifier = ">=0.6.7" }] +lsp = [{ name = "python-lsp-server" }] +test = [ + { name = "pytest", specifier = ">=8.3.3" }, + { name = "pytest-cov", specifier = ">=6.0.0" }, +] + +[[package]] +name = "packaging" +version = "24.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d0/63/68dbb6eb2de9cb10ee4c9c14a0148804425e13c4fb20d61cce69f53106da/packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f", size = 163950 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451 }, +] + +[[package]] +name = "parso" +version = "0.8.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/66/94/68e2e17afaa9169cf6412ab0f28623903be73d1b32e208d9e8e541bb086d/parso-0.8.4.tar.gz", hash = "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d", size = 400609 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c6/ac/dac4a63f978e4dcb3c6d3a78c4d8e0192a113d288502a1216950c41b1027/parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18", size = 103650 }, +] + +[[package]] +name = "pluggy" +version = "1.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 }, +] + +[[package]] +name = "pytest" +version = "8.3.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/05/35/30e0d83068951d90a01852cb1cef56e5d8a09d20c7f511634cc2f7e0372a/pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761", size = 1445919 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/11/92/76a1c94d3afee238333bc0a42b82935dd8f9cf8ce9e336ff87ee14d9e1cf/pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6", size = 343083 }, +] + +[[package]] +name = "pytest-cov" +version = "6.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "coverage" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/be/45/9b538de8cef30e17c7b45ef42f538a94889ed6a16f2387a6c89e73220651/pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0", size = 66945 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/36/3b/48e79f2cd6a61dbbd4807b4ed46cb564b4fd50a76166b1c4ea5c1d9e2371/pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35", size = 22949 }, +] + +[[package]] +name = "python-lsp-jsonrpc" +version = "1.1.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ujson" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/48/b6/fd92e2ea4635d88966bb42c20198df1a981340f07843b5e3c6694ba3557b/python-lsp-jsonrpc-1.1.2.tar.gz", hash = "sha256:4688e453eef55cd952bff762c705cedefa12055c0aec17a06f595bcc002cc912", size = 15298 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/d9/656659d5b5d5f402b2b174cd0ba9bc827e07ce3c0bf88da65424baf64af8/python_lsp_jsonrpc-1.1.2-py3-none-any.whl", hash = "sha256:7339c2e9630ae98903fdaea1ace8c47fba0484983794d6aafd0bd8989be2b03c", size = 8805 }, +] + +[[package]] +name = "python-lsp-server" +version = "1.12.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "docstring-to-markdown" }, + { name = "jedi" }, + { name = "pluggy" }, + { name = "python-lsp-jsonrpc" }, + { name = "ujson" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2b/15/b7e1577b9ca358e008b06910bf23cfa0a8be130ee9f319a262a3c610ee8d/python_lsp_server-1.12.0.tar.gz", hash = "sha256:b6a336f128da03bd9bac1e61c3acca6e84242b8b31055a1ccf49d83df9dc053b", size = 114328 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1d/49/37c9659f76dbf1018d88892c14184db36ce9df09ea7d760162584aee8a58/python_lsp_server-1.12.0-py3-none-any.whl", hash = "sha256:2e912c661881d85f67f2076e4e66268b695b62bf127e07e81f58b187d4bb6eda", size = 74782 }, +] + +[[package]] +name = "ruff" +version = "0.8.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/34/37/9c02181ef38d55b77d97c68b78e705fd14c0de0e5d085202bb2b52ce5be9/ruff-0.8.4.tar.gz", hash = "sha256:0d5f89f254836799af1615798caa5f80b7f935d7a670fad66c5007928e57ace8", size = 3402103 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/05/67/f480bf2f2723b2e49af38ed2be75ccdb2798fca7d56279b585c8f553aaab/ruff-0.8.4-py3-none-linux_armv6l.whl", hash = "sha256:58072f0c06080276804c6a4e21a9045a706584a958e644353603d36ca1eb8a60", size = 10546415 }, + { url = "https://files.pythonhosted.org/packages/eb/7a/5aba20312c73f1ce61814e520d1920edf68ca3b9c507bd84d8546a8ecaa8/ruff-0.8.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ffb60904651c00a1e0b8df594591770018a0f04587f7deeb3838344fe3adabac", size = 10346113 }, + { url = "https://files.pythonhosted.org/packages/76/f4/c41de22b3728486f0aa95383a44c42657b2db4062f3234ca36fc8cf52d8b/ruff-0.8.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:6ddf5d654ac0d44389f6bf05cee4caeefc3132a64b58ea46738111d687352296", size = 9943564 }, + { url = "https://files.pythonhosted.org/packages/0e/f0/afa0d2191af495ac82d4cbbfd7a94e3df6f62a04ca412033e073b871fc6d/ruff-0.8.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e248b1f0fa2749edd3350a2a342b67b43a2627434c059a063418e3d375cfe643", size = 10805522 }, + { url = "https://files.pythonhosted.org/packages/12/57/5d1e9a0fd0c228e663894e8e3a8e7063e5ee90f8e8e60cf2085f362bfa1a/ruff-0.8.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bf197b98ed86e417412ee3b6c893f44c8864f816451441483253d5ff22c0e81e", size = 10306763 }, + { url = "https://files.pythonhosted.org/packages/04/df/f069fdb02e408be8aac6853583572a2873f87f866fe8515de65873caf6b8/ruff-0.8.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c41319b85faa3aadd4d30cb1cffdd9ac6b89704ff79f7664b853785b48eccdf3", size = 11359574 }, + { url = "https://files.pythonhosted.org/packages/d3/04/37c27494cd02e4a8315680debfc6dfabcb97e597c07cce0044db1f9dfbe2/ruff-0.8.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:9f8402b7c4f96463f135e936d9ab77b65711fcd5d72e5d67597b543bbb43cf3f", size = 12094851 }, + { url = "https://files.pythonhosted.org/packages/81/b1/c5d7fb68506cab9832d208d03ea4668da9a9887a4a392f4f328b1bf734ad/ruff-0.8.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e4e56b3baa9c23d324ead112a4fdf20db9a3f8f29eeabff1355114dd96014604", size = 11655539 }, + { url = "https://files.pythonhosted.org/packages/ef/38/8f8f2c8898dc8a7a49bc340cf6f00226917f0f5cb489e37075bcb2ce3671/ruff-0.8.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:736272574e97157f7edbbb43b1d046125fce9e7d8d583d5d65d0c9bf2c15addf", size = 12912805 }, + { url = "https://files.pythonhosted.org/packages/06/dd/fa6660c279f4eb320788876d0cff4ea18d9af7d9ed7216d7bd66877468d0/ruff-0.8.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5fe710ab6061592521f902fca7ebcb9fabd27bc7c57c764298b1c1f15fff720", size = 11205976 }, + { url = "https://files.pythonhosted.org/packages/a8/d7/de94cc89833b5de455750686c17c9e10f4e1ab7ccdc5521b8fe911d1477e/ruff-0.8.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:13e9ec6d6b55f6da412d59953d65d66e760d583dd3c1c72bf1f26435b5bfdbae", size = 10792039 }, + { url = "https://files.pythonhosted.org/packages/6d/15/3e4906559248bdbb74854af684314608297a05b996062c9d72e0ef7c7097/ruff-0.8.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:97d9aefef725348ad77d6db98b726cfdb075a40b936c7984088804dfd38268a7", size = 10400088 }, + { url = "https://files.pythonhosted.org/packages/a2/21/9ed4c0e8133cb4a87a18d470f534ad1a8a66d7bec493bcb8bda2d1a5d5be/ruff-0.8.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:ab78e33325a6f5374e04c2ab924a3367d69a0da36f8c9cb6b894a62017506111", size = 10900814 }, + { url = "https://files.pythonhosted.org/packages/0d/5d/122a65a18955bd9da2616b69bc839351f8baf23b2805b543aa2f0aed72b5/ruff-0.8.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:8ef06f66f4a05c3ddbc9121a8b0cecccd92c5bf3dd43b5472ffe40b8ca10f0f8", size = 11268828 }, + { url = "https://files.pythonhosted.org/packages/43/a9/1676ee9106995381e3d34bccac5bb28df70194167337ed4854c20f27c7ba/ruff-0.8.4-py3-none-win32.whl", hash = "sha256:552fb6d861320958ca5e15f28b20a3d071aa83b93caee33a87b471f99a6c0835", size = 8805621 }, + { url = "https://files.pythonhosted.org/packages/10/98/ed6b56a30ee76771c193ff7ceeaf1d2acc98d33a1a27b8479cbdb5c17a23/ruff-0.8.4-py3-none-win_amd64.whl", hash = "sha256:f21a1143776f8656d7f364bd264a9d60f01b7f52243fbe90e7670c0dfe0cf65d", size = 9660086 }, + { url = "https://files.pythonhosted.org/packages/13/9f/026e18ca7d7766783d779dae5e9c656746c6ede36ef73c6d934aaf4a6dec/ruff-0.8.4-py3-none-win_arm64.whl", hash = "sha256:9183dd615d8df50defa8b1d9a074053891ba39025cf5ae88e8bcb52edcc4bf08", size = 9074500 }, +] + +[[package]] +name = "ujson" +version = "5.10.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f0/00/3110fd566786bfa542adb7932d62035e0c0ef662a8ff6544b6643b3d6fd7/ujson-5.10.0.tar.gz", hash = "sha256:b3cd8f3c5d8c7738257f1018880444f7b7d9b66232c64649f562d7ba86ad4bc1", size = 7154885 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e8/a6/fd3f8bbd80842267e2d06c3583279555e8354c5986c952385199d57a5b6c/ujson-5.10.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:98ba15d8cbc481ce55695beee9f063189dce91a4b08bc1d03e7f0152cd4bbdd5", size = 55642 }, + { url = "https://files.pythonhosted.org/packages/a8/47/dd03fd2b5ae727e16d5d18919b383959c6d269c7b948a380fdd879518640/ujson-5.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a9d2edbf1556e4f56e50fab7d8ff993dbad7f54bac68eacdd27a8f55f433578e", size = 51807 }, + { url = "https://files.pythonhosted.org/packages/25/23/079a4cc6fd7e2655a473ed9e776ddbb7144e27f04e8fc484a0fb45fe6f71/ujson-5.10.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6627029ae4f52d0e1a2451768c2c37c0c814ffc04f796eb36244cf16b8e57043", size = 51972 }, + { url = "https://files.pythonhosted.org/packages/04/81/668707e5f2177791869b624be4c06fb2473bf97ee33296b18d1cf3092af7/ujson-5.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8ccb77b3e40b151e20519c6ae6d89bfe3f4c14e8e210d910287f778368bb3d1", size = 53686 }, + { url = "https://files.pythonhosted.org/packages/bd/50/056d518a386d80aaf4505ccf3cee1c40d312a46901ed494d5711dd939bc3/ujson-5.10.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3caf9cd64abfeb11a3b661329085c5e167abbe15256b3b68cb5d914ba7396f3", size = 58591 }, + { url = "https://files.pythonhosted.org/packages/fc/d6/aeaf3e2d6fb1f4cfb6bf25f454d60490ed8146ddc0600fae44bfe7eb5a72/ujson-5.10.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6e32abdce572e3a8c3d02c886c704a38a1b015a1fb858004e03d20ca7cecbb21", size = 997853 }, + { url = "https://files.pythonhosted.org/packages/f8/d5/1f2a5d2699f447f7d990334ca96e90065ea7f99b142ce96e85f26d7e78e2/ujson-5.10.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a65b6af4d903103ee7b6f4f5b85f1bfd0c90ba4eeac6421aae436c9988aa64a2", size = 1140689 }, + { url = "https://files.pythonhosted.org/packages/f2/2c/6990f4ccb41ed93744aaaa3786394bca0875503f97690622f3cafc0adfde/ujson-5.10.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:604a046d966457b6cdcacc5aa2ec5314f0e8c42bae52842c1e6fa02ea4bda42e", size = 1043576 }, + { url = "https://files.pythonhosted.org/packages/14/f5/a2368463dbb09fbdbf6a696062d0c0f62e4ae6fa65f38f829611da2e8fdd/ujson-5.10.0-cp312-cp312-win32.whl", hash = "sha256:6dea1c8b4fc921bf78a8ff00bbd2bfe166345f5536c510671bccececb187c80e", size = 38764 }, + { url = "https://files.pythonhosted.org/packages/59/2d/691f741ffd72b6c84438a93749ac57bf1a3f217ac4b0ea4fd0e96119e118/ujson-5.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:38665e7d8290188b1e0d57d584eb8110951a9591363316dd41cf8686ab1d0abc", size = 42211 }, + { url = "https://files.pythonhosted.org/packages/0d/69/b3e3f924bb0e8820bb46671979770c5be6a7d51c77a66324cdb09f1acddb/ujson-5.10.0-cp313-cp313-macosx_10_9_x86_64.whl", hash = "sha256:618efd84dc1acbd6bff8eaa736bb6c074bfa8b8a98f55b61c38d4ca2c1f7f287", size = 55646 }, + { url = "https://files.pythonhosted.org/packages/32/8a/9b748eb543c6cabc54ebeaa1f28035b1bd09c0800235b08e85990734c41e/ujson-5.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:38d5d36b4aedfe81dfe251f76c0467399d575d1395a1755de391e58985ab1c2e", size = 51806 }, + { url = "https://files.pythonhosted.org/packages/39/50/4b53ea234413b710a18b305f465b328e306ba9592e13a791a6a6b378869b/ujson-5.10.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67079b1f9fb29ed9a2914acf4ef6c02844b3153913eb735d4bf287ee1db6e557", size = 51975 }, + { url = "https://files.pythonhosted.org/packages/b4/9d/8061934f960cdb6dd55f0b3ceeff207fcc48c64f58b43403777ad5623d9e/ujson-5.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7d0e0ceeb8fe2468c70ec0c37b439dd554e2aa539a8a56365fd761edb418988", size = 53693 }, + { url = "https://files.pythonhosted.org/packages/f5/be/7bfa84b28519ddbb67efc8410765ca7da55e6b93aba84d97764cd5794dbc/ujson-5.10.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:59e02cd37bc7c44d587a0ba45347cc815fb7a5fe48de16bf05caa5f7d0d2e816", size = 58594 }, + { url = "https://files.pythonhosted.org/packages/48/eb/85d465abafb2c69d9699cfa5520e6e96561db787d36c677370e066c7e2e7/ujson-5.10.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2a890b706b64e0065f02577bf6d8ca3b66c11a5e81fb75d757233a38c07a1f20", size = 997853 }, + { url = "https://files.pythonhosted.org/packages/9f/76/2a63409fc05d34dd7d929357b7a45e3a2c96f22b4225cd74becd2ba6c4cb/ujson-5.10.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:621e34b4632c740ecb491efc7f1fcb4f74b48ddb55e65221995e74e2d00bbff0", size = 1140694 }, + { url = "https://files.pythonhosted.org/packages/45/ed/582c4daba0f3e1688d923b5cb914ada1f9defa702df38a1916c899f7c4d1/ujson-5.10.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b9500e61fce0cfc86168b248104e954fead61f9be213087153d272e817ec7b4f", size = 1043580 }, + { url = "https://files.pythonhosted.org/packages/d7/0c/9837fece153051e19c7bade9f88f9b409e026b9525927824cdf16293b43b/ujson-5.10.0-cp313-cp313-win32.whl", hash = "sha256:4c4fc16f11ac1612f05b6f5781b384716719547e142cfd67b65d035bd85af165", size = 38766 }, + { url = "https://files.pythonhosted.org/packages/d7/72/6cb6728e2738c05bbe9bd522d6fc79f86b9a28402f38663e85a28fddd4a0/ujson-5.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:4573fd1695932d4f619928fd09d5d03d917274381649ade4328091ceca175539", size = 42212 }, +] diff --git a/files/templates/rust/.envrc b/files/templates/rust/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/files/templates/rust/.envrc @@ -0,0 +1 @@ +use flake diff --git a/files/templates/rust/Cargo.lock b/files/templates/rust/Cargo.lock new file mode 100644 index 0000000..b21cc6a --- /dev/null +++ b/files/templates/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "rust" +version = "0.1.0" diff --git a/files/templates/rust/Cargo.toml b/files/templates/rust/Cargo.toml new file mode 100644 index 0000000..7d75412 --- /dev/null +++ b/files/templates/rust/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "rust" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/files/templates/rust/flake.nix b/files/templates/rust/flake.nix new file mode 100644 index 0000000..415d1c2 --- /dev/null +++ b/files/templates/rust/flake.nix @@ -0,0 +1,70 @@ +# heavily inspired by https://github.com/nulladmin1/nix-flake-templates/blob/main/rust-fenix-naersk/flake.nix +{ + description = "Rust Flake using Fenix and Naersk"; + + inputs = { + nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; + systems.url = "github:nix-systems/default"; + naersk.url = "github:nix-community/naersk"; + fenix = { + url = "github:nix-community/fenix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + + outputs = + { self + , nixpkgs + , naersk + , fenix + , systems + , ... + }: + let + forEachSystem = nixpkgs.lib.genAttrs (import systems); + pkgsFor = forEachSystem (system: + + import nixpkgs { + inherit system; + overlays = [ + fenix.overlays.default + ]; + }); + rust-toolchain = forEachSystem (system: pkgsFor.${system}.fenix.stable); + in + { + formatter = forEachSystem (system: pkgsFor.${system}.nixpkgs-fmt); + + devShells = forEachSystem (system: { + default = pkgsFor.${system}.mkShell { + packages = with rust-toolchain.${system}; [ + cargo + rustc + clippy + rustfmt + rust-analyzer + ]; + env = { + RUST_BACKTRACE = "full"; + }; + RUST_SRC_PATH = "${rust-toolchain.${system}.rust-src}/lib/rustlib/src/rust/library"; + }; + }); + + packages = forEachSystem (system: { + default = + (pkgsFor.${system}.callPackage naersk { + inherit (rust-toolchain.${system}) cargo rustc; + }).buildPackage { + src = ./.; + }; + }); + + apps = forEachSystem (system: { + default = { + type = "app"; + program = "${self.packages.${system}.default}/bin/rust"; + }; + }); + }; +} diff --git a/files/templates/rust/src/main.rs b/files/templates/rust/src/main.rs new file mode 100644 index 0000000..e7a11a9 --- /dev/null +++ b/files/templates/rust/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} diff --git a/files/topology-images/DELL-C2665dnf.png b/files/topology-images/DELL-C2665dnf.png new file mode 100644 index 0000000..798595a Binary files /dev/null and b/files/topology-images/DELL-C2665dnf.png differ diff --git a/files/topology-images/TL-SG1005D.png b/files/topology-images/TL-SG1005D.png new file mode 100644 index 0000000..c06f063 Binary files /dev/null and b/files/topology-images/TL-SG1005D.png differ diff --git a/files/topology-images/TL-SG108.png b/files/topology-images/TL-SG108.png new file mode 100644 index 0000000..3088ba8 Binary files /dev/null and b/files/topology-images/TL-SG108.png differ diff --git a/files/topology-images/ankisync.png b/files/topology-images/ankisync.png new file mode 100644 index 0000000..3a4432c Binary files /dev/null and b/files/topology-images/ankisync.png differ diff --git a/files/topology-images/croc.png b/files/topology-images/croc.png new file mode 100644 index 0000000..1024fe0 Binary files /dev/null and b/files/topology-images/croc.png differ diff --git a/files/topology-images/firefly-iii.png b/files/topology-images/firefly-iii.png new file mode 100644 index 0000000..de09e5e Binary files /dev/null and b/files/topology-images/firefly-iii.png differ diff --git a/files/topology-images/freshrss.png b/files/topology-images/freshrss.png new file mode 100644 index 0000000..d1a7511 Binary files /dev/null and b/files/topology-images/freshrss.png differ diff --git a/files/topology-images/huawei.png b/files/topology-images/huawei.png new file mode 100644 index 0000000..20fd367 Binary files /dev/null and b/files/topology-images/huawei.png differ diff --git a/files/topology-images/hunsn.png b/files/topology-images/hunsn.png new file mode 100644 index 0000000..d011117 Binary files /dev/null and b/files/topology-images/hunsn.png differ diff --git a/files/topology-images/kavita.png b/files/topology-images/kavita.png new file mode 100644 index 0000000..dc1cd45 Binary files /dev/null and b/files/topology-images/kavita.png differ diff --git a/files/topology-images/koillection.png b/files/topology-images/koillection.png new file mode 100644 index 0000000..c38d95a Binary files /dev/null and b/files/topology-images/koillection.png differ diff --git a/files/topology-images/mac.png b/files/topology-images/mac.png new file mode 100644 index 0000000..6c82ebc Binary files /dev/null and b/files/topology-images/mac.png differ diff --git a/files/topology-images/microbin.png b/files/topology-images/microbin.png new file mode 100644 index 0000000..da0c331 Binary files /dev/null and b/files/topology-images/microbin.png differ diff --git a/files/topology-images/mpd.png b/files/topology-images/mpd.png new file mode 100644 index 0000000..d8b6d96 Binary files /dev/null and b/files/topology-images/mpd.png differ diff --git a/files/topology-images/nintendo-switch.png b/files/topology-images/nintendo-switch.png new file mode 100644 index 0000000..21f8de3 Binary files /dev/null and b/files/topology-images/nintendo-switch.png differ diff --git a/files/topology-images/pc.png b/files/topology-images/pc.png new file mode 100644 index 0000000..b8fa044 Binary files /dev/null and b/files/topology-images/pc.png differ diff --git a/files/topology-images/phone.png b/files/topology-images/phone.png new file mode 100644 index 0000000..bde15e7 Binary files /dev/null and b/files/topology-images/phone.png differ diff --git a/files/topology-images/readarr.png b/files/topology-images/readarr.png new file mode 100644 index 0000000..2ce0639 Binary files /dev/null and b/files/topology-images/readarr.png differ diff --git a/files/topology-images/shlink.png b/files/topology-images/shlink.png new file mode 100644 index 0000000..e3df864 Binary files /dev/null and b/files/topology-images/shlink.png differ diff --git a/files/topology-images/zflip6.png b/files/topology-images/zflip6.png new file mode 100644 index 0000000..5e2b59f Binary files /dev/null and b/files/topology-images/zflip6.png differ diff --git a/files/vieb/viebrc b/files/vieb/viebrc new file mode 100644 index 0000000..2a0f075 --- /dev/null +++ b/files/vieb/viebrc @@ -0,0 +1,196 @@ +" Options +set adblocker=update +set adblockernotifications=all +set cache=clearonquit +set noclearcookiesonquit +set nocleardownloadsoncompleted +set nocleardownloadsonquit +set clearhistoryinterval=none +set noclearlocalstorageonquit +set noclosablepinnedtabs +set commandhist=persistuseronly +set containerkeeponreopen +set containernewtab=s:usecurrent +set containershowname=automatic +set containersplitpage=s:usecurrent +set containerstartuppage=main +set countlimit=100 +" set nodarkreader +set darkreaderbg=#181a1b +set darkreaderbrightness=100 +set darkreadercontrast=100 +set darkreaderfg=#e8e6e3 +set darkreadergrayscale=0 +set darkreadermode=dark +set darkreadersepia=0 +set darkreadertextstroke=0 +set devtoolsposition=split +set dialogalert=notifyblock +set dialogconfirm=notifyallow +set dialogprompt=notifyblock +set downloadmethod=automatic +set downloadpath= +set encodeurlcopy=nospaces +set encodeurlext=nospaces +set explorehist=persist +set externalcommand= +set favicons=session +set followchars=numbers +set followfallbackaction=filter +set followlabelposition=outsiderighttop +set follownewtabswitch +set guifontsize=14 +set guifullscreennavbar=oninput +set guifullscreentabbar=onupdate +set guihidetimeout=5000 +set guinavbar=oninput +set guiscrollbar=onscroll +set guitabbar=onupdate +set historyperpage=100 +set ignorecase +set incsearch +set inputfocusalignment=rememberend +set keeprecentlyclosed +set lang=en +set loadingindicator=line +set mapsuggest=9000000000000000 +set mapsuggestposition=topright +set markposition=newtab +set markpositionshifted=default +set maxmapdepth=10 +set menupage=elementasneeded +set menusuggest=both +set menuvieb=both +set mintabwidth=28 +set mouse=all +set mousedisabledbehavior=nothing +set nomousefocus +set mousenewtabswitch +set mousevisualmode=onswitch +set nativenotification=never +set nativetheme=dark +set newtaburl= +set notificationduration=6000 +set notificationforpermissions=silent +set notificationforsystemcommands=errors +set notificationlimitsmall=3 +set notificationposition=bottomright +set pdfbehavior=download +set permissioncamera=ask +set permissioncertificateerror=allow +set permissionclipboardread=allow +set permissionclipboardwrite=allow +set permissionclosepage=allow +set permissiondisplaycapture=ask +set permissionfullscreen=allow +set permissiongeolocation=block +set permissionhid=block +set permissionidledetection=block +set permissionmediadevices=allowfull +set permissionmicrophone=ask +set permissionmidi=ask +set permissionmidisysex=ask +set permissionnotifications=ask +set permissionopenexternal=ask +set permissionpersistentstorage=ask +set permissionpointerlock=block +set permissionscreenwakelock=block +set permissionsensors=block +set permissionserial=block +set permissionunknown=ask +set permissionusb=allow +set permissionwindowmanagement=ask +set pointerposlocalid=domain +set pointerpostype=casing +set noquitonlasttabclose +set redirecttohttp +set noreloadtaboncrash +set replacespecial=special +set replacestartup=never +set requesttimeout=20000 +set restoretabs=all +set scrollposlocalid=domain +set scrollpostype=casing +set searchemptyscope=global +set searchpointeralignment=left +set searchscope=global +set shell= +set showcmd +set smartcase +set spell +set nosplitbelow +set nosplitright +set nosponsorblock +set suggestbouncedelay=100 +set suggestcommands=9000000000000000 +set suggesttopsites=10 +set suspendbackgroundtab +set suspendonrestore=regular +set suspendtimeout=0 +set tabclosefocus=left +set tabcycle +set tabnewposition=right +set tabopenmuted=never +set taboverflow=scroll +set tabreopenmuted=remember +set tabreopenposition=right +set timeout +set timeoutlen=2000 +set translateapi=auto +set translatekey= +set translatelang=en-us +set translateurl=https://api-free.deepl.com/v2/ +" set nouserscript +" set nouserstyle +set useragent=%firefox +set vimcommand=gvim +set windowfullscreen=restore +set windowmaximize=restore +set windowposition=restore +set windowsize=restore +set windowtitle="%app - %title" + +" Commands +colorscheme default + + +" Mappings +nmap o +nmap t <:tabnew> +nmap b buffer +nmap g0 <:buffer 0> +nmap g^ <:buffer 0> +nmap g$ <:buffer -1> +nmap <:buffer #> +nmap J +nmap K +nmap >> +nmap +nmap O +nmap gx0 <:lclose> +nmap gx$ <:rclose> +nmap x +nunmap [ +nunmap ] +nmap [[ +nmap ]] +nmap [c +nmap ]c +nmap zz +nmap zi +nmap zo +nmap zm 5 +nmap zr 5 +nmap zM 5 +nmap zR 5 +nmap zI 7 +nmap zO 7 + +" Search +set searchengine=https://kagi.com/search?q=%s +set searchwords+=no~https://search.nixos.org/options?query=%s +set searchwords+=np~https://search.nixos.org/packages?query=%s +set searchwords+=hm~https://home-manager-options.extranix.com/?query=%s + +" Viebrc generated by Vieb +" vim: ft=vim diff --git a/files/wallpaper/botanicswp.png b/files/wallpaper/botanicswp.png new file mode 100644 index 0000000..c99fa11 Binary files /dev/null and b/files/wallpaper/botanicswp.png differ diff --git a/wallpaper/lenovowp.png b/files/wallpaper/lenovowp.png similarity index 100% rename from wallpaper/lenovowp.png rename to files/wallpaper/lenovowp.png diff --git a/wallpaper/navidrome.png b/files/wallpaper/navidrome.png similarity index 100% rename from wallpaper/navidrome.png rename to files/wallpaper/navidrome.png diff --git a/wallpaper/op6wp.png b/files/wallpaper/op6wp.png similarity index 100% rename from wallpaper/op6wp.png rename to files/wallpaper/op6wp.png diff --git a/wallpaper/serverwp.png b/files/wallpaper/serverwp.png similarity index 100% rename from wallpaper/serverwp.png rename to files/wallpaper/serverwp.png diff --git a/wallpaper/standwp.png b/files/wallpaper/standwp.png similarity index 100% rename from wallpaper/standwp.png rename to files/wallpaper/standwp.png diff --git a/wallpaper/surfacewp.png b/files/wallpaper/surfacewp.png similarity index 100% rename from wallpaper/surfacewp.png rename to files/wallpaper/surfacewp.png diff --git a/wallpaper/swarsel.png b/files/wallpaper/swarsel.png similarity index 100% rename from wallpaper/swarsel.png rename to files/wallpaper/swarsel.png diff --git a/wallpaper/user.png b/files/wallpaper/user.png similarity index 100% rename from wallpaper/user.png rename to files/wallpaper/user.png diff --git a/programs/waybar/style.css b/files/waybar/style.css similarity index 85% rename from programs/waybar/style.css rename to files/waybar/style.css index 21c3cad..0148893 100644 --- a/programs/waybar/style.css +++ b/files/waybar/style.css @@ -9,7 +9,7 @@ @define-color background-critical blue; - * { +* { border: none; border-radius: 0; font-family: "FiraCode Nerd Font Propo", "Font Awesome 5 Free"; @@ -19,9 +19,9 @@ } window#waybar { - background: transparent; - color: @foreground; - transition-duration: .5s; + background: transparent; + color: @foreground; + transition-duration: .5s; } window#waybar.hidden { @@ -39,14 +39,14 @@ window#waybar.hidden { #custom-right-arrow-dark, #custom-left-arrow-dark { - color: @background; - background: @background-alt; - font-size: 24px; + color: @background; + background: @background-alt; + font-size: 24px; } #window { - font-size: 12px; - padding: 0 20px; + font-size: 12px; + padding: 0 20px; } #mode { @@ -73,21 +73,21 @@ window#waybar.hidden { #custom-outer-right-arrow-dark, #custom-outer-left-arrow-dark { - color: @background; - font-size: 24px; + color: @background; + font-size: 24px; } #custom-outer-left-arrow-dark, #custom-left-arrow-dark, #custom-left-arrow-light { - margin: 0 -1px; + margin: 0 -1px; } #custom-right-arrow-light, #custom-left-arrow-light { - color: @background-alt; - background: @background; - font-size: 24px; + color: @background-alt; + background: @background; + font-size: 24px; } #workspaces, @@ -119,20 +119,20 @@ window#waybar.hidden { #workspaces button { - padding: 0 2px; - color: #fdf6e3; + padding: 0 2px; + color: #fdf6e3; } #workspaces button.focused { - color: @foreground-warning; + color: @foreground-warning; } #workspaces button:hover { background: @foreground; color: @background; - border: @foreground; - padding: 0 2px; - box-shadow: inherit; - text-shadow: inherit; + border: @foreground; + padding: 0 2px; + box-shadow: inherit; + text-shadow: inherit; } #workspaces button.urgent { @@ -177,8 +177,8 @@ window#waybar.hidden { color: @foreground-error; } #memory { - /*color: #2aa198;*/ - color: #fdfd97; + /*color: #2aa198;*/ + color: #fdfd97; } #cpu { /*color: #6c71c4;*/ @@ -192,7 +192,7 @@ window#waybar.hidden { #battery, #custom-pseudobat { - color: cyan; + color: cyan; } #battery.discharging { color: #859900; diff --git a/files/zellij/config.kdl.nix b/files/zellij/config.kdl.nix new file mode 100644 index 0000000..e835d39 --- /dev/null +++ b/files/zellij/config.kdl.nix @@ -0,0 +1,341 @@ +{ config }: +'' + pane_frames false + simplified_ui false + default_shell "zsh" + copy_on_select true + on_force_close "detach" + show_startup_tips false + + default_layout "default" + layout_dir "${config.home.homeDirectory}/.config/zellij/layouts" + theme_dir "${config.home.homeDirectory}/.config/zellij/themes" + + keybinds clear-defaults=true { + locked { + bind "Ctrl g" { SwitchToMode "normal"; } + } + pane { + bind "left" { MoveFocus "left"; } + bind "down" { MoveFocus "down"; } + bind "up" { MoveFocus "up"; } + bind "right" { MoveFocus "right"; } + bind "c" { SwitchToMode "renamepane"; PaneNameInput 0; } + bind "d" { NewPane "down"; SwitchToMode "normal"; } + bind "e" { TogglePaneEmbedOrFloating; SwitchToMode "normal"; } + bind "f" { ToggleFocusFullscreen; SwitchToMode "normal"; } + bind "h" { MoveFocus "left"; } + bind "j" { MoveFocus "down"; } + bind "k" { MoveFocus "up"; } + bind "l" { MoveFocus "right"; } + bind "n" { NewPane; SwitchToMode "normal"; } + bind "p" { SwitchFocus; } + bind "Ctrl p" { SwitchToMode "normal"; } + bind "r" { NewPane "right"; SwitchToMode "normal"; } + bind "w" { ToggleFloatingPanes; SwitchToMode "normal"; } + bind "z" { TogglePaneFrames; SwitchToMode "normal"; } + } + tab { + bind "left" { GoToPreviousTab; } + bind "down" { GoToNextTab; } + bind "up" { GoToPreviousTab; } + bind "right" { GoToNextTab; } + bind "1" { GoToTab 1; SwitchToMode "normal"; } + bind "2" { GoToTab 2; SwitchToMode "normal"; } + bind "3" { GoToTab 3; SwitchToMode "normal"; } + bind "4" { GoToTab 4; SwitchToMode "normal"; } + bind "5" { GoToTab 5; SwitchToMode "normal"; } + bind "6" { GoToTab 6; SwitchToMode "normal"; } + bind "7" { GoToTab 7; SwitchToMode "normal"; } + bind "8" { GoToTab 8; SwitchToMode "normal"; } + bind "9" { GoToTab 9; SwitchToMode "normal"; } + bind "[" { BreakPaneLeft; SwitchToMode "normal"; } + bind "]" { BreakPaneRight; SwitchToMode "normal"; } + bind "b" { BreakPane; SwitchToMode "normal"; } + bind "h" { GoToPreviousTab; } + bind "j" { GoToNextTab; } + bind "k" { GoToPreviousTab; } + bind "l" { GoToNextTab; } + bind "n" { NewTab; SwitchToMode "normal"; } + bind "r" { SwitchToMode "renametab"; TabNameInput 0; } + bind "s" { ToggleActiveSyncTab; SwitchToMode "normal"; } + bind "Ctrl t" { SwitchToMode "normal"; } + bind "x" { CloseTab; SwitchToMode "normal"; } + bind "tab" { ToggleTab; } + } + resize { + bind "left" { Resize "Increase left"; } + bind "down" { Resize "Increase down"; } + bind "up" { Resize "Increase up"; } + bind "right" { Resize "Increase right"; } + bind "+" { Resize "Increase"; } + bind "-" { Resize "Decrease"; } + bind "=" { Resize "Increase"; } + bind "H" { Resize "Decrease left"; } + bind "J" { Resize "Decrease down"; } + bind "K" { Resize "Decrease up"; } + bind "L" { Resize "Decrease right"; } + bind "h" { Resize "Increase left"; } + bind "j" { Resize "Increase down"; } + bind "k" { Resize "Increase up"; } + bind "l" { Resize "Increase right"; } + bind "Ctrl n" { SwitchToMode "normal"; } + } + move { + bind "left" { MovePane "left"; } + bind "down" { MovePane "down"; } + bind "up" { MovePane "up"; } + bind "right" { MovePane "right"; } + bind "h" { MovePane "left"; } + bind "Ctrl h" { SwitchToMode "normal"; } + bind "j" { MovePane "down"; } + bind "k" { MovePane "up"; } + bind "l" { MovePane "right"; } + bind "n" { MovePane; } + bind "p" { MovePaneBackwards; } + bind "tab" { MovePane; } + } + scroll { + bind "e" { EditScrollback; SwitchToMode "normal"; } + bind "s" { SwitchToMode "entersearch"; SearchInput 0; } + } + search { + bind "c" { SearchToggleOption "CaseSensitivity"; } + bind "n" { Search "down"; } + bind "o" { SearchToggleOption "WholeWord"; } + bind "p" { Search "up"; } + bind "w" { SearchToggleOption "Wrap"; } + } + session { + bind "c" { + LaunchOrFocusPlugin "configuration" { + floating true + move_to_focused_tab true + } + SwitchToMode "normal" + } + bind "Ctrl o" { SwitchToMode "normal"; } + bind "p" { + LaunchOrFocusPlugin "plugin-manager" { + floating true + move_to_focused_tab true + } + SwitchToMode "normal" + } + bind "w" { + LaunchOrFocusPlugin "session-manager" { + floating true + move_to_focused_tab true + } + SwitchToMode "normal" + } + } + shared_except "locked" { + bind "Alt left" { MoveFocusOrTab "left"; } + bind "Alt down" { MoveFocus "down"; } + bind "Alt up" { MoveFocus "up"; } + bind "Alt right" { MoveFocusOrTab "right"; } + bind "Alt +" { Resize "Increase"; } + bind "Alt -" { Resize "Decrease"; } + bind "Alt =" { Resize "Increase"; } + bind "Alt [" { PreviousSwapLayout; } + bind "Alt ]" { NextSwapLayout; } + bind "Alt f" { ToggleFloatingPanes; } + bind "Ctrl g" { SwitchToMode "locked"; } + bind "Alt h" { MoveFocusOrTab "left"; } + bind "Alt i" { MoveTab "left"; } + bind "Alt j" { MoveFocus "down"; } + bind "Alt k" { MoveFocus "up"; } + bind "Alt l" { MoveFocusOrTab "right"; } + bind "Alt n" { NewPane; } + bind "Alt o" { MoveTab "right"; } + bind "Ctrl q" { Quit; } + } + shared_except "locked" "move" { + bind "Ctrl h" { SwitchToMode "move"; } + } + shared_except "locked" "session" { + bind "Ctrl o" { SwitchToMode "session"; } + } + shared_except "locked" "scroll" "search" "tmux" { + bind "Ctrl b" { SwitchToMode "tmux"; } + } + shared_except "locked" "scroll" "search" { + bind "Ctrl s" { SwitchToMode "scroll"; } + } + shared_except "locked" "tab" { + bind "Ctrl t" { SwitchToMode "tab"; } + } + shared_except "locked" "pane" { + bind "Ctrl p" { SwitchToMode "pane"; } + } + shared_except "locked" "resize" { + bind "Ctrl n" { SwitchToMode "resize"; } + } + shared_except "normal" "locked" "entersearch" { + bind "enter" { SwitchToMode "normal"; } + } + shared_except "normal" "locked" "entersearch" "renametab" "renamepane" { + bind "esc" { SwitchToMode "normal"; } + } + shared_among "pane" "tmux" { + bind "x" { CloseFocus; SwitchToMode "normal"; } + } + shared_among "scroll" "search" { + bind "PageDown" { PageScrollDown; } + bind "PageUp" { PageScrollUp; } + bind "left" { PageScrollUp; } + bind "down" { ScrollDown; } + bind "up" { ScrollUp; } + bind "right" { PageScrollDown; } + bind "Ctrl b" { PageScrollUp; } + bind "Ctrl c" { ScrollToBottom; SwitchToMode "normal"; } + bind "d" { HalfPageScrollDown; } + bind "Ctrl f" { PageScrollDown; } + bind "h" { PageScrollUp; } + bind "j" { ScrollDown; } + bind "k" { ScrollUp; } + bind "l" { PageScrollDown; } + bind "Ctrl s" { SwitchToMode "normal"; } + bind "u" { HalfPageScrollUp; } + } + entersearch { + bind "Ctrl c" { SwitchToMode "scroll"; } + bind "esc" { SwitchToMode "scroll"; } + bind "enter" { SwitchToMode "search"; } + } + renametab { + bind "esc" { UndoRenameTab; SwitchToMode "tab"; } + } + shared_among "renametab" "renamepane" { + bind "Ctrl c" { SwitchToMode "normal"; } + } + renamepane { + bind "esc" { UndoRenamePane; SwitchToMode "pane"; } + } + shared_among "session" "tmux" { + bind "d" { Detach; } + } + tmux { + bind "left" { MoveFocus "left"; SwitchToMode "normal"; } + bind "down" { MoveFocus "down"; SwitchToMode "normal"; } + bind "up" { MoveFocus "up"; SwitchToMode "normal"; } + bind "right" { MoveFocus "right"; SwitchToMode "normal"; } + bind "space" { NextSwapLayout; } + bind "\"" { NewPane "down"; SwitchToMode "normal"; } + bind "%" { NewPane "right"; SwitchToMode "normal"; } + bind "," { SwitchToMode "renametab"; } + bind "[" { SwitchToMode "scroll"; } + bind "Ctrl b" { Write 2; SwitchToMode "normal"; } + bind "c" { NewTab; SwitchToMode "normal"; } + bind "h" { MoveFocus "left"; SwitchToMode "normal"; } + bind "j" { MoveFocus "down"; SwitchToMode "normal"; } + bind "k" { MoveFocus "up"; SwitchToMode "normal"; } + bind "l" { MoveFocus "right"; SwitchToMode "normal"; } + bind "n" { GoToNextTab; SwitchToMode "normal"; } + bind "o" { FocusNextPane; } + bind "p" { GoToPreviousTab; SwitchToMode "normal"; } + bind "z" { ToggleFocusFullscreen; SwitchToMode "normal"; } + } + } + + // Plugin aliases - can be used to change the implementation of Zellij + // changing these requires a restart to take effect + plugins { + compact-bar location="zellij:compact-bar" + configuration location="zellij:configuration" + filepicker location="zellij:strider" { + cwd "/" + } + plugin-manager location="zellij:plugin-manager" + session-manager location="zellij:session-manager" + status-bar location="zellij:status-bar" + strider location="zellij:strider" + tab-bar location="zellij:tab-bar" + welcome-screen location="zellij:session-manager" { + welcome_screen true + } + } + + // Plugins to load in the background when a new session starts + // eg. "file:/path/to/my-plugin.wasm" + // eg. "https://example.com/my-plugin.wasm" + load_plugins { + } + + // Provide a command to execute when copying text. The text will be piped to + // the stdin of the program to perform the copy. This can be used with + // terminal emulators which do not support the OSC 52 ANSI control sequence + // that will be used by default if this option is not set. + // Examples: + // + // copy_command "xclip -selection clipboard" // x11 + // copy_command "wl-copy" // wayland + // copy_command "pbcopy" // osx + // + // copy_command "pbcopy" + + // Choose the destination for copied text + // Allows using the primary selection buffer (on x11/wayland) instead of the system clipboard. + // Does not apply when using copy_command. + // Options: + // - system (default) + // - primary + // + // copy_clipboard "primary" + + // Path to the default editor to use to edit pane scrollbuffer + // Default: $EDITOR or $VISUAL + // scrollback_editor "/usr/bin/vim" + + // Toggle between having Zellij lay out panes according to a predefined set of layouts whenever possible + // Options: + // - true (default) + // - false + // + // auto_layout false + + // Whether sessions should be serialized to the cache folder (including their tabs/panes, cwds and running commands) so that they can later be resurrected + // Options: + // - true (default) + // - false + // + // session_serialization false + + // Whether pane viewports are serialized along with the session, default is false + // Options: + // - true + // - false (default) + // + // serialize_pane_viewport false + + // Scrollback lines to serialize along with the pane viewport when serializing sessions, 0 + // defaults to the scrollback size. If this number is higher than the scrollback size, it will + // also default to the scrollback size. This does nothing if `serialize_pane_viewport` is not true. + // + // scrollback_lines_to_serialize 10000 + + // Enable or disable the rendering of styled and colored underlines (undercurl). + // May need to be disabled for certain unsupported terminals + // (Requires restart) + // Default: true + // + // styled_underlines false + + // How often in seconds sessions are serialized + // + // serialization_interval 10000 + + // Enable or disable writing of session metadata to disk (if disabled, other sessions might not know + // metadata info on this session) + // (Requires restart) + // Default: false + // + // disable_session_metadata false + + // Enable or disable support for the enhanced Kitty Keyboard Protocol (the host terminal must also support it) + // (Requires restart) + // Default: true (if the host terminal supports it) + // + // support_kitty_keyboard_protocol false +'' diff --git a/files/zellij/layouts/swarsel.kdl.nix b/files/zellij/layouts/swarsel.kdl.nix new file mode 100644 index 0000000..170115a --- /dev/null +++ b/files/zellij/layouts/swarsel.kdl.nix @@ -0,0 +1,159 @@ +{ config, pkgs }: +let + inherit (config.lib.stylix) colors; +in +'' + layout { + swap_tiled_layout name="vertical" { + tab max_panes=5 { + pane split_direction="vertical" { + pane + pane { children; } + } + } + tab max_panes=8 { + pane split_direction="vertical" { + pane { children; } + pane { pane; pane; pane; pane; } + } + } + tab max_panes=12 { + pane split_direction="vertical" { + pane { children; } + pane { pane; pane; pane; pane; } + pane { pane; pane; pane; pane; } + } + } + } + + swap_tiled_layout name="horizontal" { + tab max_panes=5 { + pane + pane + } + tab max_panes=8 { + pane { + pane split_direction="vertical" { children; } + pane split_direction="vertical" { pane; pane; pane; pane; } + } + } + tab max_panes=12 { + pane { + pane split_direction="vertical" { children; } + pane split_direction="vertical" { pane; pane; pane; pane; } + pane split_direction="vertical" { pane; pane; pane; pane; } + } + } + } + + swap_tiled_layout name="stacked" { + tab min_panes=5 { + pane split_direction="vertical" { + pane + pane stacked=true { children; } + } + } + } + + swap_floating_layout name="staggered" { + floating_panes + } + + swap_floating_layout name="enlarged" { + floating_panes max_panes=10 { + pane { x "5%"; y 1; width "90%"; height "90%"; } + pane { x "5%"; y 2; width "90%"; height "90%"; } + pane { x "5%"; y 3; width "90%"; height "90%"; } + pane { x "5%"; y 4; width "90%"; height "90%"; } + pane { x "5%"; y 5; width "90%"; height "90%"; } + pane { x "5%"; y 6; width "90%"; height "90%"; } + pane { x "5%"; y 7; width "90%"; height "90%"; } + pane { x "5%"; y 8; width "90%"; height "90%"; } + pane { x "5%"; y 9; width "90%"; height "90%"; } + pane focus=true { x 10; y 10; width "90%"; height "90%"; } + } + } + + swap_floating_layout name="spread" { + floating_panes max_panes=1 { + pane {y "50%"; x "50%"; } + } + floating_panes max_panes=2 { + pane { x "1%"; y "25%"; width "45%"; } + pane { x "50%"; y "25%"; width "45%"; } + } + floating_panes max_panes=3 { + pane focus=true { y "55%"; width "45%"; height "45%"; } + pane { x "1%"; y "1%"; width "45%"; } + pane { x "50%"; y "1%"; width "45%"; } + } + floating_panes max_panes=4 { + pane { x "1%"; y "55%"; width "45%"; height "45%"; } + pane focus=true { x "50%"; y "55%"; width "45%"; height "45%"; } + pane { x "1%"; y "1%"; width "45%"; height "45%"; } + pane { x "50%"; y "1%"; width "45%"; height "45%"; } + } + } + + default_tab_template { + children + pane size=1 borderless=true { + plugin location="file://${pkgs.zjstatus}/bin/zjstatus.wasm" { + format_left "{mode}#[bg=#${colors.base00}] {tabs}" + format_center "" + format_right "#[bg=#${colors.base00},fg=#${colors.base02}]#[bg=#${colors.base02},fg=#${colors.base01},bold] #[bg=#${colors.base02},fg=#${colors.base01},bold] {session} #[bg=#${colors.base02},fg=#${colors.base01},bold]" + format_space "" + format_hide_on_overlength "false" + format_precedence "lcr" + + border_enabled "false" + border_char "─" + border_format "#[fg=#6C7086]{char}" + border_position "top" + + mode_normal "#[bg=#${colors.base0B},fg=#${colors.base01},bold] NORMAL#[bg=#${colors.base01},fg=#${colors.base0B}]█" + mode_locked "#[bg=#${colors.base04},fg=#${colors.base01},bold] LOCKED #[bg=#${colors.base01},fg=#${colors.base04}]█" + mode_resize "#[bg=#${colors.base08},fg=#${colors.base01},bold] RESIZE#[bg=#${colors.base01},fg=#${colors.base08}]█" + mode_pane "#[bg=#${colors.base0D},fg=#${colors.base01},bold] PANE#[bg=#${colors.base01},fg=#${colors.base0D}]█" + mode_tab "#[bg=#${colors.base07},fg=#${colors.base01},bold] TAB#[bg=#${colors.base01},fg=#${colors.base07}]█" + mode_scroll "#[bg=#${colors.base0A},fg=#${colors.base01},bold] SCROLL#[bg=#${colors.base01},fg=#${colors.base0A}]█" + mode_enter_search "#[bg=#${colors.base0D},fg=#${colors.base01},bold] ENT-SEARCH#[bg=#${colors.base01},fg=#${colors.base0D}]█" + mode_search "#[bg=#${colors.base0D},fg=#${colors.base01},bold] SEARCHARCH#[bg=#${colors.base01},fg=#${colors.base0D}]█" + mode_rename_tab "#[bg=#${colors.base07},fg=#${colors.base01},bold] RENAME-TAB#[bg=#${colors.base01},fg=#${colors.base07}]█" + mode_rename_pane "#[bg=#${colors.base0D},fg=#${colors.base01},bold] RENAME-PANE#[bg=#${colors.base01},fg=#${colors.base0D}]█" + mode_session "#[bg=#${colors.base0E},fg=#${colors.base01},bold] SESSION#[bg=#${colors.base01},fg=#${colors.base0E}]█" + mode_move "#[bg=#${colors.base0F},fg=#${colors.base01},bold] MOVE#[bg=#${colors.base01},fg=#${colors.base0F}]█" + mode_prompt "#[bg=#${colors.base0D},fg=#${colors.base01},bold] PROMPT#[bg=#${colors.base01},fg=#${colors.base0D}]█" + mode_tmux "#[bg=#${colors.base09},fg=#${colors.base01},bold] TMUX#[bg=#${colors.base01},fg=#${colors.base09}]█" + + // formatting for inactive tabs + tab_normal "#[bg=#${colors.base01},fg=#${colors.base0C}]█#[bg=#${colors.base0C},fg=#${colors.base01},bold]{index} #[bg=#${colors.base01},fg=#${colors.base0C},bold] {name}{floating_indicator}#[bg=#${colors.base01},fg=#${colors.base01},bold]█" + tab_normal_fullscreen "#[bg=#${colors.base01},fg=#${colors.base0C}]█#[bg=#${colors.base0C},fg=#${colors.base01},bold]{index} #[bg=#${colors.base01},fg=#${colors.base0C},bold] {name}{fullscreen_indicator}#[bg=#${colors.base01},fg=#${colors.base01},bold]█" + tab_normal_sync "#[bg=#${colors.base01},fg=#${colors.base0C}]█#[bg=#${colors.base0C},fg=#${colors.base01},bold]{index} #[bg=#${colors.base01},fg=#${colors.base0C},bold] {name}{sync_indicator}#[bg=#${colors.base01},fg=#${colors.base01},bold]█" + + // formatting for the current active tab + tab_active "#[bg=#${colors.base01},fg=#${colors.base09}]█#[bg=#${colors.base09},fg=#${colors.base01},bold]{index} #[bg=#${colors.base01},fg=#${colors.base09},bold] {name}{floating_indicator}#[bg=#${colors.base01},fg=#${colors.base01},bold]█" + tab_active_fullscreen "#[bg=#${colors.base01},fg=#${colors.base09}]█#[bg=#${colors.base09},fg=#${colors.base01},bold]{index} #[bg=#${colors.base01},fg=#${colors.base09},bold] {name}{fullscreen_indicator}#[bg=#${colors.base01},fg=#${colors.base01},bold]█" + tab_active_sync "#[bg=#${colors.base01},fg=#${colors.base09}]█#[bg=#${colors.base09},fg=#${colors.base01},bold]{index} #[bg=#${colors.base01},fg=#${colors.base09},bold] {name}{sync_indicator}#[bg=#${colors.base01},fg=#${colors.base01},bold]█" + + // separator between the tabs + tab_separator "#[bg=#${colors.base00}] " + + // indicators + tab_sync_indicator " " + tab_fullscreen_indicator " 󰊓" + tab_floating_indicator " 󰹙" + + command_git_branch_command "git rev-parse --abbrev-ref HEAD" + command_git_branch_format "#[fg=blue] {stdout} " + command_git_branch_interval "10" + command_git_branch_rendermode "static" + + datetime "#[fg=#6C7086,bold] {format} " + datetime_format "%A, %d %b %Y %H:%M" + datetime_timezone "Europe/Vienna" + } + } + } + } +'' diff --git a/flake.lock b/flake.lock index c46045b..de60846 100644 --- a/flake.lock +++ b/flake.lock @@ -5,11 +5,11 @@ "fromYaml": "fromYaml" }, "locked": { - "lastModified": 1732200724, - "narHash": "sha256-+R1BH5wHhfnycySb7Sy5KbYEaTJZWm1h+LW1OtyhiTs=", + "lastModified": 1755819240, + "narHash": "sha256-qcMhnL7aGAuFuutH4rq9fvAhCpJWVHLcHVZLtPctPlo=", "owner": "SenchoPens", "repo": "base16.nix", - "rev": "153d52373b0fb2d343592871009a286ec8837aec", + "rev": "75ed5e5e3fce37df22e49125181fa37899c3ccd6", "type": "github" }, "original": { @@ -21,27 +21,28 @@ "base16-fish": { "flake": false, "locked": { - "lastModified": 1622559957, - "narHash": "sha256-PebymhVYbL8trDVVXxCvZgc0S5VxI7I1Hv4RMSquTpA=", + "lastModified": 1754405784, + "narHash": "sha256-l9xHIy+85FN+bEo6yquq2IjD1rSg9fjfjpyGP1W8YXo=", "owner": "tomyun", "repo": "base16-fish", - "rev": "2f6dd973a9075dabccd26f1cded09508180bf5fe", + "rev": "23ae20a0093dca0d7b39d76ba2401af0ccf9c561", "type": "github" }, "original": { "owner": "tomyun", "repo": "base16-fish", + "rev": "23ae20a0093dca0d7b39d76ba2401af0ccf9c561", "type": "github" } }, "base16-helix": { "flake": false, "locked": { - "lastModified": 1725860795, - "narHash": "sha256-Z2o8VBPW3I+KKTSfe25kskz0EUj7MpUh8u355Z1nVsU=", + "lastModified": 1752979451, + "narHash": "sha256-0CQM+FkYy0fOO/sMGhOoNL80ftsAzYCg9VhIrodqusM=", "owner": "tinted-theming", "repo": "base16-helix", - "rev": "7f795bf75d38e0eea9fed287264067ca187b88a9", + "rev": "27cf1e66e50abc622fb76a3019012dc07c678fac", "type": "github" }, "original": { @@ -53,26 +54,58 @@ "base16-vim": { "flake": false, "locked": { - "lastModified": 1731949548, - "narHash": "sha256-XIDexXM66sSh5j/x70e054BnUsviibUShW7XhbDGhYo=", + "lastModified": 1732806396, + "narHash": "sha256-e0bpPySdJf0F68Ndanwm+KWHgQiZ0s7liLhvJSWDNsA=", "owner": "tinted-theming", "repo": "base16-vim", - "rev": "61165b1632409bd55e530f3dbdd4477f011cadc6", + "rev": "577fe8125d74ff456cf942c733a85d769afe58b7", "type": "github" }, "original": { "owner": "tinted-theming", "repo": "base16-vim", + "rev": "577fe8125d74ff456cf942c733a85d769afe58b7", "type": "github" } }, + "blank": { + "locked": { + "lastModified": 1625557891, + "narHash": "sha256-O8/MWsPBGhhyPoPLHZAuoZiiHo9q6FLlEeIDEXuj6T4=", + "owner": "divnix", + "repo": "blank", + "rev": "5a5d2684073d9f563072ed07c871d577a6c614a8", + "type": "github" + }, + "original": { + "owner": "divnix", + "repo": "blank", + "type": "github" + } + }, + "blobs": { + "flake": false, + "locked": { + "lastModified": 1604995301, + "narHash": "sha256-wcLzgLec6SGJA8fx1OEN1yV/Py5b+U5iyYpksUY/yLw=", + "owner": "simple-nixos-mailserver", + "repo": "blobs", + "rev": "2cccdf1ca48316f2cfd1c9a0017e8de5a7156265", + "type": "gitlab" + }, + "original": { + "owner": "simple-nixos-mailserver", + "repo": "blobs", + "type": "gitlab" + } + }, "crane": { "locked": { - "lastModified": 1730652660, - "narHash": "sha256-+XVYfmVXAiYA0FZT7ijHf555dxCe+AoAT5A6RU+6vSo=", + "lastModified": 1763938834, + "narHash": "sha256-j8iB0Yr4zAvQLueCZ5abxfk6fnG/SJ5JnGUziETjwfg=", "owner": "ipetkov", "repo": "crane", - "rev": "a4ca93905455c07cb7e3aca95d4faf7601cba458", + "rev": "d9e753122e51cee64eb8d2dddfe11148f339f5a2", "type": "github" }, "original": { @@ -82,12 +115,24 @@ } }, "crane_2": { + "inputs": { + "flake-compat": "flake-compat_5", + "flake-utils": "flake-utils_7", + "nixpkgs": [ + "nixos-extra-modules", + "nixt", + "std", + "paisano-mdbook-preprocessor", + "nixpkgs" + ], + "rust-overlay": "rust-overlay_2" + }, "locked": { - "lastModified": 1732906089, - "narHash": "sha256-NvYSSiKsC0rqn9yY0a9zglLXrFp92EwKhTFZC38voCQ=", + "lastModified": 1676162383, + "narHash": "sha256-krUCKdz7ebHlFYm/A7IbKDnj2ZmMMm3yIEQcooqm7+E=", "owner": "ipetkov", "repo": "crane", - "rev": "9ed3180f45c2d1499e5af98c4ab7ffee8e886f5f", + "rev": "6fb400ec631b22ccdbc7090b38207f7fb5cfb5f2", "type": "github" }, "original": { @@ -96,18 +141,120 @@ "type": "github" } }, + "crane_3": { + "locked": { + "lastModified": 1754269165, + "narHash": "sha256-0tcS8FHd4QjbCVoxN9jI+PjHgA4vc/IjkUSp+N3zy0U=", + "owner": "ipetkov", + "repo": "crane", + "rev": "444e81206df3f7d92780680e45858e31d2f07a08", + "type": "github" + }, + "original": { + "owner": "ipetkov", + "repo": "crane", + "type": "github" + } + }, + "devshell": { + "inputs": { + "nixpkgs": "nixpkgs" + }, + "locked": { + "lastModified": 1762521437, + "narHash": "sha256-RXN+lcx4DEn3ZS+LqEJSUu/HH+dwGvy0syN7hTo/Chg=", + "owner": "numtide", + "repo": "devshell", + "rev": "07bacc9531f5f4df6657c0a02a806443685f384a", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "devshell", + "type": "github" + } + }, + "devshell_2": { + "inputs": { + "nixpkgs": [ + "nix-topology", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1728330715, + "narHash": "sha256-xRJ2nPOXb//u1jaBnDP56M7v5ldavjbtR6lfGqSvcKg=", + "owner": "numtide", + "repo": "devshell", + "rev": "dd6b80932022cea34a019e2bb32f6fa9e494dfef", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "devshell", + "type": "github" + } + }, + "devshell_3": { + "inputs": { + "nixpkgs": [ + "nixos-extra-modules", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1735644329, + "narHash": "sha256-tO3HrHriyLvipc4xr+Ewtdlo7wM1OjXNjlWRgmM7peY=", + "owner": "numtide", + "repo": "devshell", + "rev": "f7795ede5b02664b57035b3b757876703e2c3eac", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "devshell", + "type": "github" + } + }, + "devshell_4": { + "inputs": { + "flake-utils": [ + "nixos-extra-modules", + "nixt", + "std", + "flake-utils" + ], + "nixpkgs": [ + "nixos-extra-modules", + "nixt", + "std", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1682700442, + "narHash": "sha256-qjaAAcCYgp1pBBG7mY9z95ODUBZMtUpf0Qp3Gt/Wha0=", + "owner": "numtide", + "repo": "devshell", + "rev": "fb6673fe9fe4409e3f43ca86968261e970918a83", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "devshell", + "type": "github" + } + }, "disko": { "inputs": { - "nixpkgs": [ - "nixpkgs" - ] + "nixpkgs": "nixpkgs_2" }, "locked": { - "lastModified": 1733168902, - "narHash": "sha256-8dupm9GfK+BowGdQd7EHK5V61nneLfr9xR6sc5vtDi0=", + "lastModified": 1763651264, + "narHash": "sha256-8vvwZbw0s7YvBMJeyPVpWke6lg6ROgtts5N2/SMCcv4=", "owner": "nix-community", "repo": "disko", - "rev": "785c1e02c7e465375df971949b8dcbde9ec362e5", + "rev": "e86a89079587497174ccab6d0d142a65811a4fd9", "type": "github" }, "original": { @@ -116,35 +263,121 @@ "type": "github" } }, - "emacs-overlay": { + "dmerge": { "inputs": { - "nixpkgs": [ + "haumea": "haumea", + "namaka": "namaka", + "nixlib": [ + "nixos-extra-modules", + "nixt", + "std", "nixpkgs" ], + "yants": [ + "nixos-extra-modules", + "nixt", + "std", + "yants" + ] + }, + "locked": { + "lastModified": 1684178600, + "narHash": "sha256-EtSQcCHRQUBBEj4vbYU0vgPUYiKP261ero5k1QfQ3Bc=", + "owner": "divnix", + "repo": "dmerge", + "rev": "ac9932f26325afac5baa59cf6478432d17762a4e", + "type": "github" + }, + "original": { + "owner": "divnix", + "ref": "0.2.0", + "repo": "dmerge", + "type": "github" + } + }, + "dns": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs_3" + }, + "locked": { + "lastModified": 1759510210, + "narHash": "sha256-rR3BuhcSyQ3bQ0rS14I53O7gWzlPEs15skl1TWx+TeI=", + "owner": "kirelagin", + "repo": "dns.nix", + "rev": "f3cb11f642d4fa6224e2b1ddfd2c3ba42e9ffea2", + "type": "github" + }, + "original": { + "owner": "kirelagin", + "repo": "dns.nix", + "type": "github" + } + }, + "emacs-overlay": { + "inputs": { + "nixpkgs": "nixpkgs_4", "nixpkgs-stable": "nixpkgs-stable" }, "locked": { - "lastModified": 1733736037, - "narHash": "sha256-J+l1D+/hcp4LkEvOdYn17dcDvRN1JEcfF54pNgXUoag=", + "lastModified": 1760432944, + "narHash": "sha256-4OXXccXsY1sBXTXjYIthdjXLAotozSh4F8StGRuLyMQ=", "owner": "nix-community", "repo": "emacs-overlay", - "rev": "5801bf5202cd0fea8637d3891040669f46813a95", + "rev": "aba8daa237dc07a3bb28a61c252a718e8eb38057", + "type": "github" + }, + "original": { + "narHash": "sha256-4OXXccXsY1sBXTXjYIthdjXLAotozSh4F8StGRuLyMQ=", + "owner": "nix-community", + "repo": "emacs-overlay", + "rev": "aba8daa237dc07a3bb28a61c252a718e8eb38057", + "type": "github" + } + }, + "fenix": { + "inputs": { + "nixpkgs": "nixpkgs_14", + "rust-analyzer-src": "rust-analyzer-src" + }, + "locked": { + "lastModified": 1677306201, + "narHash": "sha256-VZ9x7qdTosFvVsrpgFHrtYfT6PU3yMIs7NRYn9ELapI=", + "owner": "nix-community", + "repo": "fenix", + "rev": "0923f0c162f65ae40261ec940406049726cfeab4", "type": "github" }, "original": { "owner": "nix-community", - "repo": "emacs-overlay", + "repo": "fenix", + "type": "github" + } + }, + "firefox-gnome-theme": { + "flake": false, + "locked": { + "lastModified": 1758112371, + "narHash": "sha256-lizRM2pj6PHrR25yimjyFn04OS4wcdbc38DCdBVa2rk=", + "owner": "rafaelmardojai", + "repo": "firefox-gnome-theme", + "rev": "0909cfe4a2af8d358ad13b20246a350e14c2473d", + "type": "github" + }, + "original": { + "owner": "rafaelmardojai", + "repo": "firefox-gnome-theme", "type": "github" } }, "flake-compat": { "flake": false, "locked": { - "lastModified": 1696426674, - "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "lastModified": 1747046372, + "narHash": "sha256-CIVLLkVgvHYbgI2UpXvIIBJ12HWgX+fjA8Xf8PUmqCY=", "owner": "edolstra", "repo": "flake-compat", - "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "rev": "9100a0f413b0c601e0533d1d94ffd501ce2e7885", "type": "github" }, "original": { @@ -156,11 +389,11 @@ "flake-compat_2": { "flake": false, "locked": { - "lastModified": 1696426674, - "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "lastModified": 1747046372, + "narHash": "sha256-CIVLLkVgvHYbgI2UpXvIIBJ12HWgX+fjA8Xf8PUmqCY=", "owner": "edolstra", "repo": "flake-compat", - "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "rev": "9100a0f413b0c601e0533d1d94ffd501ce2e7885", "type": "github" }, "original": { @@ -170,6 +403,7 @@ } }, "flake-compat_3": { + "flake": false, "locked": { "lastModified": 1696426674, "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", @@ -187,11 +421,11 @@ "flake-compat_4": { "flake": false, "locked": { - "lastModified": 1696426674, - "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "lastModified": 1673956053, + "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", "owner": "edolstra", "repo": "flake-compat", - "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", "type": "github" }, "original": { @@ -201,6 +435,22 @@ } }, "flake-compat_5": { + "flake": false, + "locked": { + "lastModified": 1673956053, + "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-compat_6": { "flake": false, "locked": { "lastModified": 1696426674, @@ -216,19 +466,48 @@ "type": "github" } }, + "flake-compat_7": { + "flake": false, + "locked": { + "lastModified": 1761588595, + "narHash": "sha256-XKUZz9zewJNUj46b4AJdiRZJAvSZ0Dqj2BNfXvFlJC4=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "f387cd2afec9419c8ee37694406ca490c3f34ee5", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-compat_8": { + "flake": false, + "locked": { + "lastModified": 1761588595, + "narHash": "sha256-XKUZz9zewJNUj46b4AJdiRZJAvSZ0Dqj2BNfXvFlJC4=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "f387cd2afec9419c8ee37694406ca490c3f34ee5", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, "flake-parts": { "inputs": { - "nixpkgs-lib": [ - "lanzaboote", - "nixpkgs" - ] + "nixpkgs-lib": "nixpkgs-lib" }, "locked": { - "lastModified": 1730504689, - "narHash": "sha256-hgmguH29K2fvs9szpq2r3pz2/8cJd2LPS+b4tfNFCwE=", + "lastModified": 1763759067, + "narHash": "sha256-LlLt2Jo/gMNYAwOgdRQBrsRoOz7BPRkzvNaI/fzXi2Q=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "506278e768c2a08bec68eb62932193e341f55c90", + "rev": "2cccadc7357c0ba201788ae99c4dfa90728ef5e0", "type": "github" }, "original": { @@ -239,7 +518,25 @@ }, "flake-parts_2": { "inputs": { - "nixpkgs-lib": "nixpkgs-lib" + "nixpkgs-lib": "nixpkgs-lib_2" + }, + "locked": { + "lastModified": 1738453229, + "narHash": "sha256-7H9XgNiGLKN1G1CgRh0vUL4AheZSYzPm+zmZ7vxbJdo=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "32ea77a06711b758da0ad9bd6a844c5740a87abd", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-parts_3": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib_3" }, "locked": { "lastModified": 1719994518, @@ -254,7 +551,7 @@ "type": "indirect" } }, - "flake-parts_3": { + "flake-parts_4": { "inputs": { "nixpkgs-lib": [ "nur", @@ -275,7 +572,61 @@ "type": "github" } }, + "flake-parts_5": { + "inputs": { + "nixpkgs-lib": [ + "stylix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1756770412, + "narHash": "sha256-+uWLQZccFHwqpGqr2Yt5VsW/PbeJVTn9Dk6SHWhNRPw=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "4524271976b625a4a605beefd893f270620fd751", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-parts_6": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib_4" + }, + "locked": { + "lastModified": 1759362264, + "narHash": "sha256-wfG0S7pltlYyZTM+qqlhJ7GMw2fTF4mLKCIVhLii/4M=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "758cf7296bee11f1706a574c77d072b8a7baa881", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, "flake-utils": { + "locked": { + "lastModified": 1614513358, + "narHash": "sha256-LakhOx3S1dRjnh0b5Dg3mbZyH0ToC9I8Y2wKSkBaTzU=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "5466c5bbece17adaab2d82fae80b46e807611bf3", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_2": { "inputs": { "systems": "systems" }, @@ -293,27 +644,9 @@ "type": "github" } }, - "flake-utils_2": { - "locked": { - "lastModified": 1659877975, - "narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, "flake-utils_3": { "inputs": { - "systems": [ - "stylix", - "systems" - ] + "systems": "systems_2" }, "locked": { "lastModified": 1731533236, @@ -330,6 +663,24 @@ } }, "flake-utils_4": { + "inputs": { + "systems": "systems_3" + }, + "locked": { + "lastModified": 1726560853, + "narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_5": { "inputs": { "systems": "systems_4" }, @@ -347,6 +698,54 @@ "type": "github" } }, + "flake-utils_6": { + "locked": { + "lastModified": 1659877975, + "narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_7": { + "locked": { + "lastModified": 1667395993, + "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_8": { + "inputs": { + "systems": "systems_10" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, "fromYaml": { "flake": false, "locked": { @@ -363,25 +762,29 @@ "type": "github" } }, - "fw-fanctrl": { + "git-hooks": { "inputs": { - "flake-compat": "flake-compat", + "flake-compat": [ + "simple-nixos-mailserver", + "flake-compat" + ], + "gitignore": "gitignore_5", "nixpkgs": [ + "simple-nixos-mailserver", "nixpkgs" ] }, "locked": { - "lastModified": 1724704488, - "narHash": "sha256-QmAanotjk81zsCwHI52XS4u9Cjv6KjNzTkYsAYFrubM=", - "owner": "TamtamHero", - "repo": "fw-fanctrl", - "rev": "db96c5962cff24f4c5977e30ca1c7626fb4171c7", + "lastModified": 1763319842, + "narHash": "sha256-YG19IyrTdnVn0l3DvcUYm85u3PaqBt6tI6VvolcuHnA=", + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "7275fa67fbbb75891c16d9dee7d88e58aea2d761", "type": "github" }, "original": { - "owner": "TamtamHero", - "ref": "packaging/nix", - "repo": "fw-fanctrl", + "owner": "cachix", + "repo": "git-hooks.nix", "type": "github" } }, @@ -389,7 +792,7 @@ "inputs": { "nixpkgs": [ "lanzaboote", - "pre-commit-hooks-nix", + "pre-commit", "nixpkgs" ] }, @@ -410,6 +813,7 @@ "gitignore_2": { "inputs": { "nixpkgs": [ + "nix-topology", "pre-commit-hooks", "nixpkgs" ] @@ -428,20 +832,111 @@ "type": "github" } }, + "gitignore_3": { + "inputs": { + "nixpkgs": [ + "nixos-extra-modules", + "pre-commit-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, + "gitignore_4": { + "inputs": { + "nixpkgs": [ + "pre-commit-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, + "gitignore_5": { + "inputs": { + "nixpkgs": [ + "simple-nixos-mailserver", + "git-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, "gnome-shell": { "flake": false, "locked": { - "lastModified": 1732369855, - "narHash": "sha256-JhUWbcYPjHO3Xs3x9/Z9RuqXbcp5yhPluGjwsdE2GMg=", + "host": "gitlab.gnome.org", + "lastModified": 1762869044, + "narHash": "sha256-nwm/GJ2Syigf7VccLAZ66mFC8mZJFqpJmIxSGKl7+Ds=", "owner": "GNOME", "repo": "gnome-shell", - "rev": "dadd58f630eeea41d645ee225a63f719390829dc", + "rev": "680e3d195a92203f28d4bf8c6e8bb537cc3ed4ad", + "type": "gitlab" + }, + "original": { + "host": "gitlab.gnome.org", + "owner": "GNOME", + "ref": "gnome-49", + "repo": "gnome-shell", + "type": "gitlab" + } + }, + "haumea": { + "inputs": { + "nixpkgs": [ + "nixos-extra-modules", + "nixt", + "std", + "dmerge", + "nixlib" + ] + }, + "locked": { + "lastModified": 1681176209, + "narHash": "sha256-bJLDun6esIyWtwRVXcsgzGbh4UKu8wJDrPgykqPyzmg=", + "owner": "nix-community", + "repo": "haumea", + "rev": "b915b66b27da3a595d77b139e945bb0a2fcac926", "type": "github" }, "original": { - "owner": "GNOME", - "ref": "47.2", - "repo": "gnome-shell", + "owner": "nix-community", + "repo": "haumea", "type": "github" } }, @@ -452,15 +947,16 @@ ] }, "locked": { - "lastModified": 1733484277, - "narHash": "sha256-i5ay20XsvpW91N4URET/nOc0VQWOAd4c4vbqYtcH8Rc=", - "owner": "nix-community", + "lastModified": 1762257324, + "narHash": "sha256-05SxDx82j23zd1/EMDFZTPYFgvzxviBiByUBVs+860w=", + "owner": "Swarsel", "repo": "home-manager", - "rev": "d00c6f6d0ad16d598bf7e2956f52c1d9d5de3c3a", + "rev": "d27fabec395885790e7ab666c72522e18e534117", "type": "github" }, "original": { - "owner": "nix-community", + "owner": "Swarsel", + "ref": "main", "repo": "home-manager", "type": "github" } @@ -486,57 +982,57 @@ "type": "github" } }, - "home-manager_3": { + "impermanence": { + "locked": { + "lastModified": 1737831083, + "narHash": "sha256-LJggUHbpyeDvNagTUrdhe/pRVp4pnS6wVKALS782gRI=", + "owner": "nix-community", + "repo": "impermanence", + "rev": "4b3e914cdf97a5b536a889e939fb2fd2b043a170", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "impermanence", + "type": "github" + } + }, + "incl": { "inputs": { - "nixpkgs": [ - "stylix", + "nixlib": [ + "nixos-extra-modules", + "nixt", + "std", "nixpkgs" ] }, "locked": { - "lastModified": 1733085484, - "narHash": "sha256-dVmNuUajnU18oHzBQWZm1BQtANCHaqNuxTHZQ+GN0r8=", - "owner": "nix-community", - "repo": "home-manager", - "rev": "c1fee8d4a60b89cae12b288ba9dbc608ff298163", + "lastModified": 1669263024, + "narHash": "sha256-E/+23NKtxAqYG/0ydYgxlgarKnxmDbg6rCMWnOBqn9Q=", + "owner": "divnix", + "repo": "incl", + "rev": "ce7bebaee048e4cd7ebdb4cee7885e00c4e2abca", "type": "github" }, "original": { - "owner": "nix-community", - "repo": "home-manager", - "type": "github" - } - }, - "impermanence": { - "locked": { - "lastModified": 1731242966, - "narHash": "sha256-B3C3JLbGw0FtLSWCjBxU961gLNv+BOOBC6WvstKLYMw=", - "owner": "nix-community", - "repo": "impermanence", - "rev": "3ed3f0eaae9fcc0a8331e77e9319c8a4abd8a71a", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "impermanence", + "owner": "divnix", + "repo": "incl", "type": "github" } }, "lanzaboote": { "inputs": { "crane": "crane", - "flake-compat": "flake-compat_2", - "flake-parts": "flake-parts", - "nixpkgs": "nixpkgs", - "pre-commit-hooks-nix": "pre-commit-hooks-nix", + "nixpkgs": "nixpkgs_5", + "pre-commit": "pre-commit", "rust-overlay": "rust-overlay" }, "locked": { - "lastModified": 1731941836, - "narHash": "sha256-zpmAzrvK8KdssBSwiIwwRxaUJ77oWORbW0XFvgCFpTE=", + "lastModified": 1763975256, + "narHash": "sha256-IhdDL+0YwlLz5Ty0EnAxWN/btemN9FxcQbYs/V/8jvs=", "owner": "nix-community", "repo": "lanzaboote", - "rev": "2f48272f34174fd2a5ab3df4d8a46919247be879", + "rev": "6803b15c4ab9df2dcc478254b4adb55524746ac7", "type": "github" }, "original": { @@ -545,40 +1041,153 @@ "type": "github" } }, - "nix-alien": { + "microvm": { "inputs": { - "flake-compat": "flake-compat_3", - "flake-utils": "flake-utils", - "nix-filter": "nix-filter", - "nix-index-database": "nix-index-database", - "nixpkgs": "nixpkgs_2" + "flake-utils": "flake-utils_2", + "nixpkgs": "nixpkgs_6", + "spectrum": "spectrum" }, "locked": { - "lastModified": 1731668526, - "narHash": "sha256-ZszfGYOrwol3MGFpttahldT+UOfqXckk6XwZrUyHLxE=", - "owner": "thiagokokada", - "repo": "nix-alien", - "rev": "97fe58a8ac15663b1ecdebd84d2187eb71f8532d", + "lastModified": 1763928900, + "narHash": "sha256-4+5LVMFWSUppY5yvFFdV+T8Lc/rgSYEGx38/9Y20+EI=", + "owner": "astro", + "repo": "microvm.nix", + "rev": "e3e222005b29a78f85128573f3c6f09a11270c91", "type": "github" }, "original": { - "owner": "thiagokokada", - "repo": "nix-alien", + "owner": "astro", + "repo": "microvm.nix", + "type": "github" + } + }, + "n2c": { + "inputs": { + "flake-utils": [ + "nixos-extra-modules", + "nixt", + "std", + "flake-utils" + ], + "nixpkgs": [ + "nixos-extra-modules", + "nixt", + "std", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1677330646, + "narHash": "sha256-hUYCwJneMjnxTvj30Fjow6UMJUITqHlpUGpXMPXUJsU=", + "owner": "nlewo", + "repo": "nix2container", + "rev": "ebca8f58d450cae1a19c07701a5a8ae40afc9efc", + "type": "github" + }, + "original": { + "owner": "nlewo", + "repo": "nix2container", + "type": "github" + } + }, + "namaka": { + "inputs": { + "haumea": [ + "nixos-extra-modules", + "nixt", + "std", + "dmerge", + "haumea" + ], + "nixpkgs": [ + "nixos-extra-modules", + "nixt", + "std", + "dmerge", + "nixlib" + ] + }, + "locked": { + "lastModified": 1683059428, + "narHash": "sha256-ZTMqleCWmuNWhZE375gtF1j1JRkaKEUFN1AM43e7h4Y=", + "owner": "nix-community", + "repo": "namaka", + "rev": "2deba2f416454aec770bc1cc7365e39c73e6b1d7", + "type": "github" + }, + "original": { + "owner": "nix-community", + "ref": "v0.1.1", + "repo": "namaka", + "type": "github" + } + }, + "niri-flake": { + "inputs": { + "niri-stable": "niri-stable", + "niri-unstable": "niri-unstable", + "nixpkgs": "nixpkgs_7", + "nixpkgs-stable": "nixpkgs-stable_2", + "xwayland-satellite-stable": "xwayland-satellite-stable", + "xwayland-satellite-unstable": "xwayland-satellite-unstable" + }, + "locked": { + "lastModified": 1763995371, + "narHash": "sha256-Cbekq2OAWevdTayYMO7SCf05aGHPZ236MTyCkKyYZOs=", + "owner": "sodiboo", + "repo": "niri-flake", + "rev": "c4fb0f9d13fadf1b3c33e693509d8cdcbbd7d08e", + "type": "github" + }, + "original": { + "owner": "sodiboo", + "repo": "niri-flake", + "type": "github" + } + }, + "niri-stable": { + "flake": false, + "locked": { + "lastModified": 1756556321, + "narHash": "sha256-RLD89dfjN0RVO86C/Mot0T7aduCygPGaYbog566F0Qo=", + "owner": "YaLTeR", + "repo": "niri", + "rev": "01be0e65f4eb91a9cd624ac0b76aaeab765c7294", + "type": "github" + }, + "original": { + "owner": "YaLTeR", + "ref": "v25.08", + "repo": "niri", + "type": "github" + } + }, + "niri-unstable": { + "flake": false, + "locked": { + "lastModified": 1763990232, + "narHash": "sha256-RdtlZ+nufSwEgNsF0yuTOO2eGpn87Qm9b3tRQPsibH4=", + "owner": "YaLTeR", + "repo": "niri", + "rev": "45b45ac29d654c0e6759ab996c69dfde40053536", + "type": "github" + }, + "original": { + "owner": "YaLTeR", + "repo": "niri", "type": "github" } }, "nix-darwin": { "inputs": { - "nixpkgs": [ - "nixpkgs" - ] + "nixpkgs": "nixpkgs_8" }, "locked": { - "lastModified": 1733570843, - "narHash": "sha256-sQJAxY1TYWD1UyibN/FnN97paTFuwBw3Vp3DNCyKsMk=", + "lastModified": 1763505477, + "narHash": "sha256-nJRd4LY2kT3OELfHqdgWjvToNZ4w+zKCMzS2R6z4sXE=", "owner": "lnl7", "repo": "nix-darwin", - "rev": "a35b08d09efda83625bef267eb24347b446c80b8", + "rev": "3bda9f6b14161becbd07b3c56411f1670e19b9b5", "type": "github" }, "original": { @@ -587,21 +1196,6 @@ "type": "github" } }, - "nix-filter": { - "locked": { - "lastModified": 1731533336, - "narHash": "sha256-oRam5PS1vcrr5UPgALW0eo1m/5/pls27Z/pabHNy2Ms=", - "owner": "numtide", - "repo": "nix-filter", - "rev": "f7653272fd234696ae94229839a99b73c9ab7de0", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "nix-filter", - "type": "github" - } - }, "nix-formatter-pack": { "inputs": { "nixpkgs": [ @@ -628,16 +1222,15 @@ "nix-index-database": { "inputs": { "nixpkgs": [ - "nix-alien", "nixpkgs" ] }, "locked": { - "lastModified": 1731593150, - "narHash": "sha256-FvksinoI2Y6kuwH+cKBu1oDA8uPGfoRqgtQV6O8GDc4=", + "lastModified": 1763870992, + "narHash": "sha256-NPyc76Wxmv/vAsXJ8F+/8fXECHYcv2YGSqdiSHp/F/A=", "owner": "nix-community", "repo": "nix-index-database", - "rev": "40d882b55e89add1ded379cc99edaab24983d6d9", + "rev": "d7423982c7a26586aa237d130b14c8b302c7a367", "type": "github" }, "original": { @@ -646,23 +1239,23 @@ "type": "github" } }, - "nix-index-database_2": { + "nix-minecraft": { "inputs": { - "nixpkgs": [ - "nixpkgs" - ] + "flake-compat": "flake-compat_2", + "flake-utils": "flake-utils_3", + "nixpkgs": "nixpkgs_9" }, "locked": { - "lastModified": 1733629314, - "narHash": "sha256-U0vivjQFAwjNDYt49Krevs1murX9hKBFe2Ye0cHpgbU=", - "owner": "nix-community", - "repo": "nix-index-database", - "rev": "f1e477a7dd11e27e7f98b646349cd66bbabf2fb8", + "lastModified": 1763776632, + "narHash": "sha256-mvumw4Djwi6BgMKVKw5cpNt8a80+h/LvPy2AHOtzBzE=", + "owner": "Infinidoge", + "repo": "nix-minecraft", + "rev": "e6d3b589d9f1f869e68142f44654e59fcb47390c", "type": "github" }, "original": { - "owner": "nix-community", - "repo": "nix-index-database", + "owner": "Infinidoge", + "repo": "nix-minecraft", "type": "github" } }, @@ -670,9 +1263,7 @@ "inputs": { "home-manager": "home-manager_2", "nix-formatter-pack": "nix-formatter-pack", - "nixpkgs": [ - "nixpkgs" - ], + "nixpkgs": "nixpkgs_10", "nixpkgs-docs": "nixpkgs-docs", "nixpkgs-for-bootstrap": "nixpkgs-for-bootstrap", "nmd": "nmd_2" @@ -692,774 +1283,1936 @@ "type": "github" } }, - "nix-secrets": { - "flake": false, - "locked": { - "lastModified": 1733751889, - "narHash": "sha256-aPgutKC/saFgeVhNZcqkfHKv1/avqgVlc7ntpQe6Gxc=", - "ref": "main", - "rev": "447c64561b1ed92d66a7b2c8a3e63ef55b811393", - "shallow": true, - "type": "git", - "url": "ssh://git@github.com/Swarsel/nix-secrets.git" - }, - "original": { - "ref": "main", - "shallow": true, - "type": "git", - "url": "ssh://git@github.com/Swarsel/nix-secrets.git" - } + "nix-topology": { + "inputs": { + "devshell": "devshell_2", + "flake-utils": "flake-utils_4", + "nixpkgs": "nixpkgs_11", + "pre-commit-hooks": "pre-commit-hooks" }, - "nixgl": { - "inputs": { - "flake-utils": "flake-utils_2", - "nixpkgs": "nixpkgs_3" - }, - "locked": { - "lastModified": 1713543440, - "narHash": "sha256-lnzZQYG0+EXl/6NkGpyIz+FEOc/DSEG57AP1VsdeNrM=", - "owner": "guibou", - "repo": "nixGL", - "rev": "310f8e49a149e4c9ea52f1adf70cdc768ec53f8a", - "type": "github" - }, - "original": { - "owner": "guibou", - "repo": "nixGL", - "type": "github" - } + "locked": { + "lastModified": 1762088663, + "narHash": "sha256-rpCvFan9Dji1Vw4HfVqYdfWesz5sKZE3uSgYR9gRreA=", + "owner": "oddlama", + "repo": "nix-topology", + "rev": "c15f569794a0f1a437850d0ac81675bcf23ca6cb", + "type": "github" }, - "nixlib": { - "locked": { - "lastModified": 1733620091, - "narHash": "sha256-5WoMeCkaXqTZwwCNLRzyLxEJn8ISwjx4cNqLgqKwg9s=", - "owner": "nix-community", - "repo": "nixpkgs.lib", - "rev": "f4dc9a6c02e5e14d91d158522f69f6ab4194eb5b", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "nixpkgs.lib", - "type": "github" - } - }, - "nixos-generators": { - "inputs": { - "nixlib": "nixlib", - "nixpkgs": [ - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1733706547, - "narHash": "sha256-BdFW7TMgES7q8I5FGX5hlz+0Xp4WyfAP3tHDwEupSWU=", - "owner": "nix-community", - "repo": "nixos-generators", - "rev": "f5a0197ccfef7388885fc9455e74d6dd39e0c5e8", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "nixos-generators", - "type": "github" - } - }, - "nixos-hardware": { - "locked": { - "lastModified": 1733481457, - "narHash": "sha256-IS3bxa4N1VMSh3/P6vhEAHQZecQ3oAlKCDvzCQSO5Is=", - "owner": "NixOS", - "repo": "nixos-hardware", - "rev": "e563803af3526852b6b1d77107a81908c66a9fcf", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "master", - "repo": "nixos-hardware", - "type": "github" - } - }, - "nixpkgs": { - "locked": { - "lastModified": 1730642263, - "narHash": "sha256-UXqvGZOHUDeAo8Sv5A5oObiQgBPELVgHQi130TU0jMU=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "650fe87347086b30a6dbcc32b55987ce5a23c6ae", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-unstable-small", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs-docs": { - "locked": { - "lastModified": 1705957679, - "narHash": "sha256-Q8LJaVZGJ9wo33wBafvZSzapYsjOaNjP/pOnSiKVGHY=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "9a333eaa80901efe01df07eade2c16d183761fa3", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "release-23.05", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs-for-bootstrap": { - "locked": { - "lastModified": 1720244366, - "narHash": "sha256-WrDV0FPMVd2Sq9hkR5LNHudS3OSMmUrs90JUTN+MXpA=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "49ee0e94463abada1de470c9c07bfc12b36dcf40", - "type": "github" - }, - "original": { - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "49ee0e94463abada1de470c9c07bfc12b36dcf40", - "type": "github" - } - }, - "nixpkgs-lib": { - "locked": { - "lastModified": 1719876945, - "narHash": "sha256-Fm2rDDs86sHy0/1jxTOKB1118Q0O3Uc7EC0iXvXKpbI=", - "type": "tarball", - "url": "https://github.com/NixOS/nixpkgs/archive/5daf0514482af3f97abaefc78a6606365c9108e2.tar.gz" - }, - "original": { - "type": "tarball", - "url": "https://github.com/NixOS/nixpkgs/archive/5daf0514482af3f97abaefc78a6606365c9108e2.tar.gz" - } - }, - "nixpkgs-stable": { - "locked": { - "lastModified": 1733412085, - "narHash": "sha256-FillH0qdWDt/nlO6ED7h4cmN+G9uXwGjwmCnHs0QVYM=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "4dc2fc4e62dbf62b84132fe526356fbac7b03541", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-24.11", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs-stable_2": { - "locked": { - "lastModified": 1720386169, - "narHash": "sha256-NGKVY4PjzwAa4upkGtAMz1npHGoRzWotlSnVlqI40mo=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "194846768975b7ad2c4988bdb82572c00222c0d7", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-24.05", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs-stable_3": { - "locked": { - "lastModified": 1733384649, - "narHash": "sha256-K5DJ2LpPqht7K76bsxetI+YHhGGRyVteTPRQaIIKJpw=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "190c31a89e5eec80dd6604d7f9e5af3802a58a13", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-24.05", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs-stable_4": { - "locked": { - "lastModified": 1730741070, - "narHash": "sha256-edm8WG19kWozJ/GqyYx2VjW99EdhjKwbY3ZwdlPAAlo=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "d063c1dd113c91ab27959ba540c0d9753409edf3", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-24.05", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_2": { - "locked": { - "lastModified": 1731319897, - "narHash": "sha256-PbABj4tnbWFMfBp6OcUK5iGy1QY+/Z96ZcLpooIbuEI=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "dc460ec76cbff0e66e269457d7b728432263166c", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_3": { - "locked": { - "lastModified": 1660551188, - "narHash": "sha256-a1LARMMYQ8DPx1BgoI/UN4bXe12hhZkCNqdxNi6uS0g=", - "owner": "nixos", - "repo": "nixpkgs", - "rev": "441dc5d512153039f19ef198e662e4f3dbb9fd65", - "type": "github" - }, - "original": { - "owner": "nixos", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_4": { - "locked": { - "lastModified": 1733581040, - "narHash": "sha256-Qn3nPMSopRQJgmvHzVqPcE3I03zJyl8cSbgnnltfFDY=", - "owner": "nixos", - "repo": "nixpkgs", - "rev": "22c3f2cf41a0e70184334a958e6b124fb0ce3e01", - "type": "github" - }, - "original": { - "owner": "nixos", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_5": { - "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_6": { - "locked": { - "lastModified": 1733581040, - "narHash": "sha256-Qn3nPMSopRQJgmvHzVqPcE3I03zJyl8cSbgnnltfFDY=", - "owner": "nixos", - "repo": "nixpkgs", - "rev": "22c3f2cf41a0e70184334a958e6b124fb0ce3e01", - "type": "github" - }, - "original": { - "owner": "nixos", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_7": { - "locked": { - "lastModified": 1731763621, - "narHash": "sha256-ddcX4lQL0X05AYkrkV2LMFgGdRvgap7Ho8kgon3iWZk=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "c69a9bffbecde46b4b939465422ddc59493d3e4d", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixpkgs-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_8": { - "locked": { - "lastModified": 1732238832, - "narHash": "sha256-sQxuJm8rHY20xq6Ah+GwIUkF95tWjGRd1X8xF+Pkk38=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "8edf06bea5bcbee082df1b7369ff973b91618b8d", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixpkgs-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_9": { - "locked": { - "lastModified": 1732812356, - "narHash": "sha256-LNcgjOLArRlx2W6XSi0yc0xwLjrK3KF9LxAMqUgFDgw=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "581d7e4d23b91daf2afa0005a5d3d01d6a8884fe", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixpkgs-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nmd": { - "flake": false, - "locked": { - "lastModified": 1666190571, - "narHash": "sha256-Z1hc7M9X6L+H83o9vOprijpzhTfOBjd0KmUTnpHAVjA=", - "owner": "rycee", - "repo": "nmd", - "rev": "b75d312b4f33bd3294cd8ae5c2ca8c6da2afc169", - "type": "gitlab" - }, - "original": { - "owner": "rycee", - "repo": "nmd", - "type": "gitlab" - } - }, - "nmd_2": { - "inputs": { - "nixpkgs": [ - "nix-on-droid", - "nixpkgs-docs" - ], - "scss-reset": "scss-reset" - }, - "locked": { - "lastModified": 1705050560, - "narHash": "sha256-x3zzcdvhJpodsmdjqB4t5mkVW22V3wqHLOun0KRBzUI=", - "owner": "~rycee", - "repo": "nmd", - "rev": "66d9334933119c36f91a78d565c152a4fdc8d3d3", - "type": "sourcehut" - }, - "original": { - "owner": "~rycee", - "repo": "nmd", - "type": "sourcehut" - } - }, - "nmt": { - "flake": false, - "locked": { - "lastModified": 1648075362, - "narHash": "sha256-u36WgzoA84dMVsGXzml4wZ5ckGgfnvS0ryzo/3zn/Pc=", - "owner": "rycee", - "repo": "nmt", - "rev": "d83601002c99b78c89ea80e5e6ba21addcfe12ae", - "type": "gitlab" - }, - "original": { - "owner": "rycee", - "repo": "nmt", - "type": "gitlab" - } - }, - "nswitch-rcm-nix": { - "inputs": { - "flake-parts": "flake-parts_2", - "nixpkgs": "nixpkgs_5" - }, - "locked": { - "lastModified": 1721304043, - "narHash": "sha256-8mY9tdjo44E23xGMcUFA2a1tUcEpz7oK5upuZZ9v5SU=", - "owner": "Swarsel", - "repo": "nswitch-rcm-nix", - "rev": "b45dc5d673631c97a4b8379926de89a66561d6dc", - "type": "github" - }, - "original": { - "owner": "Swarsel", - "repo": "nswitch-rcm-nix", - "type": "github" - } - }, - "nur": { - "inputs": { - "flake-parts": "flake-parts_3", - "nixpkgs": "nixpkgs_6", - "treefmt-nix": "treefmt-nix" - }, - "locked": { - "lastModified": 1733741573, - "narHash": "sha256-Nn83GW7omhAS0DliPbG14eiRDlCPJPGA+WuQa5RhLLc=", - "owner": "nix-community", - "repo": "NUR", - "rev": "7d4c32c04bfefa4bb5a77daffa5f6cb2d53df122", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "NUR", - "type": "github" - } - }, - "pre-commit-hooks": { - "inputs": { - "flake-compat": "flake-compat_4", - "gitignore": "gitignore_2", - "nixpkgs": [ - "nixpkgs" - ], - "nixpkgs-stable": "nixpkgs-stable_4" - }, - "locked": { - "lastModified": 1733665616, - "narHash": "sha256-+XTFXYlFJBxohhMGLDpYdEnhUNdxN8dyTA8WAd+lh2A=", - "owner": "cachix", - "repo": "git-hooks.nix", - "rev": "d8c02f0ffef0ef39f6063731fc539d8c71eb463a", - "type": "github" - }, - "original": { - "owner": "cachix", - "repo": "git-hooks.nix", - "type": "github" - } - }, - "pre-commit-hooks-nix": { - "inputs": { - "flake-compat": [ - "lanzaboote", - "flake-compat" - ], - "gitignore": "gitignore", - "nixpkgs": [ - "lanzaboote", - "nixpkgs" - ], - "nixpkgs-stable": "nixpkgs-stable_2" - }, - "locked": { - "lastModified": 1730302582, - "narHash": "sha256-W1MIJpADXQCgosJZT8qBYLRuZls2KSiKdpnTVdKBuvU=", - "owner": "cachix", - "repo": "pre-commit-hooks.nix", - "rev": "af8a16fe5c264f5e9e18bcee2859b40a656876cf", - "type": "github" - }, - "original": { - "owner": "cachix", - "repo": "pre-commit-hooks.nix", - "type": "github" - } - }, - "root": { - "inputs": { - "disko": "disko", - "emacs-overlay": "emacs-overlay", - "fw-fanctrl": "fw-fanctrl", - "home-manager": "home-manager", - "impermanence": "impermanence", - "lanzaboote": "lanzaboote", - "nix-alien": "nix-alien", - "nix-darwin": "nix-darwin", - "nix-index-database": "nix-index-database_2", - "nix-on-droid": "nix-on-droid", - "nix-secrets": "nix-secrets", - "nixgl": "nixgl", - "nixos-generators": "nixos-generators", - "nixos-hardware": "nixos-hardware", - "nixpkgs": "nixpkgs_4", - "nixpkgs-stable": "nixpkgs-stable_3", - "nswitch-rcm-nix": "nswitch-rcm-nix", - "nur": "nur", - "pre-commit-hooks": "pre-commit-hooks", - "sops-nix": "sops-nix", - "stylix": "stylix", - "systems": "systems_3", - "zjstatus": "zjstatus" - } - }, - "rust-overlay": { - "inputs": { - "nixpkgs": [ - "lanzaboote", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1730601085, - "narHash": "sha256-Sgax33jGuvVHTjl1P78IwzlhAGyOxtx5Q26inKja8S4=", - "owner": "oxalica", - "repo": "rust-overlay", - "rev": "8d1b40f8dfd7539aaa3de56e207e22b3cc451825", - "type": "github" - }, - "original": { - "owner": "oxalica", - "repo": "rust-overlay", - "type": "github" - } - }, - "rust-overlay_2": { - "inputs": { - "nixpkgs": [ - "zjstatus", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1732933841, - "narHash": "sha256-dge02pUSe2QeC/B3PriA0R8eAX+EU3aDoXj9FcS3XDw=", - "owner": "oxalica", - "repo": "rust-overlay", - "rev": "c65e91d4a33abc3bc4a892d3c5b5b378bad64ea1", - "type": "github" - }, - "original": { - "owner": "oxalica", - "repo": "rust-overlay", - "type": "github" - } - }, - "scss-reset": { - "flake": false, - "locked": { - "lastModified": 1631450058, - "narHash": "sha256-muDlZJPtXDIGevSEWkicPP0HQ6VtucbkMNygpGlBEUM=", - "owner": "andreymatin", - "repo": "scss-reset", - "rev": "0cf50e27a4e95e9bb5b1715eedf9c54dee1a5a91", - "type": "github" - }, - "original": { - "owner": "andreymatin", - "repo": "scss-reset", - "type": "github" - } - }, - "sops-nix": { - "inputs": { - "nixpkgs": "nixpkgs_7" - }, - "locked": { - "lastModified": 1733128155, - "narHash": "sha256-m6/qwJAJYcidGMEdLqjKzRIjapK4nUfMq7rDCTmZajc=", - "owner": "Mic92", - "repo": "sops-nix", - "rev": "c6134b6fff6bda95a1ac872a2a9d5f32e3c37856", - "type": "github" - }, - "original": { - "owner": "Mic92", - "repo": "sops-nix", - "type": "github" - } - }, - "stylix": { - "inputs": { - "base16": "base16", - "base16-fish": "base16-fish", - "base16-helix": "base16-helix", - "base16-vim": "base16-vim", - "flake-compat": "flake-compat_5", - "flake-utils": "flake-utils_3", - "gnome-shell": "gnome-shell", - "home-manager": "home-manager_3", - "nixpkgs": "nixpkgs_8", - "systems": "systems_2", - "tinted-foot": "tinted-foot", - "tinted-kitty": "tinted-kitty", - "tinted-tmux": "tinted-tmux" - }, - "locked": { - "lastModified": 1733510476, - "narHash": "sha256-RH/8yIuo+fNLCjQ6e1mnXwmmxymjvfWC9JcbDuIA8TM=", - "owner": "danth", - "repo": "stylix", - "rev": "e309d64fe7f203274a7913e1d2b74307d15ba122", - "type": "github" - }, - "original": { - "owner": "danth", - "repo": "stylix", - "type": "github" - } - }, - "systems": { - "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, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } - }, - "systems_3": { - "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_4": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } - }, - "tinted-foot": { - "flake": false, - "locked": { - "lastModified": 1726913040, - "narHash": "sha256-+eDZPkw7efMNUf3/Pv0EmsidqdwNJ1TaOum6k7lngDQ=", - "owner": "tinted-theming", - "repo": "tinted-foot", - "rev": "fd1b924b6c45c3e4465e8a849e67ea82933fcbe4", - "type": "github" - }, - "original": { - "owner": "tinted-theming", - "repo": "tinted-foot", - "rev": "fd1b924b6c45c3e4465e8a849e67ea82933fcbe4", - "type": "github" - } - }, - "tinted-kitty": { - "flake": false, - "locked": { - "lastModified": 1716423189, - "narHash": "sha256-2xF3sH7UIwegn+2gKzMpFi3pk5DlIlM18+vj17Uf82U=", - "owner": "tinted-theming", - "repo": "tinted-kitty", - "rev": "eb39e141db14baef052893285df9f266df041ff8", - "type": "github" - }, - "original": { - "owner": "tinted-theming", - "repo": "tinted-kitty", - "rev": "eb39e141db14baef052893285df9f266df041ff8", - "type": "github" - } - }, - "tinted-tmux": { - "flake": false, - "locked": { - "lastModified": 1729501581, - "narHash": "sha256-1ohEFMC23elnl39kxWnjzH1l2DFWWx4DhFNNYDTYt54=", - "owner": "tinted-theming", - "repo": "tinted-tmux", - "rev": "f0e7f7974a6441033eb0a172a0342e96722b4f14", - "type": "github" - }, - "original": { - "owner": "tinted-theming", - "repo": "tinted-tmux", - "type": "github" - } - }, - "treefmt-nix": { - "inputs": { - "nixpkgs": [ - "nur", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1733222881, - "narHash": "sha256-JIPcz1PrpXUCbaccEnrcUS8jjEb/1vJbZz5KkobyFdM=", - "owner": "numtide", - "repo": "treefmt-nix", - "rev": "49717b5af6f80172275d47a418c9719a31a78b53", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "treefmt-nix", - "type": "github" - } - }, - "zjstatus": { - "inputs": { - "crane": "crane_2", - "flake-utils": "flake-utils_4", - "nixpkgs": "nixpkgs_9", - "rust-overlay": "rust-overlay_2" - }, - "locked": { - "lastModified": 1732970864, - "narHash": "sha256-rTEdf4I4xVNhbn5vzMd/2e2Ai9E+Cra1e40GcaZT1Xw=", - "owner": "dj95", - "repo": "zjstatus", - "rev": "161d255f09b28421ba842b995ef39d395ab3e065", - "type": "github" - }, - "original": { - "owner": "dj95", - "repo": "zjstatus", - "type": "github" - } + "original": { + "owner": "oddlama", + "repo": "nix-topology", + "type": "github" } + }, + "nixago": { + "inputs": { + "flake-utils": [ + "nixos-extra-modules", + "nixt", + "std", + "flake-utils" + ], + "nixago-exts": [ + "nixos-extra-modules", + "nixt", + "std", + "blank" + ], + "nixpkgs": [ + "nixos-extra-modules", + "nixt", + "std", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1683210100, + "narHash": "sha256-bhGDOlkWtlhVECpoOog4fWiFJmLCpVEg09a40aTjCbw=", + "owner": "nix-community", + "repo": "nixago", + "rev": "1da60ad9412135f9ed7a004669fdcf3d378ec630", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixago", + "type": "github" + } + }, + "nixgl": { + "inputs": { + "flake-utils": "flake-utils_5", + "nixpkgs": "nixpkgs_12" + }, + "locked": { + "lastModified": 1762090880, + "narHash": "sha256-fbRQzIGPkjZa83MowjbD2ALaJf9y6KMDdJBQMKFeY/8=", + "owner": "guibou", + "repo": "nixGL", + "rev": "b6105297e6f0cd041670c3e8628394d4ee247ed5", + "type": "github" + }, + "original": { + "owner": "guibou", + "repo": "nixGL", + "type": "github" + } + }, + "nixlib": { + "locked": { + "lastModified": 1736643958, + "narHash": "sha256-tmpqTSWVRJVhpvfSN9KXBvKEXplrwKnSZNAoNPf/S/s=", + "owner": "nix-community", + "repo": "nixpkgs.lib", + "rev": "1418bc28a52126761c02dd3d89b2d8ca0f521181", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixpkgs.lib", + "type": "github" + } + }, + "nixos-extra-modules": { + "inputs": { + "devshell": "devshell_3", + "flake-parts": "flake-parts_2", + "nixpkgs": "nixpkgs_13", + "nixt": "nixt", + "pre-commit-hooks": "pre-commit-hooks_2" + }, + "locked": { + "lastModified": 1757854196, + "narHash": "sha256-RDr3/JTpRyXSR1OOg+wzdOUmDL1Ke05OLV/xctbuQOw=", + "owner": "oddlama", + "repo": "nixos-extra-modules", + "rev": "a584a970a05d0410dcb00e0ade684a0c0ce00c4b", + "type": "github" + }, + "original": { + "owner": "oddlama", + "ref": "main", + "repo": "nixos-extra-modules", + "type": "github" + } + }, + "nixos-generators": { + "inputs": { + "nixlib": "nixlib", + "nixpkgs": "nixpkgs_15" + }, + "locked": { + "lastModified": 1751903740, + "narHash": "sha256-PeSkNMvkpEvts+9DjFiop1iT2JuBpyknmBUs0Un0a4I=", + "owner": "nix-community", + "repo": "nixos-generators", + "rev": "032decf9db65efed428afd2fa39d80f7089085eb", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixos-generators", + "type": "github" + } + }, + "nixos-hardware": { + "locked": { + "lastModified": 1762847253, + "narHash": "sha256-BWWnUUT01lPwCWUvS0p6Px5UOBFeXJ8jR+ZdLX8IbrU=", + "owner": "NixOS", + "repo": "nixos-hardware", + "rev": "899dc449bc6428b9ee6b3b8f771ca2b0ef945ab9", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "master", + "repo": "nixos-hardware", + "type": "github" + } + }, + "nixos-images": { + "inputs": { + "nixos-stable": "nixos-stable", + "nixos-unstable": "nixos-unstable" + }, + "locked": { + "lastModified": 1763686321, + "narHash": "sha256-csmQ+rYF54VReDExlDQynz4rPgdu5nb+fzDDPB/HJkM=", + "owner": "Swarsel", + "repo": "nixos-images", + "rev": "f4744a931548edb964a7d0e4678ca9d56a7f158e", + "type": "github" + }, + "original": { + "owner": "Swarsel", + "ref": "main", + "repo": "nixos-images", + "type": "github" + } + }, + "nixos-stable": { + "locked": { + "lastModified": 1749237914, + "narHash": "sha256-N5waoqWt8aMr/MykZjSErOokYH6rOsMMXu3UOVH5kiw=", + "ref": "nixos-25.05", + "rev": "70c74b02eac46f4e4aa071e45a6189ce0f6d9265", + "shallow": true, + "type": "git", + "url": "https://github.com/NixOS/nixpkgs" + }, + "original": { + "ref": "nixos-25.05", + "shallow": true, + "type": "git", + "url": "https://github.com/NixOS/nixpkgs" + } + }, + "nixos-unstable": { + "locked": { + "lastModified": 1749401433, + "narHash": "sha256-HXIQzULIG/MEUW2Q/Ss47oE3QrjxvpUX7gUl4Xp6lnc=", + "ref": "nixpkgs-unstable", + "rev": "08fcb0dcb59df0344652b38ea6326a2d8271baff", + "shallow": true, + "type": "git", + "url": "https://github.com/NixOS/nixpkgs" + }, + "original": { + "ref": "nixpkgs-unstable", + "shallow": true, + "type": "git", + "url": "https://github.com/NixOS/nixpkgs" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1763934636, + "narHash": "sha256-9glbI7f1uU+yzQCq5LwLgdZqx6svOhZWkd4JRY265fc=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "ee09932cedcef15aaf476f9343d1dea2cb77e261", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-dev": { + "locked": { + "lastModified": 1763648956, + "narHash": "sha256-JBATYs0HPlATioA2kYFwUAsnzWv9Bd2tXqeCOr/ix6I=", + "owner": "Swarsel", + "repo": "nixpkgs", + "rev": "230b56741730ede84e7e488d11cb34044f5b54c7", + "type": "github" + }, + "original": { + "owner": "Swarsel", + "ref": "main", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-docs": { + "locked": { + "lastModified": 1705957679, + "narHash": "sha256-Q8LJaVZGJ9wo33wBafvZSzapYsjOaNjP/pOnSiKVGHY=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "9a333eaa80901efe01df07eade2c16d183761fa3", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "release-23.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-for-bootstrap": { + "locked": { + "lastModified": 1720244366, + "narHash": "sha256-WrDV0FPMVd2Sq9hkR5LNHudS3OSMmUrs90JUTN+MXpA=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "49ee0e94463abada1de470c9c07bfc12b36dcf40", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "49ee0e94463abada1de470c9c07bfc12b36dcf40", + "type": "github" + } + }, + "nixpkgs-kernel": { + "locked": { + "lastModified": 1748026106, + "narHash": "sha256-6m1Y3/4pVw1RWTsrkAK2VMYSzG4MMIj7sqUy7o8th1o=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "063f43f2dbdef86376cc29ad646c45c46e93234c", + "type": "github" + }, + "original": { + "narHash": "sha256-6m1Y3/4pVw1RWTsrkAK2VMYSzG4MMIj7sqUy7o8th1o=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "063f43f2dbdef86376cc29ad646c45c46e93234c", + "type": "github" + } + }, + "nixpkgs-lib": { + "locked": { + "lastModified": 1761765539, + "narHash": "sha256-b0yj6kfvO8ApcSE+QmA6mUfu8IYG6/uU28OFn4PaC8M=", + "owner": "nix-community", + "repo": "nixpkgs.lib", + "rev": "719359f4562934ae99f5443f20aa06c2ffff91fc", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixpkgs.lib", + "type": "github" + } + }, + "nixpkgs-lib_2": { + "locked": { + "lastModified": 1738452942, + "narHash": "sha256-vJzFZGaCpnmo7I6i416HaBLpC+hvcURh/BQwROcGIp8=", + "type": "tarball", + "url": "https://github.com/NixOS/nixpkgs/archive/072a6db25e947df2f31aab9eccd0ab75d5b2da11.tar.gz" + }, + "original": { + "type": "tarball", + "url": "https://github.com/NixOS/nixpkgs/archive/072a6db25e947df2f31aab9eccd0ab75d5b2da11.tar.gz" + } + }, + "nixpkgs-lib_3": { + "locked": { + "lastModified": 1719876945, + "narHash": "sha256-Fm2rDDs86sHy0/1jxTOKB1118Q0O3Uc7EC0iXvXKpbI=", + "type": "tarball", + "url": "https://github.com/NixOS/nixpkgs/archive/5daf0514482af3f97abaefc78a6606365c9108e2.tar.gz" + }, + "original": { + "type": "tarball", + "url": "https://github.com/NixOS/nixpkgs/archive/5daf0514482af3f97abaefc78a6606365c9108e2.tar.gz" + } + }, + "nixpkgs-lib_4": { + "locked": { + "lastModified": 1754788789, + "narHash": "sha256-x2rJ+Ovzq0sCMpgfgGaaqgBSwY+LST+WbZ6TytnT9Rk=", + "owner": "nix-community", + "repo": "nixpkgs.lib", + "rev": "a73b9c743612e4244d865a2fdee11865283c04e6", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixpkgs.lib", + "type": "github" + } + }, + "nixpkgs-stable": { + "locked": { + "lastModified": 1760139962, + "narHash": "sha256-4xggC56Rub3WInz5eD7EZWXuLXpNvJiUPahGtMkwtuc=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "7e297ddff44a3cc93673bb38d0374df8d0ad73e4", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-25.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-stable24_05": { + "locked": { + "lastModified": 1735563628, + "narHash": "sha256-OnSAY7XDSx7CtDoqNh8jwVwh4xNL/2HaJxGjryLWzX8=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "b134951a4c9f3c995fd7be05f3243f8ecd65d798", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-24.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-stable24_11": { + "locked": { + "lastModified": 1751274312, + "narHash": "sha256-/bVBlRpECLVzjV19t5KMdMFWSwKLtb5RyXdjz3LJT+g=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "50ab793786d9de88ee30ec4e4c24fb4236fc2674", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-24.11", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-stable25_05": { + "locked": { + "lastModified": 1763622513, + "narHash": "sha256-1jQnuyu82FpiSxowrF/iFK6Toh9BYprfDqfs4BB+19M=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "c58bc7f5459328e4afac201c5c4feb7c818d604b", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-25.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-stable_2": { + "locked": { + "lastModified": 1763622513, + "narHash": "sha256-1jQnuyu82FpiSxowrF/iFK6Toh9BYprfDqfs4BB+19M=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "c58bc7f5459328e4afac201c5c4feb7c818d604b", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-25.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-stable_3": { + "locked": { + "lastModified": 1763622513, + "narHash": "sha256-1jQnuyu82FpiSxowrF/iFK6Toh9BYprfDqfs4BB+19M=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "c58bc7f5459328e4afac201c5c4feb7c818d604b", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-25.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_10": { + "locked": { + "lastModified": 1764086288, + "narHash": "sha256-S223/Mc4Ax75PfWySz8b44jjAnz36jUk4U+XiCfMy9I=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "c4fd5c5627b75a9aa111ccd2ac4f86906f32af2a", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_11": { + "locked": { + "lastModified": 1730531603, + "narHash": "sha256-Dqg6si5CqIzm87sp57j5nTaeBbWhHFaVyG7V6L8k3lY=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "7ffd9ae656aec493492b44d0ddfb28e79a1ea25d", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_12": { + "locked": { + "lastModified": 1746378225, + "narHash": "sha256-OeRSuL8PUjIfL3Q0fTbNJD/fmv1R+K2JAOqWJd3Oceg=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "93e8cdce7afc64297cfec447c311470788131cd9", + "type": "github" + }, + "original": { + "owner": "nixos", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_13": { + "locked": { + "lastModified": 1763966396, + "narHash": "sha256-6eeL1YPcY1MV3DDStIDIdy/zZCDKgHdkCmsrLJFiZf0=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "5ae3b07d8d6527c42f17c876e404993199144b6a", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_14": { + "locked": { + "lastModified": 1677063315, + "narHash": "sha256-qiB4ajTeAOVnVSAwCNEEkoybrAlA+cpeiBxLobHndE8=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "988cc958c57ce4350ec248d2d53087777f9e1949", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_15": { + "locked": { + "lastModified": 1763934636, + "narHash": "sha256-9glbI7f1uU+yzQCq5LwLgdZqx6svOhZWkd4JRY265fc=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "ee09932cedcef15aaf476f9343d1dea2cb77e261", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_16": { + "locked": { + "lastModified": 1763835633, + "narHash": "sha256-HzxeGVID5MChuCPESuC0dlQL1/scDKu+MmzoVBJxulM=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "050e09e091117c3d7328c7b2b7b577492c43c134", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_17": { + "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_18": { + "locked": { + "lastModified": 1763835633, + "narHash": "sha256-HzxeGVID5MChuCPESuC0dlQL1/scDKu+MmzoVBJxulM=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "050e09e091117c3d7328c7b2b7b577492c43c134", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_19": { + "locked": { + "lastModified": 1763934636, + "narHash": "sha256-9glbI7f1uU+yzQCq5LwLgdZqx6svOhZWkd4JRY265fc=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "ee09932cedcef15aaf476f9343d1dea2cb77e261", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1763934636, + "narHash": "sha256-9glbI7f1uU+yzQCq5LwLgdZqx6svOhZWkd4JRY265fc=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "ee09932cedcef15aaf476f9343d1dea2cb77e261", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_20": { + "locked": { + "lastModified": 1763553727, + "narHash": "sha256-4aRqRkYHplWk0mrtoF5i3Uo73E3niOWiUZU8kmPm9hQ=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "094318ea16502a7a81ce90dd3638697020f030a2", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable-small", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_21": { + "locked": { + "lastModified": 1763618868, + "narHash": "sha256-v5afmLjn/uyD9EQuPBn7nZuaZVV9r+JerayK/4wvdWA=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "a8d610af3f1a5fb71e23e08434d8d61a466fc942", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_22": { + "locked": { + "lastModified": 1763966396, + "narHash": "sha256-6eeL1YPcY1MV3DDStIDIdy/zZCDKgHdkCmsrLJFiZf0=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "5ae3b07d8d6527c42f17c876e404993199144b6a", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_23": { + "locked": { + "lastModified": 1762977756, + "narHash": "sha256-4PqRErxfe+2toFJFgcRKZ0UI9NSIOJa+7RXVtBhy4KE=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "c5ae371f1a6a7fd27823bc500d9390b38c05fa55", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_24": { + "locked": { + "lastModified": 1763966396, + "narHash": "sha256-6eeL1YPcY1MV3DDStIDIdy/zZCDKgHdkCmsrLJFiZf0=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "5ae3b07d8d6527c42f17c876e404993199144b6a", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_25": { + "locked": { + "lastModified": 1761236834, + "narHash": "sha256-+pthv6hrL5VLW2UqPdISGuLiUZ6SnAXdd2DdUE+fV2Q=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "d5faa84122bc0a1fd5d378492efce4e289f8eac1", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_26": { + "locked": { + "lastModified": 1751274312, + "narHash": "sha256-/bVBlRpECLVzjV19t5KMdMFWSwKLtb5RyXdjz3LJT+g=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "50ab793786d9de88ee30ec4e4c24fb4236fc2674", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-24.11", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_27": { + "locked": { + "lastModified": 1754800730, + "narHash": "sha256-HfVZCXic9XLBgybP0318ym3cDnGwBs/+H5MgxFVYF4I=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "641d909c4a7538f1539da9240dedb1755c907e40", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_3": { + "locked": { + "lastModified": 1764086288, + "narHash": "sha256-S223/Mc4Ax75PfWySz8b44jjAnz36jUk4U+XiCfMy9I=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "c4fd5c5627b75a9aa111ccd2ac4f86906f32af2a", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_4": { + "locked": { + "lastModified": 1763966396, + "narHash": "sha256-6eeL1YPcY1MV3DDStIDIdy/zZCDKgHdkCmsrLJFiZf0=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "5ae3b07d8d6527c42f17c876e404993199144b6a", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_5": { + "locked": { + "lastModified": 1763678758, + "narHash": "sha256-+hBiJ+kG5IoffUOdlANKFflTT5nO3FrrR2CA3178Y5s=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "117cc7f94e8072499b0a7aa4c52084fa4e11cc9b", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_6": { + "locked": { + "lastModified": 1763966396, + "narHash": "sha256-6eeL1YPcY1MV3DDStIDIdy/zZCDKgHdkCmsrLJFiZf0=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "5ae3b07d8d6527c42f17c876e404993199144b6a", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_7": { + "locked": { + "lastModified": 1763966396, + "narHash": "sha256-6eeL1YPcY1MV3DDStIDIdy/zZCDKgHdkCmsrLJFiZf0=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "5ae3b07d8d6527c42f17c876e404993199144b6a", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_8": { + "locked": { + "lastModified": 1763934636, + "narHash": "sha256-9glbI7f1uU+yzQCq5LwLgdZqx6svOhZWkd4JRY265fc=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "ee09932cedcef15aaf476f9343d1dea2cb77e261", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_9": { + "locked": { + "lastModified": 1748929857, + "narHash": "sha256-lcZQ8RhsmhsK8u7LIFsJhsLh/pzR9yZ8yqpTzyGdj+Q=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "c2a03962b8e24e669fb37b7df10e7c79531ff1a4", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixt": { + "inputs": { + "flake-compat": "flake-compat_4", + "nixpkgs": [ + "nixos-extra-modules", + "nixpkgs" + ], + "std": "std", + "std-data-collection": "std-data-collection" + }, + "locked": { + "lastModified": 1729273076, + "narHash": "sha256-h2Y+5bikSXS8MPYpxyZpd+VX9H5uuCS/csMMxZCoS3c=", + "owner": "nix-community", + "repo": "nixt", + "rev": "ad8863c9f9e5a166d663f2f1f0eef74ab913a883", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixt", + "type": "github" + } + }, + "nmd": { + "flake": false, + "locked": { + "lastModified": 1666190571, + "narHash": "sha256-Z1hc7M9X6L+H83o9vOprijpzhTfOBjd0KmUTnpHAVjA=", + "owner": "rycee", + "repo": "nmd", + "rev": "b75d312b4f33bd3294cd8ae5c2ca8c6da2afc169", + "type": "gitlab" + }, + "original": { + "owner": "rycee", + "repo": "nmd", + "type": "gitlab" + } + }, + "nmd_2": { + "inputs": { + "nixpkgs": [ + "nix-on-droid", + "nixpkgs-docs" + ], + "scss-reset": "scss-reset" + }, + "locked": { + "lastModified": 1705050560, + "narHash": "sha256-x3zzcdvhJpodsmdjqB4t5mkVW22V3wqHLOun0KRBzUI=", + "owner": "~rycee", + "repo": "nmd", + "rev": "66d9334933119c36f91a78d565c152a4fdc8d3d3", + "type": "sourcehut" + }, + "original": { + "owner": "~rycee", + "repo": "nmd", + "type": "sourcehut" + } + }, + "nmt": { + "flake": false, + "locked": { + "lastModified": 1648075362, + "narHash": "sha256-u36WgzoA84dMVsGXzml4wZ5ckGgfnvS0ryzo/3zn/Pc=", + "owner": "rycee", + "repo": "nmt", + "rev": "d83601002c99b78c89ea80e5e6ba21addcfe12ae", + "type": "gitlab" + }, + "original": { + "owner": "rycee", + "repo": "nmt", + "type": "gitlab" + } + }, + "nosys": { + "locked": { + "lastModified": 1668010795, + "narHash": "sha256-JBDVBnos8g0toU7EhIIqQ1If5m/nyBqtHhL3sicdPwI=", + "owner": "divnix", + "repo": "nosys", + "rev": "feade0141487801c71ff55623b421ed535dbdefa", + "type": "github" + }, + "original": { + "owner": "divnix", + "repo": "nosys", + "type": "github" + } + }, + "nswitch-rcm-nix": { + "inputs": { + "flake-parts": "flake-parts_3", + "nixpkgs": "nixpkgs_17" + }, + "locked": { + "lastModified": 1721304043, + "narHash": "sha256-8mY9tdjo44E23xGMcUFA2a1tUcEpz7oK5upuZZ9v5SU=", + "owner": "Swarsel", + "repo": "nswitch-rcm-nix", + "rev": "b45dc5d673631c97a4b8379926de89a66561d6dc", + "type": "github" + }, + "original": { + "owner": "Swarsel", + "repo": "nswitch-rcm-nix", + "type": "github" + } + }, + "nur": { + "inputs": { + "flake-parts": "flake-parts_4", + "nixpkgs": "nixpkgs_18" + }, + "locked": { + "lastModified": 1763996502, + "narHash": "sha256-pJGdiniI2GntAsMSLBo8sNmb61XJ7Jl9vLayMl57qUo=", + "owner": "nix-community", + "repo": "NUR", + "rev": "dad4410a04874ea636c9ebae579b74342f04ea20", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "NUR", + "type": "github" + } + }, + "nur_2": { + "inputs": { + "flake-parts": [ + "stylix", + "flake-parts" + ], + "nixpkgs": [ + "stylix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1758998580, + "narHash": "sha256-VLx0z396gDCGSiowLMFz5XRO/XuNV+4EnDYjdJhHvUk=", + "owner": "nix-community", + "repo": "NUR", + "rev": "ba8d9c98f5f4630bcb0e815ab456afd90c930728", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "NUR", + "type": "github" + } + }, + "paisano": { + "inputs": { + "nixpkgs": [ + "nixos-extra-modules", + "nixt", + "std", + "nixpkgs" + ], + "nosys": "nosys", + "yants": [ + "nixos-extra-modules", + "nixt", + "std", + "yants" + ] + }, + "locked": { + "lastModified": 1678949904, + "narHash": "sha256-oAoF66hYYz1RPh3lEwb9/4e4iyBAfTbQKZRRQ8gP0Ds=", + "owner": "paisano-nix", + "repo": "core", + "rev": "88f2aff10a5064551d1d4cb86800d17084489ce3", + "type": "github" + }, + "original": { + "owner": "paisano-nix", + "repo": "core", + "type": "github" + } + }, + "paisano-actions": { + "inputs": { + "nixpkgs": [ + "nixos-extra-modules", + "nixt", + "std", + "paisano-mdbook-preprocessor", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1677306424, + "narHash": "sha256-H9/dI2rGEbKo4KEisqbRPHFG2ajF8Tm111NPdKGIf28=", + "owner": "paisano-nix", + "repo": "actions", + "rev": "65ec4e080b3480167fc1a748c89a05901eea9a9b", + "type": "github" + }, + "original": { + "owner": "paisano-nix", + "repo": "actions", + "type": "github" + } + }, + "paisano-mdbook-preprocessor": { + "inputs": { + "crane": "crane_2", + "fenix": "fenix", + "nixpkgs": [ + "nixos-extra-modules", + "nixt", + "std", + "nixpkgs" + ], + "paisano-actions": "paisano-actions", + "std": [ + "nixos-extra-modules", + "nixt", + "std" + ] + }, + "locked": { + "lastModified": 1680654400, + "narHash": "sha256-Qdpio+ldhUK3zfl22Mhf8HUULdUOJXDWDdO7MIK69OU=", + "owner": "paisano-nix", + "repo": "mdbook-paisano-preprocessor", + "rev": "11a8fc47f574f194a7ae7b8b98001f6143ba4cf1", + "type": "github" + }, + "original": { + "owner": "paisano-nix", + "repo": "mdbook-paisano-preprocessor", + "type": "github" + } + }, + "paisano-tui": { + "inputs": { + "nixpkgs": [ + "nixos-extra-modules", + "nixt", + "std", + "blank" + ], + "std": [ + "nixos-extra-modules", + "nixt", + "std" + ] + }, + "locked": { + "lastModified": 1681847764, + "narHash": "sha256-mdd7PJW1BZvxy0cIKsPfAO+ohVl/V7heE5ZTAHzTdv8=", + "owner": "paisano-nix", + "repo": "tui", + "rev": "3096bad91cae73ab8ab3367d31f8a143d248a244", + "type": "github" + }, + "original": { + "owner": "paisano-nix", + "ref": "0.1.1", + "repo": "tui", + "type": "github" + } + }, + "pre-commit": { + "inputs": { + "flake-compat": "flake-compat", + "gitignore": "gitignore", + "nixpkgs": [ + "lanzaboote", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1763741496, + "narHash": "sha256-uIRqs/H18YEtMOn1OkbnPH+aNTwXKx+iU3qnxEkVUd0=", + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "rev": "20e71a403c5de9ce5bd799031440da9728c1cda1", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "type": "github" + } + }, + "pre-commit-hooks": { + "inputs": { + "flake-compat": "flake-compat_3", + "gitignore": "gitignore_2", + "nixpkgs": [ + "nix-topology", + "nixpkgs" + ], + "nixpkgs-stable": [ + "nix-topology", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1730797577, + "narHash": "sha256-SrID5yVpyUfknUTGWgYkTyvdr9J1LxUym4om3SVGPkg=", + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "rev": "1864030ed24a2b8b4e4d386a5eeaf0c5369e50a9", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "type": "github" + } + }, + "pre-commit-hooks_2": { + "inputs": { + "flake-compat": "flake-compat_6", + "gitignore": "gitignore_3", + "nixpkgs": [ + "nixos-extra-modules", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1737465171, + "narHash": "sha256-R10v2hoJRLq8jcL4syVFag7nIGE7m13qO48wRIukWNg=", + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "rev": "9364dc02281ce2d37a1f55b6e51f7c0f65a75f17", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "type": "github" + } + }, + "pre-commit-hooks_3": { + "inputs": { + "flake-compat": "flake-compat_7", + "gitignore": "gitignore_4", + "nixpkgs": "nixpkgs_19" + }, + "locked": { + "lastModified": 1763988335, + "narHash": "sha256-QlcnByMc8KBjpU37rbq5iP7Cp97HvjRP0ucfdh+M4Qc=", + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "50b9238891e388c9fdc6a5c49e49c42533a1b5ce", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", + "type": "github" + } + }, + "root": { + "inputs": { + "devshell": "devshell", + "disko": "disko", + "dns": "dns", + "emacs-overlay": "emacs-overlay", + "flake-parts": "flake-parts", + "home-manager": "home-manager", + "impermanence": "impermanence", + "lanzaboote": "lanzaboote", + "microvm": "microvm", + "niri-flake": "niri-flake", + "nix-darwin": "nix-darwin", + "nix-index-database": "nix-index-database", + "nix-minecraft": "nix-minecraft", + "nix-on-droid": "nix-on-droid", + "nix-topology": "nix-topology", + "nixgl": "nixgl", + "nixos-extra-modules": "nixos-extra-modules", + "nixos-generators": "nixos-generators", + "nixos-hardware": "nixos-hardware", + "nixos-images": "nixos-images", + "nixpkgs": "nixpkgs_16", + "nixpkgs-dev": "nixpkgs-dev", + "nixpkgs-kernel": "nixpkgs-kernel", + "nixpkgs-stable": "nixpkgs-stable_3", + "nixpkgs-stable24_05": "nixpkgs-stable24_05", + "nixpkgs-stable24_11": "nixpkgs-stable24_11", + "nixpkgs-stable25_05": "nixpkgs-stable25_05", + "nswitch-rcm-nix": "nswitch-rcm-nix", + "nur": "nur", + "pre-commit-hooks": "pre-commit-hooks_3", + "simple-nixos-mailserver": "simple-nixos-mailserver", + "smallpkgs": "smallpkgs", + "sops-nix": "sops-nix", + "spicetify-nix": "spicetify-nix", + "stylix": "stylix", + "swarsel-nix": "swarsel-nix", + "systems": "systems_8", + "treefmt-nix": "treefmt-nix", + "vbc-nix": "vbc-nix", + "zjstatus": "zjstatus" + } + }, + "rust-analyzer-src": { + "flake": false, + "locked": { + "lastModified": 1677221702, + "narHash": "sha256-1M+58rC4eTCWNmmX0hQVZP20t3tfYNunl9D/PrGUyGE=", + "owner": "rust-lang", + "repo": "rust-analyzer", + "rev": "f5401f620699b26ed9d47a1d2e838143a18dbe3b", + "type": "github" + }, + "original": { + "owner": "rust-lang", + "ref": "nightly", + "repo": "rust-analyzer", + "type": "github" + } + }, + "rust-overlay": { + "inputs": { + "nixpkgs": [ + "lanzaboote", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1763865987, + "narHash": "sha256-DJpzM8Jz3B0azJcAoF+YFHr8rEbxYLJ0wy1kWZ29HOw=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "042d905c01a6eec3bcae8530dacb19cda9758a63", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, + "rust-overlay_2": { + "inputs": { + "flake-utils": [ + "nixos-extra-modules", + "nixt", + "std", + "paisano-mdbook-preprocessor", + "crane", + "flake-utils" + ], + "nixpkgs": [ + "nixos-extra-modules", + "nixt", + "std", + "paisano-mdbook-preprocessor", + "crane", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1675391458, + "narHash": "sha256-ukDKZw922BnK5ohL9LhwtaDAdCsJL7L6ScNEyF1lO9w=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "383a4acfd11d778d5c2efcf28376cbd845eeaedf", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, + "rust-overlay_3": { + "inputs": { + "nixpkgs": [ + "zjstatus", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1754880555, + "narHash": "sha256-tG6l0wiX8V8IvG4HFYY8IYN5vpNAxQ+UWunjjpE6SqU=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "17c591a44e4eb77f05f27cd37e1cfc3f219c7fc4", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, + "scss-reset": { + "flake": false, + "locked": { + "lastModified": 1631450058, + "narHash": "sha256-muDlZJPtXDIGevSEWkicPP0HQ6VtucbkMNygpGlBEUM=", + "owner": "andreymatin", + "repo": "scss-reset", + "rev": "0cf50e27a4e95e9bb5b1715eedf9c54dee1a5a91", + "type": "github" + }, + "original": { + "owner": "andreymatin", + "repo": "scss-reset", + "type": "github" + } + }, + "simple-nixos-mailserver": { + "inputs": { + "blobs": "blobs", + "flake-compat": "flake-compat_8", + "git-hooks": "git-hooks", + "nixpkgs": "nixpkgs_20" + }, + "locked": { + "lastModified": 1763564778, + "narHash": "sha256-HSWMOylEaTtVgzIjpTbjcjVLXHDwNyV081eVUBfAcMs=", + "owner": "simple-nixos-mailserver", + "repo": "nixos-mailserver", + "rev": "4987d275a90392347f84923cd4cd8efcf0aa7a22", + "type": "gitlab" + }, + "original": { + "owner": "simple-nixos-mailserver", + "ref": "master", + "repo": "nixos-mailserver", + "type": "gitlab" + } + }, + "smallpkgs": { + "locked": { + "lastModified": 1749401433, + "narHash": "sha256-HXIQzULIG/MEUW2Q/Ss47oE3QrjxvpUX7gUl4Xp6lnc=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "08fcb0dcb59df0344652b38ea6326a2d8271baff", + "type": "github" + }, + "original": { + "narHash": "sha256-HXIQzULIG/MEUW2Q/Ss47oE3QrjxvpUX7gUl4Xp6lnc=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "08fcb0dcb59df0344652b38ea6326a2d8271baff", + "type": "github" + } + }, + "sops-nix": { + "inputs": { + "nixpkgs": "nixpkgs_21" + }, + "locked": { + "lastModified": 1763870012, + "narHash": "sha256-AHxFfIu73SpNLAOZbu/AvpLhZ/Szhx6gRPj9ufZtaZA=", + "owner": "Mic92", + "repo": "sops-nix", + "rev": "4e7d74d92398b933cc0e0e25af5b0836efcfdde3", + "type": "github" + }, + "original": { + "owner": "Mic92", + "repo": "sops-nix", + "type": "github" + } + }, + "spectrum": { + "flake": false, + "locked": { + "lastModified": 1759482047, + "narHash": "sha256-H1wiXRQHxxPyMMlP39ce3ROKCwI5/tUn36P8x6dFiiQ=", + "ref": "refs/heads/main", + "rev": "c5d5786d3dc938af0b279c542d1e43bce381b4b9", + "revCount": 996, + "type": "git", + "url": "https://spectrum-os.org/git/spectrum" + }, + "original": { + "type": "git", + "url": "https://spectrum-os.org/git/spectrum" + } + }, + "spicetify-nix": { + "inputs": { + "nixpkgs": "nixpkgs_22", + "systems": "systems_5" + }, + "locked": { + "lastModified": 1763985453, + "narHash": "sha256-vUqODgLIjeyHN7DP8dVx7oH9yB/L8qcxpN//4EmMQcM=", + "owner": "Gerg-l", + "repo": "spicetify-nix", + "rev": "89cd40c646ec5b12e5c20c0e18f082e7629d4819", + "type": "github" + }, + "original": { + "owner": "Gerg-l", + "repo": "spicetify-nix", + "type": "github" + } + }, + "std": { + "inputs": { + "arion": [ + "nixos-extra-modules", + "nixt", + "std", + "blank" + ], + "blank": "blank", + "devshell": "devshell_4", + "dmerge": "dmerge", + "flake-utils": "flake-utils_6", + "incl": "incl", + "makes": [ + "nixos-extra-modules", + "nixt", + "std", + "blank" + ], + "microvm": [ + "nixos-extra-modules", + "nixt", + "std", + "blank" + ], + "n2c": "n2c", + "nixago": "nixago", + "nixpkgs": [ + "nixos-extra-modules", + "nixt", + "nixpkgs" + ], + "paisano": "paisano", + "paisano-mdbook-preprocessor": "paisano-mdbook-preprocessor", + "paisano-tui": "paisano-tui", + "yants": "yants" + }, + "locked": { + "lastModified": 1684180498, + "narHash": "sha256-kA58ms4yunOVPhe3r7V0IIKeWUV+vl4r2GTcfFfYW5o=", + "owner": "divnix", + "repo": "std", + "rev": "45b431ae09df98e046bcc8271aa209bdfc87444d", + "type": "github" + }, + "original": { + "owner": "divnix", + "repo": "std", + "type": "github" + } + }, + "std-data-collection": { + "inputs": { + "nixpkgs": [ + "nixos-extra-modules", + "nixt", + "nixpkgs" + ], + "std": [ + "nixos-extra-modules", + "nixt", + "std" + ] + }, + "locked": { + "lastModified": 1676163535, + "narHash": "sha256-xofkWLBqU4zj5vzJhWor2Z9CyPGKt7UGkTchsCT48Po=", + "owner": "divnix", + "repo": "std-data-collection", + "rev": "f713d81a6197e1b0854fb201cc7acde5ef9e93d4", + "type": "github" + }, + "original": { + "owner": "divnix", + "repo": "std-data-collection", + "type": "github" + } + }, + "stylix": { + "inputs": { + "base16": "base16", + "base16-fish": "base16-fish", + "base16-helix": "base16-helix", + "base16-vim": "base16-vim", + "firefox-gnome-theme": "firefox-gnome-theme", + "flake-parts": "flake-parts_5", + "gnome-shell": "gnome-shell", + "nixpkgs": "nixpkgs_23", + "nur": "nur_2", + "systems": "systems_6", + "tinted-foot": "tinted-foot", + "tinted-kitty": "tinted-kitty", + "tinted-schemes": "tinted-schemes", + "tinted-tmux": "tinted-tmux", + "tinted-zed": "tinted-zed" + }, + "locked": { + "lastModified": 1763845141, + "narHash": "sha256-o8TKdZluj/yC8qPIVNe2g4qopyFmQglH52+lvQx82kE=", + "owner": "danth", + "repo": "stylix", + "rev": "adc650610085adbe130b9860d5bdb869f96050af", + "type": "github" + }, + "original": { + "owner": "danth", + "repo": "stylix", + "type": "github" + } + }, + "swarsel-nix": { + "inputs": { + "flake-parts": "flake-parts_6", + "nixpkgs": "nixpkgs_24", + "systems": "systems_7" + }, + "locked": { + "lastModified": 1760190732, + "narHash": "sha256-Bxn/5+MCKOzR9LgUyHDhxCU3eejxz+hfsAT9Sqqz6B0=", + "owner": "Swarsel", + "repo": "swarsel-nix", + "rev": "f0ab1f68c94d777aa7d0a8f23745cb9aa8172fd4", + "type": "github" + }, + "original": { + "owner": "Swarsel", + "ref": "main", + "repo": "swarsel-nix", + "type": "github" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "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, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_3": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_4": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_5": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_6": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_7": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_8": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "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": { + "lastModified": 1726913040, + "narHash": "sha256-+eDZPkw7efMNUf3/Pv0EmsidqdwNJ1TaOum6k7lngDQ=", + "owner": "tinted-theming", + "repo": "tinted-foot", + "rev": "fd1b924b6c45c3e4465e8a849e67ea82933fcbe4", + "type": "github" + }, + "original": { + "owner": "tinted-theming", + "repo": "tinted-foot", + "rev": "fd1b924b6c45c3e4465e8a849e67ea82933fcbe4", + "type": "github" + } + }, + "tinted-kitty": { + "flake": false, + "locked": { + "lastModified": 1735730497, + "narHash": "sha256-4KtB+FiUzIeK/4aHCKce3V9HwRvYaxX+F1edUrfgzb8=", + "owner": "tinted-theming", + "repo": "tinted-kitty", + "rev": "de6f888497f2c6b2279361bfc790f164bfd0f3fa", + "type": "github" + }, + "original": { + "owner": "tinted-theming", + "repo": "tinted-kitty", + "type": "github" + } + }, + "tinted-schemes": { + "flake": false, + "locked": { + "lastModified": 1757716333, + "narHash": "sha256-d4km8W7w2zCUEmPAPUoLk1NlYrGODuVa3P7St+UrqkM=", + "owner": "tinted-theming", + "repo": "schemes", + "rev": "317a5e10c35825a6c905d912e480dfe8e71c7559", + "type": "github" + }, + "original": { + "owner": "tinted-theming", + "repo": "schemes", + "type": "github" + } + }, + "tinted-tmux": { + "flake": false, + "locked": { + "lastModified": 1757811970, + "narHash": "sha256-n5ZJgmzGZXOD9pZdAl1OnBu3PIqD+X3vEBUGbTi4JiI=", + "owner": "tinted-theming", + "repo": "tinted-tmux", + "rev": "d217ba31c846006e9e0ae70775b0ee0f00aa6b1e", + "type": "github" + }, + "original": { + "owner": "tinted-theming", + "repo": "tinted-tmux", + "type": "github" + } + }, + "tinted-zed": { + "flake": false, + "locked": { + "lastModified": 1757811247, + "narHash": "sha256-4EFOUyLj85NRL3OacHoLGEo0wjiRJzfsXtR4CZWAn6w=", + "owner": "tinted-theming", + "repo": "base16-zed", + "rev": "824fe0aacf82b3c26690d14e8d2cedd56e18404e", + "type": "github" + }, + "original": { + "owner": "tinted-theming", + "repo": "base16-zed", + "type": "github" + } + }, + "treefmt-nix": { + "inputs": { + "nixpkgs": "nixpkgs_25" + }, + "locked": { + "lastModified": 1762938485, + "narHash": "sha256-AlEObg0syDl+Spi4LsZIBrjw+snSVU4T8MOeuZJUJjM=", + "owner": "numtide", + "repo": "treefmt-nix", + "rev": "5b4ee75aeefd1e2d5a1cc43cf6ba65eba75e83e4", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "treefmt-nix", + "type": "github" + } + }, + "vbc-nix": { + "inputs": { + "nixpkgs": "nixpkgs_26", + "systems": "systems_9" + }, + "locked": { + "lastModified": 1742477270, + "narHash": "sha256-u78SeVemHqEkN6J+PieL1Kymu+n7LWiTPrUXNd+uePA=", + "ref": "main", + "rev": "0525ad64e2729077ed2cf313d2022e8b8c51153f", + "revCount": 2, + "type": "git", + "url": "ssh://git@github.com/vbc-it/vbc-nix.git" + }, + "original": { + "ref": "main", + "type": "git", + "url": "ssh://git@github.com/vbc-it/vbc-nix.git" + } + }, + "xwayland-satellite-stable": { + "flake": false, + "locked": { + "lastModified": 1755491097, + "narHash": "sha256-m+9tUfsmBeF2Gn4HWa6vSITZ4Gz1eA1F5Kh62B0N4oE=", + "owner": "Supreeeme", + "repo": "xwayland-satellite", + "rev": "388d291e82ffbc73be18169d39470f340707edaa", + "type": "github" + }, + "original": { + "owner": "Supreeeme", + "ref": "v0.7", + "repo": "xwayland-satellite", + "type": "github" + } + }, + "xwayland-satellite-unstable": { + "flake": false, + "locked": { + "lastModified": 1763704521, + "narHash": "sha256-ceYEV6PnvUN8Zixao4gpPuN+VT3B0SlAXKuPNHZhqUY=", + "owner": "Supreeeme", + "repo": "xwayland-satellite", + "rev": "f379ff5722a821212eb59ada9cf8e51cb3654aad", + "type": "github" + }, + "original": { + "owner": "Supreeeme", + "repo": "xwayland-satellite", + "type": "github" + } + }, + "yants": { + "inputs": { + "nixpkgs": [ + "nixos-extra-modules", + "nixt", + "std", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1667096281, + "narHash": "sha256-wRRec6ze0gJHmGn6m57/zhz/Kdvp9HS4Nl5fkQ+uIuA=", + "owner": "divnix", + "repo": "yants", + "rev": "d18f356ec25cb94dc9c275870c3a7927a10f8c3c", + "type": "github" + }, + "original": { + "owner": "divnix", + "repo": "yants", + "type": "github" + } + }, + "zjstatus": { + "inputs": { + "crane": "crane_3", + "flake-utils": "flake-utils_8", + "nixpkgs": "nixpkgs_27", + "rust-overlay": "rust-overlay_3" + }, + "locked": { + "lastModified": 1761162625, + "narHash": "sha256-cJD5RccT5aFwLFiId8PW91z39MpoQZIymj+qZEJ5jTE=", + "owner": "dj95", + "repo": "zjstatus", + "rev": "a4bb655af8f49fe53de7fefca54348de21ecbbb2", + "type": "github" + }, + "original": { + "owner": "dj95", + "repo": "zjstatus", + "type": "github" + } + } }, "root": "root", "version": 7 diff --git a/flake.nix b/flake.nix index 925b8ce..944e25f 100644 --- a/flake.nix +++ b/flake.nix @@ -4,282 +4,86 @@ nixConfig = { extra-substituters = [ "https://nix-community.cachix.org" - "https://cache.ngi0.nixos.org/" ]; - extra-trusted-public-keys = [ "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" - "cache.ngi0.nixos.org-1:KqH5CBLNSyX184S9BKZJo1LxrxJ9ltnY2uAs5c/f1MA=" ]; }; - inputs = { - nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; + smallpkgs.url = "github:nixos/nixpkgs/08fcb0dcb59df0344652b38ea6326a2d8271baff?narHash=sha256-HXIQzULIG/MEUW2Q/Ss47oE3QrjxvpUX7gUl4Xp6lnc%3D&shallow=1"; + nixpkgs-dev.url = "github:Swarsel/nixpkgs/main"; + nixpkgs-kernel.url = "github:NixOS/nixpkgs/063f43f2dbdef86376cc29ad646c45c46e93234c?narHash=sha256-6m1Y3/4pVw1RWTsrkAK2VMYSzG4MMIj7sqUy7o8th1o%3D"; #specifically pinned for kernel version + nixpkgs-stable.url = "github:NixOS/nixpkgs/nixos-25.05"; + nixpkgs-stable24_05.url = "github:NixOS/nixpkgs/nixos-24.05"; + nixpkgs-stable24_11.url = "github:NixOS/nixpkgs/nixos-24.11"; + nixpkgs-stable25_05.url = "github:NixOS/nixpkgs/nixos-25.05"; - nixpkgs-stable.url = "github:NixOS/nixpkgs/nixos-24.05"; - - systems.url = "github:nix-systems/default-linux"; - - # user-level configuration home-manager = { - url = "github:nix-community/home-manager"; + # url = "github:nix-community/home-manager"; + url = "github:Swarsel/home-manager/main"; inputs.nixpkgs.follows = "nixpkgs"; }; - - # overlay to access bleeding edge emacs - emacs-overlay = { - url = "github:nix-community/emacs-overlay"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - - # nix user repository - # i use this mainly to not have to build all firefox extensions - # myself as well as for the emacs-init package (tbd) - nur.url = "github:nix-community/NUR"; - - # provides GL to non-NixOS hosts - nixgl.url = "github:guibou/nixGL"; - - # manages all theming using Home-Manager - stylix.url = "github:danth/stylix"; - - # nix secrets management - sops-nix.url = "github:Mic92/sops-nix"; - - # enable secure boot on NixOS - lanzaboote.url = "github:nix-community/lanzaboote"; - - # nix for android - nix-on-droid = { - url = "github:nix-community/nix-on-droid/release-24.05"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - - # generate NixOS images - nixos-generators = { - url = "github:nix-community/nixos-generators"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - - # hardware quirks on nix - nixos-hardware = { - url = "github:NixOS/nixos-hardware/master"; - }; - - # dynamic library loading - nix-alien = { - url = "github:thiagokokada/nix-alien"; - }; - - # automatic nintendo switch payload injection - nswitch-rcm-nix = { - url = "github:Swarsel/nswitch-rcm-nix"; - }; - - # weekly updated nix-index database nix-index-database = { url = "github:nix-community/nix-index-database"; inputs.nixpkgs.follows = "nixpkgs"; }; - disko = { - url = "github:nix-community/disko"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - + # emacs-overlay.url = "github:nix-community/emacs-overlay"; + emacs-overlay.url = "github:nix-community/emacs-overlay/aba8daa237dc07a3bb28a61c252a718e8eb38057?narHash=sha256-4OXXccXsY1sBXTXjYIthdjXLAotozSh4F8StGRuLyMQ%3D"; + swarsel-nix.url = "github:Swarsel/swarsel-nix/main"; + systems.url = "github:nix-systems/default"; + nur.url = "github:nix-community/NUR"; + nixgl.url = "github:guibou/nixGL"; + stylix.url = "github:danth/stylix"; + sops-nix.url = "github:Mic92/sops-nix"; + lanzaboote.url = "github:nix-community/lanzaboote"; + nix-on-droid.url = "github:nix-community/nix-on-droid/release-24.05"; + nixos-generators.url = "github:nix-community/nixos-generators"; + nixos-images.url = "github:Swarsel/nixos-images/main"; + nixos-hardware.url = "github:NixOS/nixos-hardware/master"; + nswitch-rcm-nix.url = "github:Swarsel/nswitch-rcm-nix"; + disko.url = "github:nix-community/disko"; impermanence.url = "github:nix-community/impermanence"; - - zjstatus = { - url = "github:dj95/zjstatus"; - }; - - fw-fanctrl = { - url = "github:TamtamHero/fw-fanctrl/packaging/nix"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - - nix-darwin = { - url = "github:lnl7/nix-darwin"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - - pre-commit-hooks = { - url = "github:cachix/git-hooks.nix"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - - nix-secrets = { - url = "git+ssh://git@github.com/Swarsel/nix-secrets.git?ref=main&shallow=1"; - flake = false; - inputs = { }; - }; - + zjstatus.url = "github:dj95/zjstatus"; + nix-darwin.url = "github:lnl7/nix-darwin"; + pre-commit-hooks.url = "github:cachix/git-hooks.nix"; + vbc-nix.url = "git+ssh://git@github.com/vbc-it/vbc-nix.git?ref=main"; + nix-topology.url = "github:oddlama/nix-topology"; + flake-parts.url = "github:hercules-ci/flake-parts"; + devshell.url = "github:numtide/devshell"; + spicetify-nix.url = "github:Gerg-l/spicetify-nix"; + niri-flake.url = "github:sodiboo/niri-flake"; + nixos-extra-modules.url = "github:oddlama/nixos-extra-modules/main"; + microvm.url = "github:astro/microvm.nix"; + treefmt-nix.url = "github:numtide/treefmt-nix"; + dns.url = "github:kirelagin/dns.nix"; + nix-minecraft.url = "github:Infinidoge/nix-minecraft"; + simple-nixos-mailserver.url = "gitlab:simple-nixos-mailserver/nixos-mailserver/master"; }; outputs = - inputs@{ self - , nixpkgs - , home-manager - , nix-darwin - , systems - , ... - }: - let - - inherit (self) outputs; - lib = nixpkgs.lib // home-manager.lib; - - pkgsFor = lib.genAttrs (import systems) ( - system: - import nixpkgs { - inherit system; - config.allowUnfree = true; - } - ); - forEachSystem = f: lib.genAttrs (import systems) (system: f pkgsFor.${system}); - forAllSystems = lib.genAttrs [ + inputs: + inputs.flake-parts.lib.mkFlake { inherit inputs; } { + imports = [ + ./nix/globals.nix + ./nix/hosts.nix + ./nix/topology.nix + ./nix/devshell.nix + ./nix/apps.nix + ./nix/packages.nix + ./nix/overlays.nix + ./nix/lib.nix + ./nix/templates.nix + ./nix/formatter.nix + ./nix/modules.nix + ./nix/iso.nix + ]; + systems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ]; - mkFullHost = host: isNixos: { - ${host} = - let - func = if isNixos then lib.nixosSystem else inputs.nix-darwin.lib.darwinSystem; - systemFunc = func; - in - systemFunc { - specialArgs = { inherit inputs outputs self; }; - modules = [ ./hosts/${if isNixos then "nixos" else "darwin"}/${host} ]; - }; - }; - mkFullHostConfigs = hosts: isNixos: lib.foldl (acc: set: acc // set) { } (lib.map (host: mkFullHost host isNixos) hosts); - readHosts = folder: lib.attrNames (builtins.readDir ./hosts/${folder}); - - # NixOS modules that can only be used on NixOS systems - nixModules = [ - inputs.stylix.nixosModules.stylix - inputs.lanzaboote.nixosModules.lanzaboote - inputs.disko.nixosModules.disko - # inputs.impermanence.nixosModules.impermanence - inputs.sops-nix.nixosModules.sops - inputs.nswitch-rcm-nix.nixosModules.nswitch-rcm - ./profiles/common/nixos - ]; - - # Home-Manager modules wanted on non-NixOS systems - homeModules = [ - inputs.stylix.homeManagerModules.stylix - ]; - - # Home-Manager modules wanted on both NixOS and non-NixOS systems - mixedModules = [ - inputs.sops-nix.homeManagerModules.sops - inputs.nix-index-database.hmModules.nix-index - ./profiles/common/home - ]; - - # For adding things to _module.args (making arguments available globally) - # moduleArgs = [ - # { - # _module.args = { inherit self; }; - # } - # ]; - - in - { - - inherit lib; - inherit mixedModules; - inherit nixModules; - - nixosModules = import ./modules/nixos; - homeManagerModules = import ./modules/home; - - packages = forEachSystem (pkgs: import ./pkgs { inherit pkgs; }); - apps = forAllSystems (system: { - default = self.apps.${system}.bootstrap; - - bootstrap = { - type = "app"; - program = "${self.packages.${system}.bootstrap}/bin/bootstrap"; - }; - - install = { - type = "app"; - program = "${self.packages.${system}.swarsel-install}/bin/swarsel-install"; - }; - - rebuild = { - type = "app"; - program = "${self.packages.${system}.swarsel-rebuild}/bin/swarsel-rebuild"; - }; - }); - devShells = forAllSystems ( - system: - let - pkgs = nixpkgs.legacyPackages.${system}; - checks = self.checks.${system}; - in - { - default = pkgs.mkShell { - NIX_CONFIG = "experimental-features = nix-command flakes"; - inherit (checks.pre-commit-check) shellHook; - buildInputs = checks.pre-commit-check.enabledPackages; - nativeBuildInputs = [ - pkgs.nix - pkgs.home-manager - pkgs.git - pkgs.just - pkgs.age - pkgs.ssh-to-age - pkgs.sops - ]; - }; - } - ); - - formatter = forEachSystem (pkgs: pkgs.nixpkgs-fmt); - checks = forAllSystems ( - system: - let - pkgs = nixpkgs.legacyPackages.${system}; - in - import ./checks { inherit self inputs system pkgs; } - ); - overlays = import ./overlays { inherit inputs; }; - - - nixosConfigurations = - mkFullHostConfigs (readHosts "nixos") true; - - homeConfigurations = { - - "swarsel@home-manager" = inputs.home-manager.lib.homeManagerConfiguration { - pkgs = pkgsFor.x86_64-linux; - extraSpecialArgs = { inherit inputs outputs; }; - modules = homeModules ++ mixedModules ++ [ - ./hosts/home-manager - ]; - }; - - }; - - darwinConfigurations = - mkFullHostConfigs (readHosts "darwin") false; - - nixOnDroidConfigurations = { - - magicant = inputs.nix-on-droid.lib.nixOnDroidConfiguration { - pkgs = pkgsFor.aarch64-linux; - modules = [ - ./hosts/magicant - ]; - }; - - }; - }; } diff --git a/hosts/nix-on-droid/magicant/default.nix b/hosts/android/aarch64-linux/magicant/default.nix similarity index 100% rename from hosts/nix-on-droid/magicant/default.nix rename to hosts/android/aarch64-linux/magicant/default.nix diff --git a/hosts/darwin/nbm-imba-166/default.nix b/hosts/darwin/nbm-imba-166/default.nix deleted file mode 100644 index 49fcfd1..0000000 --- a/hosts/darwin/nbm-imba-166/default.nix +++ /dev/null @@ -1,33 +0,0 @@ -{ self, inputs, outputs, ... }: -let - profilesPath = "${self}/profiles"; -in -{ - imports = [ - "${profilesPath}/darwin/common/nixos" - - inputs.home-manager.darwinModules.home-manager - { - home-manager.users."leon.schwarzaeugl".imports = [ - "${profilesPath}/darwin/common/home" - ] ++ (builtins.attrValues outputs.homeManagerModules); - } - ] ++ (builtins.attrValues outputs.nixosModules); - - - # Auto upgrade nix package and the daemon service. - services.nix-daemon.enable = true; - services.karabiner-elements.enable = true; - - home-manager.users."leon.schwarzaeugl".home = { - username = lib.mkForce "leon.schwarzaeugl"; - swarselsystems = { - isDarwin = true; - isLaptop = true; - isNixos = false; - isBtrfs = false; - }; - }; - - -} diff --git a/hosts/darwin/x86_64-darwin/machpizza/default.nix b/hosts/darwin/x86_64-darwin/machpizza/default.nix new file mode 100644 index 0000000..2e77295 --- /dev/null +++ b/hosts/darwin/x86_64-darwin/machpizza/default.nix @@ -0,0 +1,23 @@ +{ lib, config, ... }: +let + inherit (config.repo.secrets.local) workUser; +in +{ + + # Auto upgrade nix package and the daemon service. + services.nix-daemon.enable = true; + services.karabiner-elements.enable = true; + + home-manager.users.workUser.home = { + username = lib.mkForce workUser; + swarselsystems = { + isDarwin = true; + isLaptop = true; + isNixos = false; + isBtrfs = false; + mainUser = workUser; + homeDir = "/home/${workUser}"; + flakePath = "/home/${workUser}/.dotfiles"; + }; + }; +} diff --git a/hosts/darwin/x86_64-darwin/machpizza/secrets/pii.nix.enc b/hosts/darwin/x86_64-darwin/machpizza/secrets/pii.nix.enc new file mode 100644 index 0000000..8b96a26 --- /dev/null +++ b/hosts/darwin/x86_64-darwin/machpizza/secrets/pii.nix.enc @@ -0,0 +1,16 @@ +{ + "data": "ENC[AES256_GCM,data:6u0RRfaZaNk5KwnMoWY4dUC7xn132a7yKDZnStUSRS+Ci7XHMak=,iv:VQ2cYcdOS+S31d1yQioj95CTVmuvBVkgojIs6ib9iOM=,tag:QtC54hIryboeaOnDf1u2yw==,type:str]", + "sops": { + "lastmodified": "2025-06-11T13:04:16Z", + "mac": "ENC[AES256_GCM,data:sOzsL5QIET0hGTR3UwcKx7G8RAlOoLZaDlqsn9Yqw2+0yHPmNFs1N1BST3NNaNe+P9j2XruGgBNGCCm9igq8j37W46hf6uAy69Rx1Kzvrxih2Qu3P0Bb1ozyymQxeXDtKdvC0pxOFsgEk05l9VG0JM2Calxq/pK/EoGPfRQS1Zg=,iv:l0M0BrEQSixlU4I2UrB5g0FaKL32/VrCyJcm3MXujRs=,tag:hiNfmFMpHtoghOEv5JmVKw==,type:str]", + "pgp": [ + { + "created_at": "2025-06-11T13:03:51Z", + "enc": "-----BEGIN PGP MESSAGE-----\n\nhQIMAwDh3VI7VctTAQ//cqwpzR+VevsftDMoj79xiFvayPxluot/mZKQAMPNpMIG\nKDNMYYnIKa1z5TBeDVuivslEytIqB8zEmiZ0Sa6oMJ3T1t72cQbKjARKyKxneGAz\nYqVEM/zHq6W4E0NwE74F4ZAhGA8abFu6nKxQwITwyw28TiOzkNHG0W49ZRLXAHRm\nRBih8p6B05Q1EPK3I3Gz4KUklqNptrbjtRvTzcLcVEkfbOhKz2OOck1a/kqjmKrb\n7/9ORD00wfcXnUykIzN7noe5WixEuDdaE1T2f7kgB1749OVPNW4ZhWsm6yGsRJbJ\nh3n4xUhTrwRZ+9MtWqOdoJ8Z2I8ylUmXiHJYfOj/U/BG7H4y/EMXQ8RR4sMZjlcm\nqhuzor4Ku8Og72RHhY7SnSCCSH10uHVqlfapVH7iLkwywg3pKWdqqEv7wU7A83tR\noDa7+zD4wZYS4p6TEvvv9jyUE9r5A0r5evqHSHzM6Cgkp42FDWkTb30NeBvX2RJC\nyBeQEPqiaAIM+dUdxvM+cFzYBMVdfMtgQHwr3Wkw+Bb2+Pt/JDxcSDBtJbxl+GGp\n+tWn6etfSe4Nr0Z0abgUcKq+niaM8rD4W0DhLNDLhXE2KRTbQV0YgBqlXZf+uY8A\nHagbCeGGT0k67PJs++hlDEeVhB980eMzHdLsv0w+Ie6bttgY81gOvsrr23RQN42F\nAgwDC9FRLmchgYQBD/46neLbZcA0IIPUyeOjwiS2p1O1sR/i9UaSALa+4lw/pdCu\n7iPWwGMDNkh6I+5A3++3lC3MME7A846MFGq9iFpH/+TyTZrqnwcwGY92CE60T1Q6\nouA+g7C/CIX1r04IiAVxi9tBjUmB+dFApdFCC5Mg6Yx+3zh6Z49zvMoO5yGqLLhE\nhqAgxJB0lB07nepgB0spJAaKBs7GyYEss3Cm5WpsitLitPRMEUKLcdvYUw6G09Kc\ndmJb9LbZy4Mn7YziIb+czWZ/hW6B7BUSUZMhQJwMcRFBT6+6aTpO6zWM7URbPQaO\nieN+2ShM5OotiUiO3nfRquBw5mUFDOR1ZVxF/rBtiZe2Jt0URE7pKfcuFQREKp01\nVgI+JUrEl0t8e5J3SSAoXColf+Oq4xDY+CNUJOAtuJ/LrNc0+Q0KwZwShHzGOl5M\neqUgkS+IMYrfJjuJZjTzQTJJ6PeC2VpEGO7czgCn9/5FftsrH2wSSLL4FGX4tXfU\nhrbtt4gMN0had0QkZkuhxlIwYcATjUQ7CGQfrhINC+EpEju/NlE6zuuIa+05eigR\n3kEemBa5Ely4onQeMh81nOAyhkhj6QcbE7qn+ueUMAb70u5B115ULLQUrivLu2jI\nSK6o1WAeZKZIcf0/6iB+mMc7qbG36nelK2JYK8e0KiVSIUGehpYwV3ELwuhzEtJc\nAYobc//aa6GU3pCFzp90TA9kAZXhqgaw9wkzicueAhgCfr8s0FxG5WxWQxfJBLYF\nVSPqrqJ0EBU1EF9G2nz0ynJL1iWiN5VcN7JTXYXTK8TPJUe0ZU1boS4AhOY=\n=AG4y\n-----END PGP MESSAGE-----", + "fp": "4BE7925262289B476DBBC17B76FD3810215AE097" + } + ], + "unencrypted_suffix": "_unencrypted", + "version": "3.10.2" + } +} diff --git a/hosts/home-manager/default/default.nix b/hosts/home-manager/default/default.nix deleted file mode 100644 index 548b943..0000000 --- a/hosts/home-manager/default/default.nix +++ /dev/null @@ -1,55 +0,0 @@ -{ self, inputs, outputs, config, ... }: -{ - - imports = builtins.attrValues outputs.homeManagerModules; - - nixpkgs = { - overlays = [ outputs.overlays.default ]; - config = { - allowUnfree = true; - }; - }; - - services.xcape = { - enable = true; - mapExpression = { - Control_L = "Escape"; - }; - }; - - programs.zsh.initExtra = " - export GPG_TTY=\"$(tty)\" - export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket) - gpgconf --launch gpg-agent - "; - - swarselsystems = { - isLaptop = true; - isNixos = false; - wallpaper = self + /wallpaper/surfacewp.png; - temperatureHwmon = { - isAbsolutePath = true; - path = "/sys/devices/platform/thinkpad_hwmon/hwmon/"; - input-filename = "temp1_input"; - }; - monitors = { - main = { - name = "California Institute of Technology 0x1407 Unknown"; - mode = "1920x1080"; # TEMPLATE - scale = "1"; - position = "2560,0"; - workspace = "2:二"; - output = "eDP-1"; - }; - }; - inputs = { - "1:1:AT_Translated_Set_2_keyboard" = { - xkb_layout = "us"; - xkb_options = "grp:win_space_toggle"; - xkb_variant = "altgr-intl"; - }; - }; - keybindings = { }; - }; - -} diff --git a/hosts/home/aarch64-linux/treehouse/default.nix b/hosts/home/aarch64-linux/treehouse/default.nix new file mode 100644 index 0000000..90acf4b --- /dev/null +++ b/hosts/home/aarch64-linux/treehouse/default.nix @@ -0,0 +1,39 @@ +{ self, pkgs, ... }: +{ + + imports = [ + # inputs.sops-nix.homeManagerModules.sops + "${self}/modules/home" + "${self}/modules/nixos/common/pii.nix" + "${self}/modules/nixos/common/meta.nix" + ]; + + + services.xcape = { + enable = true; + mapExpression = { + Control_L = "Escape"; + }; + }; + + home.packages = with pkgs; [ + attic-client + ]; + # programs.zsh.initContent = " + # export GPG_TTY=\"$(tty)\" + # export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket) + # gpgconf --launch gpg-agent + # "; + swarselmodules.pii = true; + + swarselsystems = { + isLaptop = false; + isNixos = false; + wallpaper = self + /files/wallpaper/surfacewp.png; + }; + + swarselprofiles = { + dgxspark = true; + }; + +} diff --git a/hosts/nixos/aarch64-linux/belchsfactory/default.nix b/hosts/nixos/aarch64-linux/belchsfactory/default.nix new file mode 100644 index 0000000..cd85107 --- /dev/null +++ b/hosts/nixos/aarch64-linux/belchsfactory/default.nix @@ -0,0 +1,58 @@ +{ self, lib, minimal, ... }: +{ + imports = [ + ./hardware-configuration.nix + ./disk-config.nix + + "${self}/modules/nixos/optional/systemd-networkd-server.nix" + ]; + + node.lockFromBootstrapping = lib.mkForce false; + + topology.self = { + icon = "devices.cloud-server"; + }; + swarselmodules.server.nginx = false; + + swarselsystems = { + flakePath = "/root/.dotfiles"; + info = "VM.Standard.A1.Flex, 4 vCPUs, 24GB RAM"; + isImpermanence = true; + isSecureBoot = false; + isCrypted = true; + isSwap = false; + rootDisk = "/dev/sda"; + isBtrfs = true; + isNixos = true; + isLinux = true; + isCloud = true; + server = { + garage = { + data_dir = { + capacity = "150G"; + path = "/var/lib/garage/data"; + }; + keys = { + nixos = [ + "attic" + ]; + }; + buckets = [ + "attic" + ]; + }; + }; + }; +} // lib.optionalAttrs (!minimal) { + swarselprofiles = { + server = true; + }; + + swarselmodules.server = { + ssh-builder = lib.mkDefault true; + postgresql = lib.mkDefault true; + attic = lib.mkDefault true; + garage = lib.mkDefault true; + }; + +} diff --git a/hosts/nixos/aarch64-linux/belchsfactory/disk-config.nix b/hosts/nixos/aarch64-linux/belchsfactory/disk-config.nix new file mode 100644 index 0000000..9a98cce --- /dev/null +++ b/hosts/nixos/aarch64-linux/belchsfactory/disk-config.nix @@ -0,0 +1,121 @@ +{ lib, pkgs, config, ... }: +let + type = "btrfs"; + extraArgs = [ "-L" "nixos" "-f" ]; # force overwrite + subvolumes = { + "/root" = { + mountpoint = "/"; + mountOptions = [ + "subvol=root" + "compress=zstd" + "noatime" + ]; + }; + "/home" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/home"; + mountOptions = [ + "subvol=home" + "compress=zstd" + "noatime" + ]; + }; + "/persist" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/persist"; + mountOptions = [ + "subvol=persist" + "compress=zstd" + "noatime" + ]; + }; + "/log" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/var/log"; + mountOptions = [ + "subvol=log" + "compress=zstd" + "noatime" + ]; + }; + "/nix" = { + mountpoint = "/nix"; + mountOptions = [ + "subvol=nix" + "compress=zstd" + "noatime" + ]; + }; + "/swap" = lib.mkIf config.swarselsystems.isSwap { + mountpoint = "/.swapvol"; + swap.swapfile.size = config.swarselsystems.swapSize; + }; + }; +in +{ + disko = { + imageBuilder.extraDependencies = [ pkgs.kmod ]; + devices = { + disk = { + disk0 = { + type = "disk"; + device = config.swarselsystems.rootDisk; + content = { + type = "gpt"; + partitions = { + ESP = { + priority = 1; + name = "ESP"; + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "defaults" ]; + }; + }; + root = lib.mkIf (!config.swarselsystems.isCrypted) { + size = "100%"; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/disk/by-label/nixos" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + luks = lib.mkIf config.swarselsystems.isCrypted { + size = "100%"; + content = { + type = "luks"; + name = "cryptroot"; + passwordFile = "/tmp/disko-password"; # this is populated by bootstrap.sh + settings = { + allowDiscards = true; + # https://github.com/hmajid2301/dotfiles/blob/a0b511c79b11d9b4afe2a5e2b7eedb2af23e288f/systems/x86_64-linux/framework/disks.nix#L36 + crypttabExtraOpts = [ + "fido2-device=auto" + "token-timeout=10" + ]; + }; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/mapper/cryptroot" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + }; + }; + }; + }; + }; + }; + }; + + fileSystems."/persist".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + fileSystems."/home".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; +} diff --git a/hosts/nixos/aarch64-linux/belchsfactory/hardware-configuration.nix b/hosts/nixos/aarch64-linux/belchsfactory/hardware-configuration.nix new file mode 100644 index 0000000..2278aaf --- /dev/null +++ b/hosts/nixos/aarch64-linux/belchsfactory/hardware-configuration.nix @@ -0,0 +1,15 @@ +{ lib, modulesPath, ... }: +{ + imports = [ (modulesPath + "/profiles/qemu-guest.nix") ]; + + boot = { + initrd = { + availableKernelModules = [ "xhci_pci" "virtio_pci" "virtio_scsi" "usbhid" ]; + kernelModules = [ ]; + }; + kernelModules = [ ]; + extraModulePackages = [ ]; + }; + + nixpkgs.hostPlatform = lib.mkForce "aarch64-linux"; +} diff --git a/hosts/nixos/aarch64-linux/belchsfactory/secrets/pii.nix.enc b/hosts/nixos/aarch64-linux/belchsfactory/secrets/pii.nix.enc new file mode 100644 index 0000000..efc25e8 --- /dev/null +++ b/hosts/nixos/aarch64-linux/belchsfactory/secrets/pii.nix.enc @@ -0,0 +1,22 @@ +{ + "data": "ENC[AES256_GCM,data:8qaX0CjyxK8qoAyVyxwfXlejWyGSY579EVmmUCi9PPyB5LyPjfDvXxlRFCOlC6eYbSJ1AWLqqZ6yYgZaimUHkOTh7dL+D4wSkmGeRnxZoQhq9n9sYZPJUfqEhMwEGxlrAvchXJuruZG+Tp9+Ev0if9f9J9qdU1y+yLGQxc2vnibMg2uxdpfYjHaDWa9bybRQZxINkD//um8uxkRs0xvWgZu63ReQZMPjx9K3vNtdJTZsW5+ZUB368QA2mnry2Zf60PWJT/+NsNKIwyzjhUNJ/eTFxjNJ4zPj/AnXFezfGvpVu6XFYsLk5uPb3XfpUlCj4mTVvmVlA40lf4rOhyoRRAW8d28puJArBf3nPzIkWQUfmFwO5EE3qPDkjMlaRa/RdRx0dvrbLDv7Ujt1XaK8bl3Vkz77oumCYFPV7J4mAeu3/LFBAoWKik6Wj8WQE+QwUWo=,iv:ZQaOO2Blpqn+Xnzt4fcPu+rNAvEdluwJEYRxPVItLcU=,tag:rKJ5g27ZK1wCpcyCVfffpA==,type:str]", + "sops": { + "age": [ + { + "recipient": "age1k73gy5em3js9zklnnkzp5hme9k04lny32fgahmzddknjw5c295asdyr4x6", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBzbi9PZkRob2JkcjlEMUJu\nSG5TemplWkhWVXZNWStCVXhrUlFRSUtPeWk4CjZEQVN4b1lYVkxYQmU0SEJ0QnAv\nTE9IdHZUYmVjb0hxSno1QWxGN1ZMUFEKLS0tIEwrVU5uZmZPRGdZcjVsVk1IQ1Vv\nRXdMcW0xR2g5SCswKzF5RkIwUmtocDgKVI/EMQuvfKGeJH7wFm8VP5rKLhYKOlPt\nA+QIDAdrtFogW9Swwhzxu1tIOfMXzfyW9P+ec/b6/vU96PMqJQ6ZGg==\n-----END AGE ENCRYPTED FILE-----\n" + } + ], + "lastmodified": "2025-11-28T14:15:06Z", + "mac": "ENC[AES256_GCM,data:TxnVPtRHzUEr9StM3RlOgqD11036yM74HL1Q8ZkNSU89geAaUoDj8LJD1QKglDT5UNzfKeaZD4DT6bqill+H5FUuonOgLPxNoFKMyWhppQkMWM5F/bw8JUulacmE28b2Rd5zRVOYe3TkE11kMAbxRD+CvqEFBrLsZAndr9QdfUc=,iv:uzjzk1FUN52oAE0cuw7OLLmMRxE/VLQ+tUExxYQjwTQ=,tag:+BOG6wRb0h/jhyy7l8ZA/A==,type:str]", + "pgp": [ + { + "created_at": "2025-11-25T18:32:49Z", + "enc": "-----BEGIN PGP MESSAGE-----\n\nhQIMAwDh3VI7VctTAQ/+Mi33CAnGK/475xmMlZn2P4aR2iFjWFms6XU540JZnfQi\nF6/bjq1otgxGlnR6x3zhPQU3whCQIv538UeiYWMoS8oPxj5b5eF33agihYaCq2wx\nHv4p0+hOJMl2SJPCHfmTkClqYGYMOzTPe1g6oiY0N3FWVoiWXdbWNkIGVNjgkedz\n5f9JPFWn6iB/Z07qUMwG2OOzh8ZPlh/PgNCBrCVMUYrD/FrAck389uMw4yHFz8AV\n3ETnx2gHFTwL5F8H7x3uVungoBVCJk+NpXiKS6nVKwH4jliydiU2ZClSzjHpCqCW\nd365MCahC67IkuCkWhwuPwDaKIk7Qw4rZaLybcad5/TQ0zT+XCm6/2DYIYTj2gip\nqrBDZxHZhkpYcArjckWDRchO9t9E/c3qJfD1Zxi6fBz0vu2WcCuTT8Qd6Zn+DlMb\nVr0D2LPlZGRJ+kM9xuZXaY1bGNAA2POvLn698prPuTkMNxidQEhPNuNy4PlYKXAP\nFfRzJ5zFUneW19j8SgL6BxfLoYDFWkoHIutNDH5H290MJqnFDUrQ5bQn8odM+1OL\noJ1AchHN3J0J5aa2Z8X0NSVN7N0TmU3xVZ1GmfdqbH+3V+OR3NMgJ/FKMQEutT56\nAsBc7tSHtJGaRS9plJ+RryuPRRnqGmRkS3vVmBkrD+pY/TwUbXUBKjEOWhq9uwiF\nAgwDC9FRLmchgYQBEACD1XnsK/sTsgtvt69H/aBHWVIWQNTmdhwJBUHmqkusFhPf\nXxfGN+bvapWulYI+Wb4LAQQbUhMmz8drPnWpCEobS3LSeU8CDD3wBrGAJubI7YLK\nttn4oB7XK5mrg9SIQ8M8kOElv19oCMudkX8dRs4gs0TBO6jbr7/lsiyL/sN3Ylk+\nnyORFeSgE9vVcvJ8QnIF+MQXF9Re61zJFqjXiDMEklzbHHVeLzS5IlYgJoDvV3Gg\n9lTtvdO/FV5JtjFeYI16rjPb7ip/KtljU5pBM8wp6VU4Dre0VsRBgztm279g+WaL\nDJuf6lmfwNSk66tiLpsaJoEu7A+UhLURI10cv92E7fydbGRZMgSjK6ZK4Ue6WH1U\nYQJenngZPXcRcqfCeTVTjzG6ikL3aCfvbuJ3/oT8Y8oBA5Ch2PG7fWAJMMUVIFAM\nLO8KqCSdRCoJrJ69s8iyBycOhPhMiwLZU2HLlMux/kLq5OB2JMGm8P4nxoXTp9Dz\n2TPoPigZritYHsIXZ3cM2iR3OL3AiotKlaIp74ElUeuc0K+Bcp1C//OtKTPuYGnc\n0ttC/dx3c9vv6W80JJ6i7bCRoDiuGrrdx783ly2br4VLDFSaS8rNbrM5ccSTVImw\nUFxZO9rLO0n7N6z4hlgrKw3G1SWKYqbgOVXxIog7st8JvmPLQZYjEuH9Xwq6WdJc\nAU2esxsAaDKyIPHg+DAXOPBagzU1tBKFYtwaiFVDqYk5gNE/2hAnKcuU7O3sua1q\ntsgL2kY8VSHcFFv8N6FhDYPdCrDgAwOtJSZGf7uV92q7/vbMWx+vGq/7FaQ=\n=m1sm\n-----END PGP MESSAGE-----", + "fp": "4BE7925262289B476DBBC17B76FD3810215AE097" + } + ], + "unencrypted_suffix": "_unencrypted", + "version": "3.11.0" + } +} diff --git a/hosts/nixos/aarch64-linux/liliputsteps/default.nix b/hosts/nixos/aarch64-linux/liliputsteps/default.nix new file mode 100644 index 0000000..dc866d7 --- /dev/null +++ b/hosts/nixos/aarch64-linux/liliputsteps/default.nix @@ -0,0 +1,41 @@ +{ self, lib, minimal, ... }: +{ + imports = [ + ./hardware-configuration.nix + ./disk-config.nix + + "${self}/modules/nixos/optional/systemd-networkd-server.nix" + ]; + + topology.self = { + icon = "devices.cloud-server"; + }; + + swarselsystems = { + flakePath = "/root/.dotfiles"; + info = "VM.Standard.A1.Flex, 1 vCPUs, 8GB RAM"; + isImpermanence = true; + isSecureBoot = false; + isCrypted = true; + isSwap = false; + rootDisk = "/dev/disk/by-id/scsi-360fb180663ec4f2793a763a087d46885"; + isBtrfs = true; + isNixos = true; + isLinux = true; + isCloud = true; + mainUser = "jump"; + }; +} // lib.optionalAttrs (!minimal) { + swarselprofiles = { + server = true; + }; + + swarselmodules.server = { + nginx = false; + bastion = true; + # ssh = false; + }; + + # users.users.swarsel.enable = lib.mkForce false; + # home-manager.users.swarsel.enable = lib.mkForce false +} diff --git a/hosts/nixos/aarch64-linux/liliputsteps/disk-config.nix b/hosts/nixos/aarch64-linux/liliputsteps/disk-config.nix new file mode 100644 index 0000000..9a98cce --- /dev/null +++ b/hosts/nixos/aarch64-linux/liliputsteps/disk-config.nix @@ -0,0 +1,121 @@ +{ lib, pkgs, config, ... }: +let + type = "btrfs"; + extraArgs = [ "-L" "nixos" "-f" ]; # force overwrite + subvolumes = { + "/root" = { + mountpoint = "/"; + mountOptions = [ + "subvol=root" + "compress=zstd" + "noatime" + ]; + }; + "/home" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/home"; + mountOptions = [ + "subvol=home" + "compress=zstd" + "noatime" + ]; + }; + "/persist" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/persist"; + mountOptions = [ + "subvol=persist" + "compress=zstd" + "noatime" + ]; + }; + "/log" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/var/log"; + mountOptions = [ + "subvol=log" + "compress=zstd" + "noatime" + ]; + }; + "/nix" = { + mountpoint = "/nix"; + mountOptions = [ + "subvol=nix" + "compress=zstd" + "noatime" + ]; + }; + "/swap" = lib.mkIf config.swarselsystems.isSwap { + mountpoint = "/.swapvol"; + swap.swapfile.size = config.swarselsystems.swapSize; + }; + }; +in +{ + disko = { + imageBuilder.extraDependencies = [ pkgs.kmod ]; + devices = { + disk = { + disk0 = { + type = "disk"; + device = config.swarselsystems.rootDisk; + content = { + type = "gpt"; + partitions = { + ESP = { + priority = 1; + name = "ESP"; + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "defaults" ]; + }; + }; + root = lib.mkIf (!config.swarselsystems.isCrypted) { + size = "100%"; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/disk/by-label/nixos" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + luks = lib.mkIf config.swarselsystems.isCrypted { + size = "100%"; + content = { + type = "luks"; + name = "cryptroot"; + passwordFile = "/tmp/disko-password"; # this is populated by bootstrap.sh + settings = { + allowDiscards = true; + # https://github.com/hmajid2301/dotfiles/blob/a0b511c79b11d9b4afe2a5e2b7eedb2af23e288f/systems/x86_64-linux/framework/disks.nix#L36 + crypttabExtraOpts = [ + "fido2-device=auto" + "token-timeout=10" + ]; + }; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/mapper/cryptroot" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + }; + }; + }; + }; + }; + }; + }; + + fileSystems."/persist".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + fileSystems."/home".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; +} diff --git a/hosts/nixos/aarch64-linux/liliputsteps/hardware-configuration.nix b/hosts/nixos/aarch64-linux/liliputsteps/hardware-configuration.nix new file mode 100644 index 0000000..2278aaf --- /dev/null +++ b/hosts/nixos/aarch64-linux/liliputsteps/hardware-configuration.nix @@ -0,0 +1,15 @@ +{ lib, modulesPath, ... }: +{ + imports = [ (modulesPath + "/profiles/qemu-guest.nix") ]; + + boot = { + initrd = { + availableKernelModules = [ "xhci_pci" "virtio_pci" "virtio_scsi" "usbhid" ]; + kernelModules = [ ]; + }; + kernelModules = [ ]; + extraModulePackages = [ ]; + }; + + nixpkgs.hostPlatform = lib.mkForce "aarch64-linux"; +} diff --git a/hosts/nixos/aarch64-linux/liliputsteps/secrets/pii.nix.enc b/hosts/nixos/aarch64-linux/liliputsteps/secrets/pii.nix.enc new file mode 100644 index 0000000..bd5dbdf --- /dev/null +++ b/hosts/nixos/aarch64-linux/liliputsteps/secrets/pii.nix.enc @@ -0,0 +1,22 @@ +{ + "data": "ENC[AES256_GCM,data:GntHmFTkr7OKUlAVPP1aPeGJEoM1/W9xoZzdXG/udBrKB8eadaOsdsT9/I4Q4zydLnAUZAb+k+/pu3inqiGPClNWU0LUMj7wTwPuVe57EyLaO2oaN4z2nvWhJnwfatvdLrFICz3MN7XLnpEe3D+3ovN2hmys1pd6cAJtEKDtmLJ3RNAhEXrMwOZ0MSzylApoi9yXULH8PqNBX7jPOZYYZ0jlnIbZB267Ln19ES0bZcK7L0608NdB+Q3xb3TQ+oSfnvsdxKyPkPqjxAto40feG97UYVW6AgYV1KlRp9etjEhIRZgn1qDvigGM/Y4HLgLxPM83h79LIVHDj1OySMyYR4bfwAR1U+Ij2nX0Wv6Q/nKx0Nmghen40AqLYp762ACLVRd30DALthhtMxhsiYIT6za3dNFRNnL1Lfss1+IwDm+XHBehBQsjXbs06nZcQURfszW03Y9KH1h5ePIS93gmkdUyH5Ya1JT609s8faukz4fcNmnXlZcnCW4fUawW3YS1zpWPGDNm54GFI06vii5JuVORrf6m2HJEIyYSzeYASC+rZOfEF8gXGjyaeh/B9nAzSq2Q/Nfm+fsceXfOkhD+ZD/nYg+whYPPfA38B5oWvwnSNRNipJLYVvdLLd6M9pTV2FHuEsFKpXwumuwMAhl287jpDVb5B6gYPnWm4zOXYX3KXd68KVFNOGCC1XrrlqVBwQqraozD+1e77eCK4OEyF8R2Wt+mCFDwrMp5hKiiFCHEX67RYqWwmZVx2hS1bovBfacoXknUaSQnfpUd5GYIVYqonyqo6cdn6LKR/0d+7wR+JuL+PO83XcEQvegfHXAXmxIEzPdsL2PqVWGL2B/qyyAZGb3hoY7hmrpEeCCefYhSkxewVDCuvL7xLBCFjq0PsPJw0CqYE0KDIgXxcGLQ5f+pn6O07YDfN+7PVPrPAaN/UTwd+2Xa9UfVELdKKhAWiywsiDCUVO9vkpvgSoYYSrtB8Ceg3RXWohbO8VrjF6UhUxnslAw8TBnBx4FtaSuI73UiJnkg9V1es47NmOA7,iv:JYRzdtAYu24aWIL/hfWLbkS8xpcPw3ylZROuuUMVmIY=,tag:Ot7G/QiTLhmnlYe7Z9aOTQ==,type:str]", + "sops": { + "age": [ + { + "recipient": "age1ly2endyt0y9xyddj6yuj4nw6fa3ltvzlvew4cr4lzs6dv8dkavpqadmyxx", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBGVU5HTGhyL0ZBRXkzZ3hq\ndzBMd1JZTktZbWNFMGRzcXhFK3RHb090cFdBCmpMa0FNMWFCenBjYk9FaDIrTkFS\nSnN6S210ejN5SVVhd2FWRG1SUHB4WWcKLS0tIDV2K0h1QWxwUXkwVnZlYnR6eEtl\nUVR0UGJOR1hadUtNcjYyWE9wblAwWFUKVM+J/pqtZFADYTQHfWCdvPzlhtgR6zAy\nu0EWk77+K2J0GeBuDr1W5yblUCknht6WZCJZcO6fW7AuWSQK3e/EVA==\n-----END AGE ENCRYPTED FILE-----\n" + } + ], + "lastmodified": "2025-12-01T16:51:40Z", + "mac": "ENC[AES256_GCM,data:SWLGPgFcdiGSvN5BTmE8Nq7+pBiNJM05H1hhqJY6wJqYZehKhQrQRj6/DSlYWPvYE/DdWo5Tiuc3RNY3NANwhki+7kl0OBxHoaHqBgOTa96rdPwe6V3s55v++jtm0xg/qLHEPCqrKqw/aiBAQLJkDOh/IykeEXBMW3S6EM+aQ0U=,iv:2wn4jQHdWWhIzOyGhZxow8WG6W0VgA2gwhb5X+k9ja0=,tag:8g4wQb0u7vbIPkVX8Ey0eA==,type:str]", + "pgp": [ + { + "created_at": "2025-12-01T15:59:42Z", + "enc": "-----BEGIN PGP MESSAGE-----\n\nhQIMAwDh3VI7VctTAQ//cl6I+s/JLwwTCX7WKdzeOIkrsK9DpY3pXBuzoZRSRSJE\nwFJO99Uc7/uH1DSsEB/25CWI6eWx7k6l7YDbcbXQgi5ZNoAt7BePeCu2LK/3coZB\nJe4SManP0sPqxrSd92Tnm6Zl9EL4cJ/5D2C2RBTWOaOtZHR8gyxx5+rzCotCoTXA\nJseGE4B8r/M0O7PAS9+oD14AwCndhuvkmFOq0Y1/wXldV6yCdgc//0oJBSTCBJUZ\nYMSQLovEYGvF9bFfpWYU8J53WqlGn7QKVccDN0/gfi8IVGVZGccUA58VaVqkzR41\ndYlRZ/sjtd+VXmOg8Fx79bOlzTn+RBCp9y+q5yKnzUKGe0/Lrnt6+j7+ieIowi76\npBd0bEaoh6wqdCJ7GSjsj5kdSXRop3Ae0ff+J0pBQNctehpcWj5/TpeA1zyslwEC\nD1B/KVN+Gh0XBCg636dUkt2E4NPNDckSRuvTLy+8IkTm7aQqTjqDu3WUOSPzZiZK\nBUGZWwXAS+xPPMH26X6gPTfZj+7Gdv6yxTVIwkphDbWfihxIP//WNbKX1QN4VSHf\nCmoPOrriIdgZ7d2olZEJxPgEVzavkRkiMSFQbQgzjx5Af3ccdav3mxlubjXldmpe\n689Joj8cgBPg1Yfk/yl7tVK9TFJgYXTqKfsXwscrSlsV+dRAN0pHuq1uo9cTE/SF\nAgwDC9FRLmchgYQBEADCJ5IVMNp+PgUDOiajCfpNq3/HsntzIWG0tIjCb5L9TFWQ\nMA2LQWhcU5CRBh7Sakf8IFi/U40SD+dILUh8JR/7g2i9mCS+1e0pkUwSIYxzAI+z\nQeycuyOrdQJFrk+nFbTdZVAerElxew/wQUiC2uoI8tA5+XyNeNfipaptPh9FpFuz\nXhFbkZDJ4kapGzsAn4FgUdmdqAgZ5n2W46WAmDmVKM0W1F0zZdkBEdkEKkv1gRpZ\nRntb/mVEiGAdXv6yAzvHrxgIBkxazzstRmCMXa252RUIakXqvkP1vw7B6ChSFQR+\nq9WNo9x0EYXivd/+ROjHT7WNhEToWems/3CQpQd1LEFXajLdpAWd875acqhBJqtY\nkpKqUG5F4JmTZ7hMuGI0g30nOofMtmFhDX/gCpJ97lEudHyNrHe0KWaQAwtRknz+\nrcPrZQmGRRcf4xcBVe/EDUNlkp9fPWEhFAwKMsVkkvCAADZbvdhLR6URJMmUj5KG\nOuwglHnSOMxCovAQUd3vCtNkkAnRPNOW/WMThr+qfjq8oKdDIaYBxjzjSz1FIsho\nKiz4W3flRzUcALjKTXadQl/jJEhpP3C6Ivh0d29SiKyrWG+Y4KlDIRctub9UjH46\nb2wqbnBzSrC8u9xJINIB4yryXsZiQyP5b39guSKIPjURebus7LBxq+0I7Z1OptJe\nAYk5htmFDe9Sgc+Do1L0kdxjblaoWOc0OiwYshQ9cMv+/IsU0U6T7w2A+8QkzPFc\nGVEmrW1Jyz2O3eMpq/Nl2IsmPDYTEPqhkRtAshBuYsoZJUz73/EovcSxyJ2moA==\n=o5Pw\n-----END PGP MESSAGE-----", + "fp": "4BE7925262289B476DBBC17B76FD3810215AE097" + } + ], + "unencrypted_suffix": "_unencrypted", + "version": "3.11.0" + } +} diff --git a/hosts/nixos/aarch64-linux/moonside/default.nix b/hosts/nixos/aarch64-linux/moonside/default.nix new file mode 100644 index 0000000..1c3cf3f --- /dev/null +++ b/hosts/nixos/aarch64-linux/moonside/default.nix @@ -0,0 +1,168 @@ +{ lib, config, minimal, ... }: +let + inherit (config.repo.secrets.local.syncthing) dev1 dev2 dev3 loc1; + inherit (config.swarselsystems) sopsFile; +in +{ + imports = [ + ./hardware-configuration.nix + ./disk-config.nix + ]; + + sops = { + age.sshKeyPaths = lib.mkDefault [ "/etc/ssh/ssh_host_ed25519_key" ]; + secrets = { + wireguard-private-key = { inherit sopsFile; }; + wireguard-home-preshared-key = { inherit sopsFile; }; + }; + }; + + boot = { + loader.systemd-boot.enable = true; + tmp.cleanOnBoot = true; + }; + + environment = { + etc."issue".text = "\4"; + }; + + topology.self = { + icon = "devices.cloud-server"; + interfaces.wg = { + addresses = [ "192.168.3.4" ]; + renderer.hidePhysicalConnections = true; + virtual = true; + type = "wireguard"; + }; + }; + + networking = { + domain = "subnet03291956.vcn03291956.oraclevcn.com"; + firewall = { + allowedTCPPorts = [ 8384 ]; + }; + wireguard = { + enable = true; + interfaces = { + home-vpn = { + privateKeyFile = config.sops.secrets.wireguard-private-key.path; + # ips = [ "192.168.3.4/32" ]; + ips = [ "192.168.178.201/24" ]; + peers = [ + { + # publicKey = "NNGvakADslOTCmN9HJOW/7qiM+oJ3jAlSZGoShg4ZWw="; + publicKey = "PmeFInoEJcKx+7Kva4dNnjOEnJ8lbudSf1cbdo/tzgw="; + presharedKeyFile = config.sops.secrets.wireguard-home-preshared-key.path; + name = "moonside"; + persistentKeepalive = 25; + # endpoint = "${config.repo.secrets.common.ipv4}:51820"; + endpoint = "${config.repo.secrets.common.wireguardEndpoint}"; + # allowedIPs = [ + # "192.168.3.0/24" + # "192.168.1.0/24" + # ]; + allowedIPs = [ + "192.168.178.0/24" + ]; + } + ]; + }; + }; + }; + }; + + hardware = { + enableAllFirmware = lib.mkForce false; + }; + + system.stateVersion = "23.11"; + + services.syncthing = { + dataDir = lib.mkForce "/sync"; + settings = { + devices = config.swarselsystems.syncthing.devices // { + "${dev1}" = { + id = "OCCDGDF-IPZ6HHQ-5SSLQ3L-MSSL5ZW-IX5JTAM-PW4PYEK-BRNMJ7E-Q7YDMA7"; + }; + "${dev2}" = { + id = "LPCFIIB-ENUM2V6-F2BWVZ6-F2HXCL2-BSBZXUF-TIMNKYB-7CATP7H-YU5D3AH"; + }; + "${dev3}" = { + id = "LAUT2ZP-KEZY35H-AHR3ARD-URAREJI-2B22P5T-PIMUNWW-PQRDETU-7KIGNQR"; + }; + }; + folders = { + "Documents" = { + path = "/sync/Documents"; + type = "receiveonly"; + versioning = { + type = "simple"; + params.keep = "2"; + }; + devices = [ "pyramid" ]; + id = "hgr3d-pfu3w"; + }; + "runandbun" = { + path = "/sync/runandbun"; + type = "receiveonly"; + versioning = { + type = "simple"; + params.keep = "5"; + }; + devices = [ "winters" "magicant" ]; + id = "kwnql-ev64v"; + }; + "${loc1}" = { + path = "/sync/${loc1}"; + type = "receiveonly"; + versioning = { + type = "simple"; + params.keep = "3"; + }; + devices = [ dev1 dev2 dev3 ]; + id = "5gsxv-rzzst"; + }; + }; + }; + }; + + swarselsystems = { + flakePath = "/root/.dotfiles"; + info = "VM.Standard.A1.Flex, 4 vCPUs, 24GB RAM"; + isImpermanence = true; + isSecureBoot = false; + isCrypted = false; + isSwap = false; + rootDisk = "/dev/sda"; + isBtrfs = true; + isNixos = true; + isLinux = true; + server = { + restic = { + bucketName = "SwarselMoonside"; + paths = [ + "/persist/opt/minecraft" + ]; + }; + }; + syncthing = { + serviceDomain = config.repo.secrets.common.services.domains.syncthing3; + }; + }; +} // lib.optionalAttrs (!minimal) { + swarselprofiles = { + server = true; + }; + + swarselmodules.server = { + oauth2-proxy = true; + croc = true; + microbin = true; + shlink = true; + slink = true; + syncthing = true; + minecraft = true; + restic = true; + diskEncryption = lib.mkForce false; + }; +} diff --git a/hosts/nixos/aarch64-linux/moonside/disk-config.nix b/hosts/nixos/aarch64-linux/moonside/disk-config.nix new file mode 100644 index 0000000..76fc1a4 --- /dev/null +++ b/hosts/nixos/aarch64-linux/moonside/disk-config.nix @@ -0,0 +1,123 @@ +# NOTE: ... is needed because dikso passes diskoFile +{ lib +, config +, ... +}: +let + type = "btrfs"; + extraArgs = [ "-L" "nixos" "-f" ]; # force overwrite + subvolumes = { + "/root" = { + mountpoint = "/"; + mountOptions = [ + "subvol=root" + "compress=zstd" + "noatime" + ]; + }; + "/home" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/home"; + mountOptions = [ + "subvol=home" + "compress=zstd" + "noatime" + ]; + }; + "/persist" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/persist"; + mountOptions = [ + "subvol=persist" + "compress=zstd" + "noatime" + ]; + }; + "/log" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/var/log"; + mountOptions = [ + "subvol=log" + "compress=zstd" + "noatime" + ]; + }; + "/nix" = { + mountpoint = "/nix"; + mountOptions = [ + "subvol=nix" + "compress=zstd" + "noatime" + ]; + }; + "/swap" = lib.mkIf config.swarselsystems.isSwap { + mountpoint = "/.swapvol"; + swap.swapfile.size = config.swarselsystems.swapSize; + }; + }; +in +{ + disko.devices = { + disk = { + disk0 = { + type = "disk"; + device = config.swarselsystems.rootDisk; + content = { + type = "gpt"; + partitions = { + ESP = { + priority = 1; + name = "ESP"; + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "defaults" ]; + }; + }; + root = { + size = "100%"; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/disk/by-label/nixos" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + }; + }; + }; + disk1 = { + type = "disk"; + device = "/dev/sdb"; + content = { + type = "gpt"; + partitions = { + sync = { + size = "100%"; + content = { + type = "btrfs"; + extraArgs = [ "-L" "sync" "-f" ]; # force overwrite + subvolumes = { + "/sync" = { + mountpoint = "/sync"; + mountOptions = [ + "subvol=root" + "compress=zstd" + "noatime" + ]; + }; + }; + }; + }; + }; + }; + }; + }; + }; + + fileSystems."/persist".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + fileSystems."/home".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; +} diff --git a/hosts/nixos/aarch64-linux/moonside/hardware-configuration.nix b/hosts/nixos/aarch64-linux/moonside/hardware-configuration.nix new file mode 100644 index 0000000..2278aaf --- /dev/null +++ b/hosts/nixos/aarch64-linux/moonside/hardware-configuration.nix @@ -0,0 +1,15 @@ +{ lib, modulesPath, ... }: +{ + imports = [ (modulesPath + "/profiles/qemu-guest.nix") ]; + + boot = { + initrd = { + availableKernelModules = [ "xhci_pci" "virtio_pci" "virtio_scsi" "usbhid" ]; + kernelModules = [ ]; + }; + kernelModules = [ ]; + extraModulePackages = [ ]; + }; + + nixpkgs.hostPlatform = lib.mkForce "aarch64-linux"; +} diff --git a/hosts/nixos/aarch64-linux/moonside/secrets/pii.nix.enc b/hosts/nixos/aarch64-linux/moonside/secrets/pii.nix.enc new file mode 100644 index 0000000..dd4cf5e --- /dev/null +++ b/hosts/nixos/aarch64-linux/moonside/secrets/pii.nix.enc @@ -0,0 +1,22 @@ +{ + "data": "ENC[AES256_GCM,data:jGfSfCOqW+p24TaH0vlcNImiY/Pu9YhdIwri4N4RvG64f1fmfNV3z6LmoShCYBfIWF2P7DvOa92dPY2ek9UiC1bEmiMtc/scpGxpir4WNuMLUtMWb0IGmnhtzq7fRAH5FkYLJBSW7pAgVsoajRGbo8Dbk5Dqcm75Pfj2YcC79oAckYt3vSzBcskgJ+ccdCfJ6vDlnAilay/GatZbIQmbEefOi9Rplfln8Ounj/hH+Z6zat04+rI5Lj8bTPu7NOeUlUmgoApuJSFafTb3zgxqnvQL5axOgIaJqiXFWhIf5httmu0mjhJupMXxt14IXgKe+ESAZFF8hWHHUNOpE8gEt5tPRQ1hqA7eHoGSYCrEQK9rSXRweO9LCfGV1+UduXgX1hKgwKDS4A5u69MvcpXQoSYX33ZzuwY7tbykb1tbEb3jN2BOSCBB2ZKHRfsTMqAHTE1RekcBArMxp7+8BkM/oww8RTMJ3I8tcU3QAr/LoFvKwvfIVrbT9gSlKSZUeoBc0WMzmRdjXhAZmQe2pb/TOFmPm31ih/E98zKA8PXhNrqjzEVN99lfn/NKsOLd9a8LXK8XoTTueTWqENEdJRx6dHpWuqBy5GdkrDVCRzgiO3Hpkwg56nPmCGoD5o1IgnRLJItNYrIRejIRaISjlefpezCMYIGMIx+CusvAwiOuuWT6kNfDnaK1U4P3Ndk39lsz8Eg2GMruc4VZ3kpTCeQdvbl/jmFwNMPtzJYooiDualIAL95iZU+RW/K+2g3ZA/Q/gJrc+hB6I+z3PzMod5015Oj0FG97XQzn2TeBD1fuO8UtyxSNajGD3ZK3Laa5QrSNUrzlf7YONSn98Z8OqKsAz+D/vnr0Lg4kjrrhYvN6GpR/QqMnNZT7m4d/oxACDycao6ZUDNE/dvuXSA4nSJp+5cxDXjgSMhnOgS7/gCiLhEBkLwzwdexT/e5vGcqqMmyeMK8vSFsPpRoPv26nsyRalwctY2ClX5KrEEckHNf+p9djB7eJDyLxXkPRLm0yp3dcmcEyk0tUffpcJ6zqWnlm46yfAf29fmIJfQWJ8ehSY+bYwDnx2LmCPcfH+sRSSV2Y1Ay22ry9rVJU88SuRdSPsHOitCuu0TQU56Su0wG24ilh6Bq4Dk+0JxlL3wyPWsnoaYvaRiJ6cs3j0tTwwxepbwiakLzWnVcqHDSoQ+Bn0T4CmcF5ztmpuLZSe/UXA48k77JmbT8vne0ig+kVfRuKhG+qV6g+GnxTIPPXGzQ1hWTS3Fg8YBMt1XYyjX3xa218agvPwLhCru1v3dAfHKk6N8G6SN6EN78RQmJApjSHAGFO,iv:a18hH0e5s4BTTlVIkQT34z8a2jELj59ZHhBbb93o3t0=,tag:sj4baRiZic6sWnJXjhL7TQ==,type:str]", + "sops": { + "age": [ + { + "recipient": "age18quey88vge7xytclg2nuq4ncme86dg04lxwczqxczmdchnjg3p0saehsnh", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB2YjdYNFF5Q1VzQTZ0WU1z\nN2R6cEVObU9RMXdpd2x0Mjh2cmpvY0VvNjE4CmF5Sm1vZWRoOTFIY2pkQUVRQ3FY\nVEd3eGpCbGQ3cUpvTE9JdjJMWnQvckEKLS0tIFRpZDZ1ZGZKaXpObFhZVlNqV0hB\nT20rRGV6S3gvWkZLUzQzVVNGQWNGVkUK0bAeRuI0vb7MJTtpxuD56nwZAk39sHAa\njEhntqsV9ts1Vbw2f0mZEqDdzd64NTtDm/YIwygZ2udV27mXNhVUVw==\n-----END AGE ENCRYPTED FILE-----\n" + } + ], + "lastmodified": "2025-11-27T14:12:09Z", + "mac": "ENC[AES256_GCM,data:6CqpegjS90H6fAllBsvz3d/y4MpNyMUo+v1sby4hHHw36GlQvnULHuv8dhXrlYaE+L21aoz1RITl7IEtNl/R8zjGh8b0dGIc2iUa2M5dNvHNPMTuucAEQPuEEvTiwI72winpEkdB86fHFFHvBwHwmlNVFJYx5b9bNlpjCofewQI=,iv:qOv8s8j5jOtcoKzgN/HkXvIsS/sk/DFZ4lcEKBLsrKA=,tag:ifXbcFGzpJ+DSJPkvaX0pw==,type:str]", + "pgp": [ + { + "created_at": "2025-06-13T20:12:55Z", + "enc": "-----BEGIN PGP MESSAGE-----\n\nhQIMAwDh3VI7VctTAQ/9HYZO7Bu/PhfIEnzlD9RpDhgk79rSdl9rfrssXOhsXh6j\ne016mp6UswsFuNUCArHOzOQ0wF7QolP/TW4ZAXK/Rb1cTr88JVuGy9UPx5cLHlaU\nZBmhFZjkYYIuYkPgKc/ztcsqGrJ/gqz15hjerFIB2vbcFRKfxN5xwIxb/hC8dWdF\n1V5iJhyTwvITBzXSJ4PfOh2RjfGmytKd5/Gf1DouW1H2Y7JgNSZPmesci5BUYyDd\nkt+rUjwe3FefOfzPVCA7ojfBuNxhU1sLJiEbGqEwd4XkwzU421jOIEzLM7qhUbGx\n0HzPUflTO85acBpwP3vf0NtsJXZyYG4/v81GLm11MEpwt5n/nJaxokbbT8CPKVpN\n8gXSwO2VhIDFWGeRMvfG3NNmwnJRJiSS0FTpRwqt3bF7btBfEE75HTGZq0qI+p+3\nPPqWz3SLMeAQvTqmscGpuIATX5PEDm+knq/D9W903mLeACZEMy8Tk1LDyuwJCK01\nJX687nOKgWfsq0PnhItF5Z1jfSMbJb6g3fH2Fpn6aB9bx9WNARNu2s28s3StE31K\nLtAvRsWNH6UzfO3VHMkphHrd7ARDre4pCeHs8B3wy+HswZxO2FEawTD0Ps0hejNF\nZPI18eTmCu6zuumhBwM72BZlWBj50HoqampjYtnlf3JemhYVysCbwyqou+i4S1yF\nAgwDC9FRLmchgYQBEACZ3fR5HsgS6ko5QCns6nqYfZyR2o6hyKb1iaH0veJEL9DI\n+EBaBJ6+8GPNETMACVz+wGd+GadoNWfgFNcUMz4TobTFGwsjmj5WRllxMtX1RNmf\nnqvMSflKk13DIHLbmsY4bGml0BE/ssLj0SiXOAmUWUZOMT+/+griCs4Er/fxphjA\nN3J+G83Prvynn8o924Ct1Q2wDXCWm6MENbbzts03IgkDHK1bCYVsTQ/ca2v+zB5g\nzRUR6xbi7Ysgco/DwDSu9DWIyNOMnsKnS3Mng/vXPoimlof4xGKMHRzrqdP5l95M\ntx2+/l4UNg5aQms8h9MML7AzVmVfJu3pLM9IE89WjVBgNE5/sQEfg7G7WvBBdfoR\njAHhkHOfZDlEjOnQzTR5MYZ57BGIGhHSOrg+IIX1zYaTNFEcnkfpLIJ71KOSs35w\n0hxud2CzFjxnbknvZP5myrMPwfQ1TJmR4PAWE1+XRMze18wCnXcosT7r+I/yc0mG\nhD1Q2YW0qYOY+AhOgshJ+OOvybaPFc8VlDriLoAqLXY0VaQVBIZGTHDY1SFUI4kY\ngMgmKJsWK0wn05J31FSdXYCEQubqClSN1BT+e0ceDnkioVvbTqwRBcOTXkQ9JFiA\nn65f6Ul4q9/ugOgLmrFiLDjdkmkdOOXo7QcgZrOL68+8c1xIxmhEgKobK5wBUtJc\nAXHosTJgXYvXHKDiZpFpN1gI2Y02tbxAb0Vois+ZZcP8AX0t++tZKARwguft0zr+\nWGhdQoGVeiQkAGXOgot66nGOtq/MtChmMZFEG63mc2B+84OOZBcXf66vsdU=\n=nCdw\n-----END PGP MESSAGE-----", + "fp": "4BE7925262289B476DBBC17B76FD3810215AE097" + } + ], + "unencrypted_suffix": "_unencrypted", + "version": "3.11.0" + } +} diff --git a/hosts/nixos/aarch64-linux/stoicclub/default.nix b/hosts/nixos/aarch64-linux/stoicclub/default.nix new file mode 100644 index 0000000..217d272 --- /dev/null +++ b/hosts/nixos/aarch64-linux/stoicclub/default.nix @@ -0,0 +1,39 @@ +{ self, lib, minimal, ... }: +{ + imports = [ + ./hardware-configuration.nix + ./disk-config.nix + + "${self}/modules/nixos/optional/systemd-networkd-server.nix" + ]; + + topology.self = { + icon = "devices.cloud-server"; + }; + swarselmodules.server.nginx = false; + + + swarselsystems = { + flakePath = "/root/.dotfiles"; + info = "VM.Standard.A1.Flex, 1 vCPUs, 8GB RAM"; + isImpermanence = true; + isSecureBoot = false; + isCrypted = true; + isSwap = false; + rootDisk = "/dev/disk/by-id/scsi-360e1a5236f034316a10a97cc703ce9e3"; + isBtrfs = true; + isNixos = true; + isLinux = true; + isCloud = true; + isBastionTarget = true; + }; +} // lib.optionalAttrs (!minimal) { + swarselprofiles = { + server = true; + }; + + swarselmodules.server = { + nsd = true; + nginx = false; + }; +} diff --git a/hosts/nixos/aarch64-linux/stoicclub/disk-config.nix b/hosts/nixos/aarch64-linux/stoicclub/disk-config.nix new file mode 100644 index 0000000..9a98cce --- /dev/null +++ b/hosts/nixos/aarch64-linux/stoicclub/disk-config.nix @@ -0,0 +1,121 @@ +{ lib, pkgs, config, ... }: +let + type = "btrfs"; + extraArgs = [ "-L" "nixos" "-f" ]; # force overwrite + subvolumes = { + "/root" = { + mountpoint = "/"; + mountOptions = [ + "subvol=root" + "compress=zstd" + "noatime" + ]; + }; + "/home" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/home"; + mountOptions = [ + "subvol=home" + "compress=zstd" + "noatime" + ]; + }; + "/persist" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/persist"; + mountOptions = [ + "subvol=persist" + "compress=zstd" + "noatime" + ]; + }; + "/log" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/var/log"; + mountOptions = [ + "subvol=log" + "compress=zstd" + "noatime" + ]; + }; + "/nix" = { + mountpoint = "/nix"; + mountOptions = [ + "subvol=nix" + "compress=zstd" + "noatime" + ]; + }; + "/swap" = lib.mkIf config.swarselsystems.isSwap { + mountpoint = "/.swapvol"; + swap.swapfile.size = config.swarselsystems.swapSize; + }; + }; +in +{ + disko = { + imageBuilder.extraDependencies = [ pkgs.kmod ]; + devices = { + disk = { + disk0 = { + type = "disk"; + device = config.swarselsystems.rootDisk; + content = { + type = "gpt"; + partitions = { + ESP = { + priority = 1; + name = "ESP"; + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "defaults" ]; + }; + }; + root = lib.mkIf (!config.swarselsystems.isCrypted) { + size = "100%"; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/disk/by-label/nixos" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + luks = lib.mkIf config.swarselsystems.isCrypted { + size = "100%"; + content = { + type = "luks"; + name = "cryptroot"; + passwordFile = "/tmp/disko-password"; # this is populated by bootstrap.sh + settings = { + allowDiscards = true; + # https://github.com/hmajid2301/dotfiles/blob/a0b511c79b11d9b4afe2a5e2b7eedb2af23e288f/systems/x86_64-linux/framework/disks.nix#L36 + crypttabExtraOpts = [ + "fido2-device=auto" + "token-timeout=10" + ]; + }; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/mapper/cryptroot" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + }; + }; + }; + }; + }; + }; + }; + + fileSystems."/persist".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + fileSystems."/home".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; +} diff --git a/hosts/nixos/aarch64-linux/stoicclub/hardware-configuration.nix b/hosts/nixos/aarch64-linux/stoicclub/hardware-configuration.nix new file mode 100644 index 0000000..2278aaf --- /dev/null +++ b/hosts/nixos/aarch64-linux/stoicclub/hardware-configuration.nix @@ -0,0 +1,15 @@ +{ lib, modulesPath, ... }: +{ + imports = [ (modulesPath + "/profiles/qemu-guest.nix") ]; + + boot = { + initrd = { + availableKernelModules = [ "xhci_pci" "virtio_pci" "virtio_scsi" "usbhid" ]; + kernelModules = [ ]; + }; + kernelModules = [ ]; + extraModulePackages = [ ]; + }; + + nixpkgs.hostPlatform = lib.mkForce "aarch64-linux"; +} diff --git a/hosts/nixos/aarch64-linux/stoicclub/secrets/pii.nix.enc b/hosts/nixos/aarch64-linux/stoicclub/secrets/pii.nix.enc new file mode 100644 index 0000000..e292b25 --- /dev/null +++ b/hosts/nixos/aarch64-linux/stoicclub/secrets/pii.nix.enc @@ -0,0 +1,22 @@ +{ + "data": "ENC[AES256_GCM,data:4C3fdXBKI/x/7B56b2n6OshGRaGgwYc4HQv4CRgXi+Y83hQj6wfbcqA55Xm9cXOfGAm2NNGIcUrVyuGHKlur7lUkvoNYe+a5A4GEkXVxiAoJKGcHa2nqfmR+GQJRAE6gNm9wgUL24CfKonEb09NgFBFfL7srXtkU8R1TMduUiYvzH7eNy45jQnWdQ3xgNYkb65iIZ3KCkcbjKrlOtN1Qu8+PuQmMl175gUVJcaLmpMgsz5IPetyHUWIkmqjgwhim4CyTZGwOaQW376Xq2mZUf9IOhdqLyR8GcKFLsY/GLDzp1eGfx9xUpAu3NMmjblHDdIyRcv0EjS+Cj/EUQwTrw3R2szXAb1m33sIVyloGT8RyVsu1J+RSIQOEKpVLaTxsCoulIfyBj5h9vajMVFdMmyqAFPJTVF8fNmy57VuBiDR1WYY5WT2QkBwe4A5ZZLpRmudeZAqEjD+R8Itcin4Ce8K4LtkpfLZeCUpnoaWk1u0CH5QuFCyd+s2+S2DBnFqfBmhTVzEtwXyd6zEeLo+LGCh2Eu2XwYi+DV5Xfdp4leTwEXQ+63MB2ZtOQkoxT6pi/w1rSlEcVknJJIc0HRhrRSx685i29qmcWGfjw765ECxCM2RKJKdwtYHwyLQGyTkGgzNlWr/EzskD7wwtanR0K0NUBS3MGbBaSmeI+bJ+B1ld2n7Efp1eg8AdMz/VHywvFQpS6HY5ItPCWNcDB9DMerUQINO1EtP1Dd57vafzQGGcduUKW+ywuwUdOU/XTXPaVP7VWdX9EFIlv/RMK4UX/l3Yy/Vf6iciT45zouIgoFECRe59Uz0185BHTn9xeE9oYGiLfKzlnxhNpXNaNmYGVRxKxKwfMNrA+hRtuoGrD0uE/Ev6F5ytMYMZGsQ5D6TJOHXPfAVWo5MzPA1Q2dgoCF9zZvYgCaOcSZTntoJY9X1MiwMkYIbtOtTQ4jJOI9DfXX+kOp/fejHrQEyAasCvh2zxCW2FjMckREdqtYxPEDsHGc8+0BDGgj+00a5wC19U60jolvdLsUwy41inmirgxBMaQhuavMXEpFXT0hEecZfJn8eJqPVPDVLC8LvlB+C593ByHeoR3VOIfFVv3bgCP+cQudAR+U/b8YO4gSpuVV4WF7JXLCwRCi0Flw7EzAuhuR9JYd8GKUEDctGmAYiPy1YiQCLFnAWmZvHQ2q6TeVDTQ5LPmjqM1b4iqoqn3AHhMu9HWswy4LFNujZblSo0hSHRZ+2P/+Xjrgfz2d3QF66ngEjW1tanw7hxGmiZJXXyPN+2bdB04B8ZnL/gBzQ2661fGYGYCBU=,iv:mU4ydooaOySi7MTe+b/DGfs1fzpDXbkASUo1cDsh4O8=,tag:Jh18+kJPLJFlGx5HymywOw==,type:str]", + "sops": { + "age": [ + { + "recipient": "age1glge4e97vgqzh332mqs5990vteezu2m8k4wq3z35jk0q8czw3gks2d7a3h", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBJZzY0QVQ4ZUxxZkdhQ2Zn\nOHpmTnRaR0R3cXh2Z2JFM1RDVDB2QnE3M3prCm43NjQyOS93UTZKaUlUUmhVcTdG\nUWp1YU1kVmZPc0tBN2FMY2FFVkI1a0UKLS0tIFovZi9FQlhMaXpvcnRYN2FiSm16\nTzJESjNyZ1NzajJRNDR6ZTd2TitoQTgKe2hC6OpYIzgqzhmeJuHWe0yXNE+/Ek26\nGt7s1B6OKnrj+S3es84ePOjAbLHr/ez282b/h0y55ws4R7jMemUIrQ==\n-----END AGE ENCRYPTED FILE-----\n" + } + ], + "lastmodified": "2025-12-01T12:12:55Z", + "mac": "ENC[AES256_GCM,data:AhvfUvZnKSnhQCTHJpqs5OBELhGYv66on1+kSLX2lONyTbNfwHYsJHII4zHY+bS5cBkZbjtzMfJQkFWtDbU7c8wvdJnHN6H11MOEzC+GfI3R7UzwzJsUjNYE03u8FJCuLvI1SO3EObiKIgH80MV8qlXC+1+f7mKnfZNH8Kekor8=,iv:pAEz8tDZzaFee1EcNBd6zrl0yN55ywVK/eGof/B5MAU=,tag:LbjMr3rOb3By87yOfUK/3A==,type:str]", + "pgp": [ + { + "created_at": "2025-11-20T01:03:05Z", + "enc": "-----BEGIN PGP MESSAGE-----\n\nhQIMAwDh3VI7VctTAQ//eTxMD8ZbwJUqVsi1IKK2qdprLTjE0rqdDue+OvP0V+Ns\n1uTnw+b2UBykbIofXcG4P61OxAFdEs8whiIdffQtkDTkOgzV9IQCBOSGxZGEJXMe\nrl5BZLlF98JZ5R15v8V8vMwWwtC90GZ7gZLDV+yZz40Zqm3mTrFz/3PERukwu4Gb\nLTJDOsGmpooyI8KnrIsBhfEwo7/ouAayuKQfvt2i2Tngk9Em73R91BlpcxsOEmqr\n5KWA4GCsjUOmZZKLj2vyENPgQh8t8bP5fGJ3Rf4J1MCWAB89omcE0aRWId/l5sdA\n/Nxinh3xQsiXHPzPLZQ+UjHs+MjNdUoZapoDBP84j2tHsSxh0RMRhlHpESDWq3Mm\n1acWrChyyds6Lz5ZqkioqvAZ3lslS0kPdQqfsLzYWBhA9kLOIJKYfat+vxsAPwAa\n6kceXtxSzUpThtDUPDibjomn7Mrj7ZoHhiJZup/M27glf/V4P3zk+ctpXMSIE7Ia\nQ/jgRDzpcs+u05RsP32jFbCAfi//WxRo77MoxGMJxDhYibBp+aRkFAgVYiElhxbt\n/NedcIAHSJZFyDPm0wn411+DPnUTPn9D9LCkmSG68ZeGDGZJl7Sz3bJ3obWWecTG\nBjqxMZVwRuU2gdg1IwempP9u1dP0Q+g8B3veui/gczGx3J5kvNv8hnUBTeUl2EyF\nAgwDC9FRLmchgYQBD/oCciOvXMrH9/hWIIYb1sKiuCmgdVfs7H0q92XdVNgkbPRz\nXAakX7dl5cZt748u/eCHlGUGr4q7yA1tDx9Vm/J+O2HljN3lBVCbm7HP+YcI+5g0\nvvxr0cIPtr5CXlZz6hJjTgzE4HfEKagGdjgllbHYBB+0rtq/2pZTa20fG0w4coeI\nB/D0iVFwyuM3Wxt/7gXpPtI+m/3qt8QoFIGsZkck7X5hdJwGF4DD5jKxYB28s5Hc\n4ZBG19jezjMIVJUGE58TTVDTvZvJ5Vaw2RizV8DRkFS3q0UIOapOESpZiRnoOqA1\nDQpAU26RSEj8wlYsgNrVWUpdwlYs5e3EWYNkGROTRSB/dGcCSVF31A76W7af+6uv\nwZdMCrAGlD4GBj/yojdnqstfB2Jxu99VubcImWKfaJEXYx5xoREGmK9+t896GJi+\nE8mjiMOMRZFV2n2nwTxAFMaiDJ+VpKpKGVKCOSDwqsePhY/A4kb+N1nnhutmSl/v\n1SCDDvC9+jYNLUC1IaJfFOrNClA43IdJELOAavRx2t1RdyfyOx3D8rrWhF4+NB9Z\nlAc2e7hOoP/OEtf4YjZWq3dQtWSdwePWBxD9xyvF/kEmd2NcezqdfggH3g84qBxy\nUxBDD3ojMMAXlkPU3hRiDeLd1mHxDizVxqYkIYDSeAKtuv2ECH8y7/mv3sKrFtJe\nAQvSMW7gOmIdtQaIpsXHMxzXf+Nv0l3dZeWYD/TnVvoeVOaRQ9dHrtl3J0U9UN3j\nBOJdFaptlS4SIRkva6v6srrM7dXKvjR6IabdzaWl098VW9RFD+YGJ6ZhuQ+zOA==\n=l0k2\n-----END PGP MESSAGE-----", + "fp": "4BE7925262289B476DBBC17B76FD3810215AE097" + } + ], + "unencrypted_suffix": "_unencrypted", + "version": "3.11.0" + } +} diff --git a/hosts/nixos/aarch64-linux/twothreetunnel/default.nix b/hosts/nixos/aarch64-linux/twothreetunnel/default.nix new file mode 100644 index 0000000..8a30e09 --- /dev/null +++ b/hosts/nixos/aarch64-linux/twothreetunnel/default.nix @@ -0,0 +1,36 @@ +{ self, lib, minimal, ... }: +{ + imports = [ + ./hardware-configuration.nix + ./disk-config.nix + + "${self}/modules/nixos/optional/systemd-networkd-server.nix" + ]; + + topology.self = { + icon = "devices.cloud-server"; + }; + + swarselsystems = { + flakePath = "/root/.dotfiles"; + info = "VM.Standard.A1.Flex, 2 vCPUs, 8GB RAM"; + isImpermanence = true; + isSecureBoot = false; + isCrypted = true; + isSwap = false; + rootDisk = "/dev/disk/by-id/scsi-3608deb9b0d4244de95c6620086ff740d"; + isBtrfs = true; + isNixos = true; + isLinux = true; + isCloud = true; + }; +} // lib.optionalAttrs (!minimal) { + swarselprofiles = { + server = true; + }; + + swarselmodules.server = { + nginx = false; + }; + +} diff --git a/hosts/nixos/aarch64-linux/twothreetunnel/disk-config.nix b/hosts/nixos/aarch64-linux/twothreetunnel/disk-config.nix new file mode 100644 index 0000000..9a98cce --- /dev/null +++ b/hosts/nixos/aarch64-linux/twothreetunnel/disk-config.nix @@ -0,0 +1,121 @@ +{ lib, pkgs, config, ... }: +let + type = "btrfs"; + extraArgs = [ "-L" "nixos" "-f" ]; # force overwrite + subvolumes = { + "/root" = { + mountpoint = "/"; + mountOptions = [ + "subvol=root" + "compress=zstd" + "noatime" + ]; + }; + "/home" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/home"; + mountOptions = [ + "subvol=home" + "compress=zstd" + "noatime" + ]; + }; + "/persist" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/persist"; + mountOptions = [ + "subvol=persist" + "compress=zstd" + "noatime" + ]; + }; + "/log" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/var/log"; + mountOptions = [ + "subvol=log" + "compress=zstd" + "noatime" + ]; + }; + "/nix" = { + mountpoint = "/nix"; + mountOptions = [ + "subvol=nix" + "compress=zstd" + "noatime" + ]; + }; + "/swap" = lib.mkIf config.swarselsystems.isSwap { + mountpoint = "/.swapvol"; + swap.swapfile.size = config.swarselsystems.swapSize; + }; + }; +in +{ + disko = { + imageBuilder.extraDependencies = [ pkgs.kmod ]; + devices = { + disk = { + disk0 = { + type = "disk"; + device = config.swarselsystems.rootDisk; + content = { + type = "gpt"; + partitions = { + ESP = { + priority = 1; + name = "ESP"; + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "defaults" ]; + }; + }; + root = lib.mkIf (!config.swarselsystems.isCrypted) { + size = "100%"; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/disk/by-label/nixos" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + luks = lib.mkIf config.swarselsystems.isCrypted { + size = "100%"; + content = { + type = "luks"; + name = "cryptroot"; + passwordFile = "/tmp/disko-password"; # this is populated by bootstrap.sh + settings = { + allowDiscards = true; + # https://github.com/hmajid2301/dotfiles/blob/a0b511c79b11d9b4afe2a5e2b7eedb2af23e288f/systems/x86_64-linux/framework/disks.nix#L36 + crypttabExtraOpts = [ + "fido2-device=auto" + "token-timeout=10" + ]; + }; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/mapper/cryptroot" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + }; + }; + }; + }; + }; + }; + }; + + fileSystems."/persist".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + fileSystems."/home".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; +} diff --git a/hosts/nixos/aarch64-linux/twothreetunnel/hardware-configuration.nix b/hosts/nixos/aarch64-linux/twothreetunnel/hardware-configuration.nix new file mode 100644 index 0000000..2278aaf --- /dev/null +++ b/hosts/nixos/aarch64-linux/twothreetunnel/hardware-configuration.nix @@ -0,0 +1,15 @@ +{ lib, modulesPath, ... }: +{ + imports = [ (modulesPath + "/profiles/qemu-guest.nix") ]; + + boot = { + initrd = { + availableKernelModules = [ "xhci_pci" "virtio_pci" "virtio_scsi" "usbhid" ]; + kernelModules = [ ]; + }; + kernelModules = [ ]; + extraModulePackages = [ ]; + }; + + nixpkgs.hostPlatform = lib.mkForce "aarch64-linux"; +} diff --git a/hosts/nixos/aarch64-linux/twothreetunnel/secrets/pii.nix.enc b/hosts/nixos/aarch64-linux/twothreetunnel/secrets/pii.nix.enc new file mode 100644 index 0000000..e82a9a3 --- /dev/null +++ b/hosts/nixos/aarch64-linux/twothreetunnel/secrets/pii.nix.enc @@ -0,0 +1,22 @@ +{ + "data": "ENC[AES256_GCM,data:G3Q+Hn7QkvBZeXzNR+0Bax+Va5sK5E0K3hNTkdsNJx4C6pIwrBEBOt3IKv/c00QhpAnPqo9gbKqWU9gv7I56nEOwVtVH3lrMlbxNl9LIiSv9SvSxVkTOow2msSJV/U+1KpjNQ/LnOo2Fxebfz1yiRtgi7hSazzqzIazZAFBldlKkjLR5SFCG8t5s/nccqZU+cLmS7hJDS5LtgW1XeunqUY7jnKuh7gT2I6fPsu15Vy+YeKLmYIt0a20bWGePBIlyiGRtpnMgtIt5gk5+OpSndO8P/GMgUzRwRZEL1b8U57jbhkPLdnwwy/iV6rEFCD9i6qB0ufVW/euc+y5mN0dx8op9FwJVzkJhUIIy9Qbbc8WOjjjWlwbKJNkWfYX7pTtx+xfBKuPF+IwaoMS9j+C3etkoYe5QCr9YGYM5Xer/HL0otYNacQU5S0VqPBzDnLu7NxzB4i22,iv:aFPDBmZasoqEFCbhrRtA2QMB27khuT3rdfCGAafjov0=,tag:GQGuHL5aYPc98tzc6Bb5mA==,type:str]", + "sops": { + "age": [ + { + "recipient": "age1g7atkxdlt4ymeh7v7aa2yzr2hq2qkvzrc4r49ugttm3n582ymv9qrmpk8d", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBqdEhDamZTRUhQZFNDTTl4\nVVVNNGZXa2h2THVzY0JWMjE2WjNJT0ZoblV3ClYzeEt4c0dWRzlISnN3NGthR21M\nTEtDQ011dFdhRVdPWlpweS9ma0N3dmsKLS0tIHFPQzQ5VzkyODZyY1JpcE4xR2Nl\nY2MrSERXTWkvNVZCR2xHUGh4ZXMvYTgK7pxPjnh3idl4QzBkR6LHyRskgqA3apS2\nkbg7As6wlEs34TAO8reyZknKTUd3Xif1v9RXiTcu1sEKHqkcqEoDog==\n-----END AGE ENCRYPTED FILE-----\n" + } + ], + "lastmodified": "2025-12-01T22:45:54Z", + "mac": "ENC[AES256_GCM,data:b2sWPq+S5qqSM6lON+9A//LehgR7Wy7x8EfqeiFOFo9RT3niwaKjfp/Jnf6nKbXF43XM4dsn+dIX52fgxyd0KVLnJTqinhz97sSSs7hYFdXa2FGRhI+VwmuGVvr2ylAJODQgTn+MD7I+s/3DTfh6h0V47IZvxrUpYgg7tJrxzBc=,iv:g4XVN24+COVtRQPzTiI4iki1crjBUVc7vpnJ/vucd2A=,tag:gcnfSvPWvLqG2wTZELRMsg==,type:str]", + "pgp": [ + { + "created_at": "2025-12-01T23:06:36Z", + "enc": "-----BEGIN PGP MESSAGE-----\n\nhQIMAwDh3VI7VctTAQ//RhpX1uVa49yA8FIfj/y/2C92Z7iBl+l1TGjaYMnuLAp5\nYybqAHwi1gzbnhKvpqO3ndm7qHNwbPBuYBDhu1ZDkQnzyzIthx3JA2G+je4Jem+N\nF8XWUglO+lEUpHD62s9JdOSS2dNRHSd/mcu/GV+k0/DzkXDn3TzzOciKBLn1u03+\n6T3mipG5cm00EEstR+iX46FSzOPX3M2+hYY+HY9rQa1RKUrUUsBBdCEYWgMsQOA9\nDGyweibxkcyxIGZIc882gxa06QxM07ON7NuZjW7vvUz3k7CI3bf5IBfaCvDywaDL\n0AKeTAVGVLnzdapZoP9lZmu6T639wu8BKMxSHiGeUenOrhs/Gl+CA2iCU5XimZCw\nbwPvKRbOGLu2eiBL/BHEMg1XpRw6bh24o3vNIchGRqDKbXICgkKr2gXhvli3qPrH\nCXokXF48e51bERfr9YWi0ryW5tgVEMwyubRi85cYnslwqfT78xzKMNRwF8wJ6PxG\ngwT6bEJ/f7QzXkw9VPY2HbaBBhe7XUBRDhLnV5sPBiZW2JDOt9rXH1LqWQLo7Ot6\nLWvOicAtmY5vnRIm9x1pPFKipmTWj7NzRCLEq5yt0borQsPO5RTC6fvhL/1Lpe1B\nzjAIjJBfQptEn4xjA0unZk6x45UDp9KpJz5zdKF43DSvGOkEF8NuTdEXNpeYHzCF\nAgwDC9FRLmchgYQBEADA36phB2C1d2DvEzi7AB7lK5gGExmaYSCzMJkSfjNQ4SO5\nwMhvRZZyIf5PT9wdJ6hCtOSqqhh0cubmZadrFnz/qjXLVSv9aTD4PFshF5lYgT0x\n2GkiIOkrVZ6vuP6/iIW/p+CqztDymVRR6DAhNNX6gx2NARdhii2K/hitW0QejoJk\nWY07qUIb2z0fPVp5TfAf3Nr87u3faYr0usW8GGABFA7IzJwCK1VA1284UZm4zj6Z\naHm+0wK/1g7Ck2sjzbhqzK3HlZVKd6lBIhmwdzcG1y0Ua5L7PIauLR6ArZkFD3WO\naHyyZ5hyNmoyOMjuTvPCIhiZ3T+aQK2f8pzyOApEWX4piCNhIvcSSy9AQ/f5hvVd\nWLG68dIMnmOWYxHX68jdNttSCcc9oJKNboOPKDdmEblZxGx5HZpYYL7X+Q0JKoMO\nqCXVc7GlIVLX0GghAvgC9Xww8XMQTWgJJJAVOa0tlTDJ4ybvCiyy850+ZPTevlHV\nfvlKSSCGHtjVIuZ5b+jMtBqg0aPDY0OqNFSvJ6x6wk0uICMesv2LNAKF7tUkMvHF\ncHljW96IOLocW96bwVR+nQG7U/ZY7/P6+2Nva8AgbrCd0erEZ/2lIvRV4IEzCk2g\nVzuzg+7pjkh1iHYUX+VX6CbyIPyx2Ic+VNaMrbqtC1YiPK6Bx+SF3eYHw9DYJ9Jc\nASJeqALtG3vg/TOKZwOfTp1GNvSExTUKqhEHpcCCty1UxIpNCPByvvsUqY0Q63DA\nyJ4TVO1QLCLwKz8nK8NWSRGrZ29jNJfAjcNDV/FrPiFqSPHVAErd4Vnbeu8=\n=Yn71\n-----END PGP MESSAGE-----", + "fp": "4BE7925262289B476DBBC17B76FD3810215AE097" + } + ], + "unencrypted_suffix": "_unencrypted", + "version": "3.11.0" + } +} diff --git a/hosts/nixos/chaostheatre/default.nix b/hosts/nixos/chaostheatre/default.nix deleted file mode 100644 index 4d1ccc5..0000000 --- a/hosts/nixos/chaostheatre/default.nix +++ /dev/null @@ -1,56 +0,0 @@ -{ self, inputs, outputs, config, pkgs, lib, ... }: -let - profilesPath = "${self}/profiles"; -in -{ - - imports = outputs.nixModules ++ [ - - ./hardware-configuration.nix - - "${profilesPath}/optional/nixos/autologin.nix" - - inputs.home-manager.nixosModules.home-manager - { - home-manager.users.swarsel.imports = outputs.mixedModules ++ (builtins.attrValues outputs.homeManagerModules); - } - ] ++ (builtins.attrValues outputs.nixosModules); - - - nixpkgs = { - overlays = [ outputs.overlays.default ]; - config = { - allowUnfree = true; - }; - }; - - environment.variables = { - WLR_RENDERER_ALLOW_SOFTWARE = 1; - }; - - services.qemuGuest.enable = true; - - boot = { - loader.systemd-boot.enable = lib.mkForce true; - loader.efi.canTouchEfiVariables = true; - kernelPackages = lib.mkDefault pkgs.linuxPackages_latest; - }; - - networking = { - hostName = "chaostheatre"; - firewall.enable = true; - }; - - - swarselsystems = { - wallpaper = self + /wallpaper/lenovowp.png; - initialSetup = true; - isPublic = true; - }; - - home-manager.users.swarsel.swarselsystems = { - isNixos = true; - isPublic = true; - flakePath = "/home/swarsel/.dotfiles"; - }; -} diff --git a/hosts/nixos/iso/default.nix b/hosts/nixos/iso/default.nix deleted file mode 100644 index c9abaaf..0000000 --- a/hosts/nixos/iso/default.nix +++ /dev/null @@ -1,89 +0,0 @@ -{ self, pkgs, inputs, config, lib, modulesPath, ... }: -let - pubKeys = lib.filesystem.listFilesRecursive "${self}/secrets/keys/ssh"; -in -{ - - imports = [ - - inputs.lanzaboote.nixosModules.lanzaboote - inputs.disko.nixosModules.disko - inputs.impermanence.nixosModules.impermanence - inputs.sops-nix.nixosModules.sops - "${modulesPath}/installer/cd-dvd/installation-cd-minimal.nix" - "${modulesPath}/installer/cd-dvd/channel.nix" - - "${self}/profiles/iso/minimal.nix" - - ]; - - environment.etc."issue".text = "\\4\n"; - networking.dhcpcd.runHook = "${pkgs.utillinux}/bin/agetty --reload"; - - isoImage = { - makeEfiBootable = true; - makeUsbBootable = true; - squashfsCompression = "zstd -Xcompression-level 3"; - }; - - nixpkgs = { - hostPlatform = lib.mkDefault "x86_64-linux"; - config.allowUnfree = true; - }; - - services.getty.autologinUser = lib.mkForce "swarsel"; - - users = { - allowNoPasswordLogin = true; - groups.swarsel = { }; - users = { - swarsel = { - name = "swarsel"; - group = "swarsel"; - isNormalUser = true; - password = "setup"; # this is overwritten after install - openssh.authorizedKeys.keys = lib.lists.forEach pubKeys (key: builtins.readFile key); - extraGroups = [ "wheel" ]; - }; - root = { - # password = lib.mkForce config.users.users.swarsel.password; # this is overwritten after install - openssh.authorizedKeys.keys = config.users.users.swarsel.openssh.authorizedKeys.keys; - }; - }; - }; - - boot = { - loader.systemd-boot.enable = lib.mkForce true; - loader.efi.canTouchEfiVariables = true; - }; - - programs.bash.shellAliases = { - "swarsel-install" = "nix run github:Swarsel/.dotfiles#install --"; - }; - - system.activationScripts.cache = { - text = '' - mkdir -p /home/swarsel/.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 /home/swarsel/.local/share/nix/trusted-settings.json > /dev/null - 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 > /dev/null - ''; - }; - systemd = { - services.sshd.wantedBy = lib.mkForce [ "multi-user.target" ]; - targets = { - sleep.enable = false; - suspend.enable = false; - hibernate.enable = false; - hybrid-sleep.enable = false; - }; - }; - - system.stateVersion = lib.mkForce "23.05"; - - networking = { - hostName = "drugstore"; - wireless.enable = false; - }; - -} diff --git a/hosts/nixos/nbl-imba-2/default.nix b/hosts/nixos/nbl-imba-2/default.nix deleted file mode 100644 index 4c83811..0000000 --- a/hosts/nixos/nbl-imba-2/default.nix +++ /dev/null @@ -1,218 +0,0 @@ -{ self, inputs, outputs, config, pkgs, lib, ... }: -let - profilesPath = "${self}/profiles"; -in -{ - - imports = outputs.nixModules ++ [ - inputs.nixos-hardware.nixosModules.framework-16-7040-amd - inputs.fw-fanctrl.nixosModules.default - - ./hardware-configuration.nix - ./disk-config.nix - - "${profilesPath}/optional/nixos/virtualbox.nix" - # "${profilesPath}/optional/nixos/vmware.nix" - "${profilesPath}/optional/nixos/autologin.nix" - "${profilesPath}/optional/nixos/nswitch-rcm.nix" - "${profilesPath}/optional/nixos/gaming.nix" - "${profilesPath}/optional/nixos/work.nix" - - inputs.home-manager.nixosModules.home-manager - { - home-manager.users.swarsel.imports = outputs.mixedModules ++ [ - "${profilesPath}/optional/home/gaming.nix" - "${profilesPath}/optional/home/work.nix" - ] ++ (builtins.attrValues outputs.homeManagerModules); - } - ] ++ (builtins.attrValues outputs.nixosModules); - - - nixpkgs = { - overlays = [ outputs.overlays.default ]; - config = { - allowUnfree = true; - }; - }; - - networking.networkmanager.wifi.scanRandMacAddress = false; - - boot = { - loader.systemd-boot.enable = lib.mkForce false; - loader.efi.canTouchEfiVariables = true; - lanzaboote = { - enable = true; - pkiBundle = "/etc/secureboot"; - }; - supportedFilesystems = [ "btrfs" ]; - kernelPackages = lib.mkDefault pkgs.linuxPackages_latest; - kernelParams = [ - "resume_offset=533760" - ]; - resumeDevice = "/dev/disk/by-label/nixos"; - }; - - hardware = { - amdgpu = { - opencl.enable = true; - amdvlk = { - enable = true; - support32Bit.enable = true; - }; - }; - }; - - programs.fw-fanctrl.enable = true; - - networking = { - hostName = "nbl-imba-2"; - fqdn = "nbl-imba-2.imp.univie.ac.at"; - firewall.enable = true; - }; - - - services = { - fwupd.enable = true; - udev.extraRules = '' - ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="0bda", ATTR{idProduct}=="8156", ATTR{power/autosuspend}="20" - ''; - }; - - swarselsystems = { - wallpaper = self + /wallpaper/lenovowp.png; - hasBluetooth = true; - hasFingerprint = true; - impermanence = false; - isBtrfs = true; - }; - - home-manager.users.swarsel.swarselsystems = { - isLaptop = true; - isNixos = true; - isBtrfs = true; - flakePath = "/home/swarsel/.dotfiles"; - cpuCount = 16; - # temperatureHwmon = { - # isAbsolutePath = true; - # path = "/sys/devices/platform/thinkpad_hwmon/hwmon/"; - # input-filename = "temp1_input"; - # }; - # ------ ----- - # | DP-4 | |eDP-1| - # ------ ----- - startup = [ - { command = "nextcloud --background"; } - { command = "vesktop --start-minimized --enable-speech-dispatcher --ozone-platform-hint=auto --enable-features=WaylandWindowDecorations --enable-wayland-ime"; } - { command = "element-desktop --hidden --enable-features=UseOzonePlatform --ozone-platform=wayland --disable-gpu-driver-bug-workarounds"; } - { command = "ANKI_WAYLAND=1 anki"; } - { command = "OBSIDIAN_USE_WAYLAND=1 obsidian"; } - { command = "nm-applet"; } - { command = "teams-for-linux"; } - { command = "1password"; } - { command = "feishin"; } - ]; - sharescreen = "eDP-2"; - lowResolution = "1280x800"; - highResolution = "2560x1600"; - monitors = { - main = { - name = "BOE 0x0BC9 Unknown"; - mode = "2560x1600"; # TEMPLATE - scale = "1"; - position = "2560,0"; - workspace = "15:L"; - output = "eDP-2"; - }; - homedesktop = { - name = "Philips Consumer Electronics Company PHL BDM3270 AU11806002320"; - mode = "2560x1440"; - scale = "1"; - position = "0,0"; - workspace = "1:一"; - output = "DP-11"; - }; - work_back_middle = { - name = "LG Electronics LG Ultra HD 0x000305A6"; - mode = "2560x1440"; - scale = "1"; - position = "5120,0"; - workspace = "1:一"; - output = "DP-10"; - }; - work_front_left = { - name = "LG Electronics LG Ultra HD 0x0007AB45"; - mode = "3840x2160"; - scale = "1"; - position = "5120,0"; - workspace = "1:一"; - output = "DP-7"; - }; - work_back_right = { - name = "HP Inc. HP Z32 CN41212T55"; - mode = "3840x2160"; - scale = "1"; - position = "5120,0"; - workspace = "1:一"; - output = "DP-3"; - }; - work_middle_middle_main = { - name = "HP Inc. HP 732pk CNC4080YL5"; - mode = "3840x2160"; - scale = "1"; - position = "-1280,0"; - workspace = "11:M"; - output = "DP-8"; - }; - work_middle_middle_side = { - name = "Hewlett Packard HP Z24i CN44250RDT"; - mode = "1920x1200"; - transform = "270"; - scale = "1"; - position = "-2480,0"; - workspace = "12:S"; - output = "DP-9"; - }; - work_seminary = { - name = "Applied Creative Technology Transmitter QUATTRO201811"; - mode = "1280x720"; - scale = "1"; - position = "10000,10000"; # i.e. this screen is inaccessible by moving the mouse - workspace = "12:S"; - output = "DP-4"; - }; - }; - inputs = { - "12972:18:Framework_Laptop_16_Keyboard_Module_-_ANSI_Keyboard" = { - xkb_layout = "us"; - xkb_variant = "altgr-intl"; - }; - "1133:45081:MX_Master_2S_Keyboard" = { - xkb_layout = "us"; - xkb_variant = "altgr-intl"; - }; - "2362:628:PIXA3854:00_093A:0274_Touchpad" = { - dwt = "enabled"; - tap = "enabled"; - natural_scroll = "enabled"; - middle_emulation = "enabled"; - }; - "1133:50504:Logitech_USB_Receiver" = { - xkb_layout = "us"; - xkb_variant = "altgr-intl"; - }; - "1133:45944:MX_KEYS_S" = { - xkb_layout = "us"; - xkb_variant = "altgr-intl"; - }; - }; - keybindings = { - "Mod4+Ctrl+Shift+p" = "exec screenshare"; - }; - shellAliases = { - ans2-15_3-9 = ". ~/.venvs/ansible39_2_15_0/bin/activate"; - ans3-9 = ". ~/.venvs/ansible39/bin/activate"; - ans = ". ~/.venvs/ansible/bin/activate"; - ans2-15 = ". ~/.venvs/ansible2.15.0/bin/activate"; - }; - }; -} diff --git a/hosts/nixos/nbl-imba-2/hardware-configuration.nix b/hosts/nixos/nbl-imba-2/hardware-configuration.nix deleted file mode 100644 index cab3d56..0000000 --- a/hosts/nixos/nbl-imba-2/hardware-configuration.nix +++ /dev/null @@ -1,84 +0,0 @@ -# Do not modify this file! It was generated by ‘nixos-generate-config’ -# and may be overwritten by future invocations. Please make changes -# to /etc/nixos/configuration.nix instead. -{ config, lib, modulesPath, ... }: - -{ - imports = - [ - (modulesPath + "/installer/scan/not-detected.nix") - ]; - - boot.initrd.availableKernelModules = [ "nvme" "xhci_pci" "thunderbolt" "usb_storage" "cryptd" "usbhid" "sd_mod" "r8152" ]; - boot.initrd.kernelModules = [ ]; - boot.kernelModules = [ "kvm-amd" ]; - boot.extraModulePackages = [ ]; - boot.initrd.luks.devices."cryptroot" = { - # improve performance on ssds - bypassWorkqueues = true; - preLVM = true; - }; - - # fileSystems."/" = - # { - # device = "/dev/disk/by-uuid/3554892c-9d0b-49b2-b74a-8b5ef45569f7"; - # fsType = "btrfs"; - # options = [ "subvol=root" ]; - # }; - - # boot.initrd.luks.devices."cryptroot".device = "/dev/disk/by-uuid/98b9bf76-ca01-49f5-91ee-1884ae9ce383"; - - # fileSystems."/boot" = - # { - # device = "/dev/disk/by-uuid/5236-F44A"; - # fsType = "vfat"; - # }; - - # fileSystems."/home" = - # { - # device = "/dev/disk/by-uuid/3554892c-9d0b-49b2-b74a-8b5ef45569f7"; - # fsType = "btrfs"; - # options = [ "subvol=home" ]; - # }; - - # fileSystems."/nix" = - # { - # device = "/dev/disk/by-uuid/3554892c-9d0b-49b2-b74a-8b5ef45569f7"; - # fsType = "btrfs"; - # options = [ "subvol=nix" ]; - # }; - - # fileSystems."/persist" = - # { - # device = "/dev/disk/by-uuid/3554892c-9d0b-49b2-b74a-8b5ef45569f7"; - # fsType = "btrfs"; - # options = [ "subvol=persist" ]; - # }; - - # fileSystems."/swap" = - # { - # device = "/dev/disk/by-uuid/3554892c-9d0b-49b2-b74a-8b5ef45569f7"; - # fsType = "btrfs"; - # options = [ "subvol=swap" ]; - # }; - - # fileSystems."/var/log" = - # { - # device = "/dev/disk/by-uuid/3554892c-9d0b-49b2-b74a-8b5ef45569f7"; - # fsType = "btrfs"; - # options = [ "subvol=log" ]; - # }; - - # swapDevices = [ ]; - - # Enables DHCP on each ethernet and wireless interface. In case of scripted networking - # (the default) this is the recommended approach. When using systemd-networkd it's - # still possible to use this option, but it's recommended to use it in conjunction - # with explicit per-interface declarations with `networking.interfaces..useDHCP`. - networking.useDHCP = lib.mkDefault true; - # networking.interfaces.enp196s0f3u1c2.useDHCP = lib.mkDefault true; - # networking.interfaces.wlp4s0.useDHCP = lib.mkDefault true; - - nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; - hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; -} diff --git a/hosts/nixos/sync/default.nix b/hosts/nixos/sync/default.nix deleted file mode 100644 index cbfb8cf..0000000 --- a/hosts/nixos/sync/default.nix +++ /dev/null @@ -1,92 +0,0 @@ -{ self, inputs, outputs, lib, ... }: -let - profilesPath = "${self}/profiles"; -in -{ - imports = [ - - inputs.sops-nix.nixosModules.sops - "${profilesPath}/server/nixos" - ./hardware-configuration.nix - - inputs.home-manager.nixosModules.home-manager - { - home-manager.users.swarsel.imports = [ - "${profilesPath}/server/home" - ] ++ (builtins.attrValues outputs.homeManagerModules); - } - - ] ++ (builtins.attrValues outputs.nixosModules); - - sops = { - defaultSopsFile = lib.mkForce "/root/.dotfiles/secrets/sync/secrets.yaml"; - }; - - - services.nginx = { - virtualHosts = { - "sync.swarsel.win" = { - enableACME = true; - forceSSL = true; - acmeRoot = null; - locations = { - "/" = { - proxyPass = "http://localhost:8384/"; - extraConfig = '' - client_max_body_size 0; - ''; - }; - }; - }; - }; - }; - - boot = { - tmp.cleanOnBoot = true; - loader.grub.device = "nodev"; - }; - zramSwap.enable = false; - - networking = { - firewall.allowedTCPPorts = [ 8384 22000 ]; - firewall.allowedUDPPorts = [ 21027 22000 ]; - hostName = "sync"; - enableIPv6 = false; - domain = "subnet03112148.vcn03112148.oraclevcn.com"; - firewall.extraCommands = '' - iptables -I INPUT -m state --state NEW -p tcp --dport 80 -j ACCEPT - iptables -I INPUT -m state --state NEW -p tcp --dport 443 -j ACCEPT - iptables -I INPUT -m state --state NEW -p tcp --dport 27701 -j ACCEPT - iptables -I INPUT -m state --state NEW -p tcp --dport 8384 -j ACCEPT - iptables -I INPUT -m state --state NEW -p tcp --dport 3000 -j ACCEPT - iptables -I INPUT -m state --state NEW -p tcp --dport 22000 -j ACCEPT - iptables -I INPUT -m state --state NEW -p udp --dport 22000 -j ACCEPT - iptables -I INPUT -m state --state NEW -p udp --dport 21027 -j ACCEPT - iptables -I INPUT -m state --state NEW -p tcp --dport 9812 -j ACCEPT - ''; - }; - - # system.stateVersion = "23.11"; # TEMPLATE - but probably no need to change - - # do not manage OCI syncthing through nix config - services.syncthing = { - enable = true; - guiAddress = "0.0.0.0:8384"; - openDefaultPorts = true; - }; - - - swarselsystems = { - hasBluetooth = false; - hasFingerprint = false; - impermanence = false; - isBtrfs = false; - flakePath = "/root/.dotfiles"; - server = { - enable = true; - forgejo = true; - ankisync = true; - }; - }; - -} diff --git a/hosts/nixos/sync/hardware-configuration.nix b/hosts/nixos/sync/hardware-configuration.nix deleted file mode 100644 index e2d61ff..0000000 --- a/hosts/nixos/sync/hardware-configuration.nix +++ /dev/null @@ -1,38 +0,0 @@ -{ config -, lib -, modulesPath -, ... -}: { - imports = [ - (modulesPath + "/profiles/qemu-guest.nix") - ]; - - boot.initrd.availableKernelModules = [ "ata_piix" "uhci_hcd" "virtio_pci" "virtio_scsi" "sd_mod" ]; - boot.initrd.kernelModules = [ ]; - boot.kernelModules = [ "kvm-amd" ]; - boot.extraModulePackages = [ ]; - - fileSystems."/" = { - device = "/dev/disk/by-uuid/4b47378a-02eb-4548-bab8-59cbf379252a"; - fsType = "xfs"; - }; - - fileSystems."/boot" = { - device = "/dev/disk/by-uuid/2B75-2AD5"; - fsType = "vfat"; - }; - - swapDevices = [ - { device = "/dev/disk/by-uuid/f0126a93-753e-4769-ada8-7499a1efb3a9"; } - ]; - - # Enables DHCP on each ethernet and wireless interface. In case of scripted networking - # (the default) this is the recommended approach. When using systemd-networkd it's - # still possible to use this option, but it's recommended to use it in conjunction - # with explicit per-interface declarations with `networking.interfaces..useDHCP`. - networking.useDHCP = lib.mkDefault true; - # networking.interfaces.ens3.useDHCP = lib.mkDefault true; - - nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; - hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; -} diff --git a/hosts/nixos/toto/default.nix b/hosts/nixos/toto/default.nix deleted file mode 100644 index 742b06b..0000000 --- a/hosts/nixos/toto/default.nix +++ /dev/null @@ -1,87 +0,0 @@ -{ self, inputs, outputs, config, pkgs, lib, ... }: -let - profilesPath = "${self}/profiles"; -in -{ - - imports = [ - inputs.disko.nixosModules.disko - "${self}/hosts/nixos/toto/disk-config.nix" - { - _module.args = { - withSwap = false; - }; - } - ./hardware-configuration.nix - - inputs.sops-nix.nixosModules.sops - - "${profilesPath}/optional/nixos/autologin.nix" - "${profilesPath}/common/nixos/settings.nix" - "${profilesPath}/common/nixos/home-manager.nix" - "${profilesPath}/common/nixos/xserver.nix" - "${profilesPath}/common/nixos/users.nix" - "${profilesPath}/common/nixos/sops.nix" - "${profilesPath}/server/nixos/ssh.nix" - - inputs.home-manager.nixosModules.home-manager - { - home-manager.users.swarsel.imports = [ - inputs.sops-nix.homeManagerModules.sops - "${profilesPath}/common/home/settings.nix" - "${profilesPath}/common/home/sops.nix" - "${profilesPath}/common/home/ssh.nix" - - ] ++ (builtins.attrValues outputs.homeManagerModules); - } - ] ++ (builtins.attrValues outputs.nixosModules); - - - nixpkgs = { - overlays = [ outputs.overlays.default ]; - config = { - allowUnfree = true; - }; - }; - - environment.systemPackages = with pkgs; [ - curl - git - gnupg - rsync - ssh-to-age - sops - vim - just - ]; - - system.stateVersion = lib.mkForce "23.05"; - - boot = { - loader.systemd-boot.enable = lib.mkForce true; - loader.efi.canTouchEfiVariables = true; - supportedFilesystems = [ "btrfs" ]; - kernelPackages = lib.mkDefault pkgs.linuxPackages_latest; - }; - - - networking = { - hostName = "toto"; - firewall.enable = false; - }; - - swarselsystems = { - wallpaper = self + /wallpaper/lenovowp.png; - impermanence = false; - isBtrfs = false; - initialSetup = true; - }; - - home-manager.users.swarsel.swarselsystems = { - isLaptop = false; - isNixos = true; - isBtrfs = false; - flakePath = "/home/swarsel/.dotfiles"; - }; - -} diff --git a/hosts/nixos/toto/disk-config.nix b/hosts/nixos/toto/disk-config.nix deleted file mode 100644 index 7e61397..0000000 --- a/hosts/nixos/toto/disk-config.nix +++ /dev/null @@ -1,87 +0,0 @@ -# NOTE: ... is needed because dikso passes diskoFile -{ lib -, pkgs -, withSwap ? false -, swapSize -, ... -}: -{ - disko.devices = { - disk = { - disk0 = { - type = "disk"; - device = "/dev/vda"; - content = { - type = "gpt"; - partitions = { - ESP = { - priority = 1; - name = "ESP"; - size = "512M"; - type = "EF00"; - content = { - type = "filesystem"; - format = "vfat"; - mountpoint = "/boot"; - mountOptions = [ "defaults" ]; - }; - }; - luks = { - size = "100%"; - content = { - type = "luks"; - name = "cryptroot"; - passwordFile = "/tmp/disko-password"; # this is populated by bootstrap-nixos.sh - settings = { - allowDiscards = true; - # https://github.com/hmajid2301/dotfiles/blob/a0b511c79b11d9b4afe2a5e2b7eedb2af23e288f/systems/x86_64-linux/framework/disks.nix#L36 - crypttabExtraOpts = [ - "fido2-device=auto" - "token-timeout=10" - ]; - }; - # Subvolumes must set a mountpoint in order to be mounted, - # unless their parent is mounted - content = { - type = "btrfs"; - extraArgs = [ "-f" ]; # force overwrite - subvolumes = { - "@root" = { - mountpoint = "/"; - mountOptions = [ - "compress=zstd" - "noatime" - ]; - }; - # "@persist" = { - # mountpoint = "${config.hostSpec.persistFolder}"; - # mountOptions = [ - # "compress=zstd" - # "noatime" - # ]; - # }; - "@nix" = { - mountpoint = "/nix"; - mountOptions = [ - "compress=zstd" - "noatime" - ]; - }; - "@swap" = lib.mkIf withSwap { - mountpoint = "/.swapvol"; - swap.swapfile.size = "${swapSize}G"; - }; - }; - }; - }; - }; - }; - }; - }; - }; - }; - - environment.systemPackages = [ - pkgs.yubikey-manager # For luks fido2 enrollment before full install - ]; -} diff --git a/hosts/nixos/winters/default.nix b/hosts/nixos/winters/default.nix deleted file mode 100644 index 725adf9..0000000 --- a/hosts/nixos/winters/default.nix +++ /dev/null @@ -1,70 +0,0 @@ -{ self, inputs, outputs, config, ... }: -let - profilesPath = "${self}/profiles"; -in -{ - - imports = [ - inputs.sops-nix.nixosModules.sops - - ./hardware-configuration.nix - - "${profilesPath}/optional/nixos/autologin.nix" - "${profilesPath}/server/nixos" - - inputs.home-manager.nixosModules.home-manager - { - home-manager.users.swarsel.imports = [ - "${profilesPath}/server/home" - ] ++ (builtins.attrValues outputs.homeManagerModules); - } - - ] ++ (builtins.attrValues outputs.nixosModules); - - - nixpkgs = { - overlays = [ outputs.overlays.default ]; - config = { - allowUnfree = true; - }; - }; - - boot = { - loader.systemd-boot.enable = true; - loader.efi.canTouchEfiVariables = true; - }; - - networking = { - hostName = "winters"; - hostId = "b7778a4a"; - firewall.enable = true; - enableIPv6 = false; - firewall.allowedTCPPorts = [ 80 443 ]; - }; - - - swarselsystems = { - hasBluetooth = false; - hasFingerprint = false; - impermanence = false; - isBtrfs = false; - flakePath = "/home/swarsel/.dotfiles"; - server = { - enable = true; - kavita = true; - navidrome = true; - jellyfin = true; - spotifyd = true; - mpd = false; - matrix = true; - nextcloud = true; - immich = true; - paperless = true; - transmission = true; - syncthing = true; - monitoring = true; - freshrss = true; - }; - }; - -} diff --git a/hosts/nixos/x86_64-linux/bakery/default.nix b/hosts/nixos/x86_64-linux/bakery/default.nix new file mode 100644 index 0000000..3927663 --- /dev/null +++ b/hosts/nixos/x86_64-linux/bakery/default.nix @@ -0,0 +1,59 @@ +{ self, config, inputs, lib, minimal, ... }: +let + primaryUser = config.swarselsystems.mainUser; +in +{ + + imports = [ + inputs.nixos-hardware.nixosModules.common-cpu-intel + + ./disk-config.nix + ./hardware-configuration.nix + + "${self}/modules/nixos/optional/gaming.nix" + "${self}/modules/nixos/optional/nswitch-rcm.nix" + "${self}/modules/nixos/optional/virtualbox.nix" + + ]; + + swarselsystems = { + isLaptop = true; + isNixos = true; + isBtrfs = true; + isLinux = true; + lowResolution = "1280x800"; + highResolution = "1920x1080"; + sharescreen = "eDP-1"; + info = "Lenovo Ideapad 720S-13IKB"; + firewall = lib.mkForce true; + wallpaper = self + /files/wallpaper/lenovowp.png; + hasBluetooth = true; + hasFingerprint = true; + isImpermanence = true; + isSecureBoot = false; + isCrypted = true; + isSwap = true; + rootDisk = "/dev/nvme0n1"; + swapSize = "4G"; + }; + + home-manager.users."${primaryUser}" = { + # home.stateVersion = lib.mkForce "23.05"; + swarselsystems = { + monitors = { + main = { + name = "LG Display 0x04EF Unknown"; + mode = "1920x1080"; # TEMPLATE + scale = "1"; + position = "1920,0"; + workspace = "15:L"; + output = "eDP-1"; + }; + }; + }; + }; +} // lib.optionalAttrs (!minimal) { + swarselprofiles = { + personal = true; + }; +} diff --git a/hosts/nixos/x86_64-linux/bakery/disk-config.nix b/hosts/nixos/x86_64-linux/bakery/disk-config.nix new file mode 100644 index 0000000..3dbabf8 --- /dev/null +++ b/hosts/nixos/x86_64-linux/bakery/disk-config.nix @@ -0,0 +1,122 @@ +{ lib, pkgs, config, ... }: +let + type = "btrfs"; + extraArgs = [ "-L" "nixos" "-f" ]; # force overwrite + subvolumes = { + "/root" = { + mountpoint = "/"; + mountOptions = [ + "subvol=root" + "compress=zstd" + "noatime" + ]; + }; + "/home" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/home"; + mountOptions = [ + "subvol=home" + "compress=zstd" + "noatime" + ]; + }; + "/persist" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/persist"; + mountOptions = [ + "subvol=persist" + "compress=zstd" + "noatime" + ]; + }; + "/log" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/var/log"; + mountOptions = [ + "subvol=log" + "compress=zstd" + "noatime" + ]; + }; + "/nix" = { + mountpoint = "/nix"; + mountOptions = [ + "subvol=nix" + "compress=zstd" + "noatime" + ]; + }; + "/swap" = lib.mkIf config.swarselsystems.isSwap { + mountpoint = "/.swapvol"; + swap.swapfile.size = config.swarselsystems.swapSize; + }; + }; +in +{ + disko.devices = { + disk = { + disk0 = { + type = "disk"; + device = config.swarselsystems.rootDisk; + content = { + type = "gpt"; + partitions = { + ESP = { + priority = 1; + name = "ESP"; + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "defaults" ]; + }; + }; + root = lib.mkIf (!config.swarselsystems.isCrypted) { + size = "100%"; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/disk/by-label/nixos" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + luks = lib.mkIf config.swarselsystems.isCrypted { + size = "100%"; + content = { + type = "luks"; + name = "cryptroot"; + passwordFile = "/tmp/disko-password"; # this is populated by bootstrap.sh + settings = { + allowDiscards = true; + # https://github.com/hmajid2301/dotfiles/blob/a0b511c79b11d9b4afe2a5e2b7eedb2af23e288f/systems/x86_64-linux/framework/disks.nix#L36 + crypttabExtraOpts = [ + "fido2-device=auto" + "token-timeout=10" + ]; + }; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/mapper/cryptroot" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + }; + }; + }; + }; + }; + }; + + fileSystems."/persist".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + fileSystems."/home".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + + environment.systemPackages = [ + pkgs.yubikey-manager + ]; +} diff --git a/hosts/nixos/x86_64-linux/bakery/hardware-configuration.nix b/hosts/nixos/x86_64-linux/bakery/hardware-configuration.nix new file mode 100644 index 0000000..8322c04 --- /dev/null +++ b/hosts/nixos/x86_64-linux/bakery/hardware-configuration.nix @@ -0,0 +1,23 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ config, lib, modulesPath, ... }: + +{ + imports = + [ + (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot = { + initrd = { + availableKernelModules = [ "xhci_pci" "nvme" "usb_storage" "sd_mod" ]; + kernelModules = [ ]; + }; + kernelModules = [ ]; + extraModulePackages = [ ]; + }; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/hosts/nixos/x86_64-linux/bakery/secrets/pii.nix.enc b/hosts/nixos/x86_64-linux/bakery/secrets/pii.nix.enc new file mode 100644 index 0000000..903f22f --- /dev/null +++ b/hosts/nixos/x86_64-linux/bakery/secrets/pii.nix.enc @@ -0,0 +1,22 @@ +{ + "data": "ENC[AES256_GCM,data:M8uEE2uxhHHh5UdLO+J18EMVWm+9FCR2BHMJ3P0Il4h+0CqWOS27aVWPjI2lIt+jw5svt5kVbTIzwvw1GmEdcXzJrE9yZ0eKkXSm/TYQQZhlmcPcNeJyDf/bLivwExKicRy2JR2KNyAoiW5gISF7nkUv10EnM60mzH2RftPijvdgSTmdoNu/9Q0J3M46k+EVGO370NXT89eSbhFMS4r6M94vKaA=,iv:C4ELLFaF9yFfDH+g/TwQtRm1DuRtIAxcI55I0mpKd70=,tag:jLWAD2pLkqzekJipf/Rc5Q==,type:str]", + "sops": { + "age": [ + { + "recipient": "age1mjgw3nxlnqdj04mgjz3wn7fj2nl2nxla4p2r2fn4nkvayfgp09pqllxzyh", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBZaGtCbDBYaDZTMUhhbTY2\nbk45NWRPZU5nWmh5M0ZDNGF2Q09rNHNzRGhzCjh1d3pLRnRtZjVnaG1oN0daOXRy\nUzVFd3QzVTBib29QbGN4cXNheVRCNWcKLS0tIFlielcwODk4MjFsS29ybXNDMm5y\nN01aaHBFN0VPdTNrMzJNaE9NRG9KRnMKNV4rqYphPTyXF5m+qNq10aIov8quVh2Y\nALelTPRpD/hMYou/s8Ro49GHNNNKeV9J+4Tvq1QEmIIdvjFLy9AS9A==\n-----END AGE ENCRYPTED FILE-----\n" + } + ], + "lastmodified": "2025-07-10T15:25:21Z", + "mac": "ENC[AES256_GCM,data:pMWJo+JuSgs7RE+rc6vB1u/V3kfQzRjknxIMkNNJCcBp2WVoz84BZ23oruaB2Z/ZSO9zpaQMHkuAqGZU7CuvZ1JvECHWov5fRkXDPeaeIVw3dtof1XzH5plRmAUzabrmEzrGSnwJrJ6DRlAhrq2gDyyIY4qmUeySc7zgR7QVf0o=,iv:iCM7ulRAP5FYyR/z7CSDRYMsm2Gjs7qWLChtslGfzO4=,tag:QJ2Lxmwvgd+ILHeYhMvmwg==,type:str]", + "pgp": [ + { + "created_at": "2025-07-10T23:51:27Z", + "enc": "-----BEGIN PGP MESSAGE-----\n\nhQIMAwDh3VI7VctTARAAmKgk+exHX36+IkSQC03yiRpEKpmkqt+FcGsbDMonTyow\nmvhmwSc7UscNOgOQYDYA66vMCWE2Ij9gxFJNpPG3rXFiC11XN1/pq+Jy3Qvk3DNV\ntnXgwDvSt7Ry7FThXnPiJAkcjwYNeTniyjzKcUmXA+yEJAlswjGjH6uP/Nvkeo2n\np+OvRQc0cXHBSTbnIq4dHaqVlp1JWOQgtZVrIgwN/rv3xvDPE2E2dmCc9hUg83vk\naUT7fDo8v5hWwJJO7Q6OvECKw/D4jWTxnBP1nS3a66shkpcC7lpYQjE6AtAM3AbY\nB84rat/Tff6ZcmtxMvIa62vfwrfSh/00DmRlPkIe1KlbjrV1kafzbySjI7q1vy2l\neZL7/Zi49fy/KudQ+/OOMC/PlhGLYGtEo3sNmLY7pfBNuMmwjYQ0K/1kKQ8XXJDw\nbWQDP+8aeIKKciLy07NW5Fd5gc5S1exSFHDQyhCXjdUcPk3cTfnEvMP/T1bCNCaD\nGxy6IEifdJvYNeWyaxgbKzsLmz8kTd6wPj/v0BIdL+dy3/a/4SVLR9r7Qn3bMgkc\nb1wVY4XDyt6LPnwVY3UOFPSCVckGb8NRnciKOj1TnsaYI6xEQ0ObuuAedVJQj0wF\n5OqYrwnH+riiLFMVzsEspNQNlMTRY86zPIxuNe8qPDdVL5CotAoobzdmr9cc75uF\nAgwDC9FRLmchgYQBD/4ntfP9dGtNzb9BjR6NEmdqJDIS37lHCc6ts/f86VCiy0tk\nhdtVdZ7sYdFvzkGimfmcbsVJ5VOPK6S82L0xUlROCax1bVkjK8VjqppUbTxQMgWh\nek7pPzE66MJzXlpqGgmRHgLuV0yhTqz9TGbTetjYYlWiOGMGYHwvxMLnvTvQIbJb\nBwtpbK0SEu7ODMn1mGtWpzkVI9rDeCW/FT0bBj1KvkWBWbCVFCSVGjmxuWcFgRs/\nc3aNA/DLQMsX7TzvqiY+dXLdp9/vuyqIf+qzC8IIrI5fskzaVfjP+OzeAVTXeI/f\nYsgvF31Z+DfMAFQ7dnAQ56Ys/oSdNTaAnhfFjI4S40qw0SfZdTWzUm9IjhnZKgaU\nNV9V3b2D7nr64JxutHzYiJemlB4Oy+HhqMQR3AYeMDX3hEG1Xt7splkBLdXccIEe\nGTOoaIffV1QUAB2M9PVyidpLf98Ii9s8Mr2OUcQsYiJy7jNXTudx50mnIhmBSDPN\nk/RSFoMo0+v7jC7lWkfWhvunUJrJ37zNSEHZcJo7Wj+SflqZDI/QRQAez6xRF6ih\nzgFfAgNSDAkbymvju7I6V9TEOw8rLdlXLlBNd+GAy0S2HfNIN8lx2tVnP++zP54C\nhdEDMU+uKp98Wu1fVuMipzjfPqJ0lpNj9M2+ma3q3w1L4YbMa+nVEK4/mmP0e9Jc\nAdvTsgHHFgN5KOwmZkQdAhKJ89cwcGUwZwn/gO7pEGoOw6WaHIIE6ueOiThfkXm/\nWIe1AC/JQapdMlvmF+2Rf51RmSkWX3/vtFPNkWvgkGgCely/eDXRK/si+kk=\n=ep9e\n-----END PGP MESSAGE-----", + "fp": "4BE7925262289B476DBBC17B76FD3810215AE097" + } + ], + "unencrypted_suffix": "_unencrypted", + "version": "3.10.2" + } +} diff --git a/hosts/nixos/x86_64-linux/eagleland/default.nix b/hosts/nixos/x86_64-linux/eagleland/default.nix new file mode 100644 index 0000000..baa5bd5 --- /dev/null +++ b/hosts/nixos/x86_64-linux/eagleland/default.nix @@ -0,0 +1,38 @@ +{ self, lib, minimal, ... }: +{ + imports = [ + ./hardware-configuration.nix + ./disk-config.nix + + "${self}/modules/nixos/optional/systemd-networkd-server.nix" + ]; + + topology.self = { + icon = "devices.cloud-server"; + }; + + + swarselsystems = { + flakePath = "/root/.dotfiles"; + info = "2vCPU, 4GB Ram"; + isImpermanence = true; + isSecureBoot = false; + isCrypted = true; + isCloud = true; + isSwap = true; + swapSize = "4G"; + rootDisk = "/dev/sda"; + isBtrfs = true; + isNixos = true; + isLinux = true; + proxyHost = "eagleland"; + }; +} // lib.optionalAttrs (!minimal) { + + swarselmodules.server.mailserver = true; + + swarselprofiles = { + server = true; + }; + +} diff --git a/hosts/nixos/x86_64-linux/eagleland/disk-config.nix b/hosts/nixos/x86_64-linux/eagleland/disk-config.nix new file mode 100644 index 0000000..9a98cce --- /dev/null +++ b/hosts/nixos/x86_64-linux/eagleland/disk-config.nix @@ -0,0 +1,121 @@ +{ lib, pkgs, config, ... }: +let + type = "btrfs"; + extraArgs = [ "-L" "nixos" "-f" ]; # force overwrite + subvolumes = { + "/root" = { + mountpoint = "/"; + mountOptions = [ + "subvol=root" + "compress=zstd" + "noatime" + ]; + }; + "/home" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/home"; + mountOptions = [ + "subvol=home" + "compress=zstd" + "noatime" + ]; + }; + "/persist" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/persist"; + mountOptions = [ + "subvol=persist" + "compress=zstd" + "noatime" + ]; + }; + "/log" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/var/log"; + mountOptions = [ + "subvol=log" + "compress=zstd" + "noatime" + ]; + }; + "/nix" = { + mountpoint = "/nix"; + mountOptions = [ + "subvol=nix" + "compress=zstd" + "noatime" + ]; + }; + "/swap" = lib.mkIf config.swarselsystems.isSwap { + mountpoint = "/.swapvol"; + swap.swapfile.size = config.swarselsystems.swapSize; + }; + }; +in +{ + disko = { + imageBuilder.extraDependencies = [ pkgs.kmod ]; + devices = { + disk = { + disk0 = { + type = "disk"; + device = config.swarselsystems.rootDisk; + content = { + type = "gpt"; + partitions = { + ESP = { + priority = 1; + name = "ESP"; + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "defaults" ]; + }; + }; + root = lib.mkIf (!config.swarselsystems.isCrypted) { + size = "100%"; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/disk/by-label/nixos" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + luks = lib.mkIf config.swarselsystems.isCrypted { + size = "100%"; + content = { + type = "luks"; + name = "cryptroot"; + passwordFile = "/tmp/disko-password"; # this is populated by bootstrap.sh + settings = { + allowDiscards = true; + # https://github.com/hmajid2301/dotfiles/blob/a0b511c79b11d9b4afe2a5e2b7eedb2af23e288f/systems/x86_64-linux/framework/disks.nix#L36 + crypttabExtraOpts = [ + "fido2-device=auto" + "token-timeout=10" + ]; + }; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/mapper/cryptroot" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + }; + }; + }; + }; + }; + }; + }; + + fileSystems."/persist".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + fileSystems."/home".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; +} diff --git a/hosts/nixos/x86_64-linux/eagleland/hardware-configuration.nix b/hosts/nixos/x86_64-linux/eagleland/hardware-configuration.nix new file mode 100644 index 0000000..8dc40ba --- /dev/null +++ b/hosts/nixos/x86_64-linux/eagleland/hardware-configuration.nix @@ -0,0 +1,18 @@ +{ lib, modulesPath, ... }: + +{ + imports = + [ + (modulesPath + "/profiles/qemu-guest.nix") + ]; + + boot = { + initrd = { + availableKernelModules = [ "ahci" "xhci_pci" "virtio_pci" "virtio_scsi" "sd_mod" "sr_mod" ]; + kernelModules = [ ]; + }; + kernelModules = [ ]; + extraModulePackages = [ ]; + }; + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; +} diff --git a/hosts/nixos/x86_64-linux/eagleland/secrets/pii.nix.enc b/hosts/nixos/x86_64-linux/eagleland/secrets/pii.nix.enc new file mode 100644 index 0000000..7407819 --- /dev/null +++ b/hosts/nixos/x86_64-linux/eagleland/secrets/pii.nix.enc @@ -0,0 +1,22 @@ +{ + "data": "ENC[AES256_GCM,data:nIgv3b+6o5Ce9X9xZtBK62f6dgsAGLPqq7aVFCw2qjD9UiHCrAY9vTn5NSW2O2pbLAfx6h7falS3/0yU+AkJ2H3zhxBy7ZxQ0m9dLoQGrYY/E9Z45xZmdFRxtzexCaxr2DxbP8haJKomQ22cHk07HGsrEZ/CFGkyjRxUr3Y4rewgZPBXahVtM75mWbNpVGApc8cs/W4JbjuXw3qlCQcACz8sZVPHKCjbEypypo6nTmU7NO7worrAJ2QgU75oGJ9g96wp9paFMEDofVp2Y25IVYReGg8T1Qi/kTcZzfzGfSpEwnQBB/ZCW6gNYhMK3shfB8DxKy6+romVXm1K+/0yUmwsCM8xC5zJX0GsO8Uu63YFrW/Y2E6aYZfBHdIgfy4lYOFKC2o0ixirw9EO8HyfsDt47QYB970vLPjYZfKNAZBgltbV3KPsOHxmgiZbTbAl0cb9zRc+jV2voH9T5VhFiUWdfaLBY1HUAVAjU7h62uZoCsi1HWyAroEROKS96npTD+3/vHehYuEGBf1IxYnLwHnKeqsr/Bqoukf3OecOH2EkMTTFQ7E0k9s0keRypoHmeYIh2a3dRcaXXbNEgiAMfabhgUh1NNcYKSZhcIekN8WN8azXjbVIrfEakJ8S+PUf5fJdspN/3Ppm06fDLv7yLHnLc8Eae2COOR8vYKIo3Onu4doxNjisfpHujLXYaCGhWpINEGWF7fkeC1B7,iv:v9MxvhcHg+P00UnOWujSgVlMNcOnDm/gK8kNcN54E2E=,tag:XnPMzsDeGJMt9yv6GnFzqg==,type:str]", + "sops": { + "age": [ + { + "recipient": "age1cmzh82q8k59yzceuuy2epmqu22g7m84gqvq056mhgehwpmvjadfsc3glc8", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBJR1ZPZFUxRTh0QjB6UDJ4\nOFd2c2lFejhHck5UdUxVbmFFbVRYNEJaSzJZCkNxbndVVThObDkxUmx2WW9ESzhh\na2o0LzFCbWdJVlRIV00rTVUwTktoek0KLS0tIC9qalVvZmpGQXZsV3RIYWRPbmRY\nam80NkRkT2l0ak8wV3pTSW9kSC9nZ3cKCH8eEMmku6WMliEDdAiW2Lk1jAGH9SoP\nWQ5Y6e90jEnp8XbGE7KYiG+jy5fHSc6Y5/YyMmi/b9bF9AhmRT6rdw==\n-----END AGE ENCRYPTED FILE-----\n" + } + ], + "lastmodified": "2025-11-28T10:50:22Z", + "mac": "ENC[AES256_GCM,data:lwkkp8YSzX8NM7E65kmPpF/q9Vn+FnCTeePLswDH6AVgndo/7QOy0GtJeXmiwt2YsA4AhRqxexWl2R8tjEysP35pyfQJ4vEkVi+V2tEnoLgftriNJzpoeVuRNXLxTPhPezOZgAcTDDL4yyqJXpcFj0PE1DPHKxazT28BoilaBYE=,iv:3dcAqkw/y6rAPL8wb5iewz37S4xszYFGHxvQiQ98sLk=,tag:SEmbptei6GrTXXyb7zwrIg==,type:str]", + "pgp": [ + { + "created_at": "2025-11-23T15:25:41Z", + "enc": "-----BEGIN PGP MESSAGE-----\n\nhQIMAwDh3VI7VctTAQ/+OOUtfNq9RBpm1/AbgTjenkcsRwzvyxMQ+VfT7AN/OjEH\naYaVnoU+IYoUJIw8u0zfFuJGyhcU862pMN+isngqNNZiEqY8C9rP4+l82Ks4qLU2\nanUk8HPcUc7bQC19zoSpl5MIeppV4SNC5OAph+YKVcj95l6OFw1EieptfhRFtTps\nwUKMf3p9FC/ndxjDG6Rxro7RQsETJgZ3DE3tRFPsBzMiC3sf+fsOzFgVyABqYZ1k\nDr+pkdBzGB3LXOyeDJWK38DxY/NEEfDgdSGLC6ntQ8eS9fbcNajT6FUwH2uwHJ4y\niWT6Q8z+XFjh3Z458tZhcnBGv6AKGeQ/QG9z+0DALKkkmij+vJqRAGjJxur6XM3K\nf0anUMXLeCINcLEa+Wv7inYJaPXu2NSmqtd1yYYXoAbVcnmzmgW9D2in+JnG5urQ\nCq0MEALyp1axExIaD3BHrFIaK9IX2PO1E/PLDng8AtGEx5Fn//OQX0Wt/yB2eEk2\n3uubPz1a1eMfRz1pK5CFOpJoZ8bmyg5n4g/5MgVgoxzA5nhjfMYD/HD8EG3ta8PI\nrQZhtlg7C+5nEsNevD4RPmzO7z1JdqJGMIWPPUJKZ7WozA5192aAw6HVKdtI4FH7\nXv4KY+GcmUvsKhpaWidW7vsY4MWSfn4m6Ybg2vqHsCUjj5fHVHF9BeKQecIcTTyF\nAgwDC9FRLmchgYQBD/4mfMCt5Ez8WITcru+pwlMHCeSUOxfftsydqdtt/gZ2oJTH\nhMMN2A26x3LXIfZ8IA6to6ldxQLfj3gDF8H+akHbRyndrA1V0U+EhoNZ/DYECkNB\nx8xtrJwsY47siT7sWlounXqnQr5E4nfSfDOsfSv04aUyyUsMqdjFRVY1/b5BCkoJ\nOptFJJjdosfmGfsHCGYvqj0XNycVQj3ioYEwOdDMlZ8riSyRTRPL9UAfgFeQ5swG\n1I1qWaF2+8KUk01wQwmwYLKs1JUnVOl6Uy4XpHbcZcCEIW3VVnwxFVCYcHwhDXWT\n4YGeGFfosuthL4AjJ2EmNKLq+sUxmD7ANS2E561+0BDAakQ3Z0eA/wpJ6VWQtfV0\n05tw6zS3BWwTi5fiiN4JvXqnj+8aT1PBtgxrCeDCjQ36KGViLzDsZOCMNYcr1EZI\nEFMTmaUDFWtoHQKi7ZU+oiRGGfZdnbh0icCsnBecePo4//LaCvBn6lA+vFBmuHLo\nZ2Idh5JSYFoEvhdX3j+sO0dOqzQdDEDy6+Y3S3T4vuSB3w5k1B5c3EDseKfLHUY/\nhgAIxO7rtELyhlFODMmEOzLWwOfxq/5ar/izxkdQS5HPNyVXT6SKikTGmI2z8Uw3\njyCaXv7ny5IVG/kR5aTP+DIHhichcpxJk7j+wZfZV/g8O2PWQpYXfxr36gSo49Je\nARJUBGaEVAhqoNfaHCUbvHCSbbI2yKY+sliX3p7MmcMdy/cvKyowQUuw/FYtdbGD\nHwCe6GZZzHWJZkX3nju3zhOy3gBDBDB1fbF4W0VjsjOwYjy/7MNMVH0eXli20Q==\n=qkvc\n-----END PGP MESSAGE-----", + "fp": "4BE7925262289B476DBBC17B76FD3810215AE097" + } + ], + "unencrypted_suffix": "_unencrypted", + "version": "3.11.0" + } +} diff --git a/hosts/nixos/x86_64-linux/hintbooth/default.nix b/hosts/nixos/x86_64-linux/hintbooth/default.nix new file mode 100644 index 0000000..dbb6c6b --- /dev/null +++ b/hosts/nixos/x86_64-linux/hintbooth/default.nix @@ -0,0 +1,36 @@ +{ lib, minimal, ... }: +{ + + imports = [ + ./hardware-configuration.nix + ./disk-config.nix + ]; + + swarselsystems = { + info = "HUNSN RM02, 8GB RAM"; + flakePath = "/root/.dotfiles"; + isImpermanence = true; + isSecureBoot = true; + isCrypted = true; + isBtrfs = true; + isLinux = true; + isNixos = true; + rootDisk = "/dev/sda"; + swapSize = "8G"; + networkKernelModules = [ "igb" ]; + }; + +} // lib.optionalAttrs (!minimal) { + + swarselprofiles = { + server = true; + router = false; + }; + + swarselmodules = { + server = { + nginx = lib.mkForce false; # we get this from the server profile + }; + }; + +} diff --git a/hosts/nixos/x86_64-linux/hintbooth/disk-config.nix b/hosts/nixos/x86_64-linux/hintbooth/disk-config.nix new file mode 100644 index 0000000..a4b5089 --- /dev/null +++ b/hosts/nixos/x86_64-linux/hintbooth/disk-config.nix @@ -0,0 +1,118 @@ +{ lib, config, ... }: +let + type = "btrfs"; + extraArgs = [ "-L" "nixos" "-f" ]; # force overwrite + subvolumes = { + "/root" = { + mountpoint = "/"; + mountOptions = [ + "subvol=root" + "compress=zstd" + "noatime" + ]; + }; + "/home" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/home"; + mountOptions = [ + "subvol=home" + "compress=zstd" + "noatime" + ]; + }; + "/persist" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/persist"; + mountOptions = [ + "subvol=persist" + "compress=zstd" + "noatime" + ]; + }; + "/log" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/var/log"; + mountOptions = [ + "subvol=log" + "compress=zstd" + "noatime" + ]; + }; + "/nix" = { + mountpoint = "/nix"; + mountOptions = [ + "subvol=nix" + "compress=zstd" + "noatime" + ]; + }; + "/swap" = lib.mkIf config.swarselsystems.isSwap { + mountpoint = "/.swapvol"; + swap.swapfile.size = config.swarselsystems.swapSize; + }; + }; +in +{ + disko.devices = { + disk = { + disk0 = { + type = "disk"; + device = config.swarselsystems.rootDisk; + content = { + type = "gpt"; + partitions = { + ESP = { + priority = 1; + name = "ESP"; + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "defaults" ]; + }; + }; + root = lib.mkIf (!config.swarselsystems.isCrypted) { + size = "100%"; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/disk/by-label/nixos" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + luks = lib.mkIf config.swarselsystems.isCrypted { + size = "100%"; + content = { + type = "luks"; + name = "cryptroot"; + passwordFile = "/tmp/disko-password"; # this is populated by bootstrap.sh + settings = { + allowDiscards = true; + # https://github.com/hmajid2301/dotfiles/blob/a0b511c79b11d9b4afe2a5e2b7eedb2af23e288f/systems/x86_64-linux/framework/disks.nix#L36 + crypttabExtraOpts = [ + "fido2-device=auto" + "token-timeout=10" + ]; + }; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/mapper/cryptroot" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + }; + }; + }; + }; + }; + }; + + fileSystems."/persist".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + fileSystems."/home".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; +} diff --git a/hosts/nixos/x86_64-linux/hintbooth/hardware-configuration.nix b/hosts/nixos/x86_64-linux/hintbooth/hardware-configuration.nix new file mode 100644 index 0000000..21725ec --- /dev/null +++ b/hosts/nixos/x86_64-linux/hintbooth/hardware-configuration.nix @@ -0,0 +1,24 @@ +{ config, lib, modulesPath, ... }: + +{ + imports = + [ + (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot = { + initrd.availableKernelModules = [ "ahci" "xhci_pci" "usbhid" "usb_storage" "sd_mod" ]; + initrd.kernelModules = [ ]; + extraModulePackages = [ ]; + }; + + # Enables DHCP on each ethernet and wireless interface. In case of scripted networking + # (the default) this is the recommended approach. When using systemd-networkd it's + # still possible to use this option, but it's recommended to use it in conjunction + # with explicit per-interface declarations with `networking.interfaces..useDHCP`. + networking.useDHCP = lib.mkDefault true; + # networking.interfaces.enp3s0.useDHCP = lib.mkDefault true; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/hosts/nixos/x86_64-linux/hintbooth/secrets/pii.nix.enc b/hosts/nixos/x86_64-linux/hintbooth/secrets/pii.nix.enc new file mode 100644 index 0000000..15fe6cb --- /dev/null +++ b/hosts/nixos/x86_64-linux/hintbooth/secrets/pii.nix.enc @@ -0,0 +1,22 @@ +{ + "data": "ENC[AES256_GCM,data:trvZ+abrf69YhdmIQ1ekgDW82PtPnJkC5bfvh6lABb1BBkPWZk8Ds7Ug4CtulspitB/Spwd0ksGHSuEpk7Xg9V+5O9nm4/8JWWh7EF4qKWeRiwqj/dpfHTtTQPOzywHQFwLg6EWS3wSwUu60dZqJ8f36rvr+KAZc71jZayZmm3TIpeDaMsCAyO+TrfzeKM8AYN4uUVr30raquNjd2XzGgufE3FFCQdo4yhvzVGHGq0+wrZGr,iv:Yx4RkCBSkB4gK1dnMGudPwPP6moR4/7ovDZ77f1WL9o=,tag:9tTUU6ax2K2CqKjxHn2ZaQ==,type:str]", + "sops": { + "age": [ + { + "recipient": "age1hsumymvh5mkqlaynrp9lv2w696yk3wtjzlyfmrpeuvh9u2tlwceqh3563x", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA0VHAxaWdiV1VlWEY2UktF\ncE96UHJnWGNpY0ZFUmZVSi9xSXpBMmI2S1VFCjB6cWtDTTJrNFhZRC9yUHRYdUpS\naytwOUJ4NTRxTmJmc0R0Wmh5dFVKbzQKLS0tIHQ2NUtqRjh6MVF6VHJFSHVFTFFD\nNWh0MDVjekFDUWZvTUZNK0Z4M0lJbVEKGZk1BvZsNTkIor5rTcpi2UE4W/BqNMWU\nIAe3irNN6p1si2zebrCEyiaJYuaVn7uYVwXcscJlNTfkr9szm8TjSA==\n-----END AGE ENCRYPTED FILE-----\n" + } + ], + "lastmodified": "2025-11-23T18:19:50Z", + "mac": "ENC[AES256_GCM,data:IA71SHchjrqqU5tRlJ4Ozgx2rRxhKE42CsC7ygBLdAZcyZs+7iMpskYejIue8+JXto7zJxe38UbolnLOaTkHzSVGJkKMYQQQ/sXoDtaWlsYTN648ug4zAbgN1neifNnG+756abcg9NEuJRXBhXDzqmAecHkzv6U0HW9LHPO9W1s=,iv:dEiu6FnSqALXDOtpCZ3FiQ8D6GU0FjQAFA12SPaSIAY=,tag:/SXghsNzu8ceOQk/2w8e7w==,type:str]", + "pgp": [ + { + "created_at": "2025-11-11T17:51:27Z", + "enc": "-----BEGIN PGP MESSAGE-----\n\nhQIMAwDh3VI7VctTAQ//cwoYXkjChyIyDP0dmqquRMAv7AsLz2IVVKcdGzqKWR/z\nx7owbhfGFaNCU/x8TWs3mUFBNnLIUQmuSWUuI30VMmFVjXQ9sybCZUCk5oFLD53+\nVPPb/KsAO06it8T0NxAlsXqe7n9fz1P16mFpMx8N1yb5s+GYG/C3UGATwJTJQn8+\nwob0NHfN/6qsZP5PzMgKlUiqc3YF+eB71KTHNDmT3l5sGsoNi0erZwNZc4VA0zn8\nPsFYodW9Mya1XUanJvrYKo9eRfrlpaUKGzn6GVlMJsZU0gNpKZepMubbev3+B1GR\nn6V+ViYWd8U9UTatuHy+aRcwEZfpXq7uKTTTdihECjNkHYSfXmUF9mjq6u5U0Lck\nykhElFADx+YEBJuavQabvYGu8fJx9DfJseNVwIv0M6hqLdg2CNMUQ1l1Q9weizeZ\nxLjme1LTlCUinJGN07CE0J9qP8syWRJYD9seP9Qc/b1IY2D8dGdgOTzO8Fx8vI+M\nOV+Q3T0Chn/f0lw2Xzu40MphB3eamt5cq0JeLQuwQHjUml0rGpi7bIj8PxeAgMkX\nXFzSokYTHGRJz2UblLnITfMaVYcu9HYHXxXIsZliaRBs2AlscyCCSQFjnEAEywlo\n9kvh49sjWztb0yGqHRAxdmJ+Sm5fCqP0huaTMXkC3zy4h0oeJte36Us0VxKk1HqF\nAgwDC9FRLmchgYQBD/oCYXtBTr276kjOMWs3WqDYMLUDbWM8d6b86HYgYvtwQy0z\nXgASNtWQsMMyIEiReSqv2H9jtTTqbUK93ALW2X7GmEvUIvmW64g1AfHKhmPw//Li\nKMxtK6sFVS/WSEYoaZarkZDwOpNx3+BnriQEHiMi21vWxCqluZFSDdls0ca2oXvF\nK9GpBUD8v5+l2EWhq5+4nxHKrDx0g+mjtZPJPRsJ1u0tisdkhRXauOvRHEymZ3mX\nRTee3FNR1t6YpXY811lX9yemXkdsSB4pzKWNQgk6U7WDkGcVaGNw0R8pS7F3YnRE\nFSJhKnhb9Bd6CX/zEV+IwEgY1yPfiEMX0bvIrcEJYgUg618YQbQPushxVk10+c66\nZJ+99g06tdyt+u8E9GpoujnoRjRWsEqElkZntd66fPuDm99qx+RHlF/1Likp/nPL\n4oIknDJu8wwoIBCtoQcWyaiNCa0Fo/HR6txyOt6tTqpwhnDGJP9UfYlKWt07CFar\nQLgZfJbHhetjXoRHMAs+WargN8KV7QGMGbQdPE+VwlZI4bKRSipH+rdDn+v50FQG\ndvFd7WRnWmTaG2W3cOLFH4pWc2MPnnxj0IHDI3U9olcCyuWAF12yC1HYuFuWeG+K\nokxmS1T1E0jIP9u8NTJBmLdjC+6U5y1ZvSZlIWB12OzBEpP7jl8uOVbD/AR4GtJe\nAf4EdsxTBocS50aRxxAOq5t3kaoTu36n1dbGDfb8k10bsBiQb6zJ+xtNQgWxNEeO\nb6YGIyglD06Wmm6C5LOyQ46KIzuFXB8irMJexApopLwIZ+jCnn0Nb1mO6DXHUw==\n=kTmR\n-----END PGP MESSAGE-----", + "fp": "4BE7925262289B476DBBC17B76FD3810215AE097" + } + ], + "unencrypted_suffix": "_unencrypted", + "version": "3.11.0" + } +} diff --git a/hosts/nixos/x86_64-linux/hotel/default.nix b/hosts/nixos/x86_64-linux/hotel/default.nix new file mode 100644 index 0000000..7d32053 --- /dev/null +++ b/hosts/nixos/x86_64-linux/hotel/default.nix @@ -0,0 +1,60 @@ +{ self, config, pkgs, lib, minimal, ... }: +let + mainUser = "demo"; +in +{ + + imports = [ + ./hardware-configuration.nix + ./disk-config.nix + { + _module.args.diskDevice = config.swarselsystems.rootDisk; + } + ]; + + environment.variables = { + WLR_RENDERER_ALLOW_SOFTWARE = 1; + }; + + services.qemuGuest.enable = true; + + boot = { + loader.systemd-boot.enable = lib.mkForce true; + loader.efi.canTouchEfiVariables = true; + kernelPackages = lib.mkDefault pkgs.linuxPackages_latest; + }; + + networking = { + hostName = "hotel"; + firewall.enable = true; + }; + + swarselmodules = { + server = { + network = lib.mkForce false; + diskEncryption = lib.mkForce false; + }; + }; + + swarselsystems = { + info = "~SwarselSystems~ demo host"; + wallpaper = self + /files/wallpaper/lenovowp.png; + isImpermanence = true; + isCrypted = true; + isSecureBoot = false; + isSwap = true; + swapSize = "4G"; + rootDisk = "/dev/vda"; + isBtrfs = false; + inherit mainUser; + isLinux = true; + isPublic = true; + isNixos = true; + }; + +} // lib.optionalAttrs (!minimal) { + swarselprofiles = { + hotel = true; + minimal = true; + }; +} diff --git a/hosts/nixos/x86_64-linux/hotel/disk-config.nix b/hosts/nixos/x86_64-linux/hotel/disk-config.nix new file mode 100644 index 0000000..5131677 --- /dev/null +++ b/hosts/nixos/x86_64-linux/hotel/disk-config.nix @@ -0,0 +1,128 @@ +# NOTE: ... is needed because dikso passes diskoFile +{ lib +, pkgs +, config +, diskDevice ? config.swarselsystem.rootDisk +, ... +}: +let + type = "btrfs"; + extraArgs = [ "-L" "nixos" "-f" ]; # force overwrite + subvolumes = { + "/root" = { + mountpoint = "/"; + mountOptions = [ + "subvol=root" + "compress=zstd" + "noatime" + ]; + }; + "/home" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/home"; + mountOptions = [ + "subvol=home" + "compress=zstd" + "noatime" + ]; + }; + "/persist" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/persist"; + mountOptions = [ + "subvol=persist" + "compress=zstd" + "noatime" + ]; + }; + "/log" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/var/log"; + mountOptions = [ + "subvol=log" + "compress=zstd" + "noatime" + ]; + }; + "/nix" = { + mountpoint = "/nix"; + mountOptions = [ + "subvol=nix" + "compress=zstd" + "noatime" + ]; + }; + "/swap" = lib.mkIf config.swarselsystems.isSwap { + mountpoint = "/.swapvol"; + swap.swapfile.size = config.swarselsystems.swapSize; + }; + }; +in +{ + disko.devices = { + disk = { + disk0 = { + type = "disk"; + device = diskDevice; + content = { + type = "gpt"; + partitions = { + ESP = { + priority = 1; + name = "ESP"; + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "defaults" ]; + }; + }; + root = lib.mkIf (!config.swarselsystems.isCrypted) { + size = "100%"; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/disk/by-label/nixos" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + luks = lib.mkIf config.swarselsystems.isCrypted { + size = "100%"; + content = { + type = "luks"; + name = "cryptroot"; + passwordFile = "/tmp/disko-password"; # this is populated by bootstrap.sh + settings = { + allowDiscards = true; + # https://github.com/hmajid2301/dotfiles/blob/a0b511c79b11d9b4afe2a5e2b7eedb2af23e288f/systems/x86_64-linux/framework/disks.nix#L36 + crypttabExtraOpts = [ + "fido2-device=auto" + "token-timeout=10" + ]; + }; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/mapper/cryptroot" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + }; + }; + }; + }; + }; + }; + + fileSystems."/persist".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + fileSystems."/home".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + + environment.systemPackages = [ + pkgs.yubikey-manager + ]; +} diff --git a/hosts/nixos/chaostheatre/hardware-configuration.nix b/hosts/nixos/x86_64-linux/hotel/hardware-configuration.nix similarity index 64% rename from hosts/nixos/chaostheatre/hardware-configuration.nix rename to hosts/nixos/x86_64-linux/hotel/hardware-configuration.nix index e2d2cf8..a6aefd7 100644 --- a/hosts/nixos/chaostheatre/hardware-configuration.nix +++ b/hosts/nixos/x86_64-linux/hotel/hardware-configuration.nix @@ -9,20 +9,11 @@ (modulesPath + "/profiles/qemu-guest.nix") ]; - boot.initrd.availableKernelModules = [ "ahci" "xhci_pci" "virtio_pci" "sr_mod" "virtio_blk" ]; - boot.initrd.kernelModules = [ ]; - boot.kernelModules = [ "kvm-amd" ]; - boot.extraModulePackages = [ ]; - - fileSystems."/" = { - device = "/dev/disk-by-uuid/d2a8fad0-373e-4bcf-8e75-d9b5ef94199c"; - fsType = "ext4"; - }; - - fileSystems."/boot" = { - device = "/dev/disk-by-uuid/5CF0-A66E"; - fsType = "vfat"; - options = [ "fmask=0077" "dmask=0077" ]; + boot = { + initrd.availableKernelModules = [ "ahci" "xhci_pci" "virtio_pci" "sr_mod" "virtio_blk" ]; + initrd.kernelModules = [ ]; + kernelModules = [ "kvm-amd" ]; + extraModulePackages = [ ]; }; swapDevices = [ ]; diff --git a/hosts/nixos/x86_64-linux/hotel/options-home.nix b/hosts/nixos/x86_64-linux/hotel/options-home.nix new file mode 100644 index 0000000..4fdd76d --- /dev/null +++ b/hosts/nixos/x86_64-linux/hotel/options-home.nix @@ -0,0 +1,2 @@ +_: +{ } diff --git a/hosts/nixos/x86_64-linux/hotel/options.nix b/hosts/nixos/x86_64-linux/hotel/options.nix new file mode 100644 index 0000000..4fdd76d --- /dev/null +++ b/hosts/nixos/x86_64-linux/hotel/options.nix @@ -0,0 +1,2 @@ +_: +{ } diff --git a/hosts/nixos/x86_64-linux/pyramid/default.nix b/hosts/nixos/x86_64-linux/pyramid/default.nix new file mode 100644 index 0000000..d5e9942 --- /dev/null +++ b/hosts/nixos/x86_64-linux/pyramid/default.nix @@ -0,0 +1,72 @@ +{ self, config, inputs, lib, minimal, ... }: +let + primaryUser = config.swarselsystems.mainUser; +in +{ + + imports = [ + inputs.nixos-hardware.nixosModules.framework-16-7040-amd + + ./disk-config.nix + ./hardware-configuration.nix + + "${self}/modules/nixos/optional/amdcpu.nix" + "${self}/modules/nixos/optional/amdgpu.nix" + "${self}/modules/nixos/optional/framework.nix" + "${self}/modules/nixos/optional/gaming.nix" + "${self}/modules/nixos/optional/hibernation.nix" + "${self}/modules/nixos/optional/nswitch-rcm.nix" + "${self}/modules/nixos/optional/virtualbox.nix" + "${self}/modules/nixos/optional/work.nix" + + ]; + + swarselsystems = { + lowResolution = "1280x800"; + highResolution = "2560x1600"; + isLaptop = true; + isNixos = true; + isBtrfs = true; + isLinux = true; + sharescreen = "eDP-2"; + info = "Framework Laptop 16, 7940HS, RX7700S, 64GB RAM"; + firewall = lib.mkForce true; + wallpaper = self + /files/wallpaper/lenovowp.png; + hasBluetooth = true; + hasFingerprint = true; + isImpermanence = false; + isSecureBoot = true; + isCrypted = true; + inherit (config.repo.secrets.local) hostName; + inherit (config.repo.secrets.local) fqdn; + hibernation.offset = 533760; + }; + + home-manager.users."${primaryUser}" = { + swarselsystems = { + isSecondaryGpu = true; + SecondaryGpuCard = "pci-0000_03_00_0"; + cpuCount = 16; + temperatureHwmon = { + isAbsolutePath = true; + path = "/sys/devices/virtual/thermal/thermal_zone0/"; + input-filename = "temp4_input"; + }; + monitors = { + main = { + # name = "BOE 0x0BC9 Unknown"; + name = "BOE 0x0BC9"; + mode = "2560x1600"; # TEMPLATE + scale = "1"; + position = "2560,0"; + workspace = "15:L"; + output = "eDP-2"; + }; + }; + }; + }; +} // lib.optionalAttrs (!minimal) { + swarselprofiles = { + personal = true; + }; +} diff --git a/hosts/nixos/nbl-imba-2/disk-config.nix b/hosts/nixos/x86_64-linux/pyramid/disk-config.nix similarity index 94% rename from hosts/nixos/nbl-imba-2/disk-config.nix rename to hosts/nixos/x86_64-linux/pyramid/disk-config.nix index 5e82f71..9a5bd69 100644 --- a/hosts/nixos/nbl-imba-2/disk-config.nix +++ b/hosts/nixos/x86_64-linux/pyramid/disk-config.nix @@ -72,6 +72,9 @@ }; }; - fileSystems."/persist".neededForBoot = true; - fileSystems."/var/log".neededForBoot = true; + fileSystems = { + "/persist".neededForBoot = true; + "/home".neededForBoot = true; + "/var/log".neededForBoot = true; + }; } diff --git a/hosts/nixos/x86_64-linux/pyramid/hardware-configuration.nix b/hosts/nixos/x86_64-linux/pyramid/hardware-configuration.nix new file mode 100644 index 0000000..8e4d75a --- /dev/null +++ b/hosts/nixos/x86_64-linux/pyramid/hardware-configuration.nix @@ -0,0 +1,71 @@ +{ config, lib, pkgs, modulesPath, ... }: +{ + imports = + [ + (modulesPath + "/installer/scan/not-detected.nix") + ]; + + # Fix Wlan after suspend or Hibernate + # environment.etc."systemd/system-sleep/fix-wifi.sh".source = + # pkgs.writeShellScript "fix-wifi.sh" '' + # case $1/$2 in + # pre/*) + # ${pkgs.kmod}/bin/modprobe -r mt7921e mt792x_lib mt76 + # echo 1 > /sys/bus/pci/devices/0000:04:00.0/remove + # ;; + + # post/*) + # ${pkgs.kmod}/bin/modprobe mt7921e + # echo 1 > /sys/bus/pci/rescan + # ;; + # esac + # ''; + + boot = { + kernelPackages = lib.mkDefault pkgs.kernel.linuxPackages; + # kernelPackages = lib.mkDefault pkgs.linuxPackages_latest; + binfmt.emulatedSystems = [ "aarch64-linux" ]; + initrd = { + availableKernelModules = [ "nvme" "xhci_pci" "thunderbolt" "usb_storage" "cryptd" "usbhid" "sd_mod" "r8152" ]; + # allow to remote build on arm (needed for moonside) + kernelModules = [ "sg" ]; + luks.devices."cryptroot" = { + # improve performance on ssds + bypassWorkqueues = true; + preLVM = true; + # crypttabExtraOpts = ["fido2-device=auto"]; + }; + }; + + kernelModules = [ "kvm-amd" ]; + kernelParams = [ + # deep sleep is discontinued by amd + # "mem_sleep_default=deep" + # supposedly, this helps save power on laptops + # in reality (at least on this model), this just generate excessive heat on the CPUs + # "amd_pstate=passive" + + # Fix screen flickering issue at the cost of battery life (disable PSR and PSR-SU, keep PR enabled) + # TODO: figure out if this is worth it + # test PSR/PR state with 'sudo grep '' /sys/kernel/debug/dri/0000*/eDP-2/*_capability' + # ref: + # https://old.reddit.com/r/framework/comments/1goh7hc/anyone_else_get_this_screen_flickering_issue/ + # https://www.reddit.com/r/NixOS/comments/1hjruq1/graphics_corruption_on_kernel_6125_and_up/ + # https://gitlab.freedesktop.org/drm/amd/-/issues/3797 + "amdgpu.dcdebugmask=0x410" + ]; + + extraModulePackages = [ ]; + }; + + # Enables DHCP on each ethernet and wireless interface. In case of scripted networking + # (the default) this is the recommended approach. When using systemd-networkd it's + # still possible to use this option, but it's recommended to use it in conjunction + # with explicit per-interface declarations with `networking.interfaces..useDHCP`. + networking.useDHCP = lib.mkDefault true; + # networking.interfaces.enp196s0f3u1c2.useDHCP = lib.mkDefault true; + # networking.interfaces.wlp4s0.useDHCP = lib.mkDefault true; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/hosts/nixos/x86_64-linux/pyramid/secrets/pii.nix.enc b/hosts/nixos/x86_64-linux/pyramid/secrets/pii.nix.enc new file mode 100644 index 0000000..8545d57 --- /dev/null +++ b/hosts/nixos/x86_64-linux/pyramid/secrets/pii.nix.enc @@ -0,0 +1,26 @@ +{ + "data": "ENC[AES256_GCM,data:8y8t7e8XhVy3lc+JcPnFFzI7DTpr+JlXfOKZJu7uX7DczTYQHIZQTrMcFjyBbB8SWJLWLUG8Yd5JGXk377CBX73cxGF+r895lxP+puoKRRzDapkg6y2uN0E3Gr1wnQFB4I8YX7n8UWnj18s3mTIohQHmhoxkuIqu2zvgEGBpMiz3oZIL4zmb8diLXh4PyB1qAI5U5RFWPpkwRWjXteD5m8mqcZ8k4A4l00IMgz2n9MJDQPMjYNITR3XbOlI1qNMYBVb3xuVLXBOBN6x5W4539kGAiHcAi8pOUvBjAXphOEGQ7uLoorAniHx2PPyqReDr5tx47h4RtKJGeGoJ6ZdaFS2LwD10Dkiac330ELLGpSuHoNn7cfw6P8xSyYfreIXbzgavZAlJ1t3fNjEwVtgz63bXL1IX326fP1WcFqBUgAMd8I+VZsxo15j92zZS8gUbdu4KdSMag4dlOa9rgJCLpZGw4UIifHn6RqbH8s/HdisWV2YA3p1/Oowp39Hnr1ZeUecHQCpC2Y/nVLZid9wy4NcIPDbkeb33vMzJ/G5o4EVeYcrnM4J7+KS7aJ4c2bbkRixc1w0bTYeQHFgvM9VBHHEO30t68AGEzju29XeMVi7bzamJZeApPEacMVzzCXlRiAWtPru9JtBYz17VXliMBiEc5Ffo12PXPV7VK/BimKBppJAGNSJiWg/fXawRJNs/fJkLywEL88cf3RYP0Wdy01umjU9tW7Y0W1zc46auKy8KPpCcT0e6kBGmlG2WJje3dNYDFUutFTllV+N7VeDOuZi4oaGrwF1Rz8cAKPrZWMyLX3bMc4EkP7t7h0DoTyXvl3CcA9/wgeCQrLIPLnUTBDTF6jsyt32IjxfiMMBTtR5hLJeM5BzybuYHI2Jbbnt2Ko+tCWOUNdRR7rOYT7o+xzm7g3apcrKIKaufc5YUxdD9asc8uAx+9w7tkg7O/2Ak9qPVgE7HIu9m5O4qaEQn8I1P1GbwiHZeIrfiRzcf6+KgjsLU7i+gCCb3EtMZJUS1CFmlyA+akgsFaunZFYLjg6vUmhQgTKhWooNj3DkdWXWN4bOB/lUyzsCezAD+HfPYyy2pYETRtS/XlpBktSYhP2yLZSxEyjsKBH8roZ/LpNwJV3RuvM+CPstj/pxf23Ayi8LrU1t88Q+/mje1OsMCr67Ltbl+7HXNcpM8zwLUfmTt72YZd1CnoAvbqM3pfecLM1AZEeR+p+xq8tsl1tRE2V0y/SH9kew4UOYRY/eZHmiy8P8Eyjj6/PL+/9+CLU9KGeK/28hGz1u1Ao03FxcPL1AeAeA1mlCNAErT/Q4GUKdDNa5uTHpU86VrMoELtvVaVn3V4AS5I+kTfvI9WF8oaI20U2ysAMpJSiPJyC5AVteyehXAEdGY7bgltvity8arU8efxwmrjbZ29ZWwRezqf1kZLb7pySCfsoqYwCFFDx4s7hD4RF1N4X9GQA5JupUO/+UZTcVX4aud+yf6uTb9yRC5LGjXJj5S03DQ+Vj35nZMUn6xhbPPnEj0uS9yug685mQm/bwUVHIEyoBZfPZquSSh1oolKsKnAPS2+fS13dr2sNuHktq40sJTTglz97ZexoIbZ7Ftx3tzFtqFMhh11EBV4eb0MCu9zwaq5DMoLugXECSkUy6Nfc9XGdRU/x3iIha36jg0wj9MwKNpztNFJzzWSVd8XU5rILbr9yWs4xZKBZq6PFx3NEXCIsJ0kkfc1FUBlnsiYG52A/zcFQZmUAPDy58M4rzLnWjC+qk7jU01Yw6aOcFqqE5kg9+AvYmF8JQ16s17d4o49I/fmL0MYVbSgdXrJZF9ejrkBkIMfu7UgbBlQdJCSW8BFx6zFmg2Y22bh52q8+//PK1rgUKs9RAsAasl8WKrKo+xNgai+1M9eMxg+wsBIP+j4WutMHXPv3AMeqt+JwIPiydPwny49820Z24h49pXPVK0EXTqZl46b7bUvyZqAbDTTDmjb/gOJII/ho6/EeaEUSk/r1NVUehq5S/e/UJagTDI3csmBgEcMYdk5CfoJt0cDeqHgrAo8U8xpURT5BAbeCHwWpI7sE47LZwHStf9WbHyacCGsob+ELvfMvunaY2YmqnlVaYulf0mgmn5YmBI8ouQ2Zc4eklzso+NN6e9j7ODhxPxF/MWKjoi/kpF8eBiEKEbPk0drOS4PcOFEDvbA7fFrwiwUnTqG2+FVBTgyidxDYX70jX5asox5wBc4WAgPXU0WNNb5I2bbenUoGKbDrZ989FblN5I3xnP5kxFq25evPtEvA5R9mwBYtBnd3UBBnDzcsI6gA7o73VW7Y25gfX5ODTRbMjxGYBU+xnNK+B9IOeMGTmFjuqchrlyaSOQ9T2Wx4kNyVUwWRMw/eZPkP6LtEQLVM8iotO6BNcPVqx6dCU4nh19IbjbfyrO0I5ZqSV/PVCRx2Pomceu0EfMpVReFvlIi/UyKROzLuOy6AY1RlthR8gM39l6a6l+WZeukkn+SoAEXeyw4U83K2H9WR6hYcgX0SPGVYfI3C83I0EChET30kiX/rb/fFtb8xdQogA4+R/vR3mPBaGMiWh0WDZVDhNy5/DlwYPYp1zDxtVjQffEhqWS5FqRdw5BsQJQc9glptU5QCgY/ITYwGlaW4OYWokFQWinH0JF9bcCjjjZMT9C52N9ZuZ0muxTT2/UxyhKhX7Eojxq6sz0HJ+TISa5FpUKx/W7I+XqT25n3PtKfnkRDDba+RxDy3bCYo60aOPfR9aCG0VbGLWgc4TQHCmC209rSSIlsD2DhBzFC2lCxasXHIgNAymGfbpOjvqdId9ev1XN0EEd0al4HBUvvGsq9FUeshAWMeWDKu1t0aDKJ6/c4bphThjoAqxtQaGPUFOhNw94PedCBgiRqXN02WZcrnqp/spj+uIfch1F/X5A3jTUev8vq/s7lge7h3CNWXNpBFrW5trdzE8N2Kw3AahsJfZCo/Qd9e6WHIDRgbZFEbKwkTIyeEW8rMv5Ls0Aq+kFvs76muJVnr+Pb7e/GabhgT3pPhYNLQWjPRQYkF2KDKrGUlrc2BkJqRLF3fhI7vQPFphWPl0Lj5idYglIn5v2P2HR9n3Z1+9oyIpmFsqjqILCdoMCDleQOb4DCzXnR5QE4LKg/jjJqqGyO4mAbpwdvN9Q4j1FOUsJNOgMNBUUdEr7n65ktKnJX5wX9cymosRUozgoteb2dblFJjY/pf8toH5kU+YIYmbQR0caw8tdpBl0ETcsaQpF3LbCsSfmN8tZyxS4R/0W782i08IsaN9uXEevlsyFgMg7I2q739fHqJ7kFeosXpKdUpOnmuoLu1A7,iv:9SAQXPwrhy5yjkNxn1lITD77MjqdrYOSlFpUBE8a/fY=,tag:tYApnwq2auUk+/N9alPX3w==,type:str]", + "sops": { + "age": [ + { + "recipient": "age16lnmuuxfuxxtty3atnhut8wseppwnhp7rdhmxqd5tdvs9qnjffjq42sqyy", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBjb21CZ0tQZlNKZkxKMGEz\nUlpMV3lSa1h5TXFNaEpvbWp3ZzZsMUFLd2hnCm9xQlo5Q3RsdW1tSFMxZjVKbjhM\nLzBaS3E1Z0lSQ2lQZEhtclBocE9CcXMKLS0tIHpaYjFIVVRWc2QyQ3hDWmNPODJR\nOFpPQlcwOERMYzhWV3J4ZmpIVUFXcGMKq/CmiIaBFfcx9Muj5LaTQ//ELHmC6WSG\ncJWyfZfrKcPDlXrz7+o9qufLogw3VIkCsTghqsbK6HOKGC5/FbnGSg==\n-----END AGE ENCRYPTED FILE-----\n" + }, + { + "recipient": "age18quey88vge7xytclg2nuq4ncme86dg04lxwczqxczmdchnjg3p0saehsnh", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA0Z2tONmQxTUhZUW12Z2Jm\nUnoxSnpYcnZDNGNzSko1ckl2RDh3NG1VS2dFCmIwUXhmSk1OUk02S0JPVDR5UWJ4\na0gwWlg0V005ZWxYa29PZ0laS2VqM0kKLS0tIHN5SU9pQ090eHljeXJGWm5hRFQ4\nZ001Nzkyb29RYkNUMDNDNlo4YnVQeTQK34bNIBgxId2+DHKQNVV3Iro3KGkE03Sp\niB1+dADT6nRvGvoyPqnLq/NYfw7eQ6XqYt55zkdCta8v6L1UNUkw8g==\n-----END AGE ENCRYPTED FILE-----\n" + } + ], + "lastmodified": "2025-10-21T19:32:24Z", + "mac": "ENC[AES256_GCM,data:wM862FQH/qX/abuD+krJOazli9Ci5GrpLtdcnzFgKCeNdjA2cfZ8M3DyzsBwMXjp6HxBHLyO7QXGcQkx3kIKGnRhEBuQzVOtrZhqcDi2Ho8iBV8Dh4xkhcpBYufw7xP8hGWg6ZVZ4JyM3P4NfAdxbfWTdc1VMStAafJ2SZ3pAYI=,iv:tDAKNe8LV40hRCqKzN6j6B71IV81SnrBgerxGPzU4Zk=,tag:7ZsST8pl9TjMog0dNKcUcA==,type:str]", + "pgp": [ + { + "created_at": "2025-06-14T22:31:01Z", + "enc": "-----BEGIN PGP MESSAGE-----\n\nhQIMAwDh3VI7VctTARAA3TBZeXf6RLph9szeqCtmoXyXDMS1l7NRjhmM85YyxcRo\nTuJQrXA8gmIAen7iVjO/FnndAqd86ddCirpBr/aEKtB9v7Poxx6A/kubV2/EurY7\ngbjWsvY/x6Cqv8IMCTkVdolZNOIYlw4bK3RqERoeWXnvCEXVK2c8fqxmcVoNv6yR\n5leIyApzs7dihbdhK+8nTunIMFJSfP+HQY/wgyowgp3cFVjPe+eTUk8T1xkrir7+\ngfddOHNKnbQWpZRBVj2NE/0dwcKX/rxPHU1sCxOg1TW05jTxavsf8x1+2ST5VLI8\nvttzB8H58OMpDZ1xgoMN7SGSWdTN7BgNcLG4rsGb/GW4+2bxJQ3hS+4aTa59ugXG\nGpqY4ooUopRyOh/hE9xqZ4CXy7IEAGbiBKnwJH+CFlXNygPSURoz9wCH5sgqQ1eA\nGfHrXcGNe2flx9gHZ3g2FUKeORs45CFQLxn2HDSuzVqn9nZfWUFddk9v7G4jSsRg\ntVrSevOXTSFzaSQr5GTQocQILG8HHkg67gKXWMNnk5CiUMVojTljcCej1F5s4Lwg\nljTfTWJMUXfD3Djc2Ap/L+PfxO/Zr0Z5glAndSFQB7aijFaQOR+TVQznRNv90UOk\nwQdF6XANcFMiK3yKQ3xZ6d7lXNTCPlLi5ngakpXhMM1lP0/xFuMWB15IL4yA1FmF\nAgwDC9FRLmchgYQBEADAz9QQ92i1rObvnk3utRhxqizU1SIKhZHEzkdJ+M/9AUQl\nDqj4ge191QMWlEh9jo5ln1abxfVMEjDbomtniPsM5kxPw9qK20M2873ibkps0yNZ\nTdqI2hhB8qBtdEOD/gKq3M27/0c3O7rpsIv8kxxdnmZ9GlRjG9c+SmVqdmZ+PLcP\nOrC+Fq8kQKhINaYdpPoT6x85FW0YLvNiR72grHOKDofqBrFChxapf4HKK6T44TX4\nPKw9G2o/XtN9Z1sfh/R44XsNwTjG8EHrwQLsFYoH3+L7UoNkkNtcwleAl0tkjyVZ\nkq4g0nJKO0KbB1HAM0opamYKOsCUaXQ1MLbXKAmIKy1wuKJR9ibH7E+2Ne41fHJv\n0v243FBnebJP5wlrDY6aBNBX5lPeJBF2q9njp2OnkHWktQD47EyhPhI0hUxN3vzL\n0dSE9/LFgWtvzXqVWIYBWMHToBBiqJRgspw3Jf4Fg0l7Q9p7u2/rwgqbIWMLIDt+\n4tn0ySuiV9jV9dVG3Ho/X7owgr57PPetTvUcU6Ph8Yiv6riLZ+qBy636iGmQd9Zz\n/8nG0BRAnU0YOdWUtvOvBvI+JC5DIs2Trj7Th0AJvlAVLiiR1+0dKk+BdNo/LGE5\nRNNgJIwGHMOZXJonuYfYe15Qy+Qcx3J/NI9VOOfSmzl7A4s8NqtuAt8FNm1cDNJc\nAZp7gi3i3PxxsEXefNMtbFDLe+5yQ4lHro47BxnNAyvnYwKC/VAiwatow9kZGNWn\nc9J/PZinOYPfalwqOl0Zn+pem0hIestNplin7v6ynxa23Cg4g1xUou0ve14=\n=UG0o\n-----END PGP MESSAGE-----", + "fp": "4BE7925262289B476DBBC17B76FD3810215AE097" + } + ], + "unencrypted_suffix": "_unencrypted", + "version": "3.11.0" + } +} diff --git a/hosts/nixos/x86_64-linux/summers/default.nix b/hosts/nixos/x86_64-linux/summers/default.nix new file mode 100644 index 0000000..347a7d0 --- /dev/null +++ b/hosts/nixos/x86_64-linux/summers/default.nix @@ -0,0 +1,99 @@ +{ self, inputs, lib, config, minimal, nodes, globals, ... }: +{ + + imports = [ + ./hardware-configuration.nix + ./disk-config.nix + + "${self}/modules/nixos/optional/microvm-host.nix" + ]; + + boot = { + loader.systemd-boot.enable = true; + loader.efi.canTouchEfiVariables = true; + }; + + swarselsystems = { + info = "ASUS Z10PA-D8, 2* Intel Xeon E5-2650 v4, 128GB RAM"; + flakePath = "/root/.dotfiles"; + isImpermanence = true; + isSecureBoot = true; + isCrypted = true; + isBtrfs = true; + isLinux = true; + isNixos = true; + withMicroVMs = false; + }; + +} // lib.optionalAttrs (!minimal) { + + swarselprofiles = { + server = true; + }; + + swarselmodules = { + server = { + diskEncryption = lib.mkForce false; # TODO: disable + nfs = false; + nginx = false; + kavita = false; + restic = false; + jellyfin = false; + navidrome = false; + spotifyd = false; + mpd = false; + postgresql = false; + matrix = false; + nextcloud = false; + immich = false; + paperless = false; + transmission = false; + syncthing = false; + grafana = false; + emacs = false; + freshrss = false; + jenkins = false; + kanidm = false; + firefly-iii = false; + koillection = false; + radicale = false; + atuin = false; + forgejo = false; + ankisync = false; + homebox = false; + opkssh = false; + garage = false; + }; + }; + + microvm.vms = + let + mkMicrovm = guestName: { + ${guestName} = { + backend = "microvm"; + autostart = true; + modules = [ + ./guests/${guestName}.nix + { + node.secretsDir = ./secrets/${guestName}; + } + ]; + microvm = { + system = "x86_64-linux"; + # baseMac = config.repo.secrets.local.networking.interfaces.lan.mac; + # interfaces.vlan-services = { }; + }; + specialArgs = { + inherit (config) nodes globals; + inherit lib; + inherit inputs minimal; + }; + }; + }; + in + lib.mkIf (!minimal && config.swarselsystems.withMicroVMs) ( + { } + // mkMicrovm "guest1" + ); + +} diff --git a/hosts/nixos/x86_64-linux/summers/disk-config.nix b/hosts/nixos/x86_64-linux/summers/disk-config.nix new file mode 100644 index 0000000..a4b5089 --- /dev/null +++ b/hosts/nixos/x86_64-linux/summers/disk-config.nix @@ -0,0 +1,118 @@ +{ lib, config, ... }: +let + type = "btrfs"; + extraArgs = [ "-L" "nixos" "-f" ]; # force overwrite + subvolumes = { + "/root" = { + mountpoint = "/"; + mountOptions = [ + "subvol=root" + "compress=zstd" + "noatime" + ]; + }; + "/home" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/home"; + mountOptions = [ + "subvol=home" + "compress=zstd" + "noatime" + ]; + }; + "/persist" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/persist"; + mountOptions = [ + "subvol=persist" + "compress=zstd" + "noatime" + ]; + }; + "/log" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/var/log"; + mountOptions = [ + "subvol=log" + "compress=zstd" + "noatime" + ]; + }; + "/nix" = { + mountpoint = "/nix"; + mountOptions = [ + "subvol=nix" + "compress=zstd" + "noatime" + ]; + }; + "/swap" = lib.mkIf config.swarselsystems.isSwap { + mountpoint = "/.swapvol"; + swap.swapfile.size = config.swarselsystems.swapSize; + }; + }; +in +{ + disko.devices = { + disk = { + disk0 = { + type = "disk"; + device = config.swarselsystems.rootDisk; + content = { + type = "gpt"; + partitions = { + ESP = { + priority = 1; + name = "ESP"; + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "defaults" ]; + }; + }; + root = lib.mkIf (!config.swarselsystems.isCrypted) { + size = "100%"; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/disk/by-label/nixos" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + luks = lib.mkIf config.swarselsystems.isCrypted { + size = "100%"; + content = { + type = "luks"; + name = "cryptroot"; + passwordFile = "/tmp/disko-password"; # this is populated by bootstrap.sh + settings = { + allowDiscards = true; + # https://github.com/hmajid2301/dotfiles/blob/a0b511c79b11d9b4afe2a5e2b7eedb2af23e288f/systems/x86_64-linux/framework/disks.nix#L36 + crypttabExtraOpts = [ + "fido2-device=auto" + "token-timeout=10" + ]; + }; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/mapper/cryptroot" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + }; + }; + }; + }; + }; + }; + + fileSystems."/persist".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + fileSystems."/home".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; +} diff --git a/hosts/nixos/x86_64-linux/summers/guests/guest1/default.nix b/hosts/nixos/x86_64-linux/summers/guests/guest1/default.nix new file mode 100644 index 0000000..7363993 --- /dev/null +++ b/hosts/nixos/x86_64-linux/summers/guests/guest1/default.nix @@ -0,0 +1,22 @@ +{ self, lib, minimal, ... }: +{ + imports = [ + "${self}/modules/nixos/optional/microvm-guest.nix" + ]; + + swarselsystems = { + info = "ASUS Z10PA-D8, 2* Intel Xeon E5-2650 v4, 128GB RAM"; + }; + +} // lib.optionalAttrs (!minimal) { + + swarselprofiles = { + server = false; + }; + + microvm = { + mem = 1024 * 4; + vcpu = 2; + }; + +} diff --git a/hosts/nixos/x86_64-linux/summers/hardware-configuration.nix b/hosts/nixos/x86_64-linux/summers/hardware-configuration.nix new file mode 100644 index 0000000..bef7987 --- /dev/null +++ b/hosts/nixos/x86_64-linux/summers/hardware-configuration.nix @@ -0,0 +1,28 @@ +{ config, lib, modulesPath, ... }: + +{ + imports = + [ + (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot = { + initrd.availableKernelModules = [ "ahci" "xhci_pci" "usbhid" "usb_storage" "sd_mod" ]; + initrd.kernelModules = [ ]; + kernelModules = [ "kvm-intel" ]; + extraModulePackages = [ ]; + + supportedFilesystems = [ "zfs" ]; + zfs.extraPools = [ "Vault" ]; + }; + + # Enables DHCP on each ethernet and wireless interface. In case of scripted networking + # (the default) this is the recommended approach. When using systemd-networkd it's + # still possible to use this option, but it's recommended to use it in conjunction + # with explicit per-interface declarations with `networking.interfaces..useDHCP`. + networking.useDHCP = lib.mkDefault true; + # networking.interfaces.enp3s0.useDHCP = lib.mkDefault true; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/hosts/nixos/x86_64-linux/summers/secrets/guest1/pii.nix.enc b/hosts/nixos/x86_64-linux/summers/secrets/guest1/pii.nix.enc new file mode 100644 index 0000000..8605563 --- /dev/null +++ b/hosts/nixos/x86_64-linux/summers/secrets/guest1/pii.nix.enc @@ -0,0 +1,15 @@ +{ + "data": "ENC[AES256_GCM,data:pGWiWA==,iv:sVpYJiphhvVPEo2MUMnpjlJmvf58/UJTTVVdU9dpqzM=,tag:2AsQRCyN9Pc/hnqviCo43g==,type:str]", + "sops": { + "lastmodified": "2025-11-06T12:11:19Z", + "mac": "ENC[AES256_GCM,data:NBAgy3MNd+p8Ih6v/JuxuMWgh0k9xj5Trg7mggBE/LrxfCZg+BpbhYcmAw/FW9Du5gq3Pcynnql3dqwKlzHEtkEOcI1MJSnBSWexgLxwEtRwbTJVOqEkCxby6dcQ4HWD1ZZnwa9Q7Cg1vcPD/yZuzVUH15mFHic7s5M5Xzdfu/w=,iv:tv8CFuXJ0iqh/Vho7vSoOpfhcGfCElMLWNvjxoE3fMg=,tag:pGP3CjKFFm0UuVgSCnn4RA==,type:str]", + "pgp": [ + { + "created_at": "2025-11-06T12:11:04Z", + "enc": "-----BEGIN PGP MESSAGE-----\n\nhQIMAwDh3VI7VctTARAAwZd6dmNcZqOWY7Ro6DXCRAD2LJuzR0AA26cRRzPgTPcw\nOwvV+Nh3hBWcZb5qkjKysZKGlIxzs4f02dKI172vUyIWQ6P5skygOOOpbr9g5171\nY0XTrmemesSKNfoUhsMFMCbFUc4HUxkUK7zadLk1AiBUqZMIFtx/riFMUBS2qTpR\nuLWiebt1Dw+rwcR8rBNxXPbeclm7322YOQDLUk4sHfi0vTvn+3sfGkbJ+OcJckoD\ndjVhWFqGUAbbELoR8yHpb+Ps6RYjKRNFNros9Yx9zQ18512gxOpRSzm0MTkKFyrz\n1UYVcv4Oz4W/e4nh1z2/re5X3l/HFUzwBG6AUTrYVuRo580kkZvWYFxHT6R+goVC\n5dhkqZpowrGpDIE/C7hKLenFIcOl1Nw5wgJ4Y9EmfZzorUnjJqT1Et2b2GU0hxvY\nKny+fiDeCfNdLzJejSNNg1/whoVmHbw3Q2aBJP0NL3nmNvaykO8RSA8WmzvQa+MA\nXweflh5G9lXOdH2vwb6EelOXpxlTjI7K/43Nbw/SXf/e1FKYK5l6TscyGEcHpFux\ns4ufYkCqTgxdKZjKwh0vqbdmbPUOCe/jqBOz6s/L/sR1/+8c2iIs0JVZd1VJSvDu\nIdfDfQh4wmso8L0qpjWimmkf0Y9itLWZo/oyioIqjVQ9+Daj2mvMkbKcSa486b2F\nAgwDC9FRLmchgYQBD/9lVmkHkPz5pbJV5U0nL3h/xx0JSyt6YYtLDacW8fw135GT\nojHijHvJAd1MqbNv391LcsZ1jtnUawNf6GAkr649lRuEH/WhNitXq20Z/06v5lwt\nGDhPMMf5uh+Uwgjxbeg/PFeTKILS2VX0tjJ8yeos2jNMOrmmwIg74V6mJk03E85K\nId06e2qNjzWlESyWOCFkfLQfSOTajQWmGyil8vNglmjuZdzLSE8eL6nA0hePnfJW\nOwewWcXEzHeeJsaevKFBBDpimAqi3XbKasQbZNSSFlkmw0vzAWKw5mzcdTMseae1\nLafjem7uw2epr4HIhwCZ47pCFrKcbweZMuUY557SomIGmv93OvglnZC40AYkJuNU\nIAVwNc8W/pd+jyiHh6tMlXfQ5/n25AcylDcacxxalNcKI0emNC90TsFc6wDpLh5D\n+R6kJ7GK8tI5BwIwtGIQmFsRREKE1x+IYATtKwQskb0Rng/D6eqNEvs8pjD1nGO3\nfNTG9G8PgC07TXSKGcNGytZy/GNSW9mnFgDgoiqh29bgfoJfSTWWvwZlzFXdWm0c\nzOiV5JSDRLewaqzhsQ/etms7qJIccRD7WcvM82x7UF0VYGd92EVsZxsq2aSVlMob\nCsxNXxij3qqNHdFgUuYYDzFym3/zmmi2wltPOZl7qYMhZI9P6wCsvDpxlFv16tJc\nAaBkBf1oOnjDvJm5i62KCEcRUmphKOB6Odr9/VHkAtgjPdWCOyge7ktbcwgsPw8L\ndemiSrNAglDX9RnPST5ggShZWn1Ik2mFfocCapvGBi5Hj9I/4xG/oIKREYc=\n=Ty0h\n-----END PGP MESSAGE-----", + "fp": "4BE7925262289B476DBBC17B76FD3810215AE097" + } + ], + "version": "3.11.0" + } +} diff --git a/hosts/nixos/x86_64-linux/summers/secrets/pii.nix.enc b/hosts/nixos/x86_64-linux/summers/secrets/pii.nix.enc new file mode 100644 index 0000000..c7afa8c --- /dev/null +++ b/hosts/nixos/x86_64-linux/summers/secrets/pii.nix.enc @@ -0,0 +1,26 @@ +{ + "data": "ENC[AES256_GCM,data:umKGtD7jTa+ex3ADPs1zR2o9YU2j3y3zCEupCGOsdJyicM7u0efXDI0g755RdPeNJiB/z1DPy+mAkePPq/m93CCppTq0BYyt0JJw53/j3ghCMJj7N3wUVstMUB01jewDSUc7SLay0lkhMCWbrTKsR1pwnfFRAG8C3rWXQB2EkU9FViCo8VaOfEF6Cq9ev/r+SEepT85wvoMxxIg=,iv:bgJXEoj7nRUsi4fA+bYVYvJYavS+BoDuQt2SCrX/2W8=,tag:lmOjPU0J0Qf/vcnO0owTZg==,type:str]", + "sops": { + "age": [ + { + "recipient": "age1h72072slm2pthn9m2qwjsyy2dsazc6hz97kpzh4gksvv0r2jqecqul8w63", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBET1RmRTM5OUxJMGNyWUZK\nMXFqUWF2ZHhOZ1pxa0RDbkNzWnVzVFFCbTJrCm1oU25haDl5eFg5T1VzOXByai84\ndTR6TGREVnBHNlV4S254dzh2Z1lvK2sKLS0tIGFLaWJFQ2VwaWtxaURqNDU2ekRQ\na09Hbm4vNnVQaEV1aGtqTTVOUWN2b28KQaoPc/UKaeQ72GdlbtWFdALywHcUkewf\nK5pEz41pzDKOjatypm9X8ZEIEarjOHIZgMpazVM4i1PRUUefSE0phw==\n-----END AGE ENCRYPTED FILE-----\n" + }, + { + "recipient": "age18quey88vge7xytclg2nuq4ncme86dg04lxwczqxczmdchnjg3p0saehsnh", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBNeGtTZ0ZSV0trWlQrS2dV\nSFo0dytGYXhRTjl6cDZrUU0wZ1IybDVRaFZrCmZmRmxJNmdwS0xodHdEOGU4bldU\nR1JScHAvZHhlVTBJbWExb0VpR0h2MXMKLS0tIDYwQmZpMjdYRmpBeXFNOXArN0h5\nVGN1THljeCtVV0hXenMyRVJkMjlHNEEKm+yZTT48nYr3H0Bd1OKw/CYk1kwnrBzk\nTgSQHsGXhmOyDag9cSZ4wAOmqtqSjA9bouFBuhl2lSbgpjnarvFaXQ==\n-----END AGE ENCRYPTED FILE-----\n" + } + ], + "lastmodified": "2025-11-10T01:10:33Z", + "mac": "ENC[AES256_GCM,data:4vPX9TdAGGBwzEc3W6pQj+BVKjp2kSAMB/L3QVXZbDHfvyKFWUOqwG8u8P7XDcuIrrpx65YuJp6zwexpJjg5zkU4favJt+uHD1wWC3TZcCpda6v3hGW3RduQAwVy+18JJ+PdSxHzrC4jmj+t/HIKp6Bt7qB0Z1ynrt/CdGIVxh0=,iv:zQQrl19jK823UynE3EXLgazehpWW5ltRCWKdnElVh5k=,tag:zIIgbyXSw6f6xW2CaVW88g==,type:str]", + "pgp": [ + { + "created_at": "2025-08-24T23:36:17Z", + "enc": "-----BEGIN PGP MESSAGE-----\n\nhQIMAwDh3VI7VctTARAAwf7TLx0TR1HBhh57CyIQLw8ztc9oblKAW/V7bSlQM/wR\nIwQTcTi3azdI9yewDRO30rIr++FEapdGVdpXoqQ8zcl49VjwDux6wzF3bsmR5Goc\nlTkDd0bmz8RBfsK+6efXiRqo3C0yP2ZTOh3PSOvsXKbYS6wY3TvNBdGnAYrfOvEw\nmBFRhn6uakw3zjVUngB1di07DH3y0wEb/r6+Mzoswzg4DqT1SAdDkfS9dpn9h3MW\n3NBesYlOukLrNA5Toi6x/fmE2lrPHt5QxPdvfvKe5ye4myZ/gBn1mdejB6U9nOsk\nRCJFMosjBH7jIpwokTjUT6Vs+zs8yrF+gbP82H4RVfZymMfdZoU/pTfYe1Mwg6Yi\ntlHyiRBgSPBY8Doa2hM8/yvmfHVMqSQf8uXltz2VC7JUGD6P0QbDLpqY3URmHg/q\nwN3zYJLlSIkU6Z7oivTjfg0dR32Z80lCdZDQf+OQsRtCUi169Fgxr7+HhdxJyj49\nFIb6CR0DHW4vsEj1GPAa0Q4uMfCxLiSZfesY8myoCtlVo7oeqx787KicJB5PryHr\nyZweKd7tXO9g8LNJtECTZ81y2/sCfSZPBia6M4oz56pIFK4jhYCY3iPnWIS77axu\n5MmqZNOP06obp87nt1ea51BmXkaYxmSPoQ5R29CeYU+m9q+kKvizncgsCl/O7U6F\nAgwDC9FRLmchgYQBEADJo2kPzrxLHptsr6aoIxfYNrQ7JJM3FAZ7do5YvAbQsl5t\ny45qZ4+qWIEMRXwji2TvgSg8/ylnZfN2+rTHdtNJkDdJ2sX+RDr8pm7L3VS2Zhjf\nIp1SdPd5cm/3QupegzUR+kcPa+gPM4asGSytIkAnnpev/DCnLsrqiejdosTDj9dn\nFtPKJKSUBzJSNRxBSpM9L+cTU1qyMT024D5Qvq6vBOjFI1YV3LSfVXQe7OZxxxVX\naChkGR1v3UjndQ4Yv9hamJJ81lRLeIcVEOpOPxLHJX76AJUqP3fR/+m2Poah8bFF\n+yIdSp2jyWOoU60We72fvlEwxsTLl8Zani+xX2ckkUCe+wsiGJLch4Df1pepxpef\nb95wZ9L0msRdHY8vRQYapde/ju8CUHgywVX7+YH3EF1bJSnUOBmyOA76v9ir09am\n49g+VomkWUuzPJ2VYQXXH6d/qn/sm9Z9yxy7e1eh5m+9cd42b4sMdW6ZCTMAtGJF\nPX0SiOMR6S0hjKVBcfcyNoT/wo7wqEl4mYDpoCy10K0nYRn+ggJnIZEJzBWibMYH\nDWUDyuQIYLjOBAchFatXyMtbc8qDorYelLX7amPRDSiDhhj6Y5nYMJtUSwfTLwkN\nrI0Q4bjE+fgNACCqPoq/BDFZotcr1b664ZUJqgnTBPKZ5OnmW/iFkOfzu4fF9tJe\nAcekEPwsFbugu2bZ0Hs5Rl/Dh9p4L9gceuMiwJ3oYGA5cwXFCeVZLNqSDLy4upVX\nnXRaMzBNGgWo4geDq5JL10Mh7/1d4GGVxdts8RGdI8zUFTPV3GOaPEHeNyIO+g==\n=2UMI\n-----END PGP MESSAGE-----", + "fp": "4BE7925262289B476DBBC17B76FD3810215AE097" + } + ], + "unencrypted_suffix": "_unencrypted", + "version": "3.11.0" + } +} diff --git a/hosts/nixos/x86_64-linux/toto/default.nix b/hosts/nixos/x86_64-linux/toto/default.nix new file mode 100644 index 0000000..3d02f5b --- /dev/null +++ b/hosts/nixos/x86_64-linux/toto/default.nix @@ -0,0 +1,42 @@ +{ self, lib, ... }: +{ + + imports = [ + ./disk-config.nix + ./hardware-configuration.nix + ]; + + networking = { + hostName = "toto"; + firewall.enable = false; + }; + + swarselprofiles = { + minimal = lib.mkForce true; + }; + + swarselmodules = { + server = { + network = lib.mkForce false; + diskEncryption = lib.mkForce false; + }; + }; + + swarselsystems = { + info = "~SwarselSystems~ remote install helper"; + wallpaper = self + /files/wallpaper/lenovowp.png; + isImpermanence = true; + isCrypted = true; + isSecureBoot = false; + isSwap = true; + swapSize = "2G"; + # rootDisk = "/dev/nvme0n1"; + rootDisk = "/dev/vda"; + # rootDisk = "/dev/vda"; + isBtrfs = true; + isLinux = true; + isLaptop = false; + isNixos = true; + }; + +} diff --git a/hosts/nixos/x86_64-linux/toto/disk-config.nix b/hosts/nixos/x86_64-linux/toto/disk-config.nix new file mode 100644 index 0000000..71838fc --- /dev/null +++ b/hosts/nixos/x86_64-linux/toto/disk-config.nix @@ -0,0 +1,127 @@ +# NOTE: ... is needed because dikso passes diskoFile +{ lib +, pkgs +, config +, ... +}: +let + type = "btrfs"; + extraArgs = [ "-L" "nixos" "-f" ]; # force overwrite + subvolumes = { + "/root" = { + mountpoint = "/"; + mountOptions = [ + "subvol=root" + "compress=zstd" + "noatime" + ]; + }; + "/home" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/home"; + mountOptions = [ + "subvol=home" + "compress=zstd" + "noatime" + ]; + }; + "/persist" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/persist"; + mountOptions = [ + "subvol=persist" + "compress=zstd" + "noatime" + ]; + }; + "/log" = lib.mkIf config.swarselsystems.isImpermanence { + mountpoint = "/var/log"; + mountOptions = [ + "subvol=log" + "compress=zstd" + "noatime" + ]; + }; + "/nix" = { + mountpoint = "/nix"; + mountOptions = [ + "subvol=nix" + "compress=zstd" + "noatime" + ]; + }; + "/swap" = lib.mkIf config.swarselsystems.isSwap { + mountpoint = "/.swapvol"; + swap.swapfile.size = config.swarselsystems.swapSize; + }; + }; +in +{ + disko.devices = { + disk = { + disk0 = { + type = "disk"; + device = config.swarselsystems.rootDisk; + content = { + type = "gpt"; + partitions = { + ESP = { + priority = 1; + name = "ESP"; + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "defaults" ]; + }; + }; + root = lib.mkIf (!config.swarselsystems.isCrypted) { + size = "100%"; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/disk/by-label/nixos" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + luks = lib.mkIf config.swarselsystems.isCrypted { + size = "100%"; + content = { + type = "luks"; + name = "cryptroot"; + passwordFile = "/tmp/disko-password"; # this is populated by bootstrap.sh + settings = { + allowDiscards = true; + # https://github.com/hmajid2301/dotfiles/blob/a0b511c79b11d9b4afe2a5e2b7eedb2af23e288f/systems/x86_64-linux/framework/disks.nix#L36 + crypttabExtraOpts = [ + "fido2-device=auto" + "token-timeout=10" + ]; + }; + content = { + inherit type subvolumes extraArgs; + postCreateHook = lib.mkIf config.swarselsystems.isImpermanence '' + MNTPOINT=$(mktemp -d) + mount "/dev/mapper/cryptroot" "$MNTPOINT" -o subvolid=5 + trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT + btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank + ''; + }; + }; + }; + }; + }; + }; + }; + }; + + fileSystems."/persist".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + fileSystems."/home".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true; + + environment.systemPackages = [ + pkgs.yubikey-manager + ]; +} diff --git a/hosts/nixos/toto/hardware-configuration.nix b/hosts/nixos/x86_64-linux/toto/hardware-configuration.nix similarity index 79% rename from hosts/nixos/toto/hardware-configuration.nix rename to hosts/nixos/x86_64-linux/toto/hardware-configuration.nix index 8f857fc..3a8c56a 100644 --- a/hosts/nixos/toto/hardware-configuration.nix +++ b/hosts/nixos/x86_64-linux/toto/hardware-configuration.nix @@ -9,10 +9,12 @@ (modulesPath + "/profiles/qemu-guest.nix") ]; - boot.initrd.availableKernelModules = [ "ahci" "xhci_pci" "virtio_pci" "sr_mod" "virtio_blk" ]; - boot.initrd.kernelModules = [ ]; - boot.kernelModules = [ "kvm-amd" ]; - boot.extraModulePackages = [ ]; + boot = { + initrd.availableKernelModules = [ "ahci" "xhci_pci" "virtio_pci" "sr_mod" "virtio_blk" ]; + initrd.kernelModules = [ ]; + kernelModules = [ "kvm-amd" ]; + extraModulePackages = [ ]; + }; # Enables DHCP on each ethernet and wireless interface. In case of scripted networking # (the default) this is the recommended approach. When using systemd-networkd it's diff --git a/hosts/nixos/x86_64-linux/winters/default.nix b/hosts/nixos/x86_64-linux/winters/default.nix new file mode 100644 index 0000000..2fb27c2 --- /dev/null +++ b/hosts/nixos/x86_64-linux/winters/default.nix @@ -0,0 +1,93 @@ +{ lib, minimal, ... }: +{ + + imports = [ + ./hardware-configuration.nix + ]; + + boot = { + loader.systemd-boot.enable = true; + loader.efi.canTouchEfiVariables = true; + }; + + # globals.hosts.${config.node.name}.ipv4 = config.repo.secrets.local.ipv4; + # globals.networks.home.hosts.${config.node.name} = { + # ipv4 = config.repo.secrets.local.home-ipv4; + # mac = config.repo.secrets.local.home-mac; + # }; + + swarselsystems = { + info = "ASRock J4105-ITX, 32GB RAM"; + flakePath = "/root/.dotfiles"; + isImpermanence = false; + isSecureBoot = false; + isCrypted = false; + isBtrfs = false; + isLinux = true; + isNixos = true; + proxyHost = "moonside"; + server = { + restic = { + bucketName = "SwarselWinters"; + paths = [ + "/Vault/data/paperless" + "/Vault/data/koillection" + "/Vault/data/postgresql" + "/Vault/data/firefly-iii" + "/Vault/data/radicale" + "/Vault/data/matrix-synapse" + "/Vault/Eternor/Paperless" + "/Vault/Eternor/Bilder" + "/Vault/Eternor/Immich" + ]; + }; + garage = { + data_dir = { + capacity = "200G"; + path = "/Vault/data/garage/data"; + }; + }; + }; + }; + +} // lib.optionalAttrs (!minimal) { + + swarselprofiles = { + server = true; + }; + + swarselmodules.server = { + diskEncryption = lib.mkForce false; + nfs = lib.mkDefault true; + nginx = lib.mkDefault true; + kavita = lib.mkDefault true; + restic = lib.mkDefault true; + jellyfin = lib.mkDefault true; + navidrome = lib.mkDefault true; + spotifyd = lib.mkDefault true; + mpd = lib.mkDefault true; + postgresql = lib.mkDefault true; + matrix = lib.mkDefault true; + nextcloud = lib.mkDefault true; + immich = lib.mkDefault true; + paperless = lib.mkDefault true; + transmission = lib.mkDefault true; + syncthing = lib.mkDefault true; + grafana = lib.mkDefault true; + emacs = lib.mkDefault true; + freshrss = lib.mkDefault true; + jenkins = lib.mkDefault false; + kanidm = lib.mkDefault true; + firefly-iii = lib.mkDefault true; + koillection = lib.mkDefault true; + radicale = lib.mkDefault true; + atuin = lib.mkDefault true; + forgejo = lib.mkDefault true; + ankisync = lib.mkDefault true; + # snipeit = lib.mkDefault false; + homebox = lib.mkDefault true; + opkssh = lib.mkDefault true; + garage = lib.mkDefault false; + }; + +} diff --git a/hosts/nixos/winters/hardware-configuration.nix b/hosts/nixos/x86_64-linux/winters/hardware-configuration.nix similarity index 54% rename from hosts/nixos/winters/hardware-configuration.nix rename to hosts/nixos/x86_64-linux/winters/hardware-configuration.nix index 9fbb76b..492d7d3 100644 --- a/hosts/nixos/winters/hardware-configuration.nix +++ b/hosts/nixos/x86_64-linux/winters/hardware-configuration.nix @@ -1,6 +1,3 @@ -# Do not modify this file! It was generated by ‘nixos-generate-config’ -# and may be overwritten by future invocations. Please make changes -# to /etc/nixos/configuration.nix instead. { config, lib, modulesPath, ... }: { @@ -9,25 +6,29 @@ (modulesPath + "/installer/scan/not-detected.nix") ]; - boot.initrd.availableKernelModules = [ "ahci" "xhci_pci" "usbhid" "usb_storage" "sd_mod" ]; - boot.initrd.kernelModules = [ ]; - boot.kernelModules = [ "kvm-intel" ]; - boot.extraModulePackages = [ ]; + boot = { + initrd.availableKernelModules = [ "ahci" "xhci_pci" "usbhid" "usb_storage" "sd_mod" ]; + initrd.kernelModules = [ ]; + kernelModules = [ "kvm-intel" ]; + extraModulePackages = [ ]; - boot.supportedFilesystems = [ "zfs" ]; - boot.zfs.extraPools = [ "Vault" ]; + supportedFilesystems = [ "zfs" ]; + zfs.extraPools = [ "Vault" ]; + }; - fileSystems."/" = - { - device = "/dev/disk/by-uuid/30e2f96a-b01d-4c27-9ebb-d5d7e9f0031f"; - fsType = "ext4"; - }; + fileSystems = { + "/" = + { + device = "/dev/disk/by-uuid/30e2f96a-b01d-4c27-9ebb-d5d7e9f0031f"; + fsType = "ext4"; + }; - fileSystems."/boot" = - { - device = "/dev/disk/by-uuid/F0D8-8BD1"; - fsType = "vfat"; - }; + "/boot" = + { + device = "/dev/disk/by-uuid/F0D8-8BD1"; + fsType = "vfat"; + }; + }; swapDevices = [{ device = "/dev/disk/by-uuid/a8eb6f3b-69bf-4160-90aa-9247abc108e0"; }]; diff --git a/hosts/nixos/x86_64-linux/winters/secrets/pii.nix.enc b/hosts/nixos/x86_64-linux/winters/secrets/pii.nix.enc new file mode 100644 index 0000000..1c519c5 --- /dev/null +++ b/hosts/nixos/x86_64-linux/winters/secrets/pii.nix.enc @@ -0,0 +1,26 @@ +{ + "data": "ENC[AES256_GCM,data:vevuVfscWMiD3Lzc/bAS+jAqpzgkfBfcFAB7ChacGaj/PJfoi5AzpmlkDhm11GBcvUXcveMnbLbQexaF3dgPVwvbD9xr6e+mcMJjIry5c5a5wOcZkyGxXgPuPg415An9AQrO56XeTTSaUL+ScQB3kv6eIyzCtxZag7pRLnOgwFuGYqfwcDIcX8QHCc0ijf3XLPaM6dEgiFYDeOMFhOF4+Z8/d9eHoEQ3tOkWTmkoVqZFz80ZicEraliWnWMvCBhRLKo3gb7KFRce/AAEZQaS3CZOJz7v7var4Ds1+PZnU282aSU/xsY5Dq1vOrsZuoYqXA5WrdC9HaXAYLGaGFCzLwRTAfJvigV4PNwOePskCSa/qRlOGpyO1t1B01Y4pghdERNlS+1ltEz8nKVfIi4DR6dKy8NIhLl3huJQy6KHsLrjDHnmxeypo2sJ+NeyuNTKqwJo9x3krcIBt8SaUoFIDkBgshcDCp2eBcKvRIOFIa8r3rsxQ7gwG3YV7hS+NR0nwsUXodGXVzrdehDNddr+mI4GEMl8TTP9sdVSaPhKpN+QB3GGGoYwX2HJYXdY9CKIIlYcgFiDfPz9x4HqGnGfSpeB6QgTK40pmRmG6jQyIFZiW+hQBS4XHtKQ8CJx4zUNpiUArYzustw6riPkfYDex21SzsUIjpRYxB8uGHFvJlJVgr4FkQQg6frebKf2EjIhjc9Mjdw+g7cGb5+WavUfy+fIXztYwRI0l8aftosfCMdGsSChntKCymz0kpGREx00HF5blA6oyifHaVxRYoqraxCwbe+p1RTFlGonaYtb0gBWpdrQU+24HVQU1rMhc8HFHPjcWofE/ymEPkhRzkxIXMmNQFi/18KvZWoy2qOVtPmsEc4mOVRtC6w9AZZpcxI9CXhhuyDZlJ/k4bJzkZFrcNW8I7OjEXTNmsYkzJDSVzD3Od/1zhubU8LYZBBXuejzeH0TXNsXbS6tQXCJ2D7Gzrcx8LpXL/a1IjAUmIXguVtPT9nGallXO9jHV9g7GGjF7weTaEMb/eNSuLgQOpq8vziN1XLWhVo0WEQ8zU97KSVJS5moaTEPAEUlHC4PfM3AQHpWMW4EL7FZu5r1yw+EDOUA4k9u9HIVbn5XVZbWb18aVVkYZoulLIVU7I74LJlYE/BSYhGzp6Ff1k6qzPNTbVgXEtiNuLQKa//8gHoQUCsu019MEVAU4LhZ+nt4genG4qFUTuBujTriO4Vhdel9Qsoq95FLXDzdwRInUzfUhbLli/rKv+LDW7wIdh/peWslq5XkWBeMqJC97OSGzM/MaWIzzMY68FjCJfYX6I2nskFD1xZiECKukn0LV/wqQhrkmUuyG6RsZGAZuOoStWJMs8v+x+ZIMHzg1jItXO2ozt8P73EvdgOExJi5/aSf8sQwX7H5lesDtnGYU5+xV9k6R8icsIqG/TLuFAiqK1hmFQv7H/9pFkRq1LUXFmJXoKDfDByG6xUjMeyYOwT6yLShhH3MMWvh3yjflwzGo7uTU1BTpNbKT0LEh3Q9C1txZ0uKROhWKu70iH+kHRFVlhUbyYpZovu3BPB3WDhLiLuXIOss5+dVv5RBSYUtxpzp7Oq7mbMRIGCY1hOVCiCcUEvcXXiQ8JBCklWUEEJ15BAIewetgDiVci4USgZZYrALplmSFkKTZbFjYEIrf3ghKFXfVTkMixRmzTHoxKpYXzvB3TZnkmAXVhvJbGEiHsAaHpcfycAXygQAWsIFYzYSDrqYXmRhwEy/A5cqy8dYx+UA3bBAi4v0QPMoro3UtdI2ipM=,iv:+QSRj/TyZl6xbwLDbuwb83RkBiLUi85VYcpss8Jn8fk=,tag:uPqu0GaUGmChLweOGN10yQ==,type:str]", + "sops": { + "age": [ + { + "recipient": "age1h72072slm2pthn9m2qwjsyy2dsazc6hz97kpzh4gksvv0r2jqecqul8w63", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBET1RmRTM5OUxJMGNyWUZK\nMXFqUWF2ZHhOZ1pxa0RDbkNzWnVzVFFCbTJrCm1oU25haDl5eFg5T1VzOXByai84\ndTR6TGREVnBHNlV4S254dzh2Z1lvK2sKLS0tIGFLaWJFQ2VwaWtxaURqNDU2ekRQ\na09Hbm4vNnVQaEV1aGtqTTVOUWN2b28KQaoPc/UKaeQ72GdlbtWFdALywHcUkewf\nK5pEz41pzDKOjatypm9X8ZEIEarjOHIZgMpazVM4i1PRUUefSE0phw==\n-----END AGE ENCRYPTED FILE-----\n" + }, + { + "recipient": "age18quey88vge7xytclg2nuq4ncme86dg04lxwczqxczmdchnjg3p0saehsnh", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBNeGtTZ0ZSV0trWlQrS2dV\nSFo0dytGYXhRTjl6cDZrUU0wZ1IybDVRaFZrCmZmRmxJNmdwS0xodHdEOGU4bldU\nR1JScHAvZHhlVTBJbWExb0VpR0h2MXMKLS0tIDYwQmZpMjdYRmpBeXFNOXArN0h5\nVGN1THljeCtVV0hXenMyRVJkMjlHNEEKm+yZTT48nYr3H0Bd1OKw/CYk1kwnrBzk\nTgSQHsGXhmOyDag9cSZ4wAOmqtqSjA9bouFBuhl2lSbgpjnarvFaXQ==\n-----END AGE ENCRYPTED FILE-----\n" + } + ], + "lastmodified": "2025-11-23T18:03:21Z", + "mac": "ENC[AES256_GCM,data:8KSKQH7qF2vLnR17a3XhYGAqYq4YNgf7XEkpeNVHD39Aj8MzdlsGPr9vI2o/N1yTpQyJrPW1ntKVvI9rHwcJhm5nyaQiHVwKHWcxcn7li6AeztV4HUqwKxQwf3MHfZ4fhWJrI7NYAuMAbmK6epa/ROGsIGnT6vQh3SImcn+Kkcg=,iv:dT8dBuSsYRxGe93/9ie/6/X4Ru5NDycz2pgMVI83wbc=,tag:r1mPjG/JOQsRDzCktIlisQ==,type:str]", + "pgp": [ + { + "created_at": "2025-08-24T23:36:17Z", + "enc": "-----BEGIN PGP MESSAGE-----\n\nhQIMAwDh3VI7VctTARAAwf7TLx0TR1HBhh57CyIQLw8ztc9oblKAW/V7bSlQM/wR\nIwQTcTi3azdI9yewDRO30rIr++FEapdGVdpXoqQ8zcl49VjwDux6wzF3bsmR5Goc\nlTkDd0bmz8RBfsK+6efXiRqo3C0yP2ZTOh3PSOvsXKbYS6wY3TvNBdGnAYrfOvEw\nmBFRhn6uakw3zjVUngB1di07DH3y0wEb/r6+Mzoswzg4DqT1SAdDkfS9dpn9h3MW\n3NBesYlOukLrNA5Toi6x/fmE2lrPHt5QxPdvfvKe5ye4myZ/gBn1mdejB6U9nOsk\nRCJFMosjBH7jIpwokTjUT6Vs+zs8yrF+gbP82H4RVfZymMfdZoU/pTfYe1Mwg6Yi\ntlHyiRBgSPBY8Doa2hM8/yvmfHVMqSQf8uXltz2VC7JUGD6P0QbDLpqY3URmHg/q\nwN3zYJLlSIkU6Z7oivTjfg0dR32Z80lCdZDQf+OQsRtCUi169Fgxr7+HhdxJyj49\nFIb6CR0DHW4vsEj1GPAa0Q4uMfCxLiSZfesY8myoCtlVo7oeqx787KicJB5PryHr\nyZweKd7tXO9g8LNJtECTZ81y2/sCfSZPBia6M4oz56pIFK4jhYCY3iPnWIS77axu\n5MmqZNOP06obp87nt1ea51BmXkaYxmSPoQ5R29CeYU+m9q+kKvizncgsCl/O7U6F\nAgwDC9FRLmchgYQBEADJo2kPzrxLHptsr6aoIxfYNrQ7JJM3FAZ7do5YvAbQsl5t\ny45qZ4+qWIEMRXwji2TvgSg8/ylnZfN2+rTHdtNJkDdJ2sX+RDr8pm7L3VS2Zhjf\nIp1SdPd5cm/3QupegzUR+kcPa+gPM4asGSytIkAnnpev/DCnLsrqiejdosTDj9dn\nFtPKJKSUBzJSNRxBSpM9L+cTU1qyMT024D5Qvq6vBOjFI1YV3LSfVXQe7OZxxxVX\naChkGR1v3UjndQ4Yv9hamJJ81lRLeIcVEOpOPxLHJX76AJUqP3fR/+m2Poah8bFF\n+yIdSp2jyWOoU60We72fvlEwxsTLl8Zani+xX2ckkUCe+wsiGJLch4Df1pepxpef\nb95wZ9L0msRdHY8vRQYapde/ju8CUHgywVX7+YH3EF1bJSnUOBmyOA76v9ir09am\n49g+VomkWUuzPJ2VYQXXH6d/qn/sm9Z9yxy7e1eh5m+9cd42b4sMdW6ZCTMAtGJF\nPX0SiOMR6S0hjKVBcfcyNoT/wo7wqEl4mYDpoCy10K0nYRn+ggJnIZEJzBWibMYH\nDWUDyuQIYLjOBAchFatXyMtbc8qDorYelLX7amPRDSiDhhj6Y5nYMJtUSwfTLwkN\nrI0Q4bjE+fgNACCqPoq/BDFZotcr1b664ZUJqgnTBPKZ5OnmW/iFkOfzu4fF9tJe\nAcekEPwsFbugu2bZ0Hs5Rl/Dh9p4L9gceuMiwJ3oYGA5cwXFCeVZLNqSDLy4upVX\nnXRaMzBNGgWo4geDq5JL10Mh7/1d4GGVxdts8RGdI8zUFTPV3GOaPEHeNyIO+g==\n=2UMI\n-----END PGP MESSAGE-----", + "fp": "4BE7925262289B476DBBC17B76FD3810215AE097" + } + ], + "unencrypted_suffix": "_unencrypted", + "version": "3.11.0" + } +} diff --git a/index.html b/index.html index 6731700..ad5d0e2 100644 --- a/index.html +++ b/index.html @@ -3,10 +3,10 @@ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> - + -SwarselSystems: NixOS + Emacs Configuration +SwarselSystems: NixOS + Emacs Configurationo