mirror of
https://github.com/Nexoniarz/nexoniarz-config-nixos-laptop.git
synced 2026-11-03 04:24:27 +00:00
Switch desktop environment from Hyprland to Pantheon
Configures Pantheon (LightDM + gala) for daily use on this ASUS TUF Gaming A15 (FA507NU), and drops everything that only existed to serve the previous Hyprland/Quickshell setup: - desktop.nix: services.desktopManager.pantheon instead of programs.hyprland + greetd; comfy laptop touchpad defaults. - drivers.nix: NVIDIA PRIME render offload between the AMD Radeon 680M (drives the panel) and the RTX 4050 Max-Q (offload-only), using this machine's real PCI bus IDs; asusd/supergfxd for ASUS-specific laptop control. - apps.nix / scripts.nix: removed Hyprland/Quickshell-only packages and scripts (kitty, rofi, quickshell, mako, hyprlock, hyprpaper/mpvpaper, the Quickshell theme-picker scripts, cursor/wallpaper/display helpers) — Pantheon ships its own Files/Terminal/Screenshot/ notifications/theming natively. Kept the DE-agnostic scripts (vault toggle, metadata stripping, brightness control, Wi-Fi hotspot, telemetry, weather). - theme.nix and default-apps.nix deleted entirely — Pantheon owns GTK/icon theming itself, no more live dconf/CSS generation pipeline needed. - Deleted hyprland/ and dotfiles/ (kitty, mako, quickshell, rofi). Verified with `nixos-rebuild build`. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RpiovBQL6k5MTDMN3Ln9nL
This commit is contained in:
commit
6bcd5e15ad
15 changed files with 766 additions and 0 deletions
37
README.md
Normal file
37
README.md
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
# nexoniarz-config-nixos-laptop
|
||||||
|
|
||||||
|
My personal NixOS system configuration tailored for daily use on an
|
||||||
|
**ASUS TUF Gaming A15 (FA507NU)**.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
- **OS:** NixOS
|
||||||
|
- **DE / Compositor:** Pantheon (gala, Wayland)
|
||||||
|
- **Display manager:** LightDM (elementary greeter)
|
||||||
|
- **Shell:** Zsh
|
||||||
|
- **CPU:** AMD Ryzen 5 7535HS
|
||||||
|
- **GPU:** AMD Radeon 680M (iGPU, drives the internal panel) + NVIDIA RTX
|
||||||
|
4050 Max-Q (dGPU, PRIME render offload only — run anything through it with
|
||||||
|
`nvidia-offload <command>`)
|
||||||
|
- **Laptop control:** `asusctl` (fan curves, keyboard backlight, battery
|
||||||
|
charge limit) + `supergfxctl` (dGPU power-state switching)
|
||||||
|
|
||||||
|
## Layout
|
||||||
|
|
||||||
|
- `configuration.nix` — top-level imports
|
||||||
|
- `hardware-configuration.nix` — generated by `nixos-generate-config`, don't
|
||||||
|
hand-edit
|
||||||
|
- `modules/system.nix` — bootloader, networking, time, sound, hardening,
|
||||||
|
nix-ld
|
||||||
|
- `modules/drivers.nix` — hybrid graphics (NVIDIA PRIME offload), ASUS
|
||||||
|
daemons, misc hardware (webcam loopback, tablet driver)
|
||||||
|
- `modules/desktop.nix` — Pantheon desktop environment
|
||||||
|
- `modules/users.nix` — user account, Steam, Firefox, Flatpak
|
||||||
|
- `modules/apps.nix` — all installed packages
|
||||||
|
- `modules/scripts.nix` + `modules/scripts/` — small custom CLI helpers
|
||||||
|
(encrypted vault toggle, metadata stripping, brightness control, Wi-Fi
|
||||||
|
hotspot, system telemetry, weather fetch)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Made by **Nexoniarz***
|
||||||
18
configuration.nix
Normal file
18
configuration.nix
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Main NixOS configuration file importing modular configurations.
|
||||||
|
|
||||||
|
{ config, pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./hardware-configuration.nix # Generated hardware scan results
|
||||||
|
./modules/system.nix # Bootloader, networking, time, sound, hardening, nix-ld
|
||||||
|
./modules/drivers.nix # AMD/NVIDIA hybrid graphics (PRIME) and ASUS laptop control
|
||||||
|
./modules/desktop.nix # Pantheon desktop environment (LightDM + gala)
|
||||||
|
./modules/users.nix # User accounts and global configurations
|
||||||
|
./modules/apps.nix # All installed packages: apps, CLI tools, dev toolchains
|
||||||
|
./modules/scripts.nix # Custom system scripts and helpers
|
||||||
|
];
|
||||||
|
|
||||||
|
# Do not change this value. Read documentation before updating.
|
||||||
|
system.stateVersion = "26.05";
|
||||||
|
}
|
||||||
45
hardware-configuration.nix
Normal file
45
hardware-configuration.nix
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
# Do not modify this file! It was generated by ‘nixos-generate-config’
|
||||||
|
# and may be overwritten by future invocations. Please make changes
|
||||||
|
# to /etc/nixos/configuration.nix instead.
|
||||||
|
{ config, lib, pkgs, modulesPath, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
imports =
|
||||||
|
[ (modulesPath + "/installer/scan/not-detected.nix")
|
||||||
|
];
|
||||||
|
|
||||||
|
boot.initrd.availableKernelModules = [ "nvme" "xhci_pci" "thunderbolt" "usb_storage" "sd_mod" ];
|
||||||
|
boot.initrd.kernelModules = [ ];
|
||||||
|
boot.kernelModules = [ "kvm-amd" ];
|
||||||
|
boot.extraModulePackages = [ ];
|
||||||
|
|
||||||
|
fileSystems."/" =
|
||||||
|
{ device = "/dev/disk/by-uuid/2e0afef3-e81a-45c1-a439-c17123eef182";
|
||||||
|
fsType = "btrfs";
|
||||||
|
};
|
||||||
|
|
||||||
|
fileSystems."/home" =
|
||||||
|
{ device = "/dev/disk/by-uuid/2e0afef3-e81a-45c1-a439-c17123eef182";
|
||||||
|
fsType = "btrfs";
|
||||||
|
options = [ "subvol=home" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
fileSystems."/nix" =
|
||||||
|
{ device = "/dev/disk/by-uuid/2e0afef3-e81a-45c1-a439-c17123eef182";
|
||||||
|
fsType = "btrfs";
|
||||||
|
options = [ "subvol=nix" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
fileSystems."/boot" =
|
||||||
|
{ device = "/dev/disk/by-uuid/CA1D-BBF9";
|
||||||
|
fsType = "vfat";
|
||||||
|
options = [ "fmask=0077" "dmask=0077" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
swapDevices =
|
||||||
|
[ { device = "/dev/disk/by-uuid/f52f4ee6-889e-4c86-82bf-ba8396e07483"; }
|
||||||
|
];
|
||||||
|
|
||||||
|
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
|
||||||
|
hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
|
||||||
|
}
|
||||||
56
modules/apps.nix
Normal file
56
modules/apps.nix
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
{ config, pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
# Every installed package — GUI apps, CLI tools, and dev toolchains alike.
|
||||||
|
# If it's "install X", it goes here.
|
||||||
|
users.users."nexoniarz".packages = with pkgs; [
|
||||||
|
# Hardware control (Pantheon itself ships Files/Terminal/Screenshot/
|
||||||
|
# notifications/dock/launcher — see services.desktopManager.pantheon
|
||||||
|
# in modules/desktop.nix, nothing to list here for those)
|
||||||
|
brightnessctl # Backlight brightness (internal laptop panel)
|
||||||
|
ddcutil # DDC/CI brightness (external monitors)
|
||||||
|
lm_sensors # sensors-detect helps ddcutil find I2C buses; also feeds asusctl
|
||||||
|
networkmanager # nmcli, for the Wi-Fi hotspot script
|
||||||
|
|
||||||
|
# Apps
|
||||||
|
blender
|
||||||
|
gimp
|
||||||
|
inkscape
|
||||||
|
vesktop
|
||||||
|
tor-browser
|
||||||
|
ffmpeg-full
|
||||||
|
vlc
|
||||||
|
filezilla
|
||||||
|
chromium
|
||||||
|
|
||||||
|
# Games
|
||||||
|
prismlauncher
|
||||||
|
pkgs.osu-lazer-bin
|
||||||
|
|
||||||
|
# Dev: compilers, runtimes, languages
|
||||||
|
glibc
|
||||||
|
musl
|
||||||
|
cmake
|
||||||
|
gnumake # Provides the 'make' command
|
||||||
|
gcc
|
||||||
|
python3
|
||||||
|
openjdk25
|
||||||
|
claude-code # AI Developer Assistant
|
||||||
|
];
|
||||||
|
|
||||||
|
# Global command-line utilities available everywhere
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
git
|
||||||
|
gh # GitHub CLI — was only installed ad-hoc before (login didn't survive)
|
||||||
|
vim
|
||||||
|
fastfetch
|
||||||
|
gparted
|
||||||
|
firejail
|
||||||
|
gnupg
|
||||||
|
lmstudio
|
||||||
|
p7zip
|
||||||
|
unzip
|
||||||
|
unrar
|
||||||
|
libreoffice # GTK3 build — matches Pantheon's native GTK theming, unlike the Qt build
|
||||||
|
];
|
||||||
|
}
|
||||||
38
modules/desktop.nix
Normal file
38
modules/desktop.nix
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
{ config, pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
# --- Pantheon: elementary OS's desktop environment (gala compositor, Wayland) ---
|
||||||
|
# Pulls in its own session (pantheon-wayland), top panel (Wingpanel), dock,
|
||||||
|
# app launcher, Files, Terminal, Screenshot, Photos, notifications, and
|
||||||
|
# GTK/icon theming — no separate compositor config or dotfile symlinking
|
||||||
|
# needed, unlike the previous Hyprland setup.
|
||||||
|
services.xserver.enable = true;
|
||||||
|
services.xserver.displayManager.lightdm.enable = true;
|
||||||
|
services.desktopManager.pantheon.enable = true;
|
||||||
|
|
||||||
|
# Keyboard layout for LightDM/XWayland; Pantheon's own session picks this
|
||||||
|
# up too.
|
||||||
|
services.xserver.xkb = {
|
||||||
|
layout = "pl";
|
||||||
|
variant = "";
|
||||||
|
};
|
||||||
|
|
||||||
|
security.polkit.enable = true;
|
||||||
|
|
||||||
|
# Native Wayland backend for Electron/Chromium-based apps
|
||||||
|
environment.sessionVariables.NIXOS_OZONE_WL = "1";
|
||||||
|
|
||||||
|
# Comfortable trackpad defaults for a laptop — tap-to-click and natural
|
||||||
|
# scrolling aren't on by default, and gala reads touchpad settings from
|
||||||
|
# GSettings at runtime (not services.libinput, which is X11-only), so
|
||||||
|
# they're set here as a dconf default instead.
|
||||||
|
programs.dconf.profiles.user.databases = [
|
||||||
|
{
|
||||||
|
settings."org/gnome/desktop/peripherals/touchpad" = {
|
||||||
|
tap-to-click = true;
|
||||||
|
natural-scroll = true;
|
||||||
|
two-finger-scrolling-enabled = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
79
modules/drivers.nix
Normal file
79
modules/drivers.nix
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
# Enable graphics driver support and 32-bit acceleration (for Steam/gaming)
|
||||||
|
hardware.graphics = {
|
||||||
|
enable = true;
|
||||||
|
enable32Bit = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
#OpenTabletDriver
|
||||||
|
hardware.opentabletdriver.enable = true;
|
||||||
|
hardware.uinput.enable = true;
|
||||||
|
boot.kernelModules = [ "uinput" "v4l2loopback" ];
|
||||||
|
|
||||||
|
# Virtual webcam device so ffmpeg (fed by the GoPro's stream) can appear
|
||||||
|
# as a normal camera to apps like Discord. exclusive_caps=1 is required
|
||||||
|
# for Chromium/WebRTC-based apps to recognize it as a real capture device.
|
||||||
|
boot.extraModulePackages = [ config.boot.kernelPackages.v4l2loopback ];
|
||||||
|
boot.extraModprobeConfig = ''
|
||||||
|
options v4l2loopback devices=1 video_nr=10 card_label="GoPro Webcam" exclusive_caps=1
|
||||||
|
# PS4/PS5 controllers (e.g. DualSense) connect over Bluetooth then
|
||||||
|
# immediately disconnect — a well-known Linux Bluetooth stack issue
|
||||||
|
# where many adapters' Enhanced Retransmission Mode implementation is
|
||||||
|
# broken. Disabling ERTM is the standard, widely-documented fix.
|
||||||
|
options bluetooth disable_ertm=1
|
||||||
|
'';
|
||||||
|
|
||||||
|
# I2C bus, for DDC/CI monitor control (brightness) via ddcutil, when
|
||||||
|
# driving an external monitor over DisplayPort/HDMI. The internal panel
|
||||||
|
# uses the kernel backlight class instead (brightness-ctl picks whichever
|
||||||
|
# applies — see modules/scripts/brightness-ctl.sh).
|
||||||
|
hardware.i2c.enable = true;
|
||||||
|
|
||||||
|
# --- Hybrid graphics: AMD Radeon 680M (iGPU, drives the internal panel)
|
||||||
|
# + NVIDIA RTX 4050 Max-Q (dGPU, offload-only) — ASUS TUF Gaming A15
|
||||||
|
# FA507NU. Bus IDs come straight from `lspci` on this machine, not
|
||||||
|
# guessed: 01:00.0 (NVIDIA) -> PCI:1:0:0, 35:00.0 (AMD) -> PCI:53:0:0.
|
||||||
|
services.xserver.videoDrivers = [ "nvidia" ];
|
||||||
|
|
||||||
|
hardware.nvidia = {
|
||||||
|
# Required settings
|
||||||
|
modesetting.enable = true;
|
||||||
|
|
||||||
|
# Enable NVIDIA Open GPU Kernel Modules (Turing architecture or newer —
|
||||||
|
# this RTX 4050 is Ada Lovelace, well within support)
|
||||||
|
open = true;
|
||||||
|
|
||||||
|
# Enable the NVIDIA settings menu
|
||||||
|
nvidiaSettings = true;
|
||||||
|
|
||||||
|
# Use the stable driver package matching current kernel
|
||||||
|
package = config.boot.kernelPackages.nvidiaPackages.stable;
|
||||||
|
|
||||||
|
# Fixes suspend/resume hangs that are common with NVIDIA on laptops.
|
||||||
|
powerManagement.enable = true;
|
||||||
|
|
||||||
|
# PRIME render offload: the AMD iGPU drives the display at all times
|
||||||
|
# (much better battery life than keeping the dGPU powered on), and the
|
||||||
|
# NVIDIA GPU is only spun up on demand for a specific process — run
|
||||||
|
# anything with `nvidia-offload <command>` (generated by
|
||||||
|
# enableOffloadCmd) to route it through the RTX 4050, e.g. games or
|
||||||
|
# Blender's Cycles renderer.
|
||||||
|
prime = {
|
||||||
|
offload = {
|
||||||
|
enable = true;
|
||||||
|
enableOffloadCmd = true;
|
||||||
|
};
|
||||||
|
amdgpuBusId = "PCI:53:0:0";
|
||||||
|
nvidiaBusId = "PCI:1:0:0";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# ASUS laptop control: keyboard backlight/fan curves/battery charge limit
|
||||||
|
# (asusctl) and dGPU power-state switching between Integrated/Hybrid modes
|
||||||
|
# (supergfxctl) — the two standard asus-linux.org daemons for ROG/TUF
|
||||||
|
# laptops, both packaged directly in nixpkgs.
|
||||||
|
services.asusd.enable = true;
|
||||||
|
services.supergfxd.enable = true;
|
||||||
|
}
|
||||||
25
modules/scripts.nix
Normal file
25
modules/scripts.nix
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
{ config, pkgs, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
# Wrap external shell scripts into system executables
|
||||||
|
vaultToggle = pkgs.writeShellScriptBin "vault-toggle" (builtins.readFile ./scripts/vault-toggle.sh);
|
||||||
|
stripMetadata = pkgs.writeShellScriptBin "strip-metadata" (builtins.readFile ./scripts/strip-metadata.sh);
|
||||||
|
brightnessCtl = pkgs.writeShellScriptBin "brightness-ctl" (builtins.readFile ./scripts/brightness-ctl.sh);
|
||||||
|
hotspotStart = pkgs.writeShellScriptBin "hotspot-start" (builtins.readFile ./scripts/hotspot-start.sh);
|
||||||
|
systemTelemetry = pkgs.writeShellScriptBin "system-telemetry" (builtins.readFile ./scripts/system-telemetry.sh);
|
||||||
|
weatherFetch = pkgs.writeShellScriptBin "weather-fetch" (builtins.readFile ./scripts/weather-fetch.sh);
|
||||||
|
in
|
||||||
|
{
|
||||||
|
# Install CLI dependencies required by the scripts
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
gocryptfs
|
||||||
|
exiftool
|
||||||
|
jq
|
||||||
|
vaultToggle
|
||||||
|
stripMetadata
|
||||||
|
brightnessCtl
|
||||||
|
hotspotStart
|
||||||
|
systemTelemetry
|
||||||
|
weatherFetch
|
||||||
|
];
|
||||||
|
}
|
||||||
56
modules/scripts/brightness-ctl.sh
Executable file
56
modules/scripts/brightness-ctl.sh
Executable file
|
|
@ -0,0 +1,56 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# Brightness control abstraction: prefers the kernel backlight class (laptop
|
||||||
|
# panels, via brightnessctl); falls back to DDC/CI over I2C (external
|
||||||
|
# monitors, via ddcutil) when no backlight device exists. Keeps the rest of
|
||||||
|
# the config (Quickshell's brightness popup) hardware-agnostic.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
has_backlight() {
|
||||||
|
[ -n "$(ls -A /sys/class/backlight 2>/dev/null)" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
case "${1:-get}" in
|
||||||
|
get)
|
||||||
|
if has_backlight; then
|
||||||
|
brightnessctl -m | cut -d, -f4 | tr -d '%'
|
||||||
|
else
|
||||||
|
ddcutil getvcp 10 --brief 2>/dev/null | awk '{print $4}'
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
set)
|
||||||
|
pct="${2:?usage: brightness-ctl set <0-100>}"
|
||||||
|
if has_backlight; then
|
||||||
|
brightnessctl set "${pct}%" > /dev/null
|
||||||
|
else
|
||||||
|
ddcutil setvcp 10 "$pct" > /dev/null
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
up|down)
|
||||||
|
# brightnessctl takes a relative step directly, but ddcutil's
|
||||||
|
# setvcp only takes an absolute value — so the DDC/CI path (this
|
||||||
|
# machine's AOC 27G2G8 has no backlight device, so it always takes
|
||||||
|
# this path) has to read the current level and clamp the step
|
||||||
|
# itself.
|
||||||
|
step="${2:-5}"
|
||||||
|
if has_backlight; then
|
||||||
|
if [ "$1" = "up" ]; then
|
||||||
|
brightnessctl set "+${step}%" > /dev/null
|
||||||
|
else
|
||||||
|
brightnessctl set "${step}%-" > /dev/null
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
cur=$(ddcutil getvcp 10 --brief 2>/dev/null | awk '{print $4}')
|
||||||
|
cur="${cur:-50}"
|
||||||
|
if [ "$1" = "up" ]; then
|
||||||
|
new=$(( cur + step > 100 ? 100 : cur + step ))
|
||||||
|
else
|
||||||
|
new=$(( cur - step < 0 ? 0 : cur - step ))
|
||||||
|
fi
|
||||||
|
ddcutil setvcp 10 "$new" > /dev/null
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "usage: brightness-ctl [get|set <0-100>|up [step]|down [step]]" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
33
modules/scripts/hotspot-start.sh
Executable file
33
modules/scripts/hotspot-start.sh
Executable file
|
|
@ -0,0 +1,33 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# Starts a Wi-Fi hotspot with explicit security/band control — the simple
|
||||||
|
# `nmcli device wifi hotspot` one-liner doesn't expose those.
|
||||||
|
# hotspot-start <ssid> <password> <wpa2|wpa3> <auto|bg|a>
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ssid="${1:?usage: hotspot-start <ssid> <password> <wpa2|wpa3> <auto|bg|a>}"
|
||||||
|
password="${2:?password required}"
|
||||||
|
security="${3:-wpa2}"
|
||||||
|
band="${4:-auto}"
|
||||||
|
|
||||||
|
iface=$(nmcli -t -f DEVICE,TYPE device | awk -F: '$2=="wifi"{print $1; exit}')
|
||||||
|
if [ -z "$iface" ]; then
|
||||||
|
echo "No Wi-Fi device found" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Idempotent: drop any previous Hotspot profile from an earlier run first.
|
||||||
|
nmcli connection delete Hotspot >/dev/null 2>&1 || true
|
||||||
|
|
||||||
|
key_mgmt="wpa-psk"
|
||||||
|
[ "$security" = "wpa3" ] && key_mgmt="sae"
|
||||||
|
|
||||||
|
nmcli connection add type wifi ifname "$iface" con-name Hotspot autoconnect no ssid "$ssid" > /dev/null
|
||||||
|
nmcli connection modify Hotspot 802-11-wireless.mode ap
|
||||||
|
if [ "$band" != "auto" ]; then
|
||||||
|
nmcli connection modify Hotspot 802-11-wireless.band "$band"
|
||||||
|
fi
|
||||||
|
nmcli connection modify Hotspot wifi-sec.key-mgmt "$key_mgmt"
|
||||||
|
nmcli connection modify Hotspot wifi-sec.psk "$password"
|
||||||
|
nmcli connection modify Hotspot ipv4.method shared
|
||||||
|
|
||||||
|
nmcli connection up Hotspot
|
||||||
24
modules/scripts/strip-metadata.sh
Executable file
24
modules/scripts/strip-metadata.sh
Executable file
|
|
@ -0,0 +1,24 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
if [ $# -eq 0 ]; then
|
||||||
|
echo "Usage: strip-metadata <file_or_directory>"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
TARGET="$1"
|
||||||
|
|
||||||
|
echo "[*] Stripping metadata from: $TARGET"
|
||||||
|
|
||||||
|
# Remove all embedded metadata while keeping original filenames
|
||||||
|
if command -v exiftool &> /dev/null; then
|
||||||
|
exiftool -all= -overwrite_original -r "$TARGET"
|
||||||
|
echo "[+] Exif metadata removed."
|
||||||
|
else
|
||||||
|
echo "[!] Warning: exiftool is not installed."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Reset timestamps (atime and mtime) to Epoch (1970-01-01 00:00:00)
|
||||||
|
echo "[*] Resetting timestamps..."
|
||||||
|
find "$TARGET" -exec touch -t 197001010000.00 {} +
|
||||||
|
|
||||||
|
echo "[+] Operation completed successfully."
|
||||||
62
modules/scripts/system-telemetry.sh
Executable file
62
modules/scripts/system-telemetry.sh
Executable file
|
|
@ -0,0 +1,62 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# Single-shot system telemetry snapshot — CPU/RAM/GPU/VRAM/disk usage — as
|
||||||
|
# one JSON object, so the Quickshell System panel can poll this on a Timer
|
||||||
|
# instead of spawning half a dozen separate processes every tick.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# --- CPU ---
|
||||||
|
# /proc/stat's first line ("cpu ...") is cumulative jiffies since boot —
|
||||||
|
# computing instantaneous usage needs two samples across a short gap, so
|
||||||
|
# both reads happen inside this one invocation rather than needing
|
||||||
|
# cross-poll state kept on the QML side.
|
||||||
|
read_cpu() {
|
||||||
|
read -r _ user nice system idle iowait irq softirq steal _ < /proc/stat
|
||||||
|
echo "$((user + nice + system + irq + softirq + steal)) $((user + nice + system + idle + iowait + irq + softirq + steal))"
|
||||||
|
}
|
||||||
|
read -r cpu_busy1 cpu_total1 <<< "$(read_cpu)"
|
||||||
|
sleep 0.2
|
||||||
|
read -r cpu_busy2 cpu_total2 <<< "$(read_cpu)"
|
||||||
|
cpu_busy_delta=$((cpu_busy2 - cpu_busy1))
|
||||||
|
cpu_total_delta=$((cpu_total2 - cpu_total1))
|
||||||
|
cpu_pct=0
|
||||||
|
[ "$cpu_total_delta" -gt 0 ] && cpu_pct=$((100 * cpu_busy_delta / cpu_total_delta))
|
||||||
|
|
||||||
|
# --- RAM ---
|
||||||
|
mem_total_kb=$(awk '/^MemTotal:/{print $2}' /proc/meminfo)
|
||||||
|
mem_avail_kb=$(awk '/^MemAvailable:/{print $2}' /proc/meminfo)
|
||||||
|
mem_used_kb=$((mem_total_kb - mem_avail_kb))
|
||||||
|
|
||||||
|
# --- GPU / VRAM ---
|
||||||
|
# NVIDIA checked first via nvidia-smi (works regardless of which DRM card
|
||||||
|
# index the driver landed on); AMD falls back to the card0 sysfs counters
|
||||||
|
# directly — whichever's actually present decides which branch fires, so
|
||||||
|
# this works unmodified on either machine.
|
||||||
|
gpu_pct=-1
|
||||||
|
vram_used_mb=-1
|
||||||
|
vram_total_mb=-1
|
||||||
|
if command -v nvidia-smi > /dev/null 2>&1 && nvidia-smi -L > /dev/null 2>&1; then
|
||||||
|
nv_out="$(nvidia-smi --query-gpu=utilization.gpu,memory.used,memory.total --format=csv,noheader,nounits -i 0 2>/dev/null | tr -d ' ')"
|
||||||
|
IFS=',' read -r gpu_pct vram_used_mb vram_total_mb <<< "$nv_out"
|
||||||
|
elif [ -e /sys/class/drm/card0/device/gpu_busy_percent ]; then
|
||||||
|
gpu_pct="$(cat /sys/class/drm/card0/device/gpu_busy_percent 2>/dev/null || echo -1)"
|
||||||
|
if [ -e /sys/class/drm/card0/device/mem_info_vram_used ]; then
|
||||||
|
vram_used_mb=$(($(cat /sys/class/drm/card0/device/mem_info_vram_used) / 1024 / 1024))
|
||||||
|
vram_total_mb=$(($(cat /sys/class/drm/card0/device/mem_info_vram_total) / 1024 / 1024))
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- Disks (root + home) ---
|
||||||
|
# Positional ($NF for mountpoint), not header-text matching — `df -h`'s
|
||||||
|
# header is locale-translated (verified live: "System plików"/"%uż." under
|
||||||
|
# this machine's pl_PL locale, not "Filesystem"/"Use%"), so matching on
|
||||||
|
# English header text would silently find nothing.
|
||||||
|
disks_json="$(df -h 2>/dev/null | awk '
|
||||||
|
NR == 1 { next }
|
||||||
|
$NF == "/" || $NF == "/home" {
|
||||||
|
gsub(/%/, "", $5)
|
||||||
|
printf "%s{\"mount\":\"%s\",\"size\":\"%s\",\"used\":\"%s\",\"avail\":\"%s\",\"pct\":\"%s\"}", (n++ ? "," : ""), $NF, $2, $3, $4, $5
|
||||||
|
}
|
||||||
|
')"
|
||||||
|
|
||||||
|
printf '{"cpuPct":%s,"memUsedKb":%s,"memTotalKb":%s,"gpuPct":%s,"vramUsedMb":%s,"vramTotalMb":%s,"disks":[%s]}\n' \
|
||||||
|
"$cpu_pct" "$mem_used_kb" "$mem_total_kb" "$gpu_pct" "$vram_used_mb" "$vram_total_mb" "$disks_json"
|
||||||
30
modules/scripts/vault-toggle.sh
Executable file
30
modules/scripts/vault-toggle.sh
Executable file
|
|
@ -0,0 +1,30 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
CIPHER_DIR="/run/media/nexoniarz/Lukas/.vault_cipher"
|
||||||
|
MOUNT_DIR="$HOME/Vault"
|
||||||
|
|
||||||
|
mkdir -p "$CIPHER_DIR" "$MOUNT_DIR"
|
||||||
|
|
||||||
|
if mountpoint -q "$MOUNT_DIR"; then
|
||||||
|
echo "[*] Synchronizing buffers and unmounting Vault..."
|
||||||
|
sync
|
||||||
|
|
||||||
|
if fusermount -u "$MOUNT_DIR"; then
|
||||||
|
echo "[+] Vault unmounted successfully."
|
||||||
|
else
|
||||||
|
echo "[!] Failed to unmount Vault. Check if any application is using $MOUNT_DIR"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "[*] Mounting Vault..."
|
||||||
|
if [ ! -f "$CIPHER_DIR/gocryptfs.conf" ]; then
|
||||||
|
echo "[!] Container not initialized. Initializing new gocryptfs vault..."
|
||||||
|
gocryptfs -init "$CIPHER_DIR" || exit 1
|
||||||
|
fi
|
||||||
|
if gocryptfs -allow_other "$CIPHER_DIR" "$MOUNT_DIR"; then
|
||||||
|
echo "[+] Vault mounted successfully at $MOUNT_DIR"
|
||||||
|
else
|
||||||
|
echo "[!] Mount failed."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
32
modules/scripts/weather-fetch.sh
Executable file
32
modules/scripts/weather-fetch.sh
Executable file
|
|
@ -0,0 +1,32 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# Fetches current weather + a short hourly forecast from Open-Meteo (free,
|
||||||
|
# no API key/account needed) for either the machine's IP-geolocated
|
||||||
|
# position (default, via ip-api.com — also free/keyless) or an explicitly
|
||||||
|
# named city, and prints one combined JSON object.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
city="${1:-}"
|
||||||
|
|
||||||
|
if [ -n "$city" ]; then
|
||||||
|
encoded="$(jq -sRr @uri <<< "$city")"
|
||||||
|
geo="$(curl -s "https://geocoding-api.open-meteo.com/v1/search?count=1&name=$encoded")"
|
||||||
|
lat="$(jq -r '.results[0].latitude // empty' <<< "$geo")"
|
||||||
|
lon="$(jq -r '.results[0].longitude // empty' <<< "$geo")"
|
||||||
|
place="$(jq -r '.results[0].name // empty' <<< "$geo")"
|
||||||
|
country="$(jq -r '.results[0].country // empty' <<< "$geo")"
|
||||||
|
else
|
||||||
|
ipgeo="$(curl -s "http://ip-api.com/json/")"
|
||||||
|
lat="$(jq -r '.lat // empty' <<< "$ipgeo")"
|
||||||
|
lon="$(jq -r '.lon // empty' <<< "$ipgeo")"
|
||||||
|
place="$(jq -r '.city // empty' <<< "$ipgeo")"
|
||||||
|
country="$(jq -r '.country // empty' <<< "$ipgeo")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$lat" ] || [ -z "$lon" ]; then
|
||||||
|
echo '{"error":"location lookup failed"}'
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
weather="$(curl -s "https://api.open-meteo.com/v1/forecast?latitude=$lat&longitude=$lon¤t=temperature_2m,weather_code,wind_speed_10m,precipitation&hourly=temperature_2m,weather_code,precipitation_probability&timezone=auto&forecast_days=2")"
|
||||||
|
|
||||||
|
jq --arg place "$place" --arg country "$country" '. + {place: $place, country: $country}' <<< "$weather"
|
||||||
204
modules/system.nix
Normal file
204
modules/system.nix
Normal file
|
|
@ -0,0 +1,204 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
# Bootloader & Kernel
|
||||||
|
boot.loader.systemd-boot.enable = true;
|
||||||
|
boot.loader.efi.canTouchEfiVariables = true;
|
||||||
|
boot.loader.systemd-boot.configurationLimit = 5;
|
||||||
|
boot.kernelPackages = pkgs.linuxPackages;
|
||||||
|
boot.supportedFilesystems = [ "fuse" ];
|
||||||
|
|
||||||
|
# Networking
|
||||||
|
networking.hostName = "nixos";
|
||||||
|
networking.networkmanager.enable = true;
|
||||||
|
|
||||||
|
# Firewall Configuration
|
||||||
|
networking.firewall = {
|
||||||
|
enable = true;
|
||||||
|
|
||||||
|
# Allow local ping diagnostic queries
|
||||||
|
allowPing = true;
|
||||||
|
|
||||||
|
allowedTCPPortRanges = [ { from = 1714; to = 1764; } ];
|
||||||
|
allowedUDPPortRanges = [ { from = 1714; to = 1764; } ];
|
||||||
|
allowedTCPPorts = [ 80 443 ];
|
||||||
|
# allowedUDPPorts = [ ];
|
||||||
|
};
|
||||||
|
|
||||||
|
# Time zone and Internationalization
|
||||||
|
time.timeZone = "Europe/Warsaw";
|
||||||
|
i18n.defaultLocale = "pl_PL.UTF-8";
|
||||||
|
i18n.extraLocaleSettings = {
|
||||||
|
LC_ADDRESS = "pl_PL.UTF-8";
|
||||||
|
LC_IDENTIFICATION = "pl_PL.UTF-8";
|
||||||
|
LC_MEASUREMENT = "pl_PL.UTF-8";
|
||||||
|
LC_MONETARY = "pl_PL.UTF-8";
|
||||||
|
LC_NAME = "pl_PL.UTF-8";
|
||||||
|
LC_NUMERIC = "pl_PL.UTF-8";
|
||||||
|
LC_PAPER = "pl_PL.UTF-8";
|
||||||
|
LC_TELEPHONE = "pl_PL.UTF-8";
|
||||||
|
LC_TIME = "pl_PL.UTF-8";
|
||||||
|
};
|
||||||
|
|
||||||
|
nix.settings.auto-optimise-store = true;
|
||||||
|
nix.gc = {
|
||||||
|
automatic = true;
|
||||||
|
dates = "weekly";
|
||||||
|
options = "--delete-older-than 7d";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Console keymap
|
||||||
|
console.keyMap = "pl2";
|
||||||
|
|
||||||
|
# Sound and Audio (Pipewire)
|
||||||
|
security.rtkit.enable = true;
|
||||||
|
services.pulseaudio.enable = false;
|
||||||
|
services.pipewire = {
|
||||||
|
enable = true;
|
||||||
|
alsa.enable = true;
|
||||||
|
alsa.support32Bit = true;
|
||||||
|
pulse.enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
hardware.bluetooth = {
|
||||||
|
enable = true;
|
||||||
|
powerOnBoot = true;
|
||||||
|
settings = {
|
||||||
|
General = {
|
||||||
|
# Shows battery charge of connected devices on supported
|
||||||
|
# Bluetooth adapters. Defaults to 'false'.
|
||||||
|
Experimental = true;
|
||||||
|
# When enabled other devices can connect faster to us, however
|
||||||
|
# the tradeoff is increased power consumption. Defaults to
|
||||||
|
# 'false'.
|
||||||
|
FastConnectable = true;
|
||||||
|
};
|
||||||
|
Policy = {
|
||||||
|
# Enable all controllers when they are found. This includes
|
||||||
|
# adapters present on start as well as adapters that are plugged
|
||||||
|
# in later on. Defaults to 'true'.
|
||||||
|
AutoEnable = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.blueman.enable = true;
|
||||||
|
|
||||||
|
#Firejail
|
||||||
|
programs.firejail = {
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
#FUSE shit
|
||||||
|
programs.fuse.userAllowOther = true;
|
||||||
|
|
||||||
|
# Enable GnuPG Agent with GUI pinentry support
|
||||||
|
programs.gnupg.agent = {
|
||||||
|
enable = true;
|
||||||
|
enableSSHSupport = true;
|
||||||
|
pinentryPackage = pkgs.pinentry-gnome3; # Matches Pantheon's GTK/gnome-keyring stack
|
||||||
|
};
|
||||||
|
|
||||||
|
security.sudo.extraConfig = ''
|
||||||
|
Defaults pwfeedback
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Printing services
|
||||||
|
services.printing.enable = true;
|
||||||
|
|
||||||
|
nixpkgs.config.allowUnfree = true;
|
||||||
|
|
||||||
|
fonts.packages = with pkgs; [
|
||||||
|
corefonts
|
||||||
|
dejavu_fonts
|
||||||
|
noto-fonts
|
||||||
|
noto-fonts-cjk-sans
|
||||||
|
noto-fonts-color-emoji
|
||||||
|
nerd-fonts.fira-code
|
||||||
|
nerd-fonts.jetbrains-mono
|
||||||
|
nerd-fonts.hack
|
||||||
|
inter
|
||||||
|
liberation_ttf
|
||||||
|
roboto
|
||||||
|
];
|
||||||
|
|
||||||
|
# --- Loader shim for running non-Nix-packaged binaries (e.g. the official
|
||||||
|
# Tor Browser bundle) that expect a standard FHS dynamic linker/libraries. ---
|
||||||
|
programs.nix-ld.enable = true;
|
||||||
|
programs.nix-ld.libraries = with pkgs; [
|
||||||
|
glib gtk3 gdk-pixbuf pango cairo atk
|
||||||
|
dbus dbus-glib fontconfig freetype
|
||||||
|
libx11 libxext libxrender libxtst
|
||||||
|
libxi libxcomposite libxdamage libxfixes
|
||||||
|
libxrandr libxcursor libxcb libxkbcommon
|
||||||
|
alsa-lib mesa zlib stdenv.cc.cc
|
||||||
|
];
|
||||||
|
environment.systemPackages = [ pkgs.file ];
|
||||||
|
|
||||||
|
# --- Hardening: swap, kernel sysctls, DNS, MAC randomization ---
|
||||||
|
|
||||||
|
# Swap: replace disk swap with compressed in-RAM swap. Nothing sensitive
|
||||||
|
# (decrypted vault contents, browser memory, GPG session data) ever gets
|
||||||
|
# written to disk in plaintext via swap. Also faster than disk swap under
|
||||||
|
# memory pressure.
|
||||||
|
zramSwap.enable = true;
|
||||||
|
swapDevices = lib.mkForce [ ];
|
||||||
|
# systemd's gpt-auto-generator independently re-discovers and activates any
|
||||||
|
# GPT partition tagged as Linux swap, regardless of the swapDevices list
|
||||||
|
# above — this disables that auto-discovery so the old disk swap partition
|
||||||
|
# actually stays off. Doesn't affect /, /home, /nix, /boot: those are
|
||||||
|
# already explicitly declared in hardware-configuration.nix, not relying on
|
||||||
|
# gpt-auto. Takes effect on next reboot.
|
||||||
|
boot.kernelParams = [ "systemd.gpt_auto=0" ];
|
||||||
|
|
||||||
|
# Kernel/system hardening sysctls
|
||||||
|
boot.kernel.sysctl = {
|
||||||
|
# Hide kernel pointers from unprivileged users (blocks a common
|
||||||
|
# local info-leak used in exploit chains).
|
||||||
|
"kernel.kptr_restrict" = 2;
|
||||||
|
# Restrict dmesg access to root.
|
||||||
|
"kernel.dmesg_restrict" = 1;
|
||||||
|
# Reverse-path filtering: drop packets with spoofed source addresses.
|
||||||
|
"net.ipv4.conf.all.rp_filter" = 1;
|
||||||
|
"net.ipv4.conf.default.rp_filter" = 1;
|
||||||
|
# Don't accept/send ICMP redirects (blocks a classic local MITM trick).
|
||||||
|
"net.ipv4.conf.all.accept_redirects" = false;
|
||||||
|
"net.ipv4.conf.default.accept_redirects" = false;
|
||||||
|
"net.ipv6.conf.all.accept_redirects" = false;
|
||||||
|
"net.ipv6.conf.default.accept_redirects" = false;
|
||||||
|
"net.ipv4.conf.all.send_redirects" = false;
|
||||||
|
"net.ipv4.conf.default.send_redirects" = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Crash dumps can contain decrypted memory contents, passwords, keys —
|
||||||
|
# never write them to disk.
|
||||||
|
systemd.coredump.enable = false;
|
||||||
|
|
||||||
|
# Blocks kexec-based kernel image tampering.
|
||||||
|
security.protectKernelImage = true;
|
||||||
|
|
||||||
|
# DNS-over-TLS system-wide (Tor Browser already routes its own DNS
|
||||||
|
# through Tor, so this only affects everything else). Cloudflare + Quad9
|
||||||
|
# both support DoT; "allow-downgrade" avoids hard failures on domains
|
||||||
|
# with broken DNSSEC deployment.
|
||||||
|
networking.nameservers = [ "1.1.1.1#cloudflare-dns.com" "9.9.9.9#dns.quad9.net" ];
|
||||||
|
services.resolved = {
|
||||||
|
enable = true;
|
||||||
|
settings.Resolve = {
|
||||||
|
DNSSEC = "allow-downgrade";
|
||||||
|
DNSOverTLS = "true";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
networking.networkmanager.dns = "systemd-resolved";
|
||||||
|
|
||||||
|
# MAC address randomization.
|
||||||
|
# WiFi: fully random per connection (you're on ethernet now, but this
|
||||||
|
# protects you if you ever use WiFi).
|
||||||
|
# Ethernet: "stable" — a consistent pseudonymous MAC per connection
|
||||||
|
# profile rather than your real hardware MAC, so it won't break any
|
||||||
|
# static DHCP reservation/MAC filtering on your OpenWRT router, while
|
||||||
|
# still not exposing your real hardware identity.
|
||||||
|
networking.networkmanager.wifi.macAddress = "random";
|
||||||
|
networking.networkmanager.wifi.scanRandMacAddress = true;
|
||||||
|
networking.networkmanager.ethernet.macAddress = "stable";
|
||||||
|
}
|
||||||
27
modules/users.nix
Normal file
27
modules/users.nix
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
{ config, pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
# Primary user account configuration (Access and settings only)
|
||||||
|
users.users."nexoniarz" = {
|
||||||
|
isNormalUser = true;
|
||||||
|
description = "Nexoniarz";
|
||||||
|
extraGroups = [ "networkmanager" "wheel" "fuse" "i2c" "video" ];
|
||||||
|
shell = pkgs.zsh;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Default shell (ZSH)
|
||||||
|
programs.zsh.enable = true;
|
||||||
|
|
||||||
|
# Web browser configuration
|
||||||
|
programs.firefox.enable = true;
|
||||||
|
|
||||||
|
# Enable Steam with optimized system configurations
|
||||||
|
programs.steam = {
|
||||||
|
enable = true;
|
||||||
|
remotePlay.openFirewall = true;
|
||||||
|
dedicatedServer.openFirewall = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Enable Flatpak support
|
||||||
|
services.flatpak.enable = true;
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue