diff --git a/Assets/screenshot1.png b/Assets/screenshot1.png deleted file mode 100644 index b24c5dd..0000000 Binary files a/Assets/screenshot1.png and /dev/null differ diff --git a/README.md b/README.md index a7e3bbc..dea78d6 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,29 @@ # nexoniarz-config-nixos -My personal NixOS system configuration and dotfiles tailored for my daily usage and needs. - -![Desktop Screenshot](Assets/screenshot1.png) +My personal NixOS system configuration. ## Overview -- **OS:** NixOS -- **WM / Compositor:** Hyprland (Wayland) -- **Bar / Panels:** Quickshell -- **Terminal:** Kitty +- **OS:** NixOS 26.05 (unstable channel) +- **Desktop:** Budgie on Wayland (labwc), SDDM +- **Bootloader:** Limine +- **Terminal:** Konsole - **Shell:** Zsh +- **Audio:** PipeWire +- **GPU:** NVIDIA (open kernel modules) + +## Layout + +| File | Contents | +|---|---| +| `configuration.nix` | Imports only | +| `modules/system.nix` | Boot, networking, locale, audio, hardening | +| `modules/drivers.nix` | GPU, tablet, I2C, RTL-SDR | +| `modules/desktop.nix` | Budgie, theming | +| `modules/users.nix` | Account, shell, Steam | +| `modules/apps.nix` | Installed packages | +| `modules/scripts.nix` | Custom scripts in `modules/scripts/` | +| `modules/default-apps.nix` | MIME associations | --- diff --git a/configuration.nix b/configuration.nix index b646a90..f639910 100644 --- a/configuration.nix +++ b/configuration.nix @@ -1,19 +1,17 @@ -# 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 # NVIDIA Open GPU kernel modules and graphics - ./modules/desktop.nix # Budgie desktop environment - ./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 - ./modules/default-apps.nix # Default app associations (terminal, image viewer, archives), LibreOffice + ./hardware-configuration.nix + ./modules/system.nix + ./modules/drivers.nix + ./modules/desktop.nix + ./modules/users.nix + ./modules/apps.nix + ./modules/scripts.nix + ./modules/default-apps.nix ]; # Do not change this value. Read documentation before updating. - system.stateVersion = "26.05"; + system.stateVersion = "26.05"; } diff --git a/modules/apps.nix b/modules/apps.nix index 73daade..d5c3626 100644 --- a/modules/apps.nix +++ b/modules/apps.nix @@ -1,18 +1,37 @@ { config, pkgs, ... }: +let + # Both SDR++ and rtl_433 default to supporting every radio ever made, which + # drags in UHD (USRP firmware), BladeRF and LimeSuite — ~1.5 GB for hardware + # we don't own. These two overrides cut that down to the RTL-SDR paths. + soapysdrLean = pkgs.soapysdr.override { + extraPackages = with pkgs; [ soapyrtlsdr soapyremote ]; + }; + + rtl433Lean = pkgs.rtl_433.override { soapysdr-with-plugins = soapysdrLean; }; + + # Leaves the RTL-SDR, rtl_tcp, file and network sources on. + sdrppLean = pkgs.sdrpp.override { + soapy_source = false; + bladerf_source = false; + limesdr_source = false; + plutosdr_source = false; + airspy_source = false; + airspyhf_source = false; + hermes_source = false; + rfspace_source = false; + dragonlabs_source = false; + spectran_http_source = false; + }; +in { - # 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; [ - tumbler # Thumbnails (paired with services.tumbler.enable; also used by Nemo) - gnome-screenshot # Screenshot capture (X11) - imv # Image viewer - brightnessctl # Backlight brightness (laptop panels) - ddcutil # DDC/CI brightness (external monitors) - lm_sensors # sensors-detect helps ddcutil find I2C buses - networkmanager # nmcli, for the Wi-Fi hotspot toggle - xdg-user-dirs # Resolves localized folder names (Obrazy, not Pictures, on pl_PL) - playerctl # MPRIS media control, for the function-key media binds + tumbler + brightnessctl + ddcutil + lm_sensors # sensors-detect helps ddcutil find the I2C buses + networkmanager + xdg-user-dirs # Resolves localized folder names (Obrazy, not Pictures) # Apps blender @@ -25,36 +44,31 @@ filezilla chromium obs-studio - easyeffects # Real-time mic/output effects (pitch, EQ, ...) — auto-creates a - # selectable "Easy Effects Source" virtual mic once an Input effect - # is added, no manual PipeWire routing needed - qpwgraph # Patchbay GUI — wires EasyEffects'/Soundux's output into the - # standalone "Virtual Microphone Sink" (see system.nix) - # Soundux (soundboard) isn't packaged in this nixpkgs channel anymore — - # installed via Flatpak instead (io.github.Soundux). + sdrppLean + rtl433Lean # Games prismlauncher - pkgs.osu-lazer-bin + osu-lazer-bin - # Dev: compilers, runtimes, languages + # Dev glibc musl cmake - gnumake # Provides the 'make' command + gnumake gcc python3 openjdk25 - claude-code # AI Developer Assistant + claude-code ]; - # Global command-line utilities available everywhere environment.systemPackages = with pkgs; [ git - gh # GitHub CLI — was only installed ad-hoc before (login didn't survive) + gh vim fastfetch gparted + efibootmgr firejail gnupg lmstudio @@ -66,10 +80,11 @@ kdePackages.kate kdePackages.qqc2-desktop-style linphonePackages.linphone-desktop - kdePackages.kcalc # Calculator (nothing filled this role before) - kdePackages.okular # Document/PDF viewer (nothing filled this role before) - kdePackages.elisa # Audio player (vlc/ffmpeg cover video already; nothing dedicated for audio) - kdePackages.konsole # Terminal (replaces kitty) - kdePackages.dolphin # File manager (replaces Thunar, alongside Budgie's default Nemo) + kdePackages.kcalc + kdePackages.okular + kdePackages.elisa + kdePackages.konsole + kdePackages.dolphin + kdePackages.plasma-systemmonitor ]; } diff --git a/modules/default-apps.nix b/modules/default-apps.nix index 44b0f05..8f43767 100644 --- a/modules/default-apps.nix +++ b/modules/default-apps.nix @@ -2,27 +2,26 @@ { environment.systemPackages = with pkgs; [ - libreoffice-qt6 # Qt6-styled build — fits the Qt theming work in theme.nix - # better than the default GTK3 build would. + libreoffice-qt6 ]; - # System-level fallback defaults (XDG spec: only consulted for a - # mimetype the user's own ~/.config/mimeapps.list doesn't already - # claim), so a future "Open With" choice always wins over this without - # needing to touch it. Mimetype lists taken directly from Gwenview's - # and Ark's own .desktop files, not guessed. + # GIO picks the terminal from here for "Open Terminal" style actions. + environment.etc."xdg/xdg-terminals.list".text = '' + org.kde.konsole.desktop + ''; + + # System-level fallbacks. Per the XDG spec these are only consulted for a + # mimetype the user's own ~/.config/mimeapps.list doesn't already claim, + # so any "Open With" choice you make later still wins over this. # - # One mimetype=desktopfile pair per line: the semicolon only separates - # multiple desktop-file candidates for the SAME key, it doesn't chain - # separate mimetype=value pairs on one line — mimeapps.list parsers - # (verified against xdg-utils' own xdg-mime script) match by scanning - # for a line that STARTS WITH "mimetype=", so cramming several pairs - # onto one semicolon-joined line silently hides every key after the - # first from ever being found. + # One mimetype=desktopfile pair per line. The semicolon only separates + # multiple candidates for the SAME key — it does not chain separate pairs, + # and parsers match by scanning for a line starting with "mimetype=", so + # cramming several onto one line silently hides all but the first. environment.etc."xdg/mimeapps.list".text = let gwenviewMimes = [ - "inode/directory" "image/avif" "image/gif" "image/heif" "image/jpeg" + "image/avif" "image/gif" "image/heif" "image/jpeg" "image/jxl" "image/png" "image/bmp" "image/x-eps" "image/x-icns" "image/x-ico" "image/x-portable-bitmap" "image/x-portable-graymap" "image/x-portable-pixmap" "image/x-xbitmap" "image/x-xpixmap" @@ -42,19 +41,40 @@ "application/x-7z-compressed" "application/vnd.rar" "application/zip" "application/x-java-archive" "application/x-arj" ]; - # Taken from Okular's own .desktop file, same as the other two lists. okularMimes = [ "application/pdf" "application/x-pdf" "image/vnd.djvu" "application/epub+zip" "application/x-fictionbook+xml" "application/x-mobipocket-ebook" "image/x-portable-document" "application/x-cbr" "application/x-cbz" "application/x-cbt" "application/x-cb7" "application/postscript" ]; + vlcMimes = [ + "video/mp4" "video/x-matroska" "video/webm" "video/x-msvideo" + "video/quicktime" "video/mpeg" "video/x-ms-wmv" "video/x-flv" + "video/3gpp" "video/ogg" "video/x-theora+ogg" "video/x-ogm+ogg" + "application/x-matroska" "application/vnd.rn-realmedia" + ]; + elisaMimes = [ + "audio/mpeg" "audio/flac" "audio/x-flac" "audio/ogg" "audio/x-vorbis+ogg" + "audio/opus" "audio/x-opus+ogg" "audio/mp4" "audio/aac" "audio/x-wav" + "audio/wav" "audio/x-ms-wma" "audio/x-aiff" "audio/x-musepack" + ]; + kateMimes = [ + "text/plain" "text/markdown" "text/x-csrc" "text/x-c++src" "text/x-chdr" + "text/x-c++hdr" "text/x-python" "text/x-java" "text/x-shellscript" + "text/x-nix" "text/css" "text/html" "text/xml" "application/json" + "application/x-yaml" "application/toml" "application/javascript" + "application/x-shellscript" "text/x-log" + ]; line = desktop: mime: "${mime}=${desktop}"; in '' [Default Applications] + inode/directory=org.kde.dolphin.desktop ${lib.concatMapStringsSep "\n" (line "org.kde.gwenview.desktop") gwenviewMimes} ${lib.concatMapStringsSep "\n" (line "org.kde.ark.desktop") arkMimes} ${lib.concatMapStringsSep "\n" (line "org.kde.okular.desktop") okularMimes} + ${lib.concatMapStringsSep "\n" (line "vlc.desktop") vlcMimes} + ${lib.concatMapStringsSep "\n" (line "org.kde.elisa.desktop") elisaMimes} + ${lib.concatMapStringsSep "\n" (line "org.kde.kate.desktop") kateMimes} ''; } diff --git a/modules/desktop.nix b/modules/desktop.nix index 24c4d32..926f34d 100644 --- a/modules/desktop.nix +++ b/modules/desktop.nix @@ -1,38 +1,50 @@ { config, pkgs, ... }: { - # --- Budgie: X11 desktop environment, lightdm login manager --- + # Budgie ships only a Wayland session here (labwc); xserver stays on for + # Xwayland and for the xkb layout below. services.xserver.enable = true; - services.xserver.displayManager.lightdm.enable = true; services.desktopManager.budgie.enable = true; + # SDDM replaces lightdm: Qt, and it actually launches Wayland sessions. + # Its own greeter runs on weston, not kwin, so no KDE compositor tags along. + services.displayManager.sddm = { + enable = true; + wayland.enable = true; + }; + security.polkit.enable = true; - # Keyboard layout for console/X11/lightdm services.xserver.xkb = { layout = "pl"; variant = ""; }; - # Thumbnails + trash/volume mount integration for Dolphin and Budgie's - # default Nemo file manager alike. services.tumbler.enable = true; services.gvfs.enable = true; - # Drop the xterm fallback terminal xserver.nix installs unconditionally — - # Konsole is the real terminal here. + # xserver.nix installs xterm unconditionally; Konsole is the terminal here. services.xserver.excludePackages = [ pkgs.xterm ]; - # GTK/Qt themselves stay at their stock defaults (no forced dark mode, no - # custom CSS) — only the icon and cursor theme are picked explicitly, via - # Budgie's own GSettings-override hook rather than a custom script. - # (extraGSettingsOverridePackages is for packages that ship their own - # gsettings-schema overrides, e.g. plugins — not theme packages, which - # just need to be on the system path for their icons/cursors to resolve.) + # Budgie's module installs GTK/MATE apps that duplicate the Qt ones in + # apps.nix. Excluding gnome-terminal also flips programs.gnome-terminal.enable + # off — the module gates that on this same list. + environment.budgie.excludePackages = with pkgs; [ + nemo # -> dolphin + gnome-terminal # -> konsole + eom # -> gwenview + pluma # -> kate + atril # -> okular + engrampa # -> ark + mate-calc # -> kcalc + mate-system-monitor # -> plasma-systemmonitor + ]; + environment.systemPackages = [ pkgs.gruvbox-plus-icons pkgs.bibata-cursors ]; + services.desktopManager.budgie.extraGSettingsOverrides = '' [org.gnome.desktop.interface] icon-theme='Gruvbox-Plus-Dark' diff --git a/modules/drivers.nix b/modules/drivers.nix index e130a93..16c8c24 100644 --- a/modules/drivers.nix +++ b/modules/drivers.nix @@ -1,43 +1,34 @@ { 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" ]; boot.extraModprobeConfig = '' - # 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. + # DualSense/PS4 pads pair over Bluetooth then drop instantly; broken + # ERTM in many adapters. Disabling it is the standard fix. options bluetooth disable_ertm=1 ''; - # I2C bus, for DDC/CI monitor control (brightness) via ddcutil — this - # machine has no laptop backlight, only external DisplayPort monitors. + # Blog V4 needs the rtlsdrblog fork of librtlsdr, which is what + # pkgs.rtl-sdr already is here. Also blacklists the DVB-T drivers. + hardware.rtl-sdr.enable = true; + + # For ddcutil — no laptop backlight here, only external DisplayPort. hardware.i2c.enable = true; - # Load NVIDIA driver for X11 and Wayland services.xserver.videoDrivers = [ "nvidia" ]; hardware.nvidia = { - # Required settings modesetting.enable = true; - - # Enable NVIDIA Open GPU Kernel Modules (Turing architecture or newer) open = true; - - # Enable the NVIDIA settings menu nvidiaSettings = true; - - # Use the stable driver package matching current kernel package = config.boot.kernelPackages.nvidiaPackages.stable; }; } diff --git a/modules/scripts.nix b/modules/scripts.nix index a6a61d8..65e0231 100644 --- a/modules/scripts.nix +++ b/modules/scripts.nix @@ -1,25 +1,14 @@ { 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 ]; } diff --git a/modules/scripts/brightness-ctl.sh b/modules/scripts/brightness-ctl.sh deleted file mode 100755 index bc58dfa..0000000 --- a/modules/scripts/brightness-ctl.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/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 diff --git a/modules/scripts/hotspot-start.sh b/modules/scripts/hotspot-start.sh deleted file mode 100755 index 5d78ba5..0000000 --- a/modules/scripts/hotspot-start.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/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 -set -euo pipefail - -ssid="${1:?usage: hotspot-start }" -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 diff --git a/modules/scripts/system-telemetry.sh b/modules/scripts/system-telemetry.sh deleted file mode 100755 index 89c72a3..0000000 --- a/modules/scripts/system-telemetry.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/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" diff --git a/modules/scripts/weather-fetch.sh b/modules/scripts/weather-fetch.sh deleted file mode 100755 index 5c83ec9..0000000 --- a/modules/scripts/weather-fetch.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/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" diff --git a/modules/system.nix b/modules/system.nix index 97ff804..a7dbdcc 100644 --- a/modules/system.nix +++ b/modules/system.nix @@ -1,31 +1,44 @@ { config, lib, pkgs, ... }: { - # Bootloader & Kernel - boot.loader.systemd-boot.enable = true; boot.loader.efi.canTouchEfiVariables = true; - boot.loader.systemd-boot.configurationLimit = 5; + boot.loader.limine = { + enable = true; + maxGenerations = 5; + + # Gruvbox, to match the icon theme. + style = { + wallpapers = [ ]; # Solid background; a path here would be used instead + interface = { + branding = "NixOS"; + brandingColor = "fabd2f"; + helpColor = "928374"; + helpColorBright = "d79921"; + }; + graphicalTerminal = { + foreground = "ebdbb2"; + background = "00282828"; + brightForeground = "fbf1c7"; + palette = "282828;cc241d;98971a;d79921;458588;b16286;689d6a;a89984"; + brightPalette = "928374;fb4934;b8bb26;fabd2f;83a598;d3869b;8ec07c;ebdbb2"; + margin = 32; + }; + }; + }; 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 = { @@ -47,10 +60,8 @@ options = "--delete-older-than 7d"; }; - # Console keymap console.keyMap = "pl2"; - # Sound and Audio (Pipewire) security.rtkit.enable = true; services.pulseaudio.enable = false; services.pipewire = { @@ -58,36 +69,6 @@ alsa.enable = true; alsa.support32Bit = true; pulse.enable = true; - - # Standalone "Virtual Microphone" device, fully independent of the real - # hardware mic — always present regardless of what's running, so apps - # like Discord keep defaulting to the real mic untouched, and only pick - # this up if explicitly selected. Feed anything into "Virtual - # Microphone Sink" (e.g. via qpwgraph/helvum, routing EasyEffects' or - # Soundux's output to it) and it comes out the other side as "Virtual - # Microphone", selectable like any other input device. - extraConfig.pipewire."99-virtual-microphone" = { - "context.modules" = [ - { - name = "libpipewire-module-loopback"; - args = { - "node.description" = "Virtual Microphone"; - "capture.props" = { - "node.name" = "virtual_mic_sink"; - "node.description" = "Virtual Microphone Sink"; - "media.class" = "Audio/Sink"; - "audio.position" = "FL,FR"; - }; - "playback.props" = { - "node.name" = "virtual_mic_source"; - "node.description" = "Virtual Microphone"; - "media.class" = "Audio/Source"; - "audio.position" = "FL,FR"; - }; - }; - } - ]; - }; }; hardware.bluetooth = { @@ -95,18 +76,10 @@ 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; + Experimental = true; # Battery level of connected devices + FastConnectable = true; # Faster reconnects, more power draw }; 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; }; }; @@ -114,26 +87,22 @@ 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-rofi; # Reuses the Rofi theme, no extra toolkit + pinentryPackage = pkgs.pinentry-rofi; }; security.sudo.extraConfig = '' Defaults pwfeedback ''; - # Printing services services.printing.enable = true; nixpkgs.config.allowUnfree = true; @@ -152,8 +121,7 @@ roboto ]; - # --- Loader shim for running non-Nix-packaged binaries (e.g. the official - # Tor Browser bundle) that expect a standard FHS dynamic linker/libraries. --- + # Lets non-Nix binaries (e.g. the Tor Browser bundle) find an FHS linker. programs.nix-ld.enable = true; programs.nix-ld.libraries = with pkgs; [ glib gtk3 gdk-pixbuf pango cairo atk @@ -165,61 +133,34 @@ ]; environment.systemPackages = [ pkgs.file ]; - # --- Hardening: swap, kernel sysctls, DNS, MAC randomization --- + # --- Hardening --- - # 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. + # zram instead of disk swap: nothing sensitive is written to disk in + # plaintext. systemd's gpt-auto-generator would otherwise re-activate the + # old swap partition regardless of swapDevices, hence the kernel param. 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; - # Restrict ptrace to a process's own children — blocks a common local - # credential-scraping/process-injection vector between unrelated - # processes. Only bites ad-hoc `gdb -p `-style attaches to a - # process that isn't your debugger's own child. + # Only bites ad-hoc `gdb -p ` on a non-child process. "kernel.yama.ptrace_scope" = 1; - # Drop the kernel-uptime-derived TCP timestamp from outgoing packets - # (a passive fingerprinting/uptime-leak vector). Negligible throughput - # impact on a normal home connection. "net.ipv4.tcp_timestamps" = 0; }; - # 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; @@ -230,26 +171,17 @@ }; 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. + # Ethernet stays "stable" (pseudonymous but consistent) so static DHCP + # reservations on the router keep working; Wi-Fi is fully random. networking.networkmanager.wifi.macAddress = "random"; networking.networkmanager.wifi.scanRandMacAddress = true; networking.networkmanager.ethernet.macAddress = "stable"; - # Disable NetworkManager's periodic external connectivity probe (normally - # pings a canary URL to detect captive portals) — one less routine - # external phone-home, no functional loss on a directly-connected desktop. + # Disable NetworkManager's periodic captive-portal probe. networking.networkmanager.settings.connectivity = { uri = ""; interval = 0; }; - # Budgie's module turns this on by default (for Budgie Control Center's - # Location Services panel) — nothing in this config needs location data. services.geoclue2.enable = false; } diff --git a/modules/users.nix b/modules/users.nix index fe92cf7..b8532df 100644 --- a/modules/users.nix +++ b/modules/users.nix @@ -1,27 +1,21 @@ { config, pkgs, ... }: { - # Primary user account configuration (Access and settings only) users.users."nexoniarz" = { isNormalUser = true; description = "Nexoniarz"; - extraGroups = [ "networkmanager" "wheel" "fuse" "i2c" "video" ]; + extraGroups = [ "networkmanager" "wheel" "fuse" "i2c" "video" "plugdev" ]; 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; }