commit 5543b7a3b7e287ab701dff3a099276041906c5df Author: Mikael Voss Date: Sun Aug 18 13:47:18 2024 +0200 Initial import diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a3d6222 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +# Hidden files +.* +!.git* + +# Nix +/result +/result-* diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..85a03cd --- /dev/null +++ b/flake.lock @@ -0,0 +1,643 @@ +{ + "nodes": { + "base16": { + "inputs": { + "fromYaml": "fromYaml" + }, + "locked": { + "lastModified": 1708890466, + "narHash": "sha256-LlrC09LoPi8OPYOGPXegD72v+//VapgAqhbOFS3i8sc=", + "owner": "SenchoPens", + "repo": "base16.nix", + "rev": "665b3c6748534eb766c777298721cece9453fdae", + "type": "github" + }, + "original": { + "owner": "SenchoPens", + "repo": "base16.nix", + "type": "github" + } + }, + "base16-fish": { + "flake": false, + "locked": { + "lastModified": 1622559957, + "narHash": "sha256-PebymhVYbL8trDVVXxCvZgc0S5VxI7I1Hv4RMSquTpA=", + "owner": "tomyun", + "repo": "base16-fish", + "rev": "2f6dd973a9075dabccd26f1cded09508180bf5fe", + "type": "github" + }, + "original": { + "owner": "tomyun", + "repo": "base16-fish", + "type": "github" + } + }, + "base16-foot": { + "flake": false, + "locked": { + "lastModified": 1696725948, + "narHash": "sha256-65bz2bUL/yzZ1c8/GQASnoiGwaF8DczlxJtzik1c0AU=", + "owner": "tinted-theming", + "repo": "base16-foot", + "rev": "eedbcfa30de0a4baa03e99f5e3ceb5535c2755ce", + "type": "github" + }, + "original": { + "owner": "tinted-theming", + "repo": "base16-foot", + "type": "github" + } + }, + "base16-helix": { + "flake": false, + "locked": { + "lastModified": 1720809814, + "narHash": "sha256-numb3xigRGnr/deF7wdjBwVg7fpbTH7reFDkJ75AJkY=", + "owner": "tinted-theming", + "repo": "base16-helix", + "rev": "34f41987bec14c0f3f6b2155c19787b1f6489625", + "type": "github" + }, + "original": { + "owner": "tinted-theming", + "repo": "base16-helix", + "type": "github" + } + }, + "base16-kitty": { + "flake": false, + "locked": { + "lastModified": 1665001328, + "narHash": "sha256-aRaizTYPpuWEcvoYE9U+YRX+Wsc8+iG0guQJbvxEdJY=", + "owner": "kdrag0n", + "repo": "base16-kitty", + "rev": "06bb401fa9a0ffb84365905ffbb959ae5bf40805", + "type": "github" + }, + "original": { + "owner": "kdrag0n", + "repo": "base16-kitty", + "type": "github" + } + }, + "base16-tmux": { + "flake": false, + "locked": { + "lastModified": 1696725902, + "narHash": "sha256-wDPg5elZPcQpu7Df0lI5O8Jv4A3T6jUQIVg63KDU+3Q=", + "owner": "tinted-theming", + "repo": "base16-tmux", + "rev": "c02050bebb60dbb20cb433cd4d8ce668ecc11ba7", + "type": "github" + }, + "original": { + "owner": "tinted-theming", + "repo": "base16-tmux", + "type": "github" + } + }, + "base16-vim": { + "flake": false, + "locked": { + "lastModified": 1716150083, + "narHash": "sha256-ZMhnNmw34ogE5rJZrjRv5MtG3WaqKd60ds2VXvT6hEc=", + "owner": "tinted-theming", + "repo": "base16-vim", + "rev": "6e955d704d046b0dc3e5c2d68a2a6eeffd2b5d3d", + "type": "github" + }, + "original": { + "owner": "tinted-theming", + "repo": "base16-vim", + "type": "github" + } + }, + "colmena": { + "inputs": { + "flake-compat": "flake-compat", + "flake-utils": "flake-utils", + "nixpkgs": [ + "nixpkgs" + ], + "stable": "stable" + }, + "locked": { + "lastModified": 1711386353, + "narHash": "sha256-gWEpb8Hybnoqb4O4tmpohGZk6+aerAbJpywKcFIiMlg=", + "owner": "zhaofengli", + "repo": "colmena", + "rev": "cd65ef7a25cdc75052fbd04b120aeb066c3881db", + "type": "github" + }, + "original": { + "owner": "zhaofengli", + "repo": "colmena", + "type": "github" + } + }, + "crane": { + "inputs": { + "nixpkgs": [ + "lanzaboote", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1721842668, + "narHash": "sha256-k3oiD2z2AAwBFLa4+xfU+7G5fisRXfkvrMTCJrjZzXo=", + "owner": "ipetkov", + "repo": "crane", + "rev": "529c1a0b1f29f0d78fa3086b8f6a134c71ef3aaf", + "type": "github" + }, + "original": { + "owner": "ipetkov", + "repo": "crane", + "type": "github" + } + }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1650374568, + "narHash": "sha256-Z+s0J8/r907g149rllvwhb4pKi8Wam5ij0st8PwAh+E=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "b4a34015c698c7793d592d66adbab377907a2be8", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-compat_2": { + "flake": false, + "locked": { + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-compat_3": { + "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-parts": { + "inputs": { + "nixpkgs-lib": [ + "lanzaboote", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1719994518, + "narHash": "sha256-pQMhCCHyQGRzdfAkdJ4cIWiw+JNuWsTX7f0ZYSyz0VY=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "9227223f6d922fee3c7b190b2cc238a99527bbb7", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-utils": { + "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_2": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1710146030, + "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flakey-profile": { + "locked": { + "lastModified": 1712898590, + "narHash": "sha256-FhGIEU93VHAChKEXx905TSiPZKga69bWl1VB37FK//I=", + "owner": "lf-", + "repo": "flakey-profile", + "rev": "243c903fd8eadc0f63d205665a92d4df91d42d9d", + "type": "github" + }, + "original": { + "owner": "lf-", + "repo": "flakey-profile", + "type": "github" + } + }, + "fromYaml": { + "flake": false, + "locked": { + "lastModified": 1689549921, + "narHash": "sha256-iX0pk/uB019TdBGlaJEWvBCfydT6sRq+eDcGPifVsCM=", + "owner": "SenchoPens", + "repo": "fromYaml", + "rev": "11fbbbfb32e3289d3c631e0134a23854e7865c84", + "type": "github" + }, + "original": { + "owner": "SenchoPens", + "repo": "fromYaml", + "type": "github" + } + }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "lanzaboote", + "pre-commit-hooks-nix", + "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": 1713702291, + "narHash": "sha256-zYP1ehjtcV8fo+c+JFfkAqktZ384Y+y779fzmR9lQAU=", + "owner": "GNOME", + "repo": "gnome-shell", + "rev": "0d0aadf013f78a7f7f1dc984d0d812971864b934", + "type": "github" + }, + "original": { + "owner": "GNOME", + "ref": "46.1", + "repo": "gnome-shell", + "type": "github" + } + }, + "home-manager": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1723986931, + "narHash": "sha256-Fy+KEvDQ+Hc8lJAV3t6leXhZJ2ncU5/esxkgt3b8DEY=", + "owner": "nix-community", + "repo": "home-manager", + "rev": "2598861031b78aadb4da7269df7ca9ddfc3e1671", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "home-manager", + "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", + "rust-overlay": "rust-overlay" + }, + "locked": { + "lastModified": 1722329086, + "narHash": "sha256-e/fSi0WER06N8WCvpht62fkGtWfe5ckDxr6zNYkwkFw=", + "owner": "nix-community", + "repo": "lanzaboote", + "rev": "f5a3a7dff44d131807fc1a89fbd8576cd870334a", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "lanzaboote", + "type": "github" + } + }, + "lix": { + "flake": false, + "locked": { + "lastModified": 1723503926, + "narHash": "sha256-Rosl9iA9MybF5Bud4BTAQ9adbY81aGmPfV8dDBGl34s=", + "rev": "bcaeb6388b8916ac6d1736e3aa2b13313e6a6bd2", + "type": "tarball", + "url": "https://git.lix.systems/api/v1/repos/lix-project/lix/archive/bcaeb6388b8916ac6d1736e3aa2b13313e6a6bd2.tar.gz?rev=bcaeb6388b8916ac6d1736e3aa2b13313e6a6bd2" + }, + "original": { + "type": "tarball", + "url": "https://git.lix.systems/lix-project/lix/archive/2.91.0.tar.gz" + } + }, + "lix-module": { + "inputs": { + "flake-utils": "flake-utils_2", + "flakey-profile": "flakey-profile", + "lix": "lix", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1723510904, + "narHash": "sha256-zNW/rqNJwhq2lYmQf19wJerRuNimjhxHKmzrWWFJYts=", + "rev": "622a2253a071a1fb97a4d3c8103a91114acc1140", + "type": "tarball", + "url": "https://git.lix.systems/api/v1/repos/lix-project/nixos-module/archive/622a2253a071a1fb97a4d3c8103a91114acc1140.tar.gz?rev=622a2253a071a1fb97a4d3c8103a91114acc1140" + }, + "original": { + "type": "tarball", + "url": "https://git.lix.systems/lix-project/nixos-module/archive/2.91.0.tar.gz" + } + }, + "nix-index-database": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1723950649, + "narHash": "sha256-dHMkGjwwCGj0c2MKyCjRXVBXq2Sz3TWbbM23AS7/5Hc=", + "owner": "nix-community", + "repo": "nix-index-database", + "rev": "392828aafbed62a6ea6ccab13728df2e67481805", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nix-index-database", + "type": "github" + } + }, + "nixos-hardware": { + "locked": { + "lastModified": 1724067415, + "narHash": "sha256-WJBAEFXAtA41RMpK8mvw0cQ62CJkNMBtzcEeNIJV7b0=", + "owner": "NixOS", + "repo": "nixos-hardware", + "rev": "b09c46430ffcf18d575acf5c339b38ac4e1db5d2", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixos-hardware", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1724177844, + "narHash": "sha256-G7Mf9uN9m8FimeP3eMHu/dOC4QS8QAzo0h4ZIlDHcCA=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "d13fa5a45a34e7c8be33474f58003914430bdc5a", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-stable": { + "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" + } + }, + "nur": { + "locked": { + "lastModified": 1724219095, + "narHash": "sha256-+HhSPWqM1VJlQTNwgJE2RmTVUMoF6FuCRKzzTgxjNcM=", + "owner": "nix-community", + "repo": "NUR", + "rev": "cb4a85f95c647cf5aa7ce75b77ff2c049137160a", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "NUR", + "type": "github" + } + }, + "pre-commit-hooks-nix": { + "inputs": { + "flake-compat": [ + "lanzaboote", + "flake-compat" + ], + "gitignore": "gitignore", + "nixpkgs": [ + "lanzaboote", + "nixpkgs" + ], + "nixpkgs-stable": "nixpkgs-stable" + }, + "locked": { + "lastModified": 1721042469, + "narHash": "sha256-6FPUl7HVtvRHCCBQne7Ylp4p+dpP3P/OYuzjztZ4s70=", + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "rev": "f451c19376071a90d8c58ab1a953c6e9840527fd", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "type": "github" + } + }, + "root": { + "inputs": { + "colmena": "colmena", + "home-manager": "home-manager", + "lanzaboote": "lanzaboote", + "lix-module": "lix-module", + "nix-index-database": "nix-index-database", + "nixos-hardware": "nixos-hardware", + "nixpkgs": "nixpkgs", + "nur": "nur", + "rust-overlay": "rust-overlay_2", + "stylix": "stylix" + } + }, + "rust-overlay": { + "inputs": { + "nixpkgs": [ + "lanzaboote", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1722219664, + "narHash": "sha256-xMOJ+HW4yj6e69PvieohUJ3dBSdgCfvI0nnCEe6/yVc=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "a6fbda5d9a14fb5f7c69b8489d24afeb349c7bb4", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, + "rust-overlay_2": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1724206841, + "narHash": "sha256-L8dKaX4T3k+TR2fEHCfGbH4UXdspovz/pj87iai9qmc=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "45e98fbd62c32e5927e952d2833fa1ba4fb35a61", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, + "stable": { + "locked": { + "lastModified": 1696039360, + "narHash": "sha256-g7nIUV4uq1TOVeVIDEZLb005suTWCUjSY0zYOlSBsyE=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "32dcb45f66c0487e92db8303a798ebc548cadedc", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-23.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "stylix": { + "inputs": { + "base16": "base16", + "base16-fish": "base16-fish", + "base16-foot": "base16-foot", + "base16-helix": "base16-helix", + "base16-kitty": "base16-kitty", + "base16-tmux": "base16-tmux", + "base16-vim": "base16-vim", + "flake-compat": "flake-compat_3", + "gnome-shell": "gnome-shell", + "home-manager": [ + "home-manager" + ], + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1724091143, + "narHash": "sha256-55CrA0BNqmnS4qB812D7JY9hNBB0r36sJlErepkfeTo=", + "owner": "danth", + "repo": "stylix", + "rev": "94d70292d0c687ebacb65d00bd516cbefa18d3ca", + "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" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..db32a21 --- /dev/null +++ b/flake.nix @@ -0,0 +1,140 @@ +{ + description = "I do not have to explain myself"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + nixos-hardware.url = "github:NixOS/nixos-hardware"; + nur.url = "github:nix-community/NUR"; + + lix-module = { + url = "https://git.lix.systems/lix-project/nixos-module/archive/2.91.0.tar.gz"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + lanzaboote = { + url = "github:nix-community/lanzaboote"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + colmena = { + url = "github:zhaofengli/colmena"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + home-manager = { + url = "github:nix-community/home-manager"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + stylix = { + url = "github:danth/stylix"; + inputs.nixpkgs.follows = "nixpkgs"; + inputs.home-manager.follows = "home-manager"; + }; + + nix-index-database = { + url = "github:nix-community/nix-index-database"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + rust-overlay = { + url = "github:oxalica/rust-overlay"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + + nixConfig = { + allow-import-form-derivation = true; + + extra-experimental-features = [ "pipe-operator" ]; + + extra-substituters = [ + "https://colmena.cachix.org" + "https://nix-community.cachix.org" + "https://cache.kyouma.net" + ]; + + extra-trusted-public-keys = [ + "colmena.cachix.org-1:7BzpDnjjH8ki2CT3f6GdOk7QAzPOl+1t3LvTLXqYcSg=" + "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" + "cache.kyouma.net:Frjwu4q1rnwE/MnSTmX9yx86GNA/z3p/oElGvucLiZg=" + ]; + }; + + outputs = { self, nixpkgs, ... }@inputs: + let + inherit (nixpkgs) lib; + + load = base: default: builtins.readDir base + |> lib.filterAttrs (name: type: builtins.match "(regular|directory)" type != null) + |> lib.mapAttrs' (name: type: { + name = if type == "regular" then lib.removeSuffix ".nix" name else name; + value = + let path = if type == "directory" then "${name}/${default}.nix" else name; + in import "${base}/${path}" inputs; + }); + + eachFlakeSystem = lib.genAttrs lib.systems.flakeExposed; + eachNixosSystem = lib.systems.flakeExposed + |> lib.systems.parse + |> builtins.filter (sys: sys.isLinux) + |> builtins.attrNames + |> lib.genAttrs; + in { + lib = load ./lib "lib" // { + inherit load; + }; + + overlays = load ./overlay "overlay"; + legacyPackages = eachFlakeSystem (system: + import nixpkgs { + inherit system; + overlays = [ self.overlays.default ]; + }); + + packages = eachFlakeSystem (system: let pkgs = self.legacyPackages.${system}; + in load ./package "package" + |> lib.mapAttrs (name: pkg: self.legacyPackages.${system}.callPackage pkg { })); + + nixosModules = load ./nixos/module "module"; + + colmena = load ./nixos/config "configuration" // { + meta = { + nixpkgs = self.legacyPackages.x86_64-linux; + }; + + defaults = { name, config, ... }: { + deployment = { + allowLocalDeployment = true; + targetHost = config.networking.fqdnOrHostName; + targetUser = null; + }; + }; + }; + + nixosConfigurations = + let hive = inputs.colmena.lib.makeHive self.outputs.colmena; + in hive.nodes; + + homeModules = load ./home/module "module"; + homeConfigurations = load ./home/config "home"; + + devShells = eachFlakeSystem (system: load ./shell "shell" + |> lib.mapAttrs (name: shell: self.legacyPackages.${system}.callPackage shell { })); + + checks = eachFlakeSystem (system: { + packages = self.packages.${system}; + devShells = self.devShells.${system}; + }) // (self.nixosConfigurations + |> lib.mapAttrsToList (name: host: { + ${host.pkgs.system} = { + nixos = { + ${name} = host.config.system.build.toplevel; + }; + }; + }) + |> lib.mergeAttrsList); + + hydraJobs = { inherit (self) checks; }; + }; +} diff --git a/home/config/nil/firefox.nix b/home/config/nil/firefox.nix new file mode 100644 index 0000000..c0a1440 --- /dev/null +++ b/home/config/nil/firefox.nix @@ -0,0 +1,246 @@ +{ ... }: { config, lib, pkgs, ... }@args: +let + osConfig = args.osConfig or { }; + + firefox-csshacks = pkgs.fetchFromGitHub { + owner = "MrOtherGuy"; + repo = "firefox-csshacks"; + rev = "7eca4b1050c4065130a2cf696302b4ef5d88d932"; + sparseCheckout = [ "!/*" "/chrome" "/content" ]; + hash = "sha256-rk0jC5AMw41xt5yItY7CAxuYAFhoe5Jy2tvwgh59cPI="; + }; +in lib.mkIf (osConfig.hardware.graphics.enable or false) { + programs.firefox = { + enable = true; + package = pkgs.firefox; + profiles = let + extensions = with config.nur.repos.rycee.firefox-addons; [ + clearurls + consent-o-matic + decentraleyes + keepassxc-browser + multi-account-containers + ublock-origin + ]; + settings = { + # use OS locale + "intl.regional_prefs.use_os_locales" = true; + + # localisation + "intl.accept_languages" = "en-gb,en,de,fr,es-es,es,pt,ja"; + "intl.locale.requested" = "en-GB,en,de,fr,es-ES,es,pt,ja"; + + # use OS resolver + "network.trr.mode" = 5; + + # force HTTPS + "dom.security.https_only_mode" = true; + "dom.security.https_only_mode_ever_enabled" = true; + + # enable EME + "media.eme.enabled" = true; + + # founts + "font.default.x-unicode" = "sans-serif"; + "font.default.x-western" = "sans-serif"; + "font.name.sans-serif.x-unicode" = "Lato"; + "font.name.sans-serif.x-western" = "Lato"; + "font.name.monospace.x-unicode" = "Fira Code"; + "font.name.monospace.x-western" = "Fira Code"; + + # hardware acceleration + "gfx.webrender.all" = true; + "layers.acceleration.force-enabled" = true; + "media.ffmpeg.vaapi.enabled" = true; + + # always ask for download location + "browser.download.useDownloadDir" = false; + + # disable firefox tab + "browser.tabs.firefox-view" = false; + + # disable firefox intro tab + "browser.startup.homepage_override.mstone" = "ignore"; + + # disable default browser check + "browser.shell.checkDefaultBrowser" = false; + + # private containor for new tab page thumbnails + "privacy.usercontext.about_newtab_segregation.enabled" = true; + + # disable Beacons API + "beacon.enabled" = false; + + # disable pings + "browser.send_pings" = false; + + # strip query parameters + "privacy.query_stripping" = true; + + # disable access to device sensors + "device.sensors.enabled" = false; + "dom.battery.enabled" = false; + + # disable media auto‐play + "media.autoplay.enabled" = false; + + # block third‐party cookies + "network.cookie.cookieBehavior" = 1; + + # spoof referrer header + "network.http.referer.spoofSource" = true; + + # isolate all browser identifier sources + "privacy.firstparty.isolate" = true; + + # resist fingerprinting + #"privacy.resistFingerprinting" = true; + + # enable built‐in tracking protection + "privacy.trackingprotection.enabled" = true; + "privacy.trackingprotection.emailtracking.enabled" = true; + "privacy.trackingprotection.socialtracking.enabled" = true; + + # disable data sharing + "app.normandy.enabled" = false; + "app.shield.optoutstudies.enabled" = false; + "datareporting.healthreport.uploadEnabled" = false; + + # disable safebrowsing + "browser.safebrowsing.downloads.enabled" = false; + "browser.safebrowsing.malware.enabled" = false; + "browser.safebrowsing.phishing.enabled" = false; + + # disable firefox account + "identity.fxaccounts.enabled" = false; + + # disable sponsored items + "browser.newtabpage.activity-stream.showSponsoredTopSites" = false; + "browser.newtabpage.enhanced" = false; + + # disable Pocket + "extensions.pocket.enabled" = false; + + # disable crash reporting + "browser.tabs.crashReporting.sendReport" = false; + "breakpad.reportURL" = ""; + + # disable accessibility services + "accessibility.force_disabled" = true; + + # disable password auto‐fill + "signon.autofillForms" = false; + + # enable user profile customisation + "toolkit.legacyUserProfileCustomizations.stylesheets" = true; + }; + userChrome = lib.concatMapStrings (css: + "@import url('${firefox-csshacks}/chrome/${css}.css');\n" + ) [ + "hide_tabs_with_one_tab" + "autohide_bookmarks_and_main_toolbars" + ]; + search = { + default = "Google Search"; + force = true; + engines = { + "Google Search" = { + urls = [{ template = "https://www.google.com/search?q={searchTerms}"; }]; + definedAliases = [ "g" ]; + }; + + "Nix Packages" = { + urls = [{ + template = "https://search.nixos.org/packages"; + params = [ + { name = "channel"; value = "unstable"; } + { name = "type"; value = "packages"; } + { name = "query"; value = "{searchTerms}"; } + ]; + }]; + + definedAliases = [ "np" ]; + }; + + "Gentoo Packages" = { + urls = [{ template = "https://packages.gentoo.org/packages/search?q={searchTerms}"; }]; + definedAliases = [ "gp" ]; + }; + + "Alpine Packages" = { + urls = [{ template = "https://pkgs.alpinelinux.org/packages?name={searchTerms}"; }]; + definedAliases = [ "ap" ]; + }; + + "NixOS Wiki" = { + urls = [{ template = "https://nixos.wiki/index.php?search={searchTerms}"; }]; + definedAliases = [ "nw" ]; + }; + + "Wikipedia (eng)" = { + urls = [{ template = "https://en.wikipedia.org/wiki/Special:Search?search={searchTerms}"; }]; + definedAliases = [ "w" ]; + }; + + "Wikipedia (deu)" = { + urls = [{ template = "https://de.wikipedia.org/wiki/Spezial:Suche?search={searchTerms}"; }]; + definedAliases = [ "wd" ]; + }; + + "Wiktionary (eng)" = { + urls = [{ template = "https://en.wiktionary.org/wiki/Special:Search?search={searchTerms}"; }]; + definedAliases = [ "k" ]; + }; + + "Wiktionary (deu)" = { + urls = [{ template = "https://de.wiktionary.org/wiki/Spezial:Suche?search={searchTerms}"; }]; + definedAliases = [ "kd" ]; + }; + + "Linguee (en‐de)" = { + urls = [{ template = "https://www.linguee.com/english-german/search?query={searchTerms}"; }]; + definedAliases = [ "en" ]; + }; + + "Linguee (en‐fr)" = { + urls = [{ template = "https://www.linguee.com/english-french/search?query={searchTerms}"; }]; + definedAliases = [ "fr" ]; + }; + + "Linguee (en‐es)" = { + urls = [{ template = "https://www.linguee.com/english-spanish/search?query={searchTerms}"; }]; + definedAliases = [ "es" ]; + }; + + "Linguee (en‐pt)" = { + urls = [{ template = "https://www.linguee.com/english-portuguese/search?query={searchTerms}"; }]; + definedAliases = [ "pt" ]; + }; + + "Jisho" = { + urls = [{ template = "https://jisho.org/search/{searchTerms}"; }]; + definedAliases = [ "ja" ]; + }; + + "DeepL" = { + urls = [{ template = "https://www.deepl.com/translator#en//{searchTerms}"; }]; + definedAliases = [ "dpl" ]; + }; + }; + }; + in { + default = { + inherit extensions settings userChrome search; + isDefault = true; + }; + sneaky = { + inherit extensions settings userChrome search; + id = 1; + }; + vanilla = { + inherit userChrome search; + id = 2; + }; + }; + }; +} diff --git a/home/config/nil/greedy.xkb b/home/config/nil/greedy.xkb new file mode 100644 index 0000000..927e79c --- /dev/null +++ b/home/config/nil/greedy.xkb @@ -0,0 +1,73 @@ +xkb_symbols "greedy" { + name[Group1]= "Greedy"; + + // Modifier keys + include "ctrl(nocaps)" + include "altwin(alt_super_win)" + include "level3(ralt_switch)" + include "level5(rctrl_switch)" + + include "compose(lwin-altgr)" + include "compose(102)" + include "nbsp(level3n)" + include "keypad(future)" + + key { [ Escape ] }; + key { [ Tab ] }; + + key { [ dollar, asciitilde, EuroSign, dead_tilde ] }; + key { [ ampersand, percent, dead_breve, dead_caron ] }; + key { [ bracketleft, 7, 0x100201E, 0x100201A ] }; + key { [ braceleft, 5, 0x100201C, 0x1002018 ] }; + key { [ braceright, 3, 0x100201D, 0x1002019 ] }; + key { [ parenleft, 1, 0x1002039, NoSymbol ] }; + key { [ equal, 9, 0x1002260, NoSymbol ] }; + key { [ asterisk, 0, 0x10022C5, NoSymbol ] }; + key { [ parenright, 2, 0x100203A, NoSymbol ] }; + key { [ plus, 4, plusminus, NoSymbol ] }; + key { [ bracketright, 6, endash, emdash ] }; + key { [ exclam, 8, exclamdown, infinity ] }; + key { [ numbersign, grave, numerosign, dead_grave ] }; + + key { [ k, K, odiaeresis, Odiaeresis ] }; + key { [ comma, less, dead_cedilla, guillemotleft ] }; + key { [ u, U, oacute, Oacute ] }; + key { [ y, Y, udiaeresis, Udiaeresis ] }; + key { [ p, P, NoSymbol, NoSymbol ] }; + key { [ w, W, NoSymbol, NoSymbol ] }; + key { [ l, L, NoSymbol, NoSymbol ] }; + key { [ m, M, mu, NoSymbol ] }; + key { [ f, F, NoSymbol, NoSymbol ] }; + key { [ c, C, copyright, NoSymbol ] }; + key { [ slash, question, division, questiondown ] }; + key { [ at, asciicircum, 0x100203D, dead_circumflex ] }; + + key { [ o, O, oacute, Oacute ] }; + key { [ a, A, aacute, Aacute ] }; + key { [ e, E, eacute, Eacute ] }; + key { [ i, I, iacute, Iacute ] }; + key { [ d, D, eth, ETH ] }; + key { [ r, R, NoSymbol, NoSymbol ] }; + key { [ n, N, ntilde, Ntilde ] }; + key { [ t, T, thorn, Thorn ] }; + key { [ h, H, NoSymbol, NoSymbol ] }; + key { [ s, S, ssharp, section ] }; + key { [ minus, underscore, 0x1002010, dead_macron ] }; + key { [ backslash, bar, NoSymbol, NoSymbol ] }; + + key { [ q, Q, adiaeresis, Adiaeresis ] }; + key { [ period, greater, ellipsis, guillemotright ] }; + key { [ apostrophe, quotedbl, dead_acute, dead_diaeresis ] }; + key { [ semicolon, colon, periodcentered, NoSymbol ] }; + key { [ z, Z, NoSymbol, NoSymbol ] }; + key { [ x, X, multiply, NoSymbol ] }; + key { [ v, V, NoSymbol, NoSymbol ] }; + key { [ g, G, NoSymbol, NoSymbol ] }; + key { [ b, B, NoSymbol, NoSymbol ] }; + key { [ j, J, NoSymbol, NoSymbol ] }; + + key { [ Up, NoSymbol, uparrow, 0x10021D1 ] }; + key { [ Left, NoSymbol, leftarrow, 0x10021D0 ] }; + key { [ Down, NoSymbol, downarrow, 0x10021D3 ] }; + key { [ Right, NoSymbol, rightarrow, 0x10021D2 ] }; +}; diff --git a/home/config/nil/home.nix b/home/config/nil/home.nix new file mode 100644 index 0000000..ae14f09 --- /dev/null +++ b/home/config/nil/home.nix @@ -0,0 +1,343 @@ +{ self, nur, stylix, nix-index-database, ... }: { config, lib, pkgs, ... }@args: +let + osConfig = args.osConfig or { }; +in { + imports = [ + nur.hmModules.nur + self.homeModules.locale-en_EU + nix-index-database.hmModules.nix-index + stylix.homeManagerModules.stylix + ] ++ self.lib.mods [ + ./firefox.nix + ./wayland.nix + ]; + + home.stateVersion = "24.11"; + home.enableNixpkgsReleaseCheck = false; + + home.activation = { + fish = lib.hm.dag.entryAfter ["writeBoundary"] '' + run ${lib.getExe config.programs.fish.package} -c 'set -U fish_greeting' + ''; + }; + + home.packages = with pkgs; [ + # Terminfo + kitty.terminfo + + # Core utilities + (lib.meta.setPrio 0 uutils-coreutils-noprefix) + + # Text manipulation + #delta + sd + skim + + # Networking + dogdns + whois + xh + + # Filesystem + file + #xcp + + # Development + pijul + + # Calculator + fend + ]; + + home.sessionVariables = { + TMPDIR = "$XDG_RUNTIME_DIR/tmp"; + }; + + editorconfig = { + enable = true; + settings = { + "*" = { + indent_style = "tab"; + tab_width = 4; + end_of_line = "lf"; + charset = "utf-8"; + trim_trailing_whitespace = true; + insert_final_newline = true; + }; + + "*.nix" = { + indent_style = "space"; + indent_size = 2; + }; + }; + }; + + home.shellAliases = { + icat = "kitten icat"; + }; + + home.preferXdgDirectories = true; + + programs.aria2 = { + enable = true; + settings = { + max-concurrent-downloads = 4; + max-connection-per-server = 2; + min-split-size = "16M"; + remote-time = true; + split = 4; + http-accept-gzip = true; + max-overall-upload-limit = "256K"; + dscp = 8; + enable-mmap = true; + file-allocation = "falloc"; + }; + }; + + programs.bat.enable = true; + + programs.bottom = { + enable = true; + settings.flags = { + group = true; + battery = true; + color = "gruvbox"; + mem_as_value = true; + network_use_binary_prefix = true; + network_use_bytes = true; + }; + }; + + programs.eza = { + enable = true; + icons = true; + git = true; + + extraOptions = [ + "--binary" + "--colour=automatic" + "--colour-scale=all" + "--colour-scale-mode=gradient" + "--group-directories-first" + ]; + }; + + programs.fd.enable = true; + + programs.fish = { + enable = true; + functions = { + fish_prompt = '' + set -l user_colour 'green' + if fish_is_root_user + set user_colour 'red' + end + + echo -n -s (set_color $user_colour --bold) $USER@ (prompt_hostname) \ + (set_color blue --bold) ' ' (prompt_pwd) ' ❯ ' (set_color normal) + ''; + + fish_right_prompt = '' + set -l st $status + + if test $st -ne 0 + set_color red --bold + printf "%s " (sysexit $st) + set_color normal + end + ''; + + fish_title = "prompt_pwd"; + + sysexit = builtins.readFile ./sysexit.fish; + }; + + interactiveShellInit = '' + if type -q tabs + tabs -4 + end + ''; + }; + + programs.git = { + enable = true; + #delta.enable = true; + + userName = "Mikael Voss"; + userEmail = "mvs@nyantec.com"; + + extraConfig = { + core = { + eol = "lf"; + fsync = "committed"; + }; + + user.signingKey = "key::sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAICczPHRwY9MAwDGlcB0QgMOJjcpLJhVU3covrW9RBS62AAAABHNzaDo= primary"; + + init.defaultBranch = "main"; + pull.rebase = true; + push.autoSetupRemote = true; + rebase.autoStash = true; + + gpg.format = "ssh"; + gpg.ssh.allowedSignersFile = toString (pkgs.writeText "allowed-signers" '' + ${config.programs.git.userEmail} AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAICczPHRwY9MAwDGlcB0QgMOJjcpLJhVU3covrW9RBS62AAAABHNzaDo= + ''); + commit.gpgSign = true; + tag.gpgSign = true; + }; + }; + + programs.helix = { + enable = true; + defaultEditor = true; + settings = { + editor.auto-pairs = { + "“" = "”"; + "‘" = "’"; + "„" = "“"; + "‚" = "‘"; + }; + + editor.whitespace.render = { + nbsp = "all"; + nnbsp = "all"; + tab = "all"; + }; + + editor.whitespace.characters = { + nbsp = "␣"; + nnbsp = "⍽"; + tab = "»"; + tabpad = "·"; + }; + + keys.normal = { + minus = "command_mode"; + r = "move_char_left"; + n = "move_visual_line_down"; + t = "move_visual_line_up"; + h = "move_char_right"; + }; + }; + }; + + programs.jq.enable = true; + programs.man.generateCaches = + osConfig.documentation.man.generateCaches or false; + programs.ripgrep.enable = true; + + programs.ssh = { + enable = true; + compression = true; + + controlMaster = "auto"; + controlPath = "\${XDG_RUNTIME_DIR}/ssh/%r@%n:%p"; + controlPersist = "1m"; + + matchBlocks = { + "*.nyantec.com".user = "mvs"; + "solitary.social" = { + user = "nil"; + forwardAgent = true; + }; + }; + + serverAliveInterval = 10; + serverAliveCountMax = 60; + }; + + programs.vim = { + enable = true; + settings = { + background = "dark"; + expandtab = false; + number = true; + shiftwidth = 4; + tabstop = 4; + }; + extraConfig = '' + " no Vi compatibility + set nocompatible + + " Unicode support + set encoding=utf-8 + + " special characters + set list + set listchars=tab:»·,trail:·,extends:… + + set ruler + + " movement + noremap r h + noremap R H + noremap n j + noremap t k + noremap h l + noremap H L + + " beginning of previous word + noremap p b + + " end of word + noremap l e + noremap L E + + " change one char + noremap X s + + " repeat search + noremap ; n + noremap : N + + " paste + noremap s p + noremap S P + + " join lines + noremap N J + + " change + noremap e c + noremap E C + + " replace + noremap z r + noremap Z R + + " inclusive jump + noremap m f + noremap M F + + " exlusive jump + noremap f t + noremap F T + + " command mode + noremap - : + ''; + }; + + services.ssh-agent.enable = true; + + systemd.user.tmpfiles.rules = [ + "d %t/ssh 700" + "d %t/tmp 700 - - 24h" + ]; + + xdg.userDirs = + let + home = config.home.homeDirectory; + in { + enable = true; + desktop = "${home}/tmp"; + documents = "${home}/var"; + download = "${home}/tmp"; + pictures = "${home}/img"; + music = "${home}/msc"; + publicShare = null; + templates = null; + videos = null; + }; +} diff --git a/home/config/nil/sysexit.fish b/home/config/nil/sysexit.fish new file mode 100644 index 0000000..03f94ac --- /dev/null +++ b/home/config/nil/sysexit.fish @@ -0,0 +1,104 @@ +if status is-interactive + function sysexit + switch $argv[1] + case 0 + echo OK + case 64 + echo USAGE + case 65 + echo DATAERR + case 66 + echo NOINPUT + case 67 + echo NOUSER + case 68 + echo NOHOST + case 69 + echo UNAVAILABLE + case 70 + echo SOFTWARE + case 71 + echo OSERR + case 72 + echo OSFILE + case 73 + echo CANTCREAT + case 74 + echo IOERR + case 75 + echo TEMPFAIL + case 76 + echo PROTOCOL + case 77 + echo NOPERM + case 78 + echo CONFIG + case 127 + echo NOTFOUND + case 129 + echo SIGHUP + case 130 + echo SIGINT + case 131 + echo SIGQUIT + case 132 + echo SIGILL + case 133 + echo SIGTRAP + case 134 + echo SIGABRT + case 135 + echo SIGBUS + case 136 + echo SIGFPE + case 137 + echo SIGKILL + case 138 + echo SIGUSR1 + case 139 + echo SIGSEGV + case 140 + echo SIGUSR2 + case 141 + echo SIGPIPE + case 142 + echo SIGALRM + case 143 + echo SIGTERM + case 144 + echo SIGSTKFLT + case 145 + echo SIGCHLD + case 146 + echo SIGCONT + case 147 + echo SIGSTOP + case 148 + echo SIGTSTP + case 149 + echo SIGTTIN + case 150 + echo SIGTTOU + case 151 + echo SIGURG + case 152 + echo SIGXCPU + case 153 + echo SIGXFSZ + case 154 + echo SIGVTALRM + case 155 + echo SIGPROF + case 156 + echo SIGWINCH + case 157 + echo SIGIO + case 158 + echo SIGPWR + case 159 + echo SIGSYS + case '*' + echo $argv[1] + end + end +end diff --git a/home/config/nil/wallpaper.png b/home/config/nil/wallpaper.png new file mode 100644 index 0000000..a0949c5 Binary files /dev/null and b/home/config/nil/wallpaper.png differ diff --git a/home/config/nil/wayland.nix b/home/config/nil/wayland.nix new file mode 100644 index 0000000..3d90216 --- /dev/null +++ b/home/config/nil/wayland.nix @@ -0,0 +1,665 @@ +{ ... }: { config, lib, pkgs, ... }@args: +let + osConfig = args.osConfig or { }; + + fira-code-features = [ + "cv01" + "cv06" + "onum" + "ss01" + "ss03" + "ss06" + "ss07" + "ss08" + "zero" + ]; + + cmd = { + brightnessctl = "${pkgs.brightnessctl}/bin/brightnessctl"; + fish = "${osConfig.programs.fish.package}/bin/fish"; + grim = "${pkgs.grim}/bin/grim -l 9"; + jq = "${config.programs.jq.package}/bin/jq"; + keepassxc = "${pkgs.keepassxc}/bin/keepassxc"; + kill = "${pkgs.procps}/bin/kill"; + kitty = ''${config.programs.kitty.package}/bin/kitty --single-instance --instance-group "$XDG_SESSION_ID"''; + loginctl = "${osConfig.systemd.package}/bin/loginctl"; + mdless = "${pkgs.mdcat}/bin/mdless"; + mpv = "${config.programs.mpv.package}/bin/mpv"; + pidof = "${pkgs.procps}/bin/pidof"; + playerctl = "${pkgs.playerctl}/bin/playerctl"; + pwvucontrol = "${pkgs.pwvucontrol}/bin/pwvucontrol"; + slurp = "${pkgs.slurp}/bin/slurp"; + swaylock = "${config.programs.swaylock.package}/bin/swaylock"; + swaymsg = "${config.wayland.windowManager.sway.package}/bin/swaymsg"; + swayrbar = "${pkgs.swayrbar.override { withPulseaudio = true; }}/bin/swayrbar"; + tofi-drun = "${config.programs.tofi.package}/bin/tofi-drun"; + wl-copy = "${pkgs.wl-clipboard}/bin/wl-copy"; + wpctl = "${osConfig.services.pipewire.wireplumber.package}/bin/wpctl"; + xargs = "${pkgs.findutils}/bin/xargs"; + xdg-open = "${pkgs.xdg-utils}/bin/xdg-open"; + }; +in lib.mkIf (osConfig.hardware.graphics.enable or false) { + fonts.fontconfig = { + enable = true; + + defaultFonts = { + sansSerif = [ + "Lato" + "M PLUS 1" + "Noto Sans" + "Symbols Nerd Font" + "Unifont" + "Unifont Upper" + ]; + + serif = [ "Noto Serif"]; + + monospace = [ + "Fira Code" + "M PLUS 1 Code" + "Noto Sans Mono" + "Symbols Nerd Font Mono" + ]; + + emoji = [ "Noto Color Emoji" ]; + }; + }; + + home.file.".xkb/symbols/greedy".source = ./greedy.xkb; + + home.keyboard = { + layout = "greedy"; + options = [ "ctrl:nocaps" ]; + }; + + home.packages = with pkgs; [ + # Founts + lato + fira-code + mplus-outline-fonts.githubRelease + (nerdfonts.override { fonts = [ "NerdFontsSymbolsOnly" ]; }) + noto-fonts + noto-fonts-color-emoji + unifont + + # Image processing + oxipng + + # Documentation + linux-manual + man-pages + man-pages-posix + + # System operations + restic + + # Cryptography + rage + + # Messaging + fractal + signal-desktop + + # Audio control + pwvucontrol + + evince + inkscape + obsidian + + kicad + calibre + keepassxc + + # Multimedia + jellyfin-mpv-shim + + libreoffice + ]; + + programs.beets = { + enable = true; + settings = { + directory = "~/msc"; + import.reflink = "auto"; + + plugins = [ + "chroma" + "spotify" + "fromfilename" + + "fetchart" + "lyrics" + "replaygain" + + "duplicates" + "hook" + ]; + + hook.hooks = [ + { + event = "import"; + command = "systemctl --user start mopidy-scan.service"; + } + ]; + }; + }; + + programs.eza.extraOptions = lib.mkAfter [ "--hyperlink" ]; + + programs.imv.enable = true; + + programs.kitty = { + enable = true; + theme = "Catppuccin-Mocha"; + settings = { + disable_ligatures = "cursor"; + + cursor_blink_interval = 0; + + scrollback_lines = 65536; + scrollback_fill_enlarged_window = true; + + enable_audio_bell = false; + + close_on_child_death = true; + + clear_all_shortcuts = true; + + # Mouse + click_interval = "0.2"; + }; + + keybindings = { + "ctrl+shift+c" = "copy_to_clipboard"; + "ctrl+shift+v" = "paste_from_clipboard"; + "ctrl+shift+s" = "paste_from_selection"; + "shift+insert" = "paste_from_selection"; + "ctrl+up" = "scroll_line_up"; + "ctrl+down" = "scroll_line_down"; + "ctrl+page_up" = "scroll_page_up"; + "ctrl+page_down" = "scroll_page_down"; + "shift+page_up" = "scroll_page_up"; + "shift+page_down" = "scroll_page_down"; + "ctrl+home" = "scroll_home"; + "ctrl+end" = "scroll_end"; + "ctrl+print_screen" = "show_scrollback"; + + "ctrl+equal" = "change_font_size all 0"; + "ctrl+plus" = "change_font_size all +1"; + "ctrl+minus" = "change_font_size all -1"; + + "ctrl+shift+u" = "kitten unicode_input"; + }; + + extraConfig = let + mouse = { + "left click ungrabbed" = "mouse_handle_click selection prompt"; + "ctrl+left click ungrabbed" = "mouse_handle_click link"; + + "left press ungrabbed" = "mouse_selection normal"; + "shift+left press ungrabbed" = "mouse_selection line"; + "ctrl+left press ungrabbed" = "mouse_selection rectangle"; + + "left doublepress ungrabbed" = "mouse_selection word"; + "left triplepress ungrabbed" = " mouse_selection line"; + } |> lib.mapAttrsToList (n: v: "mouse_map ${n} ${v}\n") + |> lib.concatStrings; + in '' + clear_all_mouse_actions yes + ${mouse} + ''; + }; + + programs.mpv = { + enable = true; + defaultProfiles = [ "high-quality" ]; + config = { + #access-references = false; + + # Video output + vo = "gpu"; + #gpu-api = "vulkan"; + hwdec = "vulkan,vaapi,auto-safe"; + vd-lavc-dr = true; + + scale = "ewa_lanczos4sharpest"; + cscale = "spline64"; + dscale = "mitchell"; + tscale = "oversample"; + + # A/V sync + video-sync = "display-resample"; + interpolation = true; + + # Audio + volume = 100; + volume-max = 100; + + # Subtitles + sub-auto = "fuzzy"; + + # Screenshots + screenshot-format = "avif"; + + # Cache + demuxer-max-bytes = "768MiB"; + demuxer-max-back-bytes = "256MiB"; + }; + + profiles = { + highres = { + scale = "spline64"; + }; + }; + + scripts = with pkgs.mpvScripts; [ + mpris + autocrop + autodeint + ]; + + scriptOpts = { + autocrop.auto = false; + }; + }; + + programs.swaylock = { + enable = true; + package = pkgs.swaylock-effects; + settings = { + screenshots = true; + effect-blur = "5x3"; + grace = 2; + }; + }; + + programs.texlive = { + enable = true; + extraPackages = tpkgs: { + inherit (tpkgs) + texlive-scripts + + xelatex-dev + fontspec + polyglossia + + hyphen-english + hyphen-french + hyphen-german + hyphen-portuguese + hyphen-spanish + + koma-script + + amsmath + bookmark + booktabs + csquotes + hyperref + multirow + paralist + preprint + realscripts + textpos + unicode-math + units + xecjk + xecolor + xltxtra + xtab + ; + }; + }; + + programs.thunderbird = { + enable = true; + package = pkgs.thunderbird; + profiles = { }; + }; + + programs.tofi = { + enable = true; + settings = { + history = true; + fuzzy-match = true; + num-results = 8; + + font = pkgs.runCommand "fount-path" { + preferLocal = true; + nativeBuildInputs = with pkgs; [ fontconfig fira-code ]; + } '' + fc-match -f "%{file}" "Fira Code" >"$out" + '' |> builtins.readFile |> lib.mkForce; + + font-size = lib.mkForce 14; + font-features = fira-code-features |> lib.concatStringsSep ","; + font-variations = "wght 450"; + font-hint = true; + + anchor = "top"; + horizontal = true; + + width = "100%"; + height = 30; + + min-input-width = 120; + result-spacing = 20; + + border-width = 0; + outline-width = 0; + + padding-top = 4; + padding-bottom = 4; + padding-left = 12; + padding-right = 12; + }; + }; + + programs.yt-dlp.enable = true; + + services.gammastep = lib.optionalAttrs (osConfig ? location) ( + let inherit (osConfig) location; in { + inherit (location) provider; + enable = true; + settings = { + general.adjustment-method = "wayland"; + }; + } // lib.optionalAttrs (location.provider == "manual") { + #inherit (location) latitude longitude; + }); + + services.mako = { + enable = true; + defaultTimeout = 5000; + }; + + services.mopidy = { + enable = true; + extensionPackages = with pkgs; [ + mopidy-iris + mopidy-local + mopidy-mpd + mopidy-mpris + ]; + settings = { + core = { + cache_dir = "$XDG_CACHE_DIR/mopidy"; + config_dir = "$XDG_CONFIG_DIR/mopidy"; + data_dir = "$XDG_DATA_DIR/mopidy"; + }; + + audio.mixer = "none"; + file.media_dirs = [ "$XDG_MUSIC_DIR" ]; + local.media_dir = "$XDG_MUSIC_DIR"; + + mpd.hostname = "localhost"; + + http = { + hostname = "localhost"; + port = 6680; + default_app = "iris"; + }; + }; + }; + + services.swayidle = { + enable = true; + events = with cmd; [ + { event = "lock"; command = "${swaylock} -f"; } + { event = "before-sleep"; command = "${loginctl} lock-session"; } + ]; + + timeouts = with cmd; [ + { + timeout = 210; + command = "${brightnessctl} --save -e set 20%-"; + resumeCommand = "${brightnessctl} --restore"; + } + { + timeout = 240; + command = "${loginctl} lock-session"; + } + { + timeout = 270; + command = "${swaymsg} output '* dpms off'"; + resumeCommand = "${swaymsg} output '* dpms on'"; + } + ]; + }; + + services.syncthing = { + enable = true; + tray.enable = true; + }; + + services.udiskie = { + enable = true; + automount = false; + }; + + stylix = { + enable = true; + + image = ./wallpaper.png; + base16Scheme = "${pkgs.base16-schemes}/share/themes/catppuccin-macchiato.yaml"; + polarity = "dark"; + + opacity = { + applications = 0.98; + desktop = 0.98; + popups = 0.99; + terminal = 0.98; + }; + + fonts = { + sansSerif = { + package = pkgs.lato; + name = "sans-serif"; + }; + + serif = { + package = pkgs.noto-fonts; + name = "serif"; + }; + + monospace = { + package = pkgs.fira-code; + name = "monospace"; + }; + + emoji = { + package = pkgs.noto-fonts-color-emoji; + name = "emoji"; + }; + + sizes = { + terminal = 11; + }; + }; + }; + + systemd.user.services = lib.genAttrs [ "syncthing" ] (service: { + Unit = { + ConditionACPower = true; + StopPropagatedFrom = [ "power-external.target" ]; + }; + }); + + wayland.windowManager.sway = { + enable = true; + checkConfig = false; + xwayland = false; + + wrapperFeatures = { + base = true; + gtk = true; + }; + + systemd.variables = lib.mkAfter [ "PATH" ]; + + extraSessionCommands = let + env = { + WLR_RENDERER = "vulkan"; + NIXOS_OZONE_WL = 1; + }; + in env + |> lib.mapAttrsToList (n: v: "export ${lib.toShellVar n v}\n") + |> lib.concatStrings; + + config = with cmd; { + input."*" = { + xkb_layout = "us,${config.home.keyboard.layout}"; + xkb_options = lib.concatStringsSep "," + config.home.keyboard.options; + xkb_switch_layout = "1"; + }; + + output = { + "*" = { + scale = "1"; + background = "${./wallpaper.png} fill"; + adaptive_sync = "on"; + }; + + "Lenovo Group Limited P40w-20 V9084N0R" = { + resolution = "5120x2160"; + position = "0 0"; + subpixel = "rgb"; + }; + + "LG Display 0x06AA Unknown" = { + position = "0 2160"; + subpixel = "rgb"; + }; + }; + + bars = [ + { + fonts = lib.mkForce { + names = [ "monospace" ]; + size = 11.0; + }; + + statusCommand = swayrbar; + } + ]; + + gaps = { + inner = 4; + outer = 4; + }; + + window.titlebar = false; + + bindkeysToCode = true; + modifier = "Mod4"; + terminal = kitty; + menu = "${tofi-drun} | ${xargs} ${swaymsg} exec --"; + + keybindings = let + mod = config.wayland.windowManager.sway.config.modifier; + in lib.mkOptionDefault { + # Workspaces + "${mod}+Grave" = "workspace number 0"; + "${mod}+Shift+Grave" = "move container to workspace number 0"; + + "${mod}+Shift+Return" = "exec ${kitty} ${fish} --private"; + + # Function keys + XF86MonBrightnessUp = "exec ${brightnessctl} -e set +5%"; + XF86MonBrightnessDown = "exec ${brightnessctl} -e set 5%-"; + XF86AudioRaiseVolume = "exec ${wpctl} set-volume @DEFAULT_AUDIO_SINK@ +2dB"; + XF86AudioLowerVolume = "exec ${wpctl} set-volume @DEFAULT_AUDIO_SINK@ -2dB"; + XF86AudioMute = "exec set-mute @DEFAULT_AUDIO_SINK@ toggle"; + XF86AudioMicMute = "exec set-mute @DEFAULT_AUDIO_SOURCE@ toggle"; + XF86AudioNext = "exec ${playerctl} next"; + XF86AudioPrev = "exec ${playerctl} previous"; + XF86AudioPlay = "exec ${playerctl} play"; + XF86AudioStop = "exec ${playerctl} pause"; + XF86Explorer = "exec ${xdg-open} https:"; + + # Screenshots + "${mod}+Print" = "exec ${grim} -g - - | ${wl-copy}"; + "${mod}+Shift+Print" = "exec ${slurp} | ${grim} -g - - | ${wl-copy}"; + "${mod}+Ctrl+Print" = '' + exec ${swaymsg} -t get_tree \ + | ${jq} -r '.. | select(.focused?) | .rect | "\(.x),\(.y) \(.width)x\(.height)"' \ + | ${grim} -g - - \ + | ${wl-copy} + ''; + }; + + startup = [ + { command = "${swaymsg} input '*' xkb_switch_layout 1"; always = true; } + { command = "${keepassxc}"; } + ]; + }; + }; + + xdg.configFile."fontconfig/conf.d/80-fira-code.conf".text = '' + + + + + + Fira Code + + + ${fira-code-features + |> map (tag: "${lib.escapeXML tag}") + |> lib.concatStrings} + + + + ''; + + xdg.configFile."kitty/open-actions.conf".text = with cmd; '' + protocol file + mime image/* + action launch --type overlay kitten icat --hold -- "$FILE_PATH" + + protocol file + mime text/markdown + action launch --type overlay ${mdless} -- "$FILE_PATH" + + protocol file + mime text/* + action launch --type overlay $EDITOR -- "$FILE_PATH" + + protocol file + mime video/* + action launch --type background ${mpv} -- "$FILE_PATH" + + protocol file + mime audio/* + action launch --type overlay ${mpv} -- "$FILE_PATH" + + protocol + action launch --type background ${xdg-open} "$FILE_PATH" + ''; + + xdg.desktopEntries = { + kitty = { + name = "kitty"; + exec = builtins.replaceStrings [ "$" ] [ ''\\$'' ] cmd.kitty; + }; + }; + + xdg.mimeApps = { + enable = true; + defaultApplications = { + "default-web-browser" = [ "firefox.desktop" ]; + "application/pdf" = [ "org.gnome.Evince.desktop" ]; + }; + }; + + xdg.portal = { + enable = true; + config.common.default = [ "wlr" "gtk" ]; + extraPortals = with pkgs; [ + xdg-desktop-portal-wlr + (xdg-desktop-portal-gtk.override { buildPortalsInGnome = false; }) + ]; + }; +} diff --git a/home/module/locale-en_EU.nix b/home/module/locale-en_EU.nix new file mode 100644 index 0000000..a169c56 --- /dev/null +++ b/home/module/locale-en_EU.nix @@ -0,0 +1,4 @@ +{ self, ... }: { lib, pkgs, ... }: { + home.language.base = lib.mkDefault "en_EU.UTF-8"; + i18n.glibcLocales = self.packages.${pkgs.system}.locale-en_EU; +} diff --git a/lib/kernel.nix b/lib/kernel.nix new file mode 100644 index 0000000..89dcc1f --- /dev/null +++ b/lib/kernel.nix @@ -0,0 +1,58 @@ +{ nixpkgs, ... }: +let + inherit (builtins) + isAttrs + isInt + length + match + toString; + + inherit (nixpkgs.lib.asserts) + assertMsg; + + inherit (nixpkgs.lib.attrsets) + isDerivation + mapAttrsToList + mergeAttrsList; + + inherit (nixpkgs.lib.lists) + flatten; + + inherit (nixpkgs.lib.strings) + concatStrings + concatStringsSep + escape; + + isKey = str: match "[0-9A-Z][0-9A-Zx_]*" str != null; + isNum = str: match "(0x[0-9A-Fa-f]+|[1-9][0-9]*)" str != null; + + mkValueString = v: let + v' = toString v; + in if v == true then "y" + else if isInt v || isNum v' then v' + else "\"${escape [ "\"" ] v'}\""; + +in rec { + flattenAttrs = let + compose = p: n: if isKey n then p ++ [ n ] else p; + recurse = p: v: + if isValue v then { ${concatStringsSep "_" p} = v; } + else mapAttrsToList (n: v: recurse (compose p n) v) v; + in attrs: recurse [ ] attrs |> flatten |> mergeAttrsList; + + option = v: { _option = v; }; + isValue = x: isAttrs x -> !isDerivation x -> x ? _option; + isOptional = x: isAttrs x && !isDerivation x && x ? _option; + getValue = x: if isOptional x then x._option else x; + + mkKey = n: assert isKey n; "CONFIG_${n}"; + + mkKeyValue = n: v: let + v' = getValue v; + in if (v' == false || v' == null) + then "# ${mkKey n} is not set" + else "${mkKey n}=${mkValueString v'}"; + + mkConfig = attrs: mapAttrsToList (k: v: mkKeyValue k v + "\n") attrs + |> concatStrings; +} diff --git a/lib/mods.nix b/lib/mods.nix new file mode 100644 index 0000000..b0ca9b6 --- /dev/null +++ b/lib/mods.nix @@ -0,0 +1 @@ +{ ... }@inputs: map (mod: import mod inputs) diff --git a/nixos/config/muon.nix b/nixos/config/muon.nix new file mode 100644 index 0000000..ded9325 --- /dev/null +++ b/nixos/config/muon.nix @@ -0,0 +1,308 @@ +{ self, nixos-hardware, ... }: { lib, config, pkgs, ... }: { +imports = [ + nixos-hardware.nixosModules.lenovo-thinkpad-x1-extreme-gen4 + ] ++ (with self.nixosModules; [ + default + physical + portable + graphical + wireless + ]); + + boot.initrd = { + luks.devices."luks-2fb93d4f-a0fe-4a49-9e40-3ac38ffe4d75".device = "/dev/disk/by-uuid/2fb93d4f-a0fe-4a49-9e40-3ac38ffe4d75"; + luks.devices."luks-ea77e674-847f-41b8-9e1d-8b6dd08710e6".device = "/dev/disk/by-uuid/ea77e674-847f-41b8-9e1d-8b6dd08710e6"; + }; + + boot.kernelParams = [ + "intel_iommu=on" + "nouveau.config=NvGspRm=1" + ]; + + boot.kernelPackages = let + inherit (self.packages.x86_64-linux) linux-hardened; + in pkgs.linuxPackagesFor (linux-hardened.override { + instSetArch = "alderlake"; + extraFirmware = [ + "i915/adlp_dmc.bin" + "i915/adlp_dmc_ver2_16.bin" + "i915/adlp_guc_70.bin" + "i915/tgl_huc.bin" + "intel/ibt-0040-0041.sfi" + "intel/ibt-0040-0041.ddc" + "intel/sof/sof-adl.ri" + "intel/sof-tplg/sof-hda-generic-2ch.tplg" + "iwlwifi-so-a0-gf-a0-89.ucode" + "iwlwifi-so-a0-gf-a0.pnvm" + "nvidia/ga107/acr/ucode_unload.bin" + "nvidia/ga107/acr/ucode_asb.bin" + "nvidia/ga107/acr/ucode_ahesasc.bin" + "nvidia/ga107/gr/fecs_bl.bin" + "nvidia/ga107/gr/fecs_sig.bin" + "nvidia/ga107/gr/gpccs_bl.bin" + "nvidia/ga107/gr/gpccs_sig.bin" + "nvidia/ga107/gr/NET_img.bin" + "nvidia/ga107/sec2/desc.bin" + "nvidia/ga107/sec2/image.bin" + "nvidia/ga107/sec2/sig.bin" + "nvidia/ga107/sec2/hs_bl_sig.bin" + "nvidia/ga107/nvdec/scrubber.bin" + "nvidia/ga107/gsp/booter_load-535.113.01.bin" + "nvidia/ga107/gsp/booter_unload-535.113.01.bin" + "nvidia/ga107/gsp/bootloader-535.113.01.bin" + "nvidia/ga107/gsp/gsp-535.113.01.bin" + "regulatory.db" + "regulatory.db.p7s" + "rtl_nic/rtl8153b-2.fw" + ]; + + extraConfig = + (with linux-hardened.profile; physical // portable // dm-crypt // wireless // audio) + // (with self.lib.kernel; { + X86_INTEL_LPSS = true; + + CPU_SUP_INTEL = true; + CPU_SUP_AMD = false; + NR_CPUS = 20; + X86_MCE_INTEL = true; + + ACPI_DPTF = true; + DPTF_POWER = true; + DPTF_PCH_FIVR = true; + INTEL_IDLE = true; + + VIRTUALIZATION = true; + KVM = true; + KVM_INTEL = true; + KVM_SMM = true; + + IP_MULTICAST = true; + + IPV6_ROUTER_PREF = true; + IPV6_ROUTE_INFO = true; + IPV6_OPTIMISTIC_DAD = true; + + BT_INTEL = true; + BT_HCIBTUSB = true; + + EISA = true; + EISA_PCI_EISA = true; + EISA_VIRTUAL_ROOT = false; + EISA_NAMES = true; + + NVME_CORE = true; + BLK_DEV_NVME = true; + NVME_VERBOSE_ERRORS = true; + NVME_HWMON = true; + + MISC_RTSX = true; + INTEL_MEI = true; + MISC_RTSX_PCI = true; + + ETHERNET = true; + AQTION = true; + + WLAN = true; + IWLWIFI = true; + IWLMVM = true; + + INPUT_MOUSEDEV = true; + INPUT_JOYDEV = true; + + KEYBOARD_ATKBD = true; + + INPUT_MOUSE = true; + MOUSE_PS2 = true; + MOUSE_PS2_TRACKPOINT = true; + + INPUT_JOYSTICK = true; + + INTEL_PCH_THERMAL = true; + + MFD_CORE = true; + MFD_INTEL_LPSS_PCI = true; + + I2C = true; + I2C_I801 = true; + + SPI = true; + SPI_MEM = true; + SPI_INTEL_PCI = true; + + INT340X_THERMAL = true; + + VIDEO = true; + VGA_SWITCHEROO = true; + DRM = true; + DRM_FBDEV_EMULATION = true; + DRM_NOUVEAU = true; + DRM_NOUVEAU_SVM = true; + DRM_NOUVEAU_GSP_DEFAULT = true; + DRM_I915 = true; + + BACKLIGHT_CLASS_DEVICE = true; + + HDMI = true; + + SND_HDA_INTEL = true; + SND_HDA_HWDEP = true; + SND_HDA_CODEC_REALTEK = true; + SND_HDA_CODEC_HDMI = true; + SND_HDA_POWER_SAVE_DEFAULT = 2; + + SND_SOC = true; + SND_SOC_SOF_TOPLEVEL = true; + SND_SOC_SOF_PCI = true; + SND_SOC_SOF_INTEL_TOPLEVEL = true; + SND_SOC_SOF_TIGERLAKE = true; + SND_SOC_SOF_HDA_LINK = true; + SND_SOC_SOF_HDA_AUDIO_CODEC = true; + SND_SOC_DMIC = true; + + HID_LENOVO = true; + HID_LOGITECH = true; + + USB_ACM = true; + + USB_SERIAL = true; + USB_SERIAL_PL2303 = true; + + EDAC_IGEN6 = true; + + ACPI_WMI = true; + MXM_WMI = true; + THINKPAD_ACPI = true; + THINKPAD_ACPI_ALSA_SUPPORT = true; + THINKPAD_ACPI_VIDEO = true; + + INTEL_TURBO_MAX_3 = true; + INTEL_VSEC = true; + + INTEL_IOMMU = true; + INTEL_IOMMU_DEFAULT_ON = true; + + SOUNDWIRE = true; + SOUNDWIRE_INTEL = true; + + INTEL_IDMA64 = true; + + INTEL_RAPL = true; + + EXT4_FS = true; + EXT4_USE_FOR_EXT2 = true; + EXT4_FS_POSIX_ACL = true; + BTRFS_FS = true; + BTRFS_FS_POSIX_ACL = true; + FUSE_FS = true; + EXFAT_FS = true; + }); + }); + + hardware.cpu.clusters.performance = lib.range 0 11; + hardware.cpu.clusters.efficiency = lib.range 12 19; + hardware.cpu.intel.updateMicrocode = true; + + hardware.glasgow.enable = true; + + hardware.graphics.extraPackages = with pkgs; [ + intel-media-driver + ]; + + hardware.keyboard.qmk.enable = true; + hardware.nitrokey.enable = true; + + hardware.sane = { + enable = true; + extraBackends = [ pkgs.utsushi ]; + }; + + hardware.trackpoint = { + enable = true; + sensitivity = 255; + speed = 64; + }; + + hardware.uinput.enable = true; + + ephemeral.enable = true; + ephemeral.device = "UUID=039aa386-a39d-4329-bcf0-48936b938db1"; + ephemeral.boot.device = "PARTUUID=61c6f04c-0923-437e-860e-e88452b8e39e"; + ephemeral.boot.fsType = "vfat"; + ephemeral.subvolumes."/home" = { + options = [ "nodev" "nosuid" ]; + extraOptions = [ "noatime" "compress=zstd" ]; + }; + + networking.firewall.extraInputRules = '' + ip6 daddr { ff02::1:3, ff02::fb } udp dport 5353 accept + ip daddr { 224.0.0.251, 224.0.0.252 } udp dport 5353 accept + + ip6 daddr ff12::8384 udp dport 21027 accept + ip daddr 255.255.255.255 udp dport 21027 accept + + udp dport 4992 accept + ''; + + networking.hosts = { + "172.16.0.1" = [ "airlink.local" ]; + "192.168.178.1" = [ "fritz.box" ]; + }; + + networking.firewall.allowedTCPPorts = [ 5000 22000 ]; + networking.firewall.allowedUDPPorts = [ 4992 22000 ]; + networking.firewall.allowedUDPPortRanges = [ + { from = 6001; to = 6011; } + ]; + + programs.ssh.knownHosts."zh1830.rsync.net".publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJtclizeBy1Uo3D86HpgD3LONGVH0CJ0NT+YfZlldAJd"; + + services.beesd.filesystems.root = { + spec = "UUID=039aa386-a39d-4329-bcf0-48936b938db1"; + hashTableSizeMB = 1024; + verbosity = "crit"; + }; + + services.fprintd.enable = true; + + services.printing.enable = true; + services.printing.drivers = with pkgs; [ + brlaser + ]; + + services.udev.packages = with pkgs; [ utsushi ]; + + systemd.services."beesd@root" = { + bindsTo = [ "power-external.target" ]; + serviceConfig = { + IOSchedulingClass = "idle"; + CPUWeight = lib.mkForce "idle"; + }; + }; + + users.users.nil.hashedPasswordFile = "/etc/keys/users/nil"; + users.users.nil.extraGroups = [ + "audio" "input" "uinput" "plugdev" "video" "render" "scanner" "nitrokey" + ]; + + nix.distributedBuilds = true; + nix.buildMachines = [ + { + hostName = "build-worker-03.nyantec.com"; + maxJobs = 16; + publicHostKey = "c3NoLWVkMjU1MTkgQUFBQUMzTnphQzFsWkRJMU5URTVBQUFBSUVHcVRZNzRjNWcxNURTTlBOTTJXZHI1akF3UzdCRmdYMVhSbmh0R09uSmMgcm9vdEBidWlsZC13b3JrZXItMDMK"; + sshKey = "/etc/keys/nix-ssh"; + sshUser = "nix-ssh"; + supportedFeatures = [ "kvm" "nixos-test" "benchmark" "big-parallel" "gccarch-x86-64-v3" ]; + system = "x86_64-linux"; + } + { + hostName = "build-worker-04.nyantec.com"; + maxJobs = 16; + publicHostKey = "c3NoLWVkMjU1MTkgQUFBQUMzTnphQzFsWkRJMU5URTVBQUFBSUNPcSs1SStubEFOMmxKb090b1hyWUVEdVovVE1QTWE0M3BJbGFibFlpZ0sgcm9vdEBidWlsZC13b3JrZXItMDQK"; + sshKey = "/etc/keys/nix-ssh"; + sshUser = "nix-ssh"; + supportedFeatures = [ "kvm" "nixos-test" "benchmark" "big-parallel" "gccarch-x86-64-v3" ]; + system = "x86_64-linux"; + } + ]; +} diff --git a/nixos/config/solitary.nix b/nixos/config/solitary.nix new file mode 100644 index 0000000..1de506f --- /dev/null +++ b/nixos/config/solitary.nix @@ -0,0 +1,738 @@ +{ self, ... }: { lib, config, pkgs, ... }: + +with lib; let + ports = { + acme = 1360; + nginx = 8080; + synapse = 8008; + syncv3 = 8009; + unbound = 8484; + }; + + security-txt = pkgs.writeText "security.txt" '' + -----BEGIN PGP SIGNED MESSAGE----- + Hash: SHA512 + + Canonical: https://solitary.social/.well-known/security.txt + Contact: mailto:mvs@nya.yt + Encryption: openpgp4fpr:950623eb2f52402e0cf56ccbee49e25700058dd6 + Preferred-Languages: en, de + -----BEGIN PGP SIGNATURE----- + + iHUEARYKAB0WIQRbjUmg6ccaTk940M7ZkbGDPEZ7AwUCYz2XrwAKCRDZkbGDPEZ7 + A4w5AQD3Mzb5Bi8CERe3j3NjQhgeEkMVBcfM3RumuWdjs6i+LgD9HHuY3Bp6ljtR + LnLJRZt4Q8CYKoPaYkSO0vBaYKmUnwY= + =iQpI + -----END PGP SIGNATURE----- + ''; +in { + imports = with self.nixosModules; [ + default + headless + acme-ocsp + ]; + + boot.loader.grub = { + enable = true; + device = "/dev/vda"; + }; + + boot.kernelPackages = let + inherit (self.packages.x86_64-linux) linux-hardened; + in pkgs.linuxPackagesFor (linux-hardened.override { + instSetArch = "x86-64-v3"; + extraConfig = linux-hardened.profile.paravirt; + }); + + environment.etc."machine-id".text = "1c97ae368741530de77aad42b5a6ae42"; + + ephemeral.device = "UUID=07a91cc3-4dd4-48e6-81d7-eb5d31fcf720"; + ephemeral.boot.device = "UUID=24c72e0c-b467-4def-a641-ae09100465f0"; + ephemeral.boot.fsType = "ext4"; + + i18n.supportedLocales = [ "C.UTF-8/UTF-8" "en_EU.UTF-8/UTF-8" "en_GB.UTF-8/UTF-8" ]; + + networking = { + hostName = "solitary"; + domain = "social"; + firewall.allowedTCPPorts = [ 22 80 443 853 ]; + firewall.allowedUDPPorts = [ 443 ]; + }; + + security.acme = { + certs.${config.networking.fqdn} = { + email = "mvs@nya.yt"; + listenHTTP = "127.0.0.1:${toString ports.acme}"; + reloadServices = [ "haproxy.service" "unbound.service" ]; + extraDomainNames = [ + "cache.solitary.social" + "matrix.solitary.social" + "media.solitary.social" + "resolve.solitary.social" + "syncv3.solitary.social" + ]; + }; + }; + + services.akkoma.enable = true; + services.akkoma.extraStatic."emoji/blobs.gg" = pkgs.akkoma-emoji.blobs_gg; + services.akkoma.extraStatic."static/terms-of-service.html" = pkgs.writeText "terms-of-service.html" '' +

