mirror of
https://github.com/Nexoniarz/nexoniarz-config-nixos.git
synced 2026-11-03 04:24:27 +00:00
Add RTL-SDR support; switch to Limine + SDDM; drop Hyprland-era leftovers
RTL-SDR Blog V4. The V4 swapped the R820T2 tuner for an R828D behind a built-in HF upconverter, so it needs the rtlsdrblog fork of librtlsdr -- the stock Osmocom one reports no supported devices. pkgs.rtl-sdr on this channel already is that fork (rtl-sdr-blog 1.3.5), so hardware.rtl-sdr's default package is correct as-is. That also blacklists the DVB-T drivers that otherwise grab the dongle on plug-in, and ships udev rules handing it to plugdev at 0660 -- hence plugdev in the user's groups, or every SDR app needs root. Apps: SDR++ and rtl_433; the rtl_* CLI tools come with the driver. Both SDR apps are overridden to drop hardware we do not own. SDR++ and rtl_433 default to supporting every radio ever made, which pulled in UHD (1.4 GB of USRP firmware), BladeRF and LimeSuite. gqrx was the original choice but reaches UHD through gr-osmosdr's gr-uhd feature; SDR++ uses no GNU Radio at all. Per-package overrides rather than a global overlay, so nothing else is affected. Bootloader: systemd-boot -> Limine, themed to match the Gruvbox icon theme. Limine installs to its own EFI directory and adds its own NVRAM entry, so systemd-boot stays on the ESP as a firmware-menu fallback. Display manager: lightdm -> SDDM with wayland.enable. Budgie in this channel ships only a Wayland session (labwc) and was already running as one; lightdm just handles that badly. SDDM's greeter runs on weston, not kwin, so no KDE compositor comes along. Qt defaults over Budgie's GTK/MATE apps. The Budgie module force-enables gnome-terminal and installs nemo, eom, pluma, atril, engrampa, mate-calc and mate-system-monitor; environment.budgie.excludePackages drops all of them in favour of konsole, dolphin, gwenview, kate, okular, ark, kcalc and plasma-systemmonitor. default-apps.nix rewritten to match: 113 associations, video to vlc, audio to elisa, text/code to kate, and /etc/xdg/xdg-terminals.list pointing at konsole. Fixes a real bug there -- inode/directory was mapped to gwenview, so folders opened in the image viewer. Hyprland-era leftovers removed. system-telemetry and weather-fetch fed Quickshell panels that no longer exist; brightness-ctl and hotspot-start lost their keybinds. jq went with weather-fetch. Also dropped gnome-screenshot, playerctl and imv. vault-toggle and strip-metadata stay -- they never depended on Hyprland. Comments trimmed throughout: deleted anything restating the code, kept the ones recording a why you cannot recover by reading it (systemd.gpt_auto, disable_ertm, ptrace_scope, the stable ethernet MAC, the mimeapps.list parser gotcha). system.nix went 225 -> 166 lines. README rewritten -- it still described Hyprland, Quickshell and Kitty. Screenshot dropped.
This commit is contained in:
parent
d332ed2ef6
commit
33bf94bd4c
14 changed files with 177 additions and 396 deletions
|
|
@ -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
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
'';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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 <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
|
||||
|
|
@ -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"
|
||||
|
|
@ -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"
|
||||
|
|
@ -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 <pid>`-style attaches to a
|
||||
# process that isn't your debugger's own child.
|
||||
# Only bites ad-hoc `gdb -p <pid>` 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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue