commit 73ff9ee8ee83f82ea10329bf4882c1b0b9691e01 Author: root Date: Mon Mar 16 12:19:11 2026 -0300 . diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..576ced9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +result +.cache diff --git a/.sops.yaml b/.sops.yaml new file mode 100644 index 0000000..3f58548 --- /dev/null +++ b/.sops.yaml @@ -0,0 +1,9 @@ +keys: + - &root age1y0tj3kt67pfnj38t9c8g2ghry3a0mhcq8rrqv5xr4jekwepxaelqzu3dkf + - &user age16v8w7q4wmn22hhakq2uzaus2508rhldm7lcwh0kukshzjzyhuqesqz44ze +creation_rules: + - path_regex: secrets/[^/]+\.yaml$ + key_groups: + - age: + - *root + - *user diff --git a/configuration.nix b/configuration.nix new file mode 100644 index 0000000..4848963 --- /dev/null +++ b/configuration.nix @@ -0,0 +1,143 @@ +# Edit this configuration file to define what should be installed on +# your system. Help is available in the configuration.nix(5) man page, on +# https://search.nixos.org/options and in the NixOS manual (`nixos-help`). + +{ + config, + lib, + pkgs, + ... +}: +{ + sops.defaultSopsFile = ./secrets/home.yaml; + sops.age.keyFile = "/.persist/root/.config/sops/age/keys.txt"; + sops.secrets."root/ssh/desktop" = { + path = "/root/.ssh/desktop"; + mode = "0600"; + }; + nix.settings.experimental-features = [ + "nix-command" + "flakes" + ]; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + + boot.initrd.systemd.enable = true; + boot.loader.systemd-boot.enable = true; + boot.loader.efi.canTouchEfiVariables = true; + + # Set your time zone. + time.timeZone = "America/Sao_Paulo"; + + # Select internationalisation properties. + i18n.defaultLocale = "en_US.UTF-8"; + #console = { + # # font = "Lat2-Terminus16"; + # keyMap = "us"; + # useXkbConfig = true; # use xkb.options in tty. + #}; + + # services.xserver.xkb.layout = "us"; + # services.xserver.xkb.options = "eurosign:e,caps:escape"; + services.printing.enable = true; + + services = { + xserver.xkb = { + layout = "us"; + variant = "altgr-intl"; + }; + pipewire = { + enable = true; + alsa.enable = true; + alsa.support32Bit = true; + pulse.enable = true; + # jack.enable = true; + }; + logind.settings.Login = { + HandlePowerKey = "ignore"; + HandlePowerKeyLongPress = "ignore"; + HandleRebootKey = "ignore"; + HandleRebootKeyLongPress = "ignore"; + HandleHibernateKey = "ignore"; + HandleHibernateKeyLongPress = "ignore"; + }; + getty = { + autologinUser = "user"; + autologinOnce = true; + }; + # greetd = { + # enable = true; + # settings = rec { + # initial_session = { + # command = "${pkgs.niri}/bin/niri-session"; + # user = "user"; + # }; + # default_session = initial_session; + # }; + # }; + tailscale.enable = true; + }; + + hardware = { + graphics = { + enable = true; + enable32Bit = true; + }; + bluetooth = { + enable = true; + powerOnBoot = true; + settings = { + General = { + Enable = "Source,Sink,Media,Socket"; + }; + }; + }; + }; + + xdg.portal = { + enable = true; + xdgOpenUsePortal = true; + # config.common.default = [ "*" ]; + extraPortals = [ + pkgs.xdg-desktop-portal-gnome + pkgs.gnome-keyring + pkgs.xdg-desktop-portal-gtk + ]; + }; + + qt = { + enable = true; + }; + + fonts.packages = with pkgs; [ + fira-code-symbols + nerd-fonts.monaspace + ]; + + environment.sessionVariables = { + NIXOS_OZONE_WL = "1"; + EDITOR = "nvim"; + GTK_IM_MODULE = "simple"; + }; + + security.pki.certificateFiles = [ ./templates/certs/hydra_root_ca.crt ]; + + system.stateVersion = "25.11"; + + systemd = { + user.services.polkit-gnome-authentication-agent-1 = { + description = "polkit-gnome-authentication-agent-1"; + wantedBy = [ "graphical-session.target" ]; + wants = [ "graphical-session.target" ]; + after = [ "graphical-session.target" ]; + serviceConfig = { + Type = "simple"; + ExecStart = "${pkgs.polkit_gnome}/libexec/polkit-gnome-authentication-agent-1"; + Restart = "on-failure"; + RestartSec = 1; + TimeoutStopSec = 10; + }; + }; + }; + services.openssh.enable = true; +} diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..2b40de6 --- /dev/null +++ b/flake.lock @@ -0,0 +1,533 @@ +{ + "nodes": { + "dgop": { + "inputs": { + "nixpkgs": [ + "dms", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1765838956, + "narHash": "sha256-A3a2ZfvjirX8VIdIPI+nAyukWs6vx4vet3fU0mpr7lU=", + "owner": "AvengeMedia", + "repo": "dgop", + "rev": "0ff697a4e3418966caa714c838fc73f1ef6ba59b", + "type": "github" + }, + "original": { + "owner": "AvengeMedia", + "repo": "dgop", + "type": "github" + } + }, + "disko": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1768920986, + "narHash": "sha256-CNzzBsRhq7gg4BMBuTDObiWDH/rFYHEuDRVOwCcwXw4=", + "owner": "nix-community", + "repo": "disko", + "rev": "de5708739256238fb912c62f03988815db89ec9a", + "type": "github" + }, + "original": { + "owner": "nix-community", + "ref": "latest", + "repo": "disko", + "type": "github" + } + }, + "dms": { + "inputs": { + "dgop": "dgop", + "nixpkgs": "nixpkgs", + "quickshell": "quickshell" + }, + "locked": { + "lastModified": 1766776522, + "narHash": "sha256-wS2fSepxdtOr4RErdEY91hkxOjsrs2nA2nm72eZMEEU=", + "owner": "AvengeMedia", + "repo": "DankMaterialShell", + "rev": "987856a1de35c62dc0930b007b561545d6a832a8", + "type": "github" + }, + "original": { + "owner": "AvengeMedia", + "repo": "DankMaterialShell", + "rev": "987856a1de35c62dc0930b007b561545d6a832a8", + "type": "github" + } + }, + "flake-parts": { + "inputs": { + "nixpkgs-lib": [ + "neovim-nightly-overlay", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1769996383, + "narHash": "sha256-AnYjnFWgS49RlqX7LrC4uA+sCCDBj0Ry/WOJ5XWAsa0=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "57928607ea566b5db3ad13af0e57e921e6b12381", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-parts_2": { + "inputs": { + "nixpkgs-lib": [ + "nur", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1733312601, + "narHash": "sha256-4pDvzqnegAfRkPwO3wmwBhVi/Sye1mzps0zHWYnP88c=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "205b12d8b7cd4802fbcb8e8ef6a0f1408781a4f9", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "home-manager": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1770260404, + "narHash": "sha256-3iVX1+7YUIt23hBx1WZsUllhbmP2EnXrV8tCRbLxHc8=", + "owner": "nix-community", + "repo": "home-manager", + "rev": "0d782ee42c86b196acff08acfbf41bb7d13eed5b", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "home-manager", + "rev": "0d782ee42c86b196acff08acfbf41bb7d13eed5b", + "type": "github" + } + }, + "home-manager_2": { + "inputs": { + "nixpkgs": [ + "impermanence", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1768598210, + "narHash": "sha256-kkgA32s/f4jaa4UG+2f8C225Qvclxnqs76mf8zvTVPg=", + "owner": "nix-community", + "repo": "home-manager", + "rev": "c47b2cc64a629f8e075de52e4742de688f930dc6", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "home-manager", + "type": "github" + } + }, + "impermanence": { + "inputs": { + "home-manager": "home-manager_2", + "nixpkgs": "nixpkgs_2" + }, + "locked": { + "lastModified": 1769548169, + "narHash": "sha256-03+JxvzmfwRu+5JafM0DLbxgHttOQZkUtDWBmeUkN8Y=", + "owner": "nix-community", + "repo": "impermanence", + "rev": "7b1d382faf603b6d264f58627330f9faa5cba149", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "impermanence", + "type": "github" + } + }, + "microvm": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ], + "spectrum": "spectrum" + }, + "locked": { + "lastModified": 1770310890, + "narHash": "sha256-lyWAs4XKg3kLYaf4gm5qc5WJrDkYy3/qeV5G733fJww=", + "owner": "microvm-nix", + "repo": "microvm.nix", + "rev": "68c9f9c6ca91841f04f726a298c385411b7bfcd5", + "type": "github" + }, + "original": { + "owner": "microvm-nix", + "repo": "microvm.nix", + "type": "github" + } + }, + "neovim-nightly-overlay": { + "inputs": { + "flake-parts": "flake-parts", + "neovim-src": "neovim-src", + "nixpkgs": "nixpkgs_3" + }, + "locked": { + "lastModified": 1771632300, + "narHash": "sha256-uP5SbbbN86+LZ8VubL01UKD6bez5DK9prqIqQOMy3Jw=", + "owner": "nix-community", + "repo": "neovim-nightly-overlay", + "rev": "0f601090d4d54b3da0d03e270cb6a5c68bf84dd3", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "neovim-nightly-overlay", + "type": "github" + } + }, + "neovim-src": { + "flake": false, + "locked": { + "lastModified": 1771630915, + "narHash": "sha256-7RPG+RG/e0O79HjNT/ztC7K7j/xXazltq3TPk1mauqY=", + "owner": "neovim", + "repo": "neovim", + "rev": "d79a9dcd422133bc1e4b4ef94444962560d7a6d7", + "type": "github" + }, + "original": { + "owner": "neovim", + "repo": "neovim", + "type": "github" + } + }, + "niri-branch": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ], + "rust-overlay": "rust-overlay" + }, + "locked": { + "lastModified": 1769284707, + "narHash": "sha256-X60XGpLjNTgYyaC/gChHGpqQqLWGI+0n5BbWaybXKiE=", + "owner": "argosnothing", + "repo": "niri", + "rev": "6dcaa349acf3b04ed1593022388b4f1cbef8893b", + "type": "github" + }, + "original": { + "owner": "argosnothing", + "ref": "hidden-workspaces", + "repo": "niri", + "type": "github" + } + }, + "niri-scratchpad": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": [ + "nixpkgs" + ], + "rust-overlay": "rust-overlay_2" + }, + "locked": { + "lastModified": 1765743947, + "narHash": "sha256-kx8XFbzG59eLNImygoN9jRjgaxR7kvmjg64equccmK0=", + "owner": "argosnothing", + "repo": "niri-scratchpad-rs", + "rev": "163420c14c9199d311627501eedee2a3b2507db2", + "type": "github" + }, + "original": { + "owner": "argosnothing", + "ref": "hidden-workspaces", + "repo": "niri-scratchpad-rs", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1766651565, + "narHash": "sha256-QEhk0eXgyIqTpJ/ehZKg9IKS7EtlWxF3N7DXy42zPfU=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "3e2499d5539c16d0d173ba53552a4ff8547f4539", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1768564909, + "narHash": "sha256-Kell/SpJYVkHWMvnhqJz/8DqQg2b6PguxVWOuadbHCc=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "e4bae1bd10c9c57b2cf517953ab70060a828ee6f", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_3": { + "locked": { + "lastModified": 1771207753, + "narHash": "sha256-b9uG8yN50DRQ6A7JdZBfzq718ryYrlmGgqkRm9OOwCE=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "d1c15b7d5806069da59e819999d70e1cec0760bf", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_4": { + "locked": { + "lastModified": 1744536153, + "narHash": "sha256-awS2zRgF4uTwrOKwwiJcByDzDOdo3Q1rPZbiHQg/N38=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "18dd725c29603f582cf1900e0d25f9f1063dbf11", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_5": { + "locked": { + "lastModified": 1771342064, + "narHash": "sha256-Aros+b3kQpzJAyxjDyhLUmnEfzQfyor2tiIoUTSgki0=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "3f03a5f1bede585f58c878c22cb12988bb0d1ed2", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_6": { + "locked": { + "lastModified": 1770562336, + "narHash": "sha256-ub1gpAONMFsT/GU2hV6ZWJjur8rJ6kKxdm9IlCT0j84=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "d6c71932130818840fc8fe9509cf50be8c64634f", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nur": { + "inputs": { + "flake-parts": "flake-parts_2", + "nixpkgs": "nixpkgs_6" + }, + "locked": { + "lastModified": 1770758031, + "narHash": "sha256-YEq6M9OOEOl7l2zr/YjOi2UnuQZZ02HvXebpWGpkEHM=", + "owner": "nix-community", + "repo": "NUR", + "rev": "6701aa01b90606ab75078c1910bb991b8e7a389b", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "NUR", + "type": "github" + } + }, + "quickshell": { + "inputs": { + "nixpkgs": [ + "dms", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1766386896, + "narHash": "sha256-1uql4y229Rh+/2da99OVNe6DfsjObukXkf60TYRCvhI=", + "ref": "refs/heads/master", + "rev": "3918290c1bcd93ed81291844d9f1ed146672dbfc", + "revCount": 714, + "type": "git", + "url": "https://git.outfoxxed.me/quickshell/quickshell" + }, + "original": { + "rev": "3918290c1bcd93ed81291844d9f1ed146672dbfc", + "type": "git", + "url": "https://git.outfoxxed.me/quickshell/quickshell" + } + }, + "root": { + "inputs": { + "disko": "disko", + "dms": "dms", + "home-manager": "home-manager", + "impermanence": "impermanence", + "microvm": "microvm", + "neovim-nightly-overlay": "neovim-nightly-overlay", + "niri-branch": "niri-branch", + "niri-scratchpad": "niri-scratchpad", + "nixpkgs": "nixpkgs_5", + "nur": "nur", + "sops-nix": "sops-nix" + } + }, + "rust-overlay": { + "inputs": { + "nixpkgs": [ + "niri-branch", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1767322002, + "narHash": "sha256-yHKXXw2OWfIFsyTjduB4EyFwR0SYYF0hK8xI9z4NIn0=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "03c6e38661c02a27ca006a284813afdc461e9f7e", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, + "rust-overlay_2": { + "inputs": { + "nixpkgs": "nixpkgs_4" + }, + "locked": { + "lastModified": 1763952169, + "narHash": "sha256-+PeDBD8P+NKauH+w7eO/QWCIp8Cx4mCfWnh9sJmy9CM=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "ab726555a9a72e6dc80649809147823a813fa95b", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, + "sops-nix": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1770683991, + "narHash": "sha256-xVfPvXDf9QN3Eh9dV+Lw6IkWG42KSuQ1u2260HKvpnc=", + "owner": "Mic92", + "repo": "sops-nix", + "rev": "8b89f44c2cc4581e402111d928869fe7ba9f7033", + "type": "github" + }, + "original": { + "owner": "Mic92", + "repo": "sops-nix", + "type": "github" + } + }, + "spectrum": { + "flake": false, + "locked": { + "lastModified": 1759482047, + "narHash": "sha256-H1wiXRQHxxPyMMlP39ce3ROKCwI5/tUn36P8x6dFiiQ=", + "ref": "refs/heads/main", + "rev": "c5d5786d3dc938af0b279c542d1e43bce381b4b9", + "revCount": 996, + "type": "git", + "url": "https://spectrum-os.org/git/spectrum" + }, + "original": { + "type": "git", + "url": "https://spectrum-os.org/git/spectrum" + } + }, + "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..d6a7c79 --- /dev/null +++ b/flake.nix @@ -0,0 +1,121 @@ +{ + description = "NixOS flake"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs"; + sops-nix = { + url = "github:Mic92/sops-nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + microvm = { + url = "github:microvm-nix/microvm.nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + disko = { + url = "github:nix-community/disko/latest"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + impermanence.url = "github:nix-community/impermanence"; + neovim-nightly-overlay.url = "github:nix-community/neovim-nightly-overlay"; + home-manager = { + url = "github:nix-community/home-manager/0d782ee42c86b196acff08acfbf41bb7d13eed5b"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + nur.url = "github:nix-community/NUR"; + niri-branch = { + url = "github:argosnothing/niri/hidden-workspaces"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + niri-scratchpad = { + url = "github:argosnothing/niri-scratchpad-rs/hidden-workspaces"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + dms.url = "github:AvengeMedia/DankMaterialShell/987856a1de35c62dc0930b007b561545d6a832a8"; + }; + + outputs = + inputs@{ + nixpkgs, + sops-nix, + impermanence, + home-manager, + ... + }: + let + hostname = "amelia"; + system = "x86_64-linux"; + pkgs = import nixpkgs { + inherit system; + config.allowUnfree = true; + # overlays = [ inputs.neovim-nightly-overlay.overlays.default ]; + }; + microvm = inputs.microvm.nixosModules.host; + in + { + nixosConfigurations."${hostname}" = nixpkgs.lib.nixosSystem { + inherit system pkgs; + specialArgs = { + inherit + nixpkgs + impermanence + home-manager + microvm + sops-nix + ; + hostname = hostname; + }; + modules = [ + ./users.nix + ./storage.nix + ./configuration.nix + ./impermanence.nix + ./networking.nix + ./packages.nix + ./kernel + ./home + inputs.sops-nix.nixosModules.sops + inputs.microvm.nixosModules.host + (import ./vms) + inputs.disko.nixosModules.disko + inputs.impermanence.nixosModules.impermanence + inputs.home-manager.nixosModules.home-manager + { + home-manager.useGlobalPkgs = true; + home-manager.useUserPackages = true; + home-manager.sharedModules = [ + inputs.sops-nix.homeManagerModules.sops + inputs.dms.homeModules.dank-material-shell + ]; + nixpkgs.overlays = [ + (_: prev: { + niri-scratchpad = inputs.niri-scratchpad.packages.${prev.system}.default; + vimPlugins = prev.vimPlugins.extend ( + f: p: { + neotest = p.neotest.overrideAttrs { + src = prev.fetchzip { + url = "https://github.com/archie-judd/neotest/archive/c8dd7597bb4182c0547d188e1dd5f684a4f01852.zip"; + sha256 = "sha256-E/Heh+mAxvN5RaWqv1UJuHSA90c0evMKFkDD1BrpV7g="; + }; + }; + neotest-pest = p.neotest-pest.overrideAttrs (_: { + src = prev.fetchFromGitHub { + owner = "jradtilbrook"; + repo = "neotest-pest"; + rev = "e92131bde9c24e632c4ad76124f545d098127e60"; + hash = "sha256-wy4nA7hxrX8JiDXkNzVHf6LUOVb8WankB600r7I8uSg="; + }; + }); + } + ); + }) + inputs.nur.overlays.default + (_: prev: { + niri = inputs.niri-branch.packages.${prev.system}.niri; + }) + ]; + } + # ./networking/wireguard + ]; + }; + }; +} diff --git a/home/bin/tmux-sessionizer b/home/bin/tmux-sessionizer new file mode 100755 index 0000000..131e045 --- /dev/null +++ b/home/bin/tmux-sessionizer @@ -0,0 +1,32 @@ +#!/usr/bin/env bash + +if [[ $# -eq 1 ]]; then + selected=$1 +else + selected=$( + ( + find ~/work -mindepth 1 -maxdepth 1 -type d + find ~/dev -mindepth 2 -maxdepth 2 -type d + find ~/dev/icefox/php -mindepth 1 -maxdepth 1 -type d + ) | fzf + ) + +fi + +if [[ -z $selected ]]; then + exit 0 +fi + +selected_name=$(basename "$selected" | tr . _) +tmux_running=$(pgrep tmux) + +if [[ -z $TMUX ]] && [[ -z $tmux_running ]]; then + tmux new-session -s "$selected_name" -c "$selected" + exit 0 +fi + +if ! tmux has-session -t="$selected_name" 2> /dev/null; then + tmux new-session -ds "$selected_name" -c "$selected" +fi + +tmux switch-client -t "$selected_name" diff --git a/home/default.nix b/home/default.nix new file mode 100644 index 0000000..52c14b8 --- /dev/null +++ b/home/default.nix @@ -0,0 +1,3 @@ +{ ... }: +{ +} diff --git a/home/files/lf/lfrc b/home/files/lf/lfrc new file mode 100644 index 0000000..e69de29 diff --git a/home/nvim/default.nix b/home/nvim/default.nix new file mode 100644 index 0000000..d99962e --- /dev/null +++ b/home/nvim/default.nix @@ -0,0 +1,416 @@ +{ + config, + pkgs, + lib, + ... +}: +with lib; +let + cfg = config.custom.neovim; +in +{ + options.custom.neovim = { + enable = mkEnableOption "Custom Neovim"; + + colorscheme = mkOption { + type = types.str; + default = "unokai"; + }; + + hostname = mkOption { + type = types.str; + }; + }; + + config = mkIf cfg.enable { + programs.neovim = { + enable = true; + defaultEditor = true; + viAlias = true; + vimAlias = false; + vimdiffAlias = true; + plugins = with pkgs.vimPlugins; [ + { + plugin = auto-session; + type = "lua"; + config = '' + require("auto-session").setup({ + cwd_change_handling = true, + suppressed_dirs = { "$HOME", "/etc/nixos", "$HOME/tmp" }, + }) + ''; + } + { + plugin = blink-cmp; + type = "lua"; + config = '' + require("blink.cmp").setup({ + completion = { + documentation = { + auto_show = true + }, + }, + keymap = { + preset = "default", + [""] = { "snippet_forward", "fallback" }, + [""] = { "select_and_accept", "snippet_forward", "fallback" }, + [""] = { "snippet_backward", "fallback" }, + }, + }) + ''; + } + { + plugin = comment-nvim; + type = "lua"; + config = '' + require('Comment').setup() + ''; + } + { + plugin = conform-nvim; + type = "lua"; + config = '' + require("conform").setup({ + formatters_by_ft = { + c = { "clang-format" }, + cpp = { "clang-format" }, + lua = { "stylua" }, + javascript = { "prettierd" }, + nix = { "nixfmt" }, + python = { "black" }, + php = { "php_cs_fixer" }, + zig = { "zigfmt" }, + css = { "prettierd" }, + scss = { "prettierd" }, + less = { "prettierd" }, + blade = { "blade-formatter" }, + go = { "gofmt" }, + wgsl = { "wgsl_fmt" }, + }, + }) + vim.api.nvim_create_autocmd("BufWritePre", { + pattern = "*", + callback = function(args) + require("conform").format({ bufnr = args.buf }) + end, + }) + vim.keymap.set("n", "rf", function() + require("conform").format({ + lsp_fallback = true, + async = true, + timeout_ms = 500, + }) + end, { desc = "conform format" }) + ''; + } + leap-nvim + { + plugin = lsp_lines-nvim; + type = "lua"; + config = '' + require("lsp_lines").setup() + vim.keymap.set("n", "i", require("lsp_lines").toggle, { desc = "Toggle LSP lines" }) + ''; + } + { + plugin = mini-icons; + type = "lua"; + config = ''require("mini.icons").setup()''; + } + { + plugin = neotest; + type = "lua"; + config = '' + require('neotest').setup({ + output = { + open_on_run = true + }, + adapters = { + require('neotest-pest'), + } + }) + vim.keymap.set('n', 'pn', function() require('neotest').run.run() end, { desc = "test nearest" }) + vim.keymap.set('n', 'pe', function() require('neotest').run.run(vim.fn.expand('%')) end, { desc = "test file" }) + ''; + } + { + plugin = neotest-pest; + type = "lua"; + } + # { + # plugin = nvim-autopairs; + # type = "lua"; + # config = '' + # require('nvim-autopairs').setup() + # ''; + # } + { + plugin = nvim-dap; + type = "lua"; + config = '' + local dap = require("dap") + dap.adapters.php = { + type = 'executable', + command = '${pkgs.nodejs}/bin/node', + args = { '${pkgs.vscode-extensions.xdebug.php-debug}/share/vscode/extensions/xdebug.php-debug/out/phpDebug.js' }, + } + + dap.configurations.php = { + { + type = 'php', + request = 'launch', + name = 'listen for xdebug', + port = 9003, + } + } + ''; + } + { + plugin = nvim-dap-ui; + type = "lua"; + config = '' + local dapui = require("dapui") + dapui.setup() + dap.listeners.before.attach.dapui_config = function() + dapui.open() + end + dap.listeners.before.launch.dapui_config = function() + dapui.open() + end + dap.listeners.before.event_terminated.dapui_config = function() + dapui.close() + end + dap.listeners.before.event_exited.dapui_config = function() + dapui.close() + end + ''; + } + nvim-nio + { + plugin = nvim-treesitter.withAllGrammars; + type = "lua"; + config = '' + local treesitter = require("nvim-treesitter") + treesitter.setup() + vim.api.nvim_create_autocmd('FileType', { + pattern = { + 'c', 'lua', 'vim', 'vimdoc', 'query', 'elixir', 'heex', 'javascript', 'typescript', + 'html', 'yaml', 'blade', 'php', 'scss', 'comment', 'cmake' , 'dockerfile', 'fish', + 'fsharp', 'git_config', 'git_rebase', 'gitignore', 'glsl', 'go', 'gomod', 'graphql', + 'haskell', 'hlsl', 'http', 'ini', 'javadoc', 'jq', 'jsdoc', 'json', 'json5', 'kitty', + 'latex', 'markdown', 'nginx', 'nix', 'php', 'php_only', 'phpdoc', 'regex', 'rust', 'sql', + 'ssh_config', 'tmux', 'vim', 'wgsl', 'yaml', 'zig', 'ols', + }, + callback = function() + vim.treesitter.start() + end, + }) + ''; + } + { + plugin = nvim-treesitter-context; + type = "lua"; + config = ''require("treesitter-context").setup()''; + } + # { + # plugin = nvim-treesitter-textobjectse + # type = "lua"; + # config = '' + # vim.g.no_plugin_maps = true + # require("treesitter-textobjects").setup() + # ''; + # } + nvim-lspconfig + nvim-nio + { + plugin = nvim-surround; + type = "lua"; + config = ''require("nvim-surround").setup()''; + } + { + plugin = nvim-web-devicons; + type = "lua"; + config = ''require("nvim-web-devicons").setup()''; + } + { + plugin = oil-nvim; + type = "lua"; + config = '' + require("oil").setup() + vim.keymap.set("n", "o", "Oil", { desc = "Oil" }) + ''; + } + { + plugin = opencode-nvim; + type = "lua"; + config = '' + vim.o.autoread = true + -- Recommended/example keymaps. + vim.keymap.set({ "n", "x" }, "", function() require("opencode").ask("@this: ", { submit = true }) end, { desc = "Ask opencode…" }) + vim.keymap.set({ "n", "x" }, "", function() require("opencode").select() end, { desc = "Execute opencode action…" }) + vim.keymap.set({ "n", "t" }, "", function() require("opencode").toggle() end, { desc = "Toggle opencode" }) + + vim.keymap.set({ "n", "x" }, "go", function() return require("opencode").operator("@this ") end, { desc = "Add range to opencode", expr = true }) + vim.keymap.set("n", "goo", function() return require("opencode").operator("@this ") .. "_" end, { desc = "Add line to opencode", expr = true }) + + vim.keymap.set("n", "", function() require("opencode").command("session.half.page.up") end, { desc = "Scroll opencode up" }) + vim.keymap.set("n", "", function() require("opencode").command("session.half.page.down") end, { desc = "Scroll opencode down" }) + + -- You may want these if you stick with the opinionated "" and "" above — otherwise consider "o…". + vim.keymap.set("n", "+", "", { desc = "Increment under cursor", noremap = true }) + vim.keymap.set("n", "-", "", { desc = "Decrement under cursor", noremap = true }) + ''; + } + phpactor + plenary-nvim + { + plugin = render-markdown-nvim; + type = "lua"; + config = ''require("render-markdown").setup()''; + } + { + plugin = snacks-nvim; + type = "lua"; + config = '' + local snacks = require("snacks") + snacks.setup({ + bigfile = {}, + dim = {}, + image = {}, + indent = {}, + lazygit = {}, + picker = { + win = { + input = { + keys = { + [""] = { "close", mode = { "n", "i" } }, + }, + }, + }, + }, + quickfile = {}, + notifier = {}, + }) + vim.keymap.set({ "n" }, "t", snacks.picker.grep, { desc = "grep picker" }) + vim.keymap.set({ "n" }, "r", snacks.picker.buffers, { desc = "buffer picker" }) + vim.keymap.set({ "n" }, "s", snacks.picker.files, { desc = "file picker" }) + vim.keymap.set({ "n" }, "ln", snacks.picker.lsp_references, { desc = "lsp references" }) + vim.keymap.set("n", "le", snacks.picker.lsp_implementations, { desc = "lsp implementations" }) + -- vim.keymap.set("n", "lg", function() snacks.lazygit() end , { desc = "lazygit" }) + ''; + } + rose-pine + { + plugin = rustaceanvim; + type = "lua"; + config = '' + vim.keymap.set("n", "da", function() vim.cmd.RustLsp('codeAction') end, { silent = true, buffer = bufnr }) + vim.keymap.set("n", "K", function() vim.cmd.RustLsp({'hover', 'actions'}) end, { silent = true, buffer = bufnr }) + ''; + } + { + plugin = tabby-nvim; + type = "lua"; + config = '' + require("tabby").setup({ + preset = "active_wins_at_tail", + options = { + theme = { + fill = "TabLineFill", + head = "TabLine", + current_tab = "TabLineSel", + tab = "TabLine", + win = "TabLine", + tail = "TabLine", + }, + nerdfont = true, + lualine_theme = nil, + tab_name = { + name_fallback = function(tabid) + return tabid + end, + }, + buf_name = { mode = "unique", }, + }, + }) + vim.keymap.set("n", "to", "Tabby jump_to_tab", { desc = "Jump to tab" }) + vim.keymap.set("n", "tf", "Tabby pick_window", { desc = "Search tab" }) + ''; + } + { + plugin = ts-autotag-nvim; + type = "lua"; + config = '' + require("ts-autotag").setup() + ''; + } + # { + # plugin = toggleterm-nvim; + # type = "lua"; + # config = '' + # require("toggleterm").setup() + # vim.keymap.set("n", "nt", "ToggleTerm size=120 direction=tab name=ttermh", { desc = "Toggle tterm tab" }) + # vim.keymap.set("n", "ns", "ToggleTerm direction=vertical name=ttermv", { desc = "Toggle tterm vertical" }) + # vim.keymap.set("n", "", "ToggleTerm direction=float name=ttermf", { desc = "Toggle tterm float" }) + # ''; + # } + { + plugin = trouble-nvim; + type = "lua"; + config = '' + require("trouble").setup({}) + vim.keymap.set("n", "id", "Trouble diagnostics toggle", { desc = "Trouble project" }) + -- vim.keymap.set("n", "io", "Trouble diagnostics toggle filter.buf=0", { desc = "Trouble buffer" }) + ''; + } + { + plugin = undotree; + type = "lua"; + config = ''vim.keymap.set("n", "u", vim.cmd.UndotreeToggle, { desc = "undotree" })''; + } + vim-repeat + { + plugin = vimtex; + type = "lua"; + config = '' + vim.g.vimtex_view_method = "zathura" + vim.g.vimtex_compiler_method = "latexmk" + ''; + } + { + plugin = which-key-nvim; + type = "lua"; + config = '' + local wk = require("which-key") + wk.setup({ + preset = "helix", + win = { row = 0, col = 0.5 }, + triggers = { + { "", mode = { "n", "v" } }, + { "", mode = { "n", "v" } }, + } + }) + wk.add({ + { "s", group = "Search..." }, + { "l", group = "Launch..." }, + { "t", group = "Tab..." }, + { "g", group = "Go..." }, + { "r", group = "Run..." }, + { "n", group = "term..." }, + }) + -- vim.keymap.set({"t"}, "", wk.show, { desc = "Show which key in terminal mode" }) + ''; + } + vim-fugitive + ]; + extraConfig = '' + colorscheme ${cfg.colorscheme} + ''; + extraLuaConfig = '' + ${builtins.readFile ./settings.lua} + ${builtins.replaceStrings [ "@HOSTNAME@" ] [ cfg.hostname ] (builtins.readFile ./plugins.lua)} + require("custom") + ''; + }; + }; +} diff --git a/home/nvim/plugins.lua b/home/nvim/plugins.lua new file mode 100644 index 0000000..e94ea77 --- /dev/null +++ b/home/nvim/plugins.lua @@ -0,0 +1,161 @@ +local hostname = "@HOSTNAME@" + +local servers = { + clangd = {}, + textlab = {}, + lua_ls = { + settings = { + Lua = { + runtime = { + version = "LuaJIT", + }, + diagnostics = { + globals = { "vim" }, + }, + workspace = { + library = vim.api.nvim_get_runtime_file("", true), + checkThirdParty = false, + }, + telemetry = { + enable = false, + }, + }, + }, + }, + nixd = { + nixpkgs = { + expr = 'import (builtins.getFlake "/etc/nixos").inputs.nixpkgs {}', + }, + formatting = { command = { "nixfmt" } }, + options = { + nixos = { + expr = '(builtins.getFlake "/etc/nixos").nixosConfigurations.' .. hostname .. ".options", + }, + home_manager = { + expr = '(builtins.getFlake "/etc/nixos").homeConfigurations.' .. hostname .. ".options", + }, + }, + }, + phpactor = {}, + zls = { + settings = { + zls = { + enable_build_on_save = true, + semantic_tokens = "partial", + }, + }, + }, + css = {}, + scss = {}, + less = {}, + blade = {}, + html = { filetypes = { "html", "blade" } }, + htmx = { filetypes = { "html", "blade" } }, + gopls = {}, + ols = {}, + wgsl_analyzer = {}, +} +for server, config in pairs(servers) do + vim.lsp.config(server, config) + vim.lsp.enable(server) +end + +-- vim.api.nvim_create_autocmd("LspAttach", { +-- group = vim.api.nvim_create_augroup("UserConfigLsp", {}), +-- callback = function(ev) +vim.keymap.set("n", "gn", vim.lsp.buf.declaration, { desc = "go to declaration" }) +vim.keymap.set("n", "ge", vim.lsp.buf.definition, { desc = "go to definition" }) +-- vim.keymap.set("n", "gi", vim.lsp.buf.implementaion, { desc = "go to implementation" }) +vim.keymap.set("n", "rr", vim.lsp.buf.rename, { desc = "lsp rename" }) +vim.keymap.set("n", "ra", vim.lsp.buf.code_action, { desc = "code action" }) +vim.keymap.set({ "n", "i" }, "", vim.lsp.buf.signature_help, { desc = "signature help" }) +vim.keymap.set("n", "gr", vim.lsp.buf.references, { desc = "references" }) +-- end, +-- }) + +local leap = require("leap") +leap.opts.preview = function(ch0, ch1, ch2) + return not (ch1:match("%s") or (ch0:match("%a") and ch1:match("%a") and ch2:match("%a"))) +end +leap.opts.equivalence_classes = { + " \t\r\n", + "([{", + ")]}", + "'\"`", +} +vim.api.nvim_set_hl(0, "LeapBackdrop", { link = "Comment" }) + +do + -- Return an argument table for `leap()`, tailored for f/t-motions. + local function as_ft(key_specific_args) + local common_args = { + inputlen = 1, + inclusive = true, + -- To limit search scope to the current line: + -- pattern = function (pat) return '\\%.l'..pat end, + opts = { + labels = "", -- force autojump + safe_labels = vim.fn.mode(1):match("[no]") and "" or nil, -- [1] + }, + } + return vim.tbl_deep_extend("keep", common_args, key_specific_args) + end + + local clever = require("leap.user").with_traversal_keys -- [2] + local clever_f = clever("f", "F") + local clever_t = clever("t", "T") + + for key, key_specific_args in pairs({ + f = { opts = clever_f }, + F = { backward = true, opts = clever_f }, + t = { offset = -1, opts = clever_t }, + T = { backward = true, offset = 1, opts = clever_t }, + }) do + vim.keymap.set({ "n", "x", "o" }, key, function() + require("leap").leap(as_ft(key_specific_args)) + end) + end +end + +vim.api.nvim_create_autocmd("CmdlineLeave", { + group = vim.api.nvim_create_augroup("LeapOnSearch", {}), + callback = function() + local ev = vim.v.event + local is_search_cmd = (ev.cmdtype == "/") or (ev.cmdtype == "?") + local cnt = vim.fn.searchcount().total + if is_search_cmd and not ev.abort and (cnt > 1) then + -- Allow CmdLineLeave-related chores to be completed before + -- invoking Leap. + vim.schedule(function() + -- We want "safe" labels, but no auto-jump (as the search + -- command already does that), so just use `safe_labels` + -- as `labels`, with n/N removed. + local labels = require("leap").opts.safe_labels:gsub("[nN]", "") + -- For `pattern` search, we never need to adjust conceallevel + -- (no user input). We cannot merge `nil` from a table, but + -- using the option's current value has the same effect. + local vim_opts = { ["wo.conceallevel"] = vim.wo.conceallevel } + require("leap").leap({ + pattern = vim.fn.getreg("/"), -- last search pattern + windows = { vim.fn.win_getid() }, + opts = { safe_labels = "", labels = labels, vim_opts = vim_opts }, + }) + end) + end + end, +}) + +vim.keymap.set({ "n", "x", "o" }, "s", "(leap)", { desc = "leap" }) +vim.keymap.set({ "n", "x", "o" }, "S", "(leap-from-window)", { desc = "leap across window" }) + +require("neotest").setup({ + adapters = { + require("neotest-pest"), + }, +}) +vim.keymap.set("n", "pn", function() + require("neotest").run.run() +end, { desc = "test nearest" }) +vim.keymap.set("n", "pe", function() + require("neotest").run.run(vim.fn.expand("%")) +end, { desc = "test file" }) diff --git a/home/nvim/settings.lua b/home/nvim/settings.lua new file mode 100644 index 0000000..83d9a76 --- /dev/null +++ b/home/nvim/settings.lua @@ -0,0 +1,147 @@ +vim.opt.number = true +vim.opt.relativenumber = true +vim.opt.cursorline = true +vim.opt.wrap = false +vim.opt.scrolloff = 10 +vim.opt.sidescrolloff = 8 + +vim.opt.tabstop = 4 +vim.opt.shiftwidth = 4 +vim.opt.softtabstop = 4 +vim.opt.expandtab = true +vim.opt.smartindent = true +vim.opt.autoindent = true + +vim.opt.ignorecase = true +vim.opt.smartcase = true +vim.opt.hlsearch = false +vim.opt.incsearch = true + +vim.opt.termguicolors = true +vim.opt.signcolumn = "yes" +vim.opt.colorcolumn = "120" +vim.opt.showmatch = false +--- vim.opt.matchtime = 2 +vim.opt.conceallevel = 0 +vim.opt.concealcursor = "" +vim.opt.synmaxcol = 1000 +vim.opt.isfname:append("@-@") + +vim.opt.backup = false +vim.opt.writebackup = false +vim.opt.swapfile = false +vim.opt.undofile = true +vim.opt.undodir = vim.fn.expand("~/.cache/vim/undodir") +vim.opt.updatetime = 100 +vim.opt.timeoutlen = 500 +vim.opt.ttimeoutlen = 0 +vim.opt.autoread = true +vim.opt.autowrite = false + +vim.opt.hidden = true +--- vim.opt.errorbells = false +vim.opt.backspace = "indent,eol,start" +vim.opt.autochdir = false +vim.opt.path:append("**") +vim.opt.selection = "exclusive" +vim.opt.mouse = "a" +vim.opt.modifiable = true +vim.opt.encoding = "UTF-8" + +-- Split behavior +vim.opt.splitbelow = true +vim.opt.splitright = true + +vim.g.mapleader = " " +vim.g.maplocalleader = vim.api.nvim_replace_termcodes("", false, false, true) + +vim.o.exrc = true +vim.o.showtabline = 2 + +vim.cmd("set title") +vim.cmd("set ic") + +-- Delete without yanking +vim.keymap.set({ "n", "v" }, "d", '"_d', { desc = "Delete without yanking" }) +vim.keymap.set({ "n", "v" }, "", '"+y', { desc = "Copy to clipboard" }) +vim.keymap.set("x", "p", '"_dP', { desc = "Replace without yanking" }) + +-- Wayland clipboard mappings +vim.keymap.set({ "n", "v" }, "y", '"+y', { desc = "Yank to system clipboard" }) +vim.keymap.set("n", "Y", '"+Y', { desc = "Yank line to system clipboard" }) +vim.keymap.set({ "n", "v" }, "p", '"+p', { desc = "Paste from system clipboard" }) +vim.keymap.set({ "n", "v" }, "P", '"+P', { desc = "Paste from system clipboard before cursor" }) + +-- Better J behavior +vim.keymap.set("n", "J", "mzJ`z", { desc = "Join lines and keep cursor position" }) + +--- center when jumping +vim.keymap.set("n", "n", "nzzzv", { desc = "Next search result (centered)" }) +vim.keymap.set("n", "N", "Nzzzv", { desc = "Previous search result (centered)" }) +vim.keymap.set("n", "", "zz", { desc = "Half page down (centered)" }) +vim.keymap.set("n", "", "zz", { desc = "Half page up (centered)" }) + +--- window navigation +vim.keymap.set("n", "Left", "h", { desc = "Move to left window" }) +vim.keymap.set("n", "Right", "l", { desc = "Move to right window" }) +vim.keymap.set("n", "Top", "k", { desc = "Move to top window" }) +vim.keymap.set("n", "Down", "j", { desc = "Move to bottom window" }) + +vim.keymap.set("t", "", "", { desc = "Exit terminal mode" }) + +vim.keymap.set("n", "tn", "$tabnew", { desc = "create tab" }) +vim.keymap.set("n", "n", function() + vim.cmd("tabnext 1") +end, { desc = "Go to tab 1" }) +vim.keymap.set("n", "e", function() + vim.cmd("tabnext 2") +end, { desc = "Go to tab 2" }) +vim.keymap.set("n", "i", function() + vim.cmd("tabnext 3") +end, { desc = "Go to tab 3" }) +vim.keymap.set("n", "a", function() + vim.cmd("tabnext 4") +end, { desc = "Go to tab 4" }) +vim.keymap.set({ "n", "t" }, "", function() + vim.cmd("tabnext #") +end, { desc = "Go to previous tab" }) +vim.keymap.set({ "n", "t" }, "", "p", { desc = "Go to previous pane" }) + +vim.keymap.set("n", "v", "vsplit", { desc = "split (vertical line)" }) +vim.keymap.set("n", "h", "split", { desc = "split (horizontal line)" }) + +vim.keymap.set("n", "", "w", { desc = "save buffer" }) + +vim.diagnostic.config({ + virtual_text = false, + virtual_lines = true, + signs = true, + underline = true, + update_in_insert = false, + severity_sort = true, +}) + +-- Highlight yanked text +vim.api.nvim_create_autocmd("TextYankPost", { + group = augroup, + callback = function() + vim.highlight.on_yank() + end, +}) + +--- return to last edit position when opening files +vim.api.nvim_create_autocmd("BufReadPost", { + group = augroup, + callback = function() + local mark = vim.api.nvim_buf_get_mark(0, '"') + local lcount = vim.api.nvim_buf_line_count(0) + if mark[1] > 0 and mark[1] <= lcount then + pcall(vim.api.nvim_win_set_cursor, 0, mark) + end + end, +}) + +--- command line completion +vim.opt.wildmenu = true +vim.opt.wildmode = "longest:full,full" +vim.opt.wildignore:append({ "*.o", "*.obj", "*.pyc", "*.class", "*.jar", "*.lock" }) diff --git a/home/root.nix b/home/root.nix new file mode 100644 index 0000000..eaa3dee --- /dev/null +++ b/home/root.nix @@ -0,0 +1,91 @@ +{ hostname, ... }: +{ + home-manager.users.root = + { config, ... }: + { + imports = [ ./nvim ]; + home.username = "root"; + home.homeDirectory = "/root"; + home.stateVersion = "25.11"; + home.enableNixpkgsReleaseCheck = false; + + home.file."/.ssh/desktop.pub".text = + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILquARrJ3Vyh5z6aeVoiYrkLpgiMts+V/JzFEvs3Cnth root@icefox.sh"; + + xdg.userDirs = { + enable = false; + extraConfig = { + XDG_CACHE_HOME = "${config.home.homeDirectory}/.cache"; + }; + }; + + programs = { + ssh = { + enable = true; + enableDefaultConfig = false; + matchBlocks = { + "icefox.sh" = { + user = "git"; + identityFile = "/root/.ssh/desktop"; + }; + }; + }; + delta = { + enable = true; + options = { + navigate = true; + line-numbers = true; + side-by-side = true; + }; + enableGitIntegration = true; + }; + git = { + enable = true; + lfs.enable = true; + settings = { + user = { + email = "root@icefox.sh"; + name = "root"; + }; + gpg.format = "ssh"; + user.signingkey = "${config.home.homeDirectory}/.ssh/desktop.pub"; + commit.gpgsign = true; + tag.gpgsign = true; + core = { + editor = "nvim"; + whitespace = "fix,only-indent-error,trailing-space,space-before-tab"; + quotepath = false; + }; + diff = { + algorithm = "histogram"; + renames = "copies"; + }; + merge = { + conflictstyle = "zdiff3"; + }; + init = { + defaultBranch = "master"; + }; + push = { + autoSetupRemote = true; + default = "current"; + }; + pull = { + rebase = true; + }; + fetch = { + prune = true; + }; + help = { + autocorrect = "prompt"; + }; + }; + }; + }; + custom.neovim = { + enable = true; + hostname = hostname; + colorscheme = "unokai"; + }; + }; +} diff --git a/home/tmux.nix b/home/tmux.nix new file mode 100644 index 0000000..4b9ac22 --- /dev/null +++ b/home/tmux.nix @@ -0,0 +1,200 @@ +{ + config, + pkgs, + lib, + ... +}: +with lib; +let + cfg = config.custom.tmux; + whichKeyConfig = pkgs.writeText "tmux-which-key-config.yaml" ( + lib.generators.toYAML { } { + command_alias_start_index = 200; + keybindings = { + prefix_table = "Space"; + }; + title = { + style = "align=centre,bold"; + prefix = "tmux"; + prefix_style = "fg=green,align=centre,bold"; + }; + custom_variables = { }; + macros = [ ]; + position = { + x = "R"; + y = "P"; + }; + items = [ + { + name = "Window 1"; + key = "n"; + command = "select-window -t 1"; + } + { + name = "Window 2"; + key = "e"; + command = "select-window -t 2"; + } + { + name = "Window 3"; + key = "i"; + command = "select-window -t 3"; + } + { + name = "Window 4"; + key = "a"; + command = "select-window -t 4"; + } + { + name = "Next window"; + key = "Enter"; + command = "next-window"; + transient = true; + } + { + name = "Last window"; + key = "Space"; + command = "last-window"; + } + { + separator = true; + } + { + name = "Copy mode"; + key = "BSpace"; + command = "copy-mode"; + } + { + separator = true; + } + { + name = "New window"; + key = "l"; + command = "new-window"; + } + { + name = "New pane (vertical line)"; + key = ","; + command = "splitw -h -c #{pane_current_path}"; + } + { + name = "Split (horizontal line)"; + key = "h"; + command = "splitw -v -c #{pane_current_path}"; + } + { + separator = true; + } + { + name = "Sessions"; + key = "m"; + menu = [ + { + name = "sessionizer"; + key = "Space"; + command = "run-shell \"tmux neww tmux-sessionizer\""; + } + { + name = "last-session"; + key = "Enter"; + command = "run-shell \"tmux switchc -l\""; + } + ]; + } + { + separator = true; + } + { + name = "Kill"; + key = "k"; + menu = [ + { + name = "Kill window"; + key = "w"; + command = "kill-window"; + } + { + name = "Kill pane"; + key = "p"; + command = "kill-pane"; + } + ]; + } + ]; + } + ); +in +{ + options.custom.tmux = { + enable = mkEnableOption "Custom Tmux"; + }; + config = mkIf cfg.enable { + programs.tmux = { + enable = true; + baseIndex = 1; + keyMode = "vi"; + mouse = true; + + plugins = with pkgs.tmuxPlugins; [ + sensible + yank + pain-control + # tmux-powerline + { + plugin = rose-pine; + extraConfig = '' + set -g @rose_pine_variant 'main' # Options are 'main', 'moon' or 'dawn' + set -g @rose_pine_host 'on' + set -g @rose_pine_directory 'on' + set -g @rose_pine_bar_bg_disable 'on' + ''; + } + { + plugin = pkgs.tmuxPlugins.tmux-which-key.overrideAttrs (old: { + postInstall = (old.postInstall or "") + '' + echo "[tmux-which-key] Pre-generating configuration at build time..." + + ${lib.getExe (pkgs.python3.withPackages (ps: with ps; [ pyyaml ]))} \ + $target/plugin/build.py \ + ${whichKeyConfig} \ + $target/init.tmux + + # Append a line to source the pre-generated config + echo 'tmux source-file "$root_dir/init.tmux"' >> $target/plugin.sh.tmux + ''; + }); + extraConfig = '' + set -g @tmux-which-key-xdg-enable 1; + set -g @tmux-which-key-disable-autobuild 1; + ''; + } + { + plugin = resurrect; + extraConfig = "set -g @ressurect-strategy-nvim 'session'"; + } + { + plugin = continuum; + extraConfig = '' + set -g @continuum-restore 'on' + set -g @continuum-save-interval '60' + ''; + } + ]; + extraConfig = '' + set -g status-position top + set -g focus-events on + set -g allow-passthrough on + set -s extended-keys on + set -g default-terminal "xterm-ghostty" + set -as terminal-features ",xterm-ghostty:extkeys" + + bind -n M-, run-shell "tmux neww tmux-sessionizer" + bind -n M-/ run-shell "tmux switch-client -t default" + bind -n M-. run-shell "tmux switchc -l" + + bind-key -n Home send Escape "OH" + bind-key -n End send Escape "OF" + ''; + }; + }; +} diff --git a/home/user.nix b/home/user.nix new file mode 100644 index 0000000..74eb5bf --- /dev/null +++ b/home/user.nix @@ -0,0 +1,855 @@ +{ hostname, ... }: +{ + home-manager.users.user = + { + config, + pkgs, + lib, + ... + }: + { + home.username = "user"; + home.homeDirectory = "/home/user"; + home.stateVersion = "25.11"; + home.sessionVariables = { + HOME = "/home/user"; + }; + + imports = [ + ./nvim + ./tmux.nix + ]; + + sops.defaultSopsFile = ../secrets/home.yaml; + sops.age.keyFile = "/.persist/${config.home.homeDirectory}/.config/sops/age/keys.txt"; + sops.secrets."user/ssh/desktop" = { + path = "${config.home.homeDirectory}/.ssh/desktop"; + mode = "0600"; + }; + home.file."/.ssh/desktop.pub".text = + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILABd/iSJ4gn/ystDqNxLJTG0n0z5VIC9YXlmdUfOhHf desktop@icefox.sh"; + sops.secrets."user/ssh/legacy_ed25519" = { + path = "${config.home.homeDirectory}/.ssh/legacy_ed25519"; + mode = "0600"; + }; + home.file."/.ssh/legacy_ed25519.pub".text = + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILkchxtY21PzSLHJ5SoYPrl03+NRzRqznbdCqNyGuOX/ master@michizure.net"; + + dconf.settings = { + "org/gnome/desktop/interface" = { + text-scaling-factor = 1.0; + }; + }; + # xresources.properties = { + # "Xcursor.size" = 14; + # # "Xft.dpi" = 144; + # "Xft.autohint" = 0; + # "Xft.lcdfilter" = "lcddefault"; + # "Xft.hintstyle" = "hintfull"; + # "Xft.hinting" = 1; + # "Xft.antialias" = 1; + # "Xft.rgba" = "rgb"; + # }; + + # systemd.user.services.xrdb-configure = { + # Unit = { + # Description = "Load Xresources"; + # }; + # Intall = { + # WantedBy = [ "graphical-session.target" ]; + # }; + # Service = { + # ExecStart = "${pkgs.xrdb}/bin/xrdb -merge ${config.home.homeDirectory}/.Xresources"; + # Type = "oneshot"; + # }; + # }; + sops.secrets."user/gpg/legacy_fnzr" = { }; + home.activation.importGpgKey = config.lib.dag.entryAfter [ "writeBoundary" ] '' + if [[ -f "${config.sops.secrets."user/gpg/legacy_fnzr".path}" ]]; then + ${pkgs.gnupg}/bin/gpg --batch --import "${ + config.sops.secrets."user/gpg/legacy_fnzr".path + }" || true + echo "YOUR_KEY_FINGERPRINT:6:" | ${pkgs.gnupg}/bin/gpg --import-ownertrust || true + fi + ''; + + xdg.configFile."mimeapps.list".force = true; + + xdg.configFile."containers/containers.conf".text = '' + [engine] + compose_warning_logs=false + events_logger="file" + + [containers] + log_driver="k8s-file" + ''; + + xdg.configFile."lazygit/config.yml".text = lib.generators.toYAML { } { + gui = { + theme = { + selectedLineBgColor = [ "reverse" ]; + }; + }; + }; + + # xdg.configFile."opencode/opencode.json".text = builtins.toJSON { + # "$schema" = "https://opencode.ai/config.json"; + # plugin = [ "opencode-antigravity-auth@latest" ]; + # provider = { + # google = { + # models = { + # antigravity-gemini-3-pro = { + # name = "Gemini 3 Pro (Antigravity)"; + # limit = { + # context = 1048576; + # output = 65535; + # }; + # modalities = { + # input = [ + # "text" + # "image" + # "pdf" + # ]; + # output = [ "text" ]; + # }; + # variants = { + # low = { + # thinkingLevel = "low"; + # }; + # high = { + # thinkingLevel = "high"; + # }; + # }; + # }; + # antigravity-gemini-3-flash = { + # name = "Gemini 3 Flash (Antigravity)"; + # limit = { + # context = 1048576; + # output = 65536; + # }; + # modalities = { + # input = [ + # "text" + # "image" + # "pdf" + # ]; + # output = [ "text" ]; + # }; + # variants = { + # minimal = { + # thinkingLevel = "minimal"; + # }; + # low = { + # thinkingLevel = "low"; + # }; + # medium = { + # thinkingLevel = "medium"; + # }; + # high = { + # thinkingLevel = "high"; + # }; + # }; + # }; + # antigravity-claude-sonnet-4-5 = { + # name = "Claude Sonnet 4.5 (Antigravity)"; + # limit = { + # context = 200000; + # output = 64000; + # }; + # modalities = { + # input = [ + # "text" + # "image" + # "pdf" + # ]; + # output = [ "text" ]; + # }; + # }; + # antigravity-claude-sonnet-4-5-thinking = { + # name = "Claude Sonnet 4.5 Thinking (Antigravity)"; + # limit = { + # context = 200000; + # output = 64000; + # }; + # modalities = { + # input = [ + # "text" + # "image" + # "pdf" + # ]; + # output = [ "text" ]; + # }; + # variants = { + # low = { + # thinkingConfig = { + # thinkingBudget = 8192; + # }; + # }; + # max = { + # thinkingConfig = { + # thinkingBudget = 32768; + # }; + # }; + # }; + # }; + # antigravity-claude-opus-4-5-thinking = { + # name = "Claude Opus 4.5 Thinking (Antigravity)"; + # limit = { + # context = 200000; + # output = 64000; + # }; + # modalities = { + # input = [ + # "text" + # "image" + # "pdf" + # ]; + # output = [ "text" ]; + # }; + # variants = { + # low = { + # thinkingConfig = { + # thinkingBudget = 8192; + # }; + # }; + # max = { + # thinkingConfig = { + # thinkingBudget = 32768; + # }; + # }; + # }; + # }; + # antigravity-claude-opus-4-6-thinking = { + # name = "Claude Opus 4.6 Thinking (Antigravity)"; + # limit = { + # context = 200000; + # output = 64000; + # }; + # modalities = { + # input = [ + # "text" + # "image" + # "pdf" + # ]; + # output = [ "text" ]; + # }; + # variants = { + # low = { + # thinkingConfig = { + # thinkingBudget = 8192; + # }; + # }; + # max = { + # thinkingConfig = { + # thinkingBudget = 32768; + # }; + # }; + # }; + # }; + # "gemini-2.5-flash" = { + # name = "Gemini 2.5 Flash (Gemini CLI)"; + # limit = { + # context = 1048576; + # output = 65536; + # }; + # modalities = { + # input = [ + # "text" + # "image" + # "pdf" + # ]; + # output = [ "text" ]; + # }; + # }; + # "gemini-2.5-pro" = { + # name = "Gemini 2.5 Pro (Gemini CLI)"; + # limit = { + # context = 1048576; + # output = 65536; + # }; + # modalities = { + # input = [ + # "text" + # "image" + # "pdf" + # ]; + # output = [ "text" ]; + # }; + # }; + # gemini-3-flash-preview = { + # name = "Gemini 3 Flash Preview (Gemini CLI)"; + # limit = { + # context = 1048576; + # output = 65536; + # }; + # modalities = { + # input = [ + # "text" + # "image" + # "pdf" + # ]; + # output = [ "text" ]; + # }; + # }; + # gemini-3-pro-preview = { + # name = "Gemini 3 Pro Preview (Gemini CLI)"; + # limit = { + # context = 1048576; + # output = 65535; + # }; + # modalities = { + # input = [ + # "text" + # "image" + # "pdf" + # ]; + # output = [ "text" ]; + # }; + # }; + # }; + # }; + # }; + # }; + + xdg.desktopEntries = { + google-chrome = { + name = "Google Chrome"; + genericName = "Web Browser"; + exec = "/run/current-system/sw/bin/google-chrome-stable"; + terminal = false; + icon = "google-chrome"; + type = "Application"; + categories = [ + "Network" + "WebBrowser" + ]; + }; + chromium-browser = { + name = "Chromium"; + genericName = "Web Browser"; + exec = "/run/current-system/sw/bin/chromium"; + terminal = false; + icon = "chromium"; + type = "Application"; + categories = [ + "Network" + "WebBrowser" + ]; + }; + chromium-browser-sandbox = { + name = "Chromium (Sandbox)"; + genericName = "Web Browser"; + exec = "/run/current-system/sw/bin/chromium-sandbox --data-dir=/data/sandbox/chromium/data-dir"; + terminal = false; + icon = "chromium"; + type = "Application"; + categories = [ + "Network" + "WebBrowser" + ]; + }; + }; + + xdg.mimeApps = { + enable = true; + defaultApplications = { + # text + "text/plain" = "nvim.desktop"; + "text/markdown" = "nvim.desktop"; + "text/x-python" = "nvim.desktop"; + "text/x-shellscript" = "nvim.desktop"; + "text/x-csrc" = "nvim.desktop"; + "text/x-c++src" = "nvim.desktop"; + "text/x-java" = "nvim.desktop"; + "text/x-makefile" = "nvim.desktop"; + "application/json" = "nvim.desktop"; + "application/javascript" = "nvim.desktop"; + "application/x-yaml" = "nvim.desktop"; + "application/xml" = "nvim.desktop"; + "text/*" = "nvim.desktop"; + + # browser + "text/html" = "firefox.desktop"; + "x-scheme-handler/http" = "firefox.desktop"; + "x-scheme-handler/https" = "firefox.desktop"; + "x-scheme-handler/about" = "firefox.desktop"; + "x-scheme-handler/unknown" = "firefox.desktop"; + + # swayimg + "image/jpeg" = "swayimg.desktop"; + "image/jpg" = "swayimg.desktop"; + "image/png" = "swayimg.desktop"; + "image/gif" = "swayimg.desktop"; + "image/webp" = "swayimg.desktop"; + "image/bmp" = "swayimg.desktop"; + "image/tiff" = "swayimg.desktop"; + "image/svg+xml" = "swayimg.desktop"; + "image/x-icon" = "swayimg.desktop"; + "image/*" = "swayimg.desktop"; + + # pdf & readers + "application/pdf" = "org.pwmt.zathura.desktop"; + "application/postscript" = "org.pwmt.zathura.desktop"; + "image/vnd.djvu" = "org.pwmt.zathura.desktop"; + "application/x-cbr" = "org.pwmt.zathura.desktop"; + "application/x-cbz" = "org.pwmt.zathura.desktop"; + "application/x-cb7" = "org.pwmt.zathura.desktop"; + "application/x-cbt" = "org.pwmt.zathura.desktop"; + "application/epub+zip" = "org.pwmt.zathura.desktop"; + + # video + "video/mp4" = "mpv.desktop"; + "video/x-matroska" = "mpv.desktop"; + "video/webm" = "mpv.desktop"; + "video/mpeg" = "mpv.desktop"; + "video/x-msvideo" = "mpv.desktop"; + "video/quicktime" = "mpv.desktop"; + "video/x-flv" = "mpv.desktop"; + "video/3gpp" = "mpv.desktop"; + "video/ogg" = "mpv.desktop"; + "video/*" = "mpv.desktop"; + + # audio + "audio/mpeg" = "mpv.desktop"; + "audio/mp4" = "mpv.desktop"; + "audio/x-wav" = "mpv.desktop"; + "audio/flac" = "mpv.desktop"; + "audio/ogg" = "mpv.desktop"; + "audio/x-vorbis+ogg" = "mpv.desktop"; + "audio/x-opus+ogg" = "mpv.desktop"; + "audio/aac" = "mpv.desktop"; + "audio/x-m4a" = "mpv.desktop"; + "audio/webm" = "mpv.desktop"; + "audio/*" = "mpv.desktop"; + }; + }; + + xdg.userDirs = { + enable = true; + createDirectories = true; + + download = "${config.home.homeDirectory}/downloads"; + documents = "${config.home.homeDirectory}/documents"; + desktop = "${config.home.homeDirectory}/desktop"; + pictures = "${config.home.homeDirectory}/pictures"; + music = "${config.home.homeDirectory}/music"; + videos = "${config.home.homeDirectory}/videos"; + templates = "${config.home.homeDirectory}"; + publicShare = "${config.home.homeDirectory}"; + + extraConfig = { + SCREENSHOTS = "${config.home.homeDirectory}/pictures/screenshots"; + XDG_CACHE_HOME = "${config.home.homeDirectory}/.cache"; + }; + }; + + programs = { + dank-material-shell.enable = true; + ssh = { + enable = true; + enableDefaultConfig = false; + matchBlocks = { + "*" = { + serverAliveInterval = 60; + serverAliveCountMax = 3; + }; + "github.com" = { + identityFile = config.sops.secrets."user/ssh/legacy_ed25519".path; + }; + "icefox.sh" = { + user = "git"; + identityFile = config.sops.secrets."user/ssh/desktop".path; + }; + }; + }; + delta = { + enable = true; + options = { + navigate = true; + line-numbers = true; + side-by-side = true; + }; + enableGitIntegration = true; + }; + git = { + enable = true; + lfs.enable = true; + signing = { + key = "${config.home.homeDirectory}/.ssh/desktop.pub"; + signByDefault = true; + }; + includes = [ + { + condition = "gitdir:~/work/"; + contents = { + user = { + name = "felipematos"; + email = "5471818+fnzr@users.noreply.github.com"; + }; + }; + } + ]; + settings = { + user = { + email = "felipe@icefox.sh"; + name = "icefox"; + signingkey = "${config.home.homeDirectory}/.ssh/desktop.pub"; + }; + gpg.format = "ssh"; + commit.gpgsign = true; + tag.gpgsign = true; + core = { + editor = "nvim"; + whitespace = "fix,only-indent-error,trailing-space,space-before-tab"; + quotepath = false; + }; + diff = { + algorithm = "histogram"; + renames = "copies"; + tool = "nvim"; + }; + difftool = { + prompt = false; + nvim.cmd = "nvim -d $LOCAL $REMOTE"; + }; + merge = { + conflictstyle = "zdiff3"; + tool = "nvim"; + }; + mergetool = { + prompt = false; + keepBackup = false; + nvim.cmd = "nvim -d $LOCAL $REMOTE $MERGED -c 'wincmd w' -c 'wincmd J'"; + }; + init = { + defaultBranch = "master"; + }; + push = { + autoSetupRemote = true; + default = "current"; + }; + pull = { + rebase = true; + }; + fetch = { + prune = true; + }; + help = { + autocorrect = "prompt"; + }; + }; + }; + }; + + home.packages = with pkgs; [ + xrdb + (writeShellApplication { + name = "tmux-sessionizer"; + runtimeInputs = [ + tmux + fzf + ]; + text = builtins.readFile ./bin/tmux-sessionizer; + }) + (writeShellScriptBin "opencode" '' + ssh -t user@192.168.77.2 " + cd $(pwd) 2>/dev/null || cd \$(mktemp -d) + opencode $* + " + '') + (writeShellScriptBin "claude" '' + ssh -t user@192.168.77.2 " + cd $(pwd) 2>/dev/null || cd \$(mktemp -d) + claude $* + " + '') + ]; + + custom.tmux.enable = true; + custom.neovim = { + enable = true; + colorscheme = "rose-pine-moon"; + hostname = hostname; + }; + + programs.fish = { + enable = true; + plugins = [ + { + name = "puffer"; + src = pkgs.fetchFromGitHub { + owner = "nickeb96"; + repo = "puffer-fish"; + rev = "83174b0"; + sha256 = "sha256-Dhx5+XRxJvlhdnFyimNxFyFiASrGU4ZwyefsDwtKnSg="; + }; + } + ]; + + interactiveShellInit = '' + set fish_greeting + bind ctrl-space "" + ''; + }; + + programs.starship = { + enable = true; + }; + + programs.zoxide = { + enable = true; + enableFishIntegration = true; + }; + + programs.ghostty = { + enable = true; + settings = { + theme = "Rose Pine Moon"; + font-family = [ + "MonaspiceNe Nerd Font Mono" + "Fire Code Symbol" + ]; + font-size = "10"; + font-feature = "+calt, +liga, +dlig, +ss01, +ss02, +ss03, +ss04, +ss05, +ss06, +ss07, +ss08, +ss09, +ss10"; + keybind = [ + "shift+escape=unbind" + # "ctrl+c=copy_to_clipboard" + "ctrl+v=paste_from_clipboard" + ]; + }; + enableFishIntegration = true; + systemd.enable = true; + }; + + programs.firefox = { + enable = true; + package = pkgs.firefox; + nativeMessagingHosts = [ + pkgs.browserpass + pkgs.tridactyl-native + ]; + profiles.default = { + id = 0; + name = "default"; + isDefault = true; + containersForce = true; + userChrome = '' + #TabsToolbar { + visibility: collapse; + } + ''; + settings = { + "toolkit.legacyUserProfileCustomizations.stylesheets" = true; + }; + # settings = { + # "tabopencontaineraware" = true; + # }; + containers = { + personal = { + id = 1; + color = "blue"; + icon = "fingerprint"; + }; + google = { + id = 2; + color = "pink"; + icon = "fence"; + }; + london = { + id = 3; + color = "orange"; + icon = "tree"; + }; + research = { + id = 4; + color = "green"; + icon = "tree"; + }; + chill = { + id = 5; + color = "turquoise"; + icon = "chill"; + }; + work = { + id = 6; + color = "red"; + icon = "briefcase"; + }; + }; + + search = { + force = true; + default = "ddg"; + order = [ + "ddg" + "Kagi" + "MyNixOS" + "PHP" + ]; + engines = { + "PHP" = { + urls = [ + { + template = "https://www.php.net/search.php"; + params = [ + { + name = "pattern"; + value = "{searchTerms}"; + } + ]; + } + ]; + definedAliases = [ "php" ]; + }; + "MyNixOS" = { + urls = [ + { + template = "https://mynixos.com/search"; + params = [ + { + name = "q"; + value = "{searchTerms}"; + } + ]; + } + ]; + definedAliases = [ "nix" ]; + }; + "Kagi" = { + urls = [ { template = "https://kagi.com/search?q={searchTerms}"; } ]; + icon = "https://kagi.com/favicon.ico"; + updateInterval = 24 * 60 * 60 * 1000; + definedAliases = [ "kg" ]; + }; + "ddg" = { + metaData.alias = "dd"; + }; + "google".metaData.hidden = true; + "bing".metaData.hidden = true; + "amazondotcom-us".metaData.hidden = true; + "ebay".metaData.hidden = true; + }; + }; + + # settings = { + # "layout.css.prefers-color-scheme.content-override" = 2; + # "privacy.resistFingerprinting" = true; + # "privacy.resistFingerprinting.exemptions" = "prefers-color-scheme"; + # "browser.theme.dark-private-windows" = true; + # }; + extensions = { + packages = with pkgs.nur.repos.rycee.firefox-addons; [ + ublock-origin + tridactyl + gopass-bridge + multi-account-containers + foxyproxy-standard + ]; + }; + }; + }; + + programs.librewolf = { + enable = true; + package = pkgs.librewolf; + + nativeMessagingHosts = [ + pkgs.browserpass + pkgs.tridactyl-native + ]; + profiles.default = { + id = 0; + name = "default"; + isDefault = true; + containersForce = true; + settings = { + "tabopencontaineraware" = true; + }; + containers = { + personal = { + id = 1; + color = "blue"; + icon = "fingerprint"; + }; + google = { + id = 2; + color = "pink"; + icon = "fence"; + }; + london = { + id = 3; + color = "orange"; + icon = "briefcase"; + }; + research = { + id = 4; + color = "green"; + icon = "tree"; + }; + chill = { + id = 5; + color = "turquoise"; + icon = "chill"; + }; + }; + + search = { + force = true; + default = "ddg"; + order = [ + "ddg" + "Kagi" + "NixOS" + ]; + engines = { + "Kagi" = { + urls = [ { template = "https://kagi.com/search?q={searchTerms}"; } ]; + icon = "https://kagi.com/favicon.ico"; + updateInterval = 24 * 60 * 60 * 1000; + definedAliases = [ "kg" ]; + }; + "nx" = { + urls = [ { template = "https://mynixos.com/search?q={searchTerms}"; } ]; + icon = "https://mynixos.com/favicon.ico"; + updateInterval = 24 * 60 * 60 * 1000; + definedAliases = [ "nx" ]; + }; + "ddg" = { + metaData.alias = "dd"; + }; + "google".metaData.hidden = true; + "bing".metaData.hidden = true; + "amazondotcom-us".metaData.hidden = true; + "ebay".metaData.hidden = true; + }; + }; + + settings = { + "layout.css.prefers-color-scheme.content-override" = 2; + "privacy.resistFingerprinting" = false; + "privacy.resistFingerprinting.exemptions" = "prefers-color-scheme"; + "browser.theme.dark-private-windows" = true; + }; + extensions = { + packages = with pkgs.nur.repos.rycee.firefox-addons; [ + ublock-origin + tridactyl + gopass-bridge + multi-account-containers + foxyproxy-standard + ]; + # force = true; + # settings."uBlock0@raymondhill.net".settings = { + # selectedFilterLists = [ + # "ublock-filters" + # "ublock-badware" + # "ublock-privacy" + # "ublock-unbreak" + # "ublock-quick-fixes" + # ]; + # }; + }; + }; + }; + }; +} diff --git a/impermanence.nix b/impermanence.nix new file mode 100644 index 0000000..b0b2f8d --- /dev/null +++ b/impermanence.nix @@ -0,0 +1,53 @@ +{ + environment.persistence."/.persist" = { + enable = true; + hideMounts = true; + directories = [ + "/etc/nixos" + "/var/lib/nixos" + ]; + users.root = { + files = [ + ".config/sops/age/keys.txt" + ]; + }; + files = [ + # + ]; + + users.user = { + files = [ + ".config/sops/age/keys.txt" + ]; + directories = [ + ".config/nvim" + ".config/niri" + ".config/ghostty" + ".config/tmux" + ".config/tmux-powerline" + ".ssh" + ".local/share/wallpapers" + ]; + }; + }; + + environment.persistence."/.nobackup" = { + enable = true; + hideMounts = true; + directories = [ + "/var/log" + "/var/cache" + "/var/lib/docker" + ]; + users.root = { + directories = [ + ".cache" + ]; + }; + users.user = { + directories = [ + ".cache" + ]; + }; + }; +} diff --git a/kernel/default.nix b/kernel/default.nix new file mode 100644 index 0000000..c823c54 --- /dev/null +++ b/kernel/default.nix @@ -0,0 +1,63 @@ +{ + lib, + pkgs, + ... +}: +{ + imports = [ + ./hardened.nix + ./vfio.nix + ./standard.nix + # ./apparmor.nix + ]; + + custom.kernel.hardened.enable = true; + custom.kernel.vfio.enable = false; + custom.kernel.standard.enable = true; + # security.apparmor.enable = false; + + specialisation.unhardened.configuration = { + custom.kernel.hardened.enable = lib.mkForce false; + # security.apparmor.enable = lib.mkForce false; + }; + + specialisation.vfio.configuration = { + custom.kernel.vfio.enable = lib.mkForce true; + custom.kernel.standard.enable = lib.mkForce false; + }; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.enableRedistributableFirmware = true; + hardware.cpu.amd.updateMicrocode = true; + + security.rtkit.enable = true; + security.sudo.enable = false; + security.doas = { + enable = true; + + extraRules = [ + { + users = [ "user" ]; + keepEnv = true; + persist = true; + } + { + users = [ "user" ]; + runAs = "agent"; + noPass = true; + keepEnv = false; + } + ]; + }; + + boot = { + loader = { + systemd-boot.enable = true; + efi.canTouchEfiVariables = true; + }; + kernelPackages = pkgs.linuxPackages_zen; + kernelParams = [ + "amd_iommu=on" + ]; + }; +} diff --git a/kernel/hardened.nix b/kernel/hardened.nix new file mode 100644 index 0000000..0006d97 --- /dev/null +++ b/kernel/hardened.nix @@ -0,0 +1,207 @@ +{ + lib, + config, + pkgs, + ... +}: +let + cfg = config.custom.kernel.hardened; +in +{ + options.custom.kernel.hardened = { + enable = lib.mkEnableOption "hardened kernel options"; + }; + config = lib.mkIf cfg.enable { + environment.systemPackages = [ + pkgs.kernel-hardening-checker + pkgs.lynis + ]; + + security = { + auditd.enable = false; + audit.enable = false; + audit.rules = [ "-a always,exit -F arch=b64 -S execve" ]; + protectKernelImage = true; + lockKernelModules = false; # this breaks iptables, wireguard, and virtd + + # force-enable the Page Table Isolation (PTI) Linux kernel feature + forcePageTableIsolation = true; + + # User namespaces are required for sandboxing. + # this means you cannot set `"user.max_user_namespaces" = 0;` in sysctl + allowUserNamespaces = true; + + # Disable unprivileged user namespaces, unless containers are enabled + unprivilegedUsernsClone = config.virtualisation.containers.enable; + allowSimultaneousMultithreading = true; + }; + + boot.kernel.sysctl = { + "fs.suid_dumpable" = 0; + # prevent pointer leaks + "kernel.kptr_restrict" = 2; + # restrict kernel log to CAP_SYSLOG capability + "kernel.dmesg_restrict" = 1; + # Note: certian container runtimes or browser sandboxes might rely on the following + # restrict eBPF to the CAP_BPF capability + "kernel.unprivileged_bpf_disabled" = 1; + # should be enabled along with bpf above + # "net.core.bpf_jit_harden" = 2; + # restrict loading TTY line disciplines to the CAP_SYS_MODULE + "dev.tty.ldisk_autoload" = 0; + # prevent exploit of use-after-free flaws + "vm.unprivileged_userfaultfd" = 0; + # kexec is used to boot another kernel during runtime and can be abused + "kernel.kexec_load_disabled" = 1; + # Kernel self-protection + # SysRq exposes a lot of potentially dangerous debugging functionality to unprivileged users + # 4 makes it so a user can only use the secure attention key. A value of 0 would disable completely + "kernel.sysrq" = 4; + # disable unprivileged user namespaces, Note: Docker, NH, and other apps may need this + "kernel.unprivileged_userns_clone" = 1; + # restrict all usage of performance events to the CAP_PERFMON capability + "kernel.perf_event_paranoid" = 3; + + # Network + # protect against SYN flood attacks (denial of service attack) + "net.ipv4.tcp_syncookies" = 1; + # protection against TIME-WAIT assassination + "net.ipv4.tcp_rfc1337" = 1; + # enable source validation of packets received (prevents IP spoofing) + "net.ipv4.conf.default.rp_filter" = 1; + "net.ipv4.conf.all.rp_filter" = 1; + + "net.ipv4.conf.all.accept_redirects" = 0; + "net.ipv4.conf.default.accept_redirects" = 0; + "net.ipv4.conf.all.secure_redirects" = 0; + "net.ipv4.conf.default.secure_redirects" = 0; + # Protect against IP spoofing + "net.ipv6.conf.all.accept_redirects" = 0; + "net.ipv6.conf.default.accept_redirects" = 0; + "net.ipv4.conf.all.send_redirects" = 0; + "net.ipv4.conf.default.send_redirects" = 0; + + # prevent man-in-the-middle attacks + "net.ipv4.icmp_echo_ignore_all" = 1; + + # ignore ICMP request, helps avoid Smurf attacks + "net.ipv4.conf.all.forwarding" = 0; + "net.ipv4.conf.default.accept_source_route" = 0; + "net.ipv4.conf.all.accept_source_route" = 0; + "net.ipv6.conf.all.accept_source_route" = 0; + "net.ipv6.conf.default.accept_source_route" = 0; + # Reverse path filtering causes the kernel to do source validation of + "net.ipv6.conf.all.forwarding" = 0; + "net.ipv6.conf.all.accept_ra" = 0; + "net.ipv6.conf.default.accept_ra" = 0; + + ## TCP hardening + # Prevent bogus ICMP errors from filling up logs. + "net.ipv4.icmp_ignore_bogus_error_responses" = 1; + + # Disable TCP SACK + "net.ipv4.tcp_sack" = 0; + "net.ipv4.tcp_dsack" = 0; + "net.ipv4.tcp_fack" = 0; + + # Userspace + # restrict usage of ptrace + "kernel.yama.ptrace_scope" = 2; + + # ASLR memory protection (64-bit systems) + "vm.mmap_rnd_bits" = 32; + "vm.mmap_rnd_compat_bits" = 16; + + # only permit symlinks to be followed when outside of a world-writable sticky directory + "fs.protected_symlinks" = 1; + "fs.protected_hardlinks" = 1; + # Prevent creating files in potentially attacker-controlled environments + "fs.protected_fifos" = 2; + "fs.protected_regular" = 2; + + # Randomize memory + "kernel.randomize_va_space" = 2; + # Exec Shield (Stack protection) + "kernel.exec-shield" = 1; + + ## TCP optimization + # TCP Fast Open is a TCP extension that reduces network latency by packing + # data in the sender’s initial TCP SYN. Setting 3 = enable TCP Fast Open for + # both incoming and outgoing connections: + "net.ipv4.tcp_fastopen" = 3; + # Bufferbloat mitigations + slight improvement in throughput & latency + "net.ipv4.tcp_congestion_control" = "bbr"; + "net.core.default_qdisc" = "cake"; + }; + + boot.kernelParams = [ + "audit=0" + # make it harder to influence slab cache layout + "slab_nomerge" + # enables zeroing of memory during allocation and free time + # helps mitigate use-after-free vulnerabilaties + "init_on_alloc=1" + "init_on_free=1" + # randomizes page allocator freelist, improving security by + # making page allocations less predictable + "page_alloc.shuffel=1" + # enables Kernel Page Table Isolation, which mitigates Meltdown and + # prevents some KASLR bypasses + "pti=on" + # randomizes the kernel stack offset on each syscall + # making attacks that rely on a deterministic stack layout difficult + "randomize_kstack_offset=on" + # disables vsyscalls, they've been replaced with vDSO + "vsyscall=none" + # disables debugfs, which exposes sensitive info about the kernel + "debugfs=off" + # certain exploits cause an "oops", this makes the kernel panic if an "oops" occurs + "oops=panic" + # only alows kernel modules that have been signed with a valid key to be loaded + # making it harder to load malicious kernel modules + # can make VirtualBox or Nvidia drivers unusable + #"module.sig_enforce=1" + # prevents user space code excalation + "lockdown=confidentiality" + # "rd.udev.log_level=3" + # "udev.log_priority=3" + ]; + + boot.blacklistedKernelModules = [ + # Obscure networking protocols + "dccp" # Datagram Congestion Control Protocol + "sctp" # Stream Control Transmission Protocol + "rds" # Reliable Datagram Sockets + "tipc" # Transparent Inter-Process Communication + "n-hdlc" # High-level Data Link Control + "ax25" # Amateur X.25 + "netrom" # NetRom + "x25" # X.25 + "rose" + "decnet" + "econet" + "af_802154" # IEEE 802.15.4 + "ipx" # Internetwork Packet Exchange + "appletalk" + "psnap" # SubnetworkAccess Protocol + "p8023" # Novell raw IEE 802.3 + "p8022" # IEE 802.3 + "can" # Controller Area Network + "atm" + # Various rare filesystems + "cramfs" + "freevxfs" + "jffs2" + "hfs" + "hfsplus" + # "udf" + # "nfs" # Network File System + # "nfsv3" + # "nfsv4" + "gfs2" # Global File System 2 + # vivid driver is only useful for testing purposes and has been the + # cause of privilege escalation vulnerabilities + "vivid" + ]; + }; +} diff --git a/kernel/standard.nix b/kernel/standard.nix new file mode 100644 index 0000000..9926a9e --- /dev/null +++ b/kernel/standard.nix @@ -0,0 +1,55 @@ +{ + config, + lib, + ... +}: +let + cfg = config.custom.kernel.standard; +in +{ + options.custom.kernel.standard = { + enable = lib.mkOption { + type = lib.types.bool; + default = true; + }; + }; + config = lib.mkIf (cfg.enable) { + hardware.nvidia = { + modesetting.enable = true; + powerManagement.enable = true; + powerManagement.finegrained = false; + open = true; + nvidiaSettings = false; + package = config.boot.kernelPackages.nvidiaPackages.stable; + }; + services.xserver.videoDrivers = [ + "nvidia" + "amdgpu" + ]; + boot = { + initrd.availableKernelModules = [ + "nvme" + "xhci_pci" + "ahci" + "usbhid" + "sd_mod" + "uas" + "usbcore" + "usb_storage" + "vfat" + "nls_cp437" + "nls_iso8859_1" + "virtio_pci" + "virtio_blk" + "virtio_net" + "virtio_ring" + ]; + initrd.kernelModules = [ + "amdgpu" + "nvidia" + "nvidia_modeset" + "nvidia_drm" + ]; + }; + }; +} diff --git a/kernel/vfio.nix b/kernel/vfio.nix new file mode 100644 index 0000000..7a94abb --- /dev/null +++ b/kernel/vfio.nix @@ -0,0 +1,70 @@ +{ + config, + lib, + pkgs, + ... +}: +let + cfg = config.custom.kernel.vfio; +in +{ + options.custom.kernel.vfio = { + enable = lib.mkOption { + type = lib.types.bool; + default = false; + }; + }; + config = lib.mkIf cfg.enable { + hardware.nvidia = lib.mkForce { + modesetting.enable = false; + }; + services.xserver.videoDrivers = [ + "amdgpu" + ]; + boot = { + extraModulePackages = [ config.boot.kernelPackages.kvmfr ]; + extraModprobeConfig = '' + options kvmfr static_size_mb=128 + ''; + kernelParams = [ + "vfio-pci.ids=10de:2204,10de:1aef" + ]; + kernelModules = [ "kvmfr" ]; + initrd.availableKernelModules = [ + "nvme" + "xhci_pci" + "ahci" + "usbhid" + "sd_mod" + "uas" + "usbcore" + "usb_storage" + "vfat" + "nls_cp437" + "nls_iso8859_1" + "virtio_pci" + "virtio_blk" + "virtio_net" + "virtio_ring" + ]; + initrd.kernelModules = [ + "vfio_pci" + "vfio_iommu_type1" + "vfio" + + "amdgpu" + "kvmfr" + "kvm-amd" + ]; + }; + services = { + udev.extraRules = '' + SUBSYSTEM=="kvmfr", OWNER="user", GROUP="kvm", MODE="0660" + ''; + }; + + environment.systemPackages = [ + pkgs.looking-glass-client + ]; + }; +} diff --git a/networking.nix b/networking.nix new file mode 100644 index 0000000..d0627e5 --- /dev/null +++ b/networking.nix @@ -0,0 +1,156 @@ +{ + config, + hostname, + pkgs, + ... +}: +{ + imports = [ ./wireguard.nix ]; + sops.secrets = { + "wg0/conf".sopsFile = ./secrets/vpn.yaml; + "wg-br0/conf".sopsFile = ./secrets/vpn.yaml; + "wg-us0/conf".sopsFile = ./secrets/vpn.yaml; + "wg-uk0/conf".sopsFile = ./secrets/vpn.yaml; + }; + + networking = { + hostName = hostname; + nameservers = [ "192.168.88.3" ]; + networkmanager.enable = false; + firewall.trustedInterfaces = [ "vlan66" ]; + useDHCP = false; + useNetworkd = true; + + # vlans.vlan66 = { + # id = 66; + # interface = "br0"; + # }; + # interfaces = { + # br0.useDHCP = true; + # vlan66.useDHCP = true; + # }; + # bridges.br0 = { + # interfaces = [ inetInterface ]; + # }; + firewall.allowedTCPPorts = [ + 9003 + 10000 + 10001 + 11000 + 11001 + 12000 + 12001 + 13000 + 13001 + ]; + }; + + systemd.network = { + enable = true; + netdevs."20-br0" = { + netdevConfig = { + Kind = "bridge"; + Name = "br0"; + }; + }; + + networks."10-tap" = { + matchConfig.Name = [ + "en*" + "eth*" + ]; + networkConfig.Bridge = "br0"; + }; + + networks."20-br0" = { + matchConfig.Name = "br0"; + networkConfig = { + DHCP = "yes"; + }; + linkConfig.RequiredForOnline = "routable"; + }; + + # netdevs."30-vlan66" = { + # netdevConfig = { + # Kind = "vlan"; + # Name = "vlan66"; + # }; + # vlanConfig = { + # Id = 66; + # }; + # }; + + # networks."30-vlan66" = { + # matchConfig.Name = "vlan66"; + # networkConfig.DHCP = "yes"; + # }; + }; + + services.wireguard-netns = { + enable = true; + namespaces = { + wg0 = { + dns = "10.2.0.1"; + address = "10.2.0.2/32"; + conf = "wg0/conf"; + }; + wg-br0 = { + dns = "10.2.0.1"; + address = "10.2.0.2/32"; + conf = "wg-br0/conf"; + }; + wg-us0 = { + dns = "10.2.0.1"; + address = "10.2.0.2/32"; + conf = "wg-us0/conf"; + }; + wg-uk0 = { + dns = "10.2.0.1"; + address = "10.2.0.2/32"; + conf = "wg-uk0/conf"; + }; + }; + }; + + # systemd.services."netns@wg0ns" = { + # description = "wg0 network namespace"; + # before = [ "network.target" ]; + # serviceConfig = { + # Type = "oneshot"; + # RemainAfterExit = true; + # ExecStart = pkgs.writers.writeBash "wg0ns-up" '' + # ${pkgs.coreutils}/bin/mkdir -p /etc/netns/wg0ns + # echo "nameserver $(cat ${config.sops.secrets."wg0/dns".path})" > /etc/netns/wg0ns/resolv.conf + # ${pkgs.iproute2}/bin/ip netns add wg0ns + # ''; + # ExecStop = "${pkgs.iproute2}/bin/ip netns del wg0ns"; + # }; + # }; + # + # systemd.services.wg0 = { + # description = "wg0 network interface"; + # bindsTo = [ "netns@wg0ns.service" ]; + # requires = [ "network-online.target" ]; + # after = [ "netns@wg0ns.service" ]; + # wants = [ "network-online.target" ]; + # wantedBy = [ "multi-user.target" ]; + # serviceConfig = { + # Type = "oneshot"; + # RemainAfterExit = true; + # ExecStart = pkgs.writers.writeBash "wg-up" '' + # ${pkgs.iproute2}/bin/ip link add wg0 type wireguard + # ${pkgs.iproute2}/bin/ip link set wg0 netns wg0ns + # ${pkgs.iproute2}/bin/ip -n wg0ns address add $(< ${config.sops.secrets."wg0/address".path}) dev wg0 + # ${pkgs.iproute2}/bin/ip netns exec wg0ns \ + # ${pkgs.wireguard-tools}/bin/wg setconf wg0 ${config.sops.secrets."wg0/conf".path} + # ${pkgs.iproute2}/bin/ip -n wg0ns link set lo up + # ${pkgs.iproute2}/bin/ip -n wg0ns link set wg0 up + # ${pkgs.iproute2}/bin/ip -n wg0ns route add default dev wg0 + # ''; + # ExecStop = pkgs.writers.writeBash "wg-down" '' + # ${pkgs.iproute2}/bin/ip -n wg0ns route del default dev wg0 + # ${pkgs.iproute2}/bin/ip -n wg0ns link del wg0 + # ''; + # }; + # }; +} diff --git a/packages.nix b/packages.nix new file mode 100644 index 0000000..531f167 --- /dev/null +++ b/packages.nix @@ -0,0 +1,248 @@ +{ config, pkgs, ... }: +{ + environment.systemPackages = with pkgs; [ + bat + black + blade-formatter + cmake + cifs-utils + coreutils + bluetuith + bluez + bluez-tools + cargo + clang + clang-tools + clevis + cliphist + distrobox + dos2unix + dnsutils + dunst + (import ./templates/extract.sh.nix { inherit pkgs; }) + eza + fd + ffmpeg + fira-code-symbols + fish + fractal + freetube + fuzzel + fzf + git + gh + ghostty + go + google-chrome + gopass + gopass-jsonapi + gopls + hyprpicker + htmx-lsp2 + imagemagick + inkscape + pavucontrol + pciutils + poppler + jetbrains.datagrip + jq + lazygit + (pkgs.writeShellScriptBin "lf" '' + cd_file="/tmp/lf-lastdir-$$" + + ${pkgs.lf}/bin/lf "$@" + + if [ -f "$cd_file" ]; then + cd "$(cat "$cd_file")" + rm "$cd_file" + fi + '') + libreoffice + libvirt + linux-firmware + lldb + lua-language-server + luarocks + lutris + mpv + nerd-fonts.monaspace + niri + niri-scratchpad + nixd + nixfmt + (wrapOBS { + plugins = with obs-studio-plugins; [ + wlrobs + obs-pipewire-audio-capture + ]; + }) + # ols + php + php84Packages.composer + php84Packages.php-cs-fixer + phpactor + podman-compose + podman-tui + prettierd + playerctl + qemu_full + qmk + quickshell + resvg + ripgrep + ripdrag + rust-analyzer + sshfs + starship + step-cli + stow + stylua + sops + swayimg + texlab + texlive.combined.scheme-full + tmux + thunderbird + tor-browser + ungoogled-chromium + unzip + virt-manager + virt-viewer + vscode-langservers-extracted + watchexec + wayland + wgsl-analyzer + # wineWowPackages.waylandFull + wineWow64Packages.waylandFull + winetricks + wl-clipboard + xxd + xdg-user-dirs + xwayland-satellite + yazi + zathura + # zig_0_15 + # zls_0_15 + zoxide + ]; + + hardware.keyboard.qmk.enable = true; + + programs = { + fish.enable = true; + virt-manager.enable = true; + direnv.enable = true; + gnupg.agent = { + enable = true; + enableSSHSupport = true; + }; + nix-ld.enable = true; + niri.enable = true; + dconf.enable = true; + thunar.enable = true; + }; + + virtualisation.containers.enable = true; + virtualisation.podman = { + enable = true; + dockerCompat = true; + # rootless = { + # enable = true; + # setSocketVariable = true; + # }; + defaultNetwork.settings.dns_enabled = true; + # storageDriver = "btrfs"; + }; + + virtualisation.spiceUSBRedirection.enable = true; + virtualisation.libvirtd = { + enable = true; + extraConfig = '' + user="user" + ''; + onBoot = "ignore"; + onShutdown = "shutdown"; + qemu = { + package = pkgs.qemu_full; + verbatimConfig = '' + cgroup_device_acl = [ + "/dev/null", "/dev/full", "/dev/zero", + "/dev/random", "/dev/urandom", "/dev/ptmx", + "/dev/kvm", "/dev/kvmfr0" + ] + ''; + runAsRoot = true; + swtpm.enable = true; + }; + }; + + programs.steam = { + enable = true; + remotePlay.openFirewall = true; + dedicatedServer.openFirewall = true; + localNetworkGameTransfers.openFirewall = true; + }; + + programs.firejail = { + enable = true; + wrappedBinaries = { + chromium-sandbox = { + executable = "${pkgs.chromium}/bin/chromium"; + profile = "${pkgs.firejail}/etc/firejail/chromium-browser.profile"; + extraArgs = [ + "--netns=wg0ns" + "--whitelist=/home/user/downloads" + "--env=TGK_THEME=Adwaita:dark" + "--dns=10.2.0.1" + "--private=/data/sandbox/chromium" + ]; + }; + google-chrome-stable = { + # executable = "${chrome-argumented}/bin/google-chrome-stable"; + executable = "${pkgs.google-chrome}/bin/google-chrome-stable"; + profile = "${pkgs.firejail}/etc/firejail/google-chrome-stable.profile"; + extraArgs = [ + "--env=GTK_THEME=Adwaita:dark" + "--netns=wg-br0ns" + "--dns=10.2.0.1" + "--whitelist=/home/user/downloads" + "--whitelist=/home/user/pictures" + ]; + }; + tor-browser = { + executable = "${pkgs.tor-browser}/bin/tor-browser"; + profile = "${pkgs.firejail}/etc/firejail/tor-browser-en-us.profile"; + extraArgs = [ + "--netns=wg0ns" + "--dns=1.1.1.1" + ]; + }; + freetube = { + executable = "${pkgs.freetube}/bin/freetube"; + profile = "${pkgs.firejail}/etc/firejail/freetube.profile"; + extraArgs = [ + "--netns=wg0ns" + "--dns=1.1.1.1" + ]; + }; + }; + }; + + # services.ollama = { + # enable = true; + # package = pkgs.ollama-cuda; + # home = "/data/ollama"; + # user = "ollama"; + # group = "user"; + # loadModels = [ + # "llama3" + # ]; + # }; + # services.open-webui = { + # enable = true; + # port = 11347; + # environment = { + # OLLAMA_API_BASE_URL = "${config.services.ollama.host}:${toString config.services.ollama.port}"; + # }; + # }; +} diff --git a/secrets/home.yaml b/secrets/home.yaml new file mode 100644 index 0000000..97ba836 --- /dev/null +++ b/secrets/home.yaml @@ -0,0 +1,36 @@ +root: + password: ENC[AES256_GCM,data:qA7sbNvWvfmWiLX4pIYOzDmuCwc3+7I1KvTHHYF5jDHR0CNRuya0XglP8TNK5qGLEJkdmD9WphdWvYY60NTOf5NFhDnqtm3ZIw==,iv:B42jl40hQbRqMRfV39fNne0E3KKCwriAQ5MQ0DF4QQA=,tag:hH/u0Qw6A2is4XOOQpnr2Q==,type:str] + ssh: + desktop: ENC[AES256_GCM,data:mjenzt2rI9vZ4VnpWttAmojzEaGDgDTO0Tc5ICTZzKRC8fDIWc/YH81mCkU8BpPJGPiCQSCPz+/r7MEjcfjC0Xhf5xnSxespw/2eiCoeR4qWGMC4SlizusR+DBxwvW71MBn8icZkJyWc9zKPAfDyZQhtVUthvcQYTVsJEvMkRYSkTQgKJI0iEpq2x4j8fKr/FY4EQsidm5BFykOYOFejECWkkcMf0i+FBS60EsH3aZV+5c5fNNlj9GIdmX5rMp8iHa/RlGfxiu0QIaZRa+Q9h+h/d2Utf5qRFv2qpq+Fk7tI9JErtwwB+tKdXbavPjgWt3YtqI4O0f+01BWKRTPzFeiRANoONuGRgcx+b/GkAaHV4P+7uqIgmWgkwqCliYkgdwFtE2dWS6M/DEO+KP+GyKUykusdx2xODp+gA/CpiJM5OWPxmsgkDkuM/aLr3cBdzUHSJ028RCWBkTO/LsUOKNBpQ/9ePM5AoGVG7//gPlPEqURh5QrsJRJnr75E1qAI1Eu5XVIFrprPx3lxJEDWv6YPjUm6Aj6g2+b9,iv:rvJGN0ha+cACzf8u9dBRu1HOMx1jyx8Gwe2MJpJ6pb4=,tag:wkbymeExmj98vzDMSG5uTQ==,type:str] +user: + password: ENC[AES256_GCM,data:s5U1eR8aM4AM4J8j1VcRM8eSS/V6iJY/Dj9Ggis466Yxg+eUYWEimY1IWWVvFReRZ8WkbACysA56YZrLdEDowc1+lzeZQvPwYg==,iv:T7W1APCEozr7Eck06cDb3+VdVwjhQ3QoOrp7t+Hr2/4=,tag:MCH47JYaLyNEboW1oHC1kQ==,type:str] + gpg: + legacy_fnzr: ENC[AES256_GCM,data:aokSG2rHR6iX94GCcCmCxcz1lXSRvO03uhaUVGrNJT5aDjNjrjLya4TpUEVLvZXy87VaZobfuR+KQIcyi5zFHNCberq3q7h2zmtKhCEsnuy97oam7X39o/Jker/36geFxkDW5kvYAtcYL16Zi6cMB2+VvI7Sv0YGawGvvFfYjHjaV/wl0QPv+jyvM/HT9V7EMqJ7CER2QQVdkPuJHQSy/LsZqtcFGEDTuiGY7jZO4wWPByQ6PNPg4SiGeRfHz9rPvKO4LxQGt6keynM7VApZjTKOMcmaTgdOEgop5Sa9nZ+b5J7BJuP69vwnyREiP6u5T5l7QSxhFei+2K9iBMke+nbwM468lwnV9pUlpbBNxMwqVIRKiAGkcyZilmhlQd9Q4Dy5LwszItOM97+gN70IFkrzf6sO3nKsQWRr7kSwOAwvn1EQGEjj+KE1KM+cu+Y31PBBzkxtWBISJA1qzGcO35aeKNv8wGDGFliecg0Dz4SmtPXwP5Cd46U5XM/w8GMGRFg0b6anink1se7hOuYYSm9PzfJKbDOEL7eV5mhAGC2Qwv1q3Vwss+r1l6/b4myesP+OeVyeGCDMhCqO9VA6sQuBuddS2hYzh7tjI+p+0VXW7wonApNCKAMY90QLu2+8f33twYncWETbK/PkTz1jr4VVQIzh65kDclGPePfC2QMMRlT8eAL8y7u2RvDl6jteeQKiLsG7sz1NCXg484GfD8l9eMW3slLtY0b+9XHuCv09kkGkoktSw2udjoF4s9iJsGKOFRGZ/nLnpoXh0ftlKHvohhfqrTmwwvbPLYg9rn59dO6ZgIwH8hVi+ERWTtfpPERYPbIGLh7iRQf6iPI2d5oiE4wVjOsidiR5fhrb+0S8oALAV1Jhm5Y5Md0ePLrnPJxOXvAqCE1WXpjmZzl37qj+1FV/FFyh3Pq+GfmSN4fEllj7rkFppGBOQ19+8mV1JFkOVfkzwqV4NP8c08FigeO3T4vyvxu4jfMbovjS6Mi8Olia7pNGB6kZogHQXIGH7WE1tqmGFnEOvOHz+YKJ48apCtZ/ePo02lu/xZM4GNO5Q1LXpZtO67tpuepBjtmSGhBhUtt2ssdLpJVsDNbuLKDrT8ZA1wD7gA2C9wx+ycT5+JqE3o99J3unxVI=,iv:o3mrSYQINgMTaQBleo9hdNZZaPC4/OFf7RaJIvDVjv0=,tag:5v0SZBOpjdkFAezrKzQfLQ==,type:str] + ssh: + desktop: ENC[AES256_GCM,data:BXzI4BQmwunDe+PnmRjeDdZgaDVaJCqErhfUiDPtgOtx0+y1wPSTQoHBWM0+qnPTo0GtK2LmjlDGSoXUUl/aavwGyHG+/XMZcRs3LLGZqAOCWCAoA4N8nJIv2PFPCDdboK99HSR70eqHWgHk8McRrqpwDUaCsTaizU+e7R7bKX08kBp+k02fE2OW7OJHTfK6H+qH8yV8PpBXGpiPG/8OMsLa9m+1burb0KeMVRVk8Jd+kQ9meYj0xUH05l/VV7jeZ5XmZQOCtNxIRDnALjfWDJ44QLcdt1OoA8WZCoUV1437u88hYi45vo8IvFK46DBMnQGnGioITkOoIzBYAPFf/RWzyJZChrQ8qgCIfoOszbGrjXu5j1upa0KvLe4EkOBCeGNi+vPG75Q6Ma25jBLXxIq+xBeoSZyW5w9GLNEjXT7D6hXiVpypBQK3AW4JjOLywXDYG5dJzqrS4QQvilKIqj/EWSGiYkrHNJd+jVaBx/M6HrgW9Vfs0JuSz1bWgzASjqn/3zx6UzbaREm+j5Is6t1PPsix+zPKAo09,iv:gmtvM+6auTFlH3fxtq+HXq5PuzGTnIRgLIVfvPuk3hw=,tag:d0kpvr12rA/HcYOw7hDBUw==,type:str] + legacy_ed25519: ENC[AES256_GCM,data:0VbcLU1XtHfgi5mM+qYZ74ZE48DiKc2lzw2Ro13XyLvQMHP6fiTKZkrPFA/LQW+sQBG2Ax5dbAYaf4Gxe5wIWKn0kU8uai17//IS2ahN91fQ2GKC3ofURfwmTEZXnQPHXjK1Kygb6uMGWYOjjiY4JCXsEr2Ur5OTH5Cn7wrOPLFp4V7rK66RlrUuYoB52uGC8ds/KZWSRKZKSRJ2fIJkAZtOFUTzU1nbScKC7pVjt1pZmCI2dYzVD3xo/p90wZAXTTq6B6pprtnApHnzEW8kP5RVUdc9euMQm/HlQUh0RexUlfJCkloVxYD0RRiGL9RFABxQCdeyK6VNcgRZ32M6cUji0FSDgE04qTz0HN062Um/ebB65zFmTAN4GZLClIUqJVa9qXweESGkzbUV5t1J7IXDtG+ZdJmPokX31ozF69Vtcf53LQOee1d4zseP+niOR63tYOkZWkthRRLx4yxXSODyZcVe7ASbwICnxmf3bh1Qbn/4LU3NSBF1DZXiVIKR9COMdO8vqx4H2zZLrkn06I33J9sjoI4ejEFX,iv:Tjts8BRYhE+Nn9dyAL2yNpvPF8oMTwyVvoQkmwAsjrA=,tag:PuHmgIvHt+Dv85EI2WFxng==,type:str] + legacy_rsa: ENC[AES256_GCM,data:PWBAlpIUbxVGDZlxJGvYRiUgeGnR7Bl1hXjzVC6MIt4hLPmc5SksBj5TmW+i6j312RLaFzYTb6SerFlFs6vn3Rtmk5Q7p/IO4JSKondJrsw1xw52YePP29FfIe7gtOxDK/F9YJhHb1VJQghQoWTN++iZjjg80iNVofBtAcrPPkyfH43Yw8In6jMla/p2w6vAhXAJS+8SpEdmdILOQT4OnDvkzi4Nwae2uFEWcGJI/kxstgAL97MTmu06qK9/zt8vuq6bTYeBOOFnasoIL+V/0A5dAz3aw8QwdSoRrN5+PEHmeB9y4+WCf10MTv8P2JxJ9ul4pCwZd2IEdg2gWSQa/vbSJdG7ZjaCih+blNEf8DTVtRQT9soTvti7MYYYziLfHw8LUT+c3nt+c0nXxVxOgRx0sGSuHsHT5HHGBOjw9PsZ+arZuwnIyrmfkm8TkvD+j7je2fqLACRBkp3CXg8a647To4GQXK0Y0yuJUpt18YSbVak9etGj5z7+PWs86NKHQ+gOrMxeirRuHGIa53FQSORYlpBZnM9FCAs4g5Fs4IZard/0LkX1lrhVUOk7OokRstiIWKJMOqRFuN+toZbCWMNVX4Hd8otSFG3U/vo3vK08TEF+HDIhp4rStPjJpOdyZStKyol6sKlHcVdMcgk79fmzesMZoSpITP/GTYe46xZ6vMQ2tvqvd0QcVJfBZuy4q2UUgjY+r8zgVRKw+Wo37YUUr4UFK2W5E23cLFkr+H9nV/cz08V1vUXk2eCi62czFXpjkpubQXysK246wHtdVFGpOmtDxicS4Zn3iqm/UxF5vKKguRaTdejXxfkRbsFhwn6/GrRAW6nxJLLVnSIzJEnNivt88m9cxmb1VYAHRZDNlGDK7ca8IhCb5yzPalRI0KqUMKen3MDLae+eEjcZH/lgGdhsZJg6Kxg/v0XC4dCJxNW+/ckIs5bjYMoQRfJ6OknAVFLwZcY0QZ+5EWrWNDkBEfPKub/r+KcF2sxIrv7KB0qXDsW4pCEcE+85i8xEiFs49ebeV4d42tsLzdYi9iVdZO4I1gzi929rbUFJLzVJCfkyn7Eic1u92UgBAa58lUFZ5LMEH9+P1V4Gm0GPIwXYvd4X+LIGhbqGDjGel+YeeLUHVRj4qeuoz1aLUCF8Cv0e3djBuhJ+tRSKdZM2aSz6PNrK2THfdFSiaHZmfH7McVXNum8TD8lhbkKIPDYdb2La3MVgvvgRN8Gw8L/Xkp/ivuFWXJ8Gc41AIUI2gY2mWbq1YAiwEuMeDJCXXAROKLQrd2rJYI7epbcw2EyLgtc90zsjWa1gFrHfBJVh23B69vWc5uEVyt/ryg3n4tp9QLjNpg0DRMjPTR+vEbsEHl7oLJdPO3XKof0h6QXXJ1ZtgHkSFS9MoXCnNhiC9ZKWA6PM31Yftp82RKiy5CSpf2AIVIOa3p9GUhVI0YlEN5tfejZuhybUL44JZ2FcVlhbC+zzLPIhROguHF0Az4Qg7tzKM9poin4xVV3HXs/mvXAcA8qnlQxnpuei3Lob4Iq1MUb9oNoA0QJ7nKIybSYUhKnGOq0Cv4ZVmxlk+RkXfTS4si3qEg3UxXjonP/e2oU334CsdSS32taP0KNTQzEP6j3AM4Zv/iEobz6XvRsKXHzbrG4UQefuQ+ZDw1DGlr/BKDLq9T+adGCWaCTKJChOIwoEQvij6rxtnGOJu9XC+/Tk8FVuzI/gPnRBOia0uUwaYskgoXmNjMgT+P8yNkdqx7MFJVdrFADyGhSaefVNszQlxfJlpAZtKazEltxmUdW6/pPoG42dfIcX+HxhbX1GqQa3japO7NrPQwLIw4LusBXd/ShLMyxkkYCcAidSgaSWgTWCzEIO5RbxRoxFA4qnEd6fqH61Y6W5Wg0Yk4DwWW/KcKn8xkgPdNk4hPq7IPL/x6Z1Dwb9zYf3T0G+97iezI9ZCNImd82aDOT5UcMZGYDD9yW9sEfohniaJcbu5DocNLTJDBa3UgiWluY7u+q4I/zPKN+9chA7h8p5BYAZJc03d1UBvHL8Mv2D7JIb/GlLhseRoV3A+b2qm6uwcxHA6zksAAx1XOZYlU88ls9ykeKKIB+AmlZEx4EuZG+E98DFp5dndMCYzL/1uy+LEsmTNrdmG+gl7bQlbYq5hOHaqtOAEsft/0VFzteRjg5Lagh0cqB1Rc92EGzQq84G5QYQb/DDZLC4i17SZEvwJoo3Ai476B6JpKefcQ5pPNf219mD/V/rodHMxm5vMC3hBQLpaSQ7ZtZ2jmwsxsWkrVaMU+NGBShqVLV+wsPlIWrSybnZC7hOLawZLev1CJ9Udiy82U1SyL9vB4dfHnhEra85nzdNvKwKzAwnr5mG2w1leJOzdg5kz8I0D98GFxmgrnOeQZ6S7/pjD7Qcw38exvEtCI8fpreAb7djbZN2sUNaSe8oitgukqNajBHlFA2z75P4dZ+IH+tTH25Inem/COojWnVQHsic03eus8x4jinbU6fxgZ6sT0SlyItTFgAAv3XqT3oHBiXIvF8DCcw7EtOeW1aZx6wR6D8JFLXTkMiXeug2wvQxV7MMXt7DBNUPqWLYnsrzAY+UaGkQtlnGiffDjCwbWkDfRpHMutMoYMk9o4yD26XTv3oV79Rod4+R39A8WEQhiHKPKFBS7TW+NttKMQVGgcmWvfRFeem4Iqy6JG22xxQqM9GK8gsUKa8MmEuLAQCGenXHIj+dOVWJugjG4IOdaQR3nB4LgwWIXHciYD9KmjlDsvd0MjQTc1bUBkS3aqOF6uvnWJ5LlWv5gs+OsFRMTe8wyqwCOLkj1EmmfJW3leEl/ONMkuaKCJTl7Yw1gto9itnC7rXFSIuGtLfW+4BSJQDYNRBskBkf81t1b6qejkS/3FFKEl8CzLdnuZU5WM5EOkR8ReAYTF/c4LYQjKDYbTAkXsuf9I8QbJXNwwJrP0C7zR4MgZQ5csKyxMNhxy5prTol5TIfCtwjy9UWOurI8WRwfqf6dyq31HtIDxD+elAJOlnZ+yHYH0Al/AETNhzWej35XJTMpYAK5wyBInM3enzBDqzEXQh4OLBwFMP0RaaZYnGTjbjyTUjmOj6GnMSbjwKECCEJFXfmpGsaxIG5RXIU71eu1x7k/Ifm3HgvQ9Q5Jw+EF6vYo1WNjOf9UbQhEhI1+uKEYEkwD/qFu07l9/WqLp3/nDNS66lnyag8jGKeO9WDb07WBBpxywtlN0vE8q9VmY7wXDdkaf5Gb13VwpaAyStANeP2Mp7XlmvYIFudzAY6kxkxCBA5rCY5guI0ebREHnJgR9ARzK3MD85X5abk8sY7Urx01tVdmx7eqVVrjBsEq65SUg8Z0jA7uVHTpOkVxboxJEWsdQN3JYYXz7Tg7M0t1PEYlxhUFIlIyvD8hrmUfxyZB0YgVI3faTezb+1I6xqAyxGFEVKPBzjyv36V9eMJmGB1wiZv3mNFqMUI9AMUHJAmIg==,iv:oGGm7bveDXNmxqe5Zina03vSVLJx9P3VBC/DbuI6KzY=,tag:taEL0E4Uinv1MQPxeRbPzA==,type:str] +sops: + age: + - recipient: age1y0tj3kt67pfnj38t9c8g2ghry3a0mhcq8rrqv5xr4jekwepxaelqzu3dkf + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBOZ3dERmxMbEJmSVhVRmVw + TUZZL0FzTHprci9ENHFodnRVWmRSbk1ab2xnCnZYeXN3MWRJZENlYmtWeFM0azdR + ZDFFYSsxRE9pdGZWV05hWnlacDlKbWcKLS0tIGNveTkwWEN2ajhaZ1JiaXRENzk0 + bFhna3RyY1kxK0IyVWlnR2FpMXk3UjQKvJaecXqAecBljJ9cNcHX13nxSxVey3LG + NdvJaMfEV4m3SqRF7YUoTzGYhucYjtX58E5SuvHnaP2qa21aDF+AZQ== + -----END AGE ENCRYPTED FILE----- + - recipient: age16v8w7q4wmn22hhakq2uzaus2508rhldm7lcwh0kukshzjzyhuqesqz44ze + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBSZnV1T0JKTXoyeUlZQ3o4 + QkR4OHZUbzQrbjdSK2VLTDNzMU9qdlUvVVUwClI4SDhMZTRDRXY3NlJSZ3REdmpJ + L2Y1N1p1VDFuK3VhbjJLaEVaenNQbWMKLS0tIEZGN3VlRFZqUFZQR1hCMTA5SEZN + NVlzQlQvMVc2dHZNK2pEWk80MStwY1UK38mxk1dJWi6XRKSwzcDA9qt8i1Grw2KJ + ac2EbJIFwYLOaMNOKF9hu+NrMdruRpU/2B8HlYYZjpNWmLb9jwI4wQ== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2025-12-22T18:37:14Z" + mac: ENC[AES256_GCM,data:BQj7pieRocXUP7as5/coL76WrpBPOwEzHlR+vTEOkBTD89hOnfUo0f2gJi/Ho4KldnCHKjQVGoLhA7l/NIuKXGs8OQ+0IYW9EOoEROi01EePW++Nw7rtOLBRQWojO9HpOmrOz8/fqMHq/vxrdrLql5gomNHJgPllBoAcALCUl2E=,iv:sPB13YhGgDO+KA+azVBqtIPrqRuoPpRfEljV5Xg4ig4=,tag:BnCePF7ii63Glq6dCI7YDg==,type:str] + unencrypted_suffix: _unencrypted + version: 3.11.0 diff --git a/secrets/vpn.yaml b/secrets/vpn.yaml new file mode 100644 index 0000000..e2601b7 --- /dev/null +++ b/secrets/vpn.yaml @@ -0,0 +1,37 @@ +wg0: + private_key: ENC[AES256_GCM,data:nr7y3wp7EtVW6uI6MBSwyMO9YuMyx/F0AZmD8GmuA3BPQTVTsVSctoKIxLE=,iv:KN68DwGuDo+aPP4mBk1MqY+lxFjisKSwXn0w+yngDRQ=,tag:gpjxIFWaZE+5hbYHVsO1ZQ==,type:str] + address: ENC[AES256_GCM,data:9Tnph2SHKeEt9Ss=,iv:CPR1N7fqqlaThGltSpfqeAOc5bAe13KWskGWj3jI8LQ=,tag:xha/hQOVqfUoGyfKbHhnuQ==,type:str] + conf: ENC[AES256_GCM,data:SRDnI+2PvK7Zz1L5XBvrBNejgJEg8DK+qVO5XEtx6Nal+f7IeB3Ascp8Bkit5fd5myn/RxiK80wYmvLkDmcJAk46UjHKOpbxJl1s5FmKDuZJ3c3MXLwH7k2PeZP14VDDlyQqlcyGBrSu74L64ZMh/6EWGKbONTD1Wt3Ykg+/RegzQFDr2CPbj6XQeXsNS2p0ugicP5ffBMTUa9KSYDMQVV80mjSZ246aeY0owU1VUsitdvsCbfxtFd5gr/9zdfOXOvGY/BKxAlvVbszCalNs9DgJDHt/,iv:FP90SvUGnsZJS7F/uxtbOqTvGOgtC4+r2+YgF5FBoQY=,tag:9G1tkXHTpbytmG9T6sTpMw==,type:str] +wg-br0: + private_key: ENC[AES256_GCM,data:y8djTiZ00DIhdN1YNUNmjqCPeSUrS+YWKfr4iLT8h54fSlgDn1OPAoyJllM=,iv:Wz/EiISOlaiSXSIa4h8L2wJPm34rxpQkErpuqAR/uC8=,tag:RS100jf8INb12q6+hGQDiw==,type:str] + conf: ENC[AES256_GCM,data:3TJ34y3NI1wO2Oyh7D72t2WmlOq/pMS43Ck3gDFV9QPSC7E3GHtc86aZqRQm8qbRqnkJco1+nlJZmsC+BQdmW+U5RkRL7vUyDmrCyeDyJvEkNIJLzcFi4lppbYXG3A+fRO2l5guQA5qNSQmnyux51yY11/OCahoFEEenL1wH+R0ugMK/LIPwK0/Y2u7c+7SvNwwtK9xQUlb4azqUsdLX0xkUFbBje2BgN50BB2TxLZJexUNjOTW9TE57tw3yI4VjYEvIyBXOK4uuuST+TcNJY5B45tjd8PmO9vPYDw==,iv:BdNVbiMjzGtX0rzkLBb/YCDxqBv15L7bJcLTPzvt/yM=,tag:NmEMTPasBSsg1GSkYi/HxA==,type:str] +wg-us0: + private_key: ENC[AES256_GCM,data:PWzeqoYLICXjYL5AV+dxUxYn6RL/tUMkfTMYhm+OdC85cPBPU135Ov15nUk=,iv:1CdiayG3F4xp3eid/ilboFUOL4Y92RUqipASOPT8Jl0=,tag:cJulFquSHjmKF+lUegp37Q==,type:str] + conf: ENC[AES256_GCM,data:x4bpjE/icVqe3lXHRNWf5W9w8EVAiNyqmFUR2LslSrEz0ekmJ4YDKDuU//+VoomsZzHhY6GhKtEVJ4Me/xY0G1+dSBBgpZlO8UyZVg8aydsVmA09fHYgwKovzHXc0XM9cbbovf2yyK8kO+X8e3ODy1dSu+a1SA3YsEp2G46kbRRxTdYazeHMJ+hJdmCONEvx0p0NcPlPAW8eZWEsAbVT/eQzB3TnF2THy/t4oWrn4r/MVvcsWgc1LJ3rVJ6L8RREU/PYBJoyDMgAs3DP79E8iOQS+bwdJj0+gcrP,iv:Ngqn/EA3QpOnBxz+slSyn+oOO33hLZlGhAg+RIlN+wI=,tag:BZFjGxI0nRsdPn99rvijdA==,type:str] +wg-uk0: + private_key: ENC[AES256_GCM,data:r1BEMvO+Q/6VTuC7N/iqWf1Cyp4WZsUitVF14n5QXPzYK9PoWgPGylQQpmg=,iv:wR1gsHzzu0C629bs7yGW6evjdieONyzMnc9vvtTEh2Q=,tag:lMk4DuTDFtOW0heIJ0Ef2A==,type:str] + conf: ENC[AES256_GCM,data:tCQaQEJ1Pa0jw96q/LRtqhAWes04GkGOUYAlZu3W3C9EGHj123dYZiWXcUgymSsi999M3RbO2mWNllSl17zkV1iGZAkA23aQLKDUU0/m/SSCLm2ohJOdLKkGeRK41TMGFRRydfYZJ9rg0iJdacfXrX2t4RGWgtprSlS2crOcrAQ+jhMjCNxKuAg0gaJyUh1lcTmOohe0aBiqxGJE+mc4mKMwCiUytNoprAc2TrnKUTQ7/eyIv9hn0PeRvLL59KFNrcVpCb7VRkufYpYlNtO1zyl2oczYzw+IXCHt,iv:S74FbQLM5sXhvoSaUD0wuMeAd7U4rL/dneaVS3ah8Bo=,tag:0U/k1Cyy4XbvmnlApg2BYg==,type:str] +sops: + age: + - recipient: age1y0tj3kt67pfnj38t9c8g2ghry3a0mhcq8rrqv5xr4jekwepxaelqzu3dkf + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBtOHZSRkpBVVdUUk9OYUFH + cVBra014WXJyRTJ0QWFKallLQlc0SXhNSlFBCmpwME92M2lCN2liVjZBRndlSVBk + OEpUU1YyakdCa0xVaHdhRlpXbGxYdUEKLS0tIDFlV1k0Qkx1UDd2NUVHTTI3NDZE + OWhIdUxDcHB4Z3dTdDkyZWF6NEJCYzAKfPB9AZFQ08yqil+4AhIi6EMy8PXI4CAz + lK4ON/M67T0UrlWN/m3pryOOr4Lj4oiZvdOR0BCO3kn4Pj0nq5jQOA== + -----END AGE ENCRYPTED FILE----- + - recipient: age16v8w7q4wmn22hhakq2uzaus2508rhldm7lcwh0kukshzjzyhuqesqz44ze + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBMSC9Td1NTMzk2NlJDTDNM + UVUzTSt1dGkrUVRGT1UzeXcwR1REN1U0dW5JCnNJRzdKZHVyR0dzaUw2TlVzQnQ2 + SHhSSGlDWUNBSXZiME5GM0JPTFRseDQKLS0tIEFnOXgzWFo2Rmo2THN4VFFIY1h0 + OEZ4WUp1QlVrTkVTN1BHMG0yaXFuSk0KLw3ZuvWTurJDTpyoq5YafLm8YFT4v4Vh + s+ay8ju3kA1CKjMF3gBQF08EoCdP/jU6tZerNwwcs17el5zIvRmG7Q== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2026-02-08T19:15:21Z" + mac: ENC[AES256_GCM,data:IxRNC13NPMIhVon0vCH3df+JxQlIPzv79H6JQzj8hkQNLxbFtPzk9DlHW1PWX90UAQbaXnzUM9uyHZhg4TypVsuKiEhpGyE4LXn/O7wD3U66YMkbqGrpKtnWbCQNdj///N5nDf71QwdLTEAzH+Kn9zRmiZ60rEu3w1Wm5vitB78=,iv:jWQvvO8kJDULepEUbWRym57whNpd23Q2PkXCDNQeJLo=,tag:wPBtn7Onr3S9ksEmdCZFzg==,type:str] + unencrypted_suffix: _unencrypted + version: 3.11.0 diff --git a/storage.nix b/storage.nix new file mode 100644 index 0000000..8ecc9fd --- /dev/null +++ b/storage.nix @@ -0,0 +1,128 @@ +{ ... }: +{ + disko.devices.disk = { + data = { + type = "disk"; + device = "/dev/disk/by-uuid/9878027d-209e-44f1-9030-13aa84c1fe0c"; + content = { + type = "gpt"; + partitions = { + root = { + size = "100%"; + content = { + type = "btrfs"; + extraArgs = [ "-f" ]; + mountpoint = "/data/.root-disk"; + mountOptions = [ + "compress=zstd" + "noatime" + ]; + subvolumes = { + "@vm" = { + mountpoint = "/data/vm"; + mountOptions = [ + "compress=zstd" + "noatime" + ]; + }; + "@games" = { + mountpoint = "/data/games"; + mountOptions = [ + "compress=zstd" + "noatime" + ]; + }; + }; + }; + }; + }; + }; + }; + main = { + type = "disk"; + device = "/dev/nvme0n1"; + content = { + type = "gpt"; + partitions = { + ESP = { + size = "2G"; + type = "EF00"; + start = "1M"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "umask=0077" ]; + }; + }; + root = { + size = "100%"; + content = { + type = "btrfs"; + extraArgs = [ "-f" ]; + mountpoint = "/.root-disk"; + mountOptions = [ + "compress=zstd" + "noatime" + ]; + subvolumes = { + "@root" = { + mountpoint = "/"; + mountOptions = [ + "compress=zstd" + "noatime" + ]; + }; + "@home" = { + mountpoint = "/home"; + mountOptions = [ + "compress=zstd" + "noatime" + ]; + }; + "@nix" = { + mountpoint = "/nix"; + mountOptions = [ + "compress=zstd" + "noatime" + ]; + }; + "@persist" = { + mountpoint = "/.persist"; + mountOptions = [ + "compress=zstd" + "noatime" + ]; + }; + "@nobackup" = { + mountpoint = "/.nobackup"; + mountOptions = [ + "compress=zstd" + "noatime" + ]; + }; + "@snapshots" = { + mountpoint = "/.snapshots"; + mountOptions = [ + "compress=zstd" + "noatime" + ]; + }; + }; + }; + }; + }; + }; + }; + }; + fileSystems."/.persist".neededForBoot = true; + fileSystems."/.nobackup".neededForBoot = true; + fileSystems."/home".neededForBoot = true; + + swapDevices = [ + { + device = "/.nobackup/swapfile"; + size = 64 * 1024; + } + ]; +} diff --git a/templates/certs/hydra_root_ca.crt b/templates/certs/hydra_root_ca.crt new file mode 100644 index 0000000..4c3a0d2 --- /dev/null +++ b/templates/certs/hydra_root_ca.crt @@ -0,0 +1,11 @@ +-----BEGIN CERTIFICATE----- +MIIBoDCCAUagAwIBAgIRAKiOpK5oYiVMtiIaoo1yW9wwCgYIKoZIzj0EAwIwLjER +MA8GA1UEChMISHlkcmEgQ0ExGTAXBgNVBAMTEEh5ZHJhIENBIFJvb3QgQ0EwHhcN +MjYwMTIzMDEzMDExWhcNMzYwMTIxMDEzMDExWjAuMREwDwYDVQQKEwhIeWRyYSBD +QTEZMBcGA1UEAxMQSHlkcmEgQ0EgUm9vdCBDQTBZMBMGByqGSM49AgEGCCqGSM49 +AwEHA0IABIR4VHh4dTyuf0Uyi1WHdjD7OAppJAbCVZ5yyxycLYa72FDOAILFQW4l +veu2lHJ2SbpXoYiojwbRt3iDdNVbA7ijRTBDMA4GA1UdDwEB/wQEAwIBBjASBgNV +HRMBAf8ECDAGAQH/AgEBMB0GA1UdDgQWBBQXrqLKUW1JM7vAL3AlmcDvMvqAMzAK +BggqhkjOPQQDAgNIADBFAiEA7OMwkoWP9UTvXz8FIo+m4sB52nw8nVfx7wwxIMwC +unECIHNHJkFPkbJoxDBz0FWc20oIQ9O8ykPclsqrNBv9wzOf +-----END CERTIFICATE----- diff --git a/templates/extract.sh.nix b/templates/extract.sh.nix new file mode 100644 index 0000000..ae4118a --- /dev/null +++ b/templates/extract.sh.nix @@ -0,0 +1,79 @@ +{ pkgs }: + +pkgs.writeShellScriptBin "extract" '' + set -euo pipefail + + RED='\033[0;31m' + GREEN='\033[0;32m' + YELLOW='\033[0;33m' + NC='\033[0m' + + log_info() { echo -e "''${GREEN}[INFO]''${NC} $1"; } + log_warn() { echo -e "''${YELLOW}[WARN]''${NC} $1"; } + log_error() { echo -e "''${RED}[ERROR]''${NC} $1"; } + + usage() { + echo "Usage: $0 [archive2] ..." + echo "Extracts zip and 7z files into folders named after the archive." + exit 1 + } + + extract_file() { + local archive="$1" + local archive_name + local output_dir + local extension + + if [[ ! -f "$archive" ]]; then + log_error "File not found: $archive" + return 1 + fi + + archive_name=$(${pkgs.coreutils}/bin/basename "$archive") + extension="''${archive_name##*.}" + extension="''${extension,,}" + + if [[ "$extension" != "zip" && "$extension" != "7z" ]]; then + log_error "Unsupported file type: $archive (only .zip and .7z supported)" + return 1 + fi + + output_dir="''${archive%.*}" + ${pkgs.coreutils}/bin/mkdir -p "$output_dir" + + log_info "Extracting: $archive -> $output_dir/" + + if ${pkgs.p7zip}/bin/7z x "$archive" -o"$output_dir" -y >/dev/null 2>&1; then + log_info "Successfully extracted with 7zip: $archive" + return 0 + fi + + log_warn "7zip failed for: $archive" + + if [[ "$extension" == "zip" ]]; then + if ${pkgs.unzip}/bin/unzip -o "$archive" -d "$output_dir" >/dev/null 2>&1; then + log_info "Successfully extracted with unzip: $archive" + return 0 + fi + log_error "unzip also failed for: $archive" + return 1 + fi + + log_error "Failed to extract: $archive" + return 1 + } + + if [[ $# -eq 0 ]]; then + usage + fi + + exit_code=0 + + for archive in "$@"; do + if ! extract_file "$archive"; then + exit_code=1 + fi + done + + exit $exit_code +'' diff --git a/templates/google-chrome.desktop b/templates/google-chrome.desktop new file mode 100644 index 0000000..ea60409 --- /dev/null +++ b/templates/google-chrome.desktop @@ -0,0 +1,221 @@ +[Desktop Entry] +Version=1.0 +Name=Google Chrome +# Only KDE 4 seems to use GenericName, so we reuse the KDE strings. +# From Ubuntu's language-pack-kde-XX-base packages, version 9.04-20090413. +GenericName=Web Browser +GenericName[ar]=متصفح الشبكة +GenericName[bg]=Уеб браузър +GenericName[ca]=Navegador web +GenericName[cs]=WWW prohlížeč +GenericName[da]=Browser +GenericName[de]=Web-Browser +GenericName[el]=Περιηγητής ιστού +GenericName[en_GB]=Web Browser +GenericName[es]=Navegador web +GenericName[et]=Veebibrauser +GenericName[fi]=WWW-selain +GenericName[fr]=Navigateur Web +GenericName[gu]=વેબ બ્રાઉઝર +GenericName[he]=דפדפן אינטרנט +GenericName[hi]=वेब ब्राउज़र +GenericName[hu]=Webböngésző +GenericName[it]=Browser Web +GenericName[ja]=ウェブブラウザ +GenericName[kn]=ಜಾಲ ವೀಕ್ಷಕ +GenericName[ko]=웹 브라우저 +GenericName[lt]=Žiniatinklio naršyklė +GenericName[lv]=Tīmekļa pārlūks +GenericName[ml]=വെബ് ബ്രൌസര്‍ +GenericName[mr]=वेब ब्राऊजर +GenericName[nb]=Nettleser +GenericName[nl]=Webbrowser +GenericName[pl]=Przeglądarka WWW +GenericName[pt]=Navegador Web +GenericName[pt_BR]=Navegador da Internet +GenericName[ro]=Navigator de Internet +GenericName[ru]=Веб-браузер +GenericName[sl]=Spletni brskalnik +GenericName[sv]=Webbläsare +GenericName[ta]=இணைய உலாவி +GenericName[th]=เว็บเบราว์เซอร์ +GenericName[tr]=Web Tarayıcı +GenericName[uk]=Навігатор Тенет +GenericName[zh_CN]=网页浏览器 +GenericName[zh_HK]=網頁瀏覽器 +GenericName[zh_TW]=網頁瀏覽器 +# Not translated in KDE, from Epiphany 2.26.1-0ubuntu1. +GenericName[bn]=ওয়েব ব্রাউজার +GenericName[fil]=Web Browser +GenericName[hr]=Web preglednik +GenericName[id]=Browser Web +GenericName[or]=ଓ୍ବେବ ବ୍ରାଉଜର +GenericName[sk]=WWW prehliadač +GenericName[sr]=Интернет прегледник +GenericName[te]=మహాతల అన్వేషి +GenericName[vi]=Bộ duyệt Web +# Gnome and KDE 3 uses Comment. +Comment=Access the Internet +Comment[ar]=الدخول إلى الإنترنت +Comment[bg]=Достъп до интернет +Comment[bn]=ইন্টারনেটটি অ্যাক্সেস করুন +Comment[ca]=Accedeix a Internet +Comment[cs]=Přístup k internetu +Comment[da]=Få adgang til internettet +Comment[de]=Internetzugriff +Comment[el]=Πρόσβαση στο Διαδίκτυο +Comment[en_GB]=Access the Internet +Comment[es]=Accede a Internet. +Comment[et]=Pääs Internetti +Comment[fi]=Käytä internetiä +Comment[fil]=I-access ang Internet +Comment[fr]=Accéder à Internet +Comment[gu]=ઇંટરનેટ ઍક્સેસ કરો +Comment[he]=גישה אל האינטרנט +Comment[hi]=इंटरनेट तक पहुंच स्थापित करें +Comment[hr]=Pristup Internetu +Comment[hu]=Internetelérés +Comment[id]=Akses Internet +Comment[it]=Accesso a Internet +Comment[ja]=インターネットにアクセス +Comment[kn]=ಇಂಟರ್ನೆಟ್ ಅನ್ನು ಪ್ರವೇಶಿಸಿ +Comment[ko]=인터넷 연결 +Comment[lt]=Interneto prieiga +Comment[lv]=Piekļūt internetam +Comment[ml]=ഇന്റര്‍‌നെറ്റ് ആക്‌സസ് ചെയ്യുക +Comment[mr]=इंटरनेटमध्ये प्रवेश करा +Comment[nb]=Gå til Internett +Comment[nl]=Verbinding maken met internet +Comment[or]=ଇଣ୍ଟର୍ନେଟ୍ ପ୍ରବେଶ କରନ୍ତୁ +Comment[pl]=Skorzystaj z internetu +Comment[pt]=Aceder à Internet +Comment[pt_BR]=Acessar a internet +Comment[ro]=Accesaţi Internetul +Comment[ru]=Доступ в Интернет +Comment[sk]=Prístup do siete Internet +Comment[sl]=Dostop do interneta +Comment[sr]=Приступите Интернету +Comment[sv]=Gå ut på Internet +Comment[ta]=இணையத்தை அணுகுதல் +Comment[te]=ఇంటర్నెట్‌ను ఆక్సెస్ చెయ్యండి +Comment[th]=เข้าถึงอินเทอร์เน็ต +Comment[tr]=İnternet'e erişin +Comment[uk]=Доступ до Інтернету +Comment[vi]=Truy cập Internet +Comment[zh_CN]=访问互联网 +Comment[zh_HK]=連線到網際網路 +Comment[zh_TW]=連線到網際網路 +Exec=@GOOGLE_CHROME_STABLE@ %U +StartupNotify=true +Terminal=false +Icon=google-chrome +Type=Application +Categories=Network;WebBrowser; +MimeType=application/pdf;application/rdf+xml;application/rss+xml;application/xhtml+xml;application/xhtml_xml;application/xml;image/gif;image/jpeg;image/png;image/webp;text/html;text/xml;x-scheme-handler/http;x-scheme-handler/https; +Actions=new-window;new-private-window; + +[Desktop Action new-window] +Name=New Window +Name[am]=አዲስ መስኮት +Name[ar]=نافذة جديدة +Name[bg]=Нов прозорец +Name[bn]=নতুন উইন্ডো +Name[ca]=Finestra nova +Name[cs]=Nové okno +Name[da]=Nyt vindue +Name[de]=Neues Fenster +Name[el]=Νέο Παράθυρο +Name[en_GB]=New Window +Name[es]=Nueva ventana +Name[et]=Uus aken +Name[fa]=پنجره جدید +Name[fi]=Uusi ikkuna +Name[fil]=New Window +Name[fr]=Nouvelle fenêtre +Name[gu]=નવી વિંડો +Name[hi]=नई विंडो +Name[hr]=Novi prozor +Name[hu]=Új ablak +Name[id]=Jendela Baru +Name[it]=Nuova finestra +Name[iw]=חלון חדש +Name[ja]=新規ウインドウ +Name[kn]=ಹೊಸ ವಿಂಡೊ +Name[ko]=새 창 +Name[lt]=Naujas langas +Name[lv]=Jauns logs +Name[ml]=പുതിയ വിന്‍ഡോ +Name[mr]=नवीन विंडो +Name[nl]=Nieuw venster +Name[no]=Nytt vindu +Name[pl]=Nowe okno +Name[pt]=Nova janela +Name[pt_BR]=Nova janela +Name[ro]=Fereastră nouă +Name[ru]=Новое окно +Name[sk]=Nové okno +Name[sl]=Novo okno +Name[sr]=Нови прозор +Name[sv]=Nytt fönster +Name[sw]=Dirisha Jipya +Name[ta]=புதிய சாளரம் +Name[te]=క్రొత్త విండో +Name[th]=หน้าต่างใหม่ +Name[tr]=Yeni Pencere +Name[uk]=Нове вікно +Name[vi]=Cửa sổ Mới +Name[zh_CN]=新建窗口 +Name[zh_TW]=開新視窗 +Exec=@GOOGLE_CHROME_STABLE@ + +[Desktop Action new-private-window] +Name=New Incognito Window +Name[ar]=نافذة جديدة للتصفح المتخفي +Name[bg]=Нов прозорец „инкогнито“ +Name[bn]=নতুন ছদ্মবেশী উইন্ডো +Name[ca]=Finestra d'incògnit nova +Name[cs]=Nové anonymní okno +Name[da]=Nyt inkognitovindue +Name[de]=Neues Inkognito-Fenster +Name[el]=Νέο παράθυρο για ανώνυμη περιήγηση +Name[en_GB]=New Incognito window +Name[es]=Nueva ventana de incógnito +Name[et]=Uus inkognito aken +Name[fa]=پنجره جدید حالت ناشناس +Name[fi]=Uusi incognito-ikkuna +Name[fil]=Bagong Incognito window +Name[fr]=Nouvelle fenêtre de navigation privée +Name[gu]=નવી છુપી વિંડો +Name[hi]=नई गुप्त विंडो +Name[hr]=Novi anoniman prozor +Name[hu]=Új Inkognitóablak +Name[id]=Jendela Penyamaran baru +Name[it]=Nuova finestra di navigazione in incognito +Name[iw]=חלון חדש לגלישה בסתר +Name[ja]=新しいシークレット ウィンドウ +Name[kn]=ಹೊಸ ಅಜ್ಞಾತ ವಿಂಡೋ +Name[ko]=새 시크릿 창 +Name[lt]=Naujas inkognito langas +Name[lv]=Jauns inkognito režīma logs +Name[ml]=പുതിയ വേഷ പ്രച്ഛന്ന വിന്‍ഡോ +Name[mr]=नवीन गुप्त विंडो +Name[nl]=Nieuw incognitovenster +Name[no]=Nytt inkognitovindu +Name[pl]=Nowe okno incognito +Name[pt]=Nova janela de navegação anónima +Name[pt_BR]=Nova janela anônima +Name[ro]=Fereastră nouă incognito +Name[ru]=Новое окно в режиме инкогнито +Name[sk]=Nové okno inkognito +Name[sl]=Novo okno brez beleženja zgodovine +Name[sr]=Нови прозор за прегледање без архивирања +Name[sv]=Nytt inkognitofönster +Name[ta]=புதிய மறைநிலைச் சாளரம் +Name[te]=క్రొత్త అజ్ఞాత విండో +Name[th]=หน้าต่างใหม่ที่ไม่ระบุตัวตน +Name[tr]=Yeni Gizli pencere +Name[uk]=Нове вікно в режимі анонімного перегляду +Name[vi]=Cửa sổ ẩn danh mới +Name[zh_CN]=新建隐身窗口 +Name[zh_TW]=新增無痕式視窗 +Exec=@GOOGLE_CHROME_STABLE@ --incognito diff --git a/users.nix b/users.nix new file mode 100644 index 0000000..4780839 --- /dev/null +++ b/users.nix @@ -0,0 +1,60 @@ +{ + config, + pkgs, + ... +}: +{ + imports = [ + ./home/user.nix + ./home/root.nix + ]; + sops.secrets."user/password" = { + neededForUsers = true; + sopsFile = ./secrets/home.yaml; + }; + sops.secrets."root/password" = { + neededForUsers = true; + sopsFile = ./secrets/home.yaml; + }; + users = { + mutableUsers = true; + + users = { + root = { + homeMode = "700"; + hashedPasswordFile = config.sops.secrets."root/password".path; + }; + microvm = { + uid = 999; + isSystemUser = true; + }; + # agent = { + # uid = 1001; + # homeMode = "770"; + # shell = pkgs.fish; + # isNormalUser = true; + # group = "agents"; + # extraGroups = [ "user" ]; + # }; + user = { + uid = 1000; + homeMode = "700"; + home = "/home/user"; + shell = pkgs.fish; + isNormalUser = true; + group = "user"; + extraGroups = [ + "libvirt" + "systemd-journal" + "kvm" + "agents" + ]; + hashedPasswordFile = config.sops.secrets."user/password".path; + }; + }; + groups = { + user.gid = 1000; + agents.gid = 777; + }; + }; +} diff --git a/vms/default.nix b/vms/default.nix new file mode 100644 index 0000000..2b47a76 --- /dev/null +++ b/vms/default.nix @@ -0,0 +1,571 @@ +{ + nixpkgs, + sops-nix, + impermanence, + home-manager, + ... +}: +{ + systemd.network.netdevs."20-microbr".netdevConfig = { + Kind = "bridge"; + Name = "microbr"; + }; + + systemd.network.networks."20-microbr" = { + matchConfig.Name = "microbr"; + addresses = [ { Address = "192.168.77.1/24"; } ]; + networkConfig = { + ConfigureWithoutCarrier = true; + }; + }; + + systemd.network.networks."21-microvm-tap" = { + matchConfig.Name = "vm-*"; + networkConfig.Bridge = "microbr"; + }; + + networking.nat = { + enable = true; + internalInterfaces = [ "microbr" ]; + externalInterface = "enp7e0"; + }; + networking.nftables = { + enable = true; + tables.nat = { + family = "ip"; + content = '' + chain postrouting { + type nat hook postrouting priority srcnat; + iifname "microbr" masquerade + } + ''; + }; + }; + + microvm.vms = { + "dealwise" = { + pkgs = import nixpkgs { + system = "x86_64-linux"; + config.allowUnfreePredicate = + pkg: + builtins.elem (nixpkgs.lib.getName pkg) [ + "claude-code" + ]; + }; + + config = + let + hostname = "ai-sandbox"; + mac = "02:00:00:00:00:06"; + in + { + config, + pkgs, + ... + }: + { + imports = [ + impermanence.nixosModules.impermanence + sops-nix.nixosModules.sops + home-manager.nixosModules.home-manager + ]; + sops = { + defaultSopsFile = ./secrets/secrets.yaml; + age.keyFile = "/.persist/root/.config/sops/age/keys.txt"; + secrets = { + "wg0/private_key" = { }; + }; + }; + boot.kernel.sysctl."kernel.unprivileged_userns_clone" = 1; + systemd.network = { + enable = true; + networks = { + "10-net" = { + matchConfig.MACAddress = mac; + linkConfig.RequiredForOnline = "routable"; + addresses = [ { Address = "192.168.77.2/24"; } ]; + routes = [ + { + Gateway = "192.168.77.1"; + Metric = 100; + } + { + Destination = "103.69.224.4/32"; + Gateway = "192.168.77.1"; + } + ]; + }; + }; + }; + + services.resolved.enable = false; + environment.etc."resolv.conf".text = '' + nameserver 10.2.0.1 + ''; + networking = { + hostName = hostname; + useNetworkd = true; + useDHCP = false; + firewall.enable = false; + wireguard.interfaces.wg0 = { + ips = [ "10.2.0.2/32" ]; + listenPort = 45974; + privateKeyFile = config.sops.secrets."wg0/private_key".path; + metric = 10; + peers = [ + { + publicKey = "D8Sqlj3TYwwnTkycV08HAlxcXXS3Ura4oamz8rB5ImM="; + endpoint = "103.69.224.4:51820"; + allowedIPs = [ + "0.0.0.0/0" + "::/0" + ]; + persistentKeepalive = 25; + } + ]; + }; + }; + + users.mutableUsers = false; + users.users.root = { + password = ""; + home = "/root"; + openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILABd/iSJ4gn/ystDqNxLJTG0n0z5VIC9YXlmdUfOhHf desktop@icefox.sh" + ]; + }; + users.users.user = { + linger = true; + home = "/home/user"; + password = ""; + group = "user"; + isNormalUser = true; + uid = 1000; + shell = pkgs.fish; + openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILABd/iSJ4gn/ystDqNxLJTG0n0z5VIC9YXlmdUfOhHf desktop@icefox.sh" + ]; + }; + users.groups.user.gid = 1000; + + home-manager = { + useGlobalPkgs = true; + useUserPackages = true; + users.user = { + home.username = "user"; + home.homeDirectory = "/home/user"; + home.stateVersion = "25.11"; + home.enableNixpkgsReleaseCheck = false; + xdg.configFile."containers/containers.conf".text = '' + [engine] + compose_warning_logs=false + events_logger="file" + + [containers] + log_driver="k8s-file" + ''; + xdg.configFile."opencode/opencode.json".text = builtins.toJSON { + "$schema" = "https://opencode.ai/config.json"; + plugin = [ "opencode-antigravity-auth@latest" ]; + provider = { + google = { + models = { + antigravity-gemini-3-pro = { + name = "Gemini 3 Pro (Antigravity)"; + limit = { + context = 1048576; + output = 65535; + }; + modalities = { + input = [ + "text" + "image" + "pdf" + ]; + output = [ "text" ]; + }; + variants = { + low = { + thinkingLevel = "low"; + }; + high = { + thinkingLevel = "high"; + }; + }; + }; + antigravity-gemini-3-flash = { + name = "Gemini 3 Flash (Antigravity)"; + limit = { + context = 1048576; + output = 65536; + }; + modalities = { + input = [ + "text" + "image" + "pdf" + ]; + output = [ "text" ]; + }; + variants = { + minimal = { + thinkingLevel = "minimal"; + }; + low = { + thinkingLevel = "low"; + }; + medium = { + thinkingLevel = "medium"; + }; + high = { + thinkingLevel = "high"; + }; + }; + }; + antigravity-claude-sonnet-4-5 = { + name = "Claude Sonnet 4.5 (Antigravity)"; + limit = { + context = 200000; + output = 64000; + }; + modalities = { + input = [ + "text" + "image" + "pdf" + ]; + output = [ "text" ]; + }; + }; + antigravity-claude-sonnet-4-5-thinking = { + name = "Claude Sonnet 4.5 Thinking (Antigravity)"; + limit = { + context = 200000; + output = 64000; + }; + modalities = { + input = [ + "text" + "image" + "pdf" + ]; + output = [ "text" ]; + }; + variants = { + low = { + thinkingConfig = { + thinkingBudget = 8192; + }; + }; + max = { + thinkingConfig = { + thinkingBudget = 32768; + }; + }; + }; + }; + antigravity-claude-opus-4-5-thinking = { + name = "Claude Opus 4.5 Thinking (Antigravity)"; + limit = { + context = 200000; + output = 64000; + }; + modalities = { + input = [ + "text" + "image" + "pdf" + ]; + output = [ "text" ]; + }; + variants = { + low = { + thinkingConfig = { + thinkingBudget = 8192; + }; + }; + max = { + thinkingConfig = { + thinkingBudget = 32768; + }; + }; + }; + }; + antigravity-claude-opus-4-6-thinking = { + name = "Claude Opus 4.6 Thinking (Antigravity)"; + limit = { + context = 200000; + output = 64000; + }; + modalities = { + input = [ + "text" + "image" + "pdf" + ]; + output = [ "text" ]; + }; + variants = { + low = { + thinkingConfig = { + thinkingBudget = 8192; + }; + }; + max = { + thinkingConfig = { + thinkingBudget = 32768; + }; + }; + }; + }; + "gemini-2.5-flash" = { + name = "Gemini 2.5 Flash (Gemini CLI)"; + limit = { + context = 1048576; + output = 65536; + }; + modalities = { + input = [ + "text" + "image" + "pdf" + ]; + output = [ "text" ]; + }; + }; + "gemini-2.5-pro" = { + name = "Gemini 2.5 Pro (Gemini CLI)"; + limit = { + context = 1048576; + output = 65536; + }; + modalities = { + input = [ + "text" + "image" + "pdf" + ]; + output = [ "text" ]; + }; + }; + gemini-3-flash-preview = { + name = "Gemini 3 Flash Preview (Gemini CLI)"; + limit = { + context = 1048576; + output = 65536; + }; + modalities = { + input = [ + "text" + "image" + "pdf" + ]; + output = [ "text" ]; + }; + }; + gemini-3-pro-preview = { + name = "Gemini 3 Pro Preview (Gemini CLI)"; + limit = { + context = 1048576; + output = 65535; + }; + modalities = { + input = [ + "text" + "image" + "pdf" + ]; + output = [ "text" ]; + }; + }; + }; + }; + }; + }; + }; + }; + + fileSystems = { + "/.persist".neededForBoot = true; + }; + environment.systemPackages = with pkgs; [ + coreutils + jq + git + fzf + claude-code + neovim + ripgrep + fd + podman-compose + opencode + + php + php.packages.composer + pkgs.nodejs_24 + pkgs.dotnet-sdk_9 + pkgs.go_1_24 + ]; + + programs = { + fish.enable = true; + starship.enable = true; + ssh = { + knownHosts = { + "github.com".publicKey = + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl"; + }; + }; + }; + + systemd.tmpfiles.rules = [ + "d /var/log/laravel 0755 1000 1000" + ]; + + environment.persistence."/.persist" = { + enable = true; + hideMounts = true; + directories = [ + "/var/lib/nixos" + ]; + files = [ + "/etc/ssh/ssh_host_ed25519_key" + "/etc/ssh/ssh_host_ed25519_key.pub" + "/etc/ssh/ssh_host_rsa_key" + "/etc/ssh/ssh_host_rsa_key.pub" + ]; + users.root = { + files = [ + ".config/sops/age/keys.txt" + ]; + }; + users.user = { + files = [ + ".claude.json" + ".claude.json.backup" + ]; + directories = [ + ".claude" + ".local/share/containers" + ".local/share/opencode" + ]; + }; + }; + + services = { + openssh = { + enable = true; + ports = [ 22 ]; + settings = { + PasswordAuthentication = false; + KbdInteractiveAuthentication = false; + PermitRootLogin = "yes"; + AllowUsers = [ + "user" + "root" + ]; + }; + }; + getty = { + autologinUser = "root"; + autologinOnce = true; + }; + }; + + virtualisation = { + containers.enable = true; + podman = { + enable = true; + defaultNetwork.settings.dns_enabled = true; + dockerCompat = true; + }; + }; + + environment.sessionVariables = { + EDITOR = "nvim"; + }; + + microvm = { + hypervisor = "qemu"; + + vcpu = 4; + mem = 8192; + socket = "control.sock"; + + interfaces = [ + { + id = "vm-${hostname}"; + type = "tap"; + mac = mac; + } + ]; + + volumes = [ + { + mountPoint = "/.persist"; + image = "persist.img"; + size = 1024 * 128; + } + { + mountPoint = "/nix/.rw-store"; + image = "nix-store.img"; + size = 1024 * 128; + } + ]; + + writableStoreOverlay = "/nix/.rw-store"; + shares = [ + { + proto = "virtiofs"; + tag = "downloads"; + source = "/home/user/downloads"; + mountPoint = "/home/user/downloads"; + } + { + proto = "virtiofs"; + tag = "pictures"; + source = "/home/user/pictures"; + mountPoint = "/home/user/pictures"; + } + { + proto = "virtiofs"; + tag = "dealwise"; + source = "/home/user/work/dealwise"; + mountPoint = "/home/user/work/dealwise"; + } + { + proto = "virtiofs"; + tag = "php-data-transfer-object"; + source = "/home/user/dev/icefox/php/data-transfer-object"; + mountPoint = "/home/user/dev/icefox/php/data-transfer-object"; + } + { + proto = "virtiofs"; + tag = "uni"; + source = "/home/user/uni"; + mountPoint = "/home/user/uni"; + } + { + proto = "virtiofs"; + tag = "dev"; + source = "/home/user/dev"; + mountPoint = "/home/user/dev"; + } + { + proto = "virtiofs"; + tag = "ro-store"; + source = "/nix/store"; + mountPoint = "/nix/.ro-store"; + } + ]; + + qemu.extraArgs = [ + "-cpu" + "host" + ]; + }; + system.stateVersion = "25.11"; + }; + }; + }; +} diff --git a/vms/secrets/secrets.yaml b/vms/secrets/secrets.yaml new file mode 100644 index 0000000..74be351 --- /dev/null +++ b/vms/secrets/secrets.yaml @@ -0,0 +1,32 @@ +ssh: + private_key: ENC[AES256_GCM,data:0EDM0MEirn14hmU3UV0yFcB6kG8zjYyt+sbIb6v2vr3sqaK0EmBf4VxX1TRxjlT3nDk7NZG60+Lw6+c45COhZX0ApYkElUxPtKXsLM4HZKruJiL3cLicdFDsL7/53tMyp6waFVejq5dbog/kya+dbUujM8p2ILqO9GjB2k0truipq6ThpinytRqu5xccjJzUbEqCrr1U2lKTIm6s83zAJfcrnwEipIoV2WqxjPpeGjGBKwfi4284O1J5zZHvbxB+CQ+4rHrkcsio4CEDLdV6s93d5FHARGt/Ni/ZXfcP2Yve5M4PrakliHVv7dVNrGqX6tDXZkhVlhzCHk0vY9dSTONuvlmeoFtSWpJXG8MfaGzmfkT+/F39U1TpbRyIPL4OyeidvBV4hTJuKmCOSraXnFwz5l3EnZhBbrCBRw8XFTZGS8v8jMcC7QTFYxCDL4GcrSJac9cgDlggygr3Vv8627a+zYSwauuNWPYEf1Nr56owZdJUc6LJpOBd+QR2fiV+coA/cNbNhWOaRS3K/NRS,iv:1lU+UUhH4m5OjyDO5s/sNGGGoT/7NxI5Cs1GL5CEIGU=,tag:EG8YZERDyeG/XkCNO7f/cQ==,type:str] +wg0: + private_key: ENC[AES256_GCM,data:nr7y3wp7EtVW6uI6MBSwyMO9YuMyx/F0AZmD8GmuA3BPQTVTsVSctoKIxLE=,iv:KN68DwGuDo+aPP4mBk1MqY+lxFjisKSwXn0w+yngDRQ=,tag:gpjxIFWaZE+5hbYHVsO1ZQ==,type:str] + address: ENC[AES256_GCM,data:9Tnph2SHKeEt9Ss=,iv:CPR1N7fqqlaThGltSpfqeAOc5bAe13KWskGWj3jI8LQ=,tag:xha/hQOVqfUoGyfKbHhnuQ==,type:str] + conf: ENC[AES256_GCM,data:SRDnI+2PvK7Zz1L5XBvrBNejgJEg8DK+qVO5XEtx6Nal+f7IeB3Ascp8Bkit5fd5myn/RxiK80wYmvLkDmcJAk46UjHKOpbxJl1s5FmKDuZJ3c3MXLwH7k2PeZP14VDDlyQqlcyGBrSu74L64ZMh/6EWGKbONTD1Wt3Ykg+/RegzQFDr2CPbj6XQeXsNS2p0ugicP5ffBMTUa9KSYDMQVV80mjSZ246aeY0owU1VUsitdvsCbfxtFd5gr/9zdfOXOvGY/BKxAlvVbszCalNs9DgJDHt/,iv:FP90SvUGnsZJS7F/uxtbOqTvGOgtC4+r2+YgF5FBoQY=,tag:9G1tkXHTpbytmG9T6sTpMw==,type:str] +wg-br0: + private_key: ENC[AES256_GCM,data:AwGwtS6Bkx5SUwxfaz/UaogGQIwqJidHzyOC0EWCA1UzEo1XV+bFKpdvOjg=,iv:O5RTjtNHC3lY+uVb6JBTwCrxpDSOsVAy8VOvsSatr0M=,tag:HelKY1PtxI3Zi+9Alrw+Ow==,type:str] +sops: + age: + - recipient: age1y0tj3kt67pfnj38t9c8g2ghry3a0mhcq8rrqv5xr4jekwepxaelqzu3dkf + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBtOHZSRkpBVVdUUk9OYUFH + cVBra014WXJyRTJ0QWFKallLQlc0SXhNSlFBCmpwME92M2lCN2liVjZBRndlSVBk + OEpUU1YyakdCa0xVaHdhRlpXbGxYdUEKLS0tIDFlV1k0Qkx1UDd2NUVHTTI3NDZE + OWhIdUxDcHB4Z3dTdDkyZWF6NEJCYzAKfPB9AZFQ08yqil+4AhIi6EMy8PXI4CAz + lK4ON/M67T0UrlWN/m3pryOOr4Lj4oiZvdOR0BCO3kn4Pj0nq5jQOA== + -----END AGE ENCRYPTED FILE----- + - recipient: age16v8w7q4wmn22hhakq2uzaus2508rhldm7lcwh0kukshzjzyhuqesqz44ze + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBMSC9Td1NTMzk2NlJDTDNM + UVUzTSt1dGkrUVRGT1UzeXcwR1REN1U0dW5JCnNJRzdKZHVyR0dzaUw2TlVzQnQ2 + SHhSSGlDWUNBSXZiME5GM0JPTFRseDQKLS0tIEFnOXgzWFo2Rmo2THN4VFFIY1h0 + OEZ4WUp1QlVrTkVTN1BHMG0yaXFuSk0KLw3ZuvWTurJDTpyoq5YafLm8YFT4v4Vh + s+ay8ju3kA1CKjMF3gBQF08EoCdP/jU6tZerNwwcs17el5zIvRmG7Q== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2026-02-06T22:06:59Z" + mac: ENC[AES256_GCM,data:IJXeoVdP8/R51hHNTkpYSj9f1bGRBh5PtlEdbcXuD12DFGZtEFcAeBgfKHSnYBRxZMedd/IxhsQYNatW8T/spAuPi0dEh2mnn9yz3evGjkc1WKGOy24Ou3xhZBboo9tzYfkX3PVGd10kx+vTJh3by7Eq4LjAfyq1vyGj1g3S5nU=,iv:wQsntFE/TO0Z5An9U7yYUIQ/nXbo5nnUQ9ukVMm0KRo=,tag:D9HpVrYEbzaCktzGmD0xvg==,type:str] + unencrypted_suffix: _unencrypted + version: 3.11.0 diff --git a/wireguard.nix b/wireguard.nix new file mode 100644 index 0000000..b980898 --- /dev/null +++ b/wireguard.nix @@ -0,0 +1,166 @@ +{ + config, + lib, + pkgs, + ... +}: + +with lib; + +let + cfg = config.services.wireguard-netns; + + vpnOptions = + { name, ... }: + { + options = { + name = mkOption { + type = types.str; + default = name; + description = "Name of the network namespace and WireGuard interface"; + }; + + dns = mkOption { + type = types.str; + description = "Network DNS"; + example = "1.1.1.1"; + }; + + address = mkOption { + type = types.str; + description = "Address"; + example = "10.2.0.1/32"; + }; + + conf = mkOption { + type = types.str; + description = "Path to sops secret containing WireGuard configuration"; + example = "wg0/conf"; + }; + }; + }; + +in +{ + options.services.wireguard-netns = { + enable = mkEnableOption "WireGuard network namespaces"; + + namespaces = mkOption { + type = types.attrsOf (types.submodule vpnOptions); + default = { }; + description = "WireGuard VPN configurations in separate network namespaces"; + example = literalExpression '' + { + wg0ns = { + dns = "10.2.0.1"; + address = "10.2.0.2/32"; + conf = "wg0/conf"; + }; + wg1ns = { + dns = "10.3.0.1"; + address = "10.3.0.2/32"; + conf = "wg1/conf"; + }; + } + ''; + }; + }; + + config = mkIf cfg.enable { + systemd.services = listToAttrs ( + flatten ( + imap1 ( + index: elem: + let + name = elem.name; + vpnCfg = elem.value; + ns = "${name}ns"; + nsIP = "10.200.${toString index}.2/24"; + hostIP = "10.200.${toString index}.1/24"; + vethHost = "veth-${name}"; + vethNS = "veth-${name}-ns"; + proxyIP = "10.200.${toString index}.2"; # IP without CIDR for binding + proxyPort = 1080; + in + [ + { + name = "netns@${ns}"; + value = { + description = "${ns} network namespace"; + before = [ "network.target" ]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + ExecStart = pkgs.writers.writeBash "${ns}-up" '' + ${pkgs.coreutils}/bin/mkdir -p /etc/netns/${ns} + echo "nameserver ${vpnCfg.dns}" > /etc/netns/${ns}/resolv.conf + ${pkgs.iproute2}/bin/ip netns add ${ns} + + ${pkgs.iproute2}/bin/ip link add ${vethHost} type veth peer name ${vethNS} + ${pkgs.iproute2}/bin/ip link set ${vethNS} netns ${ns} + + ${pkgs.iproute2}/bin/ip addr add ${hostIP} dev ${vethHost} + ${pkgs.iproute2}/bin/ip link set ${vethHost} up + + ${pkgs.iproute2}/bin/ip -n ${ns} addr add ${nsIP} dev ${vethNS} + ${pkgs.iproute2}/bin/ip -n ${ns} link set ${vethNS} up + ''; + ExecStop = pkgs.writers.writeBash "${ns}-down" '' + ${pkgs.iproute2}/bin/ip link del ${vethHost} || true + ${pkgs.iproute2}/bin/ip netns del ${ns} + ''; + }; + }; + } + + { + name = name; + value = { + description = "${name} network interface"; + bindsTo = [ "netns@${ns}.service" ]; + requires = [ "network-online.target" ]; + after = [ "netns@${ns}.service" ]; + wants = [ "network-online.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + ExecStart = pkgs.writers.writeBash "${name}-up" '' + ${pkgs.iproute2}/bin/ip link add ${name} type wireguard + ${pkgs.iproute2}/bin/ip link set ${name} netns ${ns} + ${pkgs.iproute2}/bin/ip -n ${ns} address add ${vpnCfg.address} dev ${name} + ${pkgs.iproute2}/bin/ip netns exec ${ns} \ + ${pkgs.wireguard-tools}/bin/wg setconf ${name} ${config.sops.secrets.${vpnCfg.conf}.path} + ${pkgs.iproute2}/bin/ip -n ${ns} link set lo up + ${pkgs.iproute2}/bin/ip -n ${ns} link set ${name} up + ${pkgs.iproute2}/bin/ip -n ${ns} route add default dev ${name} + ''; + ExecStop = pkgs.writers.writeBash "${name}-down" '' + ${pkgs.iproute2}/bin/ip -n ${ns} route del default dev ${name} || true + ${pkgs.iproute2}/bin/ip -n ${ns} link del ${name} || true + ''; + }; + }; + } + + { + name = "socks-${name}"; + value = { + description = "SOCKS5 proxy for ${name} namespace"; + after = [ "${name}.service" ]; + requires = [ "${name}.service" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "simple"; + Restart = "always"; + RestartSec = "5s"; + ExecStart = "${pkgs.iproute2}/bin/ip netns exec ${ns} ${pkgs.microsocks}/bin/microsocks -i ${proxyIP} -p ${toString proxyPort}"; + }; + }; + } + ] + ) (lib.attrsToList cfg.namespaces) + ) + ); + }; +}