summaryrefslogtreecommitdiff
path: root/modules/pc
diff options
context:
space:
mode:
Diffstat (limited to 'modules/pc')
-rw-r--r--modules/pc/default.nix13
-rw-r--r--modules/pc/hardware/bluetooth.nix19
-rw-r--r--modules/pc/hardware/cpu.nix21
-rw-r--r--modules/pc/hardware/default.nix14
-rw-r--r--modules/pc/hardware/tpm.nix18
-rw-r--r--modules/pc/hardware/usb.nix10
-rw-r--r--modules/pc/hardware/yubikey.nix18
-rw-r--r--modules/pc/locale.nix10
-rw-r--r--modules/pc/networking/default.nix17
-rw-r--r--modules/pc/networking/dhcpcd.nix12
-rw-r--r--modules/pc/networking/loopback.nix7
-rw-r--r--modules/pc/networking/networkmanager.nix22
-rw-r--r--modules/pc/networking/optimise.nix73
-rw-r--r--modules/pc/networking/pia.nix10
-rw-r--r--modules/pc/networking/upnp.nix12
-rw-r--r--modules/pc/security/apparmor.nix22
-rw-r--r--modules/pc/security/audit.nix17
-rw-r--r--modules/pc/security/default.nix19
-rw-r--r--modules/pc/security/doas.nix13
-rw-r--r--modules/pc/security/kernel.nix160
-rw-r--r--modules/pc/security/pam.nix50
-rw-r--r--modules/pc/security/polkit.nix7
-rw-r--r--modules/pc/security/sudo.nix75
-rw-r--r--modules/pc/software/access/default.nix6
-rw-r--r--modules/pc/software/access/gnupg.nix18
-rw-r--r--modules/pc/software/access/ssh.nix11
-rw-r--r--modules/pc/software/default.nix34
-rw-r--r--modules/pc/software/desktop/default.nix6
-rw-r--r--modules/pc/software/desktop/gtk.nix8
-rw-r--r--modules/pc/software/desktop/xdg-portal.nix15
-rw-r--r--modules/pc/software/encryption.nix16
-rw-r--r--modules/pc/software/input.nix23
-rw-r--r--modules/pc/software/multimedia/audio/default.nix6
-rw-r--r--modules/pc/software/multimedia/audio/pipewire.nix164
-rw-r--r--modules/pc/software/multimedia/audio/wireplumber.nix42
-rw-r--r--modules/pc/software/multimedia/default.nix6
-rw-r--r--modules/pc/software/multimedia/video/default.nix9
-rw-r--r--modules/pc/software/multimedia/video/vulkan.nix9
-rw-r--r--modules/pc/software/multimedia/video/xserver.nix6
-rw-r--r--modules/pc/software/services/adb.nix12
-rw-r--r--modules/pc/software/services/ananicy.nix8
-rw-r--r--modules/pc/software/services/dbus.nix15
-rw-r--r--modules/pc/software/services/default.nix22
-rw-r--r--modules/pc/software/services/logrotate.nix24
-rw-r--r--modules/pc/software/services/printing.nix19
-rw-r--r--modules/pc/software/shell.nix7
-rw-r--r--modules/pc/software/users.nix46
-rw-r--r--modules/pc/variables/default.nix11
-rw-r--r--modules/pc/variables/fcitx.nix13
49 files changed, 1191 insertions, 4 deletions
diff --git a/modules/pc/default.nix b/modules/pc/default.nix
index 97fe6b9..f35aff2 100644
--- a/modules/pc/default.nix
+++ b/modules/pc/default.nix
@@ -1,8 +1,13 @@
-{ pkgs, secrets, ... }:
+{ pkgs, ... }:
{
- i18n.defaultLocale = secrets.i18n.locale;
- time.timeZone = secrets.i18n.timezone;
- console.keyMap = secrets.i18n.keymap;
+ imports = [
+ ./hardware
+ ./networking
+ ./security
+ ./software
+ ./variables
+ ./locale.nix
+ ];
environment.systemPackages = with pkgs; [
vim
diff --git a/modules/pc/hardware/bluetooth.nix b/modules/pc/hardware/bluetooth.nix
new file mode 100644
index 0000000..9737504
--- /dev/null
+++ b/modules/pc/hardware/bluetooth.nix
@@ -0,0 +1,19 @@
+{ pkgs, ... }:
+{
+ boot.kernelParams = [ "btusb" ];
+ services.blueman.enable = true;
+
+ hardware.bluetooth = {
+ enable = true;
+ powerOnBoot = true;
+ package = pkgs.bluez5-experimental;
+ disabledPlugins = [ "sap" ];
+ # hsphfpd.enable = true;
+
+ settings.General = {
+ JustWorksRepairing = "always";
+ MultiProfile = "multiple";
+ Experimental = true;
+ };
+ };
+}
diff --git a/modules/pc/hardware/cpu.nix b/modules/pc/hardware/cpu.nix
new file mode 100644
index 0000000..1ac3a27
--- /dev/null
+++ b/modules/pc/hardware/cpu.nix
@@ -0,0 +1,21 @@
+{ pkgs, config, ... }:
+{
+ environment.systemPackages = [ pkgs.amdctl ];
+
+ powerManagement = {
+ enable = true;
+ cpuFreqGovernor = "performance";
+ };
+
+ boot = {
+ kernelModules = [
+ # "kvm-amd"
+ "amd-pstate"
+ "zenpower"
+ "msr"
+ ];
+
+ kernelParams = [ "amd_iommu=on" ];
+ extraModulePackages = [ config.boot.kernelPackages.zenpower ];
+ };
+}
diff --git a/modules/pc/hardware/default.nix b/modules/pc/hardware/default.nix
new file mode 100644
index 0000000..cc2915e
--- /dev/null
+++ b/modules/pc/hardware/default.nix
@@ -0,0 +1,14 @@
+{
+ imports = [
+ ./bluetooth.nix
+ ./cpu.nix
+ ./usb.nix
+ ./tpm.nix
+ ./yubikey.nix
+ ];
+
+ hardware = {
+ enableRedistributableFirmware = true;
+ enableAllFirmware = true;
+ };
+}
diff --git a/modules/pc/hardware/tpm.nix b/modules/pc/hardware/tpm.nix
new file mode 100644
index 0000000..b84551e
--- /dev/null
+++ b/modules/pc/hardware/tpm.nix
@@ -0,0 +1,18 @@
+{ pkgs, ... }:
+{
+ security.tpm2 = {
+ enable = true;
+ applyUdevRules = true;
+ abrmd.enable = true;
+ tctiEnvironment.enable = true;
+ pkcs11.enable = true;
+ };
+
+ environment.systemPackages = with pkgs; [
+ tpm2-tools
+ tpm2-tss
+ tpm2-abrmd
+ ];
+
+ boot.kernelModules = [ "uhid" ];
+}
diff --git a/modules/pc/hardware/usb.nix b/modules/pc/hardware/usb.nix
new file mode 100644
index 0000000..f697761
--- /dev/null
+++ b/modules/pc/hardware/usb.nix
@@ -0,0 +1,10 @@
+{ pkgs, ... }:
+{
+ environment.systemPackages = with pkgs; [
+ usbutils
+ lm_sensors
+ pciutils
+ ];
+
+ boot.kernelParams = [ "usbcore.autosuspend=-1" ];
+}
diff --git a/modules/pc/hardware/yubikey.nix b/modules/pc/hardware/yubikey.nix
new file mode 100644
index 0000000..6bd4a5c
--- /dev/null
+++ b/modules/pc/hardware/yubikey.nix
@@ -0,0 +1,18 @@
+{ pkgs, ... }:
+{
+ hardware.gpgSmartcards.enable = true;
+
+ services = {
+ pcscd.enable = true;
+ udev.packages = [ pkgs.yubikey-personalization ];
+ };
+
+ environment.systemPackages = with pkgs; [
+ yubikey-manager
+ yubikey-manager-qt
+ yubikey-personalization
+ yubikey-personalization-gui
+ yubico-piv-tool
+ yubioath-flutter
+ ];
+}
diff --git a/modules/pc/locale.nix b/modules/pc/locale.nix
new file mode 100644
index 0000000..fa47fd5
--- /dev/null
+++ b/modules/pc/locale.nix
@@ -0,0 +1,10 @@
+{ secrets, ... }:
+{
+ i18n.defaultLocale = secrets.i18n.locale;
+ location.provider = "geoclue2";
+
+ time = {
+ timeZone = secrets.i18n.timezone;
+ hardwareClockInLocalTime = false;
+ };
+}
diff --git a/modules/pc/networking/default.nix b/modules/pc/networking/default.nix
new file mode 100644
index 0000000..f73f6ab
--- /dev/null
+++ b/modules/pc/networking/default.nix
@@ -0,0 +1,17 @@
+{
+ imports = [
+ ./dhcpcd.nix
+ ./loopback.nix
+ ./networkmanager.nix
+ ./optimise.nix
+ ./pia.nix
+ ./upnp.nix
+ ];
+
+ # https://discourse.nixos.org/t/rebuild-error-failed-to-start-network-manager-wait-online/41977/2
+ systemd.network.wait-online.enable = false;
+ boot.initrd.systemd.network.wait-online.enable = false;
+
+ # https://discourse.nixos.org/t/how-to-disable-networkmanager-wait-online-service-in-the-configuration-file/19963/2
+ systemd.services.NetworkManager-wait-online.enable = false;
+}
diff --git a/modules/pc/networking/dhcpcd.nix b/modules/pc/networking/dhcpcd.nix
new file mode 100644
index 0000000..f46b657
--- /dev/null
+++ b/modules/pc/networking/dhcpcd.nix
@@ -0,0 +1,12 @@
+{
+ networking.dhcpcd = {
+ wait = "background";
+
+ extraConfig = ''
+ noarp
+ nooption domain_name_servers, domain_name, domain_search, host_name
+ nooption ntp_servers
+ nohook resolv.conf, wpa_supplicant
+ '';
+ };
+}
diff --git a/modules/pc/networking/loopback.nix b/modules/pc/networking/loopback.nix
new file mode 100644
index 0000000..62e745e
--- /dev/null
+++ b/modules/pc/networking/loopback.nix
@@ -0,0 +1,7 @@
+{ config, ... }:
+{
+ boot = {
+ kernelModules = [ "v4l2loopback" ];
+ extraModulePackages = with config.boot.kernelPackages; [ v4l2loopback ];
+ };
+}
diff --git a/modules/pc/networking/networkmanager.nix b/modules/pc/networking/networkmanager.nix
new file mode 100644
index 0000000..7ef0e04
--- /dev/null
+++ b/modules/pc/networking/networkmanager.nix
@@ -0,0 +1,22 @@
+{ pkgs, ... }:
+{
+ environment.systemPackages = [ pkgs.networkmanagerapplet ];
+
+ networking.networkmanager = {
+ enable = true;
+ plugins = [ pkgs.networkmanager-openvpn ];
+ dns = "none"; # "systemd-resolved"
+ wifi.backend = "iwd";
+
+ unmanaged = [
+ "interface-name:tailscale*"
+ "interface-name:br-*"
+ "interface-name:rndis*"
+ "interface-name:docker*"
+ "interface-name:virbr*"
+ "interface-name:vboxnet*"
+ "interface-name:waydroid*"
+ "type:bridge"
+ ];
+ };
+}
diff --git a/modules/pc/networking/optimise.nix b/modules/pc/networking/optimise.nix
new file mode 100644
index 0000000..c6f2bec
--- /dev/null
+++ b/modules/pc/networking/optimise.nix
@@ -0,0 +1,73 @@
+{
+ boot = {
+ kernelModules = [
+ "tls"
+ "tcp_bbr"
+ ];
+
+ kernel.sysctl = {
+ # TCP hardening
+ # Prevent bogus ICMP errors from filling up logs.
+ "net.ipv4.icmp_ignore_bogus_error_responses" = 1;
+ # Reverse path filtering causes the kernel to do source validation of
+ # packets received from all interfaces. This can mitigate IP spoofing.
+ "net.ipv4.conf.default.rp_filter" = 1;
+ "net.ipv4.conf.all.rp_filter" = 1;
+ # Do not accept IP source route packets (we're not a router)
+ "net.ipv4.conf.all.accept_source_route" = 0;
+ "net.ipv6.conf.all.accept_source_route" = 0;
+ # Don't send ICMP redirects (again, we're on a router)
+ "net.ipv4.conf.all.send_redirects" = 0;
+ "net.ipv4.conf.default.send_redirects" = 0;
+ # Refuse ICMP redirects (MITM mitigations)
+ "net.ipv4.conf.all.accept_redirects" = 0;
+ "net.ipv4.conf.default.accept_redirects" = 0;
+ "net.ipv4.conf.all.secure_redirects" = 0;
+ "net.ipv4.conf.default.secure_redirects" = 0;
+ "net.ipv6.conf.all.accept_redirects" = 0;
+ "net.ipv6.conf.default.accept_redirects" = 0;
+ # Protects against SYN flood attacks
+ "net.ipv4.tcp_syncookies" = 1;
+ # Incomplete protection again TIME-WAIT assassination
+ "net.ipv4.tcp_rfc1337" = 1;
+ # And other stuff
+ "net.ipv4.conf.all.log_martians" = true;
+ "net.ipv4.conf.default.log_martians" = true;
+ "net.ipv4.icmp_echo_ignore_broadcasts" = true;
+ "net.ipv6.conf.default.accept_ra" = 0;
+ "net.ipv6.conf.all.accept_ra" = 0;
+ "net.ipv4.tcp_timestamps" = 0;
+
+ # TCP optimization
+ # TCP Fast Open is a TCP extension that reduces network latency by packing
+ # data in the sender’s initial TCP SYN. Setting 3 = enable TCP Fast Open for
+ # both incoming and outgoing connections:
+ "net.ipv4.tcp_fastopen" = 3;
+ # Bufferbloat mitigations + slight improvement in throughput & latency
+ "net.ipv4.tcp_congestion_control" = "bbr";
+ "net.core.default_qdisc" = "cake";
+
+ # Other stuff that I am too lazy to document
+ "net.core.optmem_max" = 65536;
+ "net.core.rmem_default" = 1048576;
+ "net.core.rmem_max" = 16777216;
+ "net.core.somaxconn" = 8192;
+ "net.core.wmem_default" = 1048576;
+ "net.core.wmem_max" = 16777216;
+ "net.ipv4.ip_local_port_range" = "16384 65535";
+ "net.ipv4.tcp_max_syn_backlog" = 8192;
+ "net.ipv4.tcp_max_tw_buckets" = 2000000;
+ "net.ipv4.tcp_mtu_probing" = 1;
+ "net.ipv4.tcp_rmem" = "4096 1048576 2097152";
+ "net.ipv4.tcp_slow_start_after_idle" = 0;
+ "net.ipv4.tcp_tw_reuse" = 1;
+ "net.ipv4.tcp_wmem" = "4096 65536 16777216";
+ "net.ipv4.udp_rmem_min" = 8192;
+ "net.ipv4.udp_wmem_min" = 8192;
+ "net.netfilter.nf_conntrack_generic_timeout" = 60;
+ "net.netfilter.nf_conntrack_max" = 1048576;
+ "net.netfilter.nf_conntrack_tcp_timeout_established" = 600;
+ "net.netfilter.nf_conntrack_tcp_timeout_time_wait" = 1;
+ };
+ };
+}
diff --git a/modules/pc/networking/pia.nix b/modules/pc/networking/pia.nix
new file mode 100644
index 0000000..d52dbf8
--- /dev/null
+++ b/modules/pc/networking/pia.nix
@@ -0,0 +1,10 @@
+{ secrets, ... }:
+{
+ services.pia = {
+ enable = true;
+
+ authUserPass = {
+ inherit (secrets.pia) username password;
+ };
+ };
+}
diff --git a/modules/pc/networking/upnp.nix b/modules/pc/networking/upnp.nix
new file mode 100644
index 0000000..998592a
--- /dev/null
+++ b/modules/pc/networking/upnp.nix
@@ -0,0 +1,12 @@
+{
+ services.miniupnpd = {
+ enable = true;
+ natpmp = true;
+ externalInterface = "enp42s0";
+
+ internalIPs = [
+ "enp42s0"
+ "wlan0"
+ ];
+ };
+}
diff --git a/modules/pc/security/apparmor.nix b/modules/pc/security/apparmor.nix
new file mode 100644
index 0000000..170838c
--- /dev/null
+++ b/modules/pc/security/apparmor.nix
@@ -0,0 +1,22 @@
+{ pkgs, ... }:
+{
+ environment.systemPackages = with pkgs; [
+ apparmor-pam
+ apparmor-utils
+ apparmor-parser
+ apparmor-profiles
+ apparmor-bin-utils
+ apparmor-kernel-patches
+ libapparmor
+ ];
+
+ services.dbus.apparmor = "enabled";
+
+ security.apparmor = {
+ enable = true;
+ enableCache = true;
+ killUnconfinedConfinables = true;
+ packages = [ pkgs.apparmor-profiles ];
+ policies.dummy.profile = "/dummy { }";
+ };
+}
diff --git a/modules/pc/security/audit.nix b/modules/pc/security/audit.nix
new file mode 100644
index 0000000..9922213
--- /dev/null
+++ b/modules/pc/security/audit.nix
@@ -0,0 +1,17 @@
+let
+ enable = false;
+in
+{
+ security = {
+ auditd.enable = enable;
+
+ audit = {
+ inherit enable;
+
+ rules = [
+ "-a exit,always -F arch=b64 -S execve"
+ "-a exit,always -F arch=b32 -S execve"
+ ];
+ };
+ };
+}
diff --git a/modules/pc/security/default.nix b/modules/pc/security/default.nix
new file mode 100644
index 0000000..c1c084c
--- /dev/null
+++ b/modules/pc/security/default.nix
@@ -0,0 +1,19 @@
+{ config, lib, ... }:
+{
+ imports = [
+ ./apparmor.nix
+ ./audit.nix
+ ./doas.nix
+ ./kernel.nix
+ ./pam.nix
+ ./polkit.nix
+ ./sudo.nix
+ ];
+
+ security = {
+ rtkit.enable = lib.modules.mkForce config.services.pipewire.enable;
+ virtualisation.flushL1DataCache = "always";
+ };
+
+ programs.firejail.enable = true;
+}
diff --git a/modules/pc/security/doas.nix b/modules/pc/security/doas.nix
new file mode 100644
index 0000000..af717ca
--- /dev/null
+++ b/modules/pc/security/doas.nix
@@ -0,0 +1,13 @@
+{
+ security.doas = {
+ enable = true;
+ extraRules = [
+ {
+ keepEnv = true;
+ # persist = true;
+ noPass = true;
+ users = [ "ebisu" ];
+ }
+ ];
+ };
+}
diff --git a/modules/pc/security/kernel.nix b/modules/pc/security/kernel.nix
new file mode 100644
index 0000000..62b2f28
--- /dev/null
+++ b/modules/pc/security/kernel.nix
@@ -0,0 +1,160 @@
+{ lib, ... }:
+{
+ boot = {
+ # https://docs.kernel.org/admin-guide/sysctl/vm.html
+ kernel.sysctl = {
+ # The Magic SysRq key is a key combo that allows users connected to the
+ # system console of a Linux kernel to perform some low-level commands.
+ # Disable it, since we don't need it, and is a potential security concern.
+ "kernel.sysrq" = lib.mkForce 0;
+
+ # Restrict ptrace() usage to processes with a pre-defined relationship
+ # (e.g., parent/child)
+ # FIXME: this breaks game launchers, find a way to launch them with privileges (steam)
+ # gamescope wrapped with the capabilities *might* solve the issue
+ # spoiler: it didn't
+ # "kernel.yama.ptrace_scope" = 2;
+
+ # Hide kptrs even for processes with CAP_SYSLOG
+ # also prevents printing kernel pointers
+ "kernel.kptr_restrict" = 2;
+
+ # Disable bpf() JIT (to eliminate spray attacks)
+ "net.core.bpf_jit_enable" = false;
+
+ # Disable ftrace debugging
+ "kernel.ftrace_enabled" = false;
+
+ # Avoid kernel memory address exposures via dmesg (this value can also be set by CONFIG_SECURITY_DMESG_RESTRICT).
+ "kernel.dmesg_restrict" = 1;
+
+ # Prevent creating files in potentially attacker-controlled environments such
+ # as world-writable directories to make data spoofing attacks more difficult
+ "fs.protected_fifos" = 2;
+
+ # Prevent unintended writes to already-created files
+ "fs.protected_regular" = 2;
+
+ # Disable SUID binary dump
+ "fs.suid_dumpable" = 0;
+
+ # Prevent unprivileged users from creating hard or symbolic links to files
+ "fs.protected_symlinks" = 1;
+ "fs.protected_hardlinks" = 1;
+
+ # Disable late module loading
+ # "kernel.modules_disabled" = 1;
+
+ # Disallow profiling at all levels without CAP_SYS_ADMIN
+ "kernel.perf_event_paranoid" = 3;
+
+ # Require CAP_BPF to use bpf
+ "kernel.unprivileged_bpf_disabled" = true;
+
+ # Prevent boot console kernel log information leaks
+ "kernel.printk" = "3 3 3 3";
+
+ # Restrict loading TTY line disciplines to the CAP_SYS_MODULE capability to
+ # prevent unprivileged attackers from loading vulnerable line disciplines with
+ # the TIOCSETD ioctl
+ "dev.tty.ldisc_autoload" = 0;
+
+ # Kexec allows replacing the current running kernel. There may be an edge case where
+ # you wish to boot into a different kernel, but I do not require kexec. Disabling it
+ # patches a potential security hole in our system.
+ "kernel.kexec_load_disabled" = true;
+
+ # Borrowed by NixOS/nixpkgs. Since the security module does not explain what those
+ # options do, it is up you to educate yourself dear reader.
+ # See:
+ # - <https://docs.kernel.org/admin-guide/sysctl/vm.html#mmap-rnd-bits>
+ # - <https://docs.kernel.org/admin-guide/sysctl/vm.html#mmap-min-addr>
+ "vm.mmap_rnd_bits" = 32;
+ "vm.mmap_min_addr" = 65536;
+ };
+
+ # https://www.kernel.org/doc/html/latest/admin-guide/kernel-parameters.html
+ kernelParams = [
+ # I'm sure we break hibernation in at least 5 other sections of this config, so
+ # let's disable hibernation explicitly. Allowing hibernation makes it possible
+ # to replace the booted kernel with a malicious one, akin to kexec. This helps
+ # us prevent an attack called "Evil Maid" where an attacker with physical access
+ # to the device. P.S. I chose to mention "Evil Maid" specifically because it sounds
+ # funny. Do not think that is the only attack you are vulnerable to.
+ # See: <https://en.wikipedia.org/wiki/Evil_maid_attack>
+ "nohibernate"
+
+ # make stack-based attacks on the kernel harder
+ "randomize_kstack_offset=on"
+
+ # Disable vsyscalls as they are obsolete and have been replaced with vDSO.
+ # vsyscalls are also at fixed addresses in memory, making them a potential
+ # target for ROP attacks
+ # this breaks really old binaries for security
+ "vsyscall=none"
+
+ # reduce most of the exposure of a heap attack to a single cache
+ # Disable slab merging which significantly increases the difficulty of heap
+ # exploitation by preventing overwriting objects from merged caches and by
+ # making it harder to influence slab cache layout
+ "slab_nomerge"
+
+ # Disable debugfs which exposes a lot of sensitive information about the
+ # kernel. Some programs, such as powertop, use this interface to gather
+ # information about the system, but it is not necessary for the system to
+ # actually publish those. I can live without it.
+ "debugfs=off"
+
+ # Sometimes certain kernel exploits will cause what is known as an "oops".
+ # This parameter will cause the kernel to panic on such oopses, thereby
+ # preventing those exploits
+ "oops=panic"
+
+ # Only allow kernel modules that have been signed with a valid key to be
+ # loaded, which increases security by making it much harder to load a
+ # malicious kernel module
+ "module.sig_enforce=1"
+
+ # The kernel lockdown LSM can eliminate many methods that user space code
+ # could abuse to escalate to kernel privileges and extract sensitive
+ # information. This LSM is necessary to implement a clear security boundary
+ # between user space and the kernel
+ # integrity: kernel features that allow userland to modify the running kernel
+ # are disabled
+ # confidentiality: kernel features that allow userland to extract confidential
+ # information from the kernel are also disabled
+ # ArchWiki recommends opting in for "integrity", however since we avoid modifying
+ # running kernel (by the virtue of using NixOS and locking module hot-loading) the
+ # confidentiality mode is a better solution.
+ "lockdown=confidentiality"
+
+ # enable buddy allocator free poisoning
+ # on: memory will befilled with a specific byte pattern
+ # that is unlikely to occur in normal operation.
+ # off (default): page poisoning will be disabled
+ "page_poison=on"
+
+ # performance improvement for direct-mapped memory-side-cache utilization
+ # reduces the predictability of page allocations
+ "page_alloc.shuffle=1"
+
+ # for debugging kernel-level slab issues
+ "slub_debug=FZP"
+
+ # ignore access time (atime) updates on files
+ # except when they coincide with updates to the ctime or mtime
+ "rootflags=noatime"
+
+ # linux security modules
+ "lsm=landlock,lockdown,yama,integrity,apparmor,bpf,tomoyo,selinux"
+
+ # prevent the kernel from blanking plymouth out of the fb
+ "fbcon=nodefer"
+
+ # the format that will be used for integrity audit logs
+ # 0 (default): basic integrity auditing messages
+ # 1: additional integrity auditing messages
+ "integrity_audit=1"
+ ];
+ };
+}
diff --git a/modules/pc/security/pam.nix b/modules/pc/security/pam.nix
new file mode 100644
index 0000000..b7eb426
--- /dev/null
+++ b/modules/pc/security/pam.nix
@@ -0,0 +1,50 @@
+{
+ security = {
+ pam = {
+ loginLimits = [
+ {
+ domain = "@wheel";
+ item = "nofile";
+ type = "soft";
+ value = "524288";
+ }
+ {
+ domain = "@wheel";
+ item = "nofile";
+ type = "hard";
+ value = "1048576";
+ }
+ ];
+
+ services =
+ let
+ ttyAudit = {
+ enable = true;
+ enablePattern = "*";
+ };
+ in
+ {
+ swaylock.text = "auth include login";
+ gtklock.text = "auth include login";
+
+ login = {
+ inherit ttyAudit;
+
+ setLoginUid = true;
+ };
+
+ sshd = {
+ inherit ttyAudit;
+
+ setLoginUid = true;
+ };
+
+ sudo = {
+ inherit ttyAudit;
+
+ setLoginUid = true;
+ };
+ };
+ };
+ };
+}
diff --git a/modules/pc/security/polkit.nix b/modules/pc/security/polkit.nix
new file mode 100644
index 0000000..786d1a0
--- /dev/null
+++ b/modules/pc/security/polkit.nix
@@ -0,0 +1,7 @@
+{ lib, ... }:
+{
+ security.polkit = {
+ enable = true;
+ debug = lib.modules.mkDefault true;
+ };
+}
diff --git a/modules/pc/security/sudo.nix b/modules/pc/security/sudo.nix
new file mode 100644
index 0000000..6623b71
--- /dev/null
+++ b/modules/pc/security/sudo.nix
@@ -0,0 +1,75 @@
+{ pkgs, lib, ... }:
+let
+ inherit (lib.modules) mkForce;
+in
+{
+ security = {
+ sudo-rs.enable = mkForce false;
+
+ sudo = {
+ enable = true;
+ execWheelOnly = mkForce true;
+ wheelNeedsPassword = lib.modules.mkDefault false;
+
+ extraConfig = ''
+ Defaults lecture = never
+ Defaults pwfeedback
+ Defaults env_keep += "EDITOR PATH DISPLAY"
+ Defaults timestamp_timeout = 300
+ '';
+
+ extraRules = [
+ {
+ groups = [ "wheel" ];
+ commands =
+ map
+ (rule: {
+ command = lib.meta.getExe' rule.package rule.command;
+ options = [ "NOPASSWD" ];
+ })
+ (
+ with pkgs;
+ [
+ {
+ package = coreutils;
+ command = "sync";
+ }
+ {
+ package = hdparm;
+ command = "hdparm";
+ }
+ {
+ package = nixos-rebuild;
+ command = "nixos-rebuild";
+ }
+ {
+ package = nvme-cli;
+ command = "nvme";
+ }
+ {
+ package = systemd;
+ command = "poweroff";
+ }
+ {
+ package = systemd;
+ command = "reboot";
+ }
+ {
+ package = systemd;
+ command = "shutdown";
+ }
+ {
+ package = systemd;
+ command = "systemctl";
+ }
+ {
+ package = util-linux;
+ command = "dmesg";
+ }
+ ]
+ );
+ }
+ ];
+ };
+ };
+}
diff --git a/modules/pc/software/access/default.nix b/modules/pc/software/access/default.nix
new file mode 100644
index 0000000..32d5500
--- /dev/null
+++ b/modules/pc/software/access/default.nix
@@ -0,0 +1,6 @@
+{
+ imports = [
+ ./gnupg.nix
+ ./ssh.nix
+ ];
+}
diff --git a/modules/pc/software/access/gnupg.nix b/modules/pc/software/access/gnupg.nix
new file mode 100644
index 0000000..e60da30
--- /dev/null
+++ b/modules/pc/software/access/gnupg.nix
@@ -0,0 +1,18 @@
+{ pkgs, ... }:
+{
+ programs.gnupg.agent = {
+ enable = true;
+ enableSSHSupport = true;
+ pinentryPackage = pkgs.pinentry-curses;
+ enableExtraSocket = true;
+ enableBrowserSocket = true;
+
+ settings = {
+ enable-ssh-support = "";
+ ttyname = "$GPG_TTY";
+ default-cache-ttl = 34560000; # 60
+ max-cache-ttl = 34560000; # 120
+ allow-loopback-pinentry = "";
+ };
+ };
+}
diff --git a/modules/pc/software/access/ssh.nix b/modules/pc/software/access/ssh.nix
new file mode 100644
index 0000000..b514049
--- /dev/null
+++ b/modules/pc/software/access/ssh.nix
@@ -0,0 +1,11 @@
+{ lib, config, ... }:
+{
+ programs.ssh.startAgent = false;
+ security.pam.sshAgentAuth.enable = true;
+
+ services.fail2ban.jails.sshd.settings = {
+ enabled = true;
+ filter = "sshd[mode=aggressive]";
+ port = lib.strings.concatStringsSep "," (map toString config.services.openssh.ports);
+ };
+}
diff --git a/modules/pc/software/default.nix b/modules/pc/software/default.nix
new file mode 100644
index 0000000..8638a58
--- /dev/null
+++ b/modules/pc/software/default.nix
@@ -0,0 +1,34 @@
+{ pkgs, secrets, ... }:
+{
+ imports = [
+ ./access
+ ./desktop
+ ./multimedia
+ ./services
+ ./encryption.nix
+ ./input.nix
+ ./shell.nix
+ ./users.nix
+ ];
+
+ environment.enableAllTerminfo = true;
+
+ system = {
+ autoUpgrade = {
+ enable = false;
+ allowReboot = false;
+ };
+
+ switch = {
+ enable = false;
+ enableNg = true;
+ };
+ };
+
+ console = {
+ earlySetup = true;
+ font = "ter-v16n";
+ keyMap = secrets.i18n.keymap;
+ packages = [ pkgs.terminus_font ];
+ };
+}
diff --git a/modules/pc/software/desktop/default.nix b/modules/pc/software/desktop/default.nix
new file mode 100644
index 0000000..bd2c811
--- /dev/null
+++ b/modules/pc/software/desktop/default.nix
@@ -0,0 +1,6 @@
+{
+ imports = [
+ ./gtk.nix
+ ./xdg-portal.nix
+ ];
+}
diff --git a/modules/pc/software/desktop/gtk.nix b/modules/pc/software/desktop/gtk.nix
new file mode 100644
index 0000000..4357e75
--- /dev/null
+++ b/modules/pc/software/desktop/gtk.nix
@@ -0,0 +1,8 @@
+{ pkgs, ... }:
+{
+ environment.systemPackages = with pkgs; [
+ gtk2
+ gtk3
+ gtk4
+ ];
+}
diff --git a/modules/pc/software/desktop/xdg-portal.nix b/modules/pc/software/desktop/xdg-portal.nix
new file mode 100644
index 0000000..72bcb97
--- /dev/null
+++ b/modules/pc/software/desktop/xdg-portal.nix
@@ -0,0 +1,15 @@
+{ pkgs, ... }:
+{
+ xdg.portal = {
+ enable = true;
+ config.common.default = "*";
+ # wlr.enable = true;
+ # xdgOpenUsePortal = true;
+
+ extraPortals = with pkgs; [
+ xdg-desktop-portal-wlr
+ xdg-desktop-portal-gtk
+ xdg-desktop-portal-gnome
+ ];
+ };
+}
diff --git a/modules/pc/software/encryption.nix b/modules/pc/software/encryption.nix
new file mode 100644
index 0000000..53a24bb
--- /dev/null
+++ b/modules/pc/software/encryption.nix
@@ -0,0 +1,16 @@
+{
+ boot = {
+ initrd.availableKernelModules = [
+ # "aesni_intel"
+ # "cryptd"
+ "usb_storage"
+ ];
+
+ # <https://wiki.archlinux.org/title/Dm-crypt/System_configuration#Timeout>
+ kernelParams = [
+ "luks.options=timeout=0"
+ "rd.luks.options=timeout=0"
+ "rootflags=x-systemd.device-timeout=0"
+ ];
+ };
+}
diff --git a/modules/pc/software/input.nix b/modules/pc/software/input.nix
new file mode 100644
index 0000000..5d43085
--- /dev/null
+++ b/modules/pc/software/input.nix
@@ -0,0 +1,23 @@
+{ pkgs, ... }:
+{
+ i18n = {
+ inputMethod = {
+ enable = true;
+ type = "fcitx5";
+
+ fcitx5 = {
+ waylandFrontend = true;
+
+ addons = with pkgs; [
+ fcitx5-configtool
+ fcitx5-gtk
+ fcitx5-hangul
+ fcitx5-mozc
+ fcitx5-rime
+ rime-data
+ catppuccin-fcitx5
+ ];
+ };
+ };
+ };
+}
diff --git a/modules/pc/software/multimedia/audio/default.nix b/modules/pc/software/multimedia/audio/default.nix
new file mode 100644
index 0000000..f4e7f0a
--- /dev/null
+++ b/modules/pc/software/multimedia/audio/default.nix
@@ -0,0 +1,6 @@
+{
+ imports = [
+ ./pipewire.nix
+ # ./wireplumber.nix
+ ];
+}
diff --git a/modules/pc/software/multimedia/audio/pipewire.nix b/modules/pc/software/multimedia/audio/pipewire.nix
new file mode 100644
index 0000000..2824176
--- /dev/null
+++ b/modules/pc/software/multimedia/audio/pipewire.nix
@@ -0,0 +1,164 @@
+# { lib, ... }:
+# let
+# inherit (lib.modules) mkBefore;
+# inherit (lib.lists) singleton;
+# inherit (builtins) toString;
+# mapOptionDefault = lib.attrsets.mapAttrs (_: lib.modules.mkOptionDefault);
+# quantum = toString 64;
+# rate = toString 48000;
+# qr = "${quantum}/${rate}";
+# in
+{
+ services.pipewire = {
+ enable = true;
+ wireplumber.enable = true;
+ jack.enable = true;
+ pulse.enable = true;
+ audio.enable = true;
+
+ alsa = {
+ enable = true;
+ support32Bit = true;
+ };
+
+ extraConfig = {
+ pipewire = {
+ "10-logging" = {
+ "context.properties"."log.level" = 3;
+ };
+
+ # "10-defaults" = {
+ # "context.properties" = mapOptionDefault {
+ # "clock.power-of-two-quantum" = true;
+ # "core.daemon" = true;
+ # "core.name" = "pipewire-0";
+ # "link.max-buffers" = 16;
+ # "settings.check-quantum" = true;
+ # };
+
+ # "context.spa-libs" = mapOptionDefault {
+ # "audio.convert.*" = "audioconvert/libspa-audioconvert";
+ # "avb.*" = "avb/libspa-avb";
+ # "api.alsa.*" = "alsa/libspa-alsa";
+ # "api.v4l2.*" = "v4l2/libspa-v4l2";
+ # "api.libcamera.*" = "libcamera/libspa-libcamera";
+ # "api.bluez5.*" = "bluez5/libspa-bluez5";
+ # "api.vulkan.*" = "vulkan/libspa-vulkan";
+ # "api.jack.*" = "jack/libspa-jack";
+ # "support.*" = "support/libspa-support";
+ # "video.convert.*" = "videoconvert/libspa-videoconvert";
+ # };
+ # };
+ };
+
+ # pipewire-pulse = {
+ # "10-defaults" = {
+ # "context.spa-libs" = mapOptionDefault {
+ # "audio.convert.*" = "audioconvert/libspa-audioconvert";
+ # "support.*" = "support/libspa-support";
+ # };
+
+ # "pulse.cmd" = mkBefore [
+ # {
+ # cmd = "load-module";
+ # args = "module-always-sink";
+ # flags = [ ];
+ # }
+ # ];
+
+ # "pulse.properties" = {
+ # "server.address" = mkBefore [ "unix:native" ];
+ # };
+
+ # "pulse.rules" = mkBefore [
+ # {
+ # matches = [
+ # { "application.process.binary" = "teams"; }
+ # { "application.process.binary" = "teams-insiders"; }
+ # { "application.process.binary" = "skypeforlinux"; }
+ # ];
+
+ # actions.quirks = [ "force-s16-info" ];
+ # }
+ # {
+ # matches = singleton { "application.process.binary" = "firefox"; };
+ # actions.quirks = [ "remove-capture-dont-move" ];
+ # }
+ # {
+ # matches = singleton { "application.name" = "~speech-dispatcher*"; };
+
+ # actions = {
+ # update-props = {
+ # "pulse.min.req" = "1024/48000"; # 21 milliseconds
+ # "pulse.min.quantum " = "1024/48000"; # 21 milliseconds
+ # };
+ # };
+ # }
+ # ];
+ # };
+ # };
+
+ # pipewire."92-low-latency" = {
+ # "context.properties" = {
+ # "default.clock.rate" = rate;
+ # "default.clock.quantum" = quantum;
+ # "default.clock.min-quantum" = quantum;
+ # "default.clock.max-quantum" = quantum;
+ # "default.clock.allowed-rates" = [ rate ];
+ # };
+
+ # # "context.modules" = [
+ # # {
+ # # name = "libpipewire-module-rtkit";
+
+ # # flags = [
+ # # "ifexists"
+ # # "nofail"
+ # # ];
+
+ # # args = {
+ # # "nice.level" = -15;
+ # # "rt.prio" = 90;
+ # # "rt.time.soft" = 200000;
+ # # "rt.time.hard" = 200000;
+ # # };
+ # # }
+ # # {
+ # # name = "libpipewire-module-protocol-pulse";
+
+ # # args = {
+ # # "server.address" = [ "unix:native" ];
+ # # "pulse.min.quantum" = qr;
+ # # "pulse.min.req" = qr;
+ # # "pulse.min.frag" = qr;
+ # # };
+ # # }
+ # # ];
+
+ # "stream.properties" = {
+ # "node.latency" = qr;
+ # "resample.quality" = 1;
+ # };
+ # };
+
+ # pipewire-pulse."92-low-latency" = {
+ # "context.modules" = singleton {
+ # name = "libpipewire-module-protocol-pulse";
+
+ # args = {
+ # "pulse.min.req" = qr;
+ # "pulse.default.req" = qr;
+ # "pulse.max.req" = qr;
+ # "pulse.min.quantum" = qr;
+ # "pulse.max.quantum" = qr;
+ # };
+ # };
+
+ # "stream.properties" = {
+ # "node.latency" = qr;
+ # "resample.quality" = 4;
+ # };
+ # };
+ };
+ };
+}
diff --git a/modules/pc/software/multimedia/audio/wireplumber.nix b/modules/pc/software/multimedia/audio/wireplumber.nix
new file mode 100644
index 0000000..970396f
--- /dev/null
+++ b/modules/pc/software/multimedia/audio/wireplumber.nix
@@ -0,0 +1,42 @@
+let
+ rate = builtins.toString 48000;
+in
+{
+ services.pipewire.wireplumber = {
+ enable = true;
+
+ extraConfig = {
+ "10-log-level-debug" = {
+ "context.properties"."log.level" = "D";
+ };
+
+ "10-default-volume" = {
+ "wireplumber.settings"."device.routes.default-sink-volume" = 1.0;
+ };
+
+ "92-low-latency" = {
+ "monitor.alsa.rules" = [
+ {
+ matches = [
+ { "device.name" = "~alsa_card.*"; }
+ { "node.name" = "~alsa_output.*"; }
+ ];
+
+ actions.update-props = {
+ "node.description" = "ALSA Low Latency Output";
+ "audio.rate" = rate;
+ "audio.format" = "S32LE";
+ "resample.quality" = 4;
+ "resample.disable" = false;
+ "session.suspend-timeout-seconds" = 0;
+ "api.alsa.period-size" = 2;
+ "api.alsa.headroom" = 128;
+ "api.alsa.period-num" = 2;
+ "api.alsa.disable-batch" = false;
+ };
+ }
+ ];
+ };
+ };
+ };
+}
diff --git a/modules/pc/software/multimedia/default.nix b/modules/pc/software/multimedia/default.nix
new file mode 100644
index 0000000..7bf261a
--- /dev/null
+++ b/modules/pc/software/multimedia/default.nix
@@ -0,0 +1,6 @@
+{
+ imports = [
+ ./audio
+ ./video
+ ];
+}
diff --git a/modules/pc/software/multimedia/video/default.nix b/modules/pc/software/multimedia/video/default.nix
new file mode 100644
index 0000000..94aa42d
--- /dev/null
+++ b/modules/pc/software/multimedia/video/default.nix
@@ -0,0 +1,9 @@
+{ pkgs, ... }:
+{
+ imports = [
+ ./vulkan.nix
+ ./xserver.nix
+ ];
+
+ environment.systemPackages = [ pkgs.mediastreamer-openh264 ];
+}
diff --git a/modules/pc/software/multimedia/video/vulkan.nix b/modules/pc/software/multimedia/video/vulkan.nix
new file mode 100644
index 0000000..be37e0e
--- /dev/null
+++ b/modules/pc/software/multimedia/video/vulkan.nix
@@ -0,0 +1,9 @@
+{ pkgs, ... }:
+{
+ environment.systemPackages = with pkgs; [
+ vulkan-loader
+ vulkan-validation-layers
+ vulkan-tools
+ vulkan-extension-layer
+ ];
+}
diff --git a/modules/pc/software/multimedia/video/xserver.nix b/modules/pc/software/multimedia/video/xserver.nix
new file mode 100644
index 0000000..9c16f4c
--- /dev/null
+++ b/modules/pc/software/multimedia/video/xserver.nix
@@ -0,0 +1,6 @@
+{
+ services.xserver.xkb = {
+ layout = "us";
+ options = "caps:escape";
+ };
+}
diff --git a/modules/pc/software/services/adb.nix b/modules/pc/software/services/adb.nix
new file mode 100644
index 0000000..d106ead
--- /dev/null
+++ b/modules/pc/software/services/adb.nix
@@ -0,0 +1,12 @@
+{ pkgs, ... }:
+{
+ programs.adb.enable = true;
+
+ services.udev = {
+ packages = [ pkgs.android-udev-rules ];
+
+ extraRules = ''
+ SUBSYSTEM=="usb", ATTR{idVendor}=="04e8", MODE="0666", GROUP="adbusers"
+ '';
+ };
+}
diff --git a/modules/pc/software/services/ananicy.nix b/modules/pc/software/services/ananicy.nix
new file mode 100644
index 0000000..bdc9bbd
--- /dev/null
+++ b/modules/pc/software/services/ananicy.nix
@@ -0,0 +1,8 @@
+{ pkgs, ... }:
+{
+ services.ananicy = {
+ enable = false;
+ package = pkgs.ananicy-cpp;
+ rulesProvider = pkgs.ananicy-rules-cachyos;
+ };
+}
diff --git a/modules/pc/software/services/dbus.nix b/modules/pc/software/services/dbus.nix
new file mode 100644
index 0000000..8b25bf9
--- /dev/null
+++ b/modules/pc/software/services/dbus.nix
@@ -0,0 +1,15 @@
+{ pkgs, ... }:
+{
+ services.dbus = {
+ enable = true;
+ implementation = "broker";
+
+ packages = with pkgs; [
+ dconf
+ gcr
+ udisks2
+ # flatpak
+ # xdg-desktop-portal
+ ];
+ };
+}
diff --git a/modules/pc/software/services/default.nix b/modules/pc/software/services/default.nix
new file mode 100644
index 0000000..92baa54
--- /dev/null
+++ b/modules/pc/software/services/default.nix
@@ -0,0 +1,22 @@
+{ pkgs, ... }:
+{
+ imports = [
+ # ./adb.nix
+ ./ananicy.nix
+ ./dbus.nix
+ ./logrotate.nix
+ # ./printing.nix
+ ];
+
+ services = {
+ printing.enable = false;
+ gnome.gnome-keyring.enable = true;
+ fstrim.enable = false;
+ gvfs.enable = true;
+ udev.packages = [ pkgs.logitech-udev-rules ];
+ thermald.enable = true;
+ irqbalance.enable = true;
+ gpm.enable = true;
+ libinput.enable = true;
+ };
+}
diff --git a/modules/pc/software/services/logrotate.nix b/modules/pc/software/services/logrotate.nix
new file mode 100644
index 0000000..2dedf2e
--- /dev/null
+++ b/modules/pc/software/services/logrotate.nix
@@ -0,0 +1,24 @@
+{ pkgs, lib, ... }:
+{
+ services.logrotate.settings = {
+ "/var/log/audit/audit.log" = { };
+
+ header = {
+ global = true;
+ dateext = true;
+ dateformat = "-%Y-%m-%d";
+ nomail = true;
+ missingok = true;
+ copytruncate = true;
+ priority = 1;
+ frequency = "daily";
+ rotate = 7;
+ minage = 1;
+ compress = true;
+ compresscmd = "${lib.getExe' pkgs.zstd "zstd"}";
+ compressoptions = " -Xcompression-level 10";
+ compressext = "zst";
+ uncompresscmd = "${lib.getExe' pkgs.zstd "unzstd"}";
+ };
+ };
+}
diff --git a/modules/pc/software/services/printing.nix b/modules/pc/software/services/printing.nix
new file mode 100644
index 0000000..f7a38de
--- /dev/null
+++ b/modules/pc/software/services/printing.nix
@@ -0,0 +1,19 @@
+{ pkgs, ... }:
+{
+ services = {
+ printing = {
+ enable = true;
+
+ drivers = with pkgs; [
+ gutenprint
+ hplip
+ ];
+ };
+
+ avahi = {
+ enable = true;
+ nssmdns4 = true;
+ openFirewall = true;
+ };
+ };
+}
diff --git a/modules/pc/software/shell.nix b/modules/pc/software/shell.nix
new file mode 100644
index 0000000..0b3508f
--- /dev/null
+++ b/modules/pc/software/shell.nix
@@ -0,0 +1,7 @@
+{ pkgs, ... }:
+{
+ environment = with pkgs; {
+ binsh = "${dash}/bin/dash";
+ shells = [ fish ];
+ };
+}
diff --git a/modules/pc/software/users.nix b/modules/pc/software/users.nix
new file mode 100644
index 0000000..ab3fe03
--- /dev/null
+++ b/modules/pc/software/users.nix
@@ -0,0 +1,46 @@
+{ pkgs, secrets, ... }:
+let
+ initialHashedPassword = secrets.initial_hashed_password;
+in
+{
+ users = {
+ mutableUsers = false;
+
+ users = {
+ root = {
+ inherit initialHashedPassword;
+
+ shell = pkgs.bash;
+ };
+
+ ebisu = {
+ inherit initialHashedPassword;
+
+ isNormalUser = true;
+ shell = pkgs.fish;
+
+ extraGroups = [
+ "wheel"
+ "systemd-journal"
+ "audio"
+ "video"
+ "input"
+ "plugdev"
+ "lp"
+ "tss"
+ "power"
+ "nix"
+ "network"
+ "networkmanager"
+ "wireshark"
+ "mysql"
+ "docker"
+ "podman"
+ "git"
+ "libvirtd"
+ "kvm"
+ ];
+ };
+ };
+ };
+}
diff --git a/modules/pc/variables/default.nix b/modules/pc/variables/default.nix
new file mode 100644
index 0000000..1a0e958
--- /dev/null
+++ b/modules/pc/variables/default.nix
@@ -0,0 +1,11 @@
+{
+ imports = [ ./fcitx.nix ];
+
+ environment.variables = {
+ _JAVA_AWT_WM_NONREPARENTING = "1";
+ PROTON_ENABLE_NGX_UPDATER = "1";
+ GTK_USE_PORTAL = "1";
+ DIRENV_LOG_FORMAT = "";
+ SSH_AUTH_SOCK = "/run/user/1000/keyring/ssh";
+ };
+}
diff --git a/modules/pc/variables/fcitx.nix b/modules/pc/variables/fcitx.nix
new file mode 100644
index 0000000..0ac550f
--- /dev/null
+++ b/modules/pc/variables/fcitx.nix
@@ -0,0 +1,13 @@
+{
+ environment.variables = {
+ # https://fcitx-im.org/wiki/Using_Fcitx_5_on_Wayland
+ QT_IM_MODULE = "fcitx";
+ XMODIFIERS = "@im=fcitx";
+ # GTK_IM_MODULE = "wayland";
+ # GTK_IM_MODULE = "fcitx";
+ SDL_IM_MODULE = "fcitx";
+ GLFW_IM_MODULE = "ibus";
+ INPUT_METHOD = "fcitx";
+ CUDA_CACHE_PATH = "$XDG_CACHE_HOME/nv";
+ };
+}