Compare commits
184 Commits
wip-polyun
...
test-nm-ni
Author | SHA1 | Date | |
---|---|---|---|
d629db4e45 | |||
f5e5d1bcc4 | |||
30d41f82f2 | |||
62dbad3486 | |||
4287ecf0ed | |||
b13ca92b72 | |||
45e121eb1c | |||
53bbd611da | |||
f0128b9496 | |||
368169d48d | |||
cb1d5d53c6 | |||
a5a635f00b | |||
6fe3d26b30 | |||
8340cf059f | |||
e0da3ece60 | |||
8ea379d53b | |||
c7dd49af91 | |||
e8b900c722 | |||
36f4fa3018 | |||
d8d11de9bc | |||
07194d062a | |||
24c49df75f | |||
9f7e143d5e | |||
0a382ae8a3 | |||
96f177ceb2 | |||
2aa3fa35b8 | |||
8657cf1fcf | |||
f875db916d | |||
e3e86a43a9 | |||
05986d363d | |||
539d9e45a2 | |||
a380bd04c4 | |||
f296d8df93 | |||
326bf045b0 | |||
a1181a10ea | |||
9bb6a903bb | |||
214f963d89 | |||
c7eb4b66a5 | |||
452543e6f3 | |||
d692ac9851 | |||
5cba283859 | |||
7a701f92eb | |||
3c3a32e436 | |||
07aec3ca3c | |||
58d5f11c7a | |||
ed2d4ef488 | |||
e8f8866032 | |||
a2dfd8f08e | |||
c7fd3d2217 | |||
0fcc3f8d5d | |||
0bb887158b | |||
6570c5ed84 | |||
820fdecfd5 | |||
8d43565f31 | |||
18364761dd | |||
d3937487e6 | |||
3fdeacc336 | |||
847414ac1f | |||
84f2006115 | |||
7f5e12da8d | |||
afa8a3c52e | |||
bfbcb4789b | |||
2531cc1cf6 | |||
e55b75c333 | |||
adb54657d4 | |||
6eefb9ce20 | |||
2233622bb7 | |||
274a7821a7 | |||
4c84d1a727 | |||
175acf6442 | |||
0761b6135a | |||
66c899d099 | |||
4aeb3360d3 | |||
0c456d11d8 | |||
3b73773169 | |||
9ba8ff738b | |||
f1d397940f | |||
fa94fa8e6c | |||
4b9c125c8c | |||
0f7d25d8a5 | |||
140641729e | |||
32124d76bf | |||
c5c174f988 | |||
29bc1608aa | |||
635ca1e5d8 | |||
2789868703 | |||
c40ec1990a | |||
d4dfcd6510 | |||
d865be952a | |||
7c8a18ecbd | |||
35ff7de06e | |||
00d06db66a | |||
c570b7bf5d | |||
770fc2e574 | |||
0ed7eb24fb | |||
ad8e75b6a3 | |||
e8dbe0750d | |||
1378988f21 | |||
b88467771e | |||
4309d887da | |||
1ee21c4795 | |||
fb7bcbb5f5 | |||
0013e8305e | |||
7dedfcebb9 | |||
753b97ffb4 | |||
247fc1f887 | |||
3c2ca46ef9 | |||
95dc395925 | |||
cefd6c0534 | |||
05efec8fd7 | |||
e8846b2d6b | |||
be38d56717 | |||
7d242ab02c | |||
47611eaa26 | |||
9719f0f785 | |||
8042ea76e6 | |||
c59236509b | |||
50e5206b0e | |||
4ba0343315 | |||
cbe6072c03 | |||
bea1fd95e5 | |||
ae544c0649 | |||
b571f70988 | |||
e6498ad152 | |||
976b8ae45e | |||
ab7c4d7410 | |||
d2c3bec98e | |||
3c5e5632ee | |||
dcedb8d3f0 | |||
8586db59f1 | |||
1f4d500b02 | |||
56b846023b | |||
747d6c876d | |||
f38d2d52d2 | |||
04bbf54385 | |||
f2271180dd | |||
60b1ab1429 | |||
db3636641d | |||
54a891504d | |||
8ea5061bef | |||
b6d19a7a09 | |||
439be20be7 | |||
a024f685c3 | |||
9c20cef6ea | |||
abb65e55c6 | |||
a2d385708f | |||
f6f1a6e136 | |||
7941a8b1ed | |||
bbcf8841ea | |||
063b0be5b6 | |||
7e490f5c07 | |||
10a985e7f9 | |||
f3c3df2ca7 | |||
f477604063 | |||
d46fa8a242 | |||
62b2eb874c | |||
133c1b3699 | |||
1b4300dbeb | |||
a1c1a87dd8 | |||
92b9a56894 | |||
b159240b7f | |||
8a9f96eefc | |||
af5aa15c23 | |||
a03099569c | |||
b1c7061b21 | |||
c528bb3ec9 | |||
002639cc76 | |||
45967fde7b | |||
ed97a81ef3 | |||
f158842c70 | |||
90d428be7f | |||
9d7b68eeb4 | |||
8951df2e2c | |||
3a045f4d88 | |||
57d6a9a4c3 | |||
2ee39ca0cc | |||
9d9211c5fa | |||
9ce7dcd57a | |||
af72f312d3 | |||
efa1ee6c69 | |||
6a15434cc6 | |||
59e4256dd8 | |||
6365bb7594 | |||
8cb73687ce |
@@ -16,7 +16,6 @@ building [hosts/](./hosts/) will require [sops][sops].
|
||||
|
||||
you might specifically be interested in these files (elaborated further in #key-points-of-interest):
|
||||
- ~~[`sxmo-utils`](./pkgs/additional/sxmo-utils/default.nix)~~
|
||||
- ~~[example SXMO deployment](./hosts/modules/gui/sxmo/default.nix)~~
|
||||
- these files will remain until my config settles down, but i no longer use or maintain SXMO.
|
||||
- [my implementation of impermanence](./modules/persist/default.nix)
|
||||
- my way of deploying dotfiles/configuring programs per-user:
|
||||
|
29
TODO.md
29
TODO.md
@@ -1,13 +1,13 @@
|
||||
## BUGS
|
||||
- moby: megapixels doesn't load in sandbox
|
||||
- `rmDbusServices` may break sandboxing
|
||||
- e.g. if the package ships a systemd unit which references $out, then make-sandboxed won't properly update that unit.
|
||||
- `rmDbusServicesInPlace` is not affected
|
||||
- moby: touchscreen input is still enabled when screen is off
|
||||
- when moby wlan is explicitly set down (via ip link set wlan0 down), /var/lib/trust-dns/dhcp-configs doesn't get reset
|
||||
- `ip monitor` can detect those manual link state changes (NM-dispatcher it seems cannot)
|
||||
- or try dnsmasq?
|
||||
- trust-dns: can't recursively resolve api.mangadex.org
|
||||
- and *sometimes* apple.com fails
|
||||
- wg-ovpnd-* interfaces don't work, because i use the same keys across all hosts...
|
||||
- and if i had them differ and simultaneously online, then i'd exceed the OVPN machine count.
|
||||
- i should at least have them be up'd only on-demand.
|
||||
- sandbox: link cache means that if i update ~/.config/... files inline, sandboxed programs still see the old version
|
||||
- mpv: audiocast has mpv sending its output to the builtin speakers unless manually changed
|
||||
- mpv: no way to exit fullscreen video on moby
|
||||
@@ -16,7 +16,6 @@
|
||||
- decrease s6 restart time?
|
||||
- `ssh` access doesn't grant same linux capabilities as login
|
||||
- ringer (i.e. dino incoming call) doesn't prevent moby from sleeping
|
||||
- sway mouse/kb hotplug doesn't work
|
||||
- sysvol (volume overlay): when casting with `blast`, sysvol doesn't react to volume changes
|
||||
- moby: kaslr is effectively disabled
|
||||
- `dmesg | grep "KASLR disabled due to lack of seed"`
|
||||
@@ -28,7 +27,7 @@
|
||||
- `dmesg | grep 'hid_bpf: error while preloading HID BPF dispatcher: -22'`
|
||||
|
||||
## REFACTORING:
|
||||
- REMOVE DEPRECATED `crypt` from sftpgo_auth_hook
|
||||
- add import checks to my Python nix-shell scripts
|
||||
- consolidate ~/dev and ~/ref
|
||||
- ~/dev becomes a link to ~/ref/cat/mine
|
||||
- fold hosts/common/home/ssh.nix -> hosts/common/users/colin.nix
|
||||
@@ -53,6 +52,10 @@
|
||||
## IMPROVEMENTS:
|
||||
- systemd/journalctl: use a less shit pager
|
||||
- there's an env var for it: SYSTEMD_PAGER? and a flag for journalctl
|
||||
- kernels: ship the same kernel on every machine
|
||||
- then i can tune the kernels for hardening, without duplicating that work 4 times
|
||||
- zfs: replace this with something which doesn't require a custom kernel build
|
||||
- mpv: add media looping controls (e.g. loop song, loop playlist)
|
||||
|
||||
### security/resilience
|
||||
- validate duplicity backups!
|
||||
@@ -73,14 +76,15 @@
|
||||
- limit access to `~/knowledge/secrets` through an agent that requires GUI approval, so a firefox exploit can't steal all my logins
|
||||
- port sanebox to a compiled language (hare?)
|
||||
- it adds like 50-70ms launch time _on my laptop_. i'd hate to know how much that is on the pinephone.
|
||||
- remove /run/wrappers from the sandbox path
|
||||
- they're mostly useless when using no-new-privs, just an opportunity to forget to specify deps
|
||||
- make dconf stuff less monolithic
|
||||
- i.e. per-app dconf profiles for those which need it. possible static config.
|
||||
- canaries for important services
|
||||
- e.g. daily email checks; daily backup checks
|
||||
- integrate `nix check` into Gitea actions?
|
||||
|
||||
#### sudo-free world
|
||||
- `systemctl restart FOO`: needs `sudo`
|
||||
|
||||
### user experience
|
||||
- rofi: sort items case-insensitively
|
||||
- xdg-desktop-portal shouldn't kill children on exit
|
||||
@@ -95,7 +99,7 @@
|
||||
- offline docs viewer (gtk): <https://github.com/workbenchdev/Biblioteca>
|
||||
- some type of games manager/launcher
|
||||
- Gnome Highscore (retro games)?: <https://gitlab.gnome.org/World/highscore>
|
||||
- better maps for mobile (Osmin (QtQuick)? Pure Maps (Qt/Kirigami)? Gnome Maps is improved in 45)
|
||||
- better maps for mobile (Osmin (QtQuick)? Pure Maps (Qt/Kirigami)?
|
||||
- note-taking app: <https://linuxphoneapps.org/categories/note-taking/>
|
||||
- OSK overlay specifically for mobile gaming
|
||||
- i.e. mock joysticks, for use with SuperTux and SuperTuxKart
|
||||
@@ -124,6 +128,7 @@
|
||||
- direct mepo to prefer gpsd, with fallback to geoclue, for better accuracy?
|
||||
- configure geoclue to do some smoothing?
|
||||
- manually do smoothing, as some layer between mepo and geoclue/gpsd?
|
||||
- moby: port `freshen-agps` timer service to s6 (maybe i want some `s6-cron` or something)
|
||||
- moby: show battery state on ssh login
|
||||
- moby: improve gPodder launch time
|
||||
- moby: theme GTK apps (i.e. non-adwaita styles)
|
||||
@@ -131,8 +136,6 @@
|
||||
- try Gradience tool specifically for theming adwaita? <https://linuxphoneapps.org/apps/com.github.gradienceteam.gradience/>
|
||||
|
||||
#### non-moby
|
||||
- sane-tag-music: integrate `beets`/<https://beets.io/>
|
||||
- this should be able to auto-tag a large part of my library
|
||||
- RSS: integrate a paywall bypass
|
||||
- e.g. self-hosted [ladder](https://github.com/everywall/ladder) (like 12ft.io)
|
||||
- neovim: set up language server (lsp; rnix-lsp; nvim-lspconfig)
|
||||
@@ -154,6 +157,10 @@
|
||||
|
||||
### perf
|
||||
- debug nixos-rebuild times
|
||||
- use `systemctl list-jobs` to show what's being waited on
|
||||
- i think it's `systemd-networkd-wait-online.service` that's blocking this?
|
||||
- i wonder what interface it's waiting for. i should use `--ignore=...` to ignore interfaces i don't care about.
|
||||
- also `wireguard-wg-home.target` when net is offline
|
||||
- add `pkgs.impure-cached.<foo>` package set to build things with ccache enabled
|
||||
- every package here can be auto-generated, and marked with some env var so that it doesn't pollute the pure package set
|
||||
- would be super handy for package prototyping!
|
||||
|
42
flake.lock
generated
42
flake.lock
generated
@@ -61,11 +61,11 @@
|
||||
"nixpkgs-lib": "nixpkgs-lib"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1716120557,
|
||||
"narHash": "sha256-rvNq9YolMY1DRMgwdAti8qwNDjkhTsotSWa15/Ch7+A=",
|
||||
"lastModified": 1716725378,
|
||||
"narHash": "sha256-bNTVDAVBLFSSTU+q54cJnntmFKBi+F/D8sSqlZwBGiM=",
|
||||
"owner": "nix-community",
|
||||
"repo": "lib-aggregate",
|
||||
"rev": "5fa64b174daa22fe0d20ebbcc0ec2c7905b503f1",
|
||||
"rev": "dbc9130fe1455e0f6ee4d8f5f799f9be551f866b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -152,11 +152,11 @@
|
||||
},
|
||||
"nixpkgs-lib": {
|
||||
"locked": {
|
||||
"lastModified": 1716079763,
|
||||
"narHash": "sha256-DGRfb7fO7c3XDS3twmuaV5NAGPPdU3W7Q35fjIZc8iY=",
|
||||
"lastModified": 1716684580,
|
||||
"narHash": "sha256-sIbMJWJr4hl2PWd9/iWlh89QfVzBn1NJ3u5RjeZADuM=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nixpkgs.lib",
|
||||
"rev": "0df131b5ee4d928a4b664b6d0cd99cf134d6ab6b",
|
||||
"rev": "d0d27192931680482081aa1c38389da2af84a651",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -167,11 +167,11 @@
|
||||
},
|
||||
"nixpkgs-next-unpatched": {
|
||||
"locked": {
|
||||
"lastModified": 1716573668,
|
||||
"narHash": "sha256-K+8vYJtu7X+qQ1Q66kYTheq0IKKVyPMOMclY9oJYnS8=",
|
||||
"lastModified": 1717243271,
|
||||
"narHash": "sha256-M3VxP6DtREz5Lq6MKg1gQ2EeVdIbq6AEp/N1tDSrvoc=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "cc5c0d369b5e8f49705e2a2d7464e4b162804805",
|
||||
"rev": "f7de25c01e4c073c06e0525226a0c2311d530cee",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -183,11 +183,11 @@
|
||||
},
|
||||
"nixpkgs-stable": {
|
||||
"locked": {
|
||||
"lastModified": 1716061101,
|
||||
"narHash": "sha256-H0eCta7ahEgloGIwE/ihkyGstOGu+kQwAiHvwVoXaA0=",
|
||||
"lastModified": 1716655032,
|
||||
"narHash": "sha256-kQ25DAiCGigsNR/Quxm3v+JGXAEXZ8I7RAF4U94bGzE=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "e7cc61784ddf51c81487637b3031a6dd2d6673a2",
|
||||
"rev": "59a450646ec8ee0397f5fa54a08573e8240eb91f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -199,11 +199,11 @@
|
||||
},
|
||||
"nixpkgs-unpatched": {
|
||||
"locked": {
|
||||
"lastModified": 1716592782,
|
||||
"narHash": "sha256-aGafFFAkQwkiBXo+ocx4sCco+L233JqlUZhVfXceaQY=",
|
||||
"lastModified": 1717242134,
|
||||
"narHash": "sha256-2X835ZESUaQ/KZEuG9HkoEB7h0USG5uvkSUmLzFkxAE=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "2baa58d3488bd9cc4d53d6812509edc34a1c7e2a",
|
||||
"rev": "61c1d282153dbfcb5fe413c228d172d0fe7c2a7e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -223,11 +223,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1716589021,
|
||||
"narHash": "sha256-m7+ogvgw6tCk5P1H9OqS2yTFlZOus9I+Genv3PUWkno=",
|
||||
"lastModified": 1717175759,
|
||||
"narHash": "sha256-KiM5ue/UNQt8ktoqCV4yFqhHxM31U94Mf/piKW9dZ4c=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nixpkgs-wayland",
|
||||
"rev": "8746004cd97164c89f0997ea06642b819e5bc3fb",
|
||||
"rev": "93b225ddba91179248b378913a91defbc6aeb899",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -254,11 +254,11 @@
|
||||
"nixpkgs-stable": "nixpkgs-stable"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1716400300,
|
||||
"narHash": "sha256-0lMkIk9h3AzOHs1dCL9RXvvN4PM8VBKb+cyGsqOKa4c=",
|
||||
"lastModified": 1716692524,
|
||||
"narHash": "sha256-sALodaA7Zkp/JD6ehgwc0UCBrSBfB4cX66uFGTsqeFU=",
|
||||
"owner": "Mic92",
|
||||
"repo": "sops-nix",
|
||||
"rev": "b549832718b8946e875c016a4785d204fcfc2e53",
|
||||
"rev": "962797a8d7f15ed7033031731d0bb77244839960",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@@ -317,11 +317,8 @@
|
||||
commandArgv = pkg.updateScript.command or pkg.updateScript;
|
||||
command = pkgs.lib.escapeShellArgs commandArgv;
|
||||
in builtins.toString (pkgs.writeShellScript "update-${strAttrPath}" ''
|
||||
export UPDATE_NIX_NAME=${pkg.name}
|
||||
export UPDATE_NIX_PNAME=${pkg.pname}
|
||||
export UPDATE_NIX_OLD_VERSION=${pkg.version}
|
||||
export UPDATE_NIX_ATTR_PATH=${strAttrPath}
|
||||
${command}
|
||||
set -x
|
||||
env UPDATE_NIX_NAME=${pkg.name} UPDATE_NIX_PNAME=${pkg.pname} UPDATE_NIX_OLD_VERSION=${pkg.version} UPDATE_NIX_ATTR_PATH=${strAttrPath} ${command}
|
||||
'');
|
||||
};
|
||||
mkUpdatersNoAliases = opts: basePath: pkgs.lib.concatMapAttrs
|
||||
|
@@ -1,4 +1,4 @@
|
||||
{ config, pkgs, ... }:
|
||||
{ config, lib, pkgs, ... }:
|
||||
{
|
||||
imports = [
|
||||
./fs.nix
|
||||
@@ -11,6 +11,8 @@
|
||||
# don't enable wifi by default: it messes with connectivity.
|
||||
# systemd.services.iwd.enable = false;
|
||||
# systemd.services.wpa_supplicant.enable = false;
|
||||
sane.programs.wpa_supplicant.enableFor.user.colin = lib.mkForce false;
|
||||
sane.programs.wpa_supplicant.enableFor.system = lib.mkForce false;
|
||||
|
||||
sops.secrets.colin-passwd.neededForUsers = true;
|
||||
|
||||
@@ -20,11 +22,12 @@
|
||||
sane.roles.pc = true;
|
||||
sane.services.wg-home.enable = true;
|
||||
sane.services.wg-home.ip = config.sane.hosts.by-name."desko".wg-home.ip;
|
||||
sane.ovpn.addrV4 = "172.26.55.21";
|
||||
# sane.ovpn.addrV6 = "fd00:0000:1337:cafe:1111:1111:20c1:a73c";
|
||||
sane.services.duplicity.enable = true;
|
||||
|
||||
sane.nixcache.remote-builders.desko = false;
|
||||
|
||||
sane.programs.cups.enableFor.user.colin = true;
|
||||
sane.programs.sway.enableFor.user.colin = true;
|
||||
sane.programs.iphoneUtils.enableFor.user.colin = true;
|
||||
sane.programs.steam.enableFor.user.colin = true;
|
||||
|
@@ -9,12 +9,13 @@
|
||||
sane.roles.pc = true;
|
||||
sane.services.wg-home.enable = true;
|
||||
sane.services.wg-home.ip = config.sane.hosts.by-name."lappy".wg-home.ip;
|
||||
sane.ovpn.addrV4 = "172.23.119.72";
|
||||
# sane.ovpn.addrV6 = "fd00:0000:1337:cafe:1111:1111:0332:aa96/128";
|
||||
|
||||
# sane.guest.enable = true;
|
||||
boot.loader.efi.canTouchEfiVariables = false;
|
||||
sane.image.extraBootFiles = [ pkgs.bootpart-uefi-x86_64 ];
|
||||
|
||||
sane.programs.cups.enableFor.user.colin = true;
|
||||
sane.programs.stepmania.enableFor.user.colin = true;
|
||||
sane.programs.sway.enableFor.user.colin = true;
|
||||
|
||||
|
@@ -1,7 +1,4 @@
|
||||
# Pinephone
|
||||
# other setups to reference:
|
||||
# - <https://hamblingreen.gitlab.io/2022/03/02/my-pinephone-setup.html>
|
||||
# - sxmo Arch user. lots of app recommendations
|
||||
#
|
||||
# wikis, resources, ...:
|
||||
# - Linux Phone Apps: <https://linuxphoneapps.org/>
|
||||
@@ -24,6 +21,8 @@
|
||||
sane.programs.zsh.config.showDeadlines = false; # unlikely to act on them when in shell
|
||||
sane.services.wg-home.enable = true;
|
||||
sane.services.wg-home.ip = config.sane.hosts.by-name."moby".wg-home.ip;
|
||||
sane.ovpn.addrV4 = "172.24.87.255";
|
||||
# sane.ovpn.addrV6 = "fd00:0000:1337:cafe:1111:1111:18cd:a72b";
|
||||
|
||||
# XXX colin: phosh doesn't work well with passwordless login,
|
||||
# so set this more reliable default password should anything go wrong
|
||||
@@ -32,7 +31,6 @@
|
||||
|
||||
sops.secrets.colin-passwd.neededForUsers = true;
|
||||
|
||||
# sane.gui.sxmo.enable = true;
|
||||
sane.programs.sway.enableFor.user.colin = true;
|
||||
sane.programs.swaylock.enableFor.user.colin = false; #< not usable on touch
|
||||
sane.programs.schlock.enableFor.user.colin = true;
|
||||
|
@@ -267,7 +267,5 @@ in
|
||||
"lima.sched_timeout_ms=2000"
|
||||
];
|
||||
|
||||
# services.xserver.displayManager.job.preStart = ensureHWReady;
|
||||
# systemd.services.greetd.preStart = ensureHWReady;
|
||||
systemd.services.unl0kr.preStart = ensureHWReady;
|
||||
}
|
||||
|
@@ -28,6 +28,8 @@
|
||||
sane.services.wg-home.forwardToWan = true;
|
||||
sane.services.wg-home.routeThroughServo = false;
|
||||
sane.services.wg-home.ip = config.sane.hosts.by-name."servo".wg-home.ip;
|
||||
sane.ovpn.addrV4 = "172.23.174.114";
|
||||
# sane.ovpn.addrV6 = "fd00:0000:1337:cafe:1111:1111:8df3:14b0";
|
||||
sane.nixcache.remote-builders.desko = false;
|
||||
sane.nixcache.remote-builders.servo = false;
|
||||
# sane.services.duplicity.enable = true; # TODO: re-enable after HW upgrade
|
||||
|
@@ -15,6 +15,7 @@
|
||||
# - could maybe be done with some mount option?
|
||||
|
||||
{ config, lib, ... }:
|
||||
lib.mkIf false #< TODO: remove nfs altogether! it's not exactly the most secure
|
||||
{
|
||||
services.nfs.server.enable = true;
|
||||
|
||||
|
@@ -12,6 +12,7 @@ let
|
||||
external_auth_hook = pkgs.static-nix-shell.mkPython3Bin {
|
||||
pname = "external_auth_hook";
|
||||
srcRoot = ./.;
|
||||
pyPkgs = [ "passlib" ];
|
||||
};
|
||||
# Client initiates a FTP "control connection" on port 21.
|
||||
# - this handles the client -> server commands, and the server -> client status, but not the actual data
|
||||
@@ -59,18 +60,8 @@ in
|
||||
enable = true;
|
||||
group = "export";
|
||||
|
||||
package = lib.warnIf (lib.versionOlder "2.5.6" pkgs.sftpgo.version) "sftpgo update: safe to use nixpkgs' sftpgo but keep my own `patches`" pkgs.buildGoModule {
|
||||
inherit (pkgs.sftpgo) name ldflags nativeBuildInputs doCheck subPackages postInstall passthru meta;
|
||||
version = "2.5.6-unstable-2024-04-18";
|
||||
src = pkgs.fetchFromGitHub {
|
||||
# need to use > 2.5.6 for sftpgo_safe_fileinfo.patch to apply
|
||||
owner = "drakkan";
|
||||
repo = "sftpgo";
|
||||
rev = "950cf67e4c03a12c7e439802cabbb0b42d4ee5f5";
|
||||
hash = "sha256-UfiFd9NK3DdZ1J+FPGZrM7r2mo9xlKi0dsSlLEinYXM=";
|
||||
};
|
||||
vendorHash = "sha256-n1/9A2em3BCtFX+132ualh4NQwkwewMxYIMOphJEamg=";
|
||||
patches = (pkgs.sftpgo.patches or []) ++ [
|
||||
package = pkgs.sftpgo.overrideAttrs (upstream: {
|
||||
patches = (upstream.patches or []) ++ [
|
||||
# fix for compatibility with kodi:
|
||||
# ftp LIST operation returns entries over-the-wire like:
|
||||
# - dgrwxrwxr-x 1 ftp ftp 9 Apr 9 15:05 Videos
|
||||
@@ -79,7 +70,7 @@ in
|
||||
# the full set of bits, from which i filter, is found here: <https://pkg.go.dev/io/fs#FileMode>
|
||||
./safe_fileinfo.patch
|
||||
];
|
||||
};
|
||||
});
|
||||
|
||||
settings = {
|
||||
ftpd = {
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i python3 -p "python3.withPackages (ps: [ ])"
|
||||
#!nix-shell -i python3 -p "python3.withPackages (ps: [ ps.passlib ])"
|
||||
# vim: set filetype=python :
|
||||
#
|
||||
# available environment variables:
|
||||
@@ -37,9 +37,9 @@
|
||||
# - it seems (empirically) that a user can't cd above their home directory.
|
||||
# though i don't have a reference for that in the docs.
|
||||
|
||||
import crypt
|
||||
import json
|
||||
import os
|
||||
import passlib.hosts
|
||||
|
||||
from hmac import compare_digest
|
||||
|
||||
@@ -112,10 +112,8 @@ def isWireguard(ip: str) -> bool:
|
||||
|
||||
def isTrustedCred(password: str) -> bool:
|
||||
for cred in TRUSTED_CREDS:
|
||||
_, method, salt, hash_ = cred.split("$")
|
||||
# assert method == "6", f"unrecognized crypt entry: {cred}"
|
||||
if crypt.crypt(password, f"${method}${salt}") == cred:
|
||||
return True
|
||||
if passlib.hosts.linux_context.verify(password, cred):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
@@ -90,6 +90,8 @@
|
||||
];
|
||||
};
|
||||
|
||||
services.openssh.settings.UsePAM = true; #< required for `git` user to authenticate
|
||||
|
||||
# hosted git (web view and for `git <cmd>` use
|
||||
# TODO: enable publog?
|
||||
services.nginx.virtualHosts."git.uninsane.org" = {
|
||||
|
@@ -86,6 +86,7 @@ let
|
||||
(fromDb "lexfridman.com/podcast" // rat)
|
||||
(fromDb "mapspodcast.libsyn.com" // uncat) # Multidisciplinary Association for Psychedelic Studies
|
||||
(fromDb "microarch.club" // tech)
|
||||
(fromDb "mintcast.org" // tech)
|
||||
(fromDb "omegataupodcast.net" // tech) # 3/4 German; 1/4 eps are English
|
||||
(fromDb "omny.fm/shows/cool-people-who-did-cool-stuff" // pol) # Maggie Killjoy -- referenced by Cory Doctorow
|
||||
(fromDb "omny.fm/shows/money-stuff-the-podcast") # Matt Levine
|
||||
|
@@ -23,11 +23,5 @@
|
||||
# see <https://manpages.ubuntu.com/manpages/bionic/man5/user-dirs.conf.5.html>
|
||||
sane.user.fs.".config/user-dirs.conf".symlink.text = "enabled=False";
|
||||
|
||||
sane.user.fs.".profile".symlink.text = ''
|
||||
# configure XDG_<type>_DIR preferences (e.g. for downloads, screenshots, etc)
|
||||
# surround with `set -o allexport` since user-dirs.dirs doesn't `export` its vars
|
||||
set -a
|
||||
source $HOME/.config/user-dirs.dirs
|
||||
set +a
|
||||
'';
|
||||
sane.user.fs.".config/environment.d/30-user-dirs.conf".symlink.target = "../user-dirs.dirs";
|
||||
}
|
||||
|
@@ -4,6 +4,9 @@
|
||||
{ ... }:
|
||||
|
||||
{
|
||||
# partially supported in nixpkgs <repo:nixos/nixpkgs:nixos/modules/misc/ids.nix>
|
||||
sane.ids.networkmanager.uid = 57; #< nixpkgs unofficially reserves this, to match networkmanager's gid
|
||||
|
||||
# legacy servo users, some are inconvenient to migrate
|
||||
sane.ids.dhcpcd.gid = 991;
|
||||
sane.ids.dhcpcd.uid = 992;
|
||||
@@ -18,7 +21,7 @@
|
||||
sane.ids.matrix-appservice-irc.uid = 993;
|
||||
sane.ids.matrix-appservice-irc.gid = 992;
|
||||
|
||||
# greetd (used by sway)
|
||||
# greetd (legacy)
|
||||
sane.ids.greeter.uid = 999;
|
||||
sane.ids.greeter.gid = 999;
|
||||
|
||||
@@ -78,6 +81,7 @@
|
||||
|
||||
# found on graphical hosts
|
||||
sane.ids.nm-iodine.uid = 2101; # desko/moby/lappy
|
||||
sane.ids.seat.gid = 2102;
|
||||
|
||||
# found on desko host
|
||||
# from services.usbmuxd
|
||||
|
@@ -7,50 +7,62 @@
|
||||
|
||||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
def-ovpn = name: { endpoint, publicKey, addrV4, id }: {
|
||||
sane.vpn."ovpnd-${name}" = {
|
||||
inherit endpoint publicKey addrV4 id;
|
||||
privateKeyFile = config.sops.secrets."wg/ovpnd_${name}_privkey".path;
|
||||
# N.B.: OVPN issues each key (i.e. device) a different IP (addrV4), and requires you use it.
|
||||
# the IP it issues can be used to connect to any of their VPNs.
|
||||
# effectively the IP and key map 1-to-1.
|
||||
# it seems to still be possible to keep two active tunnels on one device, using the same key/IP address, though.
|
||||
def-ovpn = name: { endpoint, publicKey, id }: let
|
||||
inherit (config.sane.ovpn) addrV4;
|
||||
in {
|
||||
sane.vpn."ovpnd-${name}" = lib.mkIf (addrV4 != null) {
|
||||
inherit addrV4 endpoint publicKey id;
|
||||
privateKeyFile = config.sops.secrets."ovpn_privkey".path;
|
||||
dns = [
|
||||
"46.227.67.134"
|
||||
"192.165.9.158"
|
||||
# "2a07:a880:4601:10f0:cd45::1"
|
||||
# "2001:67c:750:1:cafe:cd45::1"
|
||||
];
|
||||
};
|
||||
|
||||
sops.secrets."wg/ovpnd_${name}_privkey" = {
|
||||
sops.secrets."ovpn_privkey" = lib.mkIf (addrV4 != null) {
|
||||
# needs to be readable by systemd-network or else it says "Ignoring network device" and doesn't expose it to networkctl.
|
||||
owner = "systemd-network";
|
||||
};
|
||||
};
|
||||
in lib.mkMerge [
|
||||
(def-ovpn "us" {
|
||||
endpoint = "vpn31.prd.losangeles.ovpn.com:9929";
|
||||
publicKey = "VW6bEWMOlOneta1bf6YFE25N/oMGh1E1UFBCfyggd0k=";
|
||||
id = 1;
|
||||
addrV4 = "172.27.237.218";
|
||||
# addrV6 = "fd00:0000:1337:cafe:1111:1111:ab00:4c8f";
|
||||
})
|
||||
# TODO: us-atl disabled until i can give it a different link-local address and wireguard key than us-mi
|
||||
# (def-ovpn "us-atl" {
|
||||
# endpoint = "vpn18.prd.atlanta.ovpn.com:9929";
|
||||
# publicKey = "Dpg/4v5s9u0YbrXukfrMpkA+XQqKIFpf8ZFgyw0IkE0=";
|
||||
# address = [
|
||||
# "172.21.182.178/32"
|
||||
# "fd00:0000:1337:cafe:1111:1111:cfcb:27e3/128"
|
||||
# ];
|
||||
# })
|
||||
(def-ovpn "us-mi" {
|
||||
endpoint = "vpn34.prd.miami.ovpn.com:9929";
|
||||
publicKey = "VtJz2irbu8mdkIQvzlsYhU+k9d55or9mx4A2a14t0V0=";
|
||||
id = 2;
|
||||
addrV4 = "172.21.182.178";
|
||||
# addrV6 = "fd00:0000:1337:cafe:1111:1111:cfcb:27e3";
|
||||
})
|
||||
(def-ovpn "ukr" {
|
||||
endpoint = "vpn96.prd.kyiv.ovpn.com:9929";
|
||||
publicKey = "CjZcXDxaaKpW8b5As1EcNbI6+42A6BjWahwXDCwfVFg=";
|
||||
id = 3;
|
||||
addrV4 = "172.18.180.159";
|
||||
# addrV6 = "fd00:0000:1337:cafe:1111:1111:ec5c:add3";
|
||||
})
|
||||
]
|
||||
in {
|
||||
options = with lib; {
|
||||
sane.ovpn.addrV4 = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = ''
|
||||
ovpn issues one IP address per device.
|
||||
set `null` to disable OVPN for this host.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkMerge [
|
||||
(def-ovpn "us" {
|
||||
endpoint = "vpn31.prd.losangeles.ovpn.com:9929";
|
||||
publicKey = "VW6bEWMOlOneta1bf6YFE25N/oMGh1E1UFBCfyggd0k=";
|
||||
id = 1;
|
||||
})
|
||||
(def-ovpn "us-mi" {
|
||||
endpoint = "vpn34.prd.miami.ovpn.com:9929";
|
||||
publicKey = "VtJz2irbu8mdkIQvzlsYhU+k9d55or9mx4A2a14t0V0=";
|
||||
id = 2;
|
||||
})
|
||||
(def-ovpn "ukr" {
|
||||
endpoint = "vpn96.prd.kyiv.ovpn.com:9929";
|
||||
publicKey = "CjZcXDxaaKpW8b5As1EcNbI6+42A6BjWahwXDCwfVFg=";
|
||||
id = 3;
|
||||
})
|
||||
# TODO: us-atl disabled until i need it again, i guess.
|
||||
# (def-ovpn "us-atl" {
|
||||
# endpoint = "vpn18.prd.atlanta.ovpn.com:9929";
|
||||
# publicKey = "Dpg/4v5s9u0YbrXukfrMpkA+XQqKIFpf8ZFgyw0IkE0=";
|
||||
# id = 4;
|
||||
# })
|
||||
];
|
||||
}
|
||||
|
@@ -1,88 +1,216 @@
|
||||
# strictly *decrease* the scope of the default nixos installation/config
|
||||
|
||||
{ lib, ... }:
|
||||
{ lib, pkgs, ... }:
|
||||
let
|
||||
suidlessPam = pkgs.pam.overrideAttrs (upstream: {
|
||||
# nixpkgs' pam hardcodes unix_chkpwd path to the /run/wrappers one,
|
||||
# but i don't want the wrapper, so undo that.
|
||||
# ideally i would patch this via an overlay, but pam is in the bootstrap so that forces a full rebuild.
|
||||
# TODO: add a `package` option to the nixos' pam module and substitute it that way.
|
||||
postPatch = (if upstream.postPatch != null then upstream.postPatch else "") + ''
|
||||
substituteInPlace modules/pam_unix/Makefile.am --replace-fail \
|
||||
"/run/wrappers/bin/unix_chkpwd" "$out/bin/unix_chkpwd"
|
||||
'';
|
||||
});
|
||||
in
|
||||
{
|
||||
# disable non-required packages like nano, perl, rsync, strace
|
||||
environment.defaultPackages = [];
|
||||
# remove a few items from /run/wrappers we don't need.
|
||||
options.security.wrappers = lib.mkOption {
|
||||
apply = lib.filterAttrs (name: _: !(builtins.elem name [
|
||||
# from <repo:nixos/nixpkgs:nixos/modules/security/polkit.nix>
|
||||
"pkexec"
|
||||
"polkit-agent-helper-1" #< used by systemd; without this you'll have to `sudo systemctl daemon-reload` instead of unauth'd `systemctl daemon-reload`
|
||||
# from <repo:nixos/nixpkgs:nixos/modules/services/system/dbus.nix>
|
||||
"dbus-daemon-launch-helper"
|
||||
# from <repo:nixos/nixpkgs:nixos/modules/security/wrappers/default.nix>
|
||||
"fusermount" #< only needed if you want to mount entries declared in /etc/fstab or mtab as unprivileged user
|
||||
"fusermount3"
|
||||
"mount" #< only needed if you want to mount entries declared in /etc/fstab or mtab as unprivileged user
|
||||
"umount"
|
||||
# from <repo:nixos/nixpkgs:nixos/modules/programs/shadow.nix>
|
||||
"newgidmap"
|
||||
"newgrp"
|
||||
"newuidmap"
|
||||
"sg"
|
||||
"su"
|
||||
# from: <repo:nixos/nixpkgs:nixos/modules/security/pam.nix>
|
||||
# requires associated `pam` patch to not hardcode unix_chkpwd path
|
||||
"unix_chkpwd"
|
||||
]));
|
||||
};
|
||||
options.security.pam.services = lib.mkOption {
|
||||
apply = services: let
|
||||
filtered = lib.filterAttrs (name: _: !(builtins.elem name [
|
||||
# from <repo:nixos/nixpkgs:nixos/modules/security/pam.nix>
|
||||
"i3lock"
|
||||
"i3lock-color"
|
||||
"vlock"
|
||||
"xlock"
|
||||
"xscreensaver"
|
||||
"runuser"
|
||||
"runuser-l"
|
||||
# from ??
|
||||
"chfn"
|
||||
"chpasswd"
|
||||
"chsh"
|
||||
"groupadd"
|
||||
"groupdel"
|
||||
"groupmems"
|
||||
"groupmod"
|
||||
"useradd"
|
||||
"userdel"
|
||||
"usermod"
|
||||
# from <repo:nixos/nixpkgs:nixos/modules/system/boot/systemd/user.nix>
|
||||
"systemd-user" #< N.B.: this causes the `systemd --user` service manager to not be started!
|
||||
])) services;
|
||||
in lib.mapAttrs (_serviceName: service: service // {
|
||||
# replace references with the old pam_unix, which calls into /run/wrappers/bin/unix_chkpwd,
|
||||
# with a pam_unix that calls into unix_chkpwd via the nix store.
|
||||
# TODO: use `security.pam.package` instead once <https://github.com/NixOS/nixpkgs/pull/314791> lands.
|
||||
text = lib.replaceStrings [" pam_unix.so" ] [ " ${suidlessPam}/lib/security/pam_unix.so" ] service.text;
|
||||
}) filtered;
|
||||
};
|
||||
|
||||
# remove all the non-existent default directories from XDG_DATA_DIRS, XDG_CONFIG_DIRS to simplify debugging.
|
||||
# this is defaulted in <repo:nixos/nixpkgs:nixos/modules/programs/environment.nix>,
|
||||
# without being gated by any higher config.
|
||||
environment.profiles = lib.mkForce [
|
||||
"/etc/profiles/per-user/$USER"
|
||||
"/run/current-system/sw"
|
||||
];
|
||||
options.environment.systemPackages = lib.mkOption {
|
||||
# see: <repo:nixos/nixpkgs:nixos/modules/config/system-path.nix>
|
||||
# it's 31 "requiredPackages", with no explanation of why they're "required"...
|
||||
# most of these can be safely removed without breaking the *boot*,
|
||||
# but some core system services DO implicitly depend on them.
|
||||
# TODO: see which more of these i can remove (or shadow/sandbox)
|
||||
apply = let
|
||||
requiredPackages = builtins.map (pkg: lib.setPrio ((pkg.meta.priority or 5) + 3) pkg) [
|
||||
# pkgs.acl
|
||||
# pkgs.attr
|
||||
# pkgs.bashInteractive
|
||||
# pkgs.bzip2
|
||||
# pkgs.coreutils-full
|
||||
# pkgs.cpio
|
||||
# pkgs.curl
|
||||
# pkgs.diffutils
|
||||
# pkgs.findutils
|
||||
# pkgs.gawk
|
||||
# pkgs.stdenv.cc.libc
|
||||
# pkgs.getent
|
||||
# pkgs.getconf
|
||||
# pkgs.gnugrep
|
||||
# pkgs.gnupatch
|
||||
# pkgs.gnused
|
||||
# pkgs.gnutar
|
||||
# pkgs.gzip
|
||||
# pkgs.xz
|
||||
pkgs.less
|
||||
# pkgs.libcap #< implicitly required by NetworkManager/wpa_supplicant!
|
||||
# pkgs.ncurses
|
||||
pkgs.netcat
|
||||
# config.programs.ssh.package
|
||||
# pkgs.mkpasswd
|
||||
pkgs.procps
|
||||
# pkgs.su
|
||||
# pkgs.time
|
||||
# pkgs.util-linux
|
||||
# pkgs.which
|
||||
# pkgs.zstd
|
||||
];
|
||||
in lib.filter (p: ! builtins.elem p requiredPackages);
|
||||
};
|
||||
|
||||
# NIXPKGS_CONFIG defaults to "/etc/nix/nixpkgs-config.nix" in <nixos/modules/programs/environment.nix>.
|
||||
# that's never existed on my system and everything does fine without it set empty (no nixpkgs API to forcibly *unset* it).
|
||||
environment.variables.NIXPKGS_CONFIG = lib.mkForce "";
|
||||
# XDG_CONFIG_DIRS defaults to "/etc/xdg", which doesn't exist.
|
||||
# in practice, pam appends the values i want to XDG_CONFIG_DIRS, though this approach causes an extra leading `:`
|
||||
environment.sessionVariables.XDG_CONFIG_DIRS = lib.mkForce [];
|
||||
# XCURSOR_PATH: defaults to `[ "$HOME/.icons" "$HOME/.local/share/icons" ]`, neither of which i use, just adding noise.
|
||||
# see: <repo:nixos/nixpkgs:nixos/modules/config/xdg/icons.nix>
|
||||
environment.sessionVariables.XCURSOR_PATH = lib.mkForce [];
|
||||
options.system.fsPackages = lib.mkOption {
|
||||
# <repo:nixos/nixpkgs:nixos/modules/tasks/filesystems/vfat.nix> adds `mtools` and `dosfstools`
|
||||
# dosfstools actually makes its way into the initrd (`fsck.vfat`).
|
||||
# mtools is like "MS-DOS for Linux", ancient functionality i'll never use.
|
||||
apply = lib.filter (p: p != pkgs.mtools);
|
||||
};
|
||||
|
||||
# disable nixos' portal module, otherwise /share/applications gets linked into the system and complicates things (sandboxing).
|
||||
# instead, i manage portals myself via the sane.programs API (e.g. sane.programs.xdg-desktop-portal).
|
||||
xdg.portal.enable = false;
|
||||
xdg.menus.enable = false; #< links /share/applications, and a bunch of other empty (i.e. unused) dirs
|
||||
config = {
|
||||
# disable non-required packages like nano, perl, rsync, strace
|
||||
environment.defaultPackages = [];
|
||||
|
||||
# xdg.autostart.enable defaults to true, and links /etc/xdg/autostart into the environment, populated with .desktop files.
|
||||
# see: <repo:nixos/nixpkgs:nixos/modules/config/xdg/autostart.nix>
|
||||
# .desktop files are a questionable way to autostart things: i generally prefer a service manager for that.
|
||||
xdg.autostart.enable = false;
|
||||
# remove all the non-existent default directories from XDG_DATA_DIRS, XDG_CONFIG_DIRS to simplify debugging.
|
||||
# this is defaulted in <repo:nixos/nixpkgs:nixos/modules/programs/environment.nix>,
|
||||
# without being gated by any higher config.
|
||||
environment.profiles = lib.mkForce [
|
||||
"/etc/profiles/per-user/$USER"
|
||||
"/run/current-system/sw"
|
||||
];
|
||||
|
||||
# nix.channel.enable: populates `/nix/var/nix/profiles/per-user/root/channels`, `/root/.nix-channels`, `$HOME/.nix-defexpr/channels`
|
||||
# <repo:nixos/nixpkgs:nixos/modules/config/nix-channel.nix>
|
||||
# TODO: may want to recreate NIX_PATH, nix.settings.nix-path
|
||||
nix.channel.enable = false;
|
||||
# NIXPKGS_CONFIG defaults to "/etc/nix/nixpkgs-config.nix" in <nixos/modules/programs/environment.nix>.
|
||||
# that's never existed on my system and everything does fine without it set empty (no nixpkgs API to forcibly *unset* it).
|
||||
environment.variables.NIXPKGS_CONFIG = lib.mkForce "";
|
||||
# XDG_CONFIG_DIRS defaults to "/etc/xdg", which doesn't exist.
|
||||
# in practice, pam appends the values i want to XDG_CONFIG_DIRS, though this approach causes an extra leading `:`
|
||||
environment.sessionVariables.XDG_CONFIG_DIRS = lib.mkForce [];
|
||||
# XCURSOR_PATH: defaults to `[ "$HOME/.icons" "$HOME/.local/share/icons" ]`, neither of which i use, just adding noise.
|
||||
# see: <repo:nixos/nixpkgs:nixos/modules/config/xdg/icons.nix>
|
||||
environment.sessionVariables.XCURSOR_PATH = lib.mkForce [];
|
||||
|
||||
# environment.stub-ld: populate /lib/ld-linux.so with an object that unconditionally errors on launch,
|
||||
# so as to inform when trying to run a non-nixos binary?
|
||||
# IMO that's confusing: i thought /lib/ld-linux.so was some file actually required by nix.
|
||||
environment.stub-ld.enable = false;
|
||||
# disable nixos' portal module, otherwise /share/applications gets linked into the system and complicates things (sandboxing).
|
||||
# instead, i manage portals myself via the sane.programs API (e.g. sane.programs.xdg-desktop-portal).
|
||||
xdg.portal.enable = false;
|
||||
xdg.menus.enable = false; #< links /share/applications, and a bunch of other empty (i.e. unused) dirs
|
||||
|
||||
# `less.enable` sets LESSKEYIN_SYSTEM, LESSOPEN, LESSCLOSE env vars, which does confusing "lesspipe" things, so disable that.
|
||||
# it's enabled by default from `<nixos/modules/programs/environment.nix>`, who also sets `PAGER="less"` and `EDITOR="nano"` (keep).
|
||||
programs.less.enable = lib.mkForce false;
|
||||
environment.variables.PAGER = lib.mkOverride 900 ""; # mkDefault sets 1000. non-override is 100. 900 will beat the nixpkgs `mkDefault` but not anyone else.
|
||||
environment.variables.EDITOR = lib.mkOverride 900 "";
|
||||
# xdg.autostart.enable defaults to true, and links /etc/xdg/autostart into the environment, populated with .desktop files.
|
||||
# see: <repo:nixos/nixpkgs:nixos/modules/config/xdg/autostart.nix>
|
||||
# .desktop files are a questionable way to autostart things: i generally prefer a service manager for that.
|
||||
xdg.autostart.enable = false;
|
||||
|
||||
# several packages (dconf, modemmanager, networkmanager, gvfs, polkit, udisks, bluez/blueman, feedbackd, etc)
|
||||
# will add themselves to the dbus search path.
|
||||
# i prefer dbus to only search XDG paths (/share/dbus-1) for service files, as that's more introspectable.
|
||||
# see: <repo:nixos/nixpkgs:nixos/modules/services/system/dbus.nix>
|
||||
# TODO: sandbox dbus? i pretty explicitly don't want to use it as a launcher.
|
||||
services.dbus.packages = lib.mkForce [
|
||||
"/run/current-system/sw"
|
||||
# config.system.path
|
||||
# pkgs.dbus
|
||||
# pkgs.polkit.out
|
||||
# pkgs.modemmanager
|
||||
# pkgs.networkmanager
|
||||
# pkgs.udisks
|
||||
# pkgs.wpa_supplicant
|
||||
];
|
||||
# nix.channel.enable: populates `/nix/var/nix/profiles/per-user/root/channels`, `/root/.nix-channels`, `$HOME/.nix-defexpr/channels`
|
||||
# <repo:nixos/nixpkgs:nixos/modules/config/nix-channel.nix>
|
||||
# TODO: may want to recreate NIX_PATH, nix.settings.nix-path
|
||||
nix.channel.enable = false;
|
||||
|
||||
# systemd by default forces shitty defaults for e.g. /tmp/.X11-unix.
|
||||
# nixos propagates those in: <nixos/modules/system/boot/systemd/tmpfiles.nix>
|
||||
# by overwriting this with an empty file, we can effectively remove it.
|
||||
environment.etc."tmpfiles.d/x11.conf".text = "# (removed by Colin)";
|
||||
# environment.stub-ld: populate /lib/ld-linux.so with an object that unconditionally errors on launch,
|
||||
# so as to inform when trying to run a non-nixos binary?
|
||||
# IMO that's confusing: i thought /lib/ld-linux.so was some file actually required by nix.
|
||||
environment.stub-ld.enable = false;
|
||||
|
||||
# see: <nixos/modules/tasks/swraid.nix>
|
||||
# it was enabled by default before 23.11
|
||||
boot.swraid.enable = lib.mkDefault false;
|
||||
# `less.enable` sets LESSKEYIN_SYSTEM, LESSOPEN, LESSCLOSE env vars, which does confusing "lesspipe" things, so disable that.
|
||||
# it's enabled by default from `<nixos/modules/programs/environment.nix>`, who also sets `PAGER="less"` and `EDITOR="nano"` (keep).
|
||||
programs.less.enable = lib.mkForce false;
|
||||
environment.variables.PAGER = lib.mkOverride 900 ""; # mkDefault sets 1000. non-override is 100. 900 will beat the nixpkgs `mkDefault` but not anyone else.
|
||||
environment.variables.EDITOR = lib.mkOverride 900 "";
|
||||
|
||||
# see: <nixos/modules/system/boot/kernel.nix>
|
||||
# by default, it adds to boot.initrd.availableKernelModules:
|
||||
# - SATA: "ahci" "sata_nv" "sata_via" "sata_sis" "sata_uli" "ata_piix" "pata_marvell"
|
||||
# - "nvme"
|
||||
# - scsi: "sd_mod" "sr_mod"
|
||||
# - SD/eMMC: "mmc_block"
|
||||
# - USB keyboards: "uhci_hcd" "ehci_hcd" "ehci_pci" "ohci_hcd" "ohci_pci" "xhci_hcd" "xhci_pci" "usbhid" "hid_generic" "hid_lenovo" "hid_apple" "hid_roccat" "hid_logitech_hidpp" "hid_logitech_dj" "hid_microsoft" "hid_cherry" "hid_corsair"
|
||||
# - LVM: "dm_mod"
|
||||
# - on x86 only: more keyboard stuff: "pcips2" "atkbd" "i8042"
|
||||
# several packages (dconf, modemmanager, networkmanager, gvfs, polkit, udisks, bluez/blueman, feedbackd, etc)
|
||||
# will add themselves to the dbus search path.
|
||||
# i prefer dbus to only search XDG paths (/share/dbus-1) for service files, as that's more introspectable.
|
||||
# see: <repo:nixos/nixpkgs:nixos/modules/services/system/dbus.nix>
|
||||
# TODO: sandbox dbus? i pretty explicitly don't want to use it as a launcher.
|
||||
services.dbus.packages = lib.mkForce [
|
||||
"/run/current-system/sw"
|
||||
# config.system.path
|
||||
# pkgs.dbus
|
||||
# pkgs.polkit.out
|
||||
# pkgs.modemmanager
|
||||
# pkgs.networkmanager
|
||||
# pkgs.udisks
|
||||
# pkgs.wpa_supplicant
|
||||
];
|
||||
|
||||
boot.initrd.includeDefaultModules = lib.mkDefault false;
|
||||
# systemd by default forces shitty defaults for e.g. /tmp/.X11-unix.
|
||||
# nixos propagates those in: <nixos/modules/system/boot/systemd/tmpfiles.nix>
|
||||
# by overwriting this with an empty file, we can effectively remove it.
|
||||
environment.etc."tmpfiles.d/x11.conf".text = "# (removed by Colin)";
|
||||
|
||||
# see: <nixos/modules/tasks/swraid.nix>
|
||||
# it was enabled by default before 23.11
|
||||
boot.swraid.enable = lib.mkDefault false;
|
||||
|
||||
# see: <nixos/modules/tasks/bcache.nix>
|
||||
# these allow you to use the Linux block cache (cool! doesn't need to be a default though)
|
||||
boot.bcache.enable = lib.mkDefault false;
|
||||
|
||||
# see: <nixos/modules/system/boot/kernel.nix>
|
||||
# by default, it adds to boot.initrd.availableKernelModules:
|
||||
# - SATA: "ahci" "sata_nv" "sata_via" "sata_sis" "sata_uli" "ata_piix" "pata_marvell"
|
||||
# - "nvme"
|
||||
# - scsi: "sd_mod" "sr_mod"
|
||||
# - SD/eMMC: "mmc_block"
|
||||
# - USB keyboards: "uhci_hcd" "ehci_hcd" "ehci_pci" "ohci_hcd" "ohci_pci" "xhci_hcd" "xhci_pci" "usbhid" "hid_generic" "hid_lenovo" "hid_apple" "hid_roccat" "hid_logitech_hidpp" "hid_logitech_dj" "hid_microsoft" "hid_cherry" "hid_corsair"
|
||||
# - LVM: "dm_mod"
|
||||
# - on x86 only: more keyboard stuff: "pcips2" "atkbd" "i8042"
|
||||
|
||||
boot.initrd.includeDefaultModules = lib.mkDefault false;
|
||||
|
||||
# see: <repo:nixos/nixpkgs:nixos/modules/virtualisation/nixos-containers.nix>
|
||||
boot.enableContainers = lib.mkDefault false;
|
||||
};
|
||||
}
|
||||
|
@@ -15,39 +15,33 @@ in
|
||||
};
|
||||
|
||||
# upstream alsa ships with PinePhone audio configs, but they don't actually produce sound.
|
||||
# see: <https://github.com/alsa-project/alsa-ucm-conf/pull/134>
|
||||
# these audio files come from some revision of:
|
||||
# - <https://gitlab.manjaro.org/manjaro-arm/packages/community/phosh/alsa-ucm-pinephone>
|
||||
# - still true as of 2024-05-26
|
||||
# - see: <https://github.com/alsa-project/alsa-ucm-conf/pull/134>
|
||||
#
|
||||
# alternative to patching is to plumb `ALSA_CONFIG_UCM2 = "${./ucm2}"` environment variable into the relevant places
|
||||
# e.g. `systemd.services.pulseaudio.environment`.
|
||||
# that leaves more opportunity for gaps (i.e. missing a service),
|
||||
# on the other hand this method causes about 500 packages to be rebuilt (including qt5 and webkitgtk).
|
||||
# we can substitute working UCM conf in two ways:
|
||||
# 1. nixpkgs' override for the `alsa-ucm-conf` package
|
||||
# - that forces a rebuild of ~500 packages (including webkitgtk).
|
||||
# 2. set ALSA_CONFIG_UCM2 = /path/to/ucm2 in the relevant places
|
||||
# - e.g. pulsewire service.
|
||||
# - easy to miss places, though.
|
||||
#
|
||||
# note that with these files, the following audio device support:
|
||||
# - headphones work.
|
||||
# - "internal earpiece" works.
|
||||
# - "internal speaker" doesn't work (but that's probably because i broke the ribbon cable)
|
||||
# - "analog output" doesn't work.
|
||||
packageUnwrapped = pkgs.alsa-ucm-conf.overrideAttrs (upstream: {
|
||||
postPatch = (upstream.postPatch or "") + ''
|
||||
cp ${./ucm2/PinePhone}/* ucm2/Allwinner/A64/PinePhone/
|
||||
# alsa-ucm-pinephone-manjaro (2024-05-26):
|
||||
# - headphones work
|
||||
# - "internal earpiece" works
|
||||
# - "internal speaker" is silent (maybe hardware issue)
|
||||
# - 3.5mm connection is flapping when playing to my car, which eventually breaks audio and requires restarting wireplumber
|
||||
# packageUnwrapped = pkgs.alsa-ucm-pinephone-manjaro.override {
|
||||
# inherit (cfg.config) preferEarpiece;
|
||||
# };
|
||||
# alsa-ucm-pinephone-pmos (2024-05-26):
|
||||
# - headphones work
|
||||
# - "internal earpiece" works
|
||||
# - "internal speaker" is silent (maybe hardware issue)
|
||||
packageUnwrapped = pkgs.alsa-ucm-pinephone-pmos.override {
|
||||
inherit (cfg.config) preferEarpiece;
|
||||
};
|
||||
|
||||
# fix the self-contained ucm files i source from to have correct path within the alsa-ucm-conf source tree
|
||||
substituteInPlace ucm2/Allwinner/A64/PinePhone/PinePhone.conf \
|
||||
--replace-fail 'HiFi.conf' '/Allwinner/A64/PinePhone/HiFi.conf'
|
||||
substituteInPlace ucm2/Allwinner/A64/PinePhone/PinePhone.conf \
|
||||
--replace-fail 'VoiceCall.conf' '/Allwinner/A64/PinePhone/VoiceCall.conf'
|
||||
'' + lib.optionalString cfg.config.preferEarpiece ''
|
||||
# decrease the priority of the internal speaker so that sounds are routed
|
||||
# to the earpiece by default.
|
||||
# this is just personal preference.
|
||||
substituteInPlace ucm2/Allwinner/A64/PinePhone/{HiFi.conf,VoiceCall.conf} \
|
||||
--replace-fail 'PlaybackPriority 300' 'PlaybackPriority 100'
|
||||
'';
|
||||
});
|
||||
|
||||
sandbox.enable = false; #< only provides #out/share/alsa
|
||||
sandbox.enable = false; #< only provides $out/share/alsa
|
||||
|
||||
# alsa-lib package only looks in its $out/share/alsa to find runtime config data, by default.
|
||||
# but ALSA_CONFIG_UCM2 is an env var that can override that.
|
||||
|
@@ -34,6 +34,7 @@ in
|
||||
];
|
||||
|
||||
sysadminUtils = declPackageSet [
|
||||
"ausyscall"
|
||||
"bridge-utils" # for brctl; debug linux "bridge" inet devices
|
||||
"btrfs-progs"
|
||||
"cacert.unbundled" # some services require unbundled /etc/ssl/certs
|
||||
@@ -43,6 +44,7 @@ in
|
||||
"dtc" # device tree [de]compiler
|
||||
"e2fsprogs" # resize2fs
|
||||
"efibootmgr"
|
||||
"errno"
|
||||
"ethtool"
|
||||
"fatresize"
|
||||
"fd"
|
||||
@@ -165,7 +167,6 @@ in
|
||||
];
|
||||
|
||||
pcConsoleUtils = declPackageSet [
|
||||
"errno" # 2024/05/18: doesn't cross compile (perl File-ShareDir / Module-Build-Tiny)
|
||||
# "gh" # MS GitHub cli
|
||||
"nix-index"
|
||||
"nixpkgs-review"
|
||||
@@ -210,6 +211,175 @@ in
|
||||
# "tree-sitter"
|
||||
];
|
||||
|
||||
gameApps = declPackageSet [
|
||||
"animatch"
|
||||
"gnome-2048"
|
||||
"gnome.hitori" # like sudoku
|
||||
];
|
||||
|
||||
pcGameApps = declPackageSet [
|
||||
# "andyetitmoves" # TODO: fix build!
|
||||
# "armagetronad" # tron/lightcycles; WAN and LAN multiplayer
|
||||
"celeste64"
|
||||
# "cutemaze" # meh: trivial maze game; qt6 and keyboard-only
|
||||
# "cuyo" # trivial puyo-puyo clone
|
||||
"endless-sky" # space merchantilism/exploration
|
||||
# "factorio"
|
||||
"frozen-bubble" # WAN + LAN + 1P/2P bubble bobble
|
||||
"hase" # WAN worms game
|
||||
# "hedgewars" # WAN + LAN worms game (5~10 people online at any moment; <https://hedgewars.org>)
|
||||
# "libremines" # meh: trivial minesweeper; qt6
|
||||
# "mario0" # SMB + portal
|
||||
# "mindustry"
|
||||
# "minesweep-rs" # CLI minesweeper
|
||||
# "nethack"
|
||||
# "osu-lazer"
|
||||
# "pinball" # 3d pinball; kb/mouse. old sourceforge project
|
||||
# "powermanga" # STYLISH space invaders derivative (keyboard-only)
|
||||
"shattered-pixel-dungeon" # doesn't cross compile
|
||||
"space-cadet-pinball" # LMB/RMB controls (bindable though. volume buttons?)
|
||||
"superTux" # keyboard-only controls
|
||||
"superTuxKart" # poor FPS on pinephone
|
||||
"tumiki-fighters" # keyboard-only
|
||||
"vvvvvv" # keyboard-only controls
|
||||
# "wine"
|
||||
];
|
||||
|
||||
guiApps = declPackageSet [
|
||||
# package sets
|
||||
"gameApps"
|
||||
"guiBaseApps"
|
||||
];
|
||||
|
||||
guiBaseApps = declPackageSet [
|
||||
# "abaddon" # discord client
|
||||
"alacritty" # terminal emulator
|
||||
"calls" # gnome calls (dialer/handler)
|
||||
"dbus"
|
||||
"dconf" # required by many packages, but not well-documented :(
|
||||
# "delfin" # Jellyfin client
|
||||
"dialect" # language translation
|
||||
"dino" # XMPP client
|
||||
"dissent" # Discord client (formerly known as: gtkcord4)
|
||||
# "emote"
|
||||
# "evince" # PDF viewer
|
||||
# "flare-signal" # gtk4 signal client
|
||||
# "foliate" # e-book reader
|
||||
"fractal" # matrix client
|
||||
"g4music" # local music player
|
||||
# "gnome.cheese"
|
||||
# "gnome-feeds" # RSS reader (with claimed mobile support)
|
||||
# "gnome.file-roller"
|
||||
"gnome.geary" # adaptive e-mail client; uses webkitgtk 4.1
|
||||
"gnome.gnome-calculator"
|
||||
"gnome.gnome-calendar"
|
||||
"gnome.gnome-clocks"
|
||||
"gnome.gnome-maps"
|
||||
# "gnome-podcasts"
|
||||
# "gnome.gnome-system-monitor"
|
||||
# "gnome.gnome-terminal" # works on phosh
|
||||
"gnome.gnome-weather"
|
||||
# "gnome.seahorse" # keyring/secret manager
|
||||
"gnome-frog" # OCR/QR decoder
|
||||
"gpodder"
|
||||
"gst-device-monitor" # for debugging audio/video
|
||||
# "gthumb"
|
||||
# "lemoa" # lemmy app
|
||||
"libcamera" # for `cam` binary (useful for debugging cameras)
|
||||
"libnotify" # for notify-send; debugging
|
||||
# "lollypop"
|
||||
"loupe" # image viewer
|
||||
"mate.engrampa" # archive manager
|
||||
"mepo" # maps viewer
|
||||
"mpv"
|
||||
"networkmanagerapplet" # for nm-connection-editor: it's better than not having any gui!
|
||||
"ntfy-sh" # notification service
|
||||
# "newsflash" # RSS viewer
|
||||
"pavucontrol"
|
||||
"pwvucontrol" # pipewire version of pavu
|
||||
# "picard" # music tagging
|
||||
# "libsForQt5.plasmatube" # Youtube player
|
||||
"signal-desktop"
|
||||
"snapshot" # camera app
|
||||
"spot" # Gnome Spotify client
|
||||
# "sublime-music"
|
||||
# "tdesktop" # broken on phosh
|
||||
# "tokodon"
|
||||
"tuba" # mastodon/pleroma client (stores pw in keyring)
|
||||
"vulkan-tools" # vulkaninfo
|
||||
# "whalebird" # pleroma client (Electron). input is broken on phosh.
|
||||
"xdg-terminal-exec"
|
||||
"zathura" # PDF/CBZ/ePUB viewer
|
||||
];
|
||||
|
||||
handheldGuiApps = declPackageSet [
|
||||
# "celluloid" # mpv frontend
|
||||
# "chatty" # matrix/xmpp/irc client (2023/12/29: disabled because broken cross build)
|
||||
"cozy" # audiobook player
|
||||
"epiphany" # gnome's web browser
|
||||
# "iotas" # note taking app
|
||||
"komikku"
|
||||
"koreader"
|
||||
"megapixels" # camera app
|
||||
"notejot" # note taking, e.g. shopping list
|
||||
"planify" # todo-tracker/planner
|
||||
"portfolio-filemanager"
|
||||
"tangram" # web browser
|
||||
"wike" # Wikipedia Reader
|
||||
"xarchiver" # archiver, backup option for when engrampa UI overflows screen and is unusale (xarchiver UI fails in different ways)
|
||||
];
|
||||
|
||||
pcGuiApps = declPackageSet [
|
||||
# package sets
|
||||
"pcGameApps"
|
||||
"pcTuiApps"
|
||||
####
|
||||
"audacity"
|
||||
# "blanket" # ambient noise generator
|
||||
"brave" # for the integrated wallet -- as a backup
|
||||
# "cantata" # music player (mpd frontend)
|
||||
# "chromium" # chromium takes hours to build. brave is chromium-based, distributed in binary form, so prefer it.
|
||||
# "cups"
|
||||
"discord" # x86-only
|
||||
"electrum"
|
||||
"element-desktop"
|
||||
"firefox"
|
||||
"font-manager"
|
||||
# "gajim" # XMPP client. cross build tries to import host gobject-introspection types (2023/09/01)
|
||||
"gimp" # broken on phosh
|
||||
# "gnome.dconf-editor"
|
||||
# "gnome.file-roller"
|
||||
"gnome.gnome-disk-utility"
|
||||
"gnome.nautilus" # file browser
|
||||
# "gnome.totem" # video player, supposedly supports UPnP
|
||||
"handbrake"
|
||||
"inkscape"
|
||||
# "jellyfin-media-player"
|
||||
"kdenlive"
|
||||
# "kid3" # audio tagging
|
||||
"krita"
|
||||
"libreoffice" # TODO: replace with an office suite that uses saner packaging?
|
||||
"losslesscut-bin" # x86-only
|
||||
# "makemkv" # x86-only
|
||||
# "monero-gui" # x86-only
|
||||
# "mumble"
|
||||
# "nheko" # Matrix chat client
|
||||
# "nicotine-plus" # soulseek client. before re-enabling this make sure it's properly sandboxed!
|
||||
# "obsidian"
|
||||
# "openscad" # 3d modeling
|
||||
# "rhythmbox" # local music player
|
||||
# "slic3r"
|
||||
"soundconverter"
|
||||
"spotify" # x86-only
|
||||
"steam"
|
||||
"tor-browser" # x86-only
|
||||
# "vlc"
|
||||
"wireshark" # could maybe ship the cli as sysadmin pkg
|
||||
# "xterm" # requires Xwayland
|
||||
# "zecwallet-lite" # x86-only
|
||||
# "zulip"
|
||||
];
|
||||
|
||||
|
||||
# INDIVIDUAL PACKAGE DEFINITIONS
|
||||
|
||||
@@ -237,14 +407,6 @@ in
|
||||
bridge-utils.sandbox.method = "bwrap"; #< bwrap, landlock: both work
|
||||
bridge-utils.sandbox.net = "all";
|
||||
|
||||
brightnessctl.sandbox.method = "landlock"; # also bwrap, but landlock is more responsive
|
||||
brightnessctl.sandbox.extraPaths = [
|
||||
"/sys/class/backlight"
|
||||
"/sys/class/leds"
|
||||
"/sys/devices"
|
||||
];
|
||||
brightnessctl.sandbox.whitelistDbus = [ "system" ];
|
||||
|
||||
btrfs-progs.sandbox.method = "bwrap"; #< bwrap, landlock: both work
|
||||
btrfs-progs.sandbox.autodetectCliPaths = "existing"; # e.g. `btrfs filesystem df /my/fs`
|
||||
|
||||
@@ -305,7 +467,7 @@ in
|
||||
];
|
||||
|
||||
dtc.sandbox.method = "bwrap";
|
||||
dtc.sandbox.autodetectCliPaths = true; # TODO:sandbox: untested
|
||||
dtc.sandbox.autodetectCliPaths = "existingFile"; # TODO:sandbox: untested
|
||||
|
||||
duplicity = {};
|
||||
|
||||
@@ -341,10 +503,9 @@ in
|
||||
ethtool.sandbox.capabilities = [ "net_admin" ];
|
||||
|
||||
# eza `ls` replacement
|
||||
# landlock is OK, only `whitelistPwd` doesn't make the intermediate symlinks traversable, so it breaks on e.g. ~/Videos/servo/Shows/foo
|
||||
# eza.sandbox.method = "landlock";
|
||||
eza.sandbox.method = "bwrap";
|
||||
eza.sandbox.autodetectCliPaths = true;
|
||||
eza.sandbox.method = "bwrap"; #< note that bwrap causes `/proc` files to be listed differently (e.g. `eza /proc/sys/net/ipv6/conf/`)
|
||||
eza.sandbox.autodetectCliPaths = "existing";
|
||||
eza.sandbox.whitelistPwd = true;
|
||||
eza.sandbox.extraHomePaths = [
|
||||
# so that e.g. `eza -l ~` can show which symlink exist
|
||||
@@ -356,7 +517,7 @@ in
|
||||
fatresize.sandbox.autodetectCliPaths = "parent"; # /dev/sda1 -> needs /dev/sda
|
||||
|
||||
fd.sandbox.method = "landlock";
|
||||
fd.sandbox.autodetectCliPaths = true;
|
||||
fd.sandbox.autodetectCliPaths = "existing";
|
||||
fd.sandbox.whitelistPwd = true;
|
||||
fd.sandbox.extraHomePaths = [
|
||||
# let it follow symlinks to non-sensitive data
|
||||
@@ -369,10 +530,10 @@ in
|
||||
ffmpeg.sandbox.autodetectCliPaths = "existingFileOrParent"; # it outputs uncreated files -> parent dir needs mounting
|
||||
|
||||
file.sandbox.method = "bwrap";
|
||||
file.sandbox.autodetectCliPaths = true;
|
||||
file.sandbox.autodetectCliPaths = "existing"; #< file OR directory, yes
|
||||
|
||||
findutils.sandbox.method = "bwrap";
|
||||
findutils.sandbox.autodetectCliPaths = true;
|
||||
findutils.sandbox.autodetectCliPaths = "existing";
|
||||
findutils.sandbox.whitelistPwd = true;
|
||||
findutils.sandbox.extraHomePaths = [
|
||||
# let it follow symlinks to non-sensitive data
|
||||
@@ -391,9 +552,7 @@ in
|
||||
});
|
||||
|
||||
forkstat.sandbox.method = "landlock"; #< doesn't seem to support bwrap
|
||||
forkstat.sandbox.extraConfig = [
|
||||
"--sanebox-keep-namespace" "pid"
|
||||
];
|
||||
forkstat.sandbox.isolatePids = false;
|
||||
forkstat.sandbox.extraPaths = [
|
||||
"/proc"
|
||||
];
|
||||
@@ -407,7 +566,7 @@ in
|
||||
|
||||
gawk.sandbox.method = "bwrap"; # TODO:sandbox: untested
|
||||
gawk.sandbox.wrapperType = "inplace"; # /share/gawk libraries refer to /libexec
|
||||
gawk.sandbox.autodetectCliPaths = true;
|
||||
gawk.sandbox.autodetectCliPaths = "existingFile";
|
||||
|
||||
gdb.sandbox.enable = false; # gdb doesn't sandbox well. i don't know how you could.
|
||||
# gdb.sandbox.method = "landlock"; # permission denied when trying to attach, even as root
|
||||
@@ -503,7 +662,7 @@ in
|
||||
"gnome.hitori".sandbox.whitelistWayland = true;
|
||||
|
||||
gnugrep.sandbox.method = "bwrap";
|
||||
gnugrep.sandbox.autodetectCliPaths = true;
|
||||
gnugrep.sandbox.autodetectCliPaths = "existing";
|
||||
gnugrep.sandbox.whitelistPwd = true;
|
||||
gnugrep.sandbox.extraHomePaths = [
|
||||
# let it follow symlinks to non-sensitive data
|
||||
@@ -511,7 +670,6 @@ in
|
||||
".persist/plaintext"
|
||||
];
|
||||
|
||||
# sed: there is an edgecase of `--file=<foo>`, wherein `foo` won't be whitelisted.
|
||||
gnused.sandbox.method = "bwrap";
|
||||
gnused.sandbox.autodetectCliPaths = "existingFile";
|
||||
gnused.sandbox.whitelistPwd = true; #< `-i` flag creates a temporary file in pwd (?) and then moves it.
|
||||
@@ -537,7 +695,7 @@ in
|
||||
|
||||
# hdparm: has to be run as sudo. e.g. `sudo hdparm -i /dev/sda`
|
||||
hdparm.sandbox.method = "bwrap";
|
||||
hdparm.sandbox.autodetectCliPaths = true;
|
||||
hdparm.sandbox.autodetectCliPaths = "existingFile";
|
||||
|
||||
host.sandbox.method = "landlock";
|
||||
host.sandbox.net = "all"; #< technically, only needs to contact localhost's DNS server
|
||||
@@ -572,16 +730,16 @@ in
|
||||
iotop.sandbox.capabilities = [ "net_admin" ];
|
||||
|
||||
# provides `ip`, `routel`, `bridge`, others.
|
||||
# landlock works fine for most of these, but `ip netns exec` uses namespaces internally,
|
||||
# and that's incompatible with landlock
|
||||
iproute2.sandbox.method = "bwrap";
|
||||
iproute2.sandbox.net = "all";
|
||||
iproute2.sandbox.capabilities = [ "net_admin" ];
|
||||
iproute2.sandbox.extraPaths = [
|
||||
"/run/netns" # for `ip netns ...` to work, but maybe not needed anymore?
|
||||
"/sys/class/net" # for `ip netns ...` to work
|
||||
"/var/run/netns"
|
||||
];
|
||||
# landlock works fine for most of these, but `ip netns exec` wants to attach to an existing namespace
|
||||
# and that means we can't use ANY sandboxer for it.
|
||||
iproute2.sandbox.enable = false;
|
||||
# iproute2.sandbox.net = "all";
|
||||
# iproute2.sandbox.capabilities = [ "net_admin" ];
|
||||
# iproute2.sandbox.extraPaths = [
|
||||
# "/run/netns" # for `ip netns ...` to work, but maybe not needed anymore?
|
||||
# "/sys/class/net" # for `ip netns ...` to work
|
||||
# "/var/run/netns"
|
||||
# ];
|
||||
|
||||
iptables.sandbox.method = "landlock";
|
||||
iptables.sandbox.net = "all";
|
||||
@@ -693,9 +851,15 @@ in
|
||||
nixpkgs-review.sandbox.wrapperType = "inplace"; #< shell completions use full paths
|
||||
nixpkgs-review.sandbox.net = "clearnet";
|
||||
nixpkgs-review.sandbox.whitelistPwd = true;
|
||||
nixpkgs-review.sandbox.extraHomePaths = [
|
||||
".config/git" #< it needs to know commiter name/email, even if not posting
|
||||
];
|
||||
nixpkgs-review.sandbox.extraPaths = [
|
||||
"/nix"
|
||||
];
|
||||
nixpkgs-review.persist.byStore.cryptClearOnBoot = [
|
||||
".cache/nixpkgs-review" #< help it not exhaust / tmpfs
|
||||
];
|
||||
|
||||
nmap.sandbox.method = "bwrap";
|
||||
nmap.sandbox.net = "all"; # clearnet and lan
|
||||
@@ -757,9 +921,7 @@ in
|
||||
|
||||
# procps: free, pgrep, pidof, pkill, ps, pwait, top, uptime, couple others
|
||||
procps.sandbox.method = "bwrap";
|
||||
procps.sandbox.extraConfig = [
|
||||
"--sanebox-keep-namespace" "pid"
|
||||
];
|
||||
procps.sandbox.isolatePids = false;
|
||||
|
||||
pstree.sandbox.method = "landlock";
|
||||
pstree.sandbox.extraPaths = [
|
||||
@@ -797,15 +959,21 @@ in
|
||||
|
||||
rustc = {};
|
||||
|
||||
sane-cast = {}; #< TODO: sandbox this the same way i sandbox go2tv
|
||||
sane-cast.sandbox.method = "bwrap";
|
||||
sane-cast.sandbox.net = "clearnet";
|
||||
sane-cast.sandbox.autodetectCliPaths = "existingFile";
|
||||
sane-cast.suggestedPrograms = [ "go2tv" ];
|
||||
|
||||
sane-die-with-parent.sandbox.enable = false; #< it's a launcher; can't sandbox
|
||||
|
||||
sane-weather.sandbox.method = "bwrap";
|
||||
sane-weather.sandbox.net = "clearnet";
|
||||
|
||||
screen.sandbox.enable = false; #< tty; needs to run anything
|
||||
|
||||
sequoia.sandbox.method = "bwrap"; # TODO:sandbox: untested
|
||||
sequoia.sandbox.whitelistPwd = true;
|
||||
sequoia.sandbox.autodetectCliPaths = true;
|
||||
sequoia.sandbox.autodetectCliPaths = "existingFileOrParent"; # supports `-o <file-to-create>`
|
||||
|
||||
shattered-pixel-dungeon.buildCost = 1;
|
||||
shattered-pixel-dungeon.persist.byStore.plaintext = [ ".local/share/.shatteredpixel/shattered-pixel-dungeon" ];
|
||||
@@ -827,6 +995,8 @@ in
|
||||
smartmontools.sandbox.autodetectCliPaths = "existing";
|
||||
smartmontools.sandbox.capabilities = [ "sys_rawio" ];
|
||||
|
||||
# snapshot camera, based on libcamera
|
||||
# TODO: enable dma heaps for more efficient buffer sharing: <https://gitlab.com/postmarketOS/pmaports/-/issues/2789>
|
||||
snapshot = {};
|
||||
|
||||
sops.sandbox.method = "bwrap"; # TODO:sandbox: untested
|
||||
@@ -900,7 +1070,7 @@ in
|
||||
tokodon.persist.byStore.private = [ ".cache/KDE/tokodon" ];
|
||||
|
||||
tree.sandbox.method = "landlock";
|
||||
tree.sandbox.autodetectCliPaths = true;
|
||||
tree.sandbox.autodetectCliPaths = "existing";
|
||||
tree.sandbox.whitelistPwd = true;
|
||||
|
||||
tumiki-fighters.buildCost = 1;
|
||||
@@ -967,6 +1137,8 @@ in
|
||||
wl-clipboard.sandbox.whitelistWayland = true;
|
||||
|
||||
wtype = {};
|
||||
wtype.sandbox.method = "bwrap";
|
||||
wtype.sandbox.whitelistWayland = true;
|
||||
|
||||
xwayland.sandbox.method = "bwrap";
|
||||
xwayland.sandbox.wrapperType = "inplace"; #< consumers use it as a library (e.g. wlroots)
|
||||
@@ -985,7 +1157,44 @@ in
|
||||
zfs = {};
|
||||
};
|
||||
|
||||
programs.feedbackd = lib.mkIf config.sane.programs.feedbackd.enabled {
|
||||
sane.persist.sys.byStore.plaintext = lib.mkIf config.sane.programs.guiApps.enabled [
|
||||
# "/var/lib/alsa" # preserve output levels, default devices
|
||||
{ path = "/var/lib/systemd/backlight"; method = "bind"; } # backlight brightness; bind because systemd T_T
|
||||
];
|
||||
|
||||
systemd.services."systemd-backlight@" = lib.mkIf config.sane.programs.guiApps.enabled {
|
||||
after = [
|
||||
"ensure-var-lib-systemd-backlight.service"
|
||||
];
|
||||
wants = [
|
||||
"ensure-var-lib-systemd-backlight.service"
|
||||
];
|
||||
};
|
||||
|
||||
hardware.opengl = lib.mkIf config.sane.programs.guiApps.enabled ({
|
||||
enable = true;
|
||||
driSupport = lib.mkDefault true;
|
||||
} // (lib.optionalAttrs pkgs.stdenv.isx86_64 {
|
||||
# for 32 bit applications
|
||||
# upstream nixpkgs forbids setting driSupport32Bit unless specifically x86_64 (so aarch64 isn't allowed)
|
||||
driSupport32Bit = lib.mkDefault true;
|
||||
}));
|
||||
|
||||
system.activationScripts.notifyActive = lib.mkIf config.sane.programs.guiApps.enabled {
|
||||
text = lib.concatStringsSep "\n" ([
|
||||
''
|
||||
tryNotifyUser() {
|
||||
local user="$1"
|
||||
local new_path="$PATH:${pkgs.sudo}/bin:${pkgs.libnotify}/bin"
|
||||
local version="$(cat $systemConfig/nixos-version)"
|
||||
PATH="$new_path" sudo -u "$user" \
|
||||
env PATH="$new_path" NIXOS_VERSION="$version" /bin/sh -c \
|
||||
'. $HOME/.profile; dbus_file="$XDG_RUNTIME_DIR/bus"; if [ -z "$DBUS_SESSION_BUS_ADDRESS" ] && [ -e "$dbus_file" ]; then export DBUS_SESSION_BUS_ADDRESS="unix:path=$dbus_file"; fi ; if [ -n "$DBUS_SESSION_BUS_ADDRESS" ]; then notify-send "nixos activated" "version: $NIXOS_VERSION" ; fi'
|
||||
}
|
||||
''
|
||||
] ++ lib.mapAttrsToList
|
||||
(user: en: lib.optionalString en "tryNotifyUser ${user}")
|
||||
config.sane.programs.guiApps.enableFor.user
|
||||
);
|
||||
};
|
||||
}
|
||||
|
@@ -19,7 +19,7 @@
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.autodetectCliPaths = true;
|
||||
sandbox.autodetectCliPaths = "existingFile";
|
||||
sandbox.extraHomePaths = [
|
||||
# support media imports via file->open dir to some common media directories
|
||||
"tmp"
|
||||
|
10
hosts/common/programs/ausyscall.nix
Normal file
10
hosts/common/programs/ausyscall.nix
Normal file
@@ -0,0 +1,10 @@
|
||||
# `ausyscall --dump`: lists all syscalls by number and name
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
sane.programs.ausyscall = {
|
||||
packageUnwrapped = pkgs.linkIntoOwnPackage pkgs.audit "bin/ausyscall";
|
||||
|
||||
sandbox.method = "landlock";
|
||||
};
|
||||
}
|
||||
|
@@ -87,7 +87,7 @@ let
|
||||
in
|
||||
{
|
||||
sane.programs.bemenu = {
|
||||
sandbox.method = "bwrap"; # landlock works, but requires *all* of /run/user/$ID to be granted.
|
||||
sandbox.method = "bwrap"; # landlock works, but requires *all* of $XDG_RUNTIME_DIR to be granted.
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.extraHomePaths = [
|
||||
".cache/fontconfig" #< else it complains, and is *way* slower
|
||||
|
@@ -39,11 +39,9 @@ in
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.net = "clearnet";
|
||||
sandbox.extraConfig = [
|
||||
# else it fails to reap its children (or, maybe, it fails to hook its parent's death signal?)
|
||||
# might be possible to remove this, but kinda hard to see a clean way.
|
||||
"--sanebox-keep-namespace" "pid"
|
||||
];
|
||||
#v else it fails to reap its children (or, maybe, it fails to hook its parent's death signal?)
|
||||
#v might be possible to remove this, but kinda hard to see a clean way.
|
||||
sandbox.isolatePids = false;
|
||||
suggestedPrograms = [ "blast-ugjka" "sane-die-with-parent" ];
|
||||
};
|
||||
|
||||
|
@@ -103,19 +103,37 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
packageUnwrapped = pkgs.bonsai.overrideAttrs (upstream: {
|
||||
# patch to place the socket in a subdirectory where it can be sandboxed
|
||||
postPatch = (upstream.postPatch or "") + ''
|
||||
substituteInPlace cmd/{bonsaictl,bonsaid}/main.ha \
|
||||
--replace-fail 'path::set(&buf, statedir, "bonsai")' 'path::set(&buf, statedir, "bonsai/bonsai")'
|
||||
'';
|
||||
});
|
||||
|
||||
fs.".config/bonsai/bonsai_tree.json".symlink.text = builtins.toJSON cfg.config.transitions;
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.extraRuntimePaths = [
|
||||
"/" #< just needs "bonsai", but needs to create it first...
|
||||
"bonsai"
|
||||
];
|
||||
|
||||
services.bonsaid = {
|
||||
description = "bonsai: programmable input dispatcher";
|
||||
dependencyOf = [ "sway" ]; # to ensure `$XDG_RUNTIME_DIR/bonsai` exists before sway binds it
|
||||
partOf = [ "graphical-session" ];
|
||||
# nice -n -11 chosen arbitrarily. i hope this will allow for faster response to inputs, but without audio underruns (pipewire is -21, dino -15-ish)
|
||||
command = "nice -n -11 bonsaid -t $HOME/.config/bonsai/bonsai_tree.json";
|
||||
cleanupCommand = "rm -f $XDG_RUNTIME_DIR/bonsai";
|
||||
command = pkgs.writeShellScript "bonsai-start" ''
|
||||
# TODO: don't create the sway directory here!
|
||||
# i do it for now because sway and bonsai call into eachother; circular dependency:
|
||||
# - sway -> bonsai -> sane-input-handler -> swaymsg
|
||||
mkdir -p $XDG_RUNTIME_DIR/{bonsai,sway}
|
||||
exec nice -n -11 bonsaid -t $HOME/.config/bonsai/bonsai_tree.json
|
||||
'';
|
||||
cleanupCommand = "rm -f $XDG_RUNTIME_DIR/bonsai/bonsai";
|
||||
readiness.waitExists = [
|
||||
"$XDG_RUNTIME_DIR/bonsai/bonsai"
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
|
@@ -8,6 +8,9 @@
|
||||
"dev" # for developing anything web-related
|
||||
"tmp"
|
||||
];
|
||||
sandbox.extraPaths = [
|
||||
"/tmp" # needed particularly if run from `sane-vpn do`
|
||||
];
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.whitelistDri = true;
|
||||
sandbox.whitelistWayland = true;
|
||||
|
23
hosts/common/programs/brightnessctl.nix
Normal file
23
hosts/common/programs/brightnessctl.nix
Normal file
@@ -0,0 +1,23 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
cfg = config.sane.programs.brightnessctl;
|
||||
in
|
||||
{
|
||||
sane.programs.brightnessctl = {
|
||||
sandbox.method = "landlock"; # also bwrap, but landlock is more responsive
|
||||
sandbox.extraPaths = [
|
||||
"/sys/class/backlight"
|
||||
"/sys/class/leds"
|
||||
"/sys/devices"
|
||||
];
|
||||
# sandbox.whitelistDbus = [ "system" ]; #< only necessary if not granting udev perms
|
||||
};
|
||||
|
||||
services.udev.extraRules = let
|
||||
chmod = "${pkgs.coreutils}/bin/chmod";
|
||||
chown = "${pkgs.coreutils}/bin/chown";
|
||||
in lib.mkIf cfg.enabled ''
|
||||
# make backlight controllable by members of `video`
|
||||
SUBSYSTEM=="backlight", RUN+="${chown} :video $sys$devpath/brightness", RUN+="${chmod} g+w $sys$devpath/brightness"
|
||||
'';
|
||||
}
|
@@ -13,6 +13,10 @@
|
||||
sane.programs.callaudiod = {
|
||||
packageUnwrapped = pkgs.rmDbusServices pkgs.callaudiod;
|
||||
|
||||
# probably more needed once i enable proper sandboxing, but for now this ensures the service isn't started too early!
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.whitelistDbus = [ "user" ];
|
||||
|
||||
services.callaudiod = {
|
||||
description = "callaudiod: dbus service to switch audio profiles and mute microphone";
|
||||
partOf = [ "default" ];
|
||||
|
@@ -1,7 +1,18 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
sane.programs.sane-battery-estimate = {
|
||||
packageUnwrapped = pkgs.static-nix-shell.mkBash {
|
||||
pname = "sane-battery-estimate";
|
||||
srcRoot = ./.;
|
||||
};
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.extraPaths = [
|
||||
"/sys/class/power_supply"
|
||||
"/sys/devices"
|
||||
];
|
||||
};
|
||||
|
||||
sane.programs.conky = {
|
||||
# TODO: non-sandboxed `conky` still ships via `sxmo-utils`, but unused
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.net = "clearnet"; #< for the scripts it calls (weather)
|
||||
sandbox.extraPaths = [
|
||||
@@ -12,18 +23,16 @@
|
||||
];
|
||||
sandbox.whitelistWayland = true;
|
||||
|
||||
fs.".config/conky/conky.conf".symlink.target =
|
||||
let
|
||||
# TODO: make this just another `suggestedPrograms`!
|
||||
battery_estimate = pkgs.static-nix-shell.mkBash {
|
||||
pname = "battery_estimate";
|
||||
srcRoot = ./.;
|
||||
};
|
||||
in pkgs.substituteAll {
|
||||
src = ./conky.conf;
|
||||
bat = "${battery_estimate}/bin/battery_estimate";
|
||||
weather = "timeout 20 ${pkgs.sane-weather}/bin/sane-weather";
|
||||
};
|
||||
suggestedPrograms = [
|
||||
"sane-battery-estimate"
|
||||
"sane-weather"
|
||||
];
|
||||
|
||||
fs.".config/conky/conky.conf".symlink.target = pkgs.substituteAll {
|
||||
src = ./conky.conf;
|
||||
bat = "sane-battery-estimate";
|
||||
weather = "timeout 20 sane-weather";
|
||||
};
|
||||
|
||||
services.conky = {
|
||||
description = "conky dynamic desktop background";
|
||||
|
@@ -1,4 +1,3 @@
|
||||
#!/bin/sh
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i bash
|
||||
|
||||
@@ -15,7 +14,7 @@ usage() {
|
||||
echo " --percent-suffix <string>: use the provided string when displaying percents"
|
||||
}
|
||||
|
||||
# these icons come from sxmo; they only render in nerdfonts
|
||||
# these icons may only render in nerdfonts
|
||||
icon_bat_chg=("" "" "" "")
|
||||
icon_bat_dis=("" "" "" "")
|
||||
suffix_icon=" " # thin space
|
54
hosts/common/programs/dbus.nix
Normal file
54
hosts/common/programs/dbus.nix
Normal file
@@ -0,0 +1,54 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
cfg = config.sane.programs.dissent;
|
||||
in
|
||||
{
|
||||
sane.programs.dbus = {
|
||||
configOption = with lib; mkOption {
|
||||
default = {};
|
||||
type = types.submodule {
|
||||
options.autostart = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
packageUnwrapped = (pkgs.dbus.override {
|
||||
# remove features i don't want. mostly to avoid undesired interactions, but also it reduces the closure by 55 MB :)
|
||||
enableSystemd = false;
|
||||
x11Support = false;
|
||||
}).overrideAttrs (upstream: {
|
||||
postFixup = (upstream.postFixup or "") + ''
|
||||
# the XML docs have a URI field which points to self,
|
||||
# and that breaks the sandbox checker
|
||||
substituteInPlace $out/share/xml/dbus-1/catalog.xml \
|
||||
--replace-fail "$out" "/run/current-system/sw"
|
||||
|
||||
# conf file points to dbus-daemon-launch-helper by absolute path,
|
||||
# which breaks sandboxing. i don't want dbus auto-launching stuff anyway though.
|
||||
substituteInPlace $out/share/dbus-1/system.conf \
|
||||
--replace-fail "$out/libexec/dbus-daemon-launch-helper" "false"
|
||||
'';
|
||||
});
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.extraRuntimePaths = [
|
||||
"/" #< it needs to create a file in the root. TODO: move the bus handle into a sandboxable subdirectory
|
||||
];
|
||||
sandbox.isolatePids = false; #< not actually sure *why* this is necessary, but it is
|
||||
|
||||
env.DBUS_SESSION_BUS_ADDRESS = "unix:path=$XDG_RUNTIME_DIR/bus";
|
||||
|
||||
# normally systemd would create a dbus session for us, but if you configure it not to do that
|
||||
# then we can create our own. not sure if there's a dependency ordering issue here: lots
|
||||
# of things depend on dbus but i don't do anything special to guarantee this is initialized
|
||||
# before them.
|
||||
services.dbus = {
|
||||
description = "dbus user session";
|
||||
partOf = lib.mkIf cfg.config.autostart [ "default" ];
|
||||
command = "dbus-daemon --session --nofork --address=$DBUS_SESSION_BUS_ADDRESS";
|
||||
readiness.waitExists = [ "$XDG_RUNTIME_DIR/bus" ];
|
||||
};
|
||||
};
|
||||
}
|
@@ -34,7 +34,7 @@ in
|
||||
|
||||
services.dconf = {
|
||||
description = "dconf configuration database/server";
|
||||
partOf = [ "graphical-session" ];
|
||||
partOf = [ "default" ];
|
||||
command = "${lib.getLib cfg.package}/libexec/dconf-service";
|
||||
};
|
||||
|
||||
|
@@ -9,10 +9,12 @@
|
||||
./animatch.nix
|
||||
./assorted.nix
|
||||
./audacity.nix
|
||||
./ausyscall.nix
|
||||
./bemenu.nix
|
||||
./blast-ugjka
|
||||
./bonsai.nix
|
||||
./brave.nix
|
||||
./brightnessctl.nix
|
||||
./bubblewrap.nix
|
||||
./callaudiod.nix
|
||||
./calls.nix
|
||||
@@ -24,6 +26,7 @@
|
||||
./cozy.nix
|
||||
./cups.nix
|
||||
./curlftpfs.nix
|
||||
./dbus.nix
|
||||
./dconf.nix
|
||||
./deadd-notification-center
|
||||
./dialect.nix
|
||||
@@ -77,6 +80,7 @@
|
||||
./megapixels.nix
|
||||
./mepo.nix
|
||||
./mimeo
|
||||
./mmcli.nix
|
||||
./modemmanager.nix
|
||||
./mopidy.nix
|
||||
./mpv
|
||||
@@ -88,6 +92,7 @@
|
||||
./nheko.nix
|
||||
./nicotine-plus.nix
|
||||
./nix-index.nix
|
||||
./nmcli.nix
|
||||
./notejot.nix
|
||||
./ntfy-sh.nix
|
||||
./objdump.nix
|
||||
@@ -107,9 +112,12 @@
|
||||
./sane-open.nix
|
||||
./sane-screenshot.nix
|
||||
./sane-scripts.nix
|
||||
./sane-theme.nix
|
||||
./sanebox.nix
|
||||
./schlock.nix
|
||||
./seatd.nix
|
||||
./sfeed.nix
|
||||
./shadow.nix
|
||||
./signal-desktop.nix
|
||||
./splatmoji.nix
|
||||
./spot.nix
|
||||
|
@@ -1,7 +1,20 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
sane.programs.errno = {
|
||||
packageUnwrapped = pkgs.linkIntoOwnPackage pkgs.moreutils "bin/errno";
|
||||
# packageUnwrapped = pkgs.linkIntoOwnPackage pkgs.moreutils "bin/errno";
|
||||
# actually, don't build all of moreutils because not all of it builds for cross targets.
|
||||
# some of this can be simplified after <https://github.com/NixOS/nixpkgs/pull/316446>
|
||||
packageUnwrapped = pkgs.moreutils.overrideAttrs (base: {
|
||||
makeFlags = (base.makeFlags or []) ++ [
|
||||
"BINS=errno"
|
||||
"MANS=errno.1"
|
||||
"PERLSCRIPTS=errno" #< Makefile errors if empty, but this works :)
|
||||
"INSTALL_BIN=install"
|
||||
];
|
||||
#v disable the perl-specific stuff
|
||||
propagatedBuildInputs = [];
|
||||
postInstall = "";
|
||||
});
|
||||
|
||||
sandbox.method = "landlock";
|
||||
};
|
||||
|
@@ -4,7 +4,7 @@
|
||||
buildCost = 1;
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.autodetectCliPaths = true;
|
||||
sandbox.autodetectCliPaths = "existingFile";
|
||||
sandbox.whitelistWayland = true;
|
||||
|
||||
mime.associations."application/pdf" = "org.gnome.Evince.desktop";
|
||||
|
@@ -209,7 +209,7 @@ in
|
||||
};
|
||||
i-still-dont-care-about-cookies = {
|
||||
package = pkgs.firefox-extensions.i-still-dont-care-about-cookies;
|
||||
enable = lib.mkDefault true;
|
||||
enable = lib.mkDefault false; #< obsoleted by uBlock Origin annoyances/cookies lists
|
||||
};
|
||||
open-in-mpv = {
|
||||
# test: `open-in-mpv 'mpv:///open?url=https://www.youtube.com/watch?v=dQw4w9WgXcQ'`
|
||||
@@ -226,7 +226,7 @@ in
|
||||
};
|
||||
ublacklist = {
|
||||
package = pkgs.firefox-extensions.ublacklist;
|
||||
enable = lib.mkDefault true;
|
||||
enable = lib.mkDefault false;
|
||||
};
|
||||
ublock-origin = {
|
||||
package = pkgs.firefox-extensions.ublock-origin;
|
||||
@@ -286,24 +286,35 @@ in
|
||||
# env.BROWSER = "${package}/bin/${cfg.browser.libName}";
|
||||
env.BROWSER = cfg.browser.libName; # used by misc tools like xdg-email, as fallback
|
||||
|
||||
# uBlock filter list configuration.
|
||||
# specifically, enable the GDPR cookie prompt blocker.
|
||||
# data.toOverwrite.filterLists is additive (i.e. it supplements the default filters)
|
||||
# this configuration method is documented here:
|
||||
# - <https://github.com/gorhill/uBlock/issues/2986#issuecomment-364035002>
|
||||
# the specific attribute path is found via scraping ublock code here:
|
||||
# - <https://github.com/gorhill/uBlock/blob/master/src/js/storage.js>
|
||||
# - <https://github.com/gorhill/uBlock/blob/master/assets/assets.json>
|
||||
fs."${cfg.browser.dotDir}/managed-storage/uBlock0@raymondhill.net.json".symlink.text = ''
|
||||
{
|
||||
"name": "uBlock0@raymondhill.net",
|
||||
"description": "ignored",
|
||||
"type": "storage",
|
||||
"data": {
|
||||
"toOverwrite": "{\"filterLists\": [\"fanboy-cookiemonster\"]}"
|
||||
}
|
||||
}
|
||||
'';
|
||||
# uBlock configuration:
|
||||
fs."${cfg.browser.dotDir}/managed-storage/uBlock0@raymondhill.net.json".symlink.target = cfg.addons.ublock-origin.package.makeConfig {
|
||||
# more filter lists are available here:
|
||||
# - <https://easylist.to>
|
||||
# - <https://github.com/easylist/easylist.git>
|
||||
# - <https://github.com/yokoffing/filterlists>
|
||||
filterFiles = let
|
||||
getUasset = n: "${pkgs.uassets}/share/filters/${n}.txt";
|
||||
in [
|
||||
# default ublock filters:
|
||||
(getUasset "ublock-filters")
|
||||
(getUasset "ublock-badware")
|
||||
(getUasset "ublock-privacy")
|
||||
(getUasset "ublock-quick-fixes")
|
||||
(getUasset "ublock-unbreak")
|
||||
(getUasset "easylist")
|
||||
(getUasset "easyprivacy")
|
||||
# (getUasset "urlhaus-1") #< TODO: i think this is the same as urlhaus-filter-online
|
||||
(getUasset "urlhaus-filter-online")
|
||||
# (getUasset "plowe-0") #< TODO: where does this come from?
|
||||
# (getUasset "ublock-cookies-adguard") #< TODO: where does this come from?
|
||||
# filters i've added:
|
||||
(getUasset "easylist-annoyances") #< blocks in-page popups, "social media content" (e.g. FB like button; improves loading time)
|
||||
(getUasset "easylist-cookies") #< blocks GDPR cookie consent popovers (e.g. at stackoverflow.com)
|
||||
# (getUasset "ublock-annoyances-others")
|
||||
# (getUasset "ublock-annoyances-cookies")
|
||||
];
|
||||
};
|
||||
|
||||
# TODO: this is better suited in `extraPrefs` during `wrapFirefox` call
|
||||
fs."${cfg.browser.dotDir}/${cfg.browser.libName}.overrides.cfg".symlink.text = ''
|
||||
// if we can't query the revocation status of a SSL cert because the issuer is offline,
|
||||
@@ -327,6 +338,8 @@ in
|
||||
defaultPref("widget.use-xdg-desktop-portal.open-uri", 1);
|
||||
|
||||
defaultPref("browser.toolbars.bookmarks.visibility", "never");
|
||||
// configure which extensions are visible by default (TODO: requires a lot of trial and error)
|
||||
// defaultPref("browser.uiCustomization.state", ...);
|
||||
|
||||
// auto-open mpv:// URIs without prompting.
|
||||
// can do this with other protocols too (e.g. matrix?). see about:config for common handlers.
|
||||
|
@@ -16,13 +16,11 @@ let
|
||||
# - (message bubble)
|
||||
# - (phone)
|
||||
# - (weather/sun-behind-clouds)
|
||||
# used particularly by sxmo utilities, but also a few of my own (e.g. conky)
|
||||
# i use these icons mostly in conky, swaync.
|
||||
#
|
||||
# nerdfonts is very heavy. each font is 20-900 MiB (2 MiB per "variation")
|
||||
# lots of redundant data inside there, but no deduplication except whatever nix or the fs does implicitly.
|
||||
wantedNerdfonts = [
|
||||
# used explicitly by SXMO
|
||||
# "DejaVuSansMono" # 25 MiB
|
||||
# good terminal/coding font. grab via nerdfonts for more emoji/unicode support
|
||||
"Hack" # 26 MiB
|
||||
"Noto" # 861 MiB
|
||||
|
@@ -50,7 +50,7 @@ in
|
||||
sane.programs.go2tv = {
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.net = "clearnet";
|
||||
sandbox.autodetectCliPaths = true;
|
||||
sandbox.autodetectCliPaths = "existingFile";
|
||||
# for GUI invocation, allow the common media directories
|
||||
sandbox.extraHomePaths = [
|
||||
"Music"
|
||||
|
@@ -17,7 +17,7 @@
|
||||
|
||||
# disable expensive sambda dependency; i don't use it.
|
||||
packageUnwrapped = pkgs.handbrake.override {
|
||||
ffmpeg-full = pkgs.ffmpeg-full.override {
|
||||
ffmpeg_7-full = pkgs.ffmpeg_7-full.override {
|
||||
withSamba = false;
|
||||
};
|
||||
};
|
||||
|
@@ -8,7 +8,7 @@
|
||||
packageUnwrapped = pkgs.libreoffice-fresh;
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.autodetectCliPaths = true;
|
||||
sandbox.autodetectCliPaths = "existingFile";
|
||||
sandbox.extraHomePaths = [
|
||||
# allow a spot to save files.
|
||||
# with bwrap sandboxing, saving to e.g. ~/ succeeds but the data is inaccessible outside the sandbox,
|
||||
|
@@ -52,11 +52,9 @@
|
||||
sandbox.extraRuntimePaths = [
|
||||
"dconf" #< else it's very spammy, and slow
|
||||
];
|
||||
sandbox.extraConfig = [
|
||||
# XXX(2024/04/21): without this it fails to convert .dng -> .jpg.
|
||||
# "bwrap: open /proc/34/ns/ns failed: No such file or directory"
|
||||
"--sanebox-keep-namespace" "pid"
|
||||
];
|
||||
# XXX(2024/04/21): without this it fails to convert .dng -> .jpg.
|
||||
# "bwrap: open /proc/34/ns/ns failed: No such file or directory"
|
||||
sandbox.isolatePids = false;
|
||||
|
||||
suggestedPrograms = [ "dconf" ]; #< not sure if necessary
|
||||
};
|
||||
|
12
hosts/common/programs/mmcli.nix
Normal file
12
hosts/common/programs/mmcli.nix
Normal file
@@ -0,0 +1,12 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
sane.programs.mmcli = {
|
||||
packageUnwrapped = pkgs.modemmanager-split.mmcli.overrideAttrs (upstream: {
|
||||
meta = upstream.meta // {
|
||||
mainProgram = "mmcli";
|
||||
};
|
||||
});
|
||||
# TODO: sandbox
|
||||
};
|
||||
}
|
||||
|
@@ -4,35 +4,83 @@ let
|
||||
in
|
||||
{
|
||||
sane.programs.modemmanager = {
|
||||
packageUnwrapped = pkgs.modemmanager-split.daemon.overrideAttrs (upstream: {
|
||||
postInstall = (upstream.postInstall or "") + ''
|
||||
substitute $out/share/dbus-1/system.d/org.freedesktop.ModemManager1.conf \
|
||||
$out/share/dbus-1/system.d/networkmanager-org.freedesktop.ModemManager1.conf \
|
||||
--replace-fail 'user="root"' 'group="networkmanager"'
|
||||
'';
|
||||
|
||||
meta = upstream.meta // {
|
||||
mainProgram = "ModemManager";
|
||||
};
|
||||
});
|
||||
# mmcli needs /run/current-system/sw/share/dbus-1 files to function
|
||||
enableFor.system = lib.mkIf (builtins.any (en: en) (builtins.attrValues cfg.enableFor.user)) true;
|
||||
|
||||
suggestedPrograms = [ "mmcli" ];
|
||||
|
||||
# bwrap sandboxing works, but requires the real user to be root.
|
||||
# landlock sandboxing works, and allows the real user to be someone else (like `networkmanager`).
|
||||
# non-root is very important, because of how many things in e.g. /dev are r/w based on uid=0.
|
||||
# TODO: have the services run as `networkmanager` user
|
||||
sandbox.method = "bwrap";
|
||||
# sandbox.method = "landlock";
|
||||
sandbox.wrapperType = "inplace"; #< .pc files, GIR files with absolute paths,
|
||||
sandbox.net = "all"; #< needed for modem bringup
|
||||
# sandbox.isolatePids = false;
|
||||
sandbox.capabilities = [
|
||||
"net_admin"
|
||||
"net_raw"
|
||||
];
|
||||
sandbox.extraPaths = lib.warn "TODO: modemmanager: sandbox more aggressively" [
|
||||
# "/"
|
||||
"/dev" #v modem-power + net are not enough
|
||||
# "/dev/modem-power"
|
||||
# "/dev/net"
|
||||
"/proc"
|
||||
# /run #v can likely be reduced more
|
||||
"/run/dbus"
|
||||
"/run/NetworkManager"
|
||||
"/run/resolvconf"
|
||||
"/run/systemd"
|
||||
"/run/udev"
|
||||
"/sys"
|
||||
# "/var"
|
||||
];
|
||||
};
|
||||
|
||||
networking.modemmanager = lib.mkIf cfg.enabled {
|
||||
enable = true;
|
||||
package = cfg.package;
|
||||
};
|
||||
|
||||
systemd.services.ModemManager = lib.mkIf cfg.enabled {
|
||||
aliases = [ "dbus-org.freedesktop.ModemManager1.service" ];
|
||||
# aliases = [ "dbus-org.freedesktop.ModemManager1.service" ];
|
||||
after = [ "polkit.service" ];
|
||||
requires = [ "polkit.service" ];
|
||||
wantedBy = [ "network.target" ];
|
||||
serviceConfig = {
|
||||
Type = "dbus";
|
||||
BusName = "org.freedesktop.ModemManager1";
|
||||
# only if started with `--debug` does mmcli let us issue AT commands like
|
||||
# `mmcli --modem any --command=<AT_CMD>`
|
||||
ExecStart = "${cfg.package}/bin/ModemManager --debug";
|
||||
# --debug sets DEBUG level logging: so reset
|
||||
ExecStartPost = "${cfg.package}/bin/mmcli --set-logging=INFO";
|
||||
path = [ "/run/current-system/sw" ]; #< so it can find `sanebox`
|
||||
|
||||
Restart = "on-abort";
|
||||
StandardError = "null";
|
||||
CapabilityBoundingSet = "CAP_SYS_ADMIN CAP_NET_ADMIN";
|
||||
ProtectSystem = true;
|
||||
ProtectHome = true;
|
||||
PrivateTmp = true;
|
||||
RestrictAddressFamilies = "AF_NETLINK AF_UNIX AF_QIPCRTR";
|
||||
NoNewPrivileges = true;
|
||||
};
|
||||
serviceConfig.Type = "dbus";
|
||||
serviceConfig.BusName = "org.freedesktop.ModemManager1";
|
||||
|
||||
# only if started with `--debug` does mmcli let us issue AT commands like
|
||||
# `mmcli --modem any --command=<AT_CMD>`
|
||||
serviceConfig.ExecStart = "${lib.getExe cfg.package} --debug";
|
||||
# --debug sets DEBUG level logging: so reset
|
||||
serviceConfig.ExecStartPost = "${lib.getExe config.sane.programs.mmcli.package} --set-logging=INFO";
|
||||
|
||||
serviceConfig.Restart = "on-abort";
|
||||
serviceConfig.StandardError = "null";
|
||||
serviceConfig.CapabilityBoundingSet = "CAP_SYS_ADMIN CAP_NET_ADMIN";
|
||||
serviceConfig.ProtectSystem = true;
|
||||
serviceConfig.ProtectHome = true;
|
||||
serviceConfig.PrivateTmp = true;
|
||||
serviceConfig.RestrictAddressFamilies = "AF_NETLINK AF_UNIX AF_QIPCRTR";
|
||||
serviceConfig.NoNewPrivileges = true;
|
||||
};
|
||||
|
||||
# so that ModemManager can discover when the modem appears
|
||||
services.udev.packages = lib.mkIf cfg.enabled [ cfg.package ];
|
||||
# services.udev.packages = lib.mkIf cfg.enabled [ cfg.package ];
|
||||
}
|
||||
|
@@ -203,7 +203,7 @@ in
|
||||
];
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.autodetectCliPaths = true;
|
||||
sandbox.autodetectCliPaths = "parent"; #< especially for subtitle downloader; also nice for viewing albums
|
||||
sandbox.net = "all";
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.whitelistDbus = [ "user" ]; #< mpris
|
||||
|
@@ -4,7 +4,7 @@
|
||||
# - properties: <https://mpv.io/manual/master/#property-list>
|
||||
|
||||
# let volume/power keys be interpreted by the system.
|
||||
# this is important for sxmo.
|
||||
# this is important for moby/bonsai.
|
||||
# mpv defaults is POWER = close, VOLUME_{UP,DOWN} = adjust application-level volume
|
||||
POWER ignore
|
||||
VOLUME_UP ignore
|
||||
|
@@ -10,9 +10,9 @@
|
||||
]);
|
||||
}));
|
||||
|
||||
suggestedPrograms = [
|
||||
"gvfs" # browse ftp://, etc
|
||||
];
|
||||
# suggestedPrograms = [
|
||||
# "gvfs" # browse ftp://, etc (TODO: fix!)
|
||||
# ];
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.whitelistDbus = [ "user" ]; # for portals launching apps
|
||||
@@ -36,11 +36,11 @@
|
||||
"/tmp"
|
||||
"/var"
|
||||
];
|
||||
sandbox.extraRuntimePaths = [
|
||||
# not sure if these are actually necessary
|
||||
"gvfs"
|
||||
"gvfsd"
|
||||
];
|
||||
# sandbox.extraRuntimePaths = [
|
||||
# # not sure if these are actually necessary
|
||||
# "gvfs"
|
||||
# "gvfsd"
|
||||
# ];
|
||||
|
||||
mime.priority = 150; #< default is 100, so higher means we fall-back to other apps that might be more specialized
|
||||
mime.associations = {
|
||||
|
@@ -7,101 +7,224 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
cfg = config.sane.programs.networkmanager;
|
||||
networkmanager = pkgs.networkmanager.overrideAttrs (upstream: {
|
||||
src = pkgs.fetchFromGitea {
|
||||
domain = "git.uninsane.org";
|
||||
owner = "colin";
|
||||
repo = "NetworkManager";
|
||||
rev = "dev-sane-1.46.0";
|
||||
hash = "sha256-S5ZiOfCpwtVVVO+DP6OPodJqzSc/LW4waI42DRkT+RA=";
|
||||
};
|
||||
# patches = [];
|
||||
});
|
||||
networkmanager-split = pkgs.networkmanager-split.override { inherit networkmanager; };
|
||||
in
|
||||
{
|
||||
sane.programs.networkmanager = {
|
||||
suggestedPrograms = [ "wpa_supplicant" ];
|
||||
enableFor.system = lib.mkIf (builtins.any (en: en) (builtins.attrValues cfg.enableFor.user)) true;
|
||||
};
|
||||
config = lib.mkMerge [
|
||||
{
|
||||
sane.programs.networkmanager = {
|
||||
packageUnwrapped = networkmanager-split.daemon.overrideAttrs (upstream: {
|
||||
# postPatch = (upstream.postPatch or "") + ''
|
||||
# substituteInPlace src/{core/org.freedesktop.NetworkManager,nm-dispatcher/nm-dispatcher}.conf --replace-fail \
|
||||
# 'user="root"' 'user="networkmanager"'
|
||||
# '';
|
||||
postInstall = (upstream.postInstall or "") + ''
|
||||
# allow the bus to owned by either root or networkmanager users
|
||||
# use the group here, that way ordinary users can be elevated to control networkmanager
|
||||
# (via e.g. `nmcli`)
|
||||
for f in org.freedesktop.NetworkManager.conf nm-dispatcher.conf ; do
|
||||
substitute $out/share/dbus-1/system.d/$f \
|
||||
$out/share/dbus-1/system.d/networkmanager-$f \
|
||||
--replace-fail 'user="root"' 'group="networkmanager"'
|
||||
done
|
||||
|
||||
# add to systemd.packages so we get the service file it ships, then override what we need to customize (taken from nixpkgs)
|
||||
systemd.packages = lib.mkIf cfg.enabled [ cfg.package ];
|
||||
systemd.services.NetworkManager = lib.mkIf cfg.enabled {
|
||||
wantedBy = [ "network.target" ];
|
||||
aliases = [ "dbus-org.freedesktop.NetworkManager.service" ];
|
||||
# remove unused services to prevent any unexpected interactions
|
||||
rm $out/etc/systemd/system/{nm-cloud-setup.service,nm-cloud-setup.timer,nm-priv-helper.service}
|
||||
'';
|
||||
});
|
||||
|
||||
serviceConfig = {
|
||||
StateDirectory = "NetworkManager";
|
||||
StateDirectoryMode = 755; # not sure if this really needs to be 755
|
||||
};
|
||||
};
|
||||
suggestedPrograms = [ "nmcli" "wpa_supplicant" ];
|
||||
enableFor.system = lib.mkIf (builtins.any (en: en) (builtins.attrValues cfg.enableFor.user)) true;
|
||||
|
||||
systemd.services.NetworkManager-wait-online = lib.mkIf cfg.enabled {
|
||||
wantedBy = [ "network-online.target" ];
|
||||
};
|
||||
# this contains both the NetworkManager service and the NetworkManager-dispatcher service
|
||||
# the latter of which calls a lot of user code.
|
||||
# as a result, this needs all the perms which my hook in modules/services/trust-dns/trust-dns-nmhook needs.
|
||||
sandbox.method = "landlock";
|
||||
sandbox.capabilities = [
|
||||
# "dac_override"
|
||||
"net_admin"
|
||||
"net_raw"
|
||||
"net_bind_service" #< TODO: is this needed? why? (DNS?)
|
||||
# "sys_module"
|
||||
"audit_write" #< allow writing to the audit log
|
||||
# "kill"
|
||||
];
|
||||
sandbox.extraPaths = [
|
||||
"/proc/net"
|
||||
"/proc/sys/net"
|
||||
"/run/NetworkManager"
|
||||
"/run/systemd" # for trust-dns-nmhook
|
||||
"/run/udev"
|
||||
# "/run/wg-home.priv"
|
||||
"/sys/class" #< TODO: specify this more precisely
|
||||
"/sys/devices"
|
||||
"/var/lib/NetworkManager"
|
||||
"/var/lib/trust-dns" #< for trust-dns-nmhook
|
||||
];
|
||||
|
||||
systemd.services.NetworkManager-dispatcher = lib.mkIf cfg.enabled {
|
||||
wantedBy = [ "NetworkManager.service" ];
|
||||
# to debug, add NM_DISPATCHER_DEBUG_LOG=1
|
||||
serviceConfig.ExecStart = [
|
||||
"" # first blank line is to clear the upstream `ExecStart` field.
|
||||
"${cfg.package}/libexec/nm-dispatcher --persist" # --persist is needed for it to actually run as a daemon
|
||||
];
|
||||
serviceConfig.Restart = "always";
|
||||
serviceConfig.RestartSec = "1s";
|
||||
};
|
||||
sandbox.whitelistDbus = [ "system" ];
|
||||
};
|
||||
}
|
||||
|
||||
environment.etc = lib.mkIf cfg.enabled {
|
||||
"NetworkManager/system-connections".source = "/var/lib/NetworkManager/system-connections";
|
||||
"NetworkManager/NetworkManager.conf".text = ''
|
||||
[device]
|
||||
# wifi.backend: wpa_supplicant or iwd
|
||||
wifi.backend=wpa_supplicant
|
||||
wifi.scan-rand-mac-address=true
|
||||
(lib.mkIf cfg.enabled {
|
||||
# add to systemd.packages so we get the service file it ships, then override what we need to customize (taken from nixpkgs)
|
||||
# systemd.packages = [ cfg.package ];
|
||||
networking.networkmanager.enable = true;
|
||||
networking.networkmanager.enableDefaultPlugins = false;
|
||||
networking.networkmanager.package = cfg.package;
|
||||
systemd.services.NetworkManager = {
|
||||
# wantedBy = [ "network.target" ];
|
||||
aliases = [ "dbus-org.freedesktop.NetworkManager.service" ];
|
||||
|
||||
[logging]
|
||||
audit=false
|
||||
# level: TRACE, DEBUG, INFO, WARN, ERR, OFF
|
||||
level=INFO
|
||||
# domain=...
|
||||
path = [ "/run/current-system/sw" ]; #< so it can find `sanebox`
|
||||
serviceConfig.RuntimeDirectory = "NetworkManager"; #< tells systemd to create /run/NetworkManager
|
||||
# serviceConfig.StateDirectory = "NetworkManager"; #< tells systemd to create /var/lib/NetworkManager
|
||||
serviceConfig.User = "networkmanager";
|
||||
serviceConfig.Group = "networkmanager";
|
||||
serviceConfig.AmbientCapabilities = [
|
||||
# "CAP_DAC_OVERRIDE"
|
||||
"CAP_NET_ADMIN"
|
||||
"CAP_NET_RAW"
|
||||
"CAP_NET_BIND_SERVICE" #< this *does* seem to be necessary, though i don't understand why. DHCP?
|
||||
# "CAP_SYS_MODULE"
|
||||
"CAP_AUDIT_WRITE" #< allow writing to the audit log
|
||||
# "CAP_KILL"
|
||||
];
|
||||
};
|
||||
|
||||
[main]
|
||||
# dhcp:
|
||||
# - `internal` (default)
|
||||
# - `dhclient` (requires dhclient to be installed)
|
||||
# - `dhcpcd` (requires dhcpcd to be installed)
|
||||
dhcp=internal
|
||||
# dns:
|
||||
# - `default`: update /etc/resolv.conf with nameservers provided by the active connection
|
||||
# - `none`: NM won't update /etc/resolv.conf
|
||||
# - `systemd-resolved`: push DNS config to systemd-resolved
|
||||
# - `dnsmasq`: run a local caching nameserver
|
||||
dns=${if config.services.resolved.enable then
|
||||
"systemd-resolved"
|
||||
else if config.sane.services.trust-dns.enable && config.sane.services.trust-dns.asSystemResolver then
|
||||
"none"
|
||||
else
|
||||
"internal"
|
||||
}
|
||||
plugins=keyfile
|
||||
# rc-manager: how NM should write to /etc/resolv.conf
|
||||
# - regardless of this setting, NM will write /var/lib/NetworkManager/resolv.conf
|
||||
rc-manager=unmanaged
|
||||
# systemd-resolved: send DNS config to systemd-resolved?
|
||||
# this setting has no effect if dns="systemd-resolved"; it's supplementary, not absolute.
|
||||
systemd-resolved=false
|
||||
# debug=... (see also: NM_DEBUG env var)
|
||||
'';
|
||||
};
|
||||
hardware.wirelessRegulatoryDatabase = lib.mkIf cfg.enabled true;
|
||||
networking.useDHCP = lib.mkIf cfg.enabled false;
|
||||
users.groups = lib.mkIf cfg.enabled {
|
||||
networkmanager.gid = config.ids.gids.networkmanager;
|
||||
};
|
||||
services.udev.packages = lib.mkIf cfg.enabled [ cfg.package ];
|
||||
security.polkit.enable = lib.mkIf cfg.enabled true;
|
||||
security.polkit.extraConfig = ''
|
||||
polkit.addRule(function(action, subject) {
|
||||
if (
|
||||
subject.isInGroup("networkmanager")
|
||||
&& (action.id.indexOf("org.freedesktop.NetworkManager.") == 0
|
||||
|| action.id.indexOf("org.freedesktop.ModemManager") == 0
|
||||
))
|
||||
{ return polkit.Result.YES; }
|
||||
});
|
||||
'';
|
||||
systemd.services.NetworkManager-wait-online = {
|
||||
path = [ "/run/current-system/sw" ]; #< so `nm-online` can find `sanebox`
|
||||
# wantedBy = [ "network-online.target" ];
|
||||
serviceConfig.User = "networkmanager";
|
||||
serviceConfig.Group = "networkmanager";
|
||||
};
|
||||
|
||||
boot.kernelModules = [ "ctr" ]; #< TODO: needed (what even is this)?
|
||||
# TODO: polkit?
|
||||
# TODO: NetworkManager-ensure-profiles?
|
||||
systemd.services.NetworkManager-dispatcher = {
|
||||
# wantedBy = [ "NetworkManager.service" ];
|
||||
after = [ "trust-dns-localhost.service" ]; #< so that /var/lib/trust-dns will exist
|
||||
path = [ "/run/current-system/sw" ]; #< so it can find `sanebox`
|
||||
# to debug, add NM_DISPATCHER_DEBUG_LOG=1
|
||||
serviceConfig.ExecStart = [
|
||||
"" # first blank line is to clear the upstream `ExecStart` field.
|
||||
"${cfg.package}/libexec/nm-dispatcher --persist" # --persist is needed for it to actually run as a daemon
|
||||
];
|
||||
serviceConfig.Restart = "always";
|
||||
serviceConfig.RestartSec = "1s";
|
||||
serviceConfig.User = "networkmanager";
|
||||
serviceConfig.Group = "networkmanager";
|
||||
};
|
||||
|
||||
networking.networkmanager.settings = {
|
||||
# wifi.backend = "wpa_supplicant";
|
||||
# wifi.scan-rand-mac-address = true;
|
||||
|
||||
# logging.audit = false;
|
||||
logging.level = "INFO";
|
||||
|
||||
# main.dhcp = "internal";
|
||||
main.dns = if config.services.resolved.enable then
|
||||
"systemd-resolved"
|
||||
else if config.sane.services.trust-dns.enable && config.sane.services.trust-dns.asSystemResolver then
|
||||
"none"
|
||||
else
|
||||
"internal"
|
||||
;
|
||||
main.systemd-resolved = false;
|
||||
};
|
||||
|
||||
environment.etc = {
|
||||
"NetworkManager/system-connections".source = "/var/lib/NetworkManager/system-connections";
|
||||
# "NetworkManager/NetworkManager.conf".text = ''
|
||||
# [device]
|
||||
# # wifi.backend: wpa_supplicant or iwd
|
||||
# wifi.backend=wpa_supplicant
|
||||
# wifi.scan-rand-mac-address=true
|
||||
|
||||
# [logging]
|
||||
# audit=false
|
||||
# # level: TRACE, DEBUG, INFO, WARN, ERR, OFF
|
||||
# level=INFO
|
||||
# # domain=...
|
||||
|
||||
# [main]
|
||||
# # dhcp:
|
||||
# # - `internal` (default)
|
||||
# # - `dhclient` (requires dhclient to be installed)
|
||||
# # - `dhcpcd` (requires dhcpcd to be installed)
|
||||
# dhcp=internal
|
||||
# # dns:
|
||||
# # - `default`: update /etc/resolv.conf with nameservers provided by the active connection
|
||||
# # - `none`: NM won't update /etc/resolv.conf
|
||||
# # - `systemd-resolved`: push DNS config to systemd-resolved
|
||||
# # - `dnsmasq`: run a local caching nameserver
|
||||
# dns=${if config.services.resolved.enable then
|
||||
# "systemd-resolved"
|
||||
# else if config.sane.services.trust-dns.enable && config.sane.services.trust-dns.asSystemResolver then
|
||||
# "none"
|
||||
# else
|
||||
# "internal"
|
||||
# }
|
||||
# plugins=keyfile
|
||||
# # rc-manager: how NM should write to /etc/resolv.conf
|
||||
# # - regardless of this setting, NM will write /var/lib/NetworkManager/resolv.conf
|
||||
# rc-manager=unmanaged
|
||||
# # systemd-resolved: send DNS config to systemd-resolved?
|
||||
# # this setting has no effect if dns="systemd-resolved"; it's supplementary, not absolute.
|
||||
# systemd-resolved=false
|
||||
# # debug=... (see also: NM_DEBUG env var)
|
||||
# '';
|
||||
};
|
||||
|
||||
# hardware.wirelessRegulatoryDatabase = true;
|
||||
# networking.useDHCP = false;
|
||||
# services.udev.packages = [ cfg.package ];
|
||||
# security.polkit.enable = lib.mkDefault true;
|
||||
|
||||
# security.polkit.extraConfig = lib.concatStringsSep "\n" [
|
||||
# # allow networkmanager unbounded control over modemmanager.
|
||||
# # i believe this was sourced from the default nixpkgs config.
|
||||
# ''
|
||||
# polkit.addRule(function(action, subject) {
|
||||
# if (subject.isInGroup("networkmanager")
|
||||
# && (
|
||||
# action.id.indexOf("org.freedesktop.NetworkManager.") == 0
|
||||
# || action.id.indexOf("org.freedesktop.ModemManager") == 0
|
||||
# )
|
||||
# ) {
|
||||
# return polkit.Result.YES;
|
||||
# }
|
||||
# });
|
||||
# ''
|
||||
|
||||
# allow networkmanager to control systemd-resolved,
|
||||
# which it needs to do to apply new DNS settings when using systemd-resolved.
|
||||
security.polkit.extraConfig = ''
|
||||
polkit.addRule(function(action, subject) {
|
||||
if (subject.isInGroup("networkmanager") && action.id.indexOf("org.freedesktop.resolve1.") == 0) {
|
||||
return polkit.Result.YES;
|
||||
}
|
||||
});
|
||||
'';
|
||||
|
||||
# users.groups.networkmanager.gid = config.ids.gids.networkmanager;
|
||||
users.users.networkmanager = {
|
||||
isSystemUser = true;
|
||||
group = "networkmanager";
|
||||
extraGroups = [ "trust-dns" ];
|
||||
};
|
||||
|
||||
# boot.kernelModules = [ "ctr" ]; #< TODO: needed (what even is this)?
|
||||
# TODO: NetworkManager-ensure-profiles?
|
||||
})
|
||||
];
|
||||
}
|
||||
|
7
hosts/common/programs/nmcli.nix
Normal file
7
hosts/common/programs/nmcli.nix
Normal file
@@ -0,0 +1,7 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
sane.programs.nmcli = {
|
||||
packageUnwrapped = pkgs.networkmanager-split.nmcli;
|
||||
# TODO: sandbox
|
||||
};
|
||||
}
|
@@ -3,7 +3,8 @@
|
||||
sane.programs.notejot = {
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.extraPaths = [ ".config/dconf" ]; #< for legacy notes (moby), loaded via dconf
|
||||
sandbox.whitelistDri = true; #< otherwise intolerably slow on moby
|
||||
sandbox.extraHomePaths = [ ".config/dconf" ]; #< for legacy notes (moby), loaded via dconf
|
||||
suggestedPrograms = [ "dconf" ]; #< else it can't persist notes
|
||||
|
||||
persist.byStore.private = [
|
||||
|
@@ -41,6 +41,9 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
# disabling systemd causes pipewire to be built with direct udev support instead
|
||||
packageUnwrapped = pkgs.pipewire.override { enableSystemd = false; };
|
||||
|
||||
suggestedPrograms = [
|
||||
# "rtkit"
|
||||
"wireplumber"
|
||||
@@ -60,9 +63,7 @@ in
|
||||
# "system"
|
||||
# ];
|
||||
sandbox.wrapperType = "inplace"; #< its config files refer to its binaries by full path
|
||||
sandbox.extraConfig = [
|
||||
"--sanebox-keep-namespace" "pid"
|
||||
];
|
||||
sandbox.isolatePids = false; #< TODO: why?
|
||||
sandbox.capabilities = [
|
||||
# if rtkit isn't present, and sandboxing is via landlock, these capabilities allow pipewire to claim higher scheduling priority
|
||||
"ipc_lock"
|
||||
@@ -143,7 +144,7 @@ in
|
||||
# '';
|
||||
|
||||
# see: <https://docs.pipewire.org/page_module_protocol_native.html>
|
||||
# defaults to placing the socket in /run/user/$id/{pipewire-0,pipewire-0-manager,...}
|
||||
# defaults to placing the socket in $XDG_RUNTIME_DIR/{pipewire-0,pipewire-0-manager,...}
|
||||
# but that's trickier to sandbox
|
||||
env.PIPEWIRE_RUNTIME_DIR = "$XDG_RUNTIME_DIR/pipewire";
|
||||
|
||||
@@ -179,6 +180,9 @@ in
|
||||
];
|
||||
cleanupCommand = ''rm -f "$XDG_RUNTIME_DIR/pulse/{native,pid}"'';
|
||||
};
|
||||
|
||||
# bring up sound by default
|
||||
services."sound".partOf = [ "default" ];
|
||||
};
|
||||
|
||||
# taken from nixos/modules/services/desktops/pipewire/pipewire.nix
|
||||
|
@@ -24,11 +24,13 @@
|
||||
"/tmp"
|
||||
"/var"
|
||||
];
|
||||
sandbox.extraRuntimePaths = [
|
||||
# not sure if these are actually necessary
|
||||
"gvfs"
|
||||
"gvfsd"
|
||||
];
|
||||
# sandbox.extraRuntimePaths = [
|
||||
# # not sure if these are actually necessary
|
||||
# "gvfs"
|
||||
# "gvfsd"
|
||||
# ];
|
||||
|
||||
# suggestedPrograms = [ "gvfs" ]; #< TODO: fix (ftp:// share, USB drive browsing)
|
||||
|
||||
mime.priority = 160; #< default is 100, so higher means we fall-back to other apps that might be more specialized
|
||||
mime.associations = {
|
||||
|
@@ -2,7 +2,7 @@
|
||||
{
|
||||
sane.programs.ripgrep = {
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.autodetectCliPaths = true;
|
||||
sandbox.autodetectCliPaths = "existing";
|
||||
sandbox.whitelistPwd = true;
|
||||
sandbox.extraHomePaths = [
|
||||
# let it follow symlinks to non-sensitive data
|
||||
|
@@ -5,7 +5,7 @@
|
||||
# - use as a launcher/file browser
|
||||
# - `rofi -sidebar-mode`
|
||||
# - separate tabs for filebrowser, drun, etc.
|
||||
# - `rofi -pid /run/user/$UID/rofi.pid -replace`
|
||||
# - `rofi -pid $XDG_RUNTIME_DIR/rofi.pid -replace`
|
||||
# - single-instance mode
|
||||
# - pid is probably optional, just need `-replace`.
|
||||
#
|
||||
@@ -112,9 +112,7 @@ in
|
||||
"/mnt/servo/media"
|
||||
"/mnt/servo/playground"
|
||||
];
|
||||
sandbox.extraConfig = [
|
||||
"--sanebox-keep-namespace" "pid" # for sane-open to toggle keyboard
|
||||
];
|
||||
sandbox.isolatePids = false; # for sane-open to toggle keyboard
|
||||
|
||||
fs.".config/rofi/config.rasi".symlink.target = ./config.rasi;
|
||||
fs."Apps".symlink.target = ".local/share/applications/rofi-applications.desktop";
|
||||
@@ -160,15 +158,15 @@ in
|
||||
})
|
||||
];
|
||||
};
|
||||
# if i could remove the sed, then maybe possible to not sandbox.
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.extraHomePaths = [
|
||||
".cache/rofi"
|
||||
".config/rofi/config.rasi"
|
||||
];
|
||||
sandbox.enable = false; # all dependencies are sandboxed
|
||||
# sandbox.method = "bwrap";
|
||||
# sandbox.whitelistWayland = true;
|
||||
# sandbox.extraHomePaths = [
|
||||
# ".cache/rofi"
|
||||
# ".config/rofi/config.rasi"
|
||||
# ];
|
||||
|
||||
suggestedPrograms = [ "rofi" ];
|
||||
suggestedPrograms = [ "gnused" "rofi" "wtype" ];
|
||||
|
||||
fs.".config/rofi-snippets/public.txt".symlink.target = ./snippets.txt;
|
||||
secrets.".config/rofi-snippets/private.txt" = ../../../../secrets/common/snippets.txt.bin;
|
||||
|
@@ -4,7 +4,11 @@
|
||||
# "bookmarking"/snippets inspired by Luke Smith:
|
||||
# - <https://www.youtube.com/watch?v=d_11QaTlf1I>
|
||||
|
||||
snippet=$(cat ~/.config/rofi-snippets/public.txt ~/.config/rofi-snippets/private.txt | \
|
||||
rofi -dmenu | \
|
||||
sed 's/ #.*$//')
|
||||
wtype "$snippet"
|
||||
# rofi flags (see: `man rofi-dmenu`):
|
||||
# `-i`: case insensitive filtering
|
||||
# `-sync -ellipsize-mode middle`: for lengthy entries, replace the *middle* with an ellipsis instead of the end
|
||||
# requires rofi 1.7.6, and `-sync`, wich must come *before* the `-dmenu` flag
|
||||
cat ~/.config/rofi-snippets/public.txt ~/.config/rofi-snippets/private.txt | \
|
||||
rofi -sync -ellipsize-mode middle -dmenu -i | \
|
||||
sed -z -e 's/ *#.*$//' -e 's/\n$//' | \
|
||||
wtype -
|
||||
|
@@ -5,7 +5,6 @@ https://nixos.org/manual/nix/stable/language/builtins.html
|
||||
https://github.com/nixos/nixpkgs/pulls?q=
|
||||
https://nur.nix-community.org/
|
||||
https://repology.org/projects/?maintainer=colin@uninsane.org&inrepo=nix_unstable&outdated=1
|
||||
https://lists.sr.ht/~mil/sxmo-devel
|
||||
https://w.uninsane.org/viewer#search?books.name=wikipedia_en_all_maxi_2022-05&pattern=
|
||||
https://jackett.uninsane.org/UI/Dashboard#search=
|
||||
https://lemmy.uninsane.org
|
||||
|
@@ -97,9 +97,7 @@ in
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.whitelistDbus = [ "user" ]; #< to launch applications
|
||||
sandbox.extraRuntimePaths = [ "sway" ];
|
||||
sandbox.extraConfig = [
|
||||
"--sanebox-keep-namespace" "pid"
|
||||
];
|
||||
sandbox.isolatePids = false; #< for toggling the keyboard
|
||||
};
|
||||
|
||||
# sane.programs.actkbd = {
|
||||
@@ -157,6 +155,7 @@ in
|
||||
voldown_pressed.timeout = recurseHold "voldown" {};
|
||||
});
|
||||
|
||||
sane.programs.sway.sandbox.extraRuntimePaths = lib.mkIf cfg.enabled [ "bonsai" ];
|
||||
sane.programs.sway.config.extra_lines = lib.mkIf cfg.enabled (
|
||||
''
|
||||
# bindsym --input-device=... :
|
||||
|
@@ -61,6 +61,24 @@ KEYBOARD="${KEYBOARD:-wvkbd-mobintl}"
|
||||
|
||||
action="$1"
|
||||
|
||||
showHelp() {
|
||||
echo "usage: sane-input-handler <action>"
|
||||
echo ""
|
||||
echo "where action is one of:"
|
||||
echo "- power_tap_{1,2}"
|
||||
echo "- power_hold"
|
||||
echo "- power_tap_1_hold"
|
||||
echo "- power_and_volup"
|
||||
echo "- power_and_voldown"
|
||||
echo "- power_then_volup"
|
||||
echo "- power_then_voldown"
|
||||
echo "- volup_tap_{1,2,3}"
|
||||
echo "- volup_hold_{1,2,3}"
|
||||
echo "- voldown_tap_{1,2,3}"
|
||||
echo "- voldown_hold_{1,2,3}"
|
||||
echo "- voldown_start"
|
||||
}
|
||||
|
||||
log() {
|
||||
printf "sane-input-handler: %s\n" "$1"
|
||||
}
|
||||
@@ -242,19 +260,31 @@ dispatchInhibited() {
|
||||
esac
|
||||
}
|
||||
|
||||
_isAllOn="$(isAllOn && echo 1 || true)"
|
||||
dispatchToplevel() {
|
||||
_isAllOn="$(isAllOn && echo 1 || true)"
|
||||
|
||||
if [ -z "$_isAllOn" ]; then
|
||||
dispatchOff
|
||||
else
|
||||
_isInhibited="$(isInhibited && echo 1 || true)"
|
||||
if [ -n "$_isInhibited" ]; then
|
||||
dispatchInhibited
|
||||
if [ -z "$_isAllOn" ]; then
|
||||
dispatchOff
|
||||
else
|
||||
dispatchOn
|
||||
_isInhibited="$(isInhibited && echo 1 || true)"
|
||||
if [ -n "$_isInhibited" ]; then
|
||||
dispatchInhibited
|
||||
else
|
||||
dispatchOn
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
dispatchDefault
|
||||
dispatchDefault
|
||||
}
|
||||
|
||||
case "$action" in
|
||||
(--help)
|
||||
showHelp
|
||||
exit 0
|
||||
;;
|
||||
(*)
|
||||
dispatchToplevel
|
||||
handleWith unmapped
|
||||
;;
|
||||
esac
|
||||
|
||||
handleWith unmapped
|
||||
|
@@ -4,13 +4,11 @@
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.autodetectCliPaths = "existing"; # for when opening a file
|
||||
sandbox.whitelistDbus = [ "user" ];
|
||||
sandbox.extraConfig = [
|
||||
"--sanebox-keep-namespace" "pid" # to toggle keyboard
|
||||
];
|
||||
sandbox.isolatePids = false; #< to toggle keyboard
|
||||
sandbox.extraHomePaths = [
|
||||
".local/share/applications"
|
||||
];
|
||||
sandbox.extraRuntimePaths = [ "sway" ];
|
||||
sandbox.extraRuntimePaths = [ "sway" ]; #< calls `swaymsg` to query rotation and see if there's room for a keyboard
|
||||
suggestedPrograms = [
|
||||
"gdbus"
|
||||
"xdg-utils"
|
||||
|
@@ -229,7 +229,6 @@ in
|
||||
fwmark=${builtins.toString vpnCfg.fwmark}
|
||||
priorityMain=${builtins.toString vpnCfg.priorityMain}
|
||||
priorityFwMark=${builtins.toString vpnCfg.priorityFwMark}
|
||||
bridgeDevice=${vpnCfg.bridgeDevice}
|
||||
addrV4=${vpnCfg.addrV4}
|
||||
name=${vpnCfg.name}
|
||||
dns=(${lib.concatStringsSep " " vpnCfg.dns})
|
||||
@@ -248,13 +247,7 @@ in
|
||||
# extraHomePaths = [ ".config/sane-vpn" ];
|
||||
};
|
||||
|
||||
"sane-scripts.which".sandbox = {
|
||||
method = "bwrap";
|
||||
extraHomePaths = [
|
||||
# for SXMO
|
||||
".config/sxmo/hooks"
|
||||
];
|
||||
};
|
||||
"sane-scripts.which".sandbox.method = "bwrap";
|
||||
|
||||
"sane-scripts.wipe".sandbox = {
|
||||
method = "bwrap";
|
||||
|
@@ -1,15 +1,6 @@
|
||||
# gtk apps search XDG_ICON_DIRS for icons (nixos specific)
|
||||
# nixos ships the hi-color icon theme by default, which has *some* icons,
|
||||
# but leaves a lot of standard ones unavailable.
|
||||
#
|
||||
# system-wide theme components live in:
|
||||
# - /run/current-system/sw/share/color-schemes/${theme}
|
||||
# - /run/current-system/sw/share/icons/${theme}
|
||||
# - /run/current-system/sw/share/icons/${theme}/cursors (cursor-theme)
|
||||
# - /run/current-system/sw/share/themes/${theme}/gtk-4.0
|
||||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
cfg = config.sane.gui.gtk;
|
||||
cfg = config.sane.programs.sane-theme.config;
|
||||
unsortedThemes = {
|
||||
# crude assortment of themes in nixpkgs; some might not be gtk themes, some gtk themes might not be in this list
|
||||
inherit (pkgs)
|
||||
@@ -278,38 +269,62 @@ let
|
||||
};
|
||||
in
|
||||
{
|
||||
options = with lib; {
|
||||
sane.gui.gtk.enable = mkOption {
|
||||
default = false;
|
||||
type = types.bool;
|
||||
description = "apply theme to gtk4 apps";
|
||||
sane.programs.sane-theme = {
|
||||
configOption = with lib; mkOption {
|
||||
default = {};
|
||||
type = types.submodule {
|
||||
options = {
|
||||
all = mkOption {
|
||||
default = false;
|
||||
type = types.bool;
|
||||
description = "install all known gtk themes (for testing)";
|
||||
};
|
||||
color-scheme = mkOption {
|
||||
default = "default";
|
||||
type = types.str;
|
||||
};
|
||||
cursor-theme = mkOption {
|
||||
default = "Adwaita";
|
||||
type = types.str;
|
||||
};
|
||||
gtk-theme = mkOption {
|
||||
default = "Adwaita";
|
||||
type = types.str;
|
||||
};
|
||||
icon-theme = mkOption {
|
||||
default = "Adwaita";
|
||||
type = types.str;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
sane.gui.gtk.all = mkOption {
|
||||
default = false;
|
||||
type = types.bool;
|
||||
description = "install all known gtk themes (for testing)";
|
||||
};
|
||||
sane.gui.gtk.color-scheme = mkOption {
|
||||
default = "default";
|
||||
type = types.str;
|
||||
};
|
||||
sane.gui.gtk.cursor-theme = mkOption {
|
||||
default = "Adwaita";
|
||||
type = types.str;
|
||||
};
|
||||
sane.gui.gtk.gtk-theme = mkOption {
|
||||
default = "Adwaita";
|
||||
type = types.str;
|
||||
};
|
||||
sane.gui.gtk.icon-theme = mkOption {
|
||||
default = "Adwaita";
|
||||
type = types.str;
|
||||
packageUnwrapped = pkgs.symlinkJoin {
|
||||
name = "sane-theme";
|
||||
paths = [
|
||||
themes.color-scheme."${cfg.color-scheme}"
|
||||
themes.cursor-theme."${cfg.cursor-theme}"
|
||||
themes.gtk-theme."${cfg.gtk-theme}"
|
||||
themes.icon-theme."${cfg.icon-theme}"
|
||||
] ++ lib.optionals cfg.all (lib.attrValues unsortedThemes);
|
||||
};
|
||||
sandbox.enable = false; #< no binaries
|
||||
|
||||
suggestedPrograms = [
|
||||
"sane-backgrounds"
|
||||
];
|
||||
};
|
||||
|
||||
config.sane.programs.dconf.config.site = lib.mkIf cfg.enable [
|
||||
sane.programs.sane-backgrounds = {
|
||||
sandbox.enable = false; #< no binaries
|
||||
};
|
||||
|
||||
|
||||
environment.pathsToLink = lib.mkIf config.sane.programs.sane-backgrounds.enabled [
|
||||
"/share/backgrounds"
|
||||
];
|
||||
sane.programs.dconf.config.site = lib.mkIf config.sane.programs.sane-theme.enabled [
|
||||
(pkgs.writeTextFile {
|
||||
name = "dconf-sway-settings";
|
||||
name = "sane-theme";
|
||||
destination = "/etc/dconf/db/site.d/10_gtk_settings";
|
||||
text = ''
|
||||
[org/gnome/desktop/interface]
|
||||
@@ -320,13 +335,6 @@ in
|
||||
'';
|
||||
})
|
||||
];
|
||||
# environment.systemPackages = lib.attrValues themes;
|
||||
config.environment.systemPackages = lib.mkIf cfg.enable ([
|
||||
themes.color-scheme."${cfg.color-scheme}"
|
||||
themes.cursor-theme."${cfg.cursor-theme}"
|
||||
themes.gtk-theme."${cfg.gtk-theme}"
|
||||
themes.icon-theme."${cfg.icon-theme}"
|
||||
] ++ lib.optionals cfg.all (lib.attrValues unsortedThemes));
|
||||
|
||||
# XXX(2024/02/05): set GSK_RENDERER=cairo to solve graphical edge-case on moby where some JPEGs would render as black!
|
||||
# - repro by loading komikku and viewing images. some fail (particularly mangadex onimai), some work.
|
||||
@@ -338,4 +346,5 @@ in
|
||||
# - upstream gtk recommends using mesa 24.0 (latest) specifically in response to the GSK renderers triggering new driver bugs,
|
||||
# so maybe i can update that before re-enabling GSK_RENDERER anywhere else.
|
||||
# environment.variables.GSK_RENDERER = "cairo";
|
||||
|
||||
}
|
52
hosts/common/programs/seatd.nix
Normal file
52
hosts/common/programs/seatd.nix
Normal file
@@ -0,0 +1,52 @@
|
||||
{ config, lib, ... }:
|
||||
let
|
||||
cfg = config.sane.programs.seatd;
|
||||
in
|
||||
lib.mkMerge [
|
||||
{
|
||||
sane.programs.seatd = {
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.capabilities = [
|
||||
"sys_tty_config" "sys_admin"
|
||||
"chown"
|
||||
"dac_override" #< TODO: is there no way to get rid of this?
|
||||
];
|
||||
sandbox.extraPaths = [
|
||||
"/dev" #< TODO: this can be removed if i have seatd restart on client error such that seatd can discover devices as they appear
|
||||
# "/dev/dri"
|
||||
# # "/dev/drm_dp_aux0"
|
||||
# # "/dev/drm_dp_aux1"
|
||||
# # "/dev/drm_dp_aux2"
|
||||
# # "/dev/fb0"
|
||||
# "/dev/input"
|
||||
# # "/dev/uinput"
|
||||
# "/dev/tty0"
|
||||
# "/dev/tty1"
|
||||
# "/proc"
|
||||
"/run" #< TODO: confine this to some subdirectory
|
||||
# "/sys"
|
||||
];
|
||||
};
|
||||
}
|
||||
(lib.mkIf cfg.enabled {
|
||||
users.groups.seat = {};
|
||||
|
||||
# TODO: /run/seatd.sock location can be configured, but only via compile-time flag
|
||||
systemd.services.seatd = {
|
||||
description = "Seat management daemon";
|
||||
documentation = [ "man:seatd(1)" ];
|
||||
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
restartIfChanged = false;
|
||||
|
||||
path = [ "/run/current-system/sw" ]; #< so `sanebox` works
|
||||
|
||||
serviceConfig = {
|
||||
Type = "simple";
|
||||
ExecStart = "${cfg.package}/bin/seatd -g seat";
|
||||
Group = "seat";
|
||||
# AmbientCapabilities = [ "CAP_SYS_TTY_CONFIG" "CAP_SYS_ADMIN" ];
|
||||
};
|
||||
};
|
||||
})
|
||||
]
|
@@ -1,6 +1,5 @@
|
||||
# simple RSS and Atom parser
|
||||
# - <https://codemadness.org/sfeed-simple-feed-parser.html>
|
||||
# - used by sxmo
|
||||
# - man 5 sfeedrc
|
||||
#
|
||||
# call `sfeed_update` to query each feed and populate entries in ~/.sfeed/feeds
|
||||
|
17
hosts/common/programs/shadow.nix
Normal file
17
hosts/common/programs/shadow.nix
Normal file
@@ -0,0 +1,17 @@
|
||||
{ config, lib, ... }:
|
||||
let
|
||||
cfg = config.sane.programs.shadow;
|
||||
in
|
||||
{
|
||||
config = lib.mkMerge [
|
||||
{
|
||||
sane.programs.shadow = {
|
||||
sandbox.enable = false; #< `login` can't be sandboxed because it launches a user shell
|
||||
};
|
||||
}
|
||||
(lib.mkIf cfg.enabled {
|
||||
services.getty.loginProgram = "${cfg.package}/bin/login";
|
||||
security.pam.services.login.startSession = lib.mkForce false; #< disable systemd integration
|
||||
})
|
||||
];
|
||||
}
|
@@ -4,6 +4,7 @@
|
||||
# sway-config docs: `man 5 sway`
|
||||
let
|
||||
cfg = config.sane.programs.sway;
|
||||
enableXWayland = config.sane.programs.xwayland.enabled;
|
||||
wrapSway = configuredSway: let
|
||||
swayLauncher = pkgs.writeShellScriptBin "sway" ''
|
||||
test -e "$(dirname "$SWAYSOCK")" || \
|
||||
@@ -26,47 +27,59 @@ let
|
||||
];
|
||||
passthru.sway-unwrapped = configuredSway;
|
||||
};
|
||||
swayPackage = wrapSway (
|
||||
pkgs.waylandPkgs.sway-unwrapped.override {
|
||||
wlroots = (pkgs.waylandPkgs.wlroots.override {
|
||||
# wlroots seems to launch Xwayland itself, and i can't easily just do that myself externally.
|
||||
# so in order for the Xwayland it launches to be sandboxed, i need to patch the sandboxed version in here.
|
||||
xwayland = config.sane.programs.xwayland.package;
|
||||
}).overrideAttrs (upstream: {
|
||||
# 2023/09/08: fix so clicking a notification can activate the corresponding window.
|
||||
# - test: run dino, receive a message while tabbed away, click the desktop notification.
|
||||
# - if sway activates the dino window (i.e. colors the workspace and tab), then all good
|
||||
# - do all of this with only a touchscreen (e.g. on mobile phone) -- NOT a mouse/pointer
|
||||
# 2023/12/17: this patch is still necessary
|
||||
## what this patch does:
|
||||
# - allows any wayland window to request activation, at any time.
|
||||
# - traditionally, wayland only allows windows to request activation if
|
||||
# the client requesting to transfer control has some connection to a recent user interaction.
|
||||
# - e.g. the active window may transfer control to any window
|
||||
# - a window which was very recently active may transfer control to itself
|
||||
## alternative (longer-term) solutions:
|
||||
# - fix this class of bug in gtk:
|
||||
# - <https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/5782>
|
||||
# - N.B.: this linked PR doesn't actually fix it
|
||||
# - add xdg_activation_v1 support to SwayNC (my notification daemon):
|
||||
# - <https://github.com/ErikReider/SwayNotificationCenter/issues/71>
|
||||
# - mako notification daemon supports activation, can use as a reference
|
||||
# - all of ~30 LoC, looks straight-forward
|
||||
# - however, it's not clear that gtk4 (or dino) actually support this mode of activation.
|
||||
# - i.e. my experience with dino is the same using mako as with SwayNC
|
||||
postPatch = (upstream.postPatch or "") + ''
|
||||
substituteInPlace types/wlr_xdg_activation_v1.c \
|
||||
--replace-fail 'if (token->seat != NULL)' 'if (false && token->seat != NULL)'
|
||||
'';
|
||||
});
|
||||
|
||||
wlroots = (pkgs.waylandPkgs.wlroots.override {
|
||||
# wlroots seems to launch Xwayland itself, and i can't easily just do that myself externally.
|
||||
# so in order for the Xwayland it launches to be sandboxed, i need to patch the sandboxed version in here.
|
||||
xwayland = config.sane.programs.xwayland.package;
|
||||
}).overrideAttrs (upstream: {
|
||||
# 2023/09/08: fix so clicking a notification can activate the corresponding window.
|
||||
# - test: run dino, receive a message while tabbed away, click the desktop notification.
|
||||
# - if sway activates the dino window (i.e. colors the workspace and tab), then all good
|
||||
# - do all of this with only a touchscreen (e.g. on mobile phone) -- NOT a mouse/pointer
|
||||
# 2023/12/17: this patch is still necessary
|
||||
## what this patch does:
|
||||
# - allows any wayland window to request activation, at any time.
|
||||
# - traditionally, wayland only allows windows to request activation if
|
||||
# the client requesting to transfer control has some connection to a recent user interaction.
|
||||
# - e.g. the active window may transfer control to any window
|
||||
# - a window which was very recently active may transfer control to itself
|
||||
## alternative (longer-term) solutions:
|
||||
# - fix this class of bug in gtk:
|
||||
# - <https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/5782>
|
||||
# - N.B.: this linked PR doesn't actually fix it
|
||||
# - add xdg_activation_v1 support to SwayNC (my notification daemon):
|
||||
# - <https://github.com/ErikReider/SwayNotificationCenter/issues/71>
|
||||
# - mako notification daemon supports activation, can use as a reference
|
||||
# - all of ~30 LoC, looks straight-forward
|
||||
# - however, it's not clear that gtk4 (or dino) actually support this mode of activation.
|
||||
# - i.e. my experience with dino is the same using mako as with SwayNC
|
||||
postPatch = (upstream.postPatch or "") + ''
|
||||
substituteInPlace types/wlr_xdg_activation_v1.c \
|
||||
--replace-fail 'if (token->seat != NULL)' 'if (false && token->seat != NULL)'
|
||||
'';
|
||||
});
|
||||
swayPackage = wrapSway (
|
||||
(pkgs.waylandPkgs.sway-unwrapped.override {
|
||||
inherit wlroots;
|
||||
# about xwayland:
|
||||
# - required by many electron apps, though some electron apps support NIXOS_OZONE_WL=1 for native wayland.
|
||||
# - when xwayland is enabled, KOreader incorrectly chooses the X11 backend
|
||||
# -> slower; blurrier
|
||||
# - xwayland uses a small amount of memory (like 30MiB, IIRC?)
|
||||
enableXWayland = config.sane.programs.xwayland.enabled;
|
||||
}
|
||||
inherit enableXWayland;
|
||||
}).overrideAttrs (upstream: {
|
||||
# fix to create SWAYSOCK and WAYLAND_DISPLAY directly in a sandboxable subdirectory:
|
||||
# i can't simply move it after creation i think because that would
|
||||
# be an unsupported cross-device `mv`?
|
||||
postPatch = (upstream.postPatch or "") + ''
|
||||
substituteInPlace sway/ipc-server.c --replace-fail \
|
||||
'"%s/sway-ipc.%u.%i.sock", dir, getuid(), getpid())' \
|
||||
'"%s/sway/sway-ipc.sock", dir)'
|
||||
substituteInPlace sway/server.c --replace-fail \
|
||||
'"wayland-%u"' '"wl/wayland-%u"'
|
||||
'';
|
||||
})
|
||||
);
|
||||
in
|
||||
{
|
||||
@@ -87,9 +100,6 @@ in
|
||||
bindsym --locked XF86AudioLowerVolume exec $volume_down
|
||||
'';
|
||||
};
|
||||
background = mkOption {
|
||||
type = types.path;
|
||||
};
|
||||
font = mkOption {
|
||||
type = types.str;
|
||||
default = "pango:monospace 11";
|
||||
@@ -138,6 +148,8 @@ in
|
||||
"s6-rc" # used by sway config
|
||||
"sane-screenshot"
|
||||
"sane-open"
|
||||
"sane-theme"
|
||||
"seatd"
|
||||
# "splatmoji" # used by sway config
|
||||
"sway-contrib.grimshot" # used by sway config
|
||||
"swayidle" # enable if you need it
|
||||
@@ -171,17 +183,20 @@ in
|
||||
];
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.wrapperType = "inplace";
|
||||
sandbox.wrapperType = "inplace"; #< `sway` is a wrapper around `sway-unwrapped`, so cheap to sandbox
|
||||
sandbox.net = "all"; # TODO: shouldn't be needed! but without this, mouse/kb hotplug doesn't work.
|
||||
sandbox.whitelistAudio = true; # it runs playerctl directly
|
||||
sandbox.whitelistDbus = [ "system" "user" ]; # to e.g. launch apps
|
||||
sandbox.whitelistDri = true;
|
||||
sandbox.whitelistX = true; # sway invokes xwayland itself
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.extraRuntimePaths = [ "/" ]; # TODO: should need just "sway". but even if i sandbox EVERY entry under run individually, it fails!
|
||||
sandbox.extraRuntimePaths = [
|
||||
"sway"
|
||||
];
|
||||
sandbox.extraPaths = [
|
||||
"/dev/input"
|
||||
"/run/systemd/sessions"
|
||||
# "/dev/input"
|
||||
"/run/seatd.sock" #< required if not using `logind` systemd login manager
|
||||
# "/run/systemd/sessions"
|
||||
"/run/udev"
|
||||
"/sys/class/backlight"
|
||||
"/sys/class/drm"
|
||||
@@ -204,13 +219,12 @@ in
|
||||
fs.".config/sway/config".symlink.target = pkgs.substituteAll {
|
||||
src = ./sway-config;
|
||||
inherit (cfg.config)
|
||||
background
|
||||
extra_lines
|
||||
font
|
||||
mod
|
||||
workspace_layout
|
||||
;
|
||||
xwayland = if config.sane.programs.xwayland.enabled then "enable" else "disable";
|
||||
xwayland = if enableXWayland then "enable" else "disable";
|
||||
};
|
||||
|
||||
env.XDG_CURRENT_DESKTOP = "sway";
|
||||
@@ -223,11 +237,19 @@ in
|
||||
env.DISPLAY = ":0";
|
||||
# docs: <https://discourse.ubuntu.com/t/environment-variables-for-wayland-hackers/12750>
|
||||
# N.B.: gtk apps support absolute paths for this; webkit apps (e.g. geary) support only relative paths (relative to $XDG_RUNTIME_DIR)
|
||||
env.WAYLAND_DISPLAY = "wayland/wayland-1";
|
||||
env.WAYLAND_DISPLAY = "wl/wayland-1";
|
||||
|
||||
services.sway = {
|
||||
description = "sway: tiling wayland desktop environment";
|
||||
dependencyOf = [ "graphical-session" ];
|
||||
partOf = [
|
||||
"wayland"
|
||||
] ++ lib.optionals enableXWayland [
|
||||
"x11"
|
||||
];
|
||||
# partOf = lib.mkMerge [
|
||||
# "wayland"
|
||||
# (lib.mkIf enableXWayland "x11")
|
||||
# ];
|
||||
command = pkgs.writeShellScript "sway-start" ''
|
||||
# have to create these directories before launching sway so that they're available in the sandbox
|
||||
mkdir -p "$(dirname "$SWAYSOCK")"
|
||||
@@ -237,28 +259,10 @@ in
|
||||
'';
|
||||
readiness.waitExists = [ "$SWAYSOCK" "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY" ];
|
||||
};
|
||||
# link the graphical-session into the default target, so sway gets auto-started
|
||||
services.graphical-session.partOf = [ "default" ];
|
||||
# launch all graphical apps by default
|
||||
services."graphical-session".partOf = [ "default" ];
|
||||
};
|
||||
|
||||
|
||||
sane.gui.gtk = lib.mkIf cfg.enabled {
|
||||
enable = lib.mkDefault true;
|
||||
# gtk-theme = lib.mkDefault "Fluent-Light-compact";
|
||||
gtk-theme = lib.mkDefault "Tokyonight-Light-B";
|
||||
# icon-theme = lib.mkDefault "HighContrast"; # 4/5 coverage on moby
|
||||
# icon-theme = lib.mkDefault "WhiteSur"; # 3.5/5 coverage on moby, but it provides a bunch for Fractal/Dino
|
||||
# icon-theme = lib.mkDefault "Humanity"; # 3.5/5 coverage on moby, but it provides the bookmark icon
|
||||
# icon-theme = lib.mkDefault "Paper"; # 3.5/5 coverage on moby, but it provides the bookmark icon
|
||||
# icon-theme = lib.mkDefault "Nordzy"; # 3/5 coverage on moby
|
||||
# icon-theme = lib.mkDefault "Fluent"; # 3/5 coverage on moby
|
||||
# icon-theme = lib.mkDefault "Colloid"; # 3/5 coverage on moby
|
||||
# icon-theme = lib.mkDefault "Qogir"; # 2.5/5 coverage on moby
|
||||
# icon-theme = lib.mkDefault "rose-pine-dawn"; # 2.5/5 coverage on moby
|
||||
# icon-theme = lib.mkDefault "Flat-Remix-Grey-Light"; # requires qtbase
|
||||
};
|
||||
|
||||
|
||||
# TODO: this can go elsewhere
|
||||
hardware.bluetooth.enable = lib.mkIf cfg.enabled true;
|
||||
services.blueman.enable = lib.mkIf cfg.enabled true;
|
||||
|
@@ -38,8 +38,7 @@ client.focused_inactive #1f5e54 #5f676a #ffffff
|
||||
client.unfocused #1f5e54 #1f554c #b4b4b4
|
||||
client.urgent #ff968b #ff968b #ffffff
|
||||
|
||||
# TODO: populate background from /run/current-system/sw/etc/... instead of hard-coded nix path
|
||||
output '*' bg "@background@" fill
|
||||
output '*' bg `ls $(echo ${XDG_DATA_DIRS//:/\/backgrounds\/sane-nixos-bg.png })/backgrounds/sane-nixos-bg.png` fill
|
||||
|
||||
### pixel boundary between windows
|
||||
# hide_edge_borders --i3 means that single-window workspaces never show window bar
|
||||
|
@@ -8,11 +8,11 @@
|
||||
|
||||
{ pkgs }:
|
||||
let
|
||||
serviceButton = svcType: name: label: {
|
||||
serviceButton = name: label: {
|
||||
inherit label;
|
||||
type = "toggle";
|
||||
command = "swaync-service-dispatcher toggle ${svcType} ${name}";
|
||||
update-command = "swaync-service-dispatcher print ${svcType} ${name}";
|
||||
command = "swaync-service-dispatcher toggle ${name}";
|
||||
update-command = "swaync-service-dispatcher print ${name}";
|
||||
active = true;
|
||||
};
|
||||
in
|
||||
@@ -46,15 +46,14 @@ in
|
||||
# 🇲 𝐌 ₘ m̄ m⃞ m̋⃞ M⃞
|
||||
# - discord
|
||||
# 🎮
|
||||
gps = serviceButton "s6" "eg25-control-gps" "";
|
||||
cell-modem = serviceButton "s6" "eg25-control-powered" "";
|
||||
vpn = serviceButton "systemd" "wg-quick-vpn-servo" "vpn::hn";
|
||||
gps = serviceButton "eg25-control-gps" "";
|
||||
cell-modem = serviceButton "eg25-control-powered" "";
|
||||
|
||||
gnome-calls = serviceButton "s6" "gnome-calls" "";
|
||||
geary = serviceButton "s6" "geary" "";
|
||||
abaddon = serviceButton "s6" "abaddon" " ";
|
||||
dissent = serviceButton "s6" "dissent" " ";
|
||||
signal-desktop = serviceButton "s6" "signal-desktop" "";
|
||||
dino = serviceButton "s6" "dino" "";
|
||||
fractal = serviceButton "s6" "fractal" "[m]";
|
||||
gnome-calls = serviceButton "gnome-calls" "";
|
||||
geary = serviceButton "geary" "";
|
||||
abaddon = serviceButton "abaddon" " ";
|
||||
dissent = serviceButton "dissent" " ";
|
||||
signal-desktop = serviceButton "signal-desktop" "";
|
||||
dino = serviceButton "dino" "";
|
||||
fractal = serviceButton "fractal" "[m]";
|
||||
}
|
||||
|
@@ -10,7 +10,7 @@
|
||||
# configuration:
|
||||
# - defaults: /run/current-system/etc/profiles/per-user/colin/etc/xdg/swaync/
|
||||
# - `man 5 swaync`
|
||||
# - view document tree: `GTK_DEBUG=interactive swaync` (`systemctl stop --user swaync` first)
|
||||
# - view document tree: `GTK_DEBUG=interactive swaync` (`s6 stop swaync` first)
|
||||
# - examples:
|
||||
# - thread: <https://github.com/ErikReider/SwayNotificationCenter/discussions/183>
|
||||
# - buttons-grid and menubar: <https://gist.github.com/JannisPetschenka/fb00eec3efea9c7fff8c38a01ce5d507>
|
||||
@@ -28,9 +28,10 @@ in
|
||||
pkgs = [
|
||||
"s6"
|
||||
"s6-rc"
|
||||
"systemd"
|
||||
];
|
||||
};
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.whitelistS6 = true;
|
||||
};
|
||||
|
||||
sane.programs.swaync-fbcli = {
|
||||
@@ -44,6 +45,9 @@ in
|
||||
"util-linux"
|
||||
];
|
||||
};
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.whitelistDbus = [ "user" ];
|
||||
sandbox.isolatePids = false; # `swaync-fbcli stop` needs to be able to find the corresponding `swaync-fbcli start` process
|
||||
};
|
||||
|
||||
sane.programs.swaynotificationcenter = {
|
||||
@@ -62,7 +66,7 @@ in
|
||||
default = {};
|
||||
};
|
||||
|
||||
# prevent dbus from automatically activating swaync so i can manage it as a systemd service instead
|
||||
# prevent dbus from automatically activating swaync so i can manage it as a service instead
|
||||
packageUnwrapped = pkgs.rmDbusServices (pkgs.swaynotificationcenter.overrideAttrs (upstream: {
|
||||
version = "0.10.1-unstable-2024-04-16";
|
||||
# toggling the panel on 0.10.1 sometimes causes toggle-buttons to toggle.
|
||||
@@ -102,23 +106,6 @@ in
|
||||
"/sys/class/backlight"
|
||||
"/sys/devices"
|
||||
];
|
||||
sandbox.extraRuntimePaths = [
|
||||
# systemd/private allows one to `systemctl --user {status,start,stop,...}`
|
||||
# notably, it does *not* allow for `systemd-run` (that's dbus: org.freedesktop.systemd1.Manager.StartTransientUnit).
|
||||
# that doesn't necessarily mean this is entirely safe against privilege escalation though.
|
||||
# TODO: audit the safety of this systemd sandboxing.
|
||||
# few alternatives:
|
||||
# - superd
|
||||
# - simply `xdg-open app://dino`, etc. `pkill` to stop, `pgrep` to query.
|
||||
# - more robust: `xdg-open sane-service://start?service=dino`
|
||||
# - still need `pgrep` to query if it's running, or have the service mark a pid file
|
||||
# - dbus activation for each app
|
||||
"systemd/private"
|
||||
];
|
||||
sandbox.extraConfig = [
|
||||
# systemctl calls seem to require same pid namespace
|
||||
"--sanebox-keep-namespace" "pid"
|
||||
];
|
||||
|
||||
# glib/gio applications support many notification backends ("portal", "gtk", "freedesktop", ...).
|
||||
# swaync implements only the `org.freedesktop.Notifications` dbus interface ("freedesktop"/fdo).
|
||||
@@ -192,8 +179,6 @@ in
|
||||
lib.optionals config.sane.programs.eg25-control.enabled [
|
||||
buttons.gps
|
||||
buttons.cell-modem
|
||||
] ++ lib.optionals false [
|
||||
buttons.vpn
|
||||
] ++ lib.optionals config.sane.programs.calls.config.autostart [
|
||||
buttons.gnome-calls
|
||||
] ++ lib.optionals config.sane.programs.dino.enabled [
|
||||
|
@@ -1,13 +1,12 @@
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i bash -p s6 -p s6-rc -p systemd
|
||||
#!nix-shell -i bash -p s6 -p s6-rc
|
||||
|
||||
# for default $PATH to take precedence over nix-shell PATH if invoked interactively,
|
||||
# otherwise we invoke a s6-rc which does not know where to find files.
|
||||
export PATH="/etc/profiles/per-user/$(whoami)/bin:/run/current-system/sw/bin:$PATH"
|
||||
|
||||
action="$1"
|
||||
type="$2"
|
||||
service="$3"
|
||||
service="$2"
|
||||
|
||||
log() {
|
||||
if [ -n "$SWAYNC_DEBUG" ]; then
|
||||
@@ -16,38 +15,17 @@ log() {
|
||||
}
|
||||
|
||||
checkActive() {
|
||||
case "$type" in
|
||||
systemd)
|
||||
systemctl is-active "$service.service" > /dev/null && echo true || echo false
|
||||
;;
|
||||
s6)
|
||||
# simulate a dry-run start. if no actions would be performed, then the service is up.
|
||||
# alternative is s6-svstat, but that doesn't support oneshots
|
||||
test -z "$(s6-rc -n 0 -b start "$service")" && echo true || echo false
|
||||
;;
|
||||
esac
|
||||
# simulate a dry-run start. if no actions would be performed, then the service is up.
|
||||
# alternative is s6-svstat, but that doesn't support oneshots
|
||||
test -z "$(s6-rc -n 0 -b start "$service")" && echo true || echo false
|
||||
}
|
||||
startService() {
|
||||
log "startService: $service"
|
||||
case "$type" in
|
||||
systemd)
|
||||
/run/wrappers/bin/sudo systemctl start "$service"
|
||||
;;
|
||||
s6)
|
||||
s6-rc -b start "$service"
|
||||
;;
|
||||
esac
|
||||
s6-rc -b start "$service"
|
||||
}
|
||||
stopService() {
|
||||
log "stopService: $service"
|
||||
case "$type" in
|
||||
systemd)
|
||||
/run/wrappers/bin/sudo systemctl stop "$service"
|
||||
;;
|
||||
s6)
|
||||
s6-rc -b stop "$service"
|
||||
;;
|
||||
esac
|
||||
s6-rc -b stop "$service"
|
||||
}
|
||||
|
||||
case "$action" in
|
||||
|
@@ -9,13 +9,12 @@ let
|
||||
};
|
||||
launcher = pkgs.writeShellApplication {
|
||||
name = "unl0kr-login";
|
||||
runtimeInputs = [
|
||||
# TODO: since this invokes `login`, adding these deps to PATH is questionable
|
||||
cfg.package
|
||||
pkgs.shadow
|
||||
redirect-tty
|
||||
];
|
||||
text = ''
|
||||
extraPath=/run/current-system/sw/bin:/bin:${lib.makeBinPath [ cfg.package config.sane.programs.shadow.package redirect-tty ]}
|
||||
locate() {
|
||||
PATH=$PATH:$extraPath command -v "$1"
|
||||
}
|
||||
|
||||
# TODO: make this more robust to failure.
|
||||
# - if `unl0kr` fails, then the second `redirect-tty` sends a newline to `login`, causing it to exit and the service fails.
|
||||
# - if `redirect-tty` fails, then... the service is left hanging.
|
||||
@@ -25,8 +24,12 @@ let
|
||||
# but modified to not leak pword to CLI
|
||||
# - implement some sort of watchdog (e.g. detect spawned children?)
|
||||
# - set a timeout at the outer scope (which gets canceled upon successful login)
|
||||
bash -c 'redirect-tty "/dev/${tty}" unl0kr ; sleep 2 ; redirect-tty "/dev/${tty}" echo ""' &
|
||||
login -p ${cfg.config.user}
|
||||
PATH=$PATH:$extraPath sh -c 'redirect-tty "/dev/${tty}" unl0kr ; sleep 2 ; redirect-tty "/dev/${tty}" echo ""' &
|
||||
|
||||
# N.B.: invoke `login` by full path instead of modifying `PATH`,
|
||||
# because we don't want the user session to inherit the PATH of this script!
|
||||
_login="$(locate login)"
|
||||
"$_login" -p ${cfg.config.user}
|
||||
'';
|
||||
};
|
||||
in
|
||||
@@ -82,30 +85,22 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
fs.".profile".symlink.text = lib.mkMerge [
|
||||
(lib.mkBefore ''
|
||||
# setup primarySessionCommands here and let any other nix config populate it later
|
||||
primarySessionCommands=()
|
||||
initPrimarySession() {
|
||||
for c in "''${primarySessionCommands[@]}"; do
|
||||
eval "$c"
|
||||
done
|
||||
}
|
||||
'')
|
||||
# lib.mkAfter so that launching the DE happens *after* any other .profile setup.
|
||||
(lib.mkAfter ''
|
||||
# if already running a desktop environment, or if running from ssh, then `tty` will show /dev/pts/NN.
|
||||
if [ "$(tty)" = "/dev/${tty}" ]; then
|
||||
if (( ''${#primarySessionCommands[@]} )); then
|
||||
echo "launching primary session commands in ${builtins.toString cfg.config.delay}s: ''${primarySessionCommands[*]}"
|
||||
# if the `sleep` call here is `Ctrl+C'd`, then it'll exit false and the desktop isn't launched.
|
||||
sleep ${builtins.toString cfg.config.delay} && \
|
||||
initPrimarySession
|
||||
fi
|
||||
fi
|
||||
'')
|
||||
suggestedPrograms = [
|
||||
"shadow" #< for login
|
||||
];
|
||||
|
||||
fs.".profile".symlink.text = ''
|
||||
unl0krCheck() {
|
||||
# if already running a desktop environment, or if running from ssh, then `tty` will show /dev/pts/NN.
|
||||
# if the `sleep` call is `Ctrl+C'd`, then it'll exit false and the session commands won't be launched
|
||||
[ "$(tty)" = "/dev/${tty}" ] && (( ''${#primarySessionCommands[@]} )) \
|
||||
&& echo "launching primary session commands in ${builtins.toString cfg.config.delay}s: ''${primarySessionCommands[*]}" \
|
||||
&& sleep ${builtins.toString cfg.config.delay}
|
||||
}
|
||||
primarySessionChecks+=('unl0krCheck')
|
||||
|
||||
'';
|
||||
|
||||
# N.B.: this sandboxing applies to `unl0kr` itself -- the on-screen-keyboard;
|
||||
# NOT to the wrapper which invokes `login`.
|
||||
sandbox.method = "bwrap";
|
||||
|
@@ -16,7 +16,7 @@ in
|
||||
};
|
||||
sandbox.method = "bwrap";
|
||||
sandbox.net = "clearnet";
|
||||
sandbox.autodetectCliPaths = true;
|
||||
sandbox.autodetectCliPaths = "existing";
|
||||
sandbox.whitelistAudio = true;
|
||||
sandbox.whitelistDbus = [ "user" ]; # mpris
|
||||
sandbox.whitelistWayland = true;
|
||||
|
@@ -91,18 +91,14 @@ in
|
||||
sandbox.whitelistWayland = true;
|
||||
sandbox.extraRuntimePaths = [
|
||||
"sway"
|
||||
# "sxmo_status" #< only necessary if relying on sxmo's statusbar periodicals service
|
||||
];
|
||||
sandbox.extraPaths = [
|
||||
# for wifi status on sxmo/phone
|
||||
"/dev/rfkill"
|
||||
# for wifi status on phone
|
||||
# "/dev/rfkill"
|
||||
# for the battery indicator
|
||||
"/sys/class/power_supply"
|
||||
"/sys/devices"
|
||||
];
|
||||
sandbox.extraHomePaths = [
|
||||
".config/sxmo/hooks"
|
||||
];
|
||||
|
||||
fs.".config/waybar/config".symlink.target =
|
||||
(pkgs.formats.json {}).generate "waybar-config.json" [
|
||||
|
@@ -61,8 +61,6 @@ window#waybar {
|
||||
#cpu,
|
||||
#custom-media,
|
||||
#custom-swaync,
|
||||
#custom-sxmo,
|
||||
#custom-sxmo-sane,
|
||||
#disk,
|
||||
#idle_inhibitor,
|
||||
#memory,
|
||||
|
@@ -1,6 +1,11 @@
|
||||
{ ... }:
|
||||
{ config, pkgs, ... }:
|
||||
{
|
||||
sane.programs.wireplumber = {
|
||||
packageUnwrapped = pkgs.wireplumber.override {
|
||||
# use the same pipewire as configured to run against.
|
||||
pipewire = config.sane.programs.pipewire.packageUnwrapped;
|
||||
};
|
||||
|
||||
sandbox.method = "bwrap";
|
||||
# sandbox.whitelistDbus = [
|
||||
# "system" #< so it can request better scheduling from rtkit
|
||||
@@ -14,16 +19,13 @@
|
||||
"/dev/video0"
|
||||
"/dev/video1"
|
||||
"/dev/video2"
|
||||
"/run/systemd"
|
||||
# "/run/systemd"
|
||||
"/run/udev"
|
||||
"/sys/class/sound"
|
||||
"/sys/class/video4linux"
|
||||
"/sys/devices"
|
||||
];
|
||||
# sandbox.extraConfig = [
|
||||
# # needed if i want rtkit to grant this higher scheduling priority
|
||||
# "--sanebox-keep-namespace" "pid"
|
||||
# ];
|
||||
sandbox.isolatePids = false; #< needed if i want rtkit to grant this higher scheduling priority
|
||||
|
||||
suggestedPrograms = [ "alsa-ucm-conf" ];
|
||||
|
||||
|
@@ -1,10 +1,77 @@
|
||||
{ config, lib, ... }:
|
||||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
cfg = config.sane.programs.wpa_supplicant;
|
||||
in
|
||||
{
|
||||
sane.programs.wpa_supplicant = {};
|
||||
services.udev.packages = lib.mkIf cfg.enabled [ cfg.package ];
|
||||
# need to be on systemd.packages so we get its service file
|
||||
systemd.packages = lib.mkIf cfg.enabled [ cfg.package ];
|
||||
config = lib.mkMerge [
|
||||
{
|
||||
sane.programs.wpa_supplicant = {
|
||||
packageUnwrapped = pkgs.wpa_supplicant.overrideAttrs (upstream: {
|
||||
# postPatch = (upstream.postPatch or "") + ''
|
||||
# substituteInPlace wpa_supplicant/dbus/dbus-wpa_supplicant.conf --replace-fail \
|
||||
# 'user="root"' 'user="networkmanager"'
|
||||
# '';
|
||||
postInstall = (upstream.postInstall or "") + ''
|
||||
substitute $out/share/dbus-1/system.d/dbus-wpa_supplicant.conf \
|
||||
$out/share/dbus-1/system.d/networkmanager-wpa_supplicant.conf \
|
||||
--replace-fail 'user="root"' 'group="networkmanager"'
|
||||
'';
|
||||
|
||||
postFixup = (upstream.postFixup or "") + ''
|
||||
# nixpkgs wpa_supplicant generates a dbus file which has a path like
|
||||
# /nix/store/abc-wpa_supplicant/nix/store/abc-wpa_supplicant/sbin/...
|
||||
# upstreaming status: <https://github.com/NixOS/nixpkgs/pull/315346>
|
||||
substituteInPlace $out/share/dbus-1/system-services/* --replace-fail \
|
||||
"$out$out" "$out"
|
||||
|
||||
# remove unused services to avoid unexpected interactions
|
||||
rm $out/etc/systemd/system/{wpa_supplicant-nl80211@,wpa_supplicant-wired@,wpa_supplicant@}.service
|
||||
'';
|
||||
});
|
||||
# bwrap sandboxing works, but requires the real user to be root.
|
||||
# landlock sandboxing works, and allows the real user to be someone else (like `networkmanager`).
|
||||
# non-root is very important, because of how many things in e.g. /dev are r/w based on uid=0.
|
||||
# sandbox.method = "bwrap";
|
||||
sandbox.method = "landlock";
|
||||
sandbox.capabilities = [
|
||||
# see also: <https://github.com/NixOS/nixpkgs/pull/305722>
|
||||
"net_admin" "net_raw"
|
||||
];
|
||||
# sandbox.extraConfig = [ "--sanebox-keep-namespace" "all" ];
|
||||
sandbox.net = "all";
|
||||
sandbox.extraPaths = [
|
||||
"/dev/net"
|
||||
"/dev/rfkill"
|
||||
"/proc/sys/net"
|
||||
"/sys/class/net"
|
||||
"/sys/devices"
|
||||
];
|
||||
sandbox.whitelistDbus = [ "system" ];
|
||||
};
|
||||
}
|
||||
(lib.mkIf cfg.enabled {
|
||||
services.udev.packages = [ cfg.package ];
|
||||
systemd.packages = [ cfg.package ]; #< needs to be on systemd.packages so we get its service file
|
||||
systemd.services.wpa_supplicant = {
|
||||
path = [ "/run/current-system/sw" ]; #< so it can find `sanebox`
|
||||
serviceConfig.User = "networkmanager";
|
||||
serviceConfig.Group = "networkmanager";
|
||||
serviceConfig.AmbientCapabilities = [
|
||||
"CAP_NET_ADMIN"
|
||||
"CAP_NET_RAW"
|
||||
];
|
||||
};
|
||||
# systemd.services.wpa_supplicant = {
|
||||
# aliases = [ "dbus-fi.w1.wpa_supplicant1.service" ];
|
||||
# before = [ "network.target" ];
|
||||
# wantedBy = [ "network.target" ];
|
||||
# serviceConfig = {
|
||||
# Type = "dbus";
|
||||
# BusName = "fi.w1.wpa_supplicant1";
|
||||
# ExecStart = "${cfg.package}/bin/wpa_supplicant -u";
|
||||
# Restart = "always";
|
||||
# };
|
||||
# };
|
||||
})
|
||||
];
|
||||
}
|
||||
|
@@ -89,7 +89,7 @@ in
|
||||
};
|
||||
# also available: ${cfg.package}/libexec/xdg-document-portal
|
||||
# - <https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.Documents.html>
|
||||
# - shares files from its namespace with programs inside a namespace, via a fuse mount at /run/user/$uid/doc
|
||||
# - shares files from its namespace with programs inside a namespace, via a fuse mount at $XDG_RUNTIME_DIR/doc
|
||||
};
|
||||
|
||||
# after #603 is resolved, i can probably stop linking `{gtk,wlr}.portal` into ~
|
||||
|
@@ -25,10 +25,21 @@ in
|
||||
enable = true;
|
||||
settings.PermitRootLogin = "no";
|
||||
settings.PasswordAuthentication = false;
|
||||
settings.UsePAM = lib.mkDefault false; #< notably, disables systemd session tracking; incidentally disables pam_mount, etc.
|
||||
};
|
||||
sane.ports.ports."22" = {
|
||||
protocol = [ "tcp" ];
|
||||
visibleTo.lan = true;
|
||||
description = lib.mkDefault "colin-ssh";
|
||||
};
|
||||
|
||||
# sane.services.dropbear = {
|
||||
# enable = true;
|
||||
# port = 1022;
|
||||
# };
|
||||
# sane.ports.ports."1022" = {
|
||||
# protocol = [ "tcp" ];
|
||||
# visibleTo.lan = true;
|
||||
# description = lib.mkDefault "colin-dropbear-ssh";
|
||||
# };
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
{ pkgs, ... }:
|
||||
{ ... }:
|
||||
let
|
||||
# N.B.: systemd doesn't like to honor its timeout settings.
|
||||
# a timeout of 20s is actually closer to 70s,
|
||||
@@ -12,11 +12,6 @@ in
|
||||
DefaultTimeoutStopSec=${builtins.toString haltTimeout}
|
||||
'';
|
||||
|
||||
systemd.user.extraConfig = ''
|
||||
# DefaultTimeoutStopSec defaults to 90s, and frequently blocks overall system shutdown.
|
||||
DefaultTimeoutStopSec=${builtins.toString haltTimeout}
|
||||
'';
|
||||
|
||||
services.journald.extraConfig = ''
|
||||
# docs: `man journald.conf`
|
||||
# merged journald config is deployed to /etc/systemd/journald.conf
|
||||
@@ -25,41 +20,6 @@ in
|
||||
Compress=no
|
||||
'';
|
||||
|
||||
# decreasing the timeout for the manager itself ("Stop job is running for User Manager for UID 1000").
|
||||
# TimeoutStopSec gets stripped from .override file for `user@`, so can't do it that way:
|
||||
# systemd.services."user@".serviceConfig.TimeoutStopSec = "20s";
|
||||
# adding just TimeoutStopSec to `user@1000` causes it to lose all the other fields, including `ExecStart`:
|
||||
# systemd.services."user@1000".serviceConfig.TimeoutStopSec = "20s";
|
||||
# so, just recreate the whole damn service as it appears with `systemd cat 'user@1000'`
|
||||
# and modify the parts i care about.
|
||||
systemd.services."user@1000" = {
|
||||
description = "User Manager for UID %i";
|
||||
documentation = [ "man:user@service(5)" ];
|
||||
after = [
|
||||
"user-runtime-dir@%i.service"
|
||||
"dbus.service"
|
||||
"systemd-oomd.service"
|
||||
];
|
||||
requires = [ "user-runtime-dir@%i.service" ];
|
||||
unitConfig.ignoreOnIsolate = true;
|
||||
|
||||
serviceConfig = {
|
||||
User = "%i";
|
||||
PAMName = "systemd-user";
|
||||
Type = "notify-reload";
|
||||
ExecStart = "${pkgs.systemd}/lib/systemd/systemd --user";
|
||||
Slice = "user-%i.slice";
|
||||
KillMode = "mixed";
|
||||
Delegate = [ "pids" "memory" "cpu" ];
|
||||
DelegateSubgroup = "init.scope";
|
||||
TasksMax = "infinity";
|
||||
TimeoutStopSec = "${builtins.toString haltTimeout}s"; #< default: 120s
|
||||
KeyringMode = "inherit";
|
||||
OOMScoreAdjust = 100;
|
||||
MemoryPressureWatch = "skip";
|
||||
};
|
||||
};
|
||||
|
||||
# allow ordinary users to `reboot` or `shutdown`.
|
||||
# source: <https://nixos.wiki/wiki/Polkit>
|
||||
security.polkit.extraConfig = ''
|
||||
|
@@ -13,14 +13,16 @@
|
||||
];
|
||||
group = "users";
|
||||
extraGroups = [
|
||||
"audio" # for wireplumber, so i can access devices without logind
|
||||
"clightning" # servo, for clightning-cli
|
||||
"dialout" # required for modem access (moby)
|
||||
"export" # to read filesystem exports (servo)
|
||||
"feedbackd" # moby, so `fbcli` can control vibrator and LEDs
|
||||
"input" # for /dev/input/<xyz>: sxmo
|
||||
"input" # for /dev/input/<xyz>... TODO:is this still necessary?
|
||||
"media" # servo
|
||||
"networkmanager"
|
||||
"nixbuild"
|
||||
"seat" # for sway, if using seatd
|
||||
"systemd-journal" # allows to view other user's journals (esp system users)
|
||||
"transmission" # servo
|
||||
"video" # mobile; for LEDs & maybe for camera?
|
||||
|
@@ -51,12 +51,6 @@ in
|
||||
sane.fs."/etc/shadow".symlink.target = "/var/lib/etc_secrets/shadow";
|
||||
|
||||
# pam.d ordering (auth section only):
|
||||
# /etc/pam.d/greetd:
|
||||
# auth optional pam_unix.so likeauth nullok # unix-early (order 11600)
|
||||
# auth optional /nix/store/051v0pwqfy1z7ld6087y99fdrv12113n-pam_mount-2.20/lib/security/pam_mount.so disable_interactive # mount (order 12000)
|
||||
# auth optional /nix/store/82zqzh7i88pxybcf48zapnz4v0jf19nm-gnome-keyring-42.1/lib/security/pam_gnome_keyring.so # gnome_keyring (order 12200)
|
||||
# auth sufficient pam_unix.so likeauth nullok try_first_pass # unix (order 12800)
|
||||
# auth required pam_deny.so # deny (order 13600)
|
||||
# /etc/pam.d/login:
|
||||
# auth optional pam_unix.so likeauth nullok # unix-early (order 11600)
|
||||
# auth optional /nix/store/051v0pwqfy1z7ld6087y99fdrv12113n-pam_mount-2.20/lib/security/pam_mount.so disable_interactive # mount (order 12000)
|
||||
@@ -104,15 +98,6 @@ in
|
||||
# - pam_cap bug, and fix: <https://bugzilla.kernel.org/show_bug.cgi?id=212945#c5>
|
||||
# - may need to use keepcaps + defer: <https://bugzilla.kernel.org/show_bug.cgi?id=214377#c3>
|
||||
|
||||
# security.pam.services.greetd.rules = {
|
||||
# # 2024/01/28: greetd seems to get its caps from systemd (pid1), no matter what i do.
|
||||
# auth.pam_cap = {
|
||||
# order = 12700;
|
||||
# control = "optional";
|
||||
# modulePath = "${libcapForPam.pam}/lib/security/pam_cap.so";
|
||||
# args = [ "keepcaps" "defer" "debug" ]; #< doesn't take effect
|
||||
# };
|
||||
# };
|
||||
security.pam.services.login.rules = {
|
||||
# keepcaps + defer WORKS
|
||||
auth.pam_cap = {
|
||||
|
@@ -3,7 +3,6 @@
|
||||
{
|
||||
imports = [
|
||||
./derived-secrets
|
||||
./gui
|
||||
./hosts.nix
|
||||
./nixcache.nix
|
||||
./roles
|
||||
|
@@ -1,222 +0,0 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
declPackageSet = pkgs: {
|
||||
packageUnwrapped = null;
|
||||
suggestedPrograms = pkgs;
|
||||
};
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
./gnome.nix
|
||||
./greetd.nix
|
||||
./gtk.nix
|
||||
./sxmo
|
||||
./theme
|
||||
];
|
||||
|
||||
sane.programs.gameApps = declPackageSet [
|
||||
"animatch"
|
||||
"gnome-2048"
|
||||
"gnome.hitori" # like sudoku
|
||||
];
|
||||
sane.programs.pcGameApps = declPackageSet [
|
||||
# "andyetitmoves" # TODO: fix build!
|
||||
# "armagetronad" # tron/lightcycles; WAN and LAN multiplayer
|
||||
"celeste64"
|
||||
# "cutemaze" # meh: trivial maze game; qt6 and keyboard-only
|
||||
# "cuyo" # trivial puyo-puyo clone
|
||||
"endless-sky" # space merchantilism/exploration
|
||||
# "factorio"
|
||||
"frozen-bubble" # WAN + LAN + 1P/2P bubble bobble
|
||||
"hase" # WAN worms game
|
||||
# "hedgewars" # WAN + LAN worms game (5~10 people online at any moment; <https://hedgewars.org>)
|
||||
# "libremines" # meh: trivial minesweeper; qt6
|
||||
# "mario0" # SMB + portal
|
||||
# "mindustry"
|
||||
# "minesweep-rs" # CLI minesweeper
|
||||
# "nethack"
|
||||
# "osu-lazer"
|
||||
# "pinball" # 3d pinball; kb/mouse. old sourceforge project
|
||||
# "powermanga" # STYLISH space invaders derivative (keyboard-only)
|
||||
"shattered-pixel-dungeon" # doesn't cross compile
|
||||
"space-cadet-pinball" # LMB/RMB controls (bindable though. volume buttons?)
|
||||
"superTux" # keyboard-only controls
|
||||
"superTuxKart" # poor FPS on pinephone
|
||||
"tumiki-fighters" # keyboard-only
|
||||
"vvvvvv" # keyboard-only controls
|
||||
# "wine"
|
||||
];
|
||||
|
||||
sane.programs.guiApps = declPackageSet [
|
||||
# package sets
|
||||
"gameApps"
|
||||
"guiBaseApps"
|
||||
];
|
||||
|
||||
sane.programs.guiBaseApps = declPackageSet [
|
||||
# "abaddon" # discord client
|
||||
"alacritty" # terminal emulator
|
||||
"calls" # gnome calls (dialer/handler)
|
||||
"dconf" # required by many packages, but not well-documented :(
|
||||
# "delfin" # Jellyfin client
|
||||
"dialect" # language translation
|
||||
"dino" # XMPP client
|
||||
"dissent" # Discord client (formerly known as: gtkcord4)
|
||||
# "emote"
|
||||
# "evince" # PDF viewer
|
||||
# "flare-signal" # gtk4 signal client
|
||||
# "foliate" # e-book reader
|
||||
"fractal" # matrix client
|
||||
"g4music" # local music player
|
||||
# "gnome.cheese"
|
||||
# "gnome-feeds" # RSS reader (with claimed mobile support)
|
||||
# "gnome.file-roller"
|
||||
"gnome.geary" # adaptive e-mail client; uses webkitgtk 4.1
|
||||
"gnome.gnome-calculator"
|
||||
"gnome.gnome-calendar"
|
||||
"gnome.gnome-clocks"
|
||||
"gnome.gnome-maps"
|
||||
# "gnome-podcasts"
|
||||
# "gnome.gnome-system-monitor"
|
||||
# "gnome.gnome-terminal" # works on phosh
|
||||
"gnome.gnome-weather"
|
||||
# "gnome.seahorse" # keyring/secret manager
|
||||
"gnome-frog" # OCR/QR decoder
|
||||
"gpodder"
|
||||
"gst-device-monitor" # for debugging audio/video
|
||||
# "gthumb"
|
||||
# "lemoa" # lemmy app
|
||||
"libcamera" # for `cam` binary (useful for debugging cameras)
|
||||
"libnotify" # for notify-send; debugging
|
||||
# "lollypop"
|
||||
"loupe" # image viewer
|
||||
"mate.engrampa" # archive manager
|
||||
"mepo" # maps viewer
|
||||
"mpv"
|
||||
"networkmanagerapplet" # for nm-connection-editor: it's better than not having any gui!
|
||||
"ntfy-sh" # notification service
|
||||
# "newsflash" # RSS viewer
|
||||
"pavucontrol"
|
||||
"pwvucontrol" # pipewire version of pavu
|
||||
# "picard" # music tagging
|
||||
# "libsForQt5.plasmatube" # Youtube player
|
||||
"signal-desktop"
|
||||
"snapshot" # camera app
|
||||
"spot" # Gnome Spotify client
|
||||
# "sublime-music"
|
||||
# "tdesktop" # broken on phosh
|
||||
# "tokodon"
|
||||
"tuba" # mastodon/pleroma client (stores pw in keyring)
|
||||
"vulkan-tools" # vulkaninfo
|
||||
# "whalebird" # pleroma client (Electron). input is broken on phosh.
|
||||
"xdg-terminal-exec"
|
||||
"zathura" # PDF/CBZ/ePUB viewer
|
||||
];
|
||||
|
||||
sane.programs.handheldGuiApps = declPackageSet [
|
||||
# "celluloid" # mpv frontend
|
||||
# "chatty" # matrix/xmpp/irc client (2023/12/29: disabled because broken cross build)
|
||||
"cozy" # audiobook player
|
||||
"epiphany" # gnome's web browser
|
||||
# "iotas" # note taking app
|
||||
"komikku"
|
||||
"koreader"
|
||||
"megapixels" # camera app
|
||||
"notejot" # note taking, e.g. shopping list
|
||||
"planify" # todo-tracker/planner
|
||||
"portfolio-filemanager"
|
||||
"tangram" # web browser
|
||||
"wike" # Wikipedia Reader
|
||||
"xarchiver"
|
||||
];
|
||||
|
||||
sane.programs.pcGuiApps = declPackageSet (
|
||||
[
|
||||
# package sets
|
||||
"pcGameApps"
|
||||
"pcTuiApps"
|
||||
] ++ [
|
||||
"audacity"
|
||||
# "blanket" # ambient noise generator
|
||||
"brave" # for the integrated wallet -- as a backup
|
||||
# "cantata" # music player (mpd frontend)
|
||||
# "chromium" # chromium takes hours to build. brave is chromium-based, distributed in binary form, so prefer it.
|
||||
"discord" # x86-only
|
||||
"electrum"
|
||||
"element-desktop"
|
||||
"firefox"
|
||||
"font-manager"
|
||||
# "gajim" # XMPP client. cross build tries to import host gobject-introspection types (2023/09/01)
|
||||
"gimp" # broken on phosh
|
||||
# "gnome.dconf-editor"
|
||||
# "gnome.file-roller"
|
||||
"gnome.gnome-disk-utility"
|
||||
"gnome.nautilus" # file browser
|
||||
# "gnome.totem" # video player, supposedly supports UPnP
|
||||
"handbrake"
|
||||
"inkscape"
|
||||
# "jellyfin-media-player"
|
||||
"kdenlive"
|
||||
# "kid3" # audio tagging
|
||||
"krita"
|
||||
"libreoffice" # TODO: replace with an office suite that uses saner packaging?
|
||||
"losslesscut-bin" # x86-only
|
||||
# "makemkv" # x86-only
|
||||
# "monero-gui" # x86-only
|
||||
# "mumble"
|
||||
# "nheko" # Matrix chat client
|
||||
# "nicotine-plus" # soulseek client. before re-enabling this make sure it's properly sandboxed!
|
||||
# "obsidian"
|
||||
# "openscad" # 3d modeling
|
||||
# "rhythmbox" # local music player
|
||||
# "slic3r"
|
||||
"soundconverter"
|
||||
"spotify" # x86-only
|
||||
"steam"
|
||||
"tor-browser" # x86-only
|
||||
# "vlc"
|
||||
"wireshark" # could maybe ship the cli as sysadmin pkg
|
||||
# "xterm" # requires Xwayland
|
||||
# "zecwallet-lite" # x86-only
|
||||
# "zulip"
|
||||
]
|
||||
);
|
||||
|
||||
# TODO: find a better place for these
|
||||
sane.persist.sys.byStore.plaintext = lib.mkIf config.sane.programs.guiApps.enabled [
|
||||
"/var/lib/alsa" # preserve output levels, default devices
|
||||
{ path = "/var/lib/systemd/backlight"; method = "bind"; } # backlight brightness; bind because systemd T_T
|
||||
];
|
||||
|
||||
systemd.services."systemd-backlight@" = lib.mkIf config.sane.programs.guiApps.enabled {
|
||||
after = [
|
||||
"ensure-var-lib-systemd-backlight.service"
|
||||
];
|
||||
wants = [
|
||||
"ensure-var-lib-systemd-backlight.service"
|
||||
];
|
||||
};
|
||||
|
||||
hardware.opengl = lib.mkIf config.sane.programs.guiApps.enabled ({
|
||||
enable = true;
|
||||
driSupport = lib.mkDefault true;
|
||||
} // (lib.optionalAttrs pkgs.stdenv.isx86_64 {
|
||||
# for 32 bit applications
|
||||
# upstream nixpkgs forbids setting driSupport32Bit unless specifically x86_64 (so aarch64 isn't allowed)
|
||||
driSupport32Bit = lib.mkDefault true;
|
||||
}));
|
||||
|
||||
system.activationScripts.notifyActive = lib.mkIf config.sane.programs.guiApps.enabled {
|
||||
text = ''
|
||||
# notify all logged-in users that the system has been activated/upgraded.
|
||||
if [ -d /run/user ]; then
|
||||
for uid in $(ls /run/user); do
|
||||
PATH="$PATH:${pkgs.sudo}/bin" \
|
||||
sudo -u "#$uid" env DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/$uid/bus" \
|
||||
PATH="$PATH:${pkgs.libnotify}/bin" \
|
||||
notify-send 'nixos activated' "version: $(cat "$systemConfig/nixos-version")"
|
||||
done
|
||||
fi
|
||||
'';
|
||||
};
|
||||
}
|
@@ -1,87 +0,0 @@
|
||||
{ lib, config, pkgs, ... }:
|
||||
|
||||
let
|
||||
cfg = config.sane.gui.gnome;
|
||||
in
|
||||
{
|
||||
options = with lib; {
|
||||
sane.gui.gnome.enable = mkOption {
|
||||
default = false;
|
||||
type = types.bool;
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
sane.programs.guiApps.enableFor.user.colin = true;
|
||||
|
||||
# start gnome/gdm on boot
|
||||
services.xserver.enable = true;
|
||||
services.xserver.desktopManager.gnome.enable = true;
|
||||
services.xserver.displayManager.gdm.enable = true;
|
||||
|
||||
# gnome does networking stuff with networkmanager
|
||||
networking.networkmanager.enable = true;
|
||||
networking.wireless.enable = lib.mkForce false;
|
||||
|
||||
|
||||
# services.xserver.desktopManager.gnome.enable enables some default apps we don't really care about.
|
||||
# see <nixos/modules/services/x11/desktop-managers/gnome.nix>
|
||||
environment.gnome.excludePackages = with pkgs; [
|
||||
# gnome.gnome-menus # unused outside gnome classic, but probably harmless
|
||||
gnome.gnome-control-center #< if you want a faster deploy
|
||||
gnome-tour
|
||||
];
|
||||
|
||||
# disable these for a faster build cycle
|
||||
services.dleyna-renderer.enable = false;
|
||||
services.dleyna-server.enable = false;
|
||||
services.gnome.gnome-browser-connector.enable = false;
|
||||
services.gnome.gnome-initial-setup.enable = false;
|
||||
services.gnome.gnome-remote-desktop.enable = false;
|
||||
services.gnome.gnome-user-share.enable = false;
|
||||
services.gnome.rygel.enable = false;
|
||||
services.gnome.evolution-data-server.enable = lib.mkForce false;
|
||||
services.gnome.gnome-online-accounts.enable = lib.mkForce false;
|
||||
services.gnome.gnome-online-miners.enable = lib.mkForce false;
|
||||
};
|
||||
# user extras:
|
||||
# obtain these by running `dconf dump /` after manually customizing gnome
|
||||
# TODO: fix "is not of type `GVariant value'"
|
||||
# dconf.settings = lib.mkIf (gui == "gnome") {
|
||||
# gnome = {
|
||||
# # control alt-tab behavior
|
||||
# "org/gnome/desktop/wm/keybindings" = {
|
||||
# switch-applications = [ "<Super>Tab" ];
|
||||
# switch-applications-backward=[];
|
||||
# switch-windows=["<Alt>Tab"];
|
||||
# switch-windows-backward=["<Super><Alt>Tab"];
|
||||
# };
|
||||
# # idle power savings
|
||||
# "org/gnome/settings-deamon/plugins/power" = {
|
||||
# idle-brigthness = 50;
|
||||
# sleep-inactive-ac-type = "nothing";
|
||||
# sleep-inactive-battery-timeout = 5400; # seconds
|
||||
# };
|
||||
# "org/gnome/shell" = {
|
||||
# favorite-apps = [
|
||||
# "org.gnome.Nautilus.desktop"
|
||||
# "firefox.desktop"
|
||||
# # "org.gnome.Terminal.desktop"
|
||||
# ];
|
||||
# };
|
||||
# "org/gnome/desktop/session" = {
|
||||
# # how long until considering a session idle (triggers e.g. screen blanking)
|
||||
# idle-delay = 900;
|
||||
# };
|
||||
# "org/gnome/desktop/interface" = {
|
||||
# text-scaling-factor = 1.25;
|
||||
# };
|
||||
# "org/gnome/desktop/media-handling" = {
|
||||
# # don't auto-mount inserted media
|
||||
# automount = false;
|
||||
# automount-open = false;
|
||||
# };
|
||||
# };
|
||||
# };
|
||||
|
||||
}
|
@@ -1,128 +0,0 @@
|
||||
# greetd source/docs:
|
||||
# - <https://git.sr.ht/~kennylevinsen/greetd>
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
systemd-cat = "${pkgs.systemd}/bin/systemd-cat";
|
||||
runWithLogger = identifier: cmd: pkgs.writeShellScriptBin identifier ''
|
||||
echo "launching ${identifier}..." | ${systemd-cat} --identifier=${identifier}
|
||||
${cmd} 2>&1 | ${systemd-cat} --identifier=${identifier}
|
||||
'';
|
||||
cfg = config.sane.gui.greetd;
|
||||
in
|
||||
{
|
||||
options = with lib; {
|
||||
sane.gui.greetd.enable = mkOption {
|
||||
default = false;
|
||||
type = types.bool;
|
||||
};
|
||||
sane.gui.greetd.session.command = mkOption {
|
||||
type = types.str;
|
||||
description = ''
|
||||
name to use for the default session in syslog.
|
||||
'';
|
||||
};
|
||||
sane.gui.greetd.session.name = mkOption {
|
||||
default = "greetd-session";
|
||||
type = types.str;
|
||||
description = "name of session to use in logger";
|
||||
};
|
||||
sane.gui.greetd.session.user = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr types.str;
|
||||
};
|
||||
|
||||
# helpers for common things to layer on top of greetd
|
||||
sane.gui.greetd.sway.enable = mkOption {
|
||||
default = false;
|
||||
type = types.bool;
|
||||
description = ''
|
||||
use sway as a wayland compositor in which to host a graphical greeter like gtkgreet, phog, etc.
|
||||
'';
|
||||
};
|
||||
sane.gui.greetd.sway.greeterCmd = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = ''
|
||||
command for sway to `exec` that provides the actual graphical greeter.
|
||||
'';
|
||||
};
|
||||
sane.gui.greetd.sway.gtkgreet.enable = mkOption {
|
||||
default = false;
|
||||
type = types.bool;
|
||||
description = ''
|
||||
have sway launch gtkgreet instead of directly presenting a desktop.
|
||||
'';
|
||||
};
|
||||
sane.gui.greetd.sway.gtkgreet.session.command = mkOption {
|
||||
type = types.str;
|
||||
description = ''
|
||||
command for gtkgreet to execute on successful authentication.
|
||||
'';
|
||||
};
|
||||
sane.gui.greetd.sway.gtkgreet.session.name = mkOption {
|
||||
type = types.str;
|
||||
description = ''
|
||||
name to use for the default session in syslog and in the gtkgreet menu.
|
||||
note that this `sessionName` will become a binary on the user's PATH.
|
||||
'';
|
||||
};
|
||||
sane.gui.greetd.sway.gtkgreet.session.user = mkOption {
|
||||
type = types.str;
|
||||
default = "colin";
|
||||
description = ''
|
||||
name of user which one expects to login as.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable (lib.mkMerge [
|
||||
(lib.mkIf cfg.sway.enable {
|
||||
sane.gui.greetd.session = if cfg.sway.greeterCmd != null then {
|
||||
name = "sway-as-greeter";
|
||||
command = let
|
||||
swayAsGreeterConfig = pkgs.writeText "sway-as-greeter-config" ''
|
||||
exec ${cfg.sway.greeterCmd}
|
||||
'';
|
||||
in "${pkgs.sway}/bin/sway --debug --config ${swayAsGreeterConfig}";
|
||||
} else {
|
||||
name = "sway";
|
||||
user = lib.mkDefault "colin";
|
||||
command = "${pkgs.sway}/bin/sway --debug";
|
||||
};
|
||||
})
|
||||
(lib.mkIf cfg.sway.gtkgreet.enable (
|
||||
let
|
||||
inherit (cfg.sway.gtkgreet) session;
|
||||
sessionProvider = runWithLogger session.name session.command;
|
||||
in {
|
||||
# gtkgreet shows the --command argument in the UI
|
||||
# - so we want it to look nice (not a /nix/store/... path)
|
||||
# - to do that we put it in the user's PATH.
|
||||
sane.gui.greetd.sway.greeterCmd = "${pkgs.greetd.gtkgreet}/bin/gtkgreet --layer-shell --command ${session.name}";
|
||||
users.users.${session.user}.packages = [ sessionProvider ];
|
||||
}
|
||||
))
|
||||
|
||||
{
|
||||
services.greetd = {
|
||||
enable = true;
|
||||
|
||||
# i could have gtkgreet launch the session directly: but stdout/stderr gets dropped
|
||||
# settings.default_session.command = cfg.session.command;
|
||||
|
||||
# wrapper to launch with stdout/stderr redirected to system journal.
|
||||
settings.default_session.command = let
|
||||
launchWithLogger = runWithLogger cfg.session.name cfg.session.command;
|
||||
in "${launchWithLogger}/bin/${cfg.session.name}";
|
||||
};
|
||||
|
||||
# persisting fontconfig & mesa_shader_cache improves start time by ~5x
|
||||
users.users.greeter.home = "/var/lib/greeter";
|
||||
sane.persist.sys.byStore.plaintext = [
|
||||
{ user = "greeter"; group = "greeter"; path = "/var/lib/greeter/.cache/fontconfig"; }
|
||||
{ user = "greeter"; group = "greeter"; path = "/var/lib/greeter/.cache/mesa_shader_cache"; }
|
||||
];
|
||||
}
|
||||
]);
|
||||
}
|
@@ -1,626 +0,0 @@
|
||||
# this work derives from noneucat's sxmo service/packages, found via NUR
|
||||
# - <repo:nix-community/nur-combined:repos/noneucat/modules/pinephone/sxmo.nix>
|
||||
# other nix works:
|
||||
# - <https://github.com/wentam/sxmo-nix>
|
||||
# - implements sxmo atop tinydm (also packaged by wentam)
|
||||
# - wentam cleans up sxmo-utils to be sealed. also patches to use systemd poweroff, etc
|
||||
# - packages a handful of anjan and proycon utilities
|
||||
# - packages <https://gitlab.com/kop316/mmsd/>
|
||||
# - packages <https://gitlab.com/kop316/vvmd/>
|
||||
# - <https://github.com/chuangzhu/nixpkgs-sxmo>
|
||||
# - implements sxmo as a direct systemd service -- apparently no DM
|
||||
# - packages sxmo-utils
|
||||
# - injects PATH into each script
|
||||
# other OS works:
|
||||
# - <https://git.sr.ht/~aren/sxmo-utils> (arch)
|
||||
# - perhaps sxmo-utils is best packaged via the `resholve` shell solver?
|
||||
#
|
||||
# sxmo upstream links:
|
||||
# - docs (rendered): <https://man.sr.ht/~anjan/sxmo-docs-next/>
|
||||
# - issue tracker: <https://todo.sr.ht/~mil/sxmo-tickets>
|
||||
# - mail list (patches): <https://lists.sr.ht/~mil/sxmo-devel>
|
||||
#
|
||||
# sxmo technical overview:
|
||||
# - inputs
|
||||
# - bonsaid: handles vol/power buttons
|
||||
# - it receives those buttons from dwm (if x11) harcoded in config.h or sway (if wayland)
|
||||
# - lisgd: handles gestures
|
||||
# - startup
|
||||
# - daemon based (lisgsd, idle_locker, statusbar_periodics)
|
||||
# - auto-started at login
|
||||
# - managable by `sxmo_jobs.sh`
|
||||
# - list available daemons: `sxmo_jobs.sh list`
|
||||
# - query if a daemon is active: `sxmo_jobs.sh running <my-daemon>`
|
||||
# - start daemon: `sxmo_jobs.sh start <my-daemon>`
|
||||
# - managable by `superctl`
|
||||
# - `superctl status`
|
||||
# - user hooks:
|
||||
# - live in ~/.config/sxmo/hooks/
|
||||
# - logs:
|
||||
# - live in ~/.local/state/sxmo.log
|
||||
# - ~/.local/state/superd.log
|
||||
# - ~/.local/state/superd/logs/<daemon>.log
|
||||
# - `journalctl --user --boot` (lightdm redirects the sxmo session stdout => systemd)
|
||||
#
|
||||
# - default components:
|
||||
# - DE: sway (if wayland), dwm (if X)
|
||||
# - menus: bemenu (if wayland), dmenu (if X)
|
||||
# - gestures: lisgd
|
||||
# - on-screen keyboard: wvkbd (if wayland), svkbd (if X)
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
cfg = config.sane.gui.sxmo;
|
||||
package = cfg.package;
|
||||
knownKeyboards = {
|
||||
# map keyboard package name -> name of binary to invoke
|
||||
wvkbd = "wvkbd-mobintl";
|
||||
svkbd = "svkbd-mobile-intl";
|
||||
};
|
||||
knownTerminals = {
|
||||
vte = "vte-2.91";
|
||||
};
|
||||
|
||||
systemd-cat = "${pkgs.systemd}/bin/systemd-cat";
|
||||
runWithLogger = identifier: cmd: pkgs.writeShellScript identifier ''
|
||||
echo "launching ${identifier}..." | ${systemd-cat} --identifier=${identifier}
|
||||
${cmd} 2>&1 | ${systemd-cat} --identifier=${identifier}
|
||||
'';
|
||||
|
||||
hookPkgs = {
|
||||
block_suspend = pkgs.static-nix-shell.mkBash {
|
||||
pname = "sxmo_hook_block_suspend.sh";
|
||||
pkgs = [ "procps" ];
|
||||
srcRoot = ./hooks;
|
||||
};
|
||||
inputhandler = pkgs.static-nix-shell.mkBash {
|
||||
pname = "sxmo_hook_inputhandler.sh";
|
||||
pkgs = [ "coreutils" "playerctl" "pulseaudio" ];
|
||||
srcRoot = ./hooks;
|
||||
};
|
||||
postwake = pkgs.static-nix-shell.mkBash {
|
||||
pname = "sxmo_hook_postwake.sh";
|
||||
pkgs = [ "coreutils" ];
|
||||
srcRoot = ./hooks;
|
||||
};
|
||||
rotate = pkgs.static-nix-shell.mkBash {
|
||||
pname = "sxmo_hook_rotate.sh";
|
||||
pkgs = {
|
||||
sway = config.sane.programs.sway.package.sway-unwrapped;
|
||||
};
|
||||
srcRoot = ./hooks;
|
||||
};
|
||||
start = pkgs.static-nix-shell.mkBash {
|
||||
pname = "sxmo_hook_start.sh";
|
||||
pkgs = [ "systemd" "xdg-user-dirs" ];
|
||||
srcRoot = ./hooks;
|
||||
};
|
||||
suspend = pkgs.static-nix-shell.mkPython3Bin {
|
||||
pname = "sxmo_suspend.sh";
|
||||
pkgs = [ "rtl8723cs-wowlan" "util-linux" ];
|
||||
srcRoot = ./hooks;
|
||||
extraMakeWrapperArgs = [ "--add-flags" "--verbose" ];
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
options = with lib; {
|
||||
sane.gui.sxmo.enable = mkOption {
|
||||
default = false;
|
||||
type = types.bool;
|
||||
};
|
||||
sane.gui.sxmo.package = mkOption {
|
||||
type = types.package;
|
||||
default = pkgs.sxmo-utils.override {
|
||||
preferSystemd = true;
|
||||
sway = config.sane.programs.sway.package.sway-unwrapped;
|
||||
};
|
||||
description = ''
|
||||
sxmo base scripts and hooks collection.
|
||||
consider overriding the outputs under /share/sxmo/default_hooks
|
||||
to insert your own user scripts.
|
||||
'';
|
||||
};
|
||||
sane.gui.sxmo.hooks = mkOption {
|
||||
type = types.attrsOf types.path;
|
||||
default = {
|
||||
# default upstream hooks
|
||||
# additional hooks are in subdirectories like three_button_touchscreen/
|
||||
# - sxmo_hook_inputhandler.sh
|
||||
# - sxmo_hook_lock.sh
|
||||
# - sxmo_hook_postwake.sh
|
||||
# - sxmo_hook_screenoff.sh
|
||||
# - sxmo_hook_unlock.sh
|
||||
# by including hooks here, updating the sxmo package also updates the hooks
|
||||
# without requiring any reboot
|
||||
"sxmo_hook_apps.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_apps.sh";
|
||||
# "sxmo_hook_block_suspend.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_block_suspend.sh";
|
||||
"sxmo_hook_call_audio.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_call_audio.sh";
|
||||
"sxmo_hook_contextmenu_fallback.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_contextmenu_fallback.sh";
|
||||
"sxmo_hook_contextmenu.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_contextmenu.sh";
|
||||
"sxmo_hook_desktop_widget.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_desktop_widget.sh";
|
||||
"sxmo_hook_discard.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_discard.sh";
|
||||
"sxmo_hook_hangup.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_hangup.sh";
|
||||
"sxmo_hook_icons.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_icons.sh";
|
||||
"sxmo_hook_lisgdstart.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_lisgdstart.sh";
|
||||
"sxmo_hook_logout.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_logout.sh";
|
||||
"sxmo_hook_missed_call.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_missed_call.sh";
|
||||
"sxmo_hook_mnc.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_mnc.sh";
|
||||
"sxmo_hook_modem.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_modem.sh";
|
||||
"sxmo_hook_mute_ring.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_mute_ring.sh";
|
||||
"sxmo_hook_network_down.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_network_down.sh";
|
||||
"sxmo_hook_network_pre_down.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_network_pre_down.sh";
|
||||
"sxmo_hook_network_pre_up.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_network_pre_up.sh";
|
||||
"sxmo_hook_network_up.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_network_up.sh";
|
||||
"sxmo_hook_notification.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_notification.sh";
|
||||
"sxmo_hook_notifications.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_notifications.sh";
|
||||
"sxmo_hook_pickup.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_pickup.sh";
|
||||
"sxmo_hook_restart_modem_daemons.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_restart_modem_daemons.sh";
|
||||
"sxmo_hook_ring.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_ring.sh";
|
||||
"sxmo_hook_rotate.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_rotate.sh";
|
||||
"sxmo_hook_screenoff.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_screenoff.sh";
|
||||
"sxmo_hook_scripts.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_scripts.sh";
|
||||
"sxmo_hook_sendsms.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_sendsms.sh";
|
||||
"sxmo_hook_smslog.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_smslog.sh";
|
||||
"sxmo_hook_sms.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_sms.sh";
|
||||
"sxmo_hook_start.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_start.sh";
|
||||
"sxmo_hook_statusbar.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_statusbar.sh";
|
||||
"sxmo_hook_stop.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_stop.sh";
|
||||
"sxmo_hook_tailtextlog.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_tailtextlog.sh";
|
||||
} // {
|
||||
# default hooks for this nix module, not upstreamable
|
||||
"sxmo_hook_block_suspend.sh" = "${hookPkgs.block_suspend}/bin/sxmo_hook_block_suspend.sh";
|
||||
"sxmo_hook_inputhandler.sh" = "${hookPkgs.inputhandler}/bin/sxmo_hook_inputhandler.sh";
|
||||
"sxmo_hook_postwake.sh" = "${hookPkgs.postwake}/bin/sxmo_hook_postwake.sh";
|
||||
"sxmo_hook_rotate.sh" = "${hookPkgs.rotate}/bin/sxmo_hook_rotate.sh";
|
||||
"sxmo_hook_start.sh" = "${hookPkgs.start}/bin/sxmo_hook_start.sh";
|
||||
"sxmo_suspend.sh" = "${hookPkgs.suspend}/bin/sxmo_suspend.sh";
|
||||
};
|
||||
description = ''
|
||||
extra hooks to add with higher priority than the builtins
|
||||
'';
|
||||
};
|
||||
sane.gui.sxmo.terminal = mkOption {
|
||||
# type = types.nullOr (types.enum [ "foot" "st" "vte" ]);
|
||||
type = types.nullOr types.str;
|
||||
default = "foot";
|
||||
description = ''
|
||||
name of terminal to use for sxmo_terminal.sh.
|
||||
foot, st, and vte have special integrations in sxmo, but any will work.
|
||||
'';
|
||||
};
|
||||
sane.gui.sxmo.keyboard = mkOption {
|
||||
# type = types.nullOr (types.enum ["wvkbd"])
|
||||
type = types.nullOr types.str;
|
||||
default = "wvkbd";
|
||||
description = ''
|
||||
name of on-screen-keyboard to use for sxmo_keyboard.sh.
|
||||
this sets the KEYBOARD environment variable.
|
||||
see also: KEYBOARD_ARGS.
|
||||
'';
|
||||
};
|
||||
sane.gui.sxmo.settings = mkOption {
|
||||
description = ''
|
||||
environment variables used to configure sxmo.
|
||||
e.g. SXMO_UNLOCK_IDLE_TIME or SXMO_VOLUME_BUTTON.
|
||||
'';
|
||||
type = types.submodule {
|
||||
freeformType = types.attrsOf types.str;
|
||||
options =
|
||||
let
|
||||
mkSettingsOpt = default: description: mkOption {
|
||||
inherit default description;
|
||||
type = types.nullOr types.str;
|
||||
};
|
||||
in {
|
||||
SXMO_BAR_SHOW_BAT_PER = mkSettingsOpt "1" "show battery percentage in statusbar";
|
||||
SXMO_DISABLE_CONFIGVERSION_CHECK = mkSettingsOpt "1" "allow omitting the configversion line from user-provided sxmo dotfiles";
|
||||
SXMO_UNLOCK_IDLE_TIME = mkSettingsOpt "300" "how many seconds of inactivity before locking the screen"; # lock -> screenoff happens 8s later, not configurable
|
||||
# SXMO_WM = mkSettingsOpt "sway" "sway or dwm. ordinarily initialized by sxmo_{x,w}init.sh";
|
||||
SXMO_NO_AUDIO = mkSettingsOpt "" "don't start pipewire/pulseaudio in sxmo_hook_start.sh, don't show audio in statusbar, disable audio menu";
|
||||
SXMO_STATES = mkSettingsOpt "unlock screenoff" "list of states the device should support (unlock, lock, screenoff)";
|
||||
SXMO_SWAY_SCALE = mkSettingsOpt "1" "sway output scale";
|
||||
SXMO_WOB_DISABLE = mkSettingsOpt "" "disable the on-screen volume display";
|
||||
};
|
||||
};
|
||||
default = {};
|
||||
};
|
||||
sane.gui.sxmo.noidle = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "inhibit lock-on-idle and screenoff-on-idle";
|
||||
};
|
||||
sane.gui.sxmo.nogesture = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "don't start lisgd gesture daemon by default";
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkMerge [
|
||||
{
|
||||
sane.programs.sxmoApps = {
|
||||
packageUnwrapped = null;
|
||||
suggestedPrograms = [
|
||||
"guiApps"
|
||||
"bemenu" # specifically to import its theming
|
||||
"bonsai"
|
||||
"sfeed" # want this here so that the user's ~/.sfeed/sfeedrc gets created
|
||||
# "superd" # make superctl (used by sxmo) be on PATH
|
||||
# "sway-autoscaler"
|
||||
"waybar-sxmo-status"
|
||||
];
|
||||
|
||||
persist.byStore.cryptClearOnBoot = [
|
||||
# builds to be 10's of MB per day
|
||||
# ".local/state/superd/logs"
|
||||
".local/share/sxmo/modem" # SMS
|
||||
".local/share/sxmo/notifications" # so i can see new SMS messages. not sure actually if this needs persisting or if it'll re-hydrate from modem.
|
||||
];
|
||||
};
|
||||
|
||||
sane.programs.waybar-sxmo-status = {
|
||||
packageUnwrapped = pkgs.static-nix-shell.mkBash {
|
||||
pname = "waybar-sxmo-status";
|
||||
srcRoot = ./.;
|
||||
pkgs = {
|
||||
sxmo-utils = package;
|
||||
"sxmo-utils.runtimeDeps" = package.runtimeDeps;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
# TODO: lift to option declaration
|
||||
# N.B.: TERMCMD was renamed SXMO_TERMINAL on 2023/08/29
|
||||
sane.gui.sxmo.settings.SXMO_TERMINAL = lib.mkIf (cfg.terminal != null)
|
||||
(lib.mkDefault (knownTerminals."${cfg.terminal}" or cfg.terminal));
|
||||
sane.gui.sxmo.settings.KEYBOARD = lib.mkIf (cfg.keyboard != null)
|
||||
(lib.mkDefault (knownKeyboards."${cfg.keyboard}" or cfg.keyboard));
|
||||
}
|
||||
|
||||
(lib.mkIf cfg.enable (lib.mkMerge [
|
||||
{
|
||||
sane.programs.sway.enableFor.user.colin = true;
|
||||
sane.programs.waybar.config = {
|
||||
top = import ./waybar-top.nix;
|
||||
fontSize = 14;
|
||||
};
|
||||
sane.programs.sway.config = {
|
||||
# N.B. missing from upstream sxmo config here is:
|
||||
# - `bindsym $mod+g exec sxmo_hook_locker.sh`
|
||||
# - `bindsym $mod+t exec sxmo_appmenu.sh power`
|
||||
# - `bindsym $mod+i exec sxmo_wmmenu.sh windowswitcher`
|
||||
# - `bindsym $mod+p exec sxmo_appmenu.sh`
|
||||
# - `bindsym $mod+Shift+p exec sxmo_appmenu.sh sys`
|
||||
# - `input * xkb_options compose:ralt`
|
||||
# these could be added, but i don't see much benefit.
|
||||
font = "pango:monospace 10";
|
||||
mod = "Mod1"; # prefer Alt
|
||||
workspace_layout = "tabbed";
|
||||
|
||||
# screenshot_cmd = "sxmo_screenshot.sh";
|
||||
extra_lines =
|
||||
let
|
||||
sxmo_init = pkgs.writeShellScript "sxmo_init.sh" ''
|
||||
# perform the same behavior as sxmo_{x,w}init.sh -- but without actually launching wayland/X11
|
||||
# this amounts to:
|
||||
# - setting env vars (e.g. getting the hooks onto PATH)
|
||||
# - placing default configs in ~ for sxmo-launched services (sxmo_migrate.sh)
|
||||
# - binding vol/power buttons (sxmo_swayinitconf.sh)
|
||||
# - launching sxmo_hook_start.sh
|
||||
#
|
||||
# the commands here are similar to upstream sxmo_winit.sh, but not identical and the ordering may be different
|
||||
|
||||
# profile may contain SXMO_DEVICE_NAME which is used by _sxmo_load_environment so load it early
|
||||
source "$XDG_CONFIG_HOME/sxmo/profile"
|
||||
# sourcing upstream sxmo_init.sh triggers _sxmo_load_environment
|
||||
# which ensures SXMO_* environment variables are set
|
||||
source ${package}/etc/profile.d/sxmo_init.sh
|
||||
# _sxmo_prepare_dirs ensures ~/.cache/sxmo & other XDG dirs exist with correct perms & owner
|
||||
_sxmo_prepare_dirs
|
||||
# migrate tells sxmo to provide the following default files:
|
||||
# - ~/.config/sxmo/profile
|
||||
# - ~/.config/fontconfig/conf.d/50-sxmo.conf
|
||||
# - ~/.config/sxmo/sway
|
||||
# - ~/.config/foot/foot.ini
|
||||
# - ~/.config/mako/config
|
||||
# - ~/.config/sxmo/bonsai_tree.json
|
||||
# - ~/.config/wob/wob.ini
|
||||
# - ~/.config/sxmo/conky.conf
|
||||
sxmo_migrate.sh sync
|
||||
# various things may have happened above that require me to re-load the profile here:
|
||||
# - _sxmo_load_environment sources a deviceprofile.sh file, which may override my profile settings.
|
||||
# very obvious if you set a non-default SXMO_SWAY_SCALE.
|
||||
# - sxmo_migrate.sh may have provided a default profile, if i failed to
|
||||
source "$XDG_CONFIG_HOME/sxmo/profile"
|
||||
# place my non-specialized hooks at higher precedence than the default device-hooks
|
||||
# alternative would be to move my hooks to ~/.config/sxmo/hooks/<device-name>.
|
||||
export PATH="$XDG_CONFIG_HOME/sxmo/hooks:$PATH"
|
||||
|
||||
# kill anything leftover from the previous sxmo run. this way we can (try to) be reentrant
|
||||
echo "sxmo_init: killing stale daemons (if active)"
|
||||
sxmo_jobs.sh stop all
|
||||
pkill bemenu
|
||||
pkill wvkbd
|
||||
pkill superd
|
||||
|
||||
# configure vol/power-button input mapping (upstream SXMO has this in sway config)
|
||||
echo "sxmo_init: configuring sway bindings/displays with:"
|
||||
echo "SXMO_POWER_BUTTON: $SXMO_POWER_BUTTON"
|
||||
echo "SXMO_VOLUME_BUTTON: $SXMO_VOLUME_BUTTON"
|
||||
echo "SXMO_SWAY_SCALE: $SXMO_SWAY_SCALE"
|
||||
sxmo_swayinitconf.sh
|
||||
|
||||
echo "sxmo_init: invoking sxmo_hook_start.sh with:"
|
||||
echo "PATH: $PATH"
|
||||
sxmo_hook_start.sh
|
||||
'';
|
||||
in ''
|
||||
# TODO: some of this is probably unnecessary
|
||||
mode "menu" {
|
||||
# just a placeholder for "menu" mode
|
||||
bindsym --input-device=1:1:1c21800.lradc XF86AudioMute exec nothing
|
||||
}
|
||||
bindsym button2 kill
|
||||
bindswitch lid:on exec sxmo_wm.sh dpms on
|
||||
bindswitch lid:off exec sxmo_wm.sh dpms off
|
||||
|
||||
exec 'printf %s "$SWAYSOCK" > "$XDG_RUNTIME_DIR"/sxmo.swaysock'
|
||||
|
||||
# XXX(2023/12/04): this shouldn't be necessary, but without this Komikku fails to launch because XDG_SESSION_TYPE is unset
|
||||
|
||||
exec dbus-update-activation-environment --systemd XDG_SESSION_TYPE
|
||||
exec_always ${sxmo_init}
|
||||
'';
|
||||
};
|
||||
|
||||
sane.programs.sxmoApps.enableFor.user.colin = true;
|
||||
|
||||
sane.programs.sway-autoscaler.config.defaultScale = builtins.fromJSON cfg.settings.SXMO_SWAY_SCALE;
|
||||
|
||||
# sxmo internally uses doas instead of sudo
|
||||
security.doas.enable = true;
|
||||
security.doas.wheelNeedsPassword = false;
|
||||
|
||||
# lightdm-mobile-greeter: "The name org.a11y.Bus was not provided by any .service files"
|
||||
services.gnome.at-spi2-core.enable = true;
|
||||
|
||||
environment.systemPackages = [
|
||||
package
|
||||
] ++ lib.optionals (cfg.terminal != null) [ pkgs."${cfg.terminal}" ]
|
||||
++ lib.optionals (cfg.keyboard != null) [ pkgs."${cfg.keyboard}" ];
|
||||
|
||||
environment.sessionVariables = {
|
||||
XDG_DATA_DIRS = [
|
||||
# TODO: only need the share/sxmo directly linked
|
||||
"${package}/share"
|
||||
];
|
||||
} // (lib.filterAttrs (k: v:
|
||||
k == "SXMO_DISABLE_CONFIGVERSION_CHECK" # read before `profile` is sourced
|
||||
|| k == "SXMO_TERMINAL" # for apps launched via `swaymsg exec -- sxmo_terminal.sh ...`
|
||||
)
|
||||
cfg.settings
|
||||
);
|
||||
|
||||
|
||||
sane.programs.bonsai.config.transitions = let
|
||||
doExec = inputName: transitions: {
|
||||
type = "exec";
|
||||
command = [
|
||||
"setsid"
|
||||
"-f"
|
||||
"sxmo_hook_inputhandler.sh"
|
||||
inputName
|
||||
];
|
||||
inherit transitions;
|
||||
};
|
||||
onDelay = ms: transitions: {
|
||||
type = "delay";
|
||||
delay_duration = ms * 1000000;
|
||||
inherit transitions;
|
||||
};
|
||||
onEvent = eventName: transitions: {
|
||||
type = "event";
|
||||
event_name = eventName;
|
||||
inherit transitions;
|
||||
};
|
||||
friendlyToBonsai = { trigger ? null, terminal ? false, timeout ? {}, power_pressed ? {}, power_released ? {}, voldown_pressed ? {}, voldown_released ? {}, volup_pressed ? {}, volup_released ? {} }@args:
|
||||
if trigger != null then [
|
||||
(doExec trigger (friendlyToBonsai (builtins.removeAttrs args ["trigger"])))
|
||||
] else let
|
||||
events = [ ]
|
||||
++ (lib.optional (timeout != {}) (onDelay (timeout.ms or 400) (friendlyToBonsai (builtins.removeAttrs timeout ["ms"]))))
|
||||
++ (lib.optional (power_pressed != {}) (onEvent "power_pressed" (friendlyToBonsai power_pressed)))
|
||||
++ (lib.optional (power_released != {}) (onEvent "power_released" (friendlyToBonsai power_released)))
|
||||
++ (lib.optional (voldown_pressed != {}) (onEvent "voldown_pressed" (friendlyToBonsai voldown_pressed)))
|
||||
++ (lib.optional (voldown_released != {}) (onEvent "voldown_released" (friendlyToBonsai voldown_released)))
|
||||
++ (lib.optional (volup_pressed != {}) (onEvent "volup_pressed" (friendlyToBonsai volup_pressed)))
|
||||
++ (lib.optional (volup_released != {}) (onEvent "volup_released" (friendlyToBonsai volup_released)))
|
||||
;
|
||||
in assert terminal -> events == []; events;
|
||||
|
||||
# trigger ${button}_hold_N every `holdTime` ms until ${button} is released
|
||||
recurseHold = button: { count ? 1, maxHolds ? 5, prefix ? "", holdTime ? 600, ... }@opts: lib.optionalAttrs (count <= maxHolds) {
|
||||
"${button}_released".terminal = true; # end the hold -> back to root state
|
||||
timeout = {
|
||||
ms = holdTime;
|
||||
trigger = "${prefix}${button}_hold_${builtins.toString count}";
|
||||
} // (recurseHold button (opts // { count = count+1; }));
|
||||
};
|
||||
|
||||
# trigger volup_tap_N or voldown_tap_N on every tap.
|
||||
# if a volume button is held, then switch into `recurseHold`'s handling instead
|
||||
volumeActions = { count ? 1, maxTaps ? 5, prefix ? "", timeout ? 600, ... }@opts: lib.optionalAttrs (count != maxTaps) {
|
||||
volup_pressed = (recurseHold "volup" opts) // {
|
||||
volup_released = {
|
||||
trigger = "${prefix}volup_tap_${builtins.toString count}";
|
||||
timeout.ms = timeout;
|
||||
} // (volumeActions (opts // { count = count+1; }));
|
||||
};
|
||||
voldown_pressed = (recurseHold "voldown" opts) // {
|
||||
voldown_released = {
|
||||
trigger = "${prefix}voldown_tap_${builtins.toString count}";
|
||||
timeout.ms = timeout;
|
||||
} // (volumeActions (opts // { count = count+1; }));
|
||||
};
|
||||
};
|
||||
in friendlyToBonsai {
|
||||
# map sequences of "events" to an argument to pass to sxmo_hook_inputhandler.sh
|
||||
|
||||
# map: power (short), power (short) x2, power (long)
|
||||
power_pressed.timeout.ms = 900; # press w/o release. this is a long timeout because it's tied to the "kill window" action.
|
||||
power_pressed.timeout.trigger = "powerhold";
|
||||
power_pressed.power_released.timeout.trigger = "powerbutton_one";
|
||||
power_pressed.power_released.timeout.ms = 300;
|
||||
power_pressed.power_released.power_pressed.trigger = "powerbutton_two";
|
||||
|
||||
# map: volume taps and holds
|
||||
volup_pressed = (recurseHold "volup" {}) // {
|
||||
# this either becomes volup_hold_* (via recurseHold, above) or:
|
||||
# - a short volup_tap_1 followed by:
|
||||
# - a *finalized* volup_1 (i.e. end of action)
|
||||
# - more taps/holds, in which case we prefix it with `modal_<action>`
|
||||
# to denote that we very explicitly entered this state.
|
||||
#
|
||||
# it's clunky: i do it this way so that voldown can map to keyboard/terminal in unlock mode
|
||||
# but trigger media controls in screenoff
|
||||
# in a way which *still* allows media controls if explicitly entered into via a tap on volup first
|
||||
volup_released = (volumeActions { prefix = "modal_"; }) // {
|
||||
trigger = "volup_tap_1";
|
||||
timeout.ms = 300;
|
||||
timeout.trigger = "volup_1";
|
||||
};
|
||||
};
|
||||
voldown_pressed = (volumeActions {}).voldown_pressed // {
|
||||
trigger = "voldown_start";
|
||||
};
|
||||
};
|
||||
|
||||
# sxmo puts in /share/sxmo:
|
||||
# - profile.d/sxmo_init.sh
|
||||
# - appcfg/
|
||||
# - default_hooks/
|
||||
# - and more
|
||||
# environment.pathsToLink = [ "/share/sxmo" ];
|
||||
|
||||
# if superd fails to start a service within 100ms, it'll try to start again
|
||||
# the fallout of this is that during intense lag (e.g. OOM or swapping) it can
|
||||
# start the service many times.
|
||||
# see <repo:craftyguy/superd:internal/cmd/cmd.go>
|
||||
# startTimerDuration = 100 * time.Millisecond
|
||||
# TODO: better fix may be to patch `sxmo_hook_lisgdstart.sh` and force it to behave as a singleton
|
||||
# systemd.services."dedupe-sxmo-lisgd" = {
|
||||
# description = "kill duplicate lisgd processes started by superd";
|
||||
# serviceConfig = {
|
||||
# Type = "oneshot";
|
||||
# };
|
||||
# script = ''
|
||||
# if [ "$(${pkgs.procps}/bin/pgrep -c lisgd)" -gt 1 ]; then
|
||||
# echo 'killing duplicated lisgd daemons'
|
||||
# ${pkgs.psmisc}/bin/killall lisgd # let superd restart it
|
||||
# fi
|
||||
# '';
|
||||
# wantedBy = [ "multi-user.target" ];
|
||||
# };
|
||||
# systemd.timers."dedupe-sxmo-lisgd" = {
|
||||
# wantedBy = [ "dedupe-sxmo-lisgd.service" ];
|
||||
# timerConfig = {
|
||||
# OnUnitActiveSec = "2min";
|
||||
# };
|
||||
# };
|
||||
|
||||
sane.user.fs = lib.mkMerge [
|
||||
{
|
||||
# link the superd services into a place where systemd can find them.
|
||||
# the unit files should be compatible, except maybe for PATH handling
|
||||
# ".config/systemd/user/autocutsel-primary.service".symlink.target = "${package}/share/superd/services/autocutsel-primary.service";
|
||||
# ".config/systemd/user/autocutsel.service".symlink.target = "${package}/share/superd/services/autocutsel.service";
|
||||
# ".config/systemd/user/bonsaid.service".symlink.target = "${package}/share/superd/services/bonsaid.service";
|
||||
# # ".config/systemd/user/dunst.service".symlink.target = "${package}/share/superd/services/dunst.service";
|
||||
# # ".config/systemd/user/mako.service".symlink.target = "${package}/share/superd/services/mako.service";
|
||||
# ".config/systemd/user/mmsd-tng.service".symlink.target = "${package}/share/superd/services/mmsd-tng.service";
|
||||
# ".config/systemd/user/sxmo_autosuspend.service".symlink.target = "${package}/share/superd/services/sxmo_autosuspend.service";
|
||||
# ".config/systemd/user/sxmo_battery_monitor.service".symlink.target = "${package}/share/superd/services/sxmo_battery_monitor.service";
|
||||
# ".config/systemd/user/sxmo_conky.service".symlink.target = "${package}/share/superd/services/sxmo_conky.service";
|
||||
# ".config/systemd/user/sxmo_desktop_widget.service".symlink.target = "${package}/share/superd/services/sxmo_desktop_widget.service";
|
||||
# ".config/systemd/user/sxmo_hook_lisgd.service".symlink.target = "${package}/share/superd/services/sxmo_hook_lisgd.service";
|
||||
# ".config/systemd/user/sxmo_menumode_toggler.service".symlink.target = "${package}/share/superd/services/sxmo_menumode_toggler.service";
|
||||
# ".config/systemd/user/sxmo_modemmonitor.service".symlink.target = "${package}/share/superd/services/sxmo_modemmonitor.service";
|
||||
# ".config/systemd/user/sxmo_networkmonitor.service".symlink.target = "${package}/share/superd/services/sxmo_networkmonitor.service";
|
||||
# ".config/systemd/user/sxmo_notificationmonitor.service".symlink.target = "${package}/share/superd/services/sxmo_notificationmonitor.service";
|
||||
# ".config/systemd/user/sxmo_soundmonitor.service".symlink.target = "${package}/share/superd/services/sxmo_soundmonitor.service";
|
||||
# ".config/systemd/user/sxmo_wob.service".symlink.target = "${package}/share/superd/services/sxmo_wob.service";
|
||||
# ".config/systemd/user/sxmo-x11-status.service".symlink.target = "${package}/share/superd/services/sxmo-x11-status.service";
|
||||
# ".config/systemd/user/unclutter.service".symlink.target = "${package}/share/superd/services/unclutter.service";
|
||||
# ".config/systemd/user/unclutter-xfixes.service".symlink.target = "${package}/share/superd/services/unclutter-xfixes.service";
|
||||
# ".config/systemd/user/vvmd.service".symlink.target = "${package}/share/superd/services/vvmd.service";
|
||||
|
||||
# service code further below tells systemd to put ~/.config/sxmo/hooks on PATH, but it puts hooks/bin on PATH instead, so symlink that
|
||||
".config/sxmo/hooks/bin".symlink.target = ".";
|
||||
|
||||
".cache/sxmo/sxmo.noidle" = lib.mkIf cfg.noidle {
|
||||
symlink.text = "";
|
||||
};
|
||||
".cache/sxmo/sxmo.nogesture" = lib.mkIf cfg.nogesture {
|
||||
symlink.text = "";
|
||||
};
|
||||
".config/sxmo/profile".symlink.text = let
|
||||
mkKeyValue = key: value: ''export ${key}="${value}"'';
|
||||
in
|
||||
lib.generators.toKeyValue { inherit mkKeyValue; } cfg.settings;
|
||||
}
|
||||
(lib.mapAttrs' (name: value: {
|
||||
# sxmo's `_sxmo_load_environments` adds to PATH:
|
||||
# - ~/.config/sxmo/hooks/$SXMO_DEVICE_NAME
|
||||
# - ~/.config/sxmo/hooks
|
||||
name = ".config/sxmo/hooks/${name}";
|
||||
value.symlink.target = value;
|
||||
}) cfg.hooks)
|
||||
];
|
||||
|
||||
sane.user.services = let
|
||||
sxmoPath = [ package ] ++ package.runtimeDeps;
|
||||
sxmoEnvSetup = ''
|
||||
# mimic my sxmo_init.sh a bit. refer to the actual sxmo_init.sh above for details.
|
||||
# the specific ordering, and the duplicated profile sourcing, matters.
|
||||
export HOME="''${HOME:-/home/colin}"
|
||||
export XDG_CONFIG_HOME="''${XDG_CONFIG_HOME:-$HOME/.config}"
|
||||
source "$XDG_CONFIG_HOME/sxmo/profile"
|
||||
source ${package}/etc/profile.d/sxmo_init.sh
|
||||
source "$XDG_CONFIG_HOME/sxmo/profile"
|
||||
export PATH="$XDG_CONFIG_HOME/sxmo/hooks:$PATH:${lib.makeBinPath sxmoPath}"
|
||||
'';
|
||||
sxmoService = name: {
|
||||
description = "sxmo ${name}";
|
||||
script = ''
|
||||
${sxmoEnvSetup}
|
||||
exec sxmo_${name}.sh
|
||||
'';
|
||||
serviceConfig.Type = "simple";
|
||||
serviceConfig.Restart = "always";
|
||||
serviceConfig.RestartSec = "20s";
|
||||
};
|
||||
in {
|
||||
# these are defined here, and started mostly in sxmo_hook_start.sh.
|
||||
# the ones commented our here are the ones i explicitly no longer use.
|
||||
# uncommenting them here *won't* cause them to be auto-started.
|
||||
sxmo_autosuspend = sxmoService "autosuspend";
|
||||
# sxmo_battery_monitor = sxmoService "battery_monitor";
|
||||
sxmo_desktop_widget = sxmoService "hook_desktop_widget";
|
||||
sxmo_hook_lisgd = sxmoService "hook_lisgdstart";
|
||||
sxmo_menumode_toggler = sxmoService "menumode_toggler";
|
||||
sxmo_modemmonitor = sxmoService "modemmonitor";
|
||||
# sxmo_networkmonitor = sxmoService "networkmonitor";
|
||||
sxmo_notificationmonitor = sxmoService "notificationmonitor";
|
||||
# sxmo_soundmonitor = sxmoService "soundmonitor";
|
||||
# sxmo_wob = sxmoService "wob";
|
||||
sxmo-x11-status = sxmoService "status_xsetroot";
|
||||
|
||||
bonsaid.script = lib.mkBefore sxmoEnvSetup;
|
||||
};
|
||||
}
|
||||
]))
|
||||
];
|
||||
}
|
@@ -1,57 +0,0 @@
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i bash -p procps
|
||||
|
||||
# Basic exponential backoff, this should save some resources if we're blocked by
|
||||
# the same thing for a while
|
||||
delay() {
|
||||
sleep "$delay_time"
|
||||
delay_time="$((delay_time*2))"
|
||||
if [ "$delay_time" -gt 45 ]; then
|
||||
delay_time=45
|
||||
fi
|
||||
}
|
||||
|
||||
wait_item() {
|
||||
delay_time=1
|
||||
while $1 > /dev/null 2>&1; do
|
||||
echo "Blocking suspend for $1"
|
||||
waited=1
|
||||
delay
|
||||
done
|
||||
}
|
||||
|
||||
##################################### below is original, not shared with upstream sxmo_hook_block_suspend.sh
|
||||
|
||||
casting_go2tv() {
|
||||
pgrep -f go2tv
|
||||
}
|
||||
|
||||
# forward to the next block_suspend.sh script (if any).
|
||||
# have to handle the case where this script is on PATH, and also when it was called without being on PATH.
|
||||
# the implementation here causes us to call ourselves exactly once, at most (or twice, if there are duplicate PATH entries)
|
||||
SXMO_HOOK_BLOCK_SUSPEND_DEPTH=$((${SXMO_HOOK_BLOCK_SUSPEND_DEPTH:-0} + 1))
|
||||
echo "recurse counter: $SXMO_HOOK_BLOCK_SUSPEND_DEPTH"
|
||||
|
||||
block_suspend_next=true
|
||||
FWD_COUNT=0
|
||||
IFS=:
|
||||
for p in $PATH ; do
|
||||
echo "testing: $p/sxmo_hook_block_suspend.sh"
|
||||
if $(test -x "$p/sxmo_hook_block_suspend.sh"); then
|
||||
FWD_COUNT=$(($FWD_COUNT + 1))
|
||||
fi
|
||||
if [ "$FWD_COUNT" -eq "$SXMO_HOOK_BLOCK_SUSPEND_DEPTH" ]; then
|
||||
block_suspend_next="$p/sxmo_hook_block_suspend.sh"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
while [ "$waited" != "0" ]; do
|
||||
waited=0
|
||||
|
||||
echo "forwarding to: $block_suspend_next"
|
||||
SXMO_HOOK_BLOCK_SUSPEND_DEPTH="$SXMO_HOOK_BLOCK_SUSPEND_DEPTH" "$block_suspend_next"
|
||||
|
||||
# wait for my own items last. else, we could wait for go2tv, then wait for internals, and in the meantime go2tv was re-spawned.
|
||||
wait_item casting_go2tv
|
||||
done
|
@@ -1,144 +0,0 @@
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i bash -p coreutils -p playerctl -p pulseaudio
|
||||
|
||||
# input map considerations
|
||||
# - using compound actions causes delays.
|
||||
# e.g. if volup->volup is a distinct action from volup, then single-volup action is forced to wait the maximum button delay.
|
||||
# - actions which are to be responsive should therefore have a dedicated key.
|
||||
# - a dedicated "kill" combo is important for unresponsive fullscreen apps, because appmenu doesn't show in those
|
||||
# - although better may be to force appmenu to show over FS apps
|
||||
# - bonsai mappings are static, so buttons can't benefit from non-compounding unless they're mapped accordingly for all lock states
|
||||
# - this limitation could be removed, but with work
|
||||
#
|
||||
# example of a design which considers these things:
|
||||
# - when unlocked:
|
||||
# - volup toggle -> app menu
|
||||
# - voldown press -> keyboard
|
||||
# - voldown hold -> terminal
|
||||
# - power x2 -> screenoff
|
||||
# - hold power -> kill app
|
||||
# - when locked:
|
||||
# - volup tap -> volume up
|
||||
# - volup hold -> media seek forward
|
||||
# - voldown tap -> volume down
|
||||
# - voldown hold -> media seek backward
|
||||
# - power x1 -> screen on
|
||||
# - power x2 -> play/pause media
|
||||
# some trickiness allows for media controls in unlocked mode:
|
||||
# - volup tap -> enter media mode
|
||||
# - i.e. in this state, vol tap/hold is mapped to volume/seek
|
||||
# - if, after entering media mode, no more taps occur, then we trigger the default app-menu action
|
||||
# limitations/downsides:
|
||||
# - power mappings means phone is artificially slow to unlock.
|
||||
# - media controls when unlocked have quirks:
|
||||
# - mashing voldown to decrease the volume will leave you with a toggled keyboard.
|
||||
# - seeking backward isn't possible except by first tapping volup.
|
||||
|
||||
|
||||
# increments to use for volume adjustment
|
||||
VOL_INCR=5
|
||||
|
||||
# replicating the naming from upstream sxmo_hook_inputhandler.sh...
|
||||
ACTION="$1"
|
||||
STATE=$(cat "$SXMO_STATE")
|
||||
|
||||
noop() {
|
||||
true
|
||||
}
|
||||
|
||||
handle_with() {
|
||||
echo "sxmo_hook_inputhandler.sh: STATE=$STATE ACTION=$ACTION: handle_with: $@"
|
||||
"$@"
|
||||
exit 0
|
||||
}
|
||||
|
||||
|
||||
# state is one of:
|
||||
# - "unlock" => normal operation; display on and touchscreen on
|
||||
# - "screenoff" => display off and touchscreen off
|
||||
# - "lock" => display on but touchscreen disabled
|
||||
# - "proximity{lock,unlock}" => intended for when in a phone call
|
||||
|
||||
if [ "$STATE" = "unlock" ]; then
|
||||
case "$ACTION" in
|
||||
# powerbutton_one: intentional default to no-op
|
||||
# powerbutton_two: intentional default to screenoff
|
||||
"powerhold")
|
||||
# power thrice: kill active window
|
||||
handle_with sxmo_killwindow.sh
|
||||
;;
|
||||
|
||||
"volup_tap_1")
|
||||
# swallow: this could be the start to a media control (multi taps / holds),
|
||||
# or it could be just a single tap -> release, handled next/below
|
||||
handle_with noop
|
||||
;;
|
||||
"volup_1")
|
||||
# volume up once: app-specific menu w/ fallback to SXMO system menu
|
||||
handle_with sxmo_appmenu.sh
|
||||
;;
|
||||
|
||||
"voldown_start")
|
||||
# volume down once: toggle keyboard
|
||||
handle_with sxmo_keyboard.sh toggle
|
||||
;;
|
||||
"voldown_hold_2")
|
||||
# hold voldown to launch terminal
|
||||
# note we already triggered the keyboard; that's fine: usually keyboard + terminal go together :)
|
||||
# voldown_hold_1 frequently triggers during short taps meant only to reveal the keyboard,
|
||||
# so prefer a longer hold duration
|
||||
handle_with sxmo_terminal.sh
|
||||
;;
|
||||
"voldown_tap_1")
|
||||
# swallow, to prevent keyboard from also triggering media controls
|
||||
handle_with noop
|
||||
;;
|
||||
voldown_hold_*)
|
||||
# swallow, to prevent terminal from also triggering media controls
|
||||
handle_with noop
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if [ "$STATE" = "screenoff" ]; then
|
||||
case "$ACTION" in
|
||||
"powerbutton_two")
|
||||
# power twice => toggle media player
|
||||
handle_with playerctl play-pause
|
||||
;;
|
||||
"powerhold")
|
||||
# power toggle during deep sleep often gets misread as power hold, so treat same
|
||||
handle_with sxmo_state.sh set unlock
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# default actions
|
||||
case "$ACTION" in
|
||||
"powerbutton_one")
|
||||
# power once => unlock
|
||||
handle_with sxmo_state.sh set unlock
|
||||
;;
|
||||
"powerbutton_two")
|
||||
# power twice => screenoff
|
||||
handle_with sxmo_state.sh set screenoff
|
||||
;;
|
||||
# powerbutton_three: intentional no-op because overloading the kill-window handler is risky
|
||||
|
||||
volup_tap*|modal_volup_tap*)
|
||||
handle_with pactl set-sink-volume @DEFAULT_SINK@ +"$VOL_INCR%"
|
||||
;;
|
||||
voldown_tap*|modal_voldown_tap*)
|
||||
handle_with pactl set-sink-volume @DEFAULT_SINK@ -"$VOL_INCR%"
|
||||
;;
|
||||
|
||||
volup_hold*|modal_volup_hold*)
|
||||
handle_with playerctl position 30+
|
||||
;;
|
||||
voldown_hold*|modal_voldown_hold*)
|
||||
handle_with playerctl position 10-
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
handle_with noop
|
@@ -1,51 +0,0 @@
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i bash -p coreutils
|
||||
|
||||
# the default sxmo_postwake handler checks if the modem is offline
|
||||
# and if so installs a wakelock to block suspend for 30s.
|
||||
# that's a questionable place to install that logic, and i want to keep stuff
|
||||
# out of the wake-from-sleep critical path, so i'm overriding this hook to disable that.
|
||||
|
||||
declare -A newmap
|
||||
wowlan_reason[0x0]="not wowlan"
|
||||
|
||||
# mappings are found in megi's linux: drivers/staging/rtl8723cs/include/hal_com.h
|
||||
wowlan_reason[0x1]="RX_PAIRWISEKEY"
|
||||
wowlan_reason[0x2]="RX_GTK"
|
||||
wowlan_reason[0x3]="RX_FOURWAY_HANDSHAKE"
|
||||
wowlan_reason[0x4]="RX_DISASSOC"
|
||||
wowlan_reason[0x8]="RX_DEAUTH"
|
||||
wowlan_reason[0x9]="RX_ARP_REQUEST"
|
||||
wowlan_reason[0x10]="FW_DECISION_DISCONNECT"
|
||||
wowlan_reason[0x21]="RX_MAGIC_PKT"
|
||||
wowlan_reason[0x22]="RX_UNICAST_PKT"
|
||||
wowlan_reason[0x23]="RX_PATTERN_PKT"
|
||||
wowlan_reason[0x24]="RTD3_SSID_MATCH"
|
||||
wowlan_reason[0x30]="RX_REALWOW_V2_WAKEUP_PKT"
|
||||
wowlan_reason[0x31]="RX_REALWOW_V2_ACK_LOST"
|
||||
wowlan_reason[0x40]="ENABLE_FAIL_DMA_IDLE"
|
||||
wowlan_reason[0x41]="ENABLE_FAIL_DMA_PAUSE"
|
||||
wowlan_reason[0x42]="RTIME_FAIL_DMA_IDLE"
|
||||
wowlan_reason[0x43]="RTIME_FAIL_DMA_PAUSE"
|
||||
wowlan_reason[0x55]="RX_PNO"
|
||||
#ifdef CONFIG_WOW_KEEP_ALIVE_PATTERN
|
||||
wowlan_reason[0x60]="WOW_KEEPALIVE_ACK_TIMEOUT"
|
||||
wowlan_reason[0x61]="WOW_KEEPALIVE_WAKE"
|
||||
#endif/*CONFIG_WOW_KEEP_ALIVE_PATTERN*/
|
||||
wowlan_reason[0x66]="AP_OFFLOAD_WAKEUP"
|
||||
wowlan_reason[0xfd]="CLK_32K_UNLOCK"
|
||||
wowlan_reason[0xfe]="CLK_32K_LOCK"
|
||||
|
||||
wowlan_text="$(cat /proc/net/rtl8723cs/wlan0/wowlan_last_wake_reason)"
|
||||
wowlan_bits="${wowlan_text/last wake reason: /}"
|
||||
wowlan_reason="${wowlan_reason[$wowlan_bits]}"
|
||||
echo "exited suspend: $wowlan_text ($wowlan_reason)"
|
||||
if [ "$wowlan_bits" != "0x0" ]; then
|
||||
# give time for userspace to respond to the wake event.
|
||||
# IM clients might have to re-establish TCP connections, perform sync, etc
|
||||
# until finally receiving the event which the system woke for,
|
||||
# TODO: if we suspended only very briefly, likely all the networking is in sync
|
||||
# and we don't have to wait this long.
|
||||
# there's no easy way *here* to know how long we slept for, though.
|
||||
sxmo_wakelock.sh lock postwake_work 25s
|
||||
fi
|
@@ -1,16 +0,0 @@
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i bash -p sway
|
||||
|
||||
# called whenever sxmo_rotate.sh is invoked.
|
||||
# i.e. whenever the screen is rotated manually, or automatically if autorotate is enabled.
|
||||
# $1 = the new orientation
|
||||
# possible values are "normal", "invert", "left" and "right"
|
||||
|
||||
# exit fullscreen, if any app is in FS.
|
||||
# this benefits UX because:
|
||||
# - most of my FS use is in landscape mode
|
||||
# - when i toggle apps or desktops i always do so in portrait mode
|
||||
# - therefore when i rotate landscape -> portrait mode, i almost never want fullscreen anymore.
|
||||
if [ "$1" = "normal" ] || [ "$1" = "invert" ]; then
|
||||
swaymsg fullscreen disable
|
||||
fi
|
@@ -1,95 +0,0 @@
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i bash -p systemd -p xdg-user-dirs
|
||||
# this is based on upstream sxmo-utils sxmo_hook_start.sh
|
||||
# but modified for nixos integration and specialize a bit to my needs
|
||||
. sxmo_common.sh
|
||||
|
||||
# Create xdg user directories, such as ~/Pictures
|
||||
xdg-user-dirs-update
|
||||
|
||||
sxmo_jobs.sh start daemon_manager
|
||||
|
||||
# Periodically update some status bar components
|
||||
# don't: statusbar is managed by waybar
|
||||
# sxmo_hook_statusbar.sh all
|
||||
# sxmo_jobs.sh start statusbar_periodics sxmo_run_aligned.sh 60 \
|
||||
# sxmo_hook_statusbar.sh periodics
|
||||
|
||||
# TODO: start these externally, via `wantedBy` in nix
|
||||
# don't: i don't use mako
|
||||
# superctl start mako
|
||||
# systemctl --user start sxmo_wob
|
||||
systemctl --user start sxmo_menumode_toggler
|
||||
systemctl --user start bonsaid
|
||||
# don't: sway background is managed externally
|
||||
# swaymsg output '*' bg "$SXMO_BG_IMG" fill
|
||||
|
||||
# To setup initial lock state
|
||||
sxmo_state.sh set unlock
|
||||
|
||||
# Turn on auto-suspend
|
||||
if [ -w "/sys/power/wakeup_count" ] && [ -f "/sys/power/wake_lock" ]; then
|
||||
systemctl --user start sxmo_autosuspend
|
||||
fi
|
||||
|
||||
# Turn on lisgd
|
||||
if [ ! -e "$XDG_CACHE_HOME"/sxmo/sxmo.nogesture ]; then
|
||||
systemctl --user start sxmo_hook_lisgd
|
||||
fi
|
||||
|
||||
if [ "$(command -v ModemManager)" ]; then
|
||||
# Turn on the dbus-monitors for modem-related tasks
|
||||
systemctl --user start sxmo_modemmonitor
|
||||
|
||||
# place a wakelock for 120s to allow the modem to fully warm up (eg25 +
|
||||
# elogind/systemd would do this for us, but we don't use those.)
|
||||
sxmo_wakelock.sh lock sxmo_modem_warming_up 120s
|
||||
fi
|
||||
|
||||
# don't: conky is managed externally
|
||||
# superctl start sxmo_conky
|
||||
|
||||
# Monitor the battery
|
||||
# don't: this is *exclusively* for sxmo_hook_statusbar.sh, which i don't use.
|
||||
# systemctl --user start sxmo_battery_monitor
|
||||
|
||||
# It watch network changes and update the status bar icon by example
|
||||
# don't: this is for sxmo_hook_statusbar.sh, which i don't use.
|
||||
# this means we never call sxmo_hook_network_{up,down,...}, but the defaults are no-op anyway
|
||||
# systemctl --user start sxmo_networkmonitor
|
||||
|
||||
# The daemon that display notifications popup messages
|
||||
# more importantly: it lights the led green when a notification arrives
|
||||
systemctl --user start sxmo_notificationmonitor
|
||||
|
||||
# monitor for headphone for statusbar
|
||||
# this also invokes `wob` whenever the volume is changed
|
||||
# don't: my volume monitoring is handled by sway
|
||||
# systemctl --user start sxmo_soundmonitor
|
||||
|
||||
# rotate UI based on physical display angle by default
|
||||
if [ -n "$SXMO_AUTOROTATE" ]; then
|
||||
# TODO: this could use ~/.cache/sxmo/sxmo.autorotate like for lisgd above
|
||||
sxmo_jobs.sh start autorotate sxmo_autorotate.sh
|
||||
fi
|
||||
|
||||
# Play a funky startup tune if you want (disabled by default)
|
||||
#mpv --quiet --no-video ~/welcome.ogg &
|
||||
|
||||
# mmsd and vvmd
|
||||
if [ -f "${SXMO_MMS_BASE_DIR:-"$HOME"/.mms/modemmanager}/mms" ]; then
|
||||
systemctl --user start mmsd-tng
|
||||
fi
|
||||
|
||||
if [ -f "${SXMO_VVM_BASE_DIR:-"$HOME"/.vvm/modemmanager}/vvm" ]; then
|
||||
systemctl --user start vvmd
|
||||
fi
|
||||
|
||||
# add some warnings if things are not setup correctly
|
||||
if ! command -v "sxmo_deviceprofile_$SXMO_DEVICE_NAME.sh"; then
|
||||
sxmo_notify_user.sh --urgency=critical \
|
||||
"No deviceprofile found $SXMO_DEVICE_NAME. See: https://sxmo.org/deviceprofile"
|
||||
fi
|
||||
|
||||
sxmo_migrate.sh state || sxmo_notify_user.sh --urgency=critical \
|
||||
"Config needs migration" "$? file(s) in your sxmo configuration are out of date and disabled - using defaults until you migrate (run sxmo_migrate.sh)"
|
@@ -1,122 +0,0 @@
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i bash -p sxmo-utils -p sxmo-utils.runtimeDeps
|
||||
#
|
||||
# usage:
|
||||
# waybar-sxmo-status widget1 [ widget2 [...]]
|
||||
#
|
||||
# where each widget is one of:
|
||||
# - modem-state
|
||||
# - modem-tech
|
||||
# - modem-signal
|
||||
# - wifi-status
|
||||
# - volume
|
||||
|
||||
# sxmo_hook_statusbar.sh assumes:
|
||||
# - mmcli, jq on PATH
|
||||
# - sxmo_hook_icons.sh and sxmo_common.sh are sourcable
|
||||
# - from sxmo_common, it only uses sxmobar (and aliases jq=gojq)
|
||||
|
||||
# setup environment so that the hooks will be on PATH:
|
||||
# - sxmo_hook_statusbar.sh
|
||||
# - sxmo_hook_icons.sh
|
||||
export HOME="${HOME:-/home/colin}"
|
||||
export XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"
|
||||
export PATH="$XDG_CONFIG_HOME/sxmo/hooks:$PATH"
|
||||
|
||||
# ensure that sxmo_audio.sh tells us the volume instead of early-returning
|
||||
export SXMO_NO_AUDIO=
|
||||
|
||||
# clunky interaction between us and sxmo_hook_statusbar.sh:
|
||||
# - we export `sxmobar` to it, but within that function cannot modify the environment
|
||||
# of *this* script, because it gets run in a different process.
|
||||
# - so, `sxmobar` prints info to stdout, and then this script re-interprets that info.
|
||||
# - practically, `sxmobar` prints shell commands, and then this script `eval`s them, to achieve that IPC.
|
||||
sxmobar() {
|
||||
action="$1"
|
||||
shift
|
||||
if [ "$action" = "-a" ]; then
|
||||
while [ -n "$*" ]; do
|
||||
arg="$1"
|
||||
case "$arg" in
|
||||
"-f"|"-b"|"-t"|"-e")
|
||||
# foreground/background/text/emphasis: ignore it
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
# begin arguments
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
echo "setitem $@"
|
||||
fi
|
||||
}
|
||||
export -f sxmobar
|
||||
|
||||
setitem() {
|
||||
id="$1"
|
||||
priority="$2"
|
||||
value="$3"
|
||||
case "$id" in
|
||||
modem-state)
|
||||
modem_state="$value"
|
||||
;;
|
||||
modem-tech)
|
||||
modem_tech="$value"
|
||||
;;
|
||||
modem-signal)
|
||||
modem_signal="$value"
|
||||
;;
|
||||
wifi-status)
|
||||
wifi_status="$value"
|
||||
;;
|
||||
volume)
|
||||
volume="$value"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
while [ -n "$*" ]; do
|
||||
variable="$1"
|
||||
shift
|
||||
case "$variable" in
|
||||
"--verbose")
|
||||
set -x
|
||||
;;
|
||||
"modem-state")
|
||||
if [ -z "$modem_state" ]; then
|
||||
eval "$(sxmo_hook_statusbar.sh modem)"
|
||||
fi
|
||||
echo -n "$modem_state"
|
||||
;;
|
||||
"modem-tech")
|
||||
if [ -z "$modem_tech" ]; then
|
||||
eval "$(sxmo_hook_statusbar.sh modem)"
|
||||
fi
|
||||
echo -n "$modem_tech"
|
||||
;;
|
||||
"modem-signal")
|
||||
if [ -z "$modem_signal" ]; then
|
||||
eval "$(sxmo_hook_statusbar.sh modem)"
|
||||
fi
|
||||
echo -n "$modem_signal"
|
||||
;;
|
||||
"wifi-status")
|
||||
if [ -z "$wifi_status" ]; then
|
||||
eval "$(sxmo_hook_statusbar.sh network wifi wlan0)"
|
||||
fi
|
||||
echo -n "$wifi_status"
|
||||
;;
|
||||
"volume")
|
||||
if [ -z "$volume" ]; then
|
||||
eval "$(sxmo_hook_statusbar.sh volume)"
|
||||
fi
|
||||
echo -n "$volume"
|
||||
;;
|
||||
*)
|
||||
echo -n "UNK: $variable"
|
||||
;;
|
||||
esac
|
||||
done
|
@@ -1,85 +0,0 @@
|
||||
# docs: https://github.com/Alexays/Waybar/wiki/Configuration
|
||||
# format specifiers: https://fmt.dev/latest/syntax.html#syntax
|
||||
# this is merged with the sway/waybar-top.nix defaults
|
||||
{
|
||||
height = 26;
|
||||
|
||||
modules-left = [ "sway/workspaces" ];
|
||||
modules-center = [ ];
|
||||
modules-right = [
|
||||
"custom/swaync"
|
||||
"clock"
|
||||
"battery"
|
||||
"custom/sxmo-sane"
|
||||
# "custom/sxmo"
|
||||
# "custom/sxmo/modem-state"
|
||||
# "custom/sxmo/modem-tech"
|
||||
# "custom/sxmo/modem-signal"
|
||||
# "custom/sxmo/wifi"
|
||||
];
|
||||
|
||||
"sway/workspaces" = {
|
||||
all-outputs = true;
|
||||
# force the bar to always show even empty workspaces
|
||||
persistent-workspaces = {
|
||||
"1" = [];
|
||||
"2" = [];
|
||||
"3" = [];
|
||||
"4" = [];
|
||||
"5" = [];
|
||||
};
|
||||
};
|
||||
|
||||
"custom/sxmo-sane" = {
|
||||
# this calls all the SXMO indicators, inline.
|
||||
# so it works even without the "statusbar periodics" sxmo service running.
|
||||
interval = 2;
|
||||
format = "{}";
|
||||
exec = "waybar-sxmo-status modem-state modem-tech modem-signal wifi-status volume";
|
||||
};
|
||||
|
||||
"custom/sxmo" = {
|
||||
# this gives wifi state, battery, mic/speaker, lockstate, time all as one widget.
|
||||
# a good starting point, but may want to split these apart later to make things configurable.
|
||||
# the values for this bar are computed in sxmo:configs/default_hooks/sxmo_hook_statusbar.sh
|
||||
exec = "sxmo_status.sh";
|
||||
interval = 1;
|
||||
format = "{}";
|
||||
};
|
||||
# not ported: battery, ethernet
|
||||
"custom/sxmo/modem-state" = {
|
||||
exec = "cat /run/user/1000/sxmo_status/default/10-modem-state";
|
||||
interval = 2;
|
||||
format = "{}";
|
||||
};
|
||||
"custom/sxmo/modem-tech" = {
|
||||
exec = "cat /run/user/1000/sxmo_status/default/11-modem-tech";
|
||||
interval = 2;
|
||||
format = "{}";
|
||||
};
|
||||
"custom/sxmo/modem-signal" = {
|
||||
exec = "cat /run/user/1000/sxmo_status/default/12-modem-signal";
|
||||
interval = 2;
|
||||
format = "{}";
|
||||
};
|
||||
"custom/sxmo/wifi" = {
|
||||
exec = "cat /run/user/1000/sxmo_status/default/30-wifi-status";
|
||||
interval = 2;
|
||||
format = "{}";
|
||||
};
|
||||
"custom/sxmo/volume" = {
|
||||
exec = "cat /run/user/1000/sxmo_status/default/50-volume";
|
||||
interval = 2;
|
||||
format = "{}";
|
||||
};
|
||||
"custom/sxmo/state" = {
|
||||
exec = "cat /run/user/1000/sxmo_status/default/90-state";
|
||||
interval = 2;
|
||||
format = "{}";
|
||||
};
|
||||
"custom/sxmo/time" = {
|
||||
exec = "cat /run/user/1000/sxmo_status/default/99-time";
|
||||
interval = 2;
|
||||
format = "{}";
|
||||
};
|
||||
}
|
@@ -1,28 +0,0 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
cfg = config.sane.gui.theme.background;
|
||||
in
|
||||
{
|
||||
options = with lib; {
|
||||
sane.gui.theme.background = {
|
||||
svg = mkOption {
|
||||
type = types.path;
|
||||
default = ./nixos-bg-02.svg;
|
||||
};
|
||||
png = mkOption {
|
||||
type = types.path;
|
||||
default = pkgs.runCommand
|
||||
"nixos-bg.png"
|
||||
{ nativeBuildInputs = [ pkgs.inkscape ]; }
|
||||
''
|
||||
inkscape ${cfg.svg} -o $out
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
sane.programs.sway.config.background = lib.mkDefault cfg.png;
|
||||
sane.gui.sxmo.settings.SXMO_BG_IMG = lib.mkDefault (builtins.toString cfg.png);
|
||||
};
|
||||
}
|
@@ -17,6 +17,9 @@ let
|
||||
persistentKeepalive = 25;
|
||||
# allows wireguard to notice DNS/hostname changes, with this much effective TTL.
|
||||
dynamicEndpointRefreshSeconds = 600;
|
||||
# the refresh fails (because e.g. DNS fails to resolve), try it again this soon instead.
|
||||
# defaults to the same as dynamicEndpointRefreshSeconds, but i think setting it that high stalls my nix switches!
|
||||
dynamicEndpointRefreshRestartSeconds = 10;
|
||||
});
|
||||
# make separate peers to route each given host
|
||||
mkClientPeers = hosts: builtins.map (p: mkPeer {
|
||||
|
9
modules/data/feeds/sources/mintcast.org/default.json
Normal file
9
modules/data/feeds/sources/mintcast.org/default.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"description": "The podcast by the Linux Mint community for all users of Linux.",
|
||||
"is_podcast": true,
|
||||
"site_name": "mintCast",
|
||||
"site_url": "https://mintcast.org",
|
||||
"title": "mintCast",
|
||||
"url": "https://mintcast.org/feed/podcast/",
|
||||
"velocity": 0.121
|
||||
}
|
@@ -39,7 +39,8 @@ let
|
||||
else
|
||||
let
|
||||
makeSandboxArgs = pkgs.callPackage ./make-sandbox-args.nix { };
|
||||
makeSandboxed = pkgs.callPackage ./make-sandboxed.nix { sanebox = config.sane.programs.sanebox.package; };
|
||||
# makeSandboxed = pkgs.callPackage ./make-sandboxed.nix { sanebox = config.sane.programs.sanebox.package; };
|
||||
makeSandboxed = pkgs.callPackage ./make-sandboxed.nix { };
|
||||
|
||||
vpn = lib.findSingle (v: v.default) null null (builtins.attrValues config.sane.vpn);
|
||||
|
||||
@@ -51,7 +52,7 @@ let
|
||||
|
||||
"/etc" #< especially for /etc/profiles/per-user/$USER/bin
|
||||
"/run/current-system" #< for basics like `ls`, and all this program's `suggestedPrograms` (/run/current-system/sw/bin)
|
||||
"/run/wrappers" #< SUID wrappers. TODO: remove!
|
||||
# "/run/wrappers" #< SUID wrappers. they don't mean much inside a namespace.
|
||||
# /run/opengl-driver is a symlink into /nix/store; needed by e.g. mpv
|
||||
"/run/opengl-driver"
|
||||
"/run/opengl-driver-32" #< XXX: doesn't exist on aarch64?
|
||||
@@ -216,13 +217,31 @@ let
|
||||
'';
|
||||
};
|
||||
services = mkOption {
|
||||
type = types.attrsOf types.anything; # options.sane.users.value.type;
|
||||
type = options.sane.user._options.services.type;
|
||||
default = {};
|
||||
description = ''
|
||||
user services to define if this package is enabled.
|
||||
acts as noop for root-enabled packages.
|
||||
see `sane.users.<user>.services` for options;
|
||||
'';
|
||||
# TODO: this `apply` should by moved to where we pass the `services` down to `sane.users`
|
||||
apply = lib.mapAttrs (svcName: svcCfg:
|
||||
svcCfg // lib.optionalAttrs (builtins.tryEval svcCfg.description).success {
|
||||
# ensure service dependencies based on what a service's program whitelists.
|
||||
# only do this for the services which are *defined* by this program though (i.e. `scvCfg ? description`)
|
||||
# so as to avoid idioms like when sway adds `graphical-session.partOf = default`
|
||||
depends = svcCfg.depends
|
||||
++ lib.optionals (svcName != "dbus" && builtins.elem "user" config.sandbox.whitelistDbus) [
|
||||
"dbus"
|
||||
] ++ lib.optionals ((!builtins.elem "wayland" svcCfg.partOf) && config.sandbox.whitelistWayland) [
|
||||
"wayland"
|
||||
] ++ lib.optionals ((!builtins.elem "x11" svcCfg.partOf) && config.sandbox.whitelistX) [
|
||||
"x11"
|
||||
] ++ lib.optionals ((!builtins.elem "sound" svcCfg.partOf) && config.sandbox.whitelistAudio) [
|
||||
"sound"
|
||||
];
|
||||
}
|
||||
);
|
||||
};
|
||||
buildCost = mkOption {
|
||||
type = types.enum [ 0 1 2 3 ];
|
||||
@@ -309,6 +328,13 @@ let
|
||||
e.g. sandbox.capabilities = [ "net_admin" "net_raw" ];
|
||||
'';
|
||||
};
|
||||
sandbox.isolatePids = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
whether to place the process in a new PID namespace, if the sandboxer supports that.
|
||||
'';
|
||||
};
|
||||
sandbox.whitelistAudio = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
@@ -457,7 +483,7 @@ let
|
||||
sandbox.extraRuntimePaths =
|
||||
lib.optionals config.sandbox.whitelistAudio [ "pipewire" "pulse" ] # this includes pipewire/pipewire-0-manager: is that ok?
|
||||
++ lib.optionals (builtins.elem "user" config.sandbox.whitelistDbus) [ "bus" ]
|
||||
++ lib.optionals config.sandbox.whitelistWayland [ "wayland" ] # app can still communicate with wayland server w/o this, if it has net access
|
||||
++ lib.optionals config.sandbox.whitelistWayland [ "wl" ] # app can still communicate with wayland server w/o this, if it has net access
|
||||
++ lib.optionals config.sandbox.whitelistS6 [ "s6" ] # TODO: this allows re-writing the services themselves: don't allow that!
|
||||
;
|
||||
sandbox.extraHomePaths = let
|
||||
@@ -475,8 +501,10 @@ let
|
||||
++ lib.optionals (mainProgram != null) (whitelistDir ".config/${mainProgram}")
|
||||
++ lib.optionals (mainProgram != null) (whitelistDir ".local/share/${mainProgram}")
|
||||
;
|
||||
sandbox.extraConfig = lib.mkIf config.sandbox.usePortal [
|
||||
sandbox.extraConfig = lib.optionals config.sandbox.usePortal [
|
||||
"--sanebox-portal"
|
||||
] ++ lib.optionals (!config.sandbox.isolatePids) [
|
||||
"--sanebox-keep-namespace" "pid"
|
||||
];
|
||||
};
|
||||
});
|
||||
|
@@ -1,5 +1,8 @@
|
||||
{ lib
|
||||
, stdenv
|
||||
, buildPackages
|
||||
, file
|
||||
, gnugrep
|
||||
, runCommandLocal
|
||||
, runtimeShell
|
||||
, sanebox
|
||||
@@ -95,20 +98,27 @@ let
|
||||
done
|
||||
}
|
||||
|
||||
if [ -e "$out/bin" ]; then
|
||||
crawlAndWrap "$out/bin"
|
||||
fi
|
||||
if [ -e "$out/libexec" ]; then
|
||||
crawlAndWrap "$out/libexec"
|
||||
fi
|
||||
for output in $outputs; do
|
||||
local outdir=''${!output}
|
||||
echo "scanning output '$output' at $outdir for binaries to sandbox"
|
||||
if [ -e "$outdir/bin" ]; then
|
||||
crawlAndWrap "$outdir/bin"
|
||||
fi
|
||||
if [ -e "$outdir/libexec" ]; then
|
||||
crawlAndWrap "$outdir/libexec"
|
||||
fi
|
||||
done
|
||||
'';
|
||||
});
|
||||
|
||||
# there are certain `meta` fields we care to preserve from the original package (priority),
|
||||
# and others we *can't* preserve (outputsToInstall).
|
||||
extractMeta = pkg: if (pkg ? meta) && (pkg.meta ? priority) then {
|
||||
inherit (pkg.meta) priority;
|
||||
} else {};
|
||||
extractMeta = pkg: let
|
||||
meta = pkg.meta or {};
|
||||
in
|
||||
(lib.optionalAttrs (meta ? priority) { inherit (meta) priority; })
|
||||
// (lib.optionalAttrs (meta ? mainProgram) { inherit (meta) mainProgram; })
|
||||
;
|
||||
|
||||
# helper used for `wrapperType == "wrappedDerivation"` which simply symlinks all a package's binaries into a new derivation
|
||||
symlinkBinaries = pkgName: package: (runCommandLocal "${pkgName}-bin-only" {} ''
|
||||
@@ -117,6 +127,10 @@ let
|
||||
mkdir -p "$out/bin"
|
||||
${buildPackages.xorg.lndir}/bin/lndir "${package}/bin" "$out/bin"
|
||||
fi
|
||||
if [ "$(readlink ${package}/sbin)" == "bin" ]; then
|
||||
# weird packages like wpa_supplicant depend on a sbin/ -> bin symlink in their service files
|
||||
ln -s bin "$out/sbin"
|
||||
fi
|
||||
if [ -e "${package}/libexec" ]; then
|
||||
mkdir -p "$out/libexec"
|
||||
${buildPackages.xorg.lndir}/bin/lndir "${package}/libexec" "$out/libexec"
|
||||
@@ -128,7 +142,7 @@ let
|
||||
meta = extractMeta package;
|
||||
});
|
||||
|
||||
# helper used for `wrapperType == "wrappedDerivation"` which ensures that and copied/symlinked share/ files (like .desktop) files
|
||||
# helper used for `wrapperType == "wrappedDerivation"` which ensures that any copied/symlinked share/ files (like .desktop) files
|
||||
# don't point to the unwrapped binaries.
|
||||
# other important files it preserves:
|
||||
# - share/applications
|
||||
@@ -136,6 +150,7 @@ let
|
||||
# - share/icons
|
||||
# - share/man
|
||||
# - share/mime
|
||||
# - {etc,lib,share}/systemd
|
||||
fixHardcodedRefs = unsandboxed: sandboxedBin: unsandboxedNonBin: unsandboxedNonBin.overrideAttrs (prevAttrs: {
|
||||
postInstall = (prevAttrs.postInstall or "") + ''
|
||||
trySubstitute() {
|
||||
@@ -155,17 +170,17 @@ let
|
||||
# fixup a few files i understand well enough
|
||||
for d in \
|
||||
$out/etc/xdg/autostart/*.desktop \
|
||||
$out/lib/systemd/user/*.service \
|
||||
$out/share/applications/*.desktop \
|
||||
$out/share/dbus-1/services/*.service \
|
||||
$out/share/systemd/user/*.service \
|
||||
$out/share/dbus-1/{services,system-services}/*.service \
|
||||
$out/{etc,lib,share}/systemd/{system,user}/*.service \
|
||||
; do
|
||||
# dbus and desktop files
|
||||
trySubstitute "$d" "Exec=%s/bin/"
|
||||
trySubstitute "$d" "Exec=%s/libexec/"
|
||||
# systemd service files
|
||||
trySubstitute "$d" "ExecStart=%s/bin/"
|
||||
trySubstitute "$d" "ExecStart=%s/libexec/"
|
||||
# Exec: dbus and desktop files
|
||||
# ExecStart,ExecReload: systemd service files
|
||||
for key in Exec ExecStart ExecReload; do
|
||||
for binLoc in bin libexec sbin; do
|
||||
trySubstitute "$d" "$key=%s/$binLoc/"
|
||||
done
|
||||
done
|
||||
done
|
||||
'';
|
||||
passthru = (prevAttrs.passthru or {}) // {
|
||||
@@ -220,43 +235,59 @@ let
|
||||
priority = ((prevAttrs.meta or {}).priority or 0) - 1;
|
||||
};
|
||||
passthru = (prevAttrs.passthru or {}) // extraPassthru // {
|
||||
checkSandboxed = runCommandLocal "${pkgName}-check-sandboxed" {} ''
|
||||
checkSandboxed = runCommandLocal "${pkgName}-check-sandboxed" {
|
||||
nativeBuildInputs = [ file gnugrep sanebox ];
|
||||
buildInputs = builtins.map (out: finalAttrs.finalPackage."${out}") (finalAttrs.outputs or [ "out" ]);
|
||||
} ''
|
||||
set -e
|
||||
# invoke each binary in a way only the sandbox wrapper will recognize,
|
||||
# ensuring that every binary has in fact been wrapped.
|
||||
_numExec=0
|
||||
_checkExecutable() {
|
||||
echo "checking if $1 is sandboxed"
|
||||
PATH="${finalAttrs.finalPackage}/bin:${sanebox}/bin:$PATH" \
|
||||
SANEBOX_DISABLE=1 \
|
||||
"$1" --sanebox-replace-cli echo "printing for test" \
|
||||
local dir="$1"
|
||||
local binname="$2"
|
||||
echo "checking if $dir/$binname is sandboxed"
|
||||
# XXX: call by full path because some binaries (e.g. util-linux) would otherwise
|
||||
# be shadowed by things the nix builder implicitly puts on PATH.
|
||||
# additionally, call via qemu and manually specify the interpreter *if the file has one*.
|
||||
# if the file doesn't have an interpreter, assume it's directly invokable by qemu (hence, the intentional lack of quotes around `interpreter`)
|
||||
set -x
|
||||
local realbin="$(realpath $dir/$binname)"
|
||||
local interpreter=$(file "$realbin" | grep --only-matching "a /nix/.* script" | cut -d" " -f2 || echo "")
|
||||
${stdenv.hostPlatform.emulator buildPackages} $interpreter "$dir/$binname" --sanebox-replace-cli echo "printing for test" \
|
||||
| grep "printing for test"
|
||||
_numExec=$(( $_numExec + 1 ))
|
||||
}
|
||||
_checkDir() {
|
||||
for b in $(ls "$1"); do
|
||||
if [ -d "$1/$b" ]; then
|
||||
local dir="$1"
|
||||
for b in $(ls "$dir"); do
|
||||
if [ -d "$dir/$b" ]; then
|
||||
if [ "$b" != .sandboxed ]; then
|
||||
_checkDir "$1/$b"
|
||||
_checkDir "$dir/$b"
|
||||
fi
|
||||
elif [ -x "$1/$b" ]; then
|
||||
_checkExecutable "$1/$b"
|
||||
elif [ -x "$dir/$b" ]; then
|
||||
_checkExecutable "$dir" "$b"
|
||||
else
|
||||
test -n "$CHECK_DIR_NON_BIN"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# *everything* in the bin dir should be a wrapped executable
|
||||
if [ -e "${finalAttrs.finalPackage}/bin" ]; then
|
||||
_checkDir "${finalAttrs.finalPackage}/bin"
|
||||
fi
|
||||
for outDir in $buildInputs; do
|
||||
echo "starting crawl from package output: $outDir"
|
||||
# *everything* in the bin dir should be a wrapped executable
|
||||
if [ -e "$outDir/bin" ]; then
|
||||
echo "checking toplevel dir at $outDir/bin"
|
||||
_checkDir "$outDir/bin"
|
||||
fi
|
||||
|
||||
# the libexec dir is 90% wrapped executables, but sometimes also .so/.la objects.
|
||||
# note that this directory isn't flat
|
||||
if [ -e "${finalAttrs.finalPackage}/libexec" ]; then
|
||||
CHECK_DIR_NON_BIN=1 _checkDir "${finalAttrs.finalPackage}/libexec"
|
||||
fi
|
||||
# the libexec dir is 90% wrapped executables, but sometimes also .so/.la objects.
|
||||
# note that this directory isn't flat
|
||||
if [ -e "$outDir/libexec" ]; then
|
||||
echo "checking toplevel dir at $outDir/libexec"
|
||||
CHECK_DIR_NON_BIN=1 _checkDir "$outDir/libexec"
|
||||
fi
|
||||
done
|
||||
|
||||
echo "successfully tested $_numExec binaries"
|
||||
test "$_numExec" -ne 0
|
||||
|
@@ -1,6 +1,7 @@
|
||||
{ ... }:
|
||||
{
|
||||
imports = [
|
||||
./dropbear.nix
|
||||
./clightning.nix
|
||||
./dyn-dns.nix
|
||||
./eg25-manager.nix
|
||||
|
37
modules/services/dropbear.nix
Normal file
37
modules/services/dropbear.nix
Normal file
@@ -0,0 +1,37 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
cfg = config.sane.services.dropbear;
|
||||
in
|
||||
{
|
||||
options = {
|
||||
sane.services.dropbear = with lib; {
|
||||
enable = mkOption {
|
||||
default = false;
|
||||
type = types.bool;
|
||||
};
|
||||
|
||||
package = mkOption {
|
||||
type = types.package;
|
||||
default = pkgs.dropbear;
|
||||
defaultText = literalExpression "pkgs.dropbear";
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
type = types.port;
|
||||
default = 22;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
systemd.services.dropbear = {
|
||||
description = "Dropbear SSH Server";
|
||||
after = [ "network.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
serviceConfig.Type = "simple";
|
||||
# N.B.: dropbear ssh key format is incompatible with OpenSSH's.
|
||||
# also, needs to be manually generated on first run (`dropbearkey -t rsa -f /etc/ssh/host_keys/dropbear_rsa_host_key -s 4096`)
|
||||
serviceConfig.ExecStart = "${cfg.package}/bin/dropbear -F -p ${builtins.toString cfg.port} -r /etc/ssh/host_keys/dropbear_rsa_host_key -r /etc/ssh/host_keys/dropbear_ed25519_host_key";
|
||||
};
|
||||
};
|
||||
}
|
@@ -1,5 +1,4 @@
|
||||
# eg25-manager: <https://gitlab.com/mobian1/eg25-manager>
|
||||
# - used by sxmo, in <configs/default_hooks/sxmo_hook_restart_modem_daemons.sh>
|
||||
# - requires modemmanager (ModemManager.service)
|
||||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
|
@@ -35,7 +35,7 @@ let
|
||||
'';
|
||||
example = {
|
||||
"%CNAMESELF%" = "lappy";
|
||||
"%AWAN%" = ''"$(cat /var/www/wan.txt)"'';
|
||||
"%AWAN%" = ''"$(cat /var/uninsane/wan.txt)"'';
|
||||
};
|
||||
};
|
||||
includes = mkOption {
|
||||
@@ -117,9 +117,9 @@ let
|
||||
'') dns.zones
|
||||
);
|
||||
|
||||
serviceConfig = config.systemd.services.trust-dns.serviceConfig // {
|
||||
serviceConfig = (config.systemd.services.hickory-dns or config.systemd.services.trust-dns).serviceConfig // {
|
||||
ExecStart = lib.escapeShellArgs ([
|
||||
"${config.services.trust-dns.package}/bin/${config.services.trust-dns.package.meta.mainProgram}"
|
||||
"${lib.getExe config.services.trust-dns.package}"
|
||||
"--port" (builtins.toString port)
|
||||
"--zonedir" "/var/lib/trust-dns/${flavor}"
|
||||
"--config" "${configPath}"
|
||||
@@ -131,7 +131,10 @@ let
|
||||
# servo/dyn-dns needs /var/lib/uninsane/wan.txt.
|
||||
# this might not exist on other systems,
|
||||
# so just bind the deepest path which is guaranteed to exist.
|
||||
ReadOnlyPaths = [ "/var/lib" ];
|
||||
ReadOnlyPaths = [ "/var/lib" ]; #< TODO: scope this down!
|
||||
} // lib.optionalAttrs cfg.asSystemResolver {
|
||||
# allow the group to write trust-dns state (needed by NetworkManager hook)
|
||||
StateDirectoryMode = "775";
|
||||
};
|
||||
};
|
||||
in
|
||||
@@ -181,9 +184,10 @@ in
|
||||
rev = "67649863faf2e08f63963a96a491a4025aaf8ed6";
|
||||
hash = "sha256-vmVY8C0cCCFxy/4+g1vKZsAD5lMaufIExnFaSVVAhGM=";
|
||||
};
|
||||
cargoHash = "sha256-FEjNxv1iu27SXQhz1+Aehs4es8VxT1BPz5uZq8TcG/k=";
|
||||
cargoHash = "sha256-NoWrQgTPOp99pEs73VQrfeU3m8fny2s20Mf9qxwiPtQ=";
|
||||
});
|
||||
};
|
||||
services.trust-dns.settings.directory = "/var/lib/trust-dns";
|
||||
|
||||
users.groups.trust-dns = {};
|
||||
users.users.trust-dns = {
|
||||
@@ -193,6 +197,18 @@ in
|
||||
|
||||
systemd.services = lib.mkMerge [
|
||||
{
|
||||
hickory-dns.enable = false;
|
||||
hickory-dns.serviceConfig = {
|
||||
DynamicUser = lib.mkForce false;
|
||||
User = "trust-dns";
|
||||
Group = "trust-dns";
|
||||
wantedBy = lib.mkForce [];
|
||||
# there can be a lot of restarts as interfaces toggle,
|
||||
# particularly around the DHCP/NetworkManager stuff.
|
||||
StartLimitBurst = 60;
|
||||
StateDirectory = lib.mkForce "trust-dns";
|
||||
};
|
||||
|
||||
trust-dns.enable = false;
|
||||
trust-dns.serviceConfig = {
|
||||
DynamicUser = lib.mkForce false;
|
||||
@@ -202,6 +218,7 @@ in
|
||||
# there can be a lot of restarts as interfaces toggle,
|
||||
# particularly around the DHCP/NetworkManager stuff.
|
||||
StartLimitBurst = 60;
|
||||
StateDirectory = lib.mkForce "trust-dns";
|
||||
};
|
||||
# trust-dns.unitConfig.StartLimitIntervalSec = 60;
|
||||
}
|
||||
@@ -214,10 +231,23 @@ in
|
||||
)
|
||||
];
|
||||
|
||||
# run a hook whenever networking details change, so the DNS zone can be updated to reflect this
|
||||
environment.etc."NetworkManager/dispatcher.d/60-trust-dns-nmhook" = lib.mkIf cfg.asSystemResolver {
|
||||
source = "${trust-dns-nmhook}/bin/trust-dns-nmhook";
|
||||
};
|
||||
|
||||
# allow NetworkManager (via trust-dns-nmhook) to restart trust-dns when necessary
|
||||
# - source: <https://stackoverflow.com/questions/61480914/using-policykit-to-allow-non-root-users-to-start-and-stop-a-service>
|
||||
security.polkit.extraConfig = lib.mkIf cfg.asSystemResolver ''
|
||||
polkit.addRule(function(action, subject) {
|
||||
if (subject.isInGroup("trust-dns") &&
|
||||
action.id == "org.freedesktop.systemd1.manage-units" &&
|
||||
action.lookup("unit") == "trust-dns-localhost.service") {
|
||||
return polkit.Result.YES;
|
||||
}
|
||||
});
|
||||
'';
|
||||
|
||||
sane.services.trust-dns.instances.localhost = lib.mkIf cfg.asSystemResolver {
|
||||
listenAddrsIpv4 = [ "127.0.0.1" ];
|
||||
listenAddrsIpv6 = [ "::1" ];
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user