Commitments

+

This is currently a single‐user instance and therefore I decided to formulate what would be Terms of Service for a multi‐user user instance as commitments. These are still incomplete and subject to expansion in the future.

+
    +
  • I shall observe and respect your boundaries.
  • +
  • I shall respect your right to disengage, and support you if you wish to disengage from others.
  • +
  • I shall accept that you may not want to be confronted with certain content and tag my posts appropriately.
  • +
+ ''; + + services.akkoma.extraStatic."favicon.png" = let + rev = "697a8211b0f427a921e7935a35d14bb3e32d0a2c"; + in pkgs.stdenvNoCC.mkDerivation { + name = "favicon.png"; + + src = pkgs.fetchurl { + url = "https://raw.githubusercontent.com/TilCreator/NixOwO/${rev}/NixOwO_plain.svg"; + hash = "sha256-tWhHMfJ3Od58N9H5yOKPMfM56hYWSOnr/TGCBi8bo9E="; + }; + + nativeBuildInputs = with pkgs; [ librsvg ]; + + dontUnpack = true; + installPhase = '' + rsvg-convert -o $out -w 96 -h 96 $src + ''; + }; + + services.akkoma.config = let + elixir = pkgs.formats.elixirConf { }; + in with elixir.lib; { + ":pleroma" = { + ":instance" = { + name = "solitary.social"; + email = "mvs+solitary.social@nya.yt"; + notify_email = "akkoma@solitary.social"; + description = "Single‐user fediverse instance"; + instance_thumbnail = "/instance/thumbnail.avif"; + limit = 5120; + description_limit = 5120; + remote_limit = 131072; + upload_limit = 160 * 1024 * 1024; + avatar_upload_limit = 2097152; + background_upload_limit = 4194304; + banner_upload_limit = 4194304; + registrations_open = false; + account_approval_required = true; + remote_post_retention_days = 180; + user_bio_length = 5120; + user_name_length = 64; + max_account_fields = 8; + cleanup_attachments = true; + }; + + "Pleroma.Web.Endpoint" = { + secret_key_base._secret = "/var/lib/secrets/akkoma/key-base"; + signing_salt._secret = "/var/lib/secrets/akkoma/signing-salt"; + live_view.signing_salt._secret = "/var/lib/secrets/akkoma/liveview-salt"; + }; + + "Pleroma.Emails.Mailer" = { + enabled = true; + adapter = mkRaw "Swoosh.Adapters.SMTP"; + relay = "localhost"; + dkim = { + a = "ed25519-sha256"; + s = "akkoma"; + d = config.networking.fqdn; + private_key = mkTuple [ + (mkAtom ":pem_plain") + (mkRaw ''File.read!("/var/lib/akkoma/dkim.pem")'') + ]; + }; + }; + + ":database".rum_enabled = true; + + ":media_proxy" = { + enabled = true; + base_url = "https://cache.solitary.social"; + proxy_opts.redirect_on_failure = true; + proxy_opts.max_body_length = 64 * 1024 * 1024; + }; + + ":media_preview_proxy" = { + enabled = false; + thumbnail_max_width = 1920; + thumbnail_max_height = 1080; + min_content_length = 128 * 1024; + }; + + "Pleroma.Upload".base_url = "https://media.solitary.social"; + + "Pleroma.Upload".filters = map mkRaw [ + "Pleroma.Upload.Filter.Exiftool.ReadDescription" + "Pleroma.Upload.Filter.Exiftool.StripMetadata" + "Pleroma.Upload.Filter.Dedupe" + "Pleroma.Upload.Filter.AnonymizeFilename" + ]; + + ":mrf".policies = map mkRaw [ + "Pleroma.Web.ActivityPub.MRF.SimplePolicy" + "Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy" + ]; + + ":mrf_simple" = { + reject = mkMap { + "bae.st" = "harassment"; + "brighteon.social" = "incompatible"; + "detroitriotcity.com" = "incompatible"; + "freeatlantis.com" = "incompatible"; + "freespeechextremist.com" = "incompatible"; + "gab.com" = "incompatible"; + "gleasonator.com" = "incompatible"; + "kitsunemimi.club" = "incompatible"; + "poa.st" = "incompatible"; + "seal.cafe" = "harassment"; + "social.quodverum.com" = "incompatible"; + "spinster.xyz" = "incompatible"; + "truthsocial.co.in" = "incompatible"; + "varishangout.net" = "incompatible"; + + "activitypub-troll.cf" = "security"; + "misskey-forkbomb.cf" = "security"; + "repl.co" = "security"; + }; + + followers_only = mkMap { + "bitcoinhackers.org" = "annoying"; + }; + }; + + ":mrf_object_age".threshold = 90 * 24 * 3600; + + ":frontend_configurations" = { + pleroma_fe = mkMap { + collapseMessageWithSubject = true; + hideSiteFavicon = true; + streaming = true; + webPushNotifications = true; + useStreamingApi = true; + scopeCopy = true; + showFeaturesPanel = false; + subjectLineBehavior = "masto"; + alwaysShowSubjectInput = true; + postContentType = "text/markdown"; + modalOnRepeat = true; + minimalScopesMode = true; + redirectRootNoLogin = "/mkl"; + translationLanguage = "EN"; + }; + }; + + ":restrict_unauthenticated" = { + timelines = mkMap { + local = false; + federated = true; + }; + }; + + ":translator" = { + enabled = true; + module = mkRaw "Pleroma.Akkoma.Translators.DeepL"; + }; + + ":deepl" = { + tier = mkAtom ":free"; + api_key._secret = "/var/lib/secrets/akkoma/deepl"; + }; + }; + + ":web_push_encryption".":vapid_details" = { + subject = "mailto:mvs+solitary.social@nya.yt"; + public_key = "BPwdJZjBeZw_ZkWU_RQ48RdPI2pHIhMAYaNJc6xut4nQRi2YSaKnfP_kLrXzRjETQh5VJsDI-azYCeEhtk-C33s"; + private_key._secret = "/var/lib/secrets/akkoma/vapid"; + }; + + ":joken".":default_signer"._secret = "/var/lib/secrets/akkoma/jwt-signer"; + }; + + services.haproxy.enable = true; + services.haproxy.config = + let + ciphers = "ECDHE+CHACHA20:ECDHE+AESGCM"; + cipherSuites = "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256"; + options = "ssl-min-ver TLSv1.2 no-tls-tickets"; + acmeDir = config.security.acme.certs.${config.networking.fqdn}.directory; + compTypes = [ + "application/javascript" + "application/json" + "image/svg+xml" + "text/css" + "text/html" + "text/javascript" + "text/plain" + ]; + in '' + global + expose-experimental-directives + + log stderr format short alert notice + + maxconn 9216 + nbthread 2 + cpu-map auto:1/all 0-63 + + ssl-default-bind-ciphers ${ciphers} + ssl-default-bind-ciphersuites ${cipherSuites} + ssl-default-bind-options prefer-client-ciphers ${options} + + ssl-default-server-ciphers ${ciphers} + ssl-default-server-ciphersuites ${cipherSuites} + ssl-default-server-options ${options} + + defaults + log global + mode http + option abortonclose + option checkcache + option forwardfor + option http-keep-alive + option http-restrict-req-hdr-names reject + option httpchk + option splice-auto + option tcp-smart-connect + + timeout connect 5s + timeout client 30s + timeout http-request 5s + timeout client-fin 5s + timeout tunnel 1h + timeout server 30s + timeout check 5s + + cache default + total-max-size 16 + max-age 240 + + frontend http + bind :::443 v4v6 defer-accept tfo ssl crt ${acmeDir}/full.pem allow-0rtt alpn h2,http/1.1 + bind quic6@:443 v4v6 ssl crt ${acmeDir}/full.pem allow-0rtt alpn h3 + bind :::80 v4v6 defer-accept tfo + + acl replay-safe method GET HEAD OPTIONS req.body_size eq 0 + + acl host-solitary hdr(host),host_only solitary.social + acl host-cache hdr(host),host_only cache.solitary.social + acl host-media hdr(host),host_only media.solitary.social + acl host-matrix hdr(host),host_only matrix.solitary.social + acl host-syncv3 hdr(host),host_only syncv3.solitary.social + acl host-resolve hdr(host),host_only resolve.solitary.social + + acl path-acme path_dir /.well-known/acme-challenge + acl path-security.txt path /.well-known/security.txt + acl path-matrix-well-known path_dir /.well-known/matrix + acl path-proxy path_dir /proxy + acl path-media path_dir /media + + #http-request normalize-uri fragment-strip + #http-request normalize-uri path-strip-dot + #http-request normalize-uri path-strip-dotdot full + #http-request normalize-uri path-merge-slashes + #http-request normalize-uri percent-decode-unreserved strict + #http-request normalize-uri percent-to-uppercase strict + #http-request normalize-uri query-sort-by-name + + http-request redirect scheme https code 301 unless { ssl_fc } or path-acme + http-request wait-for-handshake unless replay-safe + + http-response set-tos 20 if path-acme # AF22 (low‐latency, med drop) + http-response set-tos 20 if host-resolve # AF22 (low‐latency, med drop) + http-response set-tos 10 if host-matrix # AF11 (high‐throughput, low drop) + http-response set-tos 10 if host-syncv3 # AF11 (high‐throughput, low drop) + http-response set-tos 12 if host-solitary # AF12 (high‐throughput, med drop) + http-response set-tos 14 if host-media # AF13 (high‐throughput, high drop) + http-response set-tos 14 if host-cache # AF13 (high‐throughput, high drop) + + http-request cache-use default + http-request set-header X-Forwarded-Proto %[ssl_fc,iif(https,http)] + + acl no-coep res.hdr(Cross-Origin-Embedder-Policy) -m len 0 + acl no-coop res.hdr(Cross-Origin-Opener-Policy) -m len 0 + acl no-corp res.hdr(Cross-Origin-Resource-Policy) -m len 0 + acl no-csp res.hdr(Content-Security-Policy) -m len 0 + acl no-rp res.hdr(Referrer-Policy) -m len 0 + + http-response set-header Alt-Svc "h3=\":443\"" + http-response set-header Cross-Origin-Embedder-Policy require-corp if no-coep + http-response set-header Cross-Origin-Opener-Policy same-origin if no-coop + http-response set-header Cross-Origin-Resource-Policy same-origin if no-corp + http-response set-header Content-Security-Policy "default-src 'self'; frame-ancestors 'none'" if no-csp + http-response set-header Referrer-Policy same-origin if no-rp + http-response set-header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload" + http-response set-header X-Frame-Options DENY + http-response set-header X-Content-Type-Options nosniff + http-response set-header X-XSS-Protection "1; mode=block" + + compression algo gzip + compression type ${concatStringsSep " " compTypes} + http-response cache-store default + + http-request redirect code 308 location https://media.solitary.social%[capture.req.uri,regsub("^/media","")] if host-solitary path-media + http-request redirect code 308 location https://media.solitary.social%[capture.req.uri,regsub("^/media","")] if host-media path-media + http-request redirect code 308 location https://cache.solitary.social%[capture.req.uri] if host-solitary path-proxy + http-request set-path "/media%[path]" if host-media !path-media + + use_backend acme if path-acme + use_backend security.txt if path-security.txt + use_backend unbound if host-resolve + use_backend synapse if host-matrix + use_backend syncv3 if host-syncv3 + use_backend wellknown-matrix if host-solitary path-matrix-well-known + use_backend nginx if host-cache + use_backend akkoma if host-solitary + use_backend akkoma if host-media + default_backend notfound + + backend acme + server acme 127.0.0.1:${toString ports.acme} + retry-on all-retryable-errors + + backend akkoma + server akkoma /run/akkoma/socket + + backend nginx + server nginx [::1]:${toString ports.nginx} tfo proto h2 + retry-on conn-failure empty-response response-timeout + + backend synapse + server synapse [::1]:${toString ports.synapse} + + backend syncv3 + server syncv3 [::1]:${toString ports.syncv3} + + backend unbound + server unbound [::1]:${toString ports.unbound} tfo ssl ssl-min-ver TLSv1.3 alpn h2 allow-0rtt ca-file ${acmeDir}/chain.pem + retry-on conn-failure empty-response response-timeout 0rtt-rejected + + backend security.txt + http-request return status 200 content-type text/plain file ${security-txt} if { path /.well-known/security.txt } + + backend wellknown-matrix + http-request return status 200 content-type application/json file ${pkgs.writeText "client.json" (builtins.toJSON { + "m.homeserver".base_url = config.services.matrix-synapse.settings.public_baseurl; + "m.identity_server".base_url = "https://vector.im"; + "org.matrix.msc3575.proxy".url = "https://syncv3.solitary.social"; + })} if { path /.well-known/matrix/client } + + http-request return status 200 content-type application/json file ${pkgs.writeText "server.json" (builtins.toJSON { + "m.server" = "matrix.solitary.social:443"; + })} if { path /.well-known/matrix/server } + + backend notfound + http-request return status 404 + ''; + + services.matrix-synapse.enable = true; + services.matrix-synapse.settings = { + database_type = "psycopg2"; + server_name = "solitary.social"; + public_baseurl = "https://matrix.solitary.social/"; + default_identity_server = "https://vector.im"; + enable_registration = false; + + listeners = [ { + bind_addresses = [ "::1" ]; + port = ports.synapse; + type = "http"; + tls = false; + x_forwarded = true; + + resources = [ { + names = [ "client" "federation" ]; + compress = true; + } ]; + } ]; + + log_config = ./log_config.yaml; + }; + + services.nginx = { + enable = true; + + package = pkgs.tengine; + + recommendedGzipSettings = true; + recommendedOptimisation = true; + recommendedProxySettings = true; + + commonHttpConfig = '' + charset utf-8; + proxy_cache_path /var/cache/nginx/cache/akkoma_media_cache + levels= keys_zone=akkoma_media_cache:16m max_size=16g + inactive=1y use_temp_path=off; + access_log off; + + set_real_ip_from ::1; + real_ip_header X-Forwarded-For; + ''; + }; + + services.matrix-sliding-sync = { + enable = true; + environmentFile = "/etc/keys/sliding-sync.env"; + settings = { + SYNCV3_BINDADDR = "[::1]:${toString ports.syncv3}"; + SYNCV3_LOG_LEVEL = "warn"; + SYNCV3_SERVER = "https://matrix.solitary.social"; + }; + }; + + services.nginx.virtualHosts."cache.solitary.social" = { + listen = [ { + addr = "[::1]"; + port = ports.nginx; + extraParameters = [ "http2" "fastopen=512" ]; + } ]; + locations."/" = { + proxyPass = "http://unix:/run/akkoma/socket"; + extraConfig = '' + proxy_cache akkoma_media_cache; + slice 1m; + proxy_cache_key $host$uri$is_args$args$slice_range; + proxy_set_header Range $slice_range; + + proxy_buffering on; + proxy_cache_lock on; + proxy_ignore_client_abort on; + + proxy_cache_valid 200 1y; + proxy_cache_valid 206 301 304 1h; + + proxy_cache_use_stale error timeout invalid_header updating; + ''; + }; + }; + + services.postfix = { + enable = true; + destination = [ ]; + localRecipients = [ ]; + networks = [ "localhost" ]; + hostname = config.networking.fqdn; + masterConfig.smtp_inet.name = mkForce "localhost:smtp"; + }; + + services.postgresql = { + enable = true; + package = pkgs.postgresql_14; + + extraPlugins = with pkgs.postgresql_14.pkgs; [ + rum + ]; + + initialScript = pkgs.writeText "init.psql" '' + CREATE ROLE "matrix-synapse"; + CREATE DATABASE "matrix-synapse" OWNER "matrix-synapse" + TEMPLATE template0 + ENCODING 'utf8' + LOCALE 'C'; + ''; + }; + + services.unbound = { + enable = true; + + package = pkgs.unbound-with-systemd.override { + withDoH = true; + withTFO = true; + }; + + enableRootTrustAnchor = true; + }; + + + services.unbound.settings = { + server = let + acmeDir = config.security.acme.certs.${config.networking.fqdn}.directory; + num-threads = 2; + in { + inherit num-threads; + + interface = [ + "::1@53" + "127.0.0.1@53" + + "::1@${toString ports.unbound}" + + "::@853" + "0.0.0.0@853" + ]; + + so-reuseport = true; + ip-dscp = 20; + outgoing-range = 8192; + edns-buffer-size = 1472; + udp-upstream-without-downstream = true; + num-queries-per-thread = 4096; + incoming-num-tcp = 1024; + outgoing-num-tcp = 16; + stream-wait-size = "64m"; + msg-cache-size = "128m"; + msg-cache-slabs = num-threads; + rrset-cache-size = "256m"; + rrset-cache-slabs = num-threads; + infra-cache-slabs = num-threads; + key-cache-slabs = num-threads; + cache-min-ttl = 60; + cache-max-negative-ttl = 360; + prefer-ip6 = true; + tls-service-pem = "${acmeDir}/fullchain.pem"; + tls-service-key = "${acmeDir}/key.pem"; + https-port = ports.unbound; + http-query-buffer-size = "64m"; + http-response-buffer-size = "64m"; + access-control = [ "::/0 allow" "0.0.0.0/0 allow" ]; + harden-dnssec-stripped = true; + hide-identity = true; + hide-version = true; + prefetch = true; + prefetch-key = true; + serve-expired-client-timeout = 1800; + }; + }; + + systemd = let + backendServices = [ + "akkoma.service" + "matrix-synapse.service" + "nginx.service" + "unbound.service" + ]; + in { + services.akkoma.confinement.enable = false; + services.akkoma.serviceConfig.BindReadOnlyPaths = [ "/var/lib/akkoma:/var/lib/akkoma:norbind" ]; + + services.haproxy = { + confinement.enable = false; + + wants = [ "acme-finished-${config.networking.fqdn}.service" ] + ++ backendServices; + after = [ "acme-selfsigned-${config.networking.fqdn}.service" ] + ++ backendServices; + before = [ "acme-${config.networking.fqdn}.service" ]; + + reloadTriggers = [ "${config.security.acme.certs.${config.networking.fqdn}.directory}/cert.ocsp" ]; + + serviceConfig = { + BindReadOnlyPaths = [ + "/etc/haproxy.cfg" + "/etc/hosts" + "/etc/resolv.conf" + "/run/akkoma" + config.security.acme.certs."solitary.social".directory + security-txt + ]; + + CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ]; + SocketBindAllow = [ "tcp:80" "tcp:443" "udp:443" ]; + SocketBindDeny = "any"; + }; + }; + + services.matrix-sliding-sync = { + after = [ "matrix-synapse.service" ]; + serviceConfig.ReadOnlyPaths = [ + "/run/postgres" + ]; + }; + + services.nginx = { + confinement.enable = true; + after = [ "akkoma.service" ]; + serviceConfig = { + BindReadOnlyPaths = [ + "/etc/hosts" + "/etc/resolv.conf" + "/run" + ]; + + BindPaths = [ + "/var/cache/nginx" + ]; + + ProtectSystem = mkForce false; + SocketBindAllow = [ "tcp:${toString ports.nginx}" ]; + SocketBindDeny = "any"; + RestrictNetworkInterfaces = [ "lo" ]; + }; + }; + + services.unbound = { + wants = [ "acme-finished-${config.networking.fqdn}.service" ]; + after = [ "acme-selfsigned-${config.networking.fqdn}.service" ]; + }; + + services.synapse-compress-state = { + confinement.enable = true; + + after = [ "postgresql.service" ]; + description = "Compress Synapse state tables"; + serviceConfig = { + Type = "oneshot"; + ExecStart = '' + ${pkgs.matrix-synapse-tools.rust-synapse-compress-state}/bin/synapse_auto_compressor \ + -p "host=/run/postgresql \ + user=${config.services.matrix-synapse.settings.database.args.database} \ + dbname=${config.services.matrix-synapse.settings.database.args.database}" \ + -c 512 -n 128 + ''; + User = "matrix-synapse"; + WorkingDirectory = "/tmp"; + + BindReadOnlyPaths = [ + "/run/postgresql" + ]; + + ProtectProc = "noaccess"; + ProcSubset = "pid"; + ProtectHome = true; + PrivateTmp = true; + PrivateDevices = true; + PrivateIPC = true; + ProtectHostname = true; + ProtectClock = true; + ProtectKernelTunables = true; + ProtectKernelModules = true; + ProtectKernelLogs = true; + ProtectControlGroups = true; + + RestrictAddressFamilies = [ "AF_UNIX" ]; + RestrictNamespaces = true; + LockPersonality = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + RemoveIPC = true; + + CapabilityBoundingSet = null; + NoNewPrivileges = true; + SystemCallFilter = [ "@system-service" "~@resources" "~@privileged" ]; + SystemCallArchitectures = "native"; + + UMask = "0077"; + }; + }; + + timers.synapse-compress-state = { + enable = true; + description = "Compress Synapse state tables daily"; + timerConfig = { + OnCalendar = "04:00"; + }; + + wantedBy = [ "timers.target" ]; + }; + }; + + users.users.${config.services.haproxy.user}.extraGroups = [ config.security.acme.certs.${config.networking.fqdn}.group ]; + users.users.${config.services.unbound.user}.extraGroups = [ config.security.acme.certs.${config.networking.fqdn}.group ]; +} diff --git a/nixos/module/acme-ocsp.nix b/nixos/module/acme-ocsp.nix new file mode 100644 index 0000000..3d559f7 --- /dev/null +++ b/nixos/module/acme-ocsp.nix @@ -0,0 +1,85 @@ +{ ... }: { config, pkgs, lib, ...}: + +let + cfg = config.security.acme; + + script = pkgs.writeShellApplication { + name = "ocsp-query"; + runtimeInputs = with pkgs; [ openssl ]; + text = '' + cd "$1" + + tmp="$(mktemp ocsp.der.XXXXXXXXXX)" + trap 'rm -f "$tmp"' EXIT TERM + + url="$(openssl x509 -in cert.pem -noout -ocsp_uri)" + openssl ocsp -issuer chain.pem -cert cert.pem -url "$url" -respout "$tmp" + + chown "$(id -u):$(id -g)" "$tmp" + chmod 644 "$tmp" + mv "$tmp" ocsp.der + + ln -s -f ocsp.der full.ocsp + ''; + }; +in { + options.security.acme.ocspTimer = lib.mkOption { + type = with lib.types; nullOr nonEmptyStr; + default = "daily"; + description = "Realtime (wall clock) timer for regular OCSP queries."; + }; + + config = lib.mkIf (cfg.ocspTimer != null) { + systemd.services = lib.mapAttrs' (cert: conf: lib.nameValuePair "ocsp-${cert}" { + description = "Query OCSP endpoint for ${cert}"; + after = [ "network.target" "network-online.target" "acme-${cert}.service" ]; + wants = [ "network.target" "network-online.target" "acme-${cert}.service" ]; + + confinement.enable = true; + confinement.packages = with pkgs; [ openssl ]; + + serviceConfig = { + Type = "oneshot"; + + User = "acme"; + Group = conf.group; + UMask = "0022"; + + BindPaths = [ conf.directory ]; + + ExecStart = "${script}/bin/ocsp-query ${lib.escapeShellArg conf.directory}"; + + ProtectProc = "noaccess"; + ProcSubset = "pid"; + ProtectHome = true; + PrivateTmp = true; + PrivateDevices = true; + PrivateIPC = true; + ProtectHostname = true; + ProtectClock = true; + ProtectKernelTunables = true; + ProtectKernelModules = true; + ProtectKernelLogs = true; + ProtectControlGroups = true; + RestrictAddressFamilies = ["AF_INET" "AF_INET6" ]; + RestrictNamespaces = true; + LockPersonality = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + RemoveIPC = true; + CapabilityBoundingSet = null; + NoNewPrivileges = true; + SystemCallFilter = [ "@system-service" "~@privileged" "@chown" ]; + SystemCallArchitectures = "native"; + DeviceAllow = null; + DevicePolicy = "closed"; + SocketBindDeny = "any"; + }; + }) cfg.certs; + + systemd.timers = lib.mapAttrs' (cert: conf: lib.nameValuePair "ocsp-${cert}" { + description = "Query OCSP endpoint for ${cert} regularly"; + timerConfig.OnCalendar = cfg.ocspTimer; + }) cfg.certs; + }; +} diff --git a/nixos/module/broken.nix b/nixos/module/broken.nix new file mode 100644 index 0000000..912090f --- /dev/null +++ b/nixos/module/broken.nix @@ -0,0 +1,7 @@ +{ ... }: { config, lib, ... }: { + nixpkgs.config = { + permittedInsecurePackages = [ + "jitsi-meet-1.0.8043" + ]; + }; +} diff --git a/nixos/module/btrfs.nix b/nixos/module/btrfs.nix new file mode 100644 index 0000000..1199c12 --- /dev/null +++ b/nixos/module/btrfs.nix @@ -0,0 +1,66 @@ +{ self, ... }: { config, lib, pkgs, ... }: let + monthly = { + OnCalendar = "monthly"; + RandomizedDelaySec = "1w"; + }; + + timers = { + "btrfs-scrub@nix" = monthly; + "btrfs-scrub@home" = monthly; + "btrfs-scrub@var" = monthly; + "btrfs-balance@nix" = monthly; + }; +in { + imports = with self.nixosModules; [ + powersupply + ]; + + systemd = { + services = + let + btrfs = "${pkgs.btrfs-progs}/bin/btrfs"; + + service = serviceConfig: { + unitConfig = { + ConditionPathIsMountPoint = "%f"; + RequiresMountsFor = "%f"; + Requisite = [ "power-external.target" ]; + StopPropagatedFrom = [ "power-external.target" ]; + }; + + serviceConfig = { + Type = "exec"; + KillSignal = "SIGINT"; + + CPUSchedulingPolicy = "batch"; + IOSchedulingClass = "idle"; + CPUWeight = "idle"; + } // serviceConfig; + }; + in { + "btrfs-scrub@" = service { + ExecStart = "${btrfs} scrub start -B %f"; + BindPaths = [ "%f:%f:norbind" ]; + }; + + "btrfs-balance@" = service { + ExecStart = "${btrfs} balance start -dusage=10 -musage=5 %f"; + }; + } // lib.mapAttrs (name: _: { + overrideStrategy = "asDropin"; + }) timers; + + timers = lib.mapAttrs (name: timerConfig: { + bindsTo = [ "power-external.target" ]; + + unitConfig = { + ConditionPathIsMountPoint = "%f"; + RequiresMountsFor = "%f"; + }; + + timerConfig = timerConfig // { + Persistent = true; + }; + }) timers; + }; +} diff --git a/nixos/module/clusters.nix b/nixos/module/clusters.nix new file mode 100644 index 0000000..32fc8f2 --- /dev/null +++ b/nixos/module/clusters.nix @@ -0,0 +1,46 @@ +{ ... }: { config, lib, ... }: + +let + cfg = config.hardware.cpu.clusters; + + concat = lib.concatMapStringsSep "," toString; + performance = concat cfg.performance; + efficiency = concat cfg.efficiency; +in { + options = { + hardware.cpu.clusters = { + performance = lib.mkOption { + type = with lib.types; listOf ints.unsigned; + default = [ ]; + description = "List of performance CPUs"; + }; + + efficiency = lib.mkOption { + type = with lib.types; listOf ints.unsigned; + default = [ ]; + description = "List of efficiency CPUs"; + }; + }; + }; + + config = lib.mkIf (cfg.performance != [ ] && cfg.efficiency != [ ]) { + boot.kernelParams = [ + "irqaffinity=${efficiency}" + "nohz_full=${performance}" + "rcu_nocbs=all" + ]; + + systemd.slices = lib.genAttrs [ "system" ] (slice: { + sliceConfig.AllowedCPUs = efficiency; + }); + + systemd.user.slices = lib.genAttrs [ "session" "app" ] (slice: { + sliceConfig.AllowedCPUs = efficiency; + }); + + assertions = lib.singleton { + assertion = lib.mutuallyExclusive cfg.performance cfg.efficiency; + message = "Performance and efficiency clusters must not overlap"; + }; + }; +} diff --git a/nixos/module/datacow.nix b/nixos/module/datacow.nix new file mode 100644 index 0000000..42071e1 --- /dev/null +++ b/nixos/module/datacow.nix @@ -0,0 +1,15 @@ +{ ... }: { config, lib, pkgs, ... }: + +let + cfg = config.services; + + noDataCow = dir: '' + mkdir -p ${lib.escapeShellArg dir} + ${pkgs.e2fsprogs}/bin/chattr +C ${lib.escapeShellArg dir} + ''; +in { + systemd.services.mysql.preStart = lib.mkIf cfg.mysql.enable + (lib.mkBefore (noDataCow cfg.mysql.dataDir)); + systemd.services.postgresql.preStart = lib.mkIf cfg.postgresql.enable + (lib.mkBefore (noDataCow cfg.postgresql.dataDir)); +} diff --git a/nixos/module/default.nix b/nixos/module/default.nix new file mode 100644 index 0000000..e5522d6 --- /dev/null +++ b/nixos/module/default.nix @@ -0,0 +1,82 @@ +{ self, ... }: { config, lib, pkgs, ... }: { + imports = with self.nixosModules; [ + broken + btrfs + clusters + datacow + email + ephemeral + iosched + kernel + locale-en_EU + network + nix + openssh + powersupply + security + users + zram + ]; + + #boot.initrd.systemd.enable = true; + boot.tmp.useTmpfs = true; + + documentation = { + dev.enable = true; + doc.enable = false; + info.enable = false; + man.generateCaches = false; + }; + + environment = { + binsh = "${pkgs.dash}${pkgs.dash.shellPath}"; + + shellAliases = builtins.mapAttrs (name: lib.mkOverride 999) { + ls = null; + ll = null; + l = null; + }; + + systemPackages = with pkgs; [ + # Terminfo + kitty.terminfo + + # Utilities + (lib.meta.setPrio 0 uutils-coreutils-noprefix) + + # Hardware info + pciutils + usbutils + ]; + }; + + hardware.block = { + defaultScheduler = "kyber"; + defaultSchedulerRotational = "bfq"; + scheduler = { + "mmcblk*" = "bfq"; + }; + }; + + hardware.enableRedistributableFirmware = false; + hardware.firmware = with pkgs; [ + linux-firmware + #alsa-firmware + sof-firmware + ]; + + ephemeral.enable = lib.mkDefault true; + + location.provider = lib.mkIf config.hardware.graphics.enable "geoclue2"; + + services.dbus.implementation = "broker"; + services.lvm.enable = lib.mkDefault false; + + #system.etc.overlay.enable = true; + + system.stateVersion = "24.11"; + + time.timeZone = lib.mkDefault "CET"; + + users.mutableUsers = false; +} diff --git a/nixos/module/email.nix b/nixos/module/email.nix new file mode 100644 index 0000000..143981e --- /dev/null +++ b/nixos/module/email.nix @@ -0,0 +1,5 @@ +{ ... }: { lib, ... }: { + services.postfix.config = lib.mkDefault { + smtpd_tls_security_level = "may"; + }; +} diff --git a/nixos/module/ephemeral.nix b/nixos/module/ephemeral.nix new file mode 100644 index 0000000..a757c7c --- /dev/null +++ b/nixos/module/ephemeral.nix @@ -0,0 +1,237 @@ +{ ... }: { config, lib, ...}: + +let + cfg = config.ephemeral; + + device = lib.mkOption { + type = lib.types.nonEmptyStr; + description = "Device to mount."; + }; + + options = lib.mkOption { + type = with lib.types; listOf nonEmptyStr; + readOnly = true; + description = "Options used to mount the file system."; + }; + + extraOptions = lib.mkOption { + type = with lib.types; listOf nonEmptyStr; + default = [ ]; + description = "Additional options used to mount the file system."; + }; + + filesystem = { + options = { + inherit device options extraOptions; + fsType = lib.mkOption { + type = lib.types.nonEmptyStr; + description = "Type of the file system."; + }; + }; + }; + + tmpfs = { + options = { + inherit options extraOptions; + name = lib.mkOption { + type = lib.types.nonEmptyStr; + default = "none"; + description = "Name of the file system."; + }; + + size = lib.mkOption { + type = with lib.types; either nonEmptyStr ints.positive; + description = "Size of the file system."; + }; + + mode = lib.mkOption { + type = lib.types.nonEmptyStr; + description = "Initial permissions of the root directory."; + }; + + uid = lib.mkOption { + type = with lib.types; either nonEmptyStr ints.unsigned; + default = 0; + description = "Initial user ID of the root directory"; + }; + + gid = lib.mkOption { + type = with lib.types; either nonEmptyStr ints.unsigned; + default = 0; + description = "Initial group ID of the root directory"; + }; + }; + }; + + subvol = { + options = { + inherit options extraOptions; + subvolume = lib.mkOption { + type = with lib.types; nullOr nonEmptyStr; + default = null; + description = "Source path of the subvolume."; + }; + }; + }; + + ephemeralDefaults = { + "/" = { + size = "64m"; + mode = "755"; + uid = 0; + gid = 0; + options = [ "nodev" "noexec" "nosuid" ]; + extraOptions = [ ]; + }; + "/run/nix" = { + size = "80%"; + mode = "1775"; + uid = 0; + gid = "nixbld"; + options = [ "nodev" "nosuid" ]; + extraOptions = [ ]; + }; + "/tmp" = { + size = "256m"; + mode = "1777"; + uid = 0; + gid = 0; + options = [ "nodev" "noexec" "nosuid" ]; + extraOptions = [ ]; + }; + }; + + subvolumeDefaults = { + "/etc/keys" = { + options = [ "nodev" "noexec" "nosuid" ]; + extraOptions = [ "noatime" "compress=zstd" ]; + }; + "/etc/credstore" = { + options = [ "nodev" "noexec" "nosuid" ]; + extraOptions = [ "noatime" "compress=zstd" ]; + }; + "/etc/credstore.encrypted" = { + options = [ "nodev" "noexec" "nosuid" ]; + extraOptions = [ "noatime" ]; + }; + "/nix" = { + options = [ "nodev" "nosuid" ]; + extraOptions = [ "noatime" "compress=zstd" ]; + }; + "/var" = { + options = [ "nodev" "noexec" "nosuid" ]; + extraOptions = [ "noatime" "compress=zstd" ]; + }; + }; +in { + options = { + ephemeral = { + enable = lib.mkEnableOption "ephemeral filesystem"; + + device = lib.mkOption { + type = lib.types.nonEmptyStr; + description = "Persistent btrfs device."; + }; + + boot = { + inherit device; + + fsType = lib.mkOption { + type = lib.types.nonEmptyStr; + }; + + options = lib.mkOption { + inherit (options) type readOnly description; + default = [ "nodev" "noexec" "nosuid" ] + ++ lib.optionals (cfg.boot.fsType == "vfat") [ "fmask=0137" "dmask=022" ] + ++ lib.optionals (builtins.match "ext[34]" cfg.boot.fsType != null) [ "data=journal" ]; + }; + + extraOptions = lib.mkOption { + inherit (extraOptions) type description; + default = [ "noatime" ]; + }; + }; + + ephemeral = lib.mkOption { + type = with lib.types; attrsOf (submodule tmpfs); + description = "Ephemeral filesystems."; + default = ephemeralDefaults; + }; + + subvolumes = lib.mkOption { + type = with lib.types; attrsOf (submodule subvol); + description = "Persistent subvolumes."; + default = subvolumeDefaults; + example = { + "/home" = { + options = [ "nodev" "noexec" "nosuid" ]; + extraOptions = [ "noatime" "compress=zstd" ]; + }; + }; + }; + }; + }; + + config = lib.mkIf cfg.enable { + boot.initrd.availableKernelModules = [ "zstd" ]; + boot.supportedFilesystems = [ "btrfs" ]; + + environment.etc.machine-id.source = lib.mkDefault "/etc/keys/machine-id"; + environment.etc.secureboot.source = lib.mkDefault "/etc/keys/secureboot"; + + fileSystems = { + "/boot" = { + device = cfg.boot.device; + fsType = cfg.boot.fsType; + options = cfg.boot.options ++ cfg.boot.extraOptions; + }; + } // + (builtins.mapAttrs (key: val: { + fsType = "tmpfs"; + options = val.options ++ val.extraOptions + ++ [ + "strictatime" + "size=${toString val.size}" + "mode=${val.mode}" + "uid=${toString val.uid}" + "gid=${toString val.gid}" + "huge=within_size" + ]; + }) (ephemeralDefaults // cfg.ephemeral)) // + (builtins.mapAttrs (key: val: { + device = cfg.device; + fsType = "btrfs"; + options = val.options ++ val.extraOptions + ++ [ "subvol=${if (val ? subvolume && val.subvolume != null) then val.subvolume else key}" ]; + neededForBoot = true; + }) (subvolumeDefaults // cfg.subvolumes)); + + nix.settings.build-dir = lib.mkDefault "/run/nix"; + systemd.services.nix-daemon.environment.TMPDIR = lib.mkDefault "/run/nix"; + + systemd.tmpfiles.settings.ephemeral = { + "/etc/keys".z = { + mode = "0751"; + user = "root"; + group = "root"; + }; + "/etc/credentials".z = { + mode = "0750"; + user = "root"; + group = "root"; + }; + "/etc/credentials.encrypted".z = { + mode = "0750"; + user = "root"; + group = "root"; + }; + "/run/nix".D = { + mode = "1775"; + user = "root"; + group = "nixbld"; + age = "1d"; + }; + }; + }; +} diff --git a/nixos/module/graphical.nix b/nixos/module/graphical.nix new file mode 100644 index 0000000..117a4db --- /dev/null +++ b/nixos/module/graphical.nix @@ -0,0 +1,21 @@ +{ ... }: { config, lib, pkgs, ... }: { + boot.kernel.sysctl = { + "kernel.sysrq" = lib.mkDefault "0x1f4"; + "kernel.unprivileged_userns_clone" = lib.mkDefault 1; + }; + + environment.pathsToLink = [ + "/share/applications" + "/share/xdg-desktop-portal" + ]; + + hardware.graphics.enable = true; + + security.polkit.enable = true; + security.rtkit.enable = true; + + services.pipewire = { + enable = true; + pulse.enable = true; + }; +} diff --git a/nixos/module/headless.nix b/nixos/module/headless.nix new file mode 100644 index 0000000..c02d4fa --- /dev/null +++ b/nixos/module/headless.nix @@ -0,0 +1,31 @@ +{ self, ... }: { config, lib, pkgs, ... }: { + imports = with self.nixosModules; [ + mimalloc + ]; + + boot.kernelParams = [ "panic=-1" ]; + + boot.initrd.network = { + enable = false; + ssh.enable = true; + ssh.authorizedKeys = lib.flatten (lib.mapAttrsToList (_: user: user.openssh.authorizedKeys.keys) (lib.filterAttrs (_: user: lib.any (group: group == "wheel") user.extraGroups) config.users.users)); + }; + + hardware.graphics.enable = false; + + security.lockKernelModules = true; + security.pam.sshAgentAuth.enable = true; + security.protectKernelImage = true; + services.openssh.enable = true; + services.openssh.openFirewall = true; + + systemd.network.networks."97-ethernet-default-dhcp-static.network" = { + matchConfig.Type = "ether"; + matchConfig.Name = "en*"; + + networkConfig.DHCP = "yes"; + dhcpV4Config.UseDNS = false; + dhcpV6Config.UseDNS = false; + ipv6AcceptRAConfig.Token = lib.mkDefault "static:::1"; + }; +} diff --git a/nixos/module/iosched.nix b/nixos/module/iosched.nix new file mode 100644 index 0000000..16145f7 --- /dev/null +++ b/nixos/module/iosched.nix @@ -0,0 +1,118 @@ +{ ... }: { config, lib, pkgs, ... }: + +let + cfg = config.hardware.block; + escape = lib.strings.escape [ ''"'' ]; + + inherit (lib) + mkIf + mkOption + types + + concatStrings + mapAttrsToList + optionalString; +in { + options.hardware.block = { + defaultScheduler = mkOption { + type = with types; nullOr nonEmptyStr; + default = null; + description = '' + Default block I/O scheduler. + + Unless `null`, the value is assigned through a udev rule matching all + block devices. + ''; + example = "kyber"; + }; + + defaultSchedulerRotational = mkOption { + type = with types; nullOr nonEmptyStr; + default = null; + description = '' + Default block I/O scheduler for rotational drives (e.g. hard disks). + + Unless `null`, the value is assigned through a udev rule matching all + rotational block devices. + + This option takes precedence over + {option}`config.hardware.block.defaultScheduler`. + ''; + example = "bfq"; + }; + + scheduler = mkOption { + type = with types; attrsOf nonEmptyStr; + default = { }; + description = '' + Assign block I/O scheduler by device name pattern. + + Names are matched using the {manpage}`udev(7)` pattern syntax: + + `*` + : Matches zero or more characters. + + `?` + : Matches any single character. + + `[]` + : Matches any single character specified in the brackets. Ranges are + supported via the `-` character. + + `|` + : Separates alternative patterns. + + + Please note that overlapping patterns may produce unexpected results. + More complex configurations requiring these should instead be specified + directly through custom udev rules, for example via + [{option}`config.services.udev.extraRules`](#opt-services.udev.extraRules), + to ensure correct ordering. + + Available schedulers depend on the kernel configuration but modern + Linux systems typically support: + + `none` + : No‐operation scheduler with no re‐ordering of requests. Suitable + for devices with fast random I/O such as NVMe SSDs. + + [`mq-deadline`](https://www.kernel.org/doc/html/latest/block/deadline-iosched.html) + : Simple latency‐oriented general‐purpose scheduler. + + [`kyber`](https://www.kernel.org/doc/html/latest/block/kyber-iosched.html) + : Simple latency‐oriented scheduler for fast multi‐queue devices + like NVMe SSDs. + + [`bfq`](https://www.kernel.org/doc/html/latest/block/bfq-iosched.html) + : Complex fairness‐oriented scheduler. Higher processing overhead, + but good interactive response, especially with slower devices. + + + Schedulers assigned through this option take precedence over + {option}`config.hardware.block.defaultScheduler` and + {option}`config.hardware.block.defaultSchedulerRotational` but may be + overridden by other udev rules. + ''; + example = { + "mmcblk[0-9]*" = "bfq"; + "nvme[0-9]*" = "kyber"; + }; + }; + }; + + config = mkIf (cfg.defaultScheduler != null || + cfg.defaultSchedulerRotational != null || cfg.scheduler != { }) { + services.udev.packages = [ + (pkgs.writeTextDir "etc/udev/rules.d/98-block-io-scheduler.rules" + (optionalString (cfg.defaultScheduler != null) '' + SUBSYSTEM=="block", ACTION=="add|change", TEST=="queue/scheduler", ATTR{queue/scheduler}="${escape cfg.defaultScheduler}" + '' + optionalString (cfg.defaultSchedulerRotational != null) '' + SUBSYSTEM=="block", ACTION=="add|change", ATTR{queue/rotational}=="1", TEST=="queue/scheduler", ATTR{queue/scheduler}="${escape cfg.defaultSchedulerRotational}" + '' + concatStrings (mapAttrsToList (name: sched: '' + SUBSYSTEM=="block", ACTION=="add|change", KERNEL=="${escape name}", ATTR{queue/scheduler}="${escape sched}" + '') cfg.scheduler))) + ]; + }; + + meta.maintainers = with lib.maintainers; [ mvs ]; +} diff --git a/nixos/module/kernel.nix b/nixos/module/kernel.nix new file mode 100644 index 0000000..cd555a6 --- /dev/null +++ b/nixos/module/kernel.nix @@ -0,0 +1,141 @@ +{ self, ... }: { lib, pkgs, ... }: { + boot.consoleLogLevel = lib.mkDefault 3; + + boot.initrd = { + includeDefaultModules = lib.mkDefault false; + luks.cryptoModules = lib.mkDefault [ ]; + verbose = lib.mkDefault false; + }; + + boot.kernelPackages = lib.mkDefault + (pkgs.linuxPackagesFor self.packages.${pkgs.system}.linux-hardened); + boot.modprobeConfig.enable = lib.mkDefault false; + + boot.kernelParams = [ + # Disable kernel messages on the console + "quiet" + + # Zero‐fill page and slab allocations on free + "init_on_free=1" + + # Disable I/O delay + "io_delay=none" + + # Enable page allocator free list randomisation + "page_alloc.shuffle=1" + + # Disable slab merging + "slab_nomerge" + + # Disable vsyscall mechanism + "vsyscall=none" + + # Enable transparent hugepages + "transparent_hugepage=always" + ]; + + boot.kernel.sysctl = { + # Mitigate some TOCTOU vulnerabilities + "fs.protected_fifos" = 2; + "fs.protected_hardlinks" = 1; + "fs.protected_regular" = 2; + "fs.protected_symlinks" = 1; + + # Disable automatic loading of TTY line disciplines + "dev.tty.ldisc_autoload" = 0; + + # Disable first 64 KiB of virtual memory for allocation + "vm.mmap_min_addr" = 65536; + + # Increase ASLR randomisation + "vm.mmap_rnd_bits" = 32; + "vm.mmap_rnd_compat_bits" = 16; + + # Restrict ptrace() + "kernel.yama.ptrace_scope" = 1; + + # Hide kernel memory addresses + "kernel.kptr_restrict" = 2; + + # Restrict kernel log access + "kernel.dmesg_restrict" = 1; + + # Enable hardened eBPF JIT + "kernel.unprivileged_bpf_disabled" = 1; + "net.core.bpf_jit_enable" = 1; + "net.core.bpf_jit_harden" = 2; + + # Ignore ICMP redirects + "net.ipv4.conf.default.accept_redirects" = 0; + "net.ipv6.conf.default.accept_redirects" = 0; + "net.ipv4.conf.all.accept_redirects" = 0; + "net.ipv6.conf.all.accept_redirects" = 0; + + # Set default Qdisc + "net.core.default_qdisc" = "fq"; + + # Increase minimum PMTU + "net.ipv4.route.min_pmtu" = 1280; + + # Set default TCP congestion control algorithm + "net.ipv4.tcp_congestion_control" = "bbr"; + + # Enable ECN + "net.ipv4.tcp_ecn" = 1; + + # Enable TCP fast open + "net.ipv4.tcp_fastopen" = 3; + + # Disable TCP slow start after idling + "net.ipv4.tcp_slow_start_after_idle" = 0; + + # Allow re‐use of TCP ports during TIME-WAIT + "net.ipv4.tcp_tw_reuse" = 1; + + # Enable TCP MTU probing + "net.ipv4.tcp_mtu_probing" = 1; + "net.ipv4.tcp_mtu_probe_floor" = 1220; + + # Increase socket buffer space + # default of 16 MiB should be sufficient to saturate 1GE + # maximum for 54 MiB sufficient for 10GE + "net.core.rmem_default" = 16777216; + "net.core.rmem_max" = 56623104; + "net.core.wmem_default" = 16777216; + "net.core.wmem_max" = 56623104; + "net.core.optmem_max" = 65536; + "net.ipv4.tcp_rmem" = "4096 1048576 56623104"; + "net.ipv4.tcp_wmem" = "4096 65536 56623104"; + "net.ipv4.tcp_notsent_lowat" = 16384; + "net.ipv4.udp_rmem_min" = 9216; + "net.ipv4.udp_wmem_min" = 9216; + + # Reduce TCP keep‐alive time‐out to 2 minutes + "net.ipv4.tcp_keepalive_time" = 60; + "net.ipv4.tcp_keepalive_probes" = 6; + "net.ipv4.tcp_keepalive_intvl" = 10; + + # Widen local port range + "net.ipv4.ip_local_port_range" = "16384 65535"; + + # Increase default MTU + "net.ipv6.conf.default.mtu" = 1452; + "net.ipv6.conf.all.mtu" = 1452; + + # Set traffic class for NDP to CS6 (network control) + "net.ipv6.conf.default.ndisc_tclass" = 192; + "net.ipv6.conf.all.ndisc_tclass" = 192; + + # Dirty page cache ratio + "vm.dirty_background_ratio" = 3; + "vm.dirty_ratio" = 6; + }; + + # Work around initrd generation bug + environment.etc."modprobe.d/nixos.conf".text = ""; + + systemd.tmpfiles.rules = [ + "w- /sys/kernel/mm/transparent_hugepage/enabled - - - - always" + "w- /sys/kernel/mm/transparent_hugepage/defrag - - - - defer+madvise" + ]; +} diff --git a/nixos/module/locale-en_EU.nix b/nixos/module/locale-en_EU.nix new file mode 100644 index 0000000..a82296c --- /dev/null +++ b/nixos/module/locale-en_EU.nix @@ -0,0 +1,7 @@ +{ self, ... }: { config, lib, pkgs, ... }: { + i18n.defaultLocale = lib.mkDefault "en_EU.UTF-8"; + i18n.glibcLocales = self.packages.${pkgs.system}.locale-en_EU.override { + allLocales = builtins.any (x: x == "all") config.i18n.supportedLocales; + locales = config.i18n.supportedLocales; + }; +} diff --git a/nixos/module/mimalloc.nix b/nixos/module/mimalloc.nix new file mode 100644 index 0000000..006f79e --- /dev/null +++ b/nixos/module/mimalloc.nix @@ -0,0 +1,4 @@ +{ ... }: { config, lib, pkgs, ... }: { + environment.memoryAllocator.provider = "mimalloc"; + environment.variables.MIMALLOC_LARGE_OS_PAGES = 1; +} diff --git a/nixos/module/network.nix b/nixos/module/network.nix new file mode 100644 index 0000000..d9b3b78 --- /dev/null +++ b/nixos/module/network.nix @@ -0,0 +1,49 @@ +{ ... }: { lib, name, ... }: { + networking.nameservers = [ + "[2a05:f480:1800:d2e::1]:853#resolve.solitary.social" + "80.240.30.163:853#resolve.solitary.social" + "[2a01:4f8:1c0c:6c89::1]:853#resolve.nyantec.com" + "116.203.220.161:853#resolve.nyantec.com" + ]; + + networking.hostName = lib.mkDefault name; + networking.nftables.enable = true; + networking.useNetworkd = true; + + services.resolved = { + enable = true; + dnsovertls = "true"; + dnssec = "true"; + }; + + systemd.network.networks."98-ethernet-default-dhcp" = { + matchConfig.Type = "ether"; + matchConfig.Name = "en*"; + + DHCP = lib.mkDefault "yes"; + dhcpV4Config.UseDNS = false; + dhcpV6Config.UseDNS = false; + ipv6AcceptRAConfig.Token = "prefixstable"; + + fairQueueingConfig.Pacing = true; + }; + + systemd.network.networks."98-wireless-client-dhcp" = { + matchConfig.Type = "wlan"; + matchConfig.WLANInterfaceType = "station"; + + DHCP = lib.mkDefault "yes"; + dhcpV4Config.UseDNS = false; + dhcpV4Config.RouteMetric = 1025; + dhcpV6Config.UseDNS = false; + ipv6AcceptRAConfig.Token = "prefixstable"; + ipv6AcceptRAConfig.RouteMetric = 1025; + + cakeConfig = { + Bandwidth = lib.mkDefault "100M"; + AutoRateIngress = true; + UseRawPacketSize = false; + PriorityQueueingPreset = "diffserv4"; + }; + }; +} diff --git a/nixos/module/nitrokey-random.nix b/nixos/module/nitrokey-random.nix new file mode 100644 index 0000000..7902f33 --- /dev/null +++ b/nixos/module/nitrokey-random.nix @@ -0,0 +1,23 @@ +{ ... }: { config, lib, pkgs, ... }: + +lib.mkIf config.hardware.nitrokey.enable { + services.udev.packages = [ + (pkgs.writeTextDir "etc/udev/rules.d/98-nitrokey-random-seed.rules" '' + SUBSYSTEM=="hidraw", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="42b1|42b2", TAG+="systemd", ENV{SYSTEMD_WANTS}+="nitrokey-random-seed@%k.service" + '') + ]; + + systemd.services."nitrokey-random-seed@" = { + description = "Feed kernel from Nitrokey TRNG"; + serviceConfig = { + Type = "oneshot"; + ExecStart = "${pkgs.pynitrokey}/bin/nitropy fido2 rng feedkernel"; + DynamicUser = true; + SupplementaryGroups = [ "plugdev" ]; + AmbientCapabilities = [ "CAP_SYS_ADMIN" ]; + + DeviceAllow = [ "/dev/%i rw" ]; + DevicePolicy = "closed"; + }; + }; +} diff --git a/nixos/module/nix.nix b/nixos/module/nix.nix new file mode 100644 index 0000000..112be36 --- /dev/null +++ b/nixos/module/nix.nix @@ -0,0 +1,67 @@ +{ self, ... }: { lib, pkgs, ... }: +let + inherit (pkgs.stdenv) hostPlatform; +# inherit (inputs.idiosyn.lib.platforms.${hostPlatform.system}.gcc) arch; +in { + imports = with self.nixosModules; [ + powersupply + ]; + + nix = { + package = pkgs.lix; + + channel.enable = false; + + daemonCPUSchedPolicy = "batch"; + daemonIOSchedClass = "best-effort"; + daemonIOSchedPriority = 7; + + gc = { + automatic = true; + dates = "weekly"; + randomizedDelaySec = "24h"; + options = "--delete-older-than 10d"; + }; + + settings = { + experimental-features = [ + "cgroups" + "flakes" + "nix-command" + "repl-flake" + "pipe-operator" + ]; + + allowed-users = [ "@users" ]; + trusted-users = [ "@wheel" ]; + + builders-use-substitutes = true; + download-attempts = 8; + http-connections = 128; + max-substitution-jobs = 128; + preallocate-contents = true; + use-cgroups = true; + use-xdg-base-directories = true; + +/* system-features = lib.mkOptionDefault + (map (arch: "gccarch-${arch}") ([ arch ] ++ lib.systems.architectures.inferiors.${arch} or [ ]));*/ + }; + + registry = { + nixpkgs.to = { + type = "path"; + path = pkgs.path; + narHash = lib.trim (builtins.readFile + (pkgs.runCommandLocal "get-nixpkgs-hash" + { nativeBuildInputs = [ pkgs.nix ]; } + "nix-hash --type sha256 --sri ${pkgs.path} > $out")); + }; + }; + }; + + systemd = { + services.nix-daemon.serviceConfig.Slice = "nix-build.slice"; + slices.nix-build = { }; + timers.nix-gc.bindsTo = [ "power-external.target" ]; + }; +} diff --git a/nixos/module/openssh.nix b/nixos/module/openssh.nix new file mode 100644 index 0000000..cd110f2 --- /dev/null +++ b/nixos/module/openssh.nix @@ -0,0 +1,64 @@ +{ ... }: { lib, ...}: + +let + ciphers = [ + "chacha20-poly1305@openssh.com" + "aes256-gcm@openssh.com" + "aes128-gcm@openssh.com" + ]; + + sigAlgorithms = [ + "ssh-ed25519-cert-v01@openssh.com" + "ssh-ed25519" + "sk-ssh-ed25519-cert-v01@openssh.com" + "sk-ssh-ed25519@openssh.com" + ]; + + kexAlgorithms = [ + "sntrup761x25519-sha512@openssh.com" + "curve25519-sha256" + "curve25519-sha256@libssh.org" + ]; + + macs = [ + "umac-128-etm@openssh.com" + "hmac-sha2-512-etm@openssh.com" + "hmac-sha2-256-etm@openssh.com" + ]; +in { + programs.ssh = { + inherit ciphers kexAlgorithms macs; + hostKeyAlgorithms = sigAlgorithms; + pubkeyAcceptedKeyTypes = sigAlgorithms; + setXAuthLocation = false; + }; + + services.openssh = { + hostKeys = lib.mkDefault [ + { + path = "/etc/keys/ssh_host_ed25519_key"; + type = "ed25519"; + } + ]; + + settings = { + PermitRootLogin = "no"; + + PasswordAuthentication = false; + KbdInteractiveAuthentication = false; + AuthenticationMethods = "publickey"; + + Ciphers = ciphers; + Macs = macs; + + KexAlgorithms = kexAlgorithms; + HostKeyAlgorithms = lib.concatStringsSep "," sigAlgorithms; + PubkeyAcceptedAlgorithms = lib.concatStringsSep "," sigAlgorithms; + + # Remove stale Unix sockets when forwarding + StreamLocalBindUnlink = true; + + ClientAliveInterval = 900; + }; + }; +} diff --git a/nixos/module/physical.nix b/nixos/module/physical.nix new file mode 100644 index 0000000..6e29993 --- /dev/null +++ b/nixos/module/physical.nix @@ -0,0 +1,19 @@ +{ self, lanzaboote, ... }: { config, lib, pkgs, ... }: { + imports = [ + lanzaboote.nixosModules.lanzaboote + ] ++ (with self.nixosModules; [ + nitrokey-random + ]); + + boot = { + loader.efi.canTouchEfiVariables = true; + + lanzaboote = { + enable = true; + pkiBundle = lib.mkDefault "/etc/keys/secureboot"; + }; + }; + + security.tpm2.enable = true; + services.fwupd.enable = true; +} diff --git a/nixos/module/portable.nix b/nixos/module/portable.nix new file mode 100644 index 0000000..5771686 --- /dev/null +++ b/nixos/module/portable.nix @@ -0,0 +1,34 @@ +{ ... }: { lib, config, pkgs, ... }: { + # Work around TTL‐based rate limiting in mobile networks + boot.kernel.sysctl."net.ipv4.ip_default_ttl" = 65; + + powerManagement.cpuFreqGovernor = lib.mkDefault "powersave"; + powerManagement.scsiLinkPolicy = lib.mkDefault "med_power_with_dipm"; + + services.auto-cpufreq = { + enable = true; + settings = { + battery = { + governor = "powersave"; + turbo = "never"; + }; + + charger = { + governor = "powersave"; + turbo = "auto"; + }; + }; + }; + + services.thermald.enable = lib.mkDefault true; + services.tlp.enable = false; + + services.udev.packages = [ + (pkgs.writeTextDir "/etc/udev/rules.d/98-power-supply-portable.rules" '' + SUBSYSTEM=="power_supply", ATTR{status}=="Discharging", SYSCTL{vm/dirty_writeback_centisecs}="6000" + SUBSYSTEM=="power_supply", ATTR{status}!="Discharging", SYSCTL{vm/dirty_writeback_centisecs}="1500" + SUBSYSTEM=="power_supply", ATTR{status}=="Discharging", ATTR{capacity}=="[3-5]", RUN+="${config.systemd.package}/bin/systemctl suspend" + SUBSYSTEM=="power_supply", ATTR{status}=="Discharging", ATTR{capacity}=="[0-2]", RUN+="${config.systemd.package}/bin/systemctl poweroff" + '') + ]; +} diff --git a/nixos/module/powersupply.nix b/nixos/module/powersupply.nix new file mode 100644 index 0000000..186d2fc --- /dev/null +++ b/nixos/module/powersupply.nix @@ -0,0 +1,27 @@ +{ ... }: { config, lib, pkgs, ... }: { + services.udev.packages = [ + (pkgs.writeTextDir "/etc/udev/rules.d/98-power-supply.rules" '' + SUBSYSTEM=="power_supply", KERNEL=="AC", TAG+="systemd", ENV{SYSTEMD_WANTS}+="power-internal.target power-external.target" + '') + ]; + + systemd.targets.power-internal = { + description = "On internal power supply"; + conflicts = [ "power-external.target" ]; + wantedBy = [ "multi-user.target" ]; + unitConfig = { + ConditionACPower = false; + DefaultDependencies = false; + }; + }; + + systemd.targets.power-external = { + description = "On external power supply"; + conflicts = [ "power-internal.target" ]; + wantedBy = [ "multi-user.target" ]; + unitConfig = { + ConditionACPower = true; + DefaultDependencies = false; + }; + }; +} diff --git a/nixos/module/security.nix b/nixos/module/security.nix new file mode 100644 index 0000000..109c102 --- /dev/null +++ b/nixos/module/security.nix @@ -0,0 +1,21 @@ +{ ... }: { lib, config, ... }: { + boot.loader.systemd-boot.editor = false; + + security.acme.acceptTerms = true; + security.pam.services.swaylock.fprintAuth = false; + security.pam.services.login.fprintAuth = false; + security.pam.services.sudo-rs = { + fprintAuth = config.services.fprintd.enable; + sshAgentAuth = config.security.pam.sshAgentAuth.enable; + }; + + security.sudo.enable = false; + security.sudo-rs = { + enable = true; + execWheelOnly = true; + wheelNeedsPassword = config.security.pam.services.sudo-rs.fprintAuth + || config.security.pam.services.sudo-rs.sshAgentAuth; + }; + + services.logind.killUserProcesses = true; +} diff --git a/nixos/module/users.nix b/nixos/module/users.nix new file mode 100644 index 0000000..69306b1 --- /dev/null +++ b/nixos/module/users.nix @@ -0,0 +1,59 @@ +{ self, home-manager, ...}: { config, lib, pkgs, ... }: +let + graphical = config.hardware.graphics.enable; +in { + imports = [ home-manager.nixosModules.home-manager ]; + + home-manager = { + useUserPackages = lib.mkDefault true; + useGlobalPkgs = lib.mkDefault true; + users = { inherit (self.homeConfigurations) nil; }; + }; + + nixpkgs.config.allowUnfreePredicate = lib.mkIf graphical + (pkg: builtins.elem (lib.getName pkg) [ "obsidian" ]); + + programs.dconf.enable = lib.mkIf graphical true; + programs.fish.enable = true; + + services.udev.packages = [ + (pkgs.writeTextDir "/etc/udev/rules.d/98-user-power-supply.rules" '' + SUBSYSTEM=="power_supply", KERNEL=="AC", TAG+="systemd", ENV{SYSTEMD_USER_WANTS}+="power-internal.target power-external.target" + '') + ]; + + systemd.user = { + targets = { + power-internal = { + description = "On internal power supply"; + conflicts = [ "power-external.target" ]; + wantedBy = [ "default.target" ]; + unitConfig = { + ConditionACPower = false; + DefaultDependencies = false; + }; + }; + + power-external = { + description = "On external power supply"; + conflicts = [ "power-internal.target" ]; + wantedBy = [ "default.target" ]; + unitConfig = { + ConditionACPower = true; + DefaultDependencies = false; + }; + }; + }; + }; + + users.users.nil = { + isNormalUser = true; + shell = config.programs.fish.package; + extraGroups = [ "wheel" ]; + openssh.authorizedKeys.keys = [ + "sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAICczPHRwY9MAwDGlcB0QgMOJjcpLJhVU3covrW9RBS62AAAABHNzaDo= primary" + "sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIAgnEAwe59/yY/U55y7WxGa/QI20/XMQEsQvs1/6LitRAAAABHNzaDo= backup" + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGOTvXiNHTXq9wkcxdVOblHVyvcAaCfxmJp/CXI4rzMj legacy" + ]; + }; +} diff --git a/nixos/module/wireless.nix b/nixos/module/wireless.nix new file mode 100644 index 0000000..f667432 --- /dev/null +++ b/nixos/module/wireless.nix @@ -0,0 +1,16 @@ +{ ... }: { config, ...}: { + hardware.bluetooth.enable = true; + hardware.wirelessRegulatoryDatabase = true; + networking.wireless.iwd = { + enable = true; + settings = { + General = { + AddressRandomization = "network"; + }; + + Rank = { + BandModifier2_4GHz = 0.8; + }; + }; + }; +} diff --git a/nixos/module/zram.nix b/nixos/module/zram.nix new file mode 100644 index 0000000..24a2b55 --- /dev/null +++ b/nixos/module/zram.nix @@ -0,0 +1,82 @@ +{ ... }: { lib, pkgs, ... }: { + boot.kernelParams = [ + "zswap.zpool=zsmalloc" + "zram.num_devices=0" + ]; + + boot.kernel.sysctl = { + "vm.page-cluster" = lib.mkDefault 0; + "vm.swappiness" = lib.mkDefault 180; + "vm.watermark_boost_factor" = lib.mkDefault 0; + "vm.watermark_scale_factor" = lib.mkDefault 125; + }; + + systemd.services.zram-swap = + let + writeShell = { name, text, runtimeInputs ? [ ] }: + pkgs.writeShellApplication { inherit name text runtimeInputs; } + "/bin/${name}"; + in { + description = "Compressed in-memory swap space"; + + wantedBy = [ "swap.target" ]; + unitConfig.DefaultDependencies = false; + + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + RuntimeDirectory = "zram-swap"; + + CapabilityBoundingSet = [ "CAP_DAC_OVERRIDE" "CAP_SYS_ADMIN" ]; + SystemCallFilter = [ "@system-service" "@swap" ]; + + ExecStartPre = writeShell { + name = "zram-swap-start-pre"; + runtimeInputs = with pkgs; [ coreutils getconf util-linux ]; + text = '' + pages="$(getconf _PHYS_PAGES)" + pagesize="$(getconf PAGESIZE)" + + dev="$(cat /sys/class/zram-control/hot_add)" + echo "$dev" >"$RUNTIME_DIRECTORY/device" + + echo zstd >"/sys/block/zram$dev/comp_algorithm" + echo "$((pages * pagesize * 3 / 2))" >"/sys/block/zram$dev/disksize" + echo "$((pages * pagesize * 3 / 4))" >"/sys/block/zram$dev/mem_limit" + + mkswap "/dev/zram$dev" + ''; + }; + + ExecStart = writeShell { + name = "zram-swap-start"; + runtimeInputs = with pkgs; [ util-linux ]; + text = '' + swapon --discard --priority 32767 "/dev/zram$(<"$RUNTIME_DIRECTORY/device")" + ''; + }; + + ExecStop = writeShell { + name = "zram-swap-stop"; + runtimeInputs = with pkgs; [ util-linux ]; + text = '' + swapoff "/dev/zram$(<"$RUNTIME_DIRECTORY/device")" + ''; + }; + + ExecStopPost = writeShell { + name = "zram-swap-stop-post"; + runtimeInputs = with pkgs; [ coreutils ]; + text = '' + test -s "$RUNTIME_DIRECTORY/device" || exit 0 + + dev="$(<"$RUNTIME_DIRECTORY/device")" + + echo 1 >"/sys/block/zram$dev/reset" + echo "$dev" >/sys/class/zram-control/hot_remove + + rm -f -- "$RUNTIME_DIRECTORY/device" + ''; + }; + }; + }; +} diff --git a/overlay/default.nix b/overlay/default.nix new file mode 100644 index 0000000..61c8a17 --- /dev/null +++ b/overlay/default.nix @@ -0,0 +1,13 @@ +{ self, nixpkgs, lix-module, colmena, rust-overlay, ... }: + +final: prev: + +nixpkgs.lib.composeManyExtensions [ + lix-module.overlays.default + colmena.overlays.default + rust-overlay.overlays.default +# self.overlays.no-x +# self.overlays.no-alsa +# self.overlays.no-jemalloc +# self.overlays.modern-minimal +] final prev diff --git a/overlay/modern-minimal.nix b/overlay/modern-minimal.nix new file mode 100644 index 0000000..971e29b --- /dev/null +++ b/overlay/modern-minimal.nix @@ -0,0 +1,69 @@ +{ nixpkgs, ... }: final: prev: { + curl = prev.curl.override { + gssSupport = false; + scpSupport = false; + zstdSupport = true; + }; + + ffmpeg = prev.ffmpeg.override { + ffmpegVariant = "headless"; + withAlsa = false; + withSsh = false; + }; + + firefox-unwrapped = prev.firefox-unwrapped.override { + alsaSupport = false; + gssSupport = false; + jemallocSupport = false; + sndioSupport = false; + }; + + firefox = final.wrapFirefox final.firefox-unwrapped { }; + + imv = prev.imv.override { + withWindowSystem = "wayland"; + }; + + mesa = prev.mesa.override { + galliumDrivers = [ + "iris" + "kmsro" + "nouveau" + "radeonsi" + "swrast" + "zink" + ]; + + vulkanDrivers = [ + "amd" + "intel" + "nouveau" + "swrast" + ]; + + eglPlatforms = [ "wayland" ]; + }; + + mpv-unwrapped = prev.mpv-unwrapped.override { + alsaSupport = false; + cacaSupport = false; + openalSupport = false; + sdl2Support = false; + vdpauSupport = false; + x11Support = false; + xineramaSupport = false; + xvSupport = false; + }; + + mpv = final.mpv-unwrapped.wrapper { + mpv = final.mpv-unwrapped; + }; + + systemd = prev.systemd.override { + withApparmor = false; + withHomed = false; + withIptables = false; + }; + + foo = null; +} diff --git a/overlay/no-alsa.nix b/overlay/no-alsa.nix new file mode 100644 index 0000000..b5221b6 --- /dev/null +++ b/overlay/no-alsa.nix @@ -0,0 +1,20 @@ +{ nixpkgs, ... }: final: prev: + +let + inherit (nixpkgs.lib.attrsets) genAttrs; +in genAttrs [ + "SDL2" + "firefox-unwrapped" + "mpv-unwrapped" +] (pkg: prev.${pkg}.override { alsaSupport = false; }) +// genAttrs [ + "ffmpeg" + "libcanberra" +] (pkg: prev.${pkg}.override { withAlsa = false; }) +// { + firefox = final.wrapFirefox final.firefox-unwrapped { }; + + mpv = final.mpv-unwrapped.wrapper { + mpv = final.mpv-unwrapped; + }; +} diff --git a/overlay/no-jemalloc.nix b/overlay/no-jemalloc.nix new file mode 100644 index 0000000..93f52e3 --- /dev/null +++ b/overlay/no-jemalloc.nix @@ -0,0 +1,10 @@ +{ nixpkgs, ... }: final: prev: + +let + inherit (nixpkgs.lib.attrsets) genAttrs; +in genAttrs [ + "firefox-unwrapped" +] (pkg: prev.${pkg}.override { jemallocSupport = false; }) +// { + firefox = final.wrapFirefox final.firefox-unwrapped { }; +} diff --git a/overlay/no-x.nix b/overlay/no-x.nix new file mode 100644 index 0000000..ca0eaab --- /dev/null +++ b/overlay/no-x.nix @@ -0,0 +1,102 @@ +{ nixpkgs, ... }: final: prev: + +let + inherit (nixpkgs.lib.attrsets) genAttrs; + inherit (nixpkgs.lib.lists) remove toList; + inherit (nixpkgs.lib.strings) mesonBool mesonEnable; +in genAttrs [ + "SDL2" + "cairo" + "dbus" + "ghostscript" + "gobject-introspection" + "gtk3" + "gtk4" + "imlib2" + "libcaca" + "pango" + "pipewire" +] (pkg: prev.${pkg}.override { x11Support = false; }) + +// genAttrs [ + "intel-media-driver" + "mupdf" +] (pkg: prev.${pkg}.override { enableX11 = false; }) + +// genAttrs [ + "hyprland" + "sway" + "sway-unwrapped" + "swayfx" + "swayfx-unwrapped" + "wlroots" +] (pkg: prev.${pkg}.override { enableXWayland = false; }) + +// { + beam = prev.beam_nox; + graphviz = prev.graphviz-nox; + + gammastep = prev.gammastep.override { + withRandr = false; + }; + + gd = prev.gd.override { withXorg = false; }; + + gst_all_1 = prev.gst_all_1 // genAttrs [ + "gst-plugins-base" + "gst-plugins-good" + ] (pkg: prev.gst_all_1.${pkg}.override { enableX11 = false; }); + + imagemagick = prev.imagemagick.override { + libX11Support = false; + libXtSupport = false; + }; + + libepoxy = (prev.libepoxy.overrideAttrs (prevAttrs: { + buildInputs = prevAttrs.buildInputs or [ ] + ++ [ final.libGL ]; + mesonFlags = prevAttrs.mesonFlags or [ ] + |> map (flag: if flag == "-Degl=no" then "-Degl=yes" else flag); + })).override { + x11Support = false; + }; + + libgnomekbd = prev.libgnomekbd.overrideAttrs (prevAttrs: { + mesonFlags = prevAttrs.mesonFlags or [ ] + ++ [ (mesonBool "tests" false) ]; + }); + + mesa = (prev.mesa.overrideAttrs (prevAttrs: { + mesonFlags = prevAttrs.mesonFlags or [ ] ++ [ + (mesonEnable "xlib-lease" false) + (mesonEnable "glx" false) + (mesonEnable "gallium-vdpau" false) + ]; + })).override { + eglPlatforms = [ "wayland" ]; + }; + + mpv-unwrapped = prev.mpv-unwrapped.override { + x11Support = false; + xineramaSupport = false; + xvSupport = false; + }; + + mpv = final.mpv-unwrapped.wrapper { + mpv = final.mpv-unwrapped; + }; + + w3m = prev.w3m.override { + x11Support = false; + imlib2 = final.imlib2; + }; + + utsushi = prev.utsushi.overrideAttrs (prevAttrs: { + buildInputs = remove prev.gtkmm2.dev prevAttrs.buildInputs; + }); + + wayland = prev.wayland.override { + # broken + withDocumentation = false; + }; +} diff --git a/overlay/pkgconf.nix b/overlay/pkgconf.nix new file mode 100644 index 0000000..0b42762 --- /dev/null +++ b/overlay/pkgconf.nix @@ -0,0 +1,14 @@ +{ ... }: + +final: prev: { + pkg-config = prev.pkg-config.override { + pkg-config = final.libpkgconf.overrideAttrs (prevAttrs: { + postInstall = let + ext = final.hostPlatform.extensions.executable; + in prevAttrs.postInstall or "" + '' + ln -s pkgconf${ext} "$out/bin/pkg-config${ext}" + ln -s pkgconf.1 "$man/share/man/man1/pkg-config.1" + ''; + }); + }; +} diff --git a/package/libslz.nix b/package/libslz.nix new file mode 100644 index 0000000..e09a646 --- /dev/null +++ b/package/libslz.nix @@ -0,0 +1,29 @@ +{ ... }: { lib, stdenv, fetchFromGitHub }: + +stdenv.mkDerivation (finalAttrs: { + pname = "libslz"; + version = "1.2.1"; + + src = fetchFromGitHub { + owner = "wtarreau"; + repo = finalAttrs.pname; + rev = "v${finalAttrs.version}"; + hash = "sha256-+3e0yTk6l8miQs/zBYSiPuj/gRWICR3QYTkV3OAHAtI="; + }; + + makeFlags = [ + "TOPDIR=$(src)" + "PREFIX=$(out)" + ]; + + buildFlags = [ + "CROSS_COMPILE=${stdenv.cc.targetPrefix}" + "CC=cc" + ]; + + meta = { + homepage = "http://www.libslz.org/"; + license = lib.licenses.mit; + maintainers = with lib.maintainers; [ mvs ]; + }; +}) diff --git a/package/linux-hardened/config.nix b/package/linux-hardened/config.nix new file mode 100644 index 0000000..5b4ca11 --- /dev/null +++ b/package/linux-hardened/config.nix @@ -0,0 +1,633 @@ +{ kernel, lib, hostPlatform, systemd }: with kernel; { + meta = { + EXPERT = true; + STAGING = true; + } // lib.optionalAttrs hostPlatform.isx86_64 { + PROCESSOR_SELECT = true; + }; + + build = { + COMPILE_TEST = false; + WERROR = true; + + STANDALONE = true; + PREVENT_FIRMWARE_BUILD = true; + + JUMP_LABEL = true; + + LTO_CLANG_FULL = true; + }; + + boot = { + KERNEL_ZSTD = true; + BLK_DEV_INITRD = true; + RD_GZIP = false; + RD_BZIP2 = false; + RD_LZMA = false; + RD_XZ = false; + RD_LZO = false; + RD_LZ4 = false; + RD_ZSTD = true; + + BOOT_CONFIG = true; + + EFI = true; + EFI_STUB = true; + + DEVTMPFS = true; + DEVTMPFS_MOUNT = true; + DEVTMPFS_SAFE = true; + + FW_LOADER = true; + FW_LOADER_COMPRESS = true; + FW_LOADER_COMPRESS_XZ = false; + FW_LOADER_COMPRESS_ZSTD = true; + FW_CACHE = true; + } // lib.optionalAttrs hostPlatform.isx86_64 { + EFI_HANDOVER_PROTOCOL = false; + }; + + debug = { + KALLSYMS = true; + KALLSYMS_ALL = false; + + SYMBOLIC_ERRNAME = true; + DEBUG_BUGVERBOSE = true; + DEBUG_INFO_DWARF5 = true; + DEBUG_INFO_SPLIT = true; + STRIP_ASM_SYMS = true; + + MAGIC_SYSRQ = true; + MAGIC_SYSRQ_DEFAULT_ENABLE = "0x1f4"; + + SLUB_DEBUG = false; + + DEBUG_WX = true; + WARN_ALL_UNSEEDED_RANDOM = true; + + RCU_TRACE = false; + + } // lib.optionalAttrs hostPlatform.isx86_64 { + X86_VERBOSE_BOOTUP = false; + EARLY_PRINTK = false; + X86_DEBUG_FPU = false; + + UNWINDER_ORC = true; + }; + + firmware = { + EFI_DXE_MEM_ATTRIBUTES = true; + EFI_BOOTLOADER_CONTROL = true; + RESET_ATTACK_MITIGATION = true; + EFI_DISABLE_PCI_DMA = true; + + EFIVAR_FS = true; + + # pstore + PSTORE = true; + PSTORE_COMPRESS = true; + EFI_VARS_PSTORE = true; + }; + + platform = { + "64BIT" = true; + } // lib.optionalAttrs hostPlatform.isx86_64 { + X86_MPPARSE = false; + X86_FRED = true; + X86_EXTENDED_PLATFORM = false; + + CPU_SUP_HYGON = false; + CPU_SUP_CENTAUR = false; + CPU_SUP_ZHAOXIN = false; + } // lib.optionalAttrs hostPlatform.isAarch64 { + ARM64_VA_BITS_48 = true; + ARM64_PAN = true; + ARM64_USE_LSE_ATOMICS = true; + ARM64_CNP = true; + ARM64_PTR_AUTH = true; + ARM64_EPAN = true; + } // lib.optionalAttrs hostPlatform.isRiscV64 { + ARCH_RV64I = true; + COMPAT = false; + }; + + security = { + SECCOMP = true; + + # Kernel memory base + RELOCATABLE = true; + RANDOMIZE_BASE = true; + RANDOMIZE_MEMORY = true; + + # Stack protection + STACKPROTECTOR = true; + STACKPROTECTOR_STRONG = true; + VMAP_STACK = true; + RANDOMIZE_KSTACK_OFFSET = true; + RANDOMIZE_KSTACK_OFFSET_DEFAULT = true; + INIT_STACK_ALL_ZERO = true; + + STRICT_KERNEL_RWX = true; + CFI_CLANG = true; + + # Slab allocator + SLAB_MERGE_DEFAULT = false; + SLAB_FREELIST_RANDOM = true; + SLAB_FREELIST_HARDENED = true; + SLAB_CANARY = true; + SLUB_CPU_PARTIAL = true; + RANDOM_KMALLOC_CACHES = true; + + # Page allocator + SHUFFLE_PAGE_ALLOCATOR = true; + COMPAT_BRK = false; + INIT_ON_FREE_DEFAULT_ON = true; + + # False positives in combination with panic on BUG() + PAGE_SANITIZE_VERIFY = false; + SLAB_SANITIZE_VERIFY = false; + + MODULES = false; + + LDISC_AUTOLOAD = false; + + DEVMEM = false; + DEVPORT = false; + + DEBUG_FS = false; + + # Bounds checking + # False positives in iwlwifi + #UBSAN = true; + #UBSAN_BOUNDS = true; + #UBSAN_SIGNED_WRAP = false; + #UBSAN_BOOL = false; + #UBSAN_ENUM = false; + + # Memory safety error detection + KFENCE = true; + KFENCE_DEFERRABLE = true; + KFENCE_BUG_ON_DATA_CORRUPTION = true; + + PANIC_ON_OOPS = true; + PANIC_TIMEOUT = (-1); + + HARDENED_USERCOPY = true; + FORTIFY_SOURCE = true; + + SECURITY_DMESG_RESTRICT = true; + SECURITY_PERF_EVENTS_RESTRICT = true; + SECURITY_TIOCSTI_RESTRICT = true; + SECURITY = true; + SECURITY_NETWORK = true; + SECURITY_SELINUX = false; + SECURITY_YAMA = true; + SECURITY_LOCKDOWN_LSM = true; + SECURITY_LOCKDOWN_LSM_EARLY = true; + LOCK_DOWN_KERNEL_FORCE_CONFIDENTIALITY = true; + SECURITY_LANDLOCK = true; + + LIST_HARDENED = true; + BUG_ON_DATA_CORRUPTION = true; + + } // lib.optionalAttrs hostPlatform.isx86_64 { + X86_UMIP = true; + X86_USER_SHADOW_STACK = true; + + STRICT_SIGALTSTACK_SIZE = true; + }; + + timer = { + NO_HZ_FULL = true; + HIGH_RES_TIMERS = true; + HZ_1000 = true; + + RTC_CLASS = true; + RTC_HCTOSYS = true; + RTC_SYSTOHC = true; + } // lib.optionalAttrs hostPlatform.isx86_64 { + X86_PM_TIMER = true; + RTC_DRV_CMOS = true; + }; + + interfaces = { + SYSVIPC = true; + USELIB = false; + + UID16 = false; + SGETMASK_SYSCALL = false; + SYSFS_SYSCALL = false; + POSIX_TIMERS = true; + PCSPKR_PLATFORM = false; + FUTEX = true; + EPOLL = true; + AIO = false; + IO_URING = true; + ADVISE_SYSCALLS = true; + + COMPAT_VDSO = false; + COMPAT_32BIT_TIME = false; + + DNOTIFY = false; + + bpf = { + BPF_SYSCALL = true; + BPF_JIT = true; + BPF_JIT_ALWAYS_ON = true; + BPF_UNPRIV_DEFAULT_OFF = true; + BPF_LSM = true; + }; + + namespaces = { + NAMESPACES = true; + UTS_NS = true; + TIME_NS = true; + USER_NS = true; + USER_NS_UNPRIVILEGED = false; + PID_NS = true; + NET_NS = true; + }; + } // lib.optionalAttrs hostPlatform.isx86_64 { + X86_VSYSCALL_EMULATION = false; + X86_IOPL_IOPERM = false; + LEGACY_VSYSCALL_NONE = true; + MODIFY_LDT_SYSCALL = false; + IA32_EMULATION = false; + }; + + scheduler = { + SMP = true; + PREEMPT_DYNAMIC = false; + + SCHED_CORE = true; + SCHED_CLUSTER = true; + SCHED_MC = true; + SCHED_AUTOGROUP = true; + + RCU_NOCB_CPU_DEFAULT_ALL = true; + RCU_LAZY = true; + + CGROUPS = true; + BLK_CGROUP = true; + CGROUP_SCHED = true; + + } // lib.optionalAttrs hostPlatform.isx86_64 { + SCHED_OMIT_FRAME_POINTER = true; + + SCHED_MC_PRIO = true; + }; + + memory = { + NUMA = true; + NUMA_BALANCING = true; + NUMA_BALANCING_DEFAULT_ENABLED = true; + + SPARSEMEM_VMEMMAP = true; + MEMORY_HOTPLUG = true; + MEMORY_HOTREMOVE = true; + + COMPACTION = true; + MIGRATION = true; + + KSM = true; + + TRANSPARENT_HUGEPAGE = true; + TRANSPARENT_HUGEPAGE_ALWAYS = true; + READ_ONLY_THP_FOR_FS = true; + HUGETLBFS = true; + HUGETLB_PAGE_OPTIMIZE_VMEMMAP = true; + HUGETLB_PAGE_OPTIMIZE_VMEMMAP_DEFAULT_ON = true; + + DEFERRED_STRUCT_PAGE_INIT = true; + + ZONE_DEVICE = true; + DEVICE_PRIVATE = true; + + LRU_GEN = true; + LRU_GEN_ENABLED = true; + + DMADEVICES = true; + ASYNC_TX_DMA = option true; + + zram = { + SWAP = true; + ZSMALLOC = true; + ZRAM = true; + ZRAM_DEF_COMP_ZSTD = true; + ZRAM_WRITEBACK = true; + CRYPTO_ZSTD = true; + }; + } // lib.optionalAttrs hostPlatform.isx86_64 { + AMD_NUMA = option false; + X86_64_ACPI_NUMA = true; + + X86_INTEL_TSX_MODE_AUTO = true; + + ADDRESS_MASKING = false; + }; + + block = { + BLOCK = true; + BLOCK_LEGACY_AUTOLOAD = false; + BLK_DEV = true; + BLK_DEV_WRITE_MOUNTED = true; + BLK_WBT = true; + BLK_WBT_MQ = true; + + PARTITION_ADVANCED = true; + MSDOS_PARTITION = false; + EFI_PARTITION = true; + + MQ_IOSCHED_DEADLINE = true; + MQ_IOSCHED_KYBER = true; + IOSCHED_BFQ = true; + BFQ_GROUP_IOSCHED = true; + + BLK_DEV_LOOP = true; + BLK_DEV_LOOP_MIN_COUNT = 0; + }; + + binfmt = { + BINFMT_ELF = true; + CORE_DUMP_DEFAULT_ELF_HEADERS = true; + BINFMT_SCRIPT = true; + BINFMT_MISC = true; + COREDUMP = true; + }; + + io = { + IOMMU_SUPPORT = true; + IOMMU_DEFAULT_DMA_STRICT = true; + IRQ_REMAP = true; + SWIOTLB_DYNAMIC = true; + } // lib.optionalAttrs hostPlatform.isx86_64 { + X86_X2APIC = true; + + AMD_IOMMU = option true; + INTEL_IOMMU = option true; + INTEL_IOMMU_SVM = option true; + INTEL_IOMMU_DEFAULT_ON = option true; + INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON = option true; + + IO_DELAY_NONE = true; + } // lib.optionalAttrs hostPlatform.isAarch64 { + ARM_SMMU_V3 = true; + }; + + bus = { + PCI = true; + PCIEPORTBUS = true; + PCI_MSI = true; + PCIE_BUS_PERFORMANCE = true; + + HID_SUPPORT = true; + HID = true; + HIDRAW = true; + UHID = true; + HID_GENERIC = true; + USB_HID = true; + USB_HIDDEV = true; + + USB_SUPPORT = true; + USB = true; + USB_PCI = true; + USB_ANNOUNCE_NEW_DEVICES = true; + USB_DEFAULT_PERSIST = true; + USB_DYNAMIC_MINORS = true; + USB_XHCI_HCD = true; + USB_XHCI_PCI = true; + }; + + power = { + PM = true; + ENERGY_MODEL = true; + ACPI = true; + ACPI_APEI = true; + ACPI_NUMA = true; + + CPU_FREQ = true; + CPU_FREQ_STAT = true; + CPU_FREQ_DEFAULT_GOV_SCHEDUTIL = true; + CPU_FREQ_GOV_SCHEDUTIL = true; + + CPU_IDLE = true; + CPU_IDLE_GOV_MENU = false; + CPU_IDLE_GOV_TEO = true; + + PCIEASPM = true; + PCIEASPM_POWER_SUPERSAVE = true; + + } // lib.optionalAttrs hostPlatform.isx86_64 { + X86_ACPI_CPUFREQ = true; + X86_ACPI_CPUFREQ_CPB = false; + } // lib.optionalAttrs (hostPlatform.isAarch64 || hostPlatform.isRiscV64) { + ACPI_CPPC_CPUFREQ = true; + }; + + framebuffer = { + DRM_SIMPLE_DRM = option true; + FB = true; + FB_EFI = true; + FB_SIMPLE = option true; + FB_DEVICE = false; + VGA_CONSOLE = false; + FRAMEBUFFER_CONSOLE = true; + FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER = true; + SYSFB_SIMPLEFB = true; + }; + + network = { + NET = true; + PACKET = true; + PACKET_DIAG = true; + UNIX = true; + UNIX_DIAG = true; + XDP_SOCKETS = true; + XDP_SOCKETS_DIAG = true; + INET = true; + SYN_COOKIES = true; + INET_DIAG = true; + INET_UDP_DIAG = true; + INET_RAW_DIAG = true; + + TCP_CONG_ADVANCED = true; + TCP_CONG_BIC = false; + TCP_CONG_CUBIC = false; + TCP_CONG_WESTWOOD = false; + TCP_CONG_HTCP = false; + TCP_CONG_BBR = true; + DEFAULT_BBR = true; + + IPV6 = true; + + NETFILTER = true; + NETFILTER_ADVANCED = true; + NETFILTER_INGRESS = true; + NETFILTER_EGRESS = true; + + NETFILTER_NETLINK_LOG = true; + NF_LOG_SYSLOG = true; + + NF_CONNTRACK = true; + NF_TABLES = true; + NF_TABLES_INET = true; + NFT_CT = true; + NFT_CONNLIMIT = true; + NFT_LIMIT = true; + NFT_LOG = true; + NFT_REJECT = true; + NFT_FIB_INET = true; + NF_TABLES_IPV4 = true; + NFT_FIB_IPV4 = true; + NF_TABLES_IPV6 = true; + NFT_FIB_IPV6 = true; + + NET_SCH_CAKE = true; + NET_SCH_FQ = true; + NET_SCH_DEFAULT = true; + DEFAULT_FQ = true; + DEFAULT_NET_SCH = "fq"; + + NETLINK_DIAG = true; + ETHTOOL_NETLINK = true; + + NETDEVICES = true; + ETHERNET = true; + }; + + chardev = { + TTY = true; + VT = true; + CONSOLE_TRANSLATIONS = true; + VT_CONSOLE = true; + UNIX98_PTYS = true; + + SERIAL_DEV_BUS = true; + SERIAL_DEV_CTRL_TTYPORT = true; + + HW_RANDOM = true; + HW_RANDOM_INTEL = false; + HW_RANDOM_AMD = false; + HW_RANDOM_VIA = false; + + TCG_TPM = true; + TCG_TPM2_HMAC = true; + HW_RANDOM_TPM = true; + TCG_TIS = true; + TCG_CRB = true; + }; + + input = { + INPUT = true; + INPUT_SPARSEKMAP = true; + INPUT_EVDEV = true; + INPUT_KEYBOARD = true; + }; + + filesystem = { + OVERLAY_FS = true; + OVERLAY_FS_REDIRECT_DIR = true; + OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW = false; + OVERLAY_FS_XINO_AUTO = true; + OVERLAY_FS_METACOPY = true; + + MSDOS_FS = true; + VFAT_FS = true; + FAT_DEFAULT_UTF8 = true; + + PROC_FS = true; + PROC_KCORE = false; + PROC_SYSCTL = true; + PROC_PAGE_MONITOR = true; + SYSFS = true; + TMPFS = true; + TMPFS_POSIX_ACL = true; + EFIVAR_FS = true; + + EROFS_FS = true; + EROFS_FS_XATTR = true; + EROFS_FS_POSIX_ACL = true; + EROFS_FS_SECURITY = false; + EROFS_FS_ZIP = true; + EROFS_FS_ZIP_ZSTD = true; + + NLS = true; + NLS_CODEPAGE_437 = true; + NLS_ISO8859_1 = true; + UNICODE = true; + }; + + fonts = { + FONTS = true; + FONT_TER16x32 = true; + }; + + systemd = lib.optionalAttrs (lib.meta.availableOn hostPlatform systemd) { + # Base requirements + DEVTMPFS = true; + CGROUPS = true; + INOTIFY_USER = true; + SIGNALFD = true; + TIMERFD = true; + EPOLL = true; + UNIX = true; + PROC_FS = true; + FHANDLE = true; + + # Legacy interfaces + UEVENT_HELPER = false; + FW_LOADER_USER_HELPER = false; + + # udev & virtualisation + DMIID = true; + + # SCSI device serial number retrieval + BLK_DEV_BSG = option true; + + # PrivateNetwork + NET_NS = true; + + # PrivateUser + USER_NS = true; + + # Optional but recommended + IPV6 = true; + AUTOFS_FS = true; + TMPFS_XATTR = true; + TMPFS_POSIX_ACL = true; + SECCOMP = true; + SECCOMP_FILTER = true; + KCMP = true; + NET_SCHED = true; + + # CPUShares + CGROUP_SCHED = true; + FAIR_GROUP_SCHED = true; + + # CPUQuota + CFS_BANDWIDTH = true; + + # IPaddress{Allow,Deny}, SocketBind{Allow,Deny}, RestrictNetworkInterfaces + BPF = true; + BPF_SYSCALL = true; + BPF_JIT = true; + CGROUP_BPF = true; + + # EFI + EFIVAR_FS = true; + EFI_PARTITION = true; + + # SMBIOS credentials + DMI = true; + DMI_SYSFS = true; + + # Real‐time scheduling + RT_GROUP_SCHED = false; + + # systemd-oomd + PSI = true; + MEMCG = true; + + AUDIT = false; + }; +} diff --git a/package/linux-hardened/package.nix b/package/linux-hardened/package.nix new file mode 100644 index 0000000..63e52fc --- /dev/null +++ b/package/linux-hardened/package.nix @@ -0,0 +1,251 @@ +{ self, ... }: { + lib, + stdenv, + buildPackages, + llvmPackages_19, + hostPlatform, + fetchFromGitHub, + buildEnv, + callPackage, + + linux-firmware, + sof-firmware, + wireless-regdb, + + systemd, + + jq, + python3, + perl, + flex, + bison, + bc, + openssl, + zstd, + + elfutils, + kmod, + ... +}@args: + +lib.makeOverridable ({ + llvmPackages ? llvmPackages_19, + instSetArch ? hostPlatform.gccarch or null, + extraConfig ? { }, + firmwarePackages ? [ + linux-firmware + sof-firmware + wireless-regdb + ], + extraFirmware ? [ ], + ... +}: + +let + inherit (self.lib) kernel; + + inherit (lib.attrsets) + filterAttrs + mapAttrsToList + mergeAttrsList; + + inherit (lib.strings) + concatStringsSep; + + firmwareEnv = buildEnv { + name = "linux-firmware"; + pathsToLink = [ "/lib/firmware" ]; + paths = firmwarePackages; + } + "/lib/firmware"; + + config = lib.mergeAttrsList (map kernel.flattenAttrs [ + (import ./config.nix { inherit kernel lib hostPlatform systemd; }) + extraConfig + { + EXTRA_FIRMWARE = extraFirmware; + EXTRA_FIRMWARE_DIR = kernel.option firmwareEnv; + } + ]); +in stdenv.mkDerivation (finalAttrs: { + __structuredAttrs = true; + + pname = "linux-hardened"; + version = "6.10.4-hardened1"; + + modDirVersion = lib.versions.pad 3 finalAttrs.version; + + src = fetchFromGitHub { + owner = "anthraxx"; + repo = finalAttrs.pname; + rev = "v${finalAttrs.version}"; + hash = "sha256-qq2vmrUIYUuXEwuZoXrXbZY/li+ReFNuqhsy1R0yx0s="; + }; + + depsBuildBuild = [ + jq + + flex + bison + bc + python3 + perl + openssl + + zstd + ]; + + nativeBuildInputs = [ + elfutils + kmod + ]; + + makeFlags = [ + "ARCH:=${hostPlatform.linuxArch}" + + "HOSTCC:=${buildPackages.stdenv.cc}/bin/${buildPackages.stdenv.cc.targetPrefix}cc" + "HOSTCXX:=${buildPackages.stdenv.cc}/bin/${buildPackages.stdenv.cc.targetPrefix}c++" + "HOSTLD:=${buildPackages.stdenv.cc}/bin/${buildPackages.stdenv.cc.targetPrefix}ld" + "HOSTAR:=${buildPackages.stdenv.cc}/bin/${buildPackages.stdenv.cc.targetPrefix}ar" + + "CC:=${llvmPackages.clang-unwrapped}/bin/clang" + "LD:=${llvmPackages.lld}/bin/ld.lld" + "AR:=${llvmPackages.llvm}/bin/llvm-ar" + "NM:=${llvmPackages.llvm}/bin/llvm-nm" + "OBJCOPY:=${llvmPackages.llvm}/bin/llvm-objcopy" + "OBJDUMP:=${llvmPackages.llvm}/bin/llvm-objdump" + "READELF:=${llvmPackages.llvm}/bin/llvm-readelf" + "STRIP:=${llvmPackages.llvm}/bin/llvm-strip" + ]; + + configfile = config |> kernel.mkConfig; + + requiredPresent = config + |> filterAttrs (n: v: !kernel.isOptional v && kernel.getValue v != false) + |> mapAttrsToList kernel.mkKeyValue; + + optionalPresent = config + |> filterAttrs (n: v: kernel.isOptional v && kernel.getValue v != false) + |> mapAttrsToList kernel.mkKeyValue; + + requiredAbsent = config + |> filterAttrs (n: v: !kernel.isOptional v && kernel.getValue v == false) + |> mapAttrsToList (n: v: kernel.mkKey n); + + optionalAbsent = config + |> filterAttrs (n: v: kernel.isOptional v && kernel.getValue v == false) + |> mapAttrsToList (n: v: kernel.mkKey n); + + postPatch = '' + patchShebangs scripts/ + ''; + + preConfigure = '' + mkdir build + + export KBUILD_BUILD_TIMESTAMP="$(date -u -d @$SOURCE_DATE_EPOCH)" + export KBUILD_OUTPUT="$(pwd)/build" + + makeFlags+=( "-j $NIX_BUILD_CORES" ) + '' + lib.optionalString (hostPlatform ? linux-kernel.target) '' + export KBUILD_IMAGE=${lib.escapeShellArg hostPlatform.linux-kernel.target} + '' + lib.optionalString (instSetArch != null) '' + export KCFLAGS="-march=${lib.escapeShellArg instSetArch}" + ''; + + configurePhase = '' + runHook preConfigure + + cat >build/.config <<<"$configfile" + make "''${makeFlags[@]}" olddefconfig + + runHook postConfigure + ''; + + postConfigure = '' + # Verify configuration + for keyValue in "''${requiredPresent[@]}"; do + if ! grep -F -x -q "$keyValue" build/.config; then + printf 'Required: %s\nActual: %s\n\n' "$keyValue" \ + "$(grep -E "''${keyValue%%=*}[ =]" build/.config || echo "(absent)")" >&2 + exit 1 + fi + done + + for key in "''${requiredAbsent[@]}"; do + if grep -E -q "^$key=" build/.config; then + printf 'Required: %s unset or absent.\n Actual: %s\n\n' "$key" \ + "$(grep -E -q "^key=" build/.config)" >&2 + exit 1 + fi + done + + for keyValue in "''${optionalPresent[@]}"; do + if ! grep -F -x -q "$keyValue" build/.config; then + printf 'Suggested: %s\nActual: %s\n\n' "$keyValue" \ + "$(grep -E "''${keyValue%%=*}[ =]" build/.config || echo "(absent)")" >&2 + fi + done + + for key in "''${optionalAbsent[@]}"; do + if grep -E -q "^$key=" build/.config; then + printf 'Suggested: %s unset or absent.\nActual: %s\n\n' "$key" \ + "$(grep -E "^$key=" build/.config)" >&2 + fi + done + ''; + + preInstall = let + installkernel = buildPackages.writeShellScriptBin "installkernel" '' + cp "$2" "$4" + cp "$3" "$4" + ''; + in '' + export HOME=${installkernel} + ''; + + installFlags = [ + "INSTALL_PATH=$(out)" + "INSTALL_MOD_PATH=$(out)" + ]; + + installTargets = [ + "install" + "modules_install" + ]; + + postInstall = '' + depmod -b "$out" ${finalAttrs.modDirVersion} + touch "$out/lib/modules/${finalAttrs.modDirVersion}/modules.order" + ''; + + passthru = { + profile = import ./profile.nix { inherit kernel lib hostPlatform; }; + + config = with kernel; { + isYes = option: getValue config.${option} or false == true; + isNo = option: getValue config.${option} or false == false; + isModule = option: false; + + isEnabled = option: getValue config.${option} or false == true; + isDisabled = option: getValue config.${option} or false == false; + }; + + isHardened = true; + isLibre = false; + isZen = false; + + features = { + efiBootStub = true; + }; + + kernelOlder = lib.versionOlder finalAttrs.version; + kernelAtLeast = lib.versionAtLeast finalAttrs.version; + }; + + meta = { + homepage = "https://github.com/anthraxx/linux-hardened"; + license = lib.licenses.gpl2Only; + maintainers = with lib.maintainers; [ mvs ]; + platforms = [ "x86_64-linux" "aarch64-linux" "riscv64-linux" ]; + }; +})) args diff --git a/package/linux-hardened/profile.nix b/package/linux-hardened/profile.nix new file mode 100644 index 0000000..a863b00 --- /dev/null +++ b/package/linux-hardened/profile.nix @@ -0,0 +1,231 @@ +{ kernel, lib, hostPlatform }: with kernel; { + paravirt = { + HYPERVISOR_GUEST = true; + PARAVIRT = true; + PARAVIRT_SPINLOCKS = true; + KVM_GUEST = true; + ARCH_CPUIDLE_HALTPOLL = true; + PARAVIRT_CLOCK = true; + + HALTPOLL_CPUIDLE = true; + + FW_CFG_SYSFS = true; + + BLK_MQ_VIRTIO = true; + VIRTIO_BLK = true; + VIRTIO_NET = true; + VIRTIO_CONSOLE = true; + + HW_RANDOM_VIRTIO = true; + + DRM = true; + DRM_FBDEV_EMULATION = true; + DRM_VIRTIO_GPU = true; + DRM_VIRTIO_GPU_KMS = true; + DRM_BOCHS = true; + DRM_SIMPLEDRM = true; + + VIRT_DRIVERS = true; + VMGENID = true; + + VIRTIO_MENU = true; + VIRTIO = true; + VIRTIO_PCI = true; + VIRTIO_PCI_LEGACY = false; + VIRTIO_BALLOON = true; + VIRTIO_INPUT = true; + + VIRTIO_IOMMU = true; + + FUSE_FS = true; + VIRTIO_FS = true; + }; + + physical = { + ACPI_BUTTON = true; + ACPI_VIDEO = true; + ACPI_FAN = true; + ACPI_TAD = true; + ACPI_PROCESSOR_AGGREGATOR = true; + ACPI_THERMAL = true; + ACPI_PCI_SLOT = true; + + SCSI = true; + BLK_DEV_SD = true; + CHR_DEV_SG = true; + SCSI_CONSTANTS = true; + SCSI_SCAN_ASYNC = true; + + USB_STORAGE = true; + USB_UAS = true; + + LEDS_CLASS = true; + LEDS_TRIGGERS = true; + LEDS_TRIGGER_PANIC = true; + LEDS_TRIGGER_NETDEV = true; + + EDAC = true; + + THERMAL = true; + THERMAL_NETLINK = true; + THERMAL_DEFAULT_GOV_FAIR_SHARE = true; + THERMAL_GOV_FAIR_SHARE = true; + + POWERCAP = true; + + RAS = true; + }; + + portable = { + PREEMPT_VOLUNTARY = true; + + SUSPEND = true; + WQ_POWER_EFFICIENT_DEFAULT = true; + ACPI_BATTERY = true; + + HOTPLUG_PCI_PCIE = true; + HOTPLUG_PCI = true; + + MEDIA_SUPPORT = true; + MEDIA_SUPPORT_FILTER = true; + MEDIA_SUBDRV_AUTOSELECT = true; + MEDIA_CAMERA_SUPPORT = true; + MEDIA_USB_SUPPORT = true; + USB_VIDEO_CLASS = true; + USB_VIDEO_CLASS_INPUT_EVDEV = true; + + HID_BATTERY_STRENGTH = true; + + USB_NET_DRIVERS = true; + USB_RTL8152 = true; + USB_USBNET = true; + USB_NET_AX88179_178A = true; + USB_NET_CDCETHER = true; + USB_NET_CDC_SUBSET = true; + + BACKLIGHT_CLASS_DEVICE = true; + + TYPEC = true; + TYPEC_TCPM = true; + TYPEC_TCPCI = true; + TYPEC_UCSI = true; + UCSI_ACPI = true; + TYPEC_DP_ALTMODE = true; + + MMC = true; + MMC_BLOCK = true; + + USB4 = true; + + KFENCE_SAMPLE_INTERVAL = "500"; + }; + + dm-crypt = { + MD = true; + MD_BITMAP_FILE = false; + BLK_DEV_DM = true; + DM_CRYPT = true; + DM_UEVENT = true; + DM_INTEGRITY = true; + + CRYPTO_AES = true; + CRYPTO_XTS = true; + CRYPTO_AEGIS128 = true; + CRYPTO_SHA256 = true; + + CRYPTO_USER_API_HASH = true; + CRYPTO_USER_API_SKCIPHER = true; + } // lib.optionalAttrs hostPlatform.isx86_64 { + CRYPTO_AES_NI_INTEL = true; + CRYPTO_AEGIS128_AESNI_SSE2 = true; + CRYPTO_SHA256_SSSE3 = true; + } // lib.optionalAttrs hostPlatform.isRiscV64 { + CRYPTO_AES_RISCV64 = true; + CRYPTO_SHA256_RISCV64 = true; + } // lib.optionalAttrs hostPlatform.isAarch64 { + CRYPTO_AES_ARM64 = true; + CRYPTO_AES_ARM64_CE = true; + CRYPTO_AES_ARM64_CE_BLK = true; + CRYPTO_AES_ARM64_NEON_BLK = true; + CRYPTO_AES_ARM64_BS = true; + CRYPTO_AEGIS128_SIMD = true; + CRYPTO_SHA256_ARM64 = true; + }; + + wireless = { + WIRELESS = true; + CFG80211 = true; + CFG80211_DEFAULT_PS = true; + CFG80211_CRDA_SUPPORT = true; + MAC80211 = true; + MAC80211_RC_MINSTREL = true; + MAC80211_RC_DEFAULT_MINSTREL = true; + MAC80211_LEDS = true; + + BT = true; + BT_BREDR = true; + BT_RFCOMM = true; + BT_HIDP = true; + BT_LE = true; + BT_LEDS = true; + + BT_HCIBTUSB_AUTOSUSPEND = option true; + BT_HCIBTUSB_BCM = option false; + BT_HCIBTUSB_RTL = option false; + + RFKILL = true; + RFKILL_INPUT = true; + + # iwd + KEYS = true; + CRYPTO_USER_API_SKCIPHER = true; + CRYPTO_USER_API_HASH = true; + CRYPTO_HMAC = true; + CRYPTO_CMAC = true; + CRYPTO_MD4 = true; + CRYPTO_MD5 = true; + CRYPTO_SHA1 = true; + CRYPTO_SHA256 = true; + CRYPTO_SHA512 = true; + CRYPTO_AES = true; + CRYPTO_ECB = true; + CRYPTO_DES = true; + CRYPTO_CBC = true; + + ASYMMETRIC_KEY_TYPE = option true; + ASYMMETRIC_PUBLIC_KEY_SUBTYPE = option true; + X509_CERTIFICATE_PARSER = option true; + PKCS7_MESSAGE_PARSER = option true; + PKCS8_PRIVATE_KEY_PARSER = option true; + } // lib.optionalAttrs hostPlatform.isx86_64 { + CRYPTO_AES_NI_INTEL = option true; + CRYPTO_DES3_EDE_X86_64 = option true; + CRYPTO_SHA1_SSSE3 = option true; + CRYPTO_SHA256_SSSE3 = option true; + CRYPTO_SHA512_SSSE3 = option true; + } // lib.optionalAttrs hostPlatform.isRiscV64 { + CRYPTO_AES_RISCV64 = option true; + CRYPTO_SHA256_RISCV64 = option true; + CRYPTO_SHA512_RISCV64 = option true; + } // lib.optionalAttrs hostPlatform.isAarch64 { + CRYPTO_AES_ARM64_CE = option true; + CRYPTO_AES_ARM64_CE_BLK = option true; + CRYPTO_SHA1_ARM64_CE = option true; + CRYPTO_SHA256_ARM64 = option true; + CRYPTO_SHA2_ARM64_CE = option true; + CRYPTO_SHA512_ARM64 = option true; + CRYPTO_SHA512_ARM64_CE = option true; + }; + + audio = { + SOUND = true; + SND = true; + SND_PCM_TIMER = true; + SND_DYNAMIC_MINORS = true; + SND_SUPPORT_OLD_API = false; + SND_PCI = true; + + SND_USB = true; + SND_USB_AUDIO = true; + }; +} diff --git a/package/locale-en_EU/en_EU b/package/locale-en_EU/en_EU new file mode 100644 index 0000000..5c23884 --- /dev/null +++ b/package/locale-en_EU/en_EU @@ -0,0 +1,120 @@ +comment_char % +escape_char / + +LC_IDENTIFICATION +title "Custom locale" +source "" +address "" +contact "Mikael Voss" +email "" +language "en" +territory "EU" +revision "0" +date "2022-10-12" + +category "i18n:2012";LC_IDENTIFICATION +category "i18n:2012";LC_CTYPE +category "i18n:2012";LC_COLLATE +category "i18n:2012";LC_MONETARY +category "i18n:2012";LC_NUMERIC +category "i18n:2012";LC_TIME +category "i18n:2012";LC_MESSAGES +category "i18n:2012";LC_PAPER +category "i18n:2012";LC_NAME +category "i18n:2012";LC_ADDRESS +category "i18n:2012";LC_TELEPHONE +category "i18n:2012";LC_MEASUREMENT +END LC_IDENTIFICATION + +LC_CTYPE +copy "i18n_ctype" + +translit_start +include "translit_neutral";"" +translit_end + +translit_start +include "translit_combining";"" +translit_end +END LC_CTYPE + +LC_COLLATE +copy "iso14651_t1" +END LC_COLLATE + +LC_NUMERIC +decimal_point "." +thousands_sep "" +grouping 3;3 +END LC_NUMERIC + +LC_MONETARY +int_curr_symbol "EUR " +currency_symbol "" +mon_decimal_point "." +mon_thousands_sep "" +mon_grouping 3;3 +positive_sign "" +negative_sign "-" +int_frac_digits 2 +frac_digits 2 +p_cs_precedes 0 +p_sep_by_space 1 +n_cs_precedes 0 +n_sep_by_space 1 +p_sign_posn 1 +n_sign_posn 1 +END LC_MONETARY + +LC_TIME +abday "Sun";"Mon";"Tue";"Wed";"Thu";"Fri";"Sat" +day "Sunday";"Monday";"Tuesday";"Wednesday";"Thursday";"Friday";"Saturday" +abmon "Jan";"Feb";"Mar";"Apr";"May";"Jun";"Jul";"Aug";"Sep";"Oct";"Nov";"Dec" +mon "January";"February";"March";"April";"May";"June";/ + "July";"August";"September";"October";"November";"December" +week 7;19971201;4 +d_t_fmt "%F %T %Z" +date_fmt "%F %T %Z" +d_fmt "%F" +t_fmt "%T" +t_fmt_ampm "" +am_pm "";"" +END LC_TIME + +LC_MESSAGES +yesexpr "^[+1Tty]" +noexpr "^[-0Ffn]" +END LC_MESSAGES + +LC_PAPER +% ISO A4 +height 297 +width 210 +END LC_PAPER + +LC_NAME +name_fmt "%p%t%g%m%t%f" +% profession + primary + additionals + family +END LC_NAME + +LC_ADDRESS +postal_fmt "%n%N%a%N%d%N%f%N%b%t%e%t%r%N%s%t%h%N%z%t%T%S%N%c%N" +% person’s name +% c/o person +% department +% firm +% building + floor + room +% street + number +% postal code + town +% state or provice +% country +END LC_ADDRESS + +LC_TELEPHONE +tel_int_fmt "+%c %a%t%l" +END LC_TELEPHONE + +LC_MEASUREMENT +% metric +measurement 1 +END LC_MEASUREMENT diff --git a/package/locale-en_EU/package.nix b/package/locale-en_EU/package.nix new file mode 100644 index 0000000..b9d7667 --- /dev/null +++ b/package/locale-en_EU/package.nix @@ -0,0 +1,15 @@ +{ ... }: { pkgs, lib, callPackage, allLocales ? false, locales ? [ "en_EU.UTF-8/UTF-8" ] }: + +let glibcLocales = callPackage + (pkgs.path + "/pkgs/development/libraries/glibc/locales.nix") + { inherit allLocales locales; }; +in glibcLocales.overrideAttrs (prevAttrs: { + postPatch = prevAttrs.postPatch + '' + cp ${./en_EU} localedata/locales/en_EU + echo 'en_EU.UTF-8/UTF-8 \' >>localedata/SUPPORTED + ''; + + meta = prevAttrs.meta // { + maintainers = with lib.maintainers; [ mvs ]; + }; +}) diff --git a/shell/default.nix b/shell/default.nix new file mode 100644 index 0000000..998c4e4 --- /dev/null +++ b/shell/default.nix @@ -0,0 +1,5 @@ +{ colmena, ... }: { mkShell, system }: + +mkShell { + packages = [ colmena.packages.${system}.colmena ]; +